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