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