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