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