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