Merge "res_musiconhold: Start playlist after initial announcement"
[asterisk/asterisk.git] / apps / app_confbridge.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2007-2008, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  * David Vossel <dvossel@digium.com>
8  *
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2. See the LICENSE file
17  * at the top of the source tree.
18  */
19
20 /*! \file
21  *
22  * \brief Conference Bridge application
23  *
24  * \author\verbatim Joshua Colp <jcolp@digium.com> \endverbatim
25  * \author\verbatim David Vossel <dvossel@digium.com> \endverbatim
26  *
27  * This is a conference bridge application utilizing the bridging core.
28  * \ingroup applications
29  */
30
31 /*! \li \ref app_confbridge.c uses the configuration file \ref confbridge.conf
32  * \addtogroup configuration_file Configuration Files
33  */
34
35 /*!
36  * \page confbridge.conf confbridge.conf
37  * \verbinclude confbridge.conf.sample
38  */
39
40 /*** MODULEINFO
41         <support_level>core</support_level>
42  ***/
43
44 #include "asterisk.h"
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49 #include <string.h>
50 #include <signal.h>
51
52 #include "asterisk/cli.h"
53 #include "asterisk/file.h"
54 #include "asterisk/channel.h"
55 #include "asterisk/pbx.h"
56 #include "asterisk/pbx.h"
57 #include "asterisk/module.h"
58 #include "asterisk/lock.h"
59 #include "asterisk/bridge.h"
60 #include "asterisk/musiconhold.h"
61 #include "asterisk/say.h"
62 #include "asterisk/audiohook.h"
63 #include "asterisk/astobj2.h"
64 #include "confbridge/include/confbridge.h"
65 #include "asterisk/paths.h"
66 #include "asterisk/manager.h"
67 #include "asterisk/test.h"
68 #include "asterisk/stasis.h"
69 #include "asterisk/stasis_bridges.h"
70 #include "asterisk/json.h"
71 #include "asterisk/format_cache.h"
72 #include "asterisk/taskprocessor.h"
73
74 /*** DOCUMENTATION
75         <application name="ConfBridge" language="en_US">
76                 <synopsis>
77                         Conference bridge application.
78                 </synopsis>
79                 <syntax>
80                         <parameter name="conference" required="true">
81                                 <para>Name of the conference bridge.  You are not limited to just
82                                 numbers.</para>
83                         </parameter>
84                         <parameter name="bridge_profile">
85                                 <para>The bridge profile name from confbridge.conf.  When left blank,
86                                 a dynamically built bridge profile created by the CONFBRIDGE dialplan
87                                 function is searched for on the channel and used.  If no dynamic
88                                 profile is present, the 'default_bridge' profile found in
89                                 confbridge.conf is used. </para>
90                                 <para>It is important to note that while user profiles may be unique
91                                 for each participant, mixing bridge profiles on a single conference
92                                 is _NOT_ recommended and will produce undefined results.</para>
93                         </parameter>
94                         <parameter name="user_profile">
95                                 <para>The user profile name from confbridge.conf.  When left blank,
96                                 a dynamically built user profile created by the CONFBRIDGE dialplan
97                                 function is searched for on the channel and used.  If no dynamic
98                                 profile is present, the 'default_user' profile found in
99                                 confbridge.conf is used.</para>
100                         </parameter>
101                         <parameter name="menu">
102                                 <para>The name of the DTMF menu in confbridge.conf to be applied to
103                                 this channel.  When left blank, a dynamically built menu profile
104                                 created by the CONFBRIDGE dialplan function is searched for on
105                                 the channel and used. If no dynamic profile is present, the
106                                 'default_menu' profile found in confbridge.conf is used.</para>
107                         </parameter>
108                 </syntax>
109                 <description>
110                         <para>Enters the user into a specified conference bridge.  The user can
111                         exit the conference by hangup or DTMF menu option.</para>
112                         <para>This application sets the following channel variable upon completion:</para>
113                         <variablelist>
114                                 <variable name="CONFBRIDGE_RESULT">
115                                         <value name="FAILED">The channel encountered an error and could not enter the conference.</value>
116                                         <value name="HANGUP">The channel exited the conference by hanging up.</value>
117                                         <value name="KICKED">The channel was kicked from the conference.</value>
118                                         <value name="ENDMARKED">The channel left the conference as a result of the last marked user leaving.</value>
119                                         <value name="DTMF">The channel pressed a DTMF sequence to exit the conference.</value>
120                                         <value name="TIMEOUT">The channel reached its configured timeout.</value>
121                                 </variable>
122                         </variablelist>
123                 </description>
124                 <see-also>
125                         <ref type="application">ConfBridge</ref>
126                         <ref type="function">CONFBRIDGE</ref>
127                         <ref type="function">CONFBRIDGE_INFO</ref>
128                 </see-also>
129         </application>
130         <function name="CONFBRIDGE" language="en_US">
131                 <synopsis>
132                         Set a custom dynamic bridge, user, or menu profile on a channel for the
133                         ConfBridge application using the same options available in confbridge.conf.
134                 </synopsis>
135                 <syntax>
136                         <parameter name="type" required="true">
137                                 <para>To what type of conference profile the option applies.</para>
138                                 <enumlist>
139                                         <enum name="bridge"></enum>
140                                         <enum name="menu"></enum>
141                                         <enum name="user"></enum>
142                                 </enumlist>
143                         </parameter>
144                         <parameter name="option" required="true">
145                                 <para>Option refers to a <filename>confbridge.conf</filename> option
146                                 that is being set dynamically on this channel, or <literal>clear</literal>
147                                 to remove already applied profile options from the channel.</para>
148                         </parameter>
149                 </syntax>
150                 <description>
151                         <para>A custom profile uses the default profile type settings defined in
152                         <filename>confbridge.conf</filename> as defaults if the profile template
153                         is not explicitly specified first.</para>
154                         <para>For <literal>bridge</literal> profiles the default template is <literal>default_bridge</literal>.</para>
155                         <para>For <literal>menu</literal> profiles the default template is <literal>default_menu</literal>.</para>
156                         <para>For <literal>user</literal> profiles the default template is <literal>default_user</literal>.</para>
157                         <para>---- Example 1 ----</para>
158                         <para>In this example the custom user profile set on the channel will
159                         automatically be used by the ConfBridge application.</para>
160                         <para>exten => 1,1,Answer()</para>
161                         <para>; In this example the effect of the following line is</para>
162                         <para>; implied:</para>
163                         <para>; same => n,Set(CONFBRIDGE(user,template)=default_user)</para>
164                         <para>same => n,Set(CONFBRIDGE(user,announce_join_leave)=yes)</para>
165                         <para>same => n,Set(CONFBRIDGE(user,startmuted)=yes)</para>
166                         <para>same => n,ConfBridge(1) </para>
167                         <para>---- Example 2 ----</para>
168                         <para>This example shows how to use a predefined user profile in
169                         <filename>confbridge.conf</filename> as a template for a dynamic profile.
170                         Here we make an admin/marked user out of the <literal>my_user</literal>
171                         profile that you define in <filename>confbridge.conf</filename>.</para>
172                         <para>exten => 1,1,Answer()</para>
173                         <para>same => n,Set(CONFBRIDGE(user,template)=my_user)</para>
174                         <para>same => n,Set(CONFBRIDGE(user,admin)=yes)</para>
175                         <para>same => n,Set(CONFBRIDGE(user,marked)=yes)</para>
176                         <para>same => n,ConfBridge(1)</para>
177                 </description>
178         </function>
179         <function name="CONFBRIDGE_INFO" language="en_US">
180                 <synopsis>
181                         Get information about a ConfBridge conference.
182                 </synopsis>
183                 <syntax>
184                         <parameter name="type" required="true">
185                                 <para>What conference information is requested.</para>
186                                 <enumlist>
187                                         <enum name="admins">
188                                                 <para>Get the number of admin users in the conference.</para>
189                                         </enum>
190                                         <enum name="locked">
191                                                 <para>Determine if the conference is locked. (0 or 1)</para>
192                                         </enum>
193                                         <enum name="marked">
194                                                 <para>Get the number of marked users in the conference.</para>
195                                         </enum>
196                                         <enum name="muted">
197                                                 <para>Determine if the conference is muted. (0 or 1)</para>
198                                         </enum>
199                                         <enum name="parties">
200                                                 <para>Get the number of users in the conference.</para>
201                                         </enum>
202                                 </enumlist>
203                         </parameter>
204                         <parameter name="conf" required="true">
205                                 <para>The name of the conference being referenced.</para>
206                         </parameter>
207                 </syntax>
208                 <description>
209                         <para>This function returns a non-negative integer for valid conference
210                         names and an empty string for invalid conference names.</para>
211                 </description>
212         </function>
213         <manager name="ConfbridgeList" language="en_US">
214                 <synopsis>
215                         List participants in a conference.
216                 </synopsis>
217                 <syntax>
218                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
219                         <parameter name="Conference" required="true">
220                                 <para>Conference number.</para>
221                         </parameter>
222                 </syntax>
223                 <description>
224                         <para>Lists all users in a particular ConfBridge conference.
225                         ConfbridgeList will follow as separate events, followed by a final event called
226                         ConfbridgeListComplete.</para>
227                 </description>
228         </manager>
229         <manager name="ConfbridgeListRooms" language="en_US">
230                 <synopsis>
231                         List active conferences.
232                 </synopsis>
233                 <syntax>
234                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
235                 </syntax>
236                 <description>
237                         <para>Lists data about all active conferences.
238                                 ConfbridgeListRooms will follow as separate events, followed by a final event called
239                                 ConfbridgeListRoomsComplete.</para>
240                 </description>
241         </manager>
242         <manager name="ConfbridgeMute" language="en_US">
243                 <synopsis>
244                         Mute a Confbridge user.
245                 </synopsis>
246                 <syntax>
247                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
248                         <parameter name="Conference" required="true" />
249                         <parameter name="Channel" required="true">
250                                 <para>If this parameter is not a complete channel name, the first channel with this prefix will be used.</para>
251                                 <para>If this parameter is "all", all channels will be muted.</para>
252                                 <para>If this parameter is "participants", all non-admin channels will be muted.</para>
253                         </parameter>
254                 </syntax>
255                 <description>
256                 </description>
257         </manager>
258         <manager name="ConfbridgeUnmute" language="en_US">
259                 <synopsis>
260                         Unmute a Confbridge user.
261                 </synopsis>
262                 <syntax>
263                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
264                         <parameter name="Conference" required="true" />
265                         <parameter name="Channel" required="true">
266                                 <para>If this parameter is not a complete channel name, the first channel with this prefix will be used.</para>
267                                 <para>If this parameter is "all", all channels will be unmuted.</para>
268                                 <para>If this parameter is "participants", all non-admin channels will be unmuted.</para>
269                         </parameter>
270                 </syntax>
271                 <description>
272                 </description>
273         </manager>
274         <manager name="ConfbridgeKick" language="en_US">
275                 <synopsis>
276                         Kick a Confbridge user.
277                 </synopsis>
278                 <syntax>
279                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
280                         <parameter name="Conference" required="true" />
281                         <parameter name="Channel" required="true" >
282                                 <para>If this parameter is "all", all channels will be kicked from the conference.</para>
283                                 <para>If this parameter is "participants", all non-admin channels will be kicked from the conference.</para>
284                         </parameter>
285                 </syntax>
286                 <description>
287                 </description>
288         </manager>
289         <manager name="ConfbridgeLock" language="en_US">
290                 <synopsis>
291                         Lock a Confbridge conference.
292                 </synopsis>
293                 <syntax>
294                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
295                         <parameter name="Conference" required="true" />
296                 </syntax>
297                 <description>
298                 </description>
299         </manager>
300         <manager name="ConfbridgeUnlock" language="en_US">
301                 <synopsis>
302                         Unlock a Confbridge conference.
303                 </synopsis>
304                 <syntax>
305                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
306                         <parameter name="Conference" required="true" />
307                 </syntax>
308                 <description>
309                 </description>
310         </manager>
311         <manager name="ConfbridgeStartRecord" language="en_US">
312                 <synopsis>
313                         Start recording a Confbridge conference.
314                 </synopsis>
315                 <syntax>
316                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
317                         <parameter name="Conference" required="true" />
318                         <parameter name="RecordFile" required="false" />
319                 </syntax>
320                 <description>
321                         <para>Start recording a conference. If recording is already present an error will be returned. If RecordFile is not provided, the default record file specified in the conference's bridge profile will be used, if that is not present either a file will automatically be generated in the monitor directory.</para>
322                 </description>
323         </manager>
324         <manager name="ConfbridgeStopRecord" language="en_US">
325                 <synopsis>
326                         Stop recording a Confbridge conference.
327                 </synopsis>
328                 <syntax>
329                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
330                         <parameter name="Conference" required="true" />
331                 </syntax>
332                 <description>
333                 </description>
334         </manager>
335         <manager name="ConfbridgeSetSingleVideoSrc" language="en_US">
336                 <synopsis>
337                         Set a conference user as the single video source distributed to all other participants.
338                 </synopsis>
339                 <syntax>
340                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
341                         <parameter name="Conference" required="true" />
342                         <parameter name="Channel" required="true">
343                                 <para>If this parameter is not a complete channel name, the first channel with this prefix will be used.</para>
344                         </parameter>
345                 </syntax>
346                 <description>
347                 </description>
348         </manager>
349
350 ***/
351
352 /*!
353  * \par Playing back a file to a channel in a conference
354  * You might notice in this application that while playing a sound file
355  * to a channel the actual conference bridge lock is not held. This is done so
356  * that other channels are not blocked from interacting with the conference bridge.
357  * Unfortunately because of this it is possible for things to change after the sound file
358  * is done being played. Data must therefore be checked after reacquiring the conference
359  * bridge lock if it is important.
360  */
361
362 static const char app[] = "ConfBridge";
363
364 /*! Number of buckets our conference bridges container can have */
365 #define CONFERENCE_BRIDGE_BUCKETS 53
366
367 /*! Initial recording filename space. */
368 #define RECORD_FILENAME_INITIAL_SPACE   128
369
370 /*! \brief Container to hold all conference bridges in progress */
371 struct ao2_container *conference_bridges;
372
373 static void leave_conference(struct confbridge_user *user);
374 static int play_sound_number(struct confbridge_conference *conference, int say_number);
375 static int execute_menu_entry(struct confbridge_conference *conference,
376         struct confbridge_user *user,
377         struct ast_bridge_channel *bridge_channel,
378         struct conf_menu_entry *menu_entry,
379         struct conf_menu *menu);
380
381 /*! \brief Hashing function used for conference bridges container */
382 static int conference_bridge_hash_cb(const void *obj, const int flags)
383 {
384         const struct confbridge_conference *conference = obj;
385         const char *name = obj;
386         int hash;
387
388         switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
389         default:
390         case OBJ_POINTER:
391                 name = conference->name;
392                 /* Fall through */
393         case OBJ_KEY:
394                 hash = ast_str_case_hash(name);
395                 break;
396         case OBJ_PARTIAL_KEY:
397                 /* Should never happen in hash callback. */
398                 ast_assert(0);
399                 hash = 0;
400                 break;
401         }
402         return hash;
403 }
404
405 /*! \brief Comparison function used for conference bridges container */
406 static int conference_bridge_cmp_cb(void *obj, void *arg, int flags)
407 {
408         const struct confbridge_conference *left = obj;
409         const struct confbridge_conference *right = arg;
410         const char *right_name = arg;
411         int cmp;
412
413         switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
414         default:
415         case OBJ_POINTER:
416                 right_name = right->name;
417                 /* Fall through */
418         case OBJ_KEY:
419                 cmp = strcasecmp(left->name, right_name);
420                 break;
421         case OBJ_PARTIAL_KEY:
422                 cmp = strncasecmp(left->name, right_name, strlen(right_name));
423                 break;
424         }
425         return cmp ? 0 : CMP_MATCH;
426 }
427
428 const char *conf_get_sound(enum conf_sounds sound, struct bridge_profile_sounds *custom_sounds)
429 {
430         switch (sound) {
431         case CONF_SOUND_HAS_JOINED:
432                 return S_OR(custom_sounds->hasjoin, "conf-hasjoin");
433         case CONF_SOUND_HAS_LEFT:
434                 return S_OR(custom_sounds->hasleft, "conf-hasleft");
435         case CONF_SOUND_KICKED:
436                 return S_OR(custom_sounds->kicked, "conf-kicked");
437         case CONF_SOUND_MUTED:
438                 return S_OR(custom_sounds->muted, "conf-muted");
439         case CONF_SOUND_UNMUTED:
440                 return S_OR(custom_sounds->unmuted, "conf-unmuted");
441         case CONF_SOUND_BINAURAL_ON:
442                 return S_OR(custom_sounds->binauralon, "confbridge-binaural-on");
443         case CONF_SOUND_BINAURAL_OFF:
444                 return S_OR(custom_sounds->binauraloff, "confbridge-binaural-off");
445         case CONF_SOUND_ONLY_ONE:
446                 return S_OR(custom_sounds->onlyone, "conf-onlyone");
447         case CONF_SOUND_THERE_ARE:
448                 return S_OR(custom_sounds->thereare, "conf-thereare");
449         case CONF_SOUND_OTHER_IN_PARTY:
450                 return S_OR(custom_sounds->otherinparty, "conf-otherinparty");
451         case CONF_SOUND_PLACE_IN_CONF:
452                 return S_OR(custom_sounds->placeintoconf, "conf-placeintoconf");
453         case CONF_SOUND_WAIT_FOR_LEADER:
454                 return S_OR(custom_sounds->waitforleader, "conf-waitforleader");
455         case CONF_SOUND_LEADER_HAS_LEFT:
456                 return S_OR(custom_sounds->leaderhasleft, "conf-leaderhasleft");
457         case CONF_SOUND_GET_PIN:
458                 return S_OR(custom_sounds->getpin, "conf-getpin");
459         case CONF_SOUND_INVALID_PIN:
460                 return S_OR(custom_sounds->invalidpin, "conf-invalidpin");
461         case CONF_SOUND_ONLY_PERSON:
462                 return S_OR(custom_sounds->onlyperson, "conf-onlyperson");
463         case CONF_SOUND_LOCKED:
464                 return S_OR(custom_sounds->locked, "conf-locked");
465         case CONF_SOUND_LOCKED_NOW:
466                 return S_OR(custom_sounds->lockednow, "conf-lockednow");
467         case CONF_SOUND_UNLOCKED_NOW:
468                 return S_OR(custom_sounds->unlockednow, "conf-unlockednow");
469         case CONF_SOUND_ERROR_MENU:
470                 return S_OR(custom_sounds->errormenu, "conf-errormenu");
471         case CONF_SOUND_JOIN:
472                 return S_OR(custom_sounds->join, "confbridge-join");
473         case CONF_SOUND_LEAVE:
474                 return S_OR(custom_sounds->leave, "confbridge-leave");
475         case CONF_SOUND_PARTICIPANTS_MUTED:
476                 return S_OR(custom_sounds->participantsmuted, "conf-now-muted");
477         case CONF_SOUND_PARTICIPANTS_UNMUTED:
478                 return S_OR(custom_sounds->participantsunmuted, "conf-now-unmuted");
479         case CONF_SOUND_BEGIN:
480                 return S_OR(custom_sounds->begin, "confbridge-conf-begin");
481         }
482
483         return "";
484 }
485
486 static void send_conf_stasis(struct confbridge_conference *conference, struct ast_channel *chan,
487         struct stasis_message_type *type, struct ast_json *extras, int channel_topic)
488 {
489         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
490         RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
491
492         json_object = ast_json_pack("{s: s}",
493                 "conference", conference->name);
494         if (!json_object) {
495                 return;
496         }
497
498         if (extras) {
499                 ast_json_object_update(json_object, extras);
500         }
501
502         ast_bridge_lock(conference->bridge);
503         msg = ast_bridge_blob_create(type,
504                 conference->bridge,
505                 chan,
506                 json_object);
507         ast_bridge_unlock(conference->bridge);
508         if (!msg) {
509                 return;
510         }
511
512         if (channel_topic) {
513                 stasis_publish(ast_channel_topic(chan), msg);
514         } else {
515                 stasis_publish(ast_bridge_topic(conference->bridge), msg);
516         }
517 }
518
519 static void send_conf_start_event(struct confbridge_conference *conference)
520 {
521         send_conf_stasis(conference, NULL, confbridge_start_type(), NULL, 0);
522 }
523
524 static void send_conf_end_event(struct confbridge_conference *conference)
525 {
526         send_conf_stasis(conference, NULL, confbridge_end_type(), NULL, 0);
527 }
528
529 static void send_join_event(struct confbridge_user *user, struct confbridge_conference *conference)
530 {
531         struct ast_json *json_object;
532
533         json_object = ast_json_pack("{s: b}",
534                 "admin", ast_test_flag(&user->u_profile, USER_OPT_ADMIN)
535         );
536         if (!json_object) {
537                 return;
538         }
539         send_conf_stasis(conference, user->chan, confbridge_join_type(), json_object, 0);
540         ast_json_unref(json_object);
541 }
542
543 static void send_leave_event(struct confbridge_user *user, struct confbridge_conference *conference)
544 {
545         struct ast_json *json_object;
546
547         json_object = ast_json_pack("{s: b}",
548                 "admin", ast_test_flag(&user->u_profile, USER_OPT_ADMIN)
549         );
550         if (!json_object) {
551                 return;
552         }
553         send_conf_stasis(conference, user->chan, confbridge_leave_type(), json_object, 0);
554         ast_json_unref(json_object);
555 }
556
557 static void send_start_record_event(struct confbridge_conference *conference)
558 {
559         send_conf_stasis(conference, NULL, confbridge_start_record_type(), NULL, 0);
560 }
561
562 static void send_stop_record_event(struct confbridge_conference *conference)
563 {
564         send_conf_stasis(conference, NULL, confbridge_stop_record_type(), NULL, 0);
565 }
566
567 static void send_mute_event(struct confbridge_user *user, struct confbridge_conference *conference)
568 {
569         struct ast_json *json_object;
570
571         json_object = ast_json_pack("{s: b}",
572                 "admin", ast_test_flag(&user->u_profile, USER_OPT_ADMIN)
573         );
574         if (!json_object) {
575                 return;
576         }
577         send_conf_stasis(conference, user->chan, confbridge_mute_type(), json_object, 1);
578         ast_json_unref(json_object);
579 }
580
581 static void send_unmute_event(struct confbridge_user *user, struct confbridge_conference *conference)
582 {
583         struct ast_json *json_object;
584
585         json_object = ast_json_pack("{s: b}",
586                 "admin", ast_test_flag(&user->u_profile, USER_OPT_ADMIN)
587         );
588         if (!json_object) {
589                 return;
590         }
591         send_conf_stasis(conference, user->chan, confbridge_unmute_type(), json_object, 1);
592         ast_json_unref(json_object);
593 }
594
595 static void set_rec_filename(struct confbridge_conference *conference, struct ast_str **filename, int is_new)
596 {
597         char *rec_file = conference->b_profile.rec_file;
598         char *ext;
599         time_t now;
600
601         if (ast_str_strlen(*filename)
602                 && ast_test_flag(&conference->b_profile, BRIDGE_OPT_RECORD_FILE_APPEND)
603                 && !is_new) {
604                 return;
605         }
606
607         time(&now);
608
609         ast_str_reset(*filename);
610         if (ast_strlen_zero(rec_file)) {
611                 ast_str_set(filename, 0, "confbridge-%s-%u.wav", conference->name,
612                         (unsigned int) now);
613         } else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_RECORD_FILE_TIMESTAMP)) {
614                 /* insert time before file extension */
615                 ext = strrchr(rec_file, '.');
616                 if (ext) {
617                         ast_str_set_substr(filename, 0, rec_file, ext - rec_file);
618                         ast_str_append(filename, 0, "-%u%s", (unsigned int) now, ext);
619                 } else {
620                         ast_str_set(filename, 0, "%s-%u", rec_file, (unsigned int) now);
621                 }
622         } else {
623                 ast_str_set(filename, 0, "%s", rec_file);
624         }
625         ast_str_append(filename, 0, ",%s%s,%s",
626                 ast_test_flag(&conference->b_profile, BRIDGE_OPT_RECORD_FILE_APPEND) ? "a" : "",
627                 conference->b_profile.rec_options,
628                 conference->b_profile.rec_command);
629 }
630
631 static int is_new_rec_file(const char *rec_file, struct ast_str **orig_rec_file)
632 {
633         if (!ast_strlen_zero(rec_file)) {
634                 if (!*orig_rec_file) {
635                         *orig_rec_file = ast_str_create(RECORD_FILENAME_INITIAL_SPACE);
636                 }
637
638                 if (*orig_rec_file
639                         && strcmp(ast_str_buffer(*orig_rec_file), rec_file)) {
640                         ast_str_set(orig_rec_file, 0, "%s", rec_file);
641                         return 1;
642                 }
643         }
644         return 0;
645 }
646
647 /*!
648  * \internal
649  * \brief Returns whether or not conference is being recorded.
650  *
651  * \param conference The bridge to check for recording
652  *
653  * \note Must be called with the conference locked
654  *
655  * \retval 1, conference is recording.
656  * \retval 0, conference is NOT recording.
657  */
658 static int conf_is_recording(struct confbridge_conference *conference)
659 {
660         return conference->record_chan != NULL;
661 }
662
663 /*!
664  * \internal
665  * \brief Stop recording a conference bridge
666  *
667  * \param conference The conference bridge on which to stop the recording
668  *
669  * \note Must be called with the conference locked
670  *
671  * \retval -1 Failure
672  * \retval 0 Success
673  */
674 static int conf_stop_record(struct confbridge_conference *conference)
675 {
676         struct ast_channel *chan;
677         struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_HANGUP };
678
679         if (!conf_is_recording(conference)) {
680                 return -1;
681         }
682
683         /* Remove the recording channel from the conference bridge. */
684         chan = conference->record_chan;
685         conference->record_chan = NULL;
686         ast_queue_frame(chan, &f);
687         ast_channel_unref(chan);
688
689         ast_test_suite_event_notify("CONF_STOP_RECORD", "Message: stopped conference recording channel\r\nConference: %s", conference->b_profile.name);
690         send_stop_record_event(conference);
691
692         return 0;
693 }
694
695 /*!
696  * \internal
697  * \brief Start recording the conference
698  *
699  * \param conference The conference bridge to start recording
700  *
701  * \note Must be called with the conference locked
702  *
703  * \retval 0 success
704  * \retval non-zero failure
705  */
706 static int conf_start_record(struct confbridge_conference *conference)
707 {
708         struct ast_app *mixmonapp;
709         struct ast_channel *chan;
710         struct ast_format_cap *cap;
711         struct ast_bridge_features *features;
712
713         if (conf_is_recording(conference)) {
714                 return -1;
715         }
716
717         mixmonapp = pbx_findapp("MixMonitor");
718         if (!mixmonapp) {
719                 ast_log(LOG_WARNING, "Cannot record ConfBridge, MixMonitor app is not installed\n");
720                 return -1;
721         }
722
723         features = ast_bridge_features_new();
724         if (!features) {
725                 return -1;
726         }
727         ast_set_flag(&features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE);
728
729         cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
730         if (!cap) {
731                 ast_bridge_features_destroy(features);
732                 return -1;
733         }
734         ast_format_cap_append(cap, ast_format_slin, 0);
735
736         /* Create the recording channel. */
737         chan = ast_request("CBRec", cap, NULL, NULL, conference->name, NULL);
738         ao2_ref(cap, -1);
739         if (!chan) {
740                 ast_bridge_features_destroy(features);
741                 return -1;
742         }
743
744         /* Start recording. */
745         set_rec_filename(conference, &conference->record_filename,
746                 is_new_rec_file(conference->b_profile.rec_file, &conference->orig_rec_file));
747         ast_answer(chan);
748         pbx_exec(chan, mixmonapp, ast_str_buffer(conference->record_filename));
749
750         /* Put the channel into the conference bridge. */
751         ast_channel_ref(chan);
752         conference->record_chan = chan;
753         if (ast_bridge_impart(conference->bridge, chan, NULL, features,
754                 AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
755                 ast_hangup(chan);
756                 ast_channel_unref(chan);
757                 conference->record_chan = NULL;
758                 return -1;
759         }
760
761         ast_test_suite_event_notify("CONF_START_RECORD", "Message: started conference recording channel\r\nConference: %s", conference->b_profile.name);
762         send_start_record_event(conference);
763
764         return 0;
765 }
766
767 /* \brief Playback the given filename and monitor for any dtmf interrupts.
768  *
769  * This function is used to playback sound files on a given channel and optionally
770  * allow dtmf interrupts to occur.
771  *
772  * If the optional bridge_channel parameter is given then sound file playback
773  * is played on that channel and dtmf interruptions are allowed. However, if
774  * bridge_channel is not set then the channel parameter is expected to be set
775  * instead and non interruptible playback is played on that channel.
776  *
777  * \param bridge_channel Bridge channel to play file on
778  * \param channel Optional channel to play file on if bridge_channel not given
779  * \param filename The file name to playback
780  *
781  * \retval -1 failure during playback, 0 on file was fully played, 1 on dtmf interrupt.
782  */
783 static int play_file(struct ast_bridge_channel *bridge_channel, struct ast_channel *channel,
784                      const char *filename)
785 {
786         struct ast_channel *chan;
787         const char *stop_digits;
788         int digit;
789
790         if (bridge_channel) {
791                 chan = bridge_channel->chan;
792                 stop_digits = AST_DIGIT_ANY;
793         } else {
794                 chan = channel;
795                 stop_digits = AST_DIGIT_NONE;
796         }
797
798         digit = ast_stream_and_wait(chan, filename, stop_digits);
799         if (digit < 0) {
800                 ast_log(LOG_WARNING, "Failed to playback file '%s' to channel\n", filename);
801                 return -1;
802         }
803
804         if (digit > 0) {
805                 ast_stopstream(bridge_channel->chan);
806                 ast_bridge_channel_feature_digit_add(bridge_channel, digit);
807                 return 1;
808         }
809
810         return 0;
811 }
812
813 /*!
814  * \internal
815  * \brief Complain if the given sound file does not exist.
816  *
817  * \param filename Sound file to check if exists.
818  *
819  * \retval non-zero if the file exists.
820  */
821 static int sound_file_exists(const char *filename)
822 {
823         if (ast_fileexists(filename, NULL, NULL)) {
824                 return -1;
825         }
826         ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
827         return 0;
828 }
829
830 /*!
831  * \brief Announce number of users in the conference bridge to the caller
832  *
833  * \param conference Conference bridge to peek at
834  * \param user Optional Caller
835  * \param bridge_channel The bridged channel involved
836  *
837  * \note if caller is NULL, the announcment will be sent to all participants in the conference.
838  * \return Returns 0 on success, -1 if the user hung up
839  */
840 static int announce_user_count(struct confbridge_conference *conference, struct confbridge_user *user,
841                                struct ast_bridge_channel *bridge_channel)
842 {
843         const char *other_in_party = conf_get_sound(CONF_SOUND_OTHER_IN_PARTY, conference->b_profile.sounds);
844         const char *only_one = conf_get_sound(CONF_SOUND_ONLY_ONE, conference->b_profile.sounds);
845         const char *there_are = conf_get_sound(CONF_SOUND_THERE_ARE, conference->b_profile.sounds);
846
847         if (conference->activeusers <= 1) {
848                 /* Awww we are the only person in the conference bridge OR we only have waitmarked users */
849                 return 0;
850         } else if (conference->activeusers == 2) {
851                 if (user) {
852                         /* Eep, there is one other person */
853                         if (play_file(bridge_channel, user->chan, only_one) < 0) {
854                                 return -1;
855                         }
856                 } else {
857                         play_sound_file(conference, only_one);
858                 }
859         } else {
860                 /* Alas multiple others in here */
861                 if (user) {
862                         if (ast_stream_and_wait(user->chan,
863                                 there_are,
864                                 "")) {
865                                 return -1;
866                         }
867                         if (ast_say_number(user->chan, conference->activeusers - 1, "", ast_channel_language(user->chan), NULL)) {
868                                 return -1;
869                         }
870                         if (play_file(bridge_channel, user->chan, other_in_party) < 0) {
871                                 return -1;
872                         }
873                 } else if (sound_file_exists(there_are) && sound_file_exists(other_in_party)) {
874                         play_sound_file(conference, there_are);
875                         play_sound_number(conference, conference->activeusers - 1);
876                         play_sound_file(conference, other_in_party);
877                 }
878         }
879         return 0;
880 }
881
882 /*!
883  * \brief Play back an audio file to a channel
884  *
885  * \param user User to play audio prompt to
886  * \param filename Prompt to play
887  *
888  * \return Returns 0 on success, -1 if the user hung up
889  * \note Generally this should be called when the conference is unlocked to avoid blocking
890  * the entire conference while the sound is played. But don't unlock the conference bridge
891  * in the middle of a state transition.
892  */
893 static int play_prompt_to_user(struct confbridge_user *user, const char *filename)
894 {
895         return ast_stream_and_wait(user->chan, filename, "");
896 }
897
898 static void handle_video_on_join(struct confbridge_conference *conference, struct ast_channel *chan, int marked)
899 {
900         /* Right now, only marked users are automatically set as the single src of video.*/
901         if (!marked) {
902                 return;
903         }
904
905         if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED)) {
906                 int set = 1;
907                 struct confbridge_user *user = NULL;
908
909                 ao2_lock(conference);
910                 /* see if anyone is already the video src */
911                 AST_LIST_TRAVERSE(&conference->active_list, user, list) {
912                         if (user->chan == chan) {
913                                 continue;
914                         }
915                         if (ast_bridge_is_video_src(conference->bridge, user->chan)) {
916                                 set = 0;
917                                 break;
918                         }
919                 }
920                 ao2_unlock(conference);
921                 if (set) {
922                         ast_bridge_set_single_src_video_mode(conference->bridge, chan);
923                 }
924         } else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED)) {
925                 /* we joined and are video capable, we override anyone else that may have already been the video feed */
926                 ast_bridge_set_single_src_video_mode(conference->bridge, chan);
927         }
928 }
929
930 static void handle_video_on_exit(struct confbridge_conference *conference, struct ast_channel *chan)
931 {
932         struct confbridge_user *user = NULL;
933
934         /* if this isn't a video source, nothing to update */
935         if (!ast_bridge_is_video_src(conference->bridge, chan)) {
936                 return;
937         }
938
939         ast_bridge_remove_video_src(conference->bridge, chan);
940
941         /* If in follow talker mode, make sure to restore this mode on the
942          * bridge when a source is removed.  It is possible this channel was
943          * only set temporarily as a video source by an AMI or DTMF action. */
944         if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) {
945                 ast_bridge_set_talker_src_video_mode(conference->bridge);
946         }
947
948         /* if the video_mode isn't set to automatically pick the video source, do nothing on exit. */
949         if (!ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED) &&
950                 !ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED)) {
951                 return;
952         }
953
954         /* Make the next available marked user the video src.  */
955         ao2_lock(conference);
956         AST_LIST_TRAVERSE(&conference->active_list, user, list) {
957                 if (user->chan == chan) {
958                         continue;
959                 }
960                 if (ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)) {
961                         ast_bridge_set_single_src_video_mode(conference->bridge, user->chan);
962                         break;
963                 }
964         }
965         ao2_unlock(conference);
966 }
967
968 struct hangup_data
969 {
970         struct confbridge_conference *conference;
971         ast_mutex_t lock;
972         ast_cond_t cond;
973         int hungup;
974 };
975
976 /*!
977  * \brief Hang up the announcer channel
978  *
979  * This hangs up the announcer channel in the conference. This
980  * runs in the playback queue taskprocessor since we do not want
981  * to hang up the channel while it's trying to play an announcement.
982  *
983  * This task is performed synchronously, so there is no need to
984  * perform any cleanup on the passed-in data.
985  *
986  * \param data A hangup_data structure
987  * \return 0
988  */
989 static int hangup_playback(void *data)
990 {
991         struct hangup_data *hangup = data;
992
993         ast_autoservice_stop(hangup->conference->playback_chan);
994
995         ast_hangup(hangup->conference->playback_chan);
996         hangup->conference->playback_chan = NULL;
997
998         ast_mutex_lock(&hangup->lock);
999         hangup->hungup = 1;
1000         ast_cond_signal(&hangup->cond);
1001         ast_mutex_unlock(&hangup->lock);
1002
1003         return 0;
1004 }
1005
1006 static void hangup_data_init(struct hangup_data *hangup, struct confbridge_conference *conference)
1007 {
1008         ast_mutex_init(&hangup->lock);
1009         ast_cond_init(&hangup->cond, NULL);
1010
1011         hangup->conference = conference;
1012         hangup->hungup = 0;
1013 }
1014
1015 static void hangup_data_destroy(struct hangup_data *hangup)
1016 {
1017         ast_mutex_destroy(&hangup->lock);
1018         ast_cond_destroy(&hangup->cond);
1019 }
1020
1021 /*!
1022  * \brief Destroy a conference bridge
1023  *
1024  * \param obj The conference bridge object
1025  *
1026  * \return Returns nothing
1027  */
1028 static void destroy_conference_bridge(void *obj)
1029 {
1030         struct confbridge_conference *conference = obj;
1031
1032         ast_debug(1, "Destroying conference bridge '%s'\n", conference->name);
1033
1034         if (conference->playback_chan) {
1035                 if (conference->playback_queue) {
1036                         struct hangup_data hangup;
1037                         hangup_data_init(&hangup, conference);
1038                         ast_taskprocessor_push(conference->playback_queue, hangup_playback, &hangup);
1039
1040                         ast_mutex_lock(&hangup.lock);
1041                         while (!hangup.hungup) {
1042                                 ast_cond_wait(&hangup.cond, &hangup.lock);
1043                         }
1044                         ast_mutex_unlock(&hangup.lock);
1045                         hangup_data_destroy(&hangup);
1046                 } else {
1047                         /* Playback queue is not yet allocated. Just hang up the channel straight */
1048                         ast_hangup(conference->playback_chan);
1049                         conference->playback_chan = NULL;
1050                 }
1051         }
1052
1053         /* Destroying a conference bridge is simple, all we have to do is destroy the bridging object */
1054         if (conference->bridge) {
1055                 ast_bridge_destroy(conference->bridge, 0);
1056                 conference->bridge = NULL;
1057         }
1058
1059         ast_channel_cleanup(conference->record_chan);
1060         ast_free(conference->orig_rec_file);
1061         ast_free(conference->record_filename);
1062
1063         conf_bridge_profile_destroy(&conference->b_profile);
1064         ast_taskprocessor_unreference(conference->playback_queue);
1065 }
1066
1067 /*! \brief Call the proper join event handler for the user for the conference bridge's current state
1068  * \internal
1069  * \param user The conference bridge user that is joining
1070  * \retval 0 success
1071  * \retval -1 failure
1072  */
1073 static int handle_conf_user_join(struct confbridge_user *user)
1074 {
1075         conference_event_fn handler;
1076         if (ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)) {
1077                 handler = user->conference->state->join_marked;
1078         } else if (ast_test_flag(&user->u_profile, USER_OPT_WAITMARKED)) {
1079                 handler = user->conference->state->join_waitmarked;
1080         } else {
1081                 handler = user->conference->state->join_unmarked;
1082         }
1083
1084         ast_assert(handler != NULL);
1085
1086         if (!handler) {
1087                 conf_invalid_event_fn(user);
1088                 return -1;
1089         }
1090
1091         handler(user);
1092
1093         return 0;
1094 }
1095
1096 /*! \brief Call the proper leave event handler for the user for the conference bridge's current state
1097  * \internal
1098  * \param user The conference bridge user that is leaving
1099  * \retval 0 success
1100  * \retval -1 failure
1101  */
1102 static int handle_conf_user_leave(struct confbridge_user *user)
1103 {
1104         conference_event_fn handler;
1105         if (ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)) {
1106                 handler = user->conference->state->leave_marked;
1107         } else if (ast_test_flag(&user->u_profile, USER_OPT_WAITMARKED)) {
1108                 handler = user->conference->state->leave_waitmarked;
1109         } else {
1110                 handler = user->conference->state->leave_unmarked;
1111         }
1112
1113         ast_assert(handler != NULL);
1114
1115         if (!handler) {
1116                 /* This should never happen. If it does, though, it is bad. The user will not have been removed
1117                  * from the appropriate list, so counts will be off and stuff. The conference won't be torn down, etc.
1118                  * Shouldn't happen, though. */
1119                 conf_invalid_event_fn(user);
1120                 return -1;
1121         }
1122
1123         handler(user);
1124
1125         return 0;
1126 }
1127
1128 void conf_update_user_mute(struct confbridge_user *user)
1129 {
1130         int mute_user;
1131         int mute_system;
1132         int mute_effective;
1133
1134         /* User level mute request. */
1135         mute_user = user->muted;
1136
1137         /* System level mute request. */
1138         mute_system = user->playing_moh
1139                 /*
1140                  * Do not allow waitmarked users to talk to anyone unless there
1141                  * is a marked user present.
1142                  */
1143                 || (!user->conference->markedusers
1144                         && ast_test_flag(&user->u_profile, USER_OPT_WAITMARKED));
1145
1146         mute_effective = mute_user || mute_system;
1147
1148         ast_debug(1, "User %s is %s: user:%d system:%d.\n",
1149                 ast_channel_name(user->chan), mute_effective ? "muted" : "unmuted",
1150                 mute_user, mute_system);
1151         user->features.mute = mute_effective;
1152         ast_test_suite_event_notify("CONF_MUTE_UPDATE",
1153                 "Mode: %s\r\n"
1154                 "Conference: %s\r\n"
1155                 "Channel: %s",
1156                 mute_effective ? "muted" : "unmuted",
1157                 user->conference->b_profile.name,
1158                 ast_channel_name(user->chan));
1159 }
1160
1161 /*
1162  * \internal
1163  * \brief Mute/unmute a single user.
1164  */
1165 static void generic_mute_unmute_user(struct confbridge_conference *conference, struct confbridge_user *user, int mute)
1166 {
1167         /* Set user level mute request. */
1168         user->muted = mute ? 1 : 0;
1169
1170         conf_update_user_mute(user);
1171         ast_test_suite_event_notify("CONF_MUTE",
1172                 "Message: participant %s %s\r\n"
1173                 "Conference: %s\r\n"
1174                 "Channel: %s",
1175                 ast_channel_name(user->chan),
1176                 mute ? "muted" : "unmuted",
1177                 conference->b_profile.name,
1178                 ast_channel_name(user->chan));
1179         if (mute) {
1180                 send_mute_event(user, conference);
1181         } else {
1182                 send_unmute_event(user, conference);
1183         }
1184 }
1185
1186 void conf_moh_stop(struct confbridge_user *user)
1187 {
1188         user->playing_moh = 0;
1189         if (!user->suspended_moh) {
1190                 int in_bridge;
1191
1192                 /*
1193                  * Locking the ast_bridge here is the only way to hold off the
1194                  * call to ast_bridge_join() in confbridge_exec() from
1195                  * interfering with the bridge and MOH operations here.
1196                  */
1197                 ast_bridge_lock(user->conference->bridge);
1198
1199                 /*
1200                  * Temporarily suspend the user from the bridge so we have
1201                  * control to stop MOH if needed.
1202                  */
1203                 in_bridge = !ast_bridge_suspend(user->conference->bridge, user->chan);
1204                 ast_moh_stop(user->chan);
1205                 if (in_bridge) {
1206                         ast_bridge_unsuspend(user->conference->bridge, user->chan);
1207                 }
1208
1209                 ast_bridge_unlock(user->conference->bridge);
1210         }
1211 }
1212
1213 void conf_moh_start(struct confbridge_user *user)
1214 {
1215         user->playing_moh = 1;
1216         if (!user->suspended_moh) {
1217                 int in_bridge;
1218
1219                 /*
1220                  * Locking the ast_bridge here is the only way to hold off the
1221                  * call to ast_bridge_join() in confbridge_exec() from
1222                  * interfering with the bridge and MOH operations here.
1223                  */
1224                 ast_bridge_lock(user->conference->bridge);
1225
1226                 /*
1227                  * Temporarily suspend the user from the bridge so we have
1228                  * control to start MOH if needed.
1229                  */
1230                 in_bridge = !ast_bridge_suspend(user->conference->bridge, user->chan);
1231                 ast_moh_start(user->chan, user->u_profile.moh_class, NULL);
1232                 if (in_bridge) {
1233                         ast_bridge_unsuspend(user->conference->bridge, user->chan);
1234                 }
1235
1236                 ast_bridge_unlock(user->conference->bridge);
1237         }
1238 }
1239
1240 /*!
1241  * \internal
1242  * \brief Unsuspend MOH for the conference user.
1243  *
1244  * \param user Conference user to unsuspend MOH on.
1245  *
1246  * \return Nothing
1247  */
1248 static void conf_moh_unsuspend(struct confbridge_user *user)
1249 {
1250         ao2_lock(user->conference);
1251         if (--user->suspended_moh == 0 && user->playing_moh) {
1252                 ast_moh_start(user->chan, user->u_profile.moh_class, NULL);
1253         }
1254         ao2_unlock(user->conference);
1255 }
1256
1257 /*!
1258  * \internal
1259  * \brief Suspend MOH for the conference user.
1260  *
1261  * \param user Conference user to suspend MOH on.
1262  *
1263  * \return Nothing
1264  */
1265 static void conf_moh_suspend(struct confbridge_user *user)
1266 {
1267         ao2_lock(user->conference);
1268         if (user->suspended_moh++ == 0 && user->playing_moh) {
1269                 ast_moh_stop(user->chan);
1270         }
1271         ao2_unlock(user->conference);
1272 }
1273
1274 int conf_handle_inactive_waitmarked(struct confbridge_user *user)
1275 {
1276         /* If we have not been quieted play back that they are waiting for the leader */
1277         if (!ast_test_flag(&user->u_profile, USER_OPT_QUIET) && play_prompt_to_user(user,
1278                         conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, user->conference->b_profile.sounds))) {
1279                 /* user hungup while the sound was playing */
1280                 return -1;
1281         }
1282         return 0;
1283 }
1284
1285 int conf_handle_only_unmarked(struct confbridge_user *user)
1286 {
1287         /* If audio prompts have not been quieted or this prompt quieted play it on out */
1288         if (!ast_test_flag(&user->u_profile, USER_OPT_QUIET | USER_OPT_NOONLYPERSON)) {
1289                 if (play_prompt_to_user(user,
1290                         conf_get_sound(CONF_SOUND_ONLY_PERSON, user->conference->b_profile.sounds))) {
1291                         /* user hungup while the sound was playing */
1292                         return -1;
1293                 }
1294         }
1295         return 0;
1296 }
1297
1298 int conf_add_post_join_action(struct confbridge_user *user, int (*func)(struct confbridge_user *user))
1299 {
1300         struct post_join_action *action;
1301         if (!(action = ast_calloc(1, sizeof(*action)))) {
1302                 return -1;
1303         }
1304         action->func = func;
1305         AST_LIST_INSERT_TAIL(&user->post_join_list, action, list);
1306         return 0;
1307 }
1308
1309
1310 void conf_handle_first_join(struct confbridge_conference *conference)
1311 {
1312         ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "confbridge:%s", conference->name);
1313 }
1314
1315 void conf_handle_second_active(struct confbridge_conference *conference)
1316 {
1317         /* If we are the second participant we may need to stop music on hold on the first */
1318         struct confbridge_user *first_user = AST_LIST_FIRST(&conference->active_list);
1319
1320         if (ast_test_flag(&first_user->u_profile, USER_OPT_MUSICONHOLD)) {
1321                 conf_moh_stop(first_user);
1322         }
1323         conf_update_user_mute(first_user);
1324 }
1325
1326 void conf_ended(struct confbridge_conference *conference)
1327 {
1328         struct pbx_find_info q = { .stacklen = 0 };
1329
1330         /* Called with a reference to conference */
1331         ao2_unlink(conference_bridges, conference);
1332         send_conf_end_event(conference);
1333         if (!ast_strlen_zero(conference->b_profile.regcontext) &&
1334                         pbx_find_extension(NULL, NULL, &q, conference->b_profile.regcontext,
1335                                 conference->name, 1, NULL, "", E_MATCH)) {
1336                 ast_context_remove_extension(conference->b_profile.regcontext,
1337                                 conference->name, 1, NULL);
1338         }
1339         ao2_lock(conference);
1340         conf_stop_record(conference);
1341         ao2_unlock(conference);
1342 }
1343
1344 /*!
1345  * \internal
1346  * \brief Allocate playback channel for a conference.
1347  * \pre expects conference to be locked before calling this function
1348  */
1349 static int alloc_playback_chan(struct confbridge_conference *conference)
1350 {
1351         struct ast_format_cap *cap;
1352         char taskprocessor_name[AST_TASKPROCESSOR_MAX_NAME + 1];
1353
1354         cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
1355         if (!cap) {
1356                 return -1;
1357         }
1358         ast_format_cap_append(cap, ast_format_slin, 0);
1359         conference->playback_chan = ast_request("CBAnn", cap, NULL, NULL,
1360                 conference->name, NULL);
1361         ao2_ref(cap, -1);
1362         if (!conference->playback_chan) {
1363                 return -1;
1364         }
1365
1366         /* To make sure playback_chan has the same language as the bridge */
1367         ast_channel_lock(conference->playback_chan);
1368         ast_channel_language_set(conference->playback_chan, conference->b_profile.language);
1369         ast_channel_unlock(conference->playback_chan);
1370
1371         ast_debug(1, "Created announcer channel '%s' to conference bridge '%s'\n",
1372                 ast_channel_name(conference->playback_chan), conference->name);
1373
1374         ast_taskprocessor_build_name(taskprocessor_name, sizeof(taskprocessor_name),
1375                 "Confbridge/%s", conference->name);
1376         conference->playback_queue = ast_taskprocessor_get(taskprocessor_name, TPS_REF_DEFAULT);
1377         if (!conference->playback_queue) {
1378                 ast_hangup(conference->playback_chan);
1379                 conference->playback_chan = NULL;
1380                 return -1;
1381         }
1382         return 0;
1383 }
1384
1385 /*!
1386  * \brief Push the announcer channel into the bridge
1387  *
1388  * This runs in the playback queue taskprocessor.
1389  *
1390  * \param data A confbridge_conference
1391  * \retval 0 Success
1392  * \retval -1 Failed to push the channel to the bridge
1393  */
1394 static int push_announcer(void *data)
1395 {
1396         struct confbridge_conference *conference = data;
1397
1398         if (conf_announce_channel_push(conference->playback_chan)) {
1399                 ast_hangup(conference->playback_chan);
1400                 conference->playback_chan = NULL;
1401                 ao2_cleanup(conference);
1402                 return -1;
1403         }
1404
1405         ast_autoservice_start(conference->playback_chan);
1406         ao2_cleanup(conference);
1407         return 0;
1408 }
1409
1410 /*!
1411  * \brief Join a conference bridge
1412  *
1413  * \param conference_name The conference name
1414  * \param user Conference bridge user structure
1415  *
1416  * \return A pointer to the conference bridge struct, or NULL if the conference room wasn't found.
1417  */
1418 static struct confbridge_conference *join_conference_bridge(const char *conference_name, struct confbridge_user *user)
1419 {
1420         struct confbridge_conference *conference;
1421         struct post_join_action *action;
1422         int max_members_reached = 0;
1423
1424         /* We explictly lock the conference bridges container ourselves so that other callers can not create duplicate conferences at the same */
1425         ao2_lock(conference_bridges);
1426
1427         ast_debug(1, "Trying to find conference bridge '%s'\n", conference_name);
1428
1429         /* Attempt to find an existing conference bridge */
1430         conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
1431         if (conference && conference->b_profile.max_members) {
1432                 max_members_reached = conference->b_profile.max_members > conference->activeusers ? 0 : 1;
1433         }
1434
1435         /* When finding a conference bridge that already exists make sure that it is not locked, and if so that we are not an admin */
1436         if (conference && (max_members_reached || conference->locked) && !ast_test_flag(&user->u_profile, USER_OPT_ADMIN)) {
1437                 ao2_unlock(conference_bridges);
1438                 ast_debug(1, "Conference '%s' is locked and caller is not an admin\n", conference_name);
1439                 ast_stream_and_wait(user->chan,
1440                         conf_get_sound(CONF_SOUND_LOCKED, conference->b_profile.sounds),
1441                         "");
1442                 ao2_ref(conference, -1);
1443                 return NULL;
1444         }
1445
1446         /* If no conference bridge was found see if we can create one */
1447         if (!conference) {
1448                 /* Try to allocate memory for a new conference bridge, if we fail... this won't end well. */
1449                 if (!(conference = ao2_alloc(sizeof(*conference), destroy_conference_bridge))) {
1450                         ao2_unlock(conference_bridges);
1451                         ast_log(LOG_ERROR, "Conference '%s' could not be created.\n", conference_name);
1452                         return NULL;
1453                 }
1454
1455                 /* Setup for the record channel */
1456                 conference->record_filename = ast_str_create(RECORD_FILENAME_INITIAL_SPACE);
1457                 if (!conference->record_filename) {
1458                         ao2_ref(conference, -1);
1459                         ao2_unlock(conference_bridges);
1460                         return NULL;
1461                 }
1462
1463                 /* Setup conference bridge parameters */
1464                 ast_copy_string(conference->name, conference_name, sizeof(conference->name));
1465                 conf_bridge_profile_copy(&conference->b_profile, &user->b_profile);
1466
1467                 /* Create an actual bridge that will do the audio mixing */
1468                 conference->bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_MULTIMIX,
1469                         AST_BRIDGE_FLAG_MASQUERADE_ONLY | AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY,
1470                         app, conference_name, NULL);
1471                 if (!conference->bridge) {
1472                         ao2_ref(conference, -1);
1473                         ao2_unlock(conference_bridges);
1474                         ast_log(LOG_ERROR, "Conference '%s' mixing bridge could not be created.\n", conference_name);
1475                         return NULL;
1476                 }
1477
1478                 /* Set the internal sample rate on the bridge from the bridge profile */
1479                 ast_bridge_set_internal_sample_rate(conference->bridge, conference->b_profile.internal_sample_rate);
1480                 /* Set the internal mixing interval on the bridge from the bridge profile */
1481                 ast_bridge_set_mixing_interval(conference->bridge, conference->b_profile.mix_interval);
1482                 ast_bridge_set_binaural_active(conference->bridge, ast_test_flag(&conference->b_profile, BRIDGE_OPT_BINAURAL_ACTIVE));
1483
1484                 if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) {
1485                         ast_bridge_set_talker_src_video_mode(conference->bridge);
1486                 } else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_SFU)) {
1487                         ast_bridge_set_sfu_video_mode(conference->bridge);
1488                         ast_bridge_set_video_update_discard(conference->bridge, conference->b_profile.video_update_discard);
1489                 }
1490
1491                 /* Link it into the conference bridges container */
1492                 if (!ao2_link(conference_bridges, conference)) {
1493                         ao2_ref(conference, -1);
1494                         ao2_unlock(conference_bridges);
1495                         ast_log(LOG_ERROR,
1496                                 "Conference '%s' could not be added to the conferences list.\n", conference_name);
1497                         return NULL;
1498                 }
1499
1500                 /* Set the initial state to EMPTY */
1501                 conference->state = CONF_STATE_EMPTY;
1502
1503                 if (alloc_playback_chan(conference)) {
1504                         ao2_unlink(conference_bridges, conference);
1505                         ao2_ref(conference, -1);
1506                         ao2_unlock(conference_bridges);
1507                         ast_log(LOG_ERROR, "Could not allocate announcer channel for conference '%s'\n", conference_name);
1508                         return NULL;
1509                 }
1510
1511                 if (ast_taskprocessor_push(conference->playback_queue, push_announcer, ao2_bump(conference))) {
1512                         ao2_unlink(conference_bridges, conference);
1513                         ao2_ref(conference, -1);
1514                         ao2_unlock(conference_bridges);
1515                         ast_log(LOG_ERROR, "Could not add announcer channel for conference '%s' bridge\n", conference_name);
1516                         return NULL;
1517                 }
1518
1519                 if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_RECORD_CONFERENCE)) {
1520                         ao2_lock(conference);
1521                         conf_start_record(conference);
1522                         ao2_unlock(conference);
1523                 }
1524
1525                 send_conf_start_event(conference);
1526
1527                 if (!ast_strlen_zero(conference->b_profile.regcontext)) {
1528                         if (!ast_exists_extension(NULL, conference->b_profile.regcontext, conference->name, 1, NULL)) {
1529                                 ast_add_extension(conference->b_profile.regcontext, 1, conference->name, 1, NULL, NULL, "Noop", NULL, NULL, "ConfBridge");
1530                         }
1531                 }
1532
1533                 ast_debug(1, "Created conference '%s' and linked to container.\n", conference_name);
1534         }
1535
1536         ao2_unlock(conference_bridges);
1537
1538         /* Setup conference bridge user parameters */
1539         user->conference = conference;
1540
1541         ao2_lock(conference);
1542
1543         /* Determine if the new user should join the conference muted. */
1544         if (ast_test_flag(&user->u_profile, USER_OPT_STARTMUTED)
1545                 || (!ast_test_flag(&user->u_profile, USER_OPT_ADMIN) && conference->muted)) {
1546                 /* Set user level mute request. */
1547                 user->muted = 1;
1548         }
1549
1550         /*
1551          * Suspend any MOH until the user actually joins the bridge of
1552          * the conference.  This way any pre-join file playback does not
1553          * need to worry about MOH.
1554          */
1555         user->suspended_moh = 1;
1556
1557         if (handle_conf_user_join(user)) {
1558                 /* Invalid event, nothing was done, so we don't want to process a leave. */
1559                 ao2_unlock(conference);
1560                 ao2_ref(conference, -1);
1561                 user->conference = NULL;
1562                 return NULL;
1563         }
1564
1565         if (ast_check_hangup(user->chan)) {
1566                 ao2_unlock(conference);
1567                 leave_conference(user);
1568                 return NULL;
1569         }
1570
1571         ao2_unlock(conference);
1572
1573         /* If an announcement is to be played play it */
1574         if (!ast_strlen_zero(user->u_profile.announcement)) {
1575                 if (play_prompt_to_user(user,
1576                         user->u_profile.announcement)) {
1577                         leave_conference(user);
1578                         return NULL;
1579                 }
1580         }
1581
1582         /* Announce number of users if need be */
1583         if (ast_test_flag(&user->u_profile, USER_OPT_ANNOUNCEUSERCOUNT)) {
1584                 if (announce_user_count(conference, user, NULL)) {
1585                         leave_conference(user);
1586                         return NULL;
1587                 }
1588         }
1589
1590         if (ast_test_flag(&user->u_profile, USER_OPT_ANNOUNCEUSERCOUNTALL) &&
1591                 (conference->activeusers > user->u_profile.announce_user_count_all_after)) {
1592                 int user_count_res;
1593
1594                 /*
1595                  * We have to autoservice the new user because he has not quite
1596                  * joined the conference yet.
1597                  */
1598                 ast_autoservice_start(user->chan);
1599                 user_count_res = announce_user_count(conference, NULL, NULL);
1600                 ast_autoservice_stop(user->chan);
1601                 if (user_count_res) {
1602                         leave_conference(user);
1603                         return NULL;
1604                 }
1605         }
1606
1607         /* Handle post-join actions */
1608         while ((action = AST_LIST_REMOVE_HEAD(&user->post_join_list, list))) {
1609                 action->func(user);
1610                 ast_free(action);
1611         }
1612
1613         return conference;
1614 }
1615
1616 /*!
1617  * \brief Leave a conference
1618  *
1619  * \param user The conference user
1620  */
1621 static void leave_conference(struct confbridge_user *user)
1622 {
1623         struct post_join_action *action;
1624
1625         ao2_lock(user->conference);
1626         handle_conf_user_leave(user);
1627         ao2_unlock(user->conference);
1628
1629         /* Discard any post-join actions */
1630         while ((action = AST_LIST_REMOVE_HEAD(&user->post_join_list, list))) {
1631                 ast_free(action);
1632         }
1633
1634         /* Done mucking with the conference, huzzah */
1635         ao2_ref(user->conference, -1);
1636         user->conference = NULL;
1637 }
1638
1639 static void playback_common(struct confbridge_conference *conference, const char *filename, int say_number)
1640 {
1641         /* Don't try to play if the playback channel has been hung up */
1642         if (!conference->playback_chan) {
1643                 return;
1644         }
1645
1646         ast_autoservice_stop(conference->playback_chan);
1647
1648         /* The channel is all under our control, in goes the prompt */
1649         if (!ast_strlen_zero(filename)) {
1650                 ast_stream_and_wait(conference->playback_chan, filename, "");
1651         } else if (say_number >= 0) {
1652                 ast_say_number(conference->playback_chan, say_number, "",
1653                         ast_channel_language(conference->playback_chan), NULL);
1654         }
1655
1656         ast_autoservice_start(conference->playback_chan);
1657 }
1658
1659 struct playback_task_data {
1660         struct confbridge_conference *conference;
1661         const char *filename;
1662         int say_number;
1663         int playback_finished;
1664         ast_mutex_t lock;
1665         ast_cond_t cond;
1666 };
1667
1668 /*!
1669  * \brief Play an announcement into a confbridge
1670  *
1671  * This runs in the playback queue taskprocessor. This ensures that
1672  * all playbacks are handled in sequence and do not play over top one
1673  * another.
1674  *
1675  * This task runs synchronously so there is no need for performing any
1676  * sort of cleanup on the input parameter.
1677  *
1678  * \param data A playback_task_data
1679  * \return 0
1680  */
1681 static int playback_task(void *data)
1682 {
1683         struct playback_task_data *ptd = data;
1684
1685         playback_common(ptd->conference, ptd->filename, ptd->say_number);
1686
1687         ast_mutex_lock(&ptd->lock);
1688         ptd->playback_finished = 1;
1689         ast_cond_signal(&ptd->cond);
1690         ast_mutex_unlock(&ptd->lock);
1691
1692         return 0;
1693 }
1694
1695 static void playback_task_data_init(struct playback_task_data *ptd, struct confbridge_conference *conference,
1696                 const char *filename, int say_number)
1697 {
1698         ast_mutex_init(&ptd->lock);
1699         ast_cond_init(&ptd->cond, NULL);
1700
1701         ptd->filename = filename;
1702         ptd->say_number = say_number;
1703         ptd->conference = conference;
1704         ptd->playback_finished = 0;
1705 }
1706
1707 static void playback_task_data_destroy(struct playback_task_data *ptd)
1708 {
1709         ast_mutex_destroy(&ptd->lock);
1710         ast_cond_destroy(&ptd->cond);
1711 }
1712
1713 static int play_sound_helper(struct confbridge_conference *conference, const char *filename, int say_number)
1714 {
1715         struct playback_task_data ptd;
1716
1717         /* Do not waste resources trying to play files that do not exist */
1718         if (ast_strlen_zero(filename)) {
1719                 if (say_number < 0) {
1720                         return 0;
1721                 }
1722         } else if (!sound_file_exists(filename)) {
1723                 return 0;
1724         }
1725
1726         playback_task_data_init(&ptd, conference, filename, say_number);
1727         if (ast_taskprocessor_push(conference->playback_queue, playback_task, &ptd)) {
1728                 if (!ast_strlen_zero(filename)) {
1729                         ast_log(LOG_WARNING, "Unable to play file '%s' to conference %s\n",
1730                                 filename, conference->name);
1731                 } else {
1732                         ast_log(LOG_WARNING, "Unable to say number '%d' to conference %s\n",
1733                                 say_number, conference->name);
1734                 }
1735                 playback_task_data_destroy(&ptd);
1736                 return -1;
1737         }
1738
1739         /* Wait for the playback to complete */
1740         ast_mutex_lock(&ptd.lock);
1741         while (!ptd.playback_finished) {
1742                 ast_cond_wait(&ptd.cond, &ptd.lock);
1743         }
1744         ast_mutex_unlock(&ptd.lock);
1745
1746         playback_task_data_destroy(&ptd);
1747
1748         return 0;
1749 }
1750
1751 int play_sound_file(struct confbridge_conference *conference, const char *filename)
1752 {
1753         return play_sound_helper(conference, filename, -1);
1754 }
1755
1756 struct async_playback_task_data {
1757         struct confbridge_conference *conference;
1758         int say_number;
1759         struct ast_channel *initiator;
1760         char filename[0];
1761 };
1762
1763 struct async_datastore_data {
1764         ast_mutex_t lock;
1765         ast_cond_t cond;
1766         int wait;
1767 };
1768
1769 static void async_datastore_data_destroy(void *data)
1770 {
1771         struct async_datastore_data *add = data;
1772
1773         ast_mutex_destroy(&add->lock);
1774         ast_cond_destroy(&add->cond);
1775
1776         ast_free(add);
1777 }
1778
1779 /*!
1780  * \brief Datastore used for timing of async announcement playback
1781  *
1782  * Announcements that are played to the entire conference can be played
1783  * asynchronously (i.e. The channel that queues the playback does not wait
1784  * for the playback to complete before continuing)
1785  *
1786  * The thing about async announcements is that the channel that queues the
1787  * announcement is either not in the bridge or is in some other way "occupied"
1788  * at the time the announcement is queued. Because of that, the initiator of
1789  * the announcement may enter after the announcement has already started,
1790  * resulting in the sound being "clipped".
1791  *
1792  * This datastore makes it so that the channel that queues the async announcement
1793  * can say "I'm ready now". This way the announcement does not start until the
1794  * initiator of the announcement is ready to hear the sound.
1795  */
1796 static struct ast_datastore_info async_datastore_info = {
1797         .type = "Confbridge async playback",
1798         .destroy = async_datastore_data_destroy,
1799 };
1800
1801 static struct async_datastore_data *async_datastore_data_alloc(void)
1802 {
1803         struct async_datastore_data *add;
1804
1805         add = ast_malloc(sizeof(*add));
1806         if (!add) {
1807                 return NULL;
1808         }
1809
1810         ast_mutex_init(&add->lock);
1811         ast_cond_init(&add->cond, NULL);
1812         add->wait = 1;
1813
1814         return add;
1815 }
1816
1817 /*!
1818  * \brief Prepare the async playback datastore
1819  *
1820  * This is done prior to queuing an async announcement. If the
1821  * datastore has not yet been created, it is allocated and initialized.
1822  * If it already exists, we set it to be in "waiting" mode.
1823  *
1824  * \param initiator The channel that is queuing the async playback
1825  * \retval 0 Success
1826  * \retval -1 Failure :(
1827  */
1828 static int setup_async_playback_datastore(struct ast_channel *initiator)
1829 {
1830         struct ast_datastore *async_datastore;
1831
1832         async_datastore = ast_channel_datastore_find(initiator, &async_datastore_info, NULL);
1833         if (async_datastore) {
1834                 struct async_datastore_data *add;
1835
1836                 add = async_datastore->data;
1837                 add->wait = 1;
1838
1839                 return 0;
1840         }
1841
1842         async_datastore = ast_datastore_alloc(&async_datastore_info, NULL);
1843         if (!async_datastore) {
1844                 return -1;
1845         }
1846
1847         async_datastore->data = async_datastore_data_alloc();
1848         if (!async_datastore->data) {
1849                 ast_datastore_free(async_datastore);
1850                 return -1;
1851         }
1852
1853         ast_channel_datastore_add(initiator, async_datastore);
1854         return 0;
1855 }
1856
1857 static struct async_playback_task_data *async_playback_task_data_alloc(
1858         struct confbridge_conference *conference, const char *filename, int say_number,
1859         struct ast_channel *initiator)
1860 {
1861         struct async_playback_task_data *aptd;
1862
1863         aptd = ast_malloc(sizeof(*aptd) + strlen(filename) + 1);
1864         if (!aptd) {
1865                 return NULL;
1866         }
1867
1868         /* Safe */
1869         strcpy(aptd->filename, filename);
1870         aptd->say_number = say_number;
1871
1872         /* You may think that we need to bump the conference refcount since we are pushing
1873          * this task to the taskprocessor.
1874          *
1875          * In this case, that actually causes a problem. The destructor for the conference
1876          * pushes a hangup task into the taskprocessor and waits for it to complete before
1877          * continuing. If the destructor gets called from a taskprocessor task, we're
1878          * deadlocked.
1879          *
1880          * So is there a risk of the conference being freed out from under us? No. Since
1881          * the destructor pushes a task into the taskprocessor and waits for it to complete,
1882          * the destructor cannot free the conference out from under us. No further tasks
1883          * can be queued onto the taskprocessor after the hangup since no channels are referencing
1884          * the conference at that point any more.
1885          */
1886         aptd->conference = conference;
1887
1888         aptd->initiator = initiator;
1889         if (initiator) {
1890                 ast_channel_ref(initiator);
1891                 ast_channel_lock(aptd->initiator);
1892                 /* We don't really care if this fails. If the datastore fails to get set up
1893                  * we'll still play the announcement. It's possible that the sound will be
1894                  * clipped for the initiator, but that's not the end of the world.
1895                  */
1896                 setup_async_playback_datastore(aptd->initiator);
1897                 ast_channel_unlock(aptd->initiator);
1898         }
1899
1900         return aptd;
1901 }
1902
1903 static void async_playback_task_data_destroy(struct async_playback_task_data *aptd)
1904 {
1905         ast_channel_cleanup(aptd->initiator);
1906         ast_free(aptd);
1907 }
1908
1909 /*!
1910  * \brief Wait for the initiator of an async playback to be ready
1911  *
1912  * See the description on the async_datastore_info structure for more
1913  * information about what this is about.
1914  *
1915  * \param initiator The channel that queued the async announcement
1916  */
1917 static void wait_for_initiator(struct ast_channel *initiator)
1918 {
1919         struct ast_datastore *async_datastore;
1920         struct async_datastore_data *add;
1921
1922         ast_channel_lock(initiator);
1923         async_datastore = ast_channel_datastore_find(initiator, &async_datastore_info, NULL);
1924         ast_channel_unlock(initiator);
1925
1926         if (!async_datastore) {
1927                 return;
1928         }
1929
1930         add = async_datastore->data;
1931
1932         ast_mutex_lock(&add->lock);
1933         while (add->wait) {
1934                 ast_cond_wait(&add->cond, &add->lock);
1935         }
1936         ast_mutex_unlock(&add->lock);
1937 }
1938
1939 /*!
1940  * \brief Play an announcement into a confbridge asynchronously
1941  *
1942  * This runs in the playback queue taskprocessor. This ensures that
1943  * all playbacks are handled in sequence and do not play over top one
1944  * another.
1945  *
1946  * \param data An async_playback_task_data
1947  * \return 0
1948  */
1949 static int async_playback_task(void *data)
1950 {
1951         struct async_playback_task_data *aptd = data;
1952
1953         /* Wait for the initiator to get back in the bridge or be hung up */
1954         if (aptd->initiator) {
1955                 wait_for_initiator(aptd->initiator);
1956         }
1957
1958         playback_common(aptd->conference, aptd->filename, aptd->say_number);
1959
1960         async_playback_task_data_destroy(aptd);
1961         return 0;
1962 }
1963
1964 static int async_play_sound_helper(struct confbridge_conference *conference,
1965         const char *filename, int say_number, struct ast_channel *initiator)
1966 {
1967         struct async_playback_task_data *aptd;
1968
1969         /* Do not waste resources trying to play files that do not exist */
1970         if (ast_strlen_zero(filename)) {
1971                 if (say_number < 0) {
1972                         return 0;
1973                 }
1974         } else if (!sound_file_exists(filename)) {
1975                 return 0;
1976         }
1977
1978         aptd = async_playback_task_data_alloc(conference, filename, say_number, initiator);
1979         if (!aptd) {
1980                 return -1;
1981         }
1982
1983         if (ast_taskprocessor_push(conference->playback_queue, async_playback_task, aptd)) {
1984                 if (!ast_strlen_zero(filename)) {
1985                         ast_log(LOG_WARNING, "Unable to play file '%s' to conference '%s'\n",
1986                                 filename, conference->name);
1987                 } else {
1988                         ast_log(LOG_WARNING, "Unable to say number '%d' to conference '%s'\n",
1989                                 say_number, conference->name);
1990                 }
1991                 async_playback_task_data_destroy(aptd);
1992                 return -1;
1993         }
1994
1995         return 0;
1996 }
1997
1998 int async_play_sound_file(struct confbridge_conference *conference,
1999         const char *filename, struct ast_channel *initiator)
2000 {
2001         return async_play_sound_helper(conference, filename, -1, initiator);
2002 }
2003
2004 void async_play_sound_ready(struct ast_channel *chan)
2005 {
2006         struct ast_datastore *async_datastore;
2007         struct async_datastore_data *add;
2008
2009         ast_channel_lock(chan);
2010         async_datastore = ast_channel_datastore_find(chan, &async_datastore_info, NULL);
2011         ast_channel_unlock(chan);
2012         if (!async_datastore) {
2013                 return;
2014         }
2015
2016         add = async_datastore->data;
2017
2018         ast_mutex_lock(&add->lock);
2019         add->wait = 0;
2020         ast_cond_signal(&add->cond);
2021         ast_mutex_unlock(&add->lock);
2022 }
2023
2024 /*!
2025  * \brief Play number into the conference bridge
2026  *
2027  * \param conference The conference bridge to say the number into
2028  * \param say_number number to say
2029  *
2030  * \retval 0 success
2031  * \retval -1 failure
2032  */
2033 static int play_sound_number(struct confbridge_conference *conference, int say_number)
2034 {
2035         return play_sound_helper(conference, NULL, say_number);
2036 }
2037
2038 static int conf_handle_talker_cb(struct ast_bridge_channel *bridge_channel, void *hook_pvt, int talking)
2039 {
2040         const struct confbridge_user *user = hook_pvt;
2041         RAII_VAR(struct confbridge_conference *, conference, NULL, ao2_cleanup);
2042         struct ast_json *talking_extras;
2043
2044         conference = ao2_find(conference_bridges, user->conference->name, OBJ_KEY);
2045         if (!conference) {
2046                 /* Remove the hook since the conference does not exist. */
2047                 return -1;
2048         }
2049
2050         talking_extras = ast_json_pack("{s: s, s: b}",
2051                 "talking_status", talking ? "on" : "off",
2052                 "admin", ast_test_flag(&user->u_profile, USER_OPT_ADMIN));
2053         if (!talking_extras) {
2054                 return 0;
2055         }
2056
2057         send_conf_stasis(conference, bridge_channel->chan, confbridge_talking_type(), talking_extras, 0);
2058         ast_json_unref(talking_extras);
2059         return 0;
2060 }
2061
2062 static int conf_get_pin(struct ast_channel *chan, struct confbridge_user *user)
2063 {
2064         char pin_guess[MAX_PIN+1] = { 0, };
2065         const char *pin = user->u_profile.pin;
2066         char *tmp = pin_guess;
2067         int i, res;
2068         unsigned int len = MAX_PIN;
2069
2070         /*
2071          * NOTE: We have not joined a conference yet so we have to use
2072          * the bridge profile requested by the user.
2073          */
2074
2075         /* give them three tries to get the pin right */
2076         for (i = 0; i < 3; i++) {
2077                 if (ast_app_getdata(chan,
2078                         conf_get_sound(CONF_SOUND_GET_PIN, user->b_profile.sounds),
2079                         tmp, len, 0) >= 0) {
2080                         if (!strcasecmp(pin, pin_guess)) {
2081                                 return 0;
2082                         }
2083                 }
2084                 ast_streamfile(chan,
2085                         conf_get_sound(CONF_SOUND_INVALID_PIN, user->b_profile.sounds),
2086                         ast_channel_language(chan));
2087                 res = ast_waitstream(chan, AST_DIGIT_ANY);
2088                 if (res > 0) {
2089                         /* Account for digit already read during ivalid pin playback
2090                          * resetting pin buf. */
2091                         pin_guess[0] = res;
2092                         pin_guess[1] = '\0';
2093                         tmp = pin_guess + 1;
2094                         len = MAX_PIN - 1;
2095                 } else {
2096                         /* reset pin buf as empty buffer. */
2097                         tmp = pin_guess;
2098                         len = MAX_PIN;
2099                 }
2100         }
2101         return -1;
2102 }
2103
2104 static int user_timeout(struct ast_bridge_channel *bridge_channel, void *ignore)
2105 {
2106         ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, 0);
2107         pbx_builtin_setvar_helper(bridge_channel->chan, "CONFBRIDGE_RESULT", "TIMEOUT");
2108         return -1;
2109 }
2110
2111 static int conf_rec_name(struct confbridge_user *user, const char *conf_name)
2112 {
2113         char destdir[PATH_MAX];
2114         int res;
2115         int duration = 20;
2116
2117         snprintf(destdir, sizeof(destdir), "%s/confbridge", ast_config_AST_SPOOL_DIR);
2118
2119         if (ast_mkdir(destdir, 0777) != 0) {
2120                 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
2121                 return -1;
2122         }
2123         snprintf(user->name_rec_location, sizeof(user->name_rec_location),
2124                  "%s/confbridge-name-%s-%s", destdir,
2125                  conf_name, ast_channel_uniqueid(user->chan));
2126
2127         if (!(ast_test_flag(&user->u_profile, USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW))) {
2128                 res = ast_play_and_record(user->chan,
2129                         "vm-rec-name",
2130                         user->name_rec_location,
2131                         10,
2132                         "sln",
2133                         &duration,
2134                         NULL,
2135                         ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE),
2136                         0,
2137                         NULL);
2138         } else {
2139                 res = ast_record_review(user->chan,
2140                         "vm-rec-name",
2141                         user->name_rec_location,
2142                         10,
2143                         "sln",
2144                         &duration,
2145                         NULL);
2146         }
2147
2148         if (res == -1) {
2149                 ast_filedelete(user->name_rec_location, NULL);
2150                 user->name_rec_location[0] = '\0';
2151                 return -1;
2152         }
2153         return 0;
2154 }
2155
2156 struct async_delete_name_rec_task_data {
2157         struct confbridge_conference *conference;
2158         char filename[0];
2159 };
2160
2161 static struct async_delete_name_rec_task_data *async_delete_name_rec_task_data_alloc(
2162         struct confbridge_conference *conference, const char *filename)
2163 {
2164         struct async_delete_name_rec_task_data *atd;
2165
2166         atd = ast_malloc(sizeof(*atd) + strlen(filename) + 1);
2167         if (!atd) {
2168                 return NULL;
2169         }
2170
2171         /* Safe */
2172         strcpy(atd->filename, filename);
2173         atd->conference = conference;
2174
2175         return atd;
2176 }
2177
2178 static void async_delete_name_rec_task_data_destroy(struct async_delete_name_rec_task_data *atd)
2179 {
2180         ast_free(atd);
2181 }
2182
2183 /*!
2184  * \brief Delete user's name file asynchronously
2185  *
2186  * This runs in the playback queue taskprocessor. This ensures that
2187  * sound file is removed after playback is finished and not before.
2188  *
2189  * \param data An async_delete_name_rec_task_data
2190  * \return 0
2191  */
2192 static int async_delete_name_rec_task(void *data)
2193 {
2194         struct async_delete_name_rec_task_data *atd = data;
2195
2196         ast_filedelete(atd->filename, NULL);
2197         ast_log(LOG_DEBUG, "Conference '%s' removed user name file '%s'\n",
2198                 atd->conference->name, atd->filename);
2199
2200         async_delete_name_rec_task_data_destroy(atd);
2201         return 0;
2202 }
2203
2204 static int async_delete_name_rec(struct confbridge_conference *conference,
2205         const char *filename)
2206 {
2207         struct async_delete_name_rec_task_data *atd;
2208
2209         if (ast_strlen_zero(filename)) {
2210                 return 0;
2211         } else if (!sound_file_exists(filename)) {
2212                 return 0;
2213         }
2214
2215         atd = async_delete_name_rec_task_data_alloc(conference, filename);
2216         if (!atd) {
2217                 return -1;
2218         }
2219
2220         if (ast_taskprocessor_push(conference->playback_queue, async_delete_name_rec_task, atd)) {
2221                 ast_log(LOG_WARNING, "Conference '%s' was unable to remove user name file '%s'\n",
2222                         conference->name, filename);
2223                 async_delete_name_rec_task_data_destroy(atd);
2224                 return -1;
2225         }
2226
2227         return 0;
2228 }
2229
2230 static int join_callback(struct ast_bridge_channel *bridge_channel, void *ignore)
2231 {
2232         async_play_sound_ready(bridge_channel->chan);
2233         return 0;
2234 }
2235
2236 /*! \brief The ConfBridge application */
2237 static int confbridge_exec(struct ast_channel *chan, const char *data)
2238 {
2239         int res = 0, volume_adjustments[2];
2240         int quiet = 0;
2241         int async_delete_task_pushed = 0;
2242         char *parse;
2243         const char *b_profile_name = NULL;
2244         const char *u_profile_name = NULL;
2245         const char *menu_profile_name = NULL;
2246         struct confbridge_conference *conference = NULL;
2247         struct confbridge_user user = {
2248                 .chan = chan,
2249                 .tech_args.talking_threshold = DEFAULT_TALKING_THRESHOLD,
2250                 .tech_args.silence_threshold = DEFAULT_SILENCE_THRESHOLD,
2251                 .tech_args.drop_silence = 0,
2252         };
2253         AST_DECLARE_APP_ARGS(args,
2254                 AST_APP_ARG(conf_name);
2255                 AST_APP_ARG(b_profile_name);
2256                 AST_APP_ARG(u_profile_name);
2257                 AST_APP_ARG(menu_profile_name);
2258         );
2259
2260         if (ast_channel_state(chan) != AST_STATE_UP) {
2261                 ast_answer(chan);
2262         }
2263
2264         if (ast_bridge_features_init(&user.features)) {
2265                 pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
2266                 res = -1;
2267                 goto confbridge_cleanup;
2268         }
2269
2270         /* We need to make a copy of the input string if we are going to modify it! */
2271         parse = ast_strdupa(data);
2272
2273         AST_STANDARD_APP_ARGS(args, parse);
2274
2275         if (ast_strlen_zero(args.conf_name)) {
2276                 pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
2277                 ast_log(LOG_WARNING, "%s requires an argument (conference name[,options])\n", app);
2278                 res = -1;
2279                 goto confbridge_cleanup;
2280         }
2281
2282         if (strlen(args.conf_name) >= MAX_CONF_NAME) {
2283                 pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
2284                 ast_log(LOG_WARNING, "%s does not accept conference names longer than %d\n", app, MAX_CONF_NAME - 1);
2285                 res = -1;
2286                 goto confbridge_cleanup;
2287         }
2288
2289         /* bridge profile name */
2290         if (args.argc > 1 && !ast_strlen_zero(args.b_profile_name)) {
2291                 b_profile_name = args.b_profile_name;
2292         }
2293         if (!conf_find_bridge_profile(chan, b_profile_name, &user.b_profile)) {
2294                 pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
2295                 ast_log(LOG_WARNING, "Conference bridge profile %s does not exist\n", b_profile_name ?
2296                         b_profile_name : DEFAULT_BRIDGE_PROFILE);
2297                 res = -1;
2298                 goto confbridge_cleanup;
2299         }
2300
2301         /* user profile name */
2302         if (args.argc > 2 && !ast_strlen_zero(args.u_profile_name)) {
2303                 u_profile_name = args.u_profile_name;
2304         }
2305         if (!conf_find_user_profile(chan, u_profile_name, &user.u_profile)) {
2306                 pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
2307                 ast_log(LOG_WARNING, "Conference user profile %s does not exist\n", u_profile_name ?
2308                         u_profile_name : DEFAULT_USER_PROFILE);
2309                 res = -1;
2310                 goto confbridge_cleanup;
2311         }
2312
2313         quiet = ast_test_flag(&user.u_profile, USER_OPT_QUIET);
2314
2315         /* ask for a PIN immediately after finding user profile.  This has to be
2316          * prompted for requardless of quiet setting. */
2317         if (!ast_strlen_zero(user.u_profile.pin)) {
2318                 if (conf_get_pin(chan, &user)) {
2319                         pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
2320                         res = -1; /* invalid PIN */
2321                         goto confbridge_cleanup;
2322                 }
2323         }
2324
2325         /* See if we need them to record a intro name */
2326         if (!quiet &&
2327                 (ast_test_flag(&user.u_profile, USER_OPT_ANNOUNCE_JOIN_LEAVE) ||
2328                 (ast_test_flag(&user.u_profile, USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW)))) {
2329                 if (conf_rec_name(&user, args.conf_name)) {
2330                         pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
2331                         res = -1; /* Hangup during name recording */
2332                         goto confbridge_cleanup;
2333                 }
2334         }
2335
2336         /* menu name */
2337         if (args.argc > 3 && !ast_strlen_zero(args.menu_profile_name)) {
2338                 menu_profile_name = args.menu_profile_name;
2339         }
2340
2341         if (conf_set_menu_to_user(chan, &user, menu_profile_name)) {
2342                 pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
2343                 ast_log(LOG_WARNING, "Conference menu profile %s does not exist\n", menu_profile_name ?
2344                         menu_profile_name : DEFAULT_MENU_PROFILE);
2345                 res = -1;
2346                 goto confbridge_cleanup;
2347         }
2348
2349         /* Set if DTMF should pass through for this user or not */
2350         if (ast_test_flag(&user.u_profile, USER_OPT_DTMF_PASS)) {
2351                 user.features.dtmf_passthrough = 1;
2352         } else {
2353                 user.features.dtmf_passthrough = 0;
2354         }
2355
2356         /* Set dsp threshold values if present */
2357         if (user.u_profile.talking_threshold) {
2358                 user.tech_args.talking_threshold = user.u_profile.talking_threshold;
2359         }
2360         if (user.u_profile.silence_threshold) {
2361                 user.tech_args.silence_threshold = user.u_profile.silence_threshold;
2362         }
2363
2364         /* Set a talker indicate call back if talking detection is requested */
2365         if (ast_test_flag(&user.u_profile, USER_OPT_TALKER_DETECT)) {
2366                 if (ast_bridge_talk_detector_hook(&user.features, conf_handle_talker_cb,
2367                         &user, NULL, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
2368                         pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
2369                         res = -1;
2370                         goto confbridge_cleanup;
2371                 }
2372         }
2373
2374         /* Look for a conference bridge matching the provided name */
2375         if (!(conference = join_conference_bridge(args.conf_name, &user))) {
2376                 pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "FAILED");
2377                 res = -1;
2378                 goto confbridge_cleanup;
2379         }
2380
2381         /* Keep a copy of volume adjustments so we can restore them later if need be */
2382         volume_adjustments[0] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_READ);
2383         volume_adjustments[1] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_WRITE);
2384
2385         if (ast_test_flag(&user.u_profile, USER_OPT_DROP_SILENCE)) {
2386                 user.tech_args.drop_silence = 1;
2387         }
2388
2389         if (ast_test_flag(&user.u_profile, USER_OPT_JITTERBUFFER) && ast_module_check("func_jitterbuffer.so")) {
2390                 ast_func_write(chan, "JITTERBUFFER(adaptive)", "default");
2391         }
2392
2393         if (ast_test_flag(&user.u_profile, USER_OPT_DENOISE) && ast_module_check("codec_speex.so")) {
2394                 ast_func_write(chan, "DENOISE(rx)", "on");
2395         }
2396
2397         /* if this user has a intro, play it before entering */
2398         if (!ast_strlen_zero(user.name_rec_location)) {
2399                 ast_autoservice_start(chan);
2400                 play_sound_file(conference, user.name_rec_location);
2401                 play_sound_file(conference,
2402                         conf_get_sound(CONF_SOUND_HAS_JOINED, conference->b_profile.sounds));
2403                 ast_autoservice_stop(chan);
2404         }
2405
2406         /* Play the Join sound to both the conference and the user entering. */
2407         if (!quiet) {
2408                 const char *join_sound = conf_get_sound(CONF_SOUND_JOIN, conference->b_profile.sounds);
2409
2410                 if (strcmp(conference->b_profile.language, ast_channel_language(chan))) {
2411                         ast_stream_and_wait(chan, join_sound, "");
2412                         ast_autoservice_start(chan);
2413                         play_sound_file(conference, join_sound);
2414                         ast_autoservice_stop(chan);
2415                 } else {
2416                         async_play_sound_file(conference, join_sound, chan);
2417                 }
2418         }
2419
2420         if (user.u_profile.timeout) {
2421                 ast_bridge_interval_hook(&user.features,
2422                         0,
2423                         user.u_profile.timeout * 1000,
2424                         user_timeout,
2425                         NULL,
2426                         NULL,
2427                         AST_BRIDGE_HOOK_REMOVE_ON_PULL);
2428         }
2429
2430         /* See if we need to automatically set this user as a video source or not */
2431         handle_video_on_join(conference, user.chan, ast_test_flag(&user.u_profile, USER_OPT_MARKEDUSER));
2432
2433         conf_moh_unsuspend(&user);
2434
2435         /* Join our conference bridge for real */
2436         send_join_event(&user, conference);
2437
2438         if (ast_bridge_join_hook(&user.features, join_callback, NULL, NULL, 0)) {
2439                 async_play_sound_ready(user.chan);
2440         }
2441
2442         ast_bridge_join(conference->bridge,
2443                 chan,
2444                 NULL,
2445                 &user.features,
2446                 &user.tech_args,
2447                 0);
2448
2449         /* This is a catch-all in case joining the bridge failed or for some reason
2450          * an async announcement got queued up and hasn't been told to play yet
2451          */
2452         async_play_sound_ready(chan);
2453
2454         if (!user.kicked && ast_check_hangup(chan)) {
2455                 pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "HANGUP");
2456         }
2457
2458         send_leave_event(&user, conference);
2459
2460         /* if we're shutting down, don't attempt to do further processing */
2461         if (ast_shutting_down()) {
2462                 /*
2463                  * Not taking any new calls at this time.  We cannot create
2464                  * the announcer channel if this is the first channel into
2465                  * the conference and we certainly cannot create any
2466                  * recording channel.
2467                  */
2468                 leave_conference(&user);
2469                 conference = NULL;
2470                 goto confbridge_cleanup;
2471         }
2472
2473         /* If this user was a video source, we need to clean up and possibly pick a new source. */
2474         handle_video_on_exit(conference, user.chan);
2475
2476         /* if this user has a intro, play it when leaving */
2477         if (!quiet && !ast_strlen_zero(user.name_rec_location)) {
2478                 async_play_sound_file(conference, user.name_rec_location, NULL);
2479                 async_play_sound_file(conference,
2480                         conf_get_sound(CONF_SOUND_HAS_LEFT, conference->b_profile.sounds), NULL);
2481                 async_delete_name_rec(conference, user.name_rec_location);
2482                 async_delete_task_pushed = 1;
2483         }
2484
2485         /* play the leave sound */
2486         if (!quiet) {
2487                 const char *leave_sound = conf_get_sound(CONF_SOUND_LEAVE, conference->b_profile.sounds);
2488                 async_play_sound_file(conference, leave_sound, NULL);
2489         }
2490
2491         /* If the user was kicked from the conference play back the audio prompt for it */
2492         if (!quiet && user.kicked) {
2493                 res = ast_stream_and_wait(chan,
2494                         conf_get_sound(CONF_SOUND_KICKED, conference->b_profile.sounds),
2495                         "");
2496         }
2497
2498         /* Easy as pie, depart this channel from the conference bridge */
2499         leave_conference(&user);
2500         conference = NULL;
2501
2502         /* Restore volume adjustments to previous values in case they were changed */
2503         if (volume_adjustments[0]) {
2504                 ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_READ, volume_adjustments[0]);
2505         }
2506         if (volume_adjustments[1]) {
2507                 ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_WRITE, volume_adjustments[1]);
2508         }
2509
2510 confbridge_cleanup:
2511         if (!async_delete_task_pushed && !ast_strlen_zero(user.name_rec_location)) {
2512                 ast_filedelete(user.name_rec_location, NULL);
2513         }
2514         ast_bridge_features_cleanup(&user.features);
2515         conf_bridge_profile_destroy(&user.b_profile);
2516         return res;
2517 }
2518
2519 static int action_toggle_mute(struct confbridge_conference *conference,
2520                               struct confbridge_user *user,
2521                               struct ast_bridge_channel *bridge_channel)
2522 {
2523         int mute;
2524
2525         /* Toggle user level mute request. */
2526         mute = !user->muted;
2527         generic_mute_unmute_user(conference, user, mute);
2528
2529         return play_file(bridge_channel, NULL,
2530                 conf_get_sound(mute ? CONF_SOUND_MUTED : CONF_SOUND_UNMUTED,
2531                         conference->b_profile.sounds)) < 0;
2532 }
2533
2534 static int action_toggle_binaural(struct confbridge_conference *conference,
2535                 struct confbridge_user *user,
2536                 struct ast_bridge_channel *bridge_channel)
2537 {
2538         unsigned int binaural;
2539         ast_bridge_channel_lock_bridge(bridge_channel);
2540         binaural = !bridge_channel->binaural_suspended;
2541         bridge_channel->binaural_suspended = binaural;
2542         ast_bridge_unlock(bridge_channel->bridge);
2543         return play_file(bridge_channel, NULL, (binaural ?
2544                                 conf_get_sound(CONF_SOUND_BINAURAL_OFF, user->b_profile.sounds) :
2545                                 conf_get_sound(CONF_SOUND_BINAURAL_ON, user->b_profile.sounds))) < 0;
2546 }
2547
2548 static int action_toggle_mute_participants(struct confbridge_conference *conference, struct confbridge_user *user)
2549 {
2550         struct confbridge_user *cur_user = NULL;
2551         const char *sound_to_play;
2552         int mute;
2553
2554         ao2_lock(conference);
2555
2556         /* Toggle bridge level mute request. */
2557         mute = !conference->muted;
2558         conference->muted = mute;
2559
2560         AST_LIST_TRAVERSE(&conference->active_list, cur_user, list) {
2561                 if (!ast_test_flag(&cur_user->u_profile, USER_OPT_ADMIN)) {
2562                         /* Set user level to bridge level mute request. */
2563                         cur_user->muted = mute;
2564                         conf_update_user_mute(cur_user);
2565                 }
2566         }
2567
2568         ao2_unlock(conference);
2569
2570         sound_to_play = conf_get_sound(
2571                 mute ? CONF_SOUND_PARTICIPANTS_MUTED : CONF_SOUND_PARTICIPANTS_UNMUTED,
2572                 conference->b_profile.sounds);
2573
2574         if (strcmp(conference->b_profile.language, ast_channel_language(user->chan))) {
2575                 /* The host needs to hear it seperately, as they don't get the audio from play_sound_helper */
2576                 ast_stream_and_wait(user->chan, sound_to_play, "");
2577
2578                 /* Announce to the group that all participants are muted */
2579                 ast_autoservice_start(user->chan);
2580                 play_sound_file(conference, sound_to_play);
2581                 ast_autoservice_stop(user->chan);
2582         } else {
2583                 /* Playing the sound asynchronously lets the sound be heard by everyone at once */
2584                 async_play_sound_file(conference, sound_to_play, user->chan);
2585         }
2586
2587         return 0;
2588 }
2589
2590 static int action_playback(struct ast_bridge_channel *bridge_channel, const char *playback_file)
2591 {
2592         char *file_copy = ast_strdupa(playback_file);
2593         char *file = NULL;
2594
2595         while ((file = strsep(&file_copy, "&"))) {
2596                 if (ast_stream_and_wait(bridge_channel->chan, file, "")) {
2597                         ast_log(LOG_WARNING, "Failed to playback file %s to channel\n", file);
2598                         return -1;
2599                 }
2600         }
2601         return 0;
2602 }
2603
2604 static int action_playback_and_continue(struct confbridge_conference *conference,
2605         struct confbridge_user *user,
2606         struct ast_bridge_channel *bridge_channel,
2607         struct conf_menu *menu,
2608         const char *playback_file,
2609         const char *cur_dtmf,
2610         int *stop_prompts)
2611 {
2612         int i;
2613         int digit = 0;
2614         char dtmf[MAXIMUM_DTMF_FEATURE_STRING];
2615         struct conf_menu_entry new_menu_entry = { { 0, }, };
2616         char *file_copy = ast_strdupa(playback_file);
2617         char *file = NULL;
2618
2619         while ((file = strsep(&file_copy, "&"))) {
2620                 if (ast_streamfile(bridge_channel->chan, file, ast_channel_language(bridge_channel->chan))) {
2621                         ast_log(LOG_WARNING, "Failed to playback file %s to channel\n", file);
2622                         return -1;
2623                 }
2624
2625                 /* now wait for more digits. */
2626                 if (!(digit = ast_waitstream(bridge_channel->chan, AST_DIGIT_ANY))) {
2627                         /* streaming finished and no DTMF was entered */
2628                         continue;
2629                 } else if (digit == -1) {
2630                         /* error */
2631                         return -1;
2632                 } else {
2633                         break; /* dtmf was entered */
2634                 }
2635         }
2636         if (!digit) {
2637                 /* streaming finished on all files and no DTMF was entered */
2638                 return -1;
2639         }
2640         ast_stopstream(bridge_channel->chan);
2641
2642         /* If we get here, then DTMF has been entered, This means no
2643          * additional prompts should be played for this menu entry */
2644         *stop_prompts = 1;
2645
2646         /* If a digit was pressed during the payback, update
2647          * the dtmf string and look for a new menu entry in the
2648          * menu structure */
2649         ast_copy_string(dtmf, cur_dtmf, sizeof(dtmf));
2650         for (i = 0; i < (MAXIMUM_DTMF_FEATURE_STRING - 1); i++) {
2651                 dtmf[i] = cur_dtmf[i];
2652                 if (!dtmf[i]) {
2653                         dtmf[i] = (char) digit;
2654                         dtmf[i + 1] = '\0';
2655                         i = -1;
2656                         break;
2657                 }
2658         }
2659         /* If i is not -1 then the new dtmf digit was _NOT_ added to the string.
2660          * If this is the case, no new DTMF sequence should be looked for. */
2661         if (i != -1) {
2662                 return 0;
2663         }
2664
2665         if (conf_find_menu_entry_by_sequence(dtmf, menu, &new_menu_entry)) {
2666                 execute_menu_entry(conference,
2667                         user,
2668                         bridge_channel,
2669                         &new_menu_entry, menu);
2670                 conf_menu_entry_destroy(&new_menu_entry);
2671         }
2672         return 0;
2673 }
2674
2675 static int action_kick_last(struct confbridge_conference *conference,
2676         struct ast_bridge_channel *bridge_channel,
2677         struct confbridge_user *user)
2678 {
2679         struct confbridge_user *last_user = NULL;
2680         int isadmin = ast_test_flag(&user->u_profile, USER_OPT_ADMIN);
2681
2682         if (!isadmin) {
2683                 play_file(bridge_channel, NULL,
2684                         conf_get_sound(CONF_SOUND_ERROR_MENU, conference->b_profile.sounds));
2685                 ast_log(LOG_WARNING, "Only admin users can use the kick_last menu action. Channel %s of conf %s is not an admin.\n",
2686                         ast_channel_name(bridge_channel->chan),
2687                         conference->name);
2688                 return -1;
2689         }
2690
2691         ao2_lock(conference);
2692         if (((last_user = AST_LIST_LAST(&conference->active_list)) == user)
2693                 || (ast_test_flag(&last_user->u_profile, USER_OPT_ADMIN))) {
2694                 ao2_unlock(conference);
2695                 play_file(bridge_channel, NULL,
2696                         conf_get_sound(CONF_SOUND_ERROR_MENU, conference->b_profile.sounds));
2697         } else if (last_user && !last_user->kicked) {
2698                 last_user->kicked = 1;
2699                 pbx_builtin_setvar_helper(last_user->chan, "CONFBRIDGE_RESULT", "KICKED");
2700                 ast_bridge_remove(conference->bridge, last_user->chan);
2701                 ao2_unlock(conference);
2702         }
2703         return 0;
2704 }
2705
2706 static int action_dialplan_exec(struct ast_bridge_channel *bridge_channel, struct conf_menu_action *menu_action)
2707 {
2708         struct ast_pbx_args args;
2709         struct ast_pbx *pbx;
2710         char *exten;
2711         char *context;
2712         int priority;
2713         int res;
2714
2715         memset(&args, 0, sizeof(args));
2716         args.no_hangup_chan = 1;
2717
2718         ast_channel_lock(bridge_channel->chan);
2719
2720         /*save off*/
2721         exten = ast_strdupa(ast_channel_exten(bridge_channel->chan));
2722         context = ast_strdupa(ast_channel_context(bridge_channel->chan));
2723         priority = ast_channel_priority(bridge_channel->chan);
2724         pbx = ast_channel_pbx(bridge_channel->chan);
2725         ast_channel_pbx_set(bridge_channel->chan, NULL);
2726
2727         /*set new*/
2728         ast_channel_exten_set(bridge_channel->chan, menu_action->data.dialplan_args.exten);
2729         ast_channel_context_set(bridge_channel->chan, menu_action->data.dialplan_args.context);
2730         ast_channel_priority_set(bridge_channel->chan, menu_action->data.dialplan_args.priority);
2731
2732         ast_channel_unlock(bridge_channel->chan);
2733
2734         /*execute*/
2735         res = ast_pbx_run_args(bridge_channel->chan, &args);
2736
2737         /*restore*/
2738         ast_channel_lock(bridge_channel->chan);
2739
2740         ast_channel_exten_set(bridge_channel->chan, exten);
2741         ast_channel_context_set(bridge_channel->chan, context);
2742         ast_channel_priority_set(bridge_channel->chan, priority);
2743         ast_channel_pbx_set(bridge_channel->chan, pbx);
2744
2745         ast_channel_unlock(bridge_channel->chan);
2746
2747         return res;
2748 }
2749
2750 static int execute_menu_entry(struct confbridge_conference *conference,
2751         struct confbridge_user *user,
2752         struct ast_bridge_channel *bridge_channel,
2753         struct conf_menu_entry *menu_entry,
2754         struct conf_menu *menu)
2755 {
2756         struct conf_menu_action *menu_action;
2757         int isadmin = ast_test_flag(&user->u_profile, USER_OPT_ADMIN);
2758         int stop_prompts = 0;
2759         int res = 0;
2760
2761         AST_LIST_TRAVERSE(&menu_entry->actions, menu_action, action) {
2762                 switch (menu_action->id) {
2763                 case MENU_ACTION_TOGGLE_MUTE:
2764                         res |= action_toggle_mute(conference, user, bridge_channel);
2765                         break;
2766                 case MENU_ACTION_TOGGLE_BINAURAL:
2767                         action_toggle_binaural(conference, user, bridge_channel);
2768                         break;
2769                 case MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS:
2770                         if (!isadmin) {
2771                                 break;
2772                         }
2773                         action_toggle_mute_participants(conference, user);
2774                         break;
2775                 case MENU_ACTION_PARTICIPANT_COUNT:
2776                         announce_user_count(conference, user, bridge_channel);
2777                         break;
2778                 case MENU_ACTION_PLAYBACK:
2779                         if (!stop_prompts) {
2780                                 res |= action_playback(bridge_channel, menu_action->data.playback_file);
2781                                 ast_test_suite_event_notify("CONF_MENU_PLAYBACK",
2782                                         "Message: %s\r\nChannel: %s",
2783                                         menu_action->data.playback_file, ast_channel_name(bridge_channel->chan));
2784                         }
2785                         break;
2786                 case MENU_ACTION_RESET_LISTENING:
2787                         ast_audiohook_volume_set(user->chan, AST_AUDIOHOOK_DIRECTION_WRITE, 0);
2788                         break;
2789                 case MENU_ACTION_RESET_TALKING:
2790                         ast_audiohook_volume_set(user->chan, AST_AUDIOHOOK_DIRECTION_READ, 0);
2791                         break;
2792                 case MENU_ACTION_INCREASE_LISTENING:
2793                         ast_audiohook_volume_adjust(user->chan,
2794                                 AST_AUDIOHOOK_DIRECTION_WRITE, 1);
2795                         break;
2796                 case MENU_ACTION_DECREASE_LISTENING:
2797                         ast_audiohook_volume_adjust(user->chan,
2798                                 AST_AUDIOHOOK_DIRECTION_WRITE, -1);
2799                         break;
2800                 case MENU_ACTION_INCREASE_TALKING:
2801                         ast_audiohook_volume_adjust(user->chan,
2802                                 AST_AUDIOHOOK_DIRECTION_READ, 1);
2803                         break;
2804                 case MENU_ACTION_DECREASE_TALKING:
2805                         ast_audiohook_volume_adjust(user->chan,
2806                                 AST_AUDIOHOOK_DIRECTION_READ, -1);
2807                         break;
2808                 case MENU_ACTION_PLAYBACK_AND_CONTINUE:
2809                         if (!(stop_prompts)) {
2810                                 res |= action_playback_and_continue(conference,
2811                                         user,
2812                                         bridge_channel,
2813                                         menu,
2814                                         menu_action->data.playback_file,
2815                                         menu_entry->dtmf,
2816                                         &stop_prompts);
2817                         }
2818                         break;
2819                 case MENU_ACTION_DIALPLAN_EXEC:
2820                         res |= action_dialplan_exec(bridge_channel, menu_action);
2821                         break;
2822                 case MENU_ACTION_ADMIN_TOGGLE_LOCK:
2823                         if (!isadmin) {
2824                                 break;
2825                         }
2826                         conference->locked = (!conference->locked ? 1 : 0);
2827                         res |= play_file(bridge_channel, NULL,
2828                                 conf_get_sound(
2829                                         conference->locked ? CONF_SOUND_LOCKED_NOW : CONF_SOUND_UNLOCKED_NOW,
2830                                         conference->b_profile.sounds)) < 0;
2831                         break;
2832                 case MENU_ACTION_ADMIN_KICK_LAST:
2833                         res |= action_kick_last(conference, bridge_channel, user);
2834                         break;
2835                 case MENU_ACTION_LEAVE:
2836                         pbx_builtin_setvar_helper(bridge_channel->chan, "CONFBRIDGE_RESULT", "DTMF");
2837                         ao2_lock(conference);
2838                         ast_bridge_remove(conference->bridge, bridge_channel->chan);
2839                         ast_test_suite_event_notify("CONF_MENU_LEAVE",
2840                                 "Channel: %s",
2841                                 ast_channel_name(bridge_channel->chan));
2842                         ao2_unlock(conference);
2843                         break;
2844                 case MENU_ACTION_NOOP:
2845                         break;
2846                 case MENU_ACTION_SET_SINGLE_VIDEO_SRC:
2847                         ao2_lock(conference);
2848                         if (!ast_test_flag(&conference->b_profile, BRIDGE_OPT_VIDEO_SRC_SFU)) {
2849                                 ast_bridge_set_single_src_video_mode(conference->bridge, bridge_channel->chan);
2850                         }
2851                         ao2_unlock(conference);
2852                         break;
2853                 case MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC:
2854                         handle_video_on_exit(conference, bridge_channel->chan);
2855                         break;
2856                 }
2857         }
2858         return res;
2859 }
2860
2861 int conf_handle_dtmf(struct ast_bridge_channel *bridge_channel,
2862         struct confbridge_user *user,
2863         struct conf_menu_entry *menu_entry,
2864         struct conf_menu *menu)
2865 {
2866         /* See if music on hold is playing */
2867         conf_moh_suspend(user);
2868
2869         /* execute the list of actions associated with this menu entry */
2870         execute_menu_entry(user->conference, user, bridge_channel, menu_entry, menu);
2871
2872         /* See if music on hold needs to be started back up again */
2873         conf_moh_unsuspend(user);
2874
2875         async_play_sound_ready(bridge_channel->chan);
2876
2877         return 0;
2878 }
2879
2880 static int kick_conference_participant(struct confbridge_conference *conference,
2881         const char *channel)
2882 {
2883         int res = -1;
2884         int match;
2885         struct confbridge_user *user = NULL;
2886         int all = !strcasecmp("all", channel);
2887         int participants = !strcasecmp("participants", channel);
2888
2889         SCOPED_AO2LOCK(bridge_lock, conference);
2890
2891         AST_LIST_TRAVERSE(&conference->active_list, user, list) {
2892                 if (user->kicked) {
2893                         continue;
2894                 }
2895                 match = !strcasecmp(channel, ast_channel_name(user->chan));
2896                 if (match || all
2897                                 || (participants && !ast_test_flag(&user->u_profile, USER_OPT_ADMIN))) {
2898                         user->kicked = 1;
2899                         pbx_builtin_setvar_helper(user->chan, "CONFBRIDGE_RESULT", "KICKED");
2900                         ast_bridge_remove(conference->bridge, user->chan);
2901                         res = 0;
2902                         if (match) {
2903                                 return res;
2904                         }
2905                 }
2906         }
2907         AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
2908                 if (user->kicked) {
2909                         continue;
2910                 }
2911                 match = !strcasecmp(channel, ast_channel_name(user->chan));
2912                 if (match || all
2913                                 || (participants && !ast_test_flag(&user->u_profile, USER_OPT_ADMIN))) {
2914                         user->kicked = 1;
2915                         pbx_builtin_setvar_helper(user->chan, "CONFBRIDGE_RESULT", "KICKED");
2916                         ast_bridge_remove(conference->bridge, user->chan);
2917                         res = 0;
2918                         if (match) {
2919                                 return res;
2920                         }
2921                 }
2922         }
2923
2924         return res;
2925 }
2926
2927 static char *complete_confbridge_name(const char *line, const char *word, int pos, int state)
2928 {
2929         int which = 0;
2930         struct confbridge_conference *conference;
2931         char *res = NULL;
2932         int wordlen = strlen(word);
2933         struct ao2_iterator iter;
2934
2935         iter = ao2_iterator_init(conference_bridges, 0);
2936         while ((conference = ao2_iterator_next(&iter))) {
2937                 if (!strncasecmp(conference->name, word, wordlen) && ++which > state) {
2938                         res = ast_strdup(conference->name);
2939                         ao2_ref(conference, -1);
2940                         break;
2941                 }
2942                 ao2_ref(conference, -1);
2943         }
2944         ao2_iterator_destroy(&iter);
2945
2946         return res;
2947 }
2948
2949 static char *complete_confbridge_participant(const char *conference_name, const char *line, const char *word, int pos, int state)
2950 {
2951         int which = 0;
2952         RAII_VAR(struct confbridge_conference *, conference, NULL, ao2_cleanup);
2953         struct confbridge_user *user;
2954         char *res = NULL;
2955         int wordlen = strlen(word);
2956
2957         conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
2958         if (!conference) {
2959                 return NULL;
2960         }
2961
2962         if (!strncasecmp("all", word, wordlen) && ++which > state) {
2963                 return ast_strdup("all");
2964         }
2965
2966         if (!strncasecmp("participants", word, wordlen) && ++which > state) {
2967                 return ast_strdup("participants");
2968         }
2969
2970         {
2971                 SCOPED_AO2LOCK(bridge_lock, conference);
2972                 AST_LIST_TRAVERSE(&conference->active_list, user, list) {
2973                         if (!strncasecmp(ast_channel_name(user->chan), word, wordlen) && ++which > state) {
2974                                 res = ast_strdup(ast_channel_name(user->chan));
2975                                 return res;
2976                         }
2977                 }
2978                 AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
2979                         if (!strncasecmp(ast_channel_name(user->chan), word, wordlen) && ++which > state) {
2980                                 res = ast_strdup(ast_channel_name(user->chan));
2981                                 return res;
2982                         }
2983                 }
2984         }
2985
2986         return NULL;
2987 }
2988
2989 static char *handle_cli_confbridge_kick(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2990 {
2991         struct confbridge_conference *conference;
2992         int not_found;
2993
2994         switch (cmd) {
2995         case CLI_INIT:
2996                 e->command = "confbridge kick";
2997                 e->usage =
2998                         "Usage: confbridge kick <conference> <channel>\n"
2999                         "       Kicks a channel out of the conference bridge.\n"
3000                         "             (all to kick everyone, participants to kick non-admins).\n";
3001                 return NULL;
3002         case CLI_GENERATE:
3003                 if (a->pos == 2) {
3004                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
3005                 }
3006                 if (a->pos == 3) {
3007                         return complete_confbridge_participant(a->argv[2], a->line, a->word, a->pos, a->n);
3008                 }
3009                 return NULL;
3010         }
3011
3012         if (a->argc != 4) {
3013                 return CLI_SHOWUSAGE;
3014         }
3015
3016         conference = ao2_find(conference_bridges, a->argv[2], OBJ_KEY);
3017         if (!conference) {
3018                 ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
3019                 return CLI_SUCCESS;
3020         }
3021         not_found = kick_conference_participant(conference, a->argv[3]);
3022         ao2_ref(conference, -1);
3023         if (not_found) {
3024                 if (!strcasecmp("all", a->argv[3]) || !strcasecmp("participants", a->argv[3])) {
3025                         ast_cli(a->fd, "No participants found!\n");
3026                 } else {
3027                         ast_cli(a->fd, "No participant named '%s' found!\n", a->argv[3]);
3028                 }
3029                 return CLI_SUCCESS;
3030         }
3031         ast_cli(a->fd, "Kicked '%s' out of conference '%s'\n", a->argv[3], a->argv[2]);
3032         return CLI_SUCCESS;
3033 }
3034
3035 static void handle_cli_confbridge_list_item(struct ast_cli_args *a, struct confbridge_user *user, int waiting)
3036 {
3037         char flag_str[6 + 1];/* Max flags + terminator */
3038         int pos = 0;
3039
3040         /* Build flags column string. */
3041         if (ast_test_flag(&user->u_profile, USER_OPT_ADMIN)) {
3042                 flag_str[pos++] = 'A';
3043         }
3044         if (ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)) {
3045                 flag_str[pos++] = 'M';
3046         }
3047         if (ast_test_flag(&user->u_profile, USER_OPT_WAITMARKED)) {
3048                 flag_str[pos++] = 'W';
3049         }
3050         if (ast_test_flag(&user->u_profile, USER_OPT_ENDMARKED)) {
3051                 flag_str[pos++] = 'E';
3052         }
3053         if (user->muted) {
3054                 flag_str[pos++] = 'm';
3055         }
3056         if (waiting) {
3057                 flag_str[pos++] = 'w';
3058         }
3059         flag_str[pos] = '\0';
3060
3061         ast_cli(a->fd, "%-30s %-6s %-16s %-16s %-16s %s\n",
3062                 ast_channel_name(user->chan),
3063                 flag_str,
3064                 user->u_profile.name,
3065                 user->conference->b_profile.name,
3066                 user->menu_name,
3067                 S_COR(ast_channel_caller(user->chan)->id.number.valid,
3068                         ast_channel_caller(user->chan)->id.number.str, "<unknown>"));
3069 }
3070
3071 static char *handle_cli_confbridge_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3072 {
3073         struct confbridge_conference *conference;
3074
3075         switch (cmd) {
3076         case CLI_INIT:
3077                 e->command = "confbridge list";
3078                 e->usage =
3079                         "Usage: confbridge list [<name>]\n"
3080                         "       Lists all currently active conference bridges or a specific conference bridge.\n"
3081                         "\n"
3082                         "       When a conference bridge name is provided, flags may be shown for users. Below\n"
3083                         "       are the flags and what they represent.\n"
3084                         "\n"
3085                         "       Flags:\n"
3086                         "         A - The user is an admin\n"
3087                         "         M - The user is a marked user\n"
3088                         "         W - The user must wait for a marked user to join\n"
3089                         "         E - The user will be kicked after the last marked user leaves the conference\n"
3090                         "         m - The user is muted\n"
3091                         "         w - The user is waiting for a marked user to join\n";
3092                 return NULL;
3093         case CLI_GENERATE:
3094                 if (a->pos == 2) {
3095                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
3096                 }
3097                 return NULL;
3098         }
3099
3100         if (a->argc == 2) {
3101                 struct ao2_iterator iter;
3102
3103                 ast_cli(a->fd, "Conference Bridge Name           Users  Marked Locked Muted\n");
3104                 ast_cli(a->fd, "================================ ====== ====== ====== =====\n");
3105                 iter = ao2_iterator_init(conference_bridges, 0);
3106                 while ((conference = ao2_iterator_next(&iter))) {
3107                         ast_cli(a->fd, "%-32s %6u %6u %-6s %s\n",
3108                                 conference->name,
3109                                 conference->activeusers + conference->waitingusers,
3110                                 conference->markedusers,
3111                                 AST_CLI_YESNO(conference->locked),
3112                                 AST_CLI_YESNO(conference->muted));
3113                         ao2_ref(conference, -1);
3114                 }
3115                 ao2_iterator_destroy(&iter);
3116                 return CLI_SUCCESS;
3117         }
3118
3119         if (a->argc == 3) {
3120                 struct confbridge_user *user;
3121
3122                 conference = ao2_find(conference_bridges, a->argv[2], OBJ_KEY);
3123                 if (!conference) {
3124                         ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
3125                         return CLI_SUCCESS;
3126                 }
3127                 ast_cli(a->fd, "Channel                        Flags  User Profile     Bridge Profile   Menu             CallerID\n");
3128                 ast_cli(a->fd, "============================== ====== ================ ================ ================ ================\n");
3129                 ao2_lock(conference);
3130                 AST_LIST_TRAVERSE(&conference->active_list, user, list) {
3131                         handle_cli_confbridge_list_item(a, user, 0);
3132                 }
3133                 AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
3134                         handle_cli_confbridge_list_item(a, user, 1);
3135                 }
3136                 ao2_unlock(conference);
3137                 ao2_ref(conference, -1);
3138                 return CLI_SUCCESS;
3139         }
3140
3141         return CLI_SHOWUSAGE;
3142 }
3143
3144 /* \internal
3145  * \brief finds a conference by name and locks/unlocks.
3146  *
3147  * \retval 0 success
3148  * \retval -1 conference not found
3149  */
3150 static int generic_lock_unlock_helper(int lock, const char *conference_name)
3151 {
3152         struct confbridge_conference *conference;
3153         int res = 0;
3154
3155         conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
3156         if (!conference) {
3157                 return -1;
3158         }
3159         ao2_lock(conference);
3160         conference->locked = lock;
3161         ast_test_suite_event_notify("CONF_LOCK", "Message: conference %s\r\nConference: %s", conference->locked ? "locked" : "unlocked", conference->b_profile.name);
3162         ao2_unlock(conference);
3163         ao2_ref(conference, -1);
3164
3165   &nbs