Add explanation of strange flag setup in app_meetme (stolen from Mark's message to...
[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  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Conference Bridge application
22  *
23  * \author\verbatim Joshua Colp <jcolp@digium.com> \endverbatim
24  *
25  * This is a conference bridge application utilizing the bridging core.
26  * \ingroup applications
27  */
28
29 #include "asterisk.h"
30
31 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <signal.h>
38
39 #include "asterisk/cli.h"
40 #include "asterisk/file.h"
41 #include "asterisk/logger.h"
42 #include "asterisk/channel.h"
43 #include "asterisk/pbx.h"
44 #include "asterisk/module.h"
45 #include "asterisk/lock.h"
46 #include "asterisk/app.h"
47 #include "asterisk/bridging.h"
48 #include "asterisk/musiconhold.h"
49 #include "asterisk/say.h"
50 #include "asterisk/audiohook.h"
51 #include "asterisk/astobj2.h"
52
53 /*** DOCUMENTATION
54         <application name="ConfBridge" language="en_US">
55                 <synopsis>
56                         Conference bridge application.
57                 </synopsis>
58                 <syntax>
59                         <parameter name="confno">
60                                 <para>The conference number</para>
61                         </parameter>
62                         <parameter name="options">
63                                 <optionlist>
64                                         <option name="a">
65                                                 <para>Set admin mode.</para>
66                                         </option>
67                                         <option name="A">
68                                                 <para>Set marked mode.</para>
69                                         </option>
70                                         <option name="c">
71                                                 <para>Announce user(s) count on joining a conference.</para>
72                                         </option>
73                                         <option name="m">
74                                                 <para>Set initially muted.</para>
75                                         </option>
76                                         <option name="M" hasparams="optional">
77                                                 <para>Enable music on hold when the conference has a single caller. Optionally,
78                                                 specify a musiconhold class to use. If one is not provided, it will use the
79                                                 channel's currently set music class, or <literal>default</literal>.</para>
80                                                 <argument name="class" required="true" />
81                                         </option>
82                                         <option name="1">
83                                                 <para>Do not play message when first person enters</para>
84                                         </option>
85                                         <option name="s">
86                                                 <para>Present menu (user or admin) when <literal>*</literal> is received
87                                                 (send to menu).</para>
88                                         </option>
89                                         <option name="w">
90                                                 <para>Wait until the marked user enters the conference.</para>
91                                         </option>
92                                         <option name="q">
93                                                 <para>Quiet mode (don't play enter/leave sounds).</para>
94                                         </option>
95                                 </optionlist>
96                       </parameter>
97                 </syntax>
98                 <description>
99                         <para>Enters the user into a specified conference bridge. The user can exit the conference by hangup only.</para>
100                         <para>The join sound can be set using the <literal>CONFBRIDGE_JOIN_SOUND</literal> variable and the leave sound can be set using the <literal>CONFBRIDGE_LEAVE_SOUND</literal> variable. These can be unique to the caller.</para>
101                         <note><para>This application will not automatically answer the channel.</para></note>
102                 </description>
103         </application>
104 ***/
105
106 /*!
107  * \par Playing back a file to a channel in a conference
108  * You might notice in this application that while playing a sound file
109  * to a channel the actual conference bridge lock is not held. This is done so
110  * that other channels are not blocked from interacting with the conference bridge.
111  * Unfortunately because of this it is possible for things to change after the sound file
112  * is done being played. Data must therefore be checked after reacquiring the conference
113  * bridge lock if it is important.
114  */
115
116 static const char app[] = "ConfBridge";
117
118 enum {
119         OPTION_ADMIN = (1 << 0),             /*!< Set if the caller is an administrator */
120         OPTION_MENU = (1 << 1),              /*!< Set if the caller should have access to the conference bridge IVR menu */
121         OPTION_MUSICONHOLD = (1 << 2),       /*!< Set if music on hold should be played if nobody else is in the conference bridge */
122         OPTION_NOONLYPERSON = (1 << 3),      /*!< Set if the "you are currently the only person in this conference" sound file should not be played */
123         OPTION_STARTMUTED = (1 << 4),        /*!< Set if the caller should be initially set muted */
124         OPTION_ANNOUNCEUSERCOUNT = (1 << 5), /*!< Set if the number of users should be announced to the caller */
125         OPTION_MARKEDUSER = (1 << 6),        /*!< Set if the caller is a marked user */
126         OPTION_WAITMARKED = (1 << 7),        /*!< Set if the conference must wait for a marked user before starting */
127         OPTION_QUIET = (1 << 8),             /*!< Set if no audio prompts should be played */
128 };
129
130 enum {
131         OPTION_MUSICONHOLD_CLASS,            /*!< If the 'M' option is set, the music on hold class to play */
132         /*This must be the last element */
133         OPTION_ARRAY_SIZE,
134 };
135
136 AST_APP_OPTIONS(app_opts,{
137         AST_APP_OPTION('A', OPTION_MARKEDUSER),
138         AST_APP_OPTION('a', OPTION_ADMIN),
139         AST_APP_OPTION('c', OPTION_ANNOUNCEUSERCOUNT),
140         AST_APP_OPTION('m', OPTION_STARTMUTED),
141         AST_APP_OPTION_ARG('M', OPTION_MUSICONHOLD, OPTION_MUSICONHOLD_CLASS),
142         AST_APP_OPTION('1', OPTION_NOONLYPERSON),
143         AST_APP_OPTION('s', OPTION_MENU),
144         AST_APP_OPTION('w', OPTION_WAITMARKED),
145         AST_APP_OPTION('q', OPTION_QUIET),
146 });
147
148 /* Maximum length of a conference bridge name */
149 #define MAX_CONF_NAME 32
150
151 /* Number of buckets our conference bridges container can have */
152 #define CONFERENCE_BRIDGE_BUCKETS 53
153
154 /*! \brief The structure that represents a conference bridge */
155 struct conference_bridge {
156         char name[MAX_CONF_NAME];                                         /*!< Name of the conference bridge */
157         struct ast_bridge *bridge;                                        /*!< Bridge structure doing the mixing */
158         unsigned int users;                                               /*!< Number of users present */
159         unsigned int markedusers;                                         /*!< Number of marked users present */
160         unsigned int locked:1;                                            /*!< Is this conference bridge locked? */
161         AST_LIST_HEAD_NOLOCK(, conference_bridge_user) users_list;        /*!< List of users participating in the conference bridge */
162         struct ast_channel *playback_chan;                                /*!< Channel used for playback into the conference bridge */
163         ast_mutex_t playback_lock;                                        /*!< Lock used for playback channel */
164 };
165
166 /*! \brief The structure that represents a conference bridge user */
167 struct conference_bridge_user {
168         struct conference_bridge *conference_bridge; /*!< Conference bridge they are participating in */
169         struct ast_channel *chan;                    /*!< Asterisk channel participating */
170         struct ast_flags flags;                      /*!< Flags passed in when the application was called */
171         char *opt_args[OPTION_ARRAY_SIZE];           /*!< Arguments to options passed when application was called */
172         struct ast_bridge_features features;         /*!< Bridge features structure */
173         unsigned int kicked:1;                       /*!< User has been kicked from the conference */
174         AST_LIST_ENTRY(conference_bridge_user) list; /*!< Linked list information */
175 };
176
177 /*! \brief Container to hold all conference bridges in progress */
178 static struct ao2_container *conference_bridges;
179
180 static int play_sound_file(struct conference_bridge *conference_bridge, const char *filename);
181
182 /*! \brief Hashing function used for conference bridges container */
183 static int conference_bridge_hash_cb(const void *obj, const int flags)
184 {
185         const struct conference_bridge *conference_bridge = obj;
186         return ast_str_case_hash(conference_bridge->name);
187 }
188
189 /*! \brief Comparison function used for conference bridges container */
190 static int conference_bridge_cmp_cb(void *obj, void *arg, int flags)
191 {
192         const struct conference_bridge *conference_bridge0 = obj, *conference_bridge1 = arg;
193         return (!strcasecmp(conference_bridge0->name, conference_bridge1->name) ? CMP_MATCH | CMP_STOP : 0);
194 }
195
196 /*!
197  * \brief Announce number of users in the conference bridge to the caller
198  *
199  * \param conference_bridge Conference bridge to peek at
200  * \param conference_bridge_user Caller
201  *
202  * \return Returns nothing
203  */
204 static void announce_user_count(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
205 {
206         if (conference_bridge->users == 1) {
207                 /* Awww we are the only person in the conference bridge */
208                 return;
209         } else if (conference_bridge->users == 2) {
210                 /* Eep, there is one other person */
211                 if (ast_stream_and_wait(conference_bridge_user->chan, "conf-onlyone", "")) {
212                         return;
213                 }
214         } else {
215                 /* Alas multiple others in here */
216                 if (ast_stream_and_wait(conference_bridge_user->chan, "conf-thereare", "")) {
217                         return;
218                 }
219                 if (ast_say_number(conference_bridge_user->chan, conference_bridge->users - 1, "", conference_bridge_user->chan->language, NULL)) {
220                         return;
221                 }
222                 if (ast_stream_and_wait(conference_bridge_user->chan, "conf-otherinparty", "")) {
223                         return;
224                 }
225         }
226 }
227
228 /*!
229  * \brief Play back an audio file to a channel
230  *
231  * \param conference_bridge Conference bridge they are in
232  * \param chan Channel to play audio prompt to
233  * \param file Prompt to play
234  *
235  * \return Returns nothing
236  *
237  * \note This function assumes that conference_bridge is locked
238  */
239 static void play_prompt_to_channel(struct conference_bridge *conference_bridge, struct ast_channel *chan, const char *file)
240 {
241         ao2_unlock(conference_bridge);
242         ast_stream_and_wait(chan, file, "");
243         ao2_lock(conference_bridge);
244 }
245
246 /*!
247  * \brief Perform post-joining marked specific actions
248  *
249  * \param conference_bridge Conference bridge being joined
250  * \param conference_bridge_user Conference bridge user joining
251  *
252  * \return Returns nothing
253  */
254 static void post_join_marked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
255 {
256         if (ast_test_flag(&conference_bridge_user->flags, OPTION_MARKEDUSER)) {
257                 struct conference_bridge_user *other_conference_bridge_user = NULL;
258
259                 /* If we are not the first marked user to join just bail out now */
260                 if (conference_bridge->markedusers >= 2) {
261                         return;
262                 }
263
264                 /* Iterate through every participant stopping MOH on them if need be */
265                 AST_LIST_TRAVERSE(&conference_bridge->users_list, other_conference_bridge_user, list) {
266                         if (other_conference_bridge_user == conference_bridge_user) {
267                                 continue;
268                         }
269                         if (ast_test_flag(&other_conference_bridge_user->flags, OPTION_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, other_conference_bridge_user->chan)) {
270                                 ast_moh_stop(other_conference_bridge_user->chan);
271                                 ast_bridge_unsuspend(conference_bridge->bridge, other_conference_bridge_user->chan);
272                         }
273                 }
274
275                 /* Next play the audio file stating they are going to be placed into the conference */
276                 if (!ast_test_flag(&conference_bridge_user->flags, OPTION_QUIET)) {
277                         ao2_unlock(conference_bridge);
278                         ast_autoservice_start(conference_bridge_user->chan);
279                         play_sound_file(conference_bridge, "conf-placeintoconf");
280                         ast_autoservice_stop(conference_bridge_user->chan);
281                         ao2_lock(conference_bridge);
282                 }
283
284                 /* Finally iterate through and unmute them all */
285                 AST_LIST_TRAVERSE(&conference_bridge->users_list, other_conference_bridge_user, list) {
286                         if (other_conference_bridge_user == conference_bridge_user) {
287                                 continue;
288                         }
289                         other_conference_bridge_user->features.mute = 0;
290                 }
291
292         } else {
293                 /* If a marked user already exists in the conference bridge we can just bail out now */
294                 if (conference_bridge->markedusers) {
295                         return;
296                 }
297                 /* Be sure we are muted so we can't talk to anybody else waiting */
298                 conference_bridge_user->features.mute = 1;
299                 /* If we have not been quieted play back that they are waiting for the leader */
300                 if (!ast_test_flag(&conference_bridge_user->flags, OPTION_QUIET)) {
301                         play_prompt_to_channel(conference_bridge, conference_bridge_user->chan, "conf-waitforleader");
302                 }
303                 /* Start music on hold if needed */
304                 /* We need to recheck the markedusers value here. play_prompt_to_channel unlocks the conference bridge, potentially
305                  * allowing a marked user to enter while the prompt was playing
306                  */
307                 if (!conference_bridge->markedusers && ast_test_flag(&conference_bridge_user->flags, OPTION_MUSICONHOLD)) {
308                         ast_moh_start(conference_bridge_user->chan, conference_bridge_user->opt_args[OPTION_MUSICONHOLD_CLASS], NULL);
309                 }
310         }
311 }
312
313 /*!
314  * \brief Perform post-joining non-marked specific actions
315  *
316  * \param conference_bridge Conference bridge being joined
317  * \param conference_bridge_user Conference bridge user joining
318  *
319  * \return Returns nothing
320  */
321 static void post_join_unmarked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
322 {
323         /* Play back audio prompt and start MOH if need be if we are the first participant */
324         if (conference_bridge->users == 1) {
325                 /* If audio prompts have not been quieted or this prompt quieted play it on out */
326                 if (!ast_test_flag(&conference_bridge_user->flags, OPTION_QUIET | OPTION_NOONLYPERSON)) {
327                         play_prompt_to_channel(conference_bridge, conference_bridge_user->chan, "conf-onlyperson");
328                 }
329                 /* If we need to start music on hold on the channel do so now */
330                 /* We need to re-check the number of users in the conference bridge here because another conference bridge
331                  * participant could have joined while the above prompt was playing for the first user.
332                  */
333                 if (conference_bridge->users == 1 && ast_test_flag(&conference_bridge_user->flags, OPTION_MUSICONHOLD)) {
334                         ast_moh_start(conference_bridge_user->chan, conference_bridge_user->opt_args[OPTION_MUSICONHOLD_CLASS], NULL);
335                 }
336                 return;
337         }
338
339         /* Announce number of users if need be */
340         if (ast_test_flag(&conference_bridge_user->flags, OPTION_ANNOUNCEUSERCOUNT)) {
341                 ao2_unlock(conference_bridge);
342                 announce_user_count(conference_bridge, conference_bridge_user);
343                 ao2_lock(conference_bridge);
344         }
345
346         /* If we are the second participant we may need to stop music on hold on the first */
347         if (conference_bridge->users == 2) {
348                 struct conference_bridge_user *first_participant = AST_LIST_FIRST(&conference_bridge->users_list);
349
350                 /* Temporarily suspend the above participant from the bridge so we have control to stop MOH if needed */
351                 if (ast_test_flag(&first_participant->flags, OPTION_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, first_participant->chan)) {
352                         ast_moh_stop(first_participant->chan);
353                         ast_bridge_unsuspend(conference_bridge->bridge, first_participant->chan);
354                 }
355         }
356 }
357
358 /*!
359  * \brief Destroy a conference bridge
360  *
361  * \param obj The conference bridge object
362  *
363  * \return Returns nothing
364  */
365 static void destroy_conference_bridge(void *obj)
366 {
367         struct conference_bridge *conference_bridge = obj;
368
369         ast_debug(1, "Destroying conference bridge '%s'\n", conference_bridge->name);
370
371         ast_mutex_destroy(&conference_bridge->playback_lock);
372
373         if (conference_bridge->playback_chan) {
374                 struct ast_channel *underlying_channel = conference_bridge->playback_chan->tech->bridged_channel(conference_bridge->playback_chan, NULL);
375                 ast_hangup(underlying_channel);
376                 ast_hangup(conference_bridge->playback_chan);
377                 conference_bridge->playback_chan = NULL;
378         }
379
380         /* Destroying a conference bridge is simple, all we have to do is destroy the bridging object */
381         if (conference_bridge->bridge) {
382                 ast_bridge_destroy(conference_bridge->bridge);
383                 conference_bridge->bridge = NULL;
384         }
385 }
386
387 /*!
388  * \brief Join a conference bridge
389  *
390  * \param name The conference name
391  * \param conference_bridge_user Conference bridge user structure
392  *
393  * \return A pointer to the conference bridge struct, or NULL if the conference room wasn't found.
394  */
395 static struct conference_bridge *join_conference_bridge(const char *name, struct conference_bridge_user *conference_bridge_user)
396 {
397         struct conference_bridge *conference_bridge = NULL;
398         struct conference_bridge tmp;
399
400         ast_copy_string(tmp.name, name, sizeof(tmp.name));
401
402         /* We explictly lock the conference bridges container ourselves so that other callers can not create duplicate conferences at the same */
403         ao2_lock(conference_bridges);
404
405         ast_debug(1, "Trying to find conference bridge '%s'\n", name);
406
407         /* Attempt to find an existing conference bridge */
408         conference_bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
409
410         /* When finding a conference bridge that already exists make sure that it is not locked, and if so that we are not an admin */
411         if (conference_bridge && conference_bridge->locked && !ast_test_flag(&conference_bridge_user->flags, OPTION_ADMIN)) {
412                 ao2_unlock(conference_bridges);
413                 ao2_ref(conference_bridge, -1);
414                 ast_debug(1, "Conference bridge '%s' is locked and caller is not an admin\n", name);
415                 ast_stream_and_wait(conference_bridge_user->chan, "conf-locked", "");
416                 return NULL;
417         }
418
419         /* If no conference bridge was found see if we can create one */
420         if (!conference_bridge) {
421                 /* Try to allocate memory for a new conference bridge, if we fail... this won't end well. */
422                 if (!(conference_bridge = ao2_alloc(sizeof(*conference_bridge), destroy_conference_bridge))) {
423                         ao2_unlock(conference_bridges);
424                         ast_log(LOG_ERROR, "Conference bridge '%s' does not exist.\n", name);
425                         return NULL;
426                 }
427
428                 /* Setup conference bridge parameters */
429                 ast_copy_string(conference_bridge->name, name, sizeof(conference_bridge->name));
430
431                 /* Create an actual bridge that will do the audio mixing */
432                 if (!(conference_bridge->bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_1TO1MIX, AST_BRIDGE_FLAG_SMART))) {
433                         ao2_ref(conference_bridge, -1);
434                         conference_bridge = NULL;
435                         ao2_unlock(conference_bridges);
436                         ast_log(LOG_ERROR, "Conference bridge '%s' could not be created.\n", name);
437                         return NULL;
438                 }
439
440                 /* Setup lock for playback channel */
441                 ast_mutex_init(&conference_bridge->playback_lock);
442
443                 /* Link it into the conference bridges container */
444                 ao2_link(conference_bridges, conference_bridge);
445
446                 ast_debug(1, "Created conference bridge '%s' and linked to container '%p'\n", name, conference_bridges);
447         }
448
449         ao2_unlock(conference_bridges);
450
451         /* Setup conference bridge user parameters */
452         conference_bridge_user->conference_bridge = conference_bridge;
453
454         ao2_lock(conference_bridge);
455
456         /* All good to go, add them in */
457         AST_LIST_INSERT_TAIL(&conference_bridge->users_list, conference_bridge_user, list);
458
459         /* Increment the users count on the bridge, but record it as it is going to need to be known right after this */
460         conference_bridge->users++;
461
462         /* If the caller is a marked user bump up the count */
463         if (ast_test_flag(&conference_bridge_user->flags, OPTION_MARKEDUSER)) {
464                 conference_bridge->markedusers++;
465         }
466
467         /* Set the device state for this conference */
468         if (conference_bridge->users == 1) {
469                 ast_devstate_changed(AST_DEVICE_INUSE, "confbridge:%s", conference_bridge->name);
470         }
471
472         /* 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 */
473         if (ast_test_flag(&conference_bridge_user->flags, OPTION_MARKEDUSER | OPTION_WAITMARKED)) {
474                 post_join_marked(conference_bridge, conference_bridge_user);
475         } else {
476                 post_join_unmarked(conference_bridge, conference_bridge_user);
477         }
478
479         ao2_unlock(conference_bridge);
480
481         return conference_bridge;
482 }
483
484 /*!
485  * \brief Leave a conference bridge
486  *
487  * \param conference_bridge The conference bridge to leave
488  * \param conference_bridge_user The conference bridge user structure
489  *
490  */
491 static void  leave_conference_bridge(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
492 {
493         ao2_lock(conference_bridge);
494
495         /* If this caller is a marked user bump down the count */
496         if (ast_test_flag(&conference_bridge_user->flags, OPTION_MARKEDUSER)) {
497                 conference_bridge->markedusers--;
498         }
499
500         /* Decrement the users count while keeping the previous participant count */
501         conference_bridge->users--;
502
503         /* Drop conference bridge user from the list, they be going bye bye */
504         AST_LIST_REMOVE(&conference_bridge->users_list, conference_bridge_user, list);
505
506         /* If there are still users in the conference bridge we may need to do things (such as start MOH on them) */
507         if (conference_bridge->users) {
508                 if (ast_test_flag(&conference_bridge_user->flags, OPTION_MARKEDUSER) && !conference_bridge->markedusers) {
509                         struct conference_bridge_user *other_participant = NULL;
510
511                         /* Start out with muting everyone */
512                         AST_LIST_TRAVERSE(&conference_bridge->users_list, other_participant, list) {
513                                 other_participant->features.mute = 1;
514                         }
515
516                         /* Play back the audio prompt saying the leader has left the conference */
517                         if (!ast_test_flag(&conference_bridge_user->flags, OPTION_QUIET)) {
518                                 ao2_unlock(conference_bridge);
519                                 ast_autoservice_start(conference_bridge_user->chan);
520                                 play_sound_file(conference_bridge, "conf-leaderhasleft");
521                                 ast_autoservice_stop(conference_bridge_user->chan);
522                                 ao2_lock(conference_bridge);
523                         }
524
525                         /* Now on to starting MOH if needed */
526                         AST_LIST_TRAVERSE(&conference_bridge->users_list, other_participant, list) {
527                                 if (ast_test_flag(&other_participant->flags, OPTION_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, other_participant->chan)) {
528                                         ast_moh_start(other_participant->chan, other_participant->opt_args[OPTION_MUSICONHOLD_CLASS], NULL);
529                                         ast_bridge_unsuspend(conference_bridge->bridge, other_participant->chan);
530                                 }
531                         }
532                 } else if (conference_bridge->users == 1) {
533                         /* Of course if there is one other person in here we may need to start up MOH on them */
534                         struct conference_bridge_user *first_participant = AST_LIST_FIRST(&conference_bridge->users_list);
535
536                         if (ast_test_flag(&first_participant->flags, OPTION_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, first_participant->chan)) {
537                                 ast_moh_start(first_participant->chan, first_participant->opt_args[OPTION_MUSICONHOLD_CLASS], NULL);
538                                 ast_bridge_unsuspend(conference_bridge->bridge, first_participant->chan);
539                         }
540                 }
541         } else {
542                 /* Set device state to "not in use" */
543                 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "confbridge:%s", conference_bridge->name);
544
545                 ao2_unlink(conference_bridges, conference_bridge);
546         }
547
548         /* Done mucking with the conference bridge, huzzah */
549         ao2_unlock(conference_bridge);
550
551         ao2_ref(conference_bridge, -1);
552 }
553
554 /*!
555  * \brief Play sound file into conference bridge
556  *
557  * \param conference_bridge The conference bridge to play sound file into
558  * \param filename Sound file to play
559  *
560  * \retval 0 success
561  * \retval -1 failure
562  */
563 static int play_sound_file(struct conference_bridge *conference_bridge, const char *filename)
564 {
565         struct ast_channel *underlying_channel;
566
567         ast_mutex_lock(&conference_bridge->playback_lock);
568
569         if (!(conference_bridge->playback_chan)) {
570                 int cause;
571                 struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
572                 struct ast_format tmpfmt;
573                 if (!cap) {
574                         return -1;
575                 }
576                 ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
577                 if (!(conference_bridge->playback_chan = ast_request("Bridge", cap, NULL, "", &cause))) {
578                         ast_mutex_unlock(&conference_bridge->playback_lock);
579                         cap = ast_format_cap_destroy(cap);
580                         return -1;
581                 }
582                 cap = ast_format_cap_destroy(cap);
583
584                 conference_bridge->playback_chan->bridge = conference_bridge->bridge;
585
586                 if (ast_call(conference_bridge->playback_chan, "", 0)) {
587                         ast_hangup(conference_bridge->playback_chan);
588                         conference_bridge->playback_chan = NULL;
589                         ast_mutex_unlock(&conference_bridge->playback_lock);
590                         return -1;
591                 }
592
593                 ast_debug(1, "Created a playback channel to conference bridge '%s'\n", conference_bridge->name);
594
595                 underlying_channel = conference_bridge->playback_chan->tech->bridged_channel(conference_bridge->playback_chan, NULL);
596         } else {
597                 /* Channel was already available so we just need to add it back into the bridge */
598                 underlying_channel = conference_bridge->playback_chan->tech->bridged_channel(conference_bridge->playback_chan, NULL);
599                 ast_bridge_impart(conference_bridge->bridge, underlying_channel, NULL, NULL);
600         }
601
602         /* The channel is all under our control, in goes the prompt */
603         ast_stream_and_wait(conference_bridge->playback_chan, filename, "");
604
605         ast_debug(1, "Departing underlying channel '%s' from bridge '%p'\n", underlying_channel->name, conference_bridge->bridge);
606         ast_bridge_depart(conference_bridge->bridge, underlying_channel);
607
608         ast_mutex_unlock(&conference_bridge->playback_lock);
609
610         return 0;
611 }
612
613 /*!
614  * \brief DTMF Menu Callback
615  *
616  * \param bridge Bridge this is involving
617  * \param bridge_channel Bridged channel this is involving
618  * \param hook_pvt User's conference bridge structure
619  *
620  * \retval 0 success
621  * \retval -1 failure
622  */
623 static int menu_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
624 {
625         struct conference_bridge_user *conference_bridge_user = hook_pvt;
626         struct conference_bridge *conference_bridge = conference_bridge_user->conference_bridge;
627         int digit, res = 0, isadmin = ast_test_flag(&conference_bridge_user->flags, OPTION_ADMIN);
628
629         /* See if music on hold is playing */
630         ao2_lock(conference_bridge);
631         if (conference_bridge->users == 1 && ast_test_flag(&conference_bridge_user->flags, OPTION_MUSICONHOLD)) {
632                 /* Just us so MOH is probably indeed going, let's stop it */
633                 ast_moh_stop(bridge_channel->chan);
634         }
635         ao2_unlock(conference_bridge);
636
637         /* Try to play back the user menu, if it fails pass this back up so the bridging core will act on it */
638         if (ast_streamfile(bridge_channel->chan, (isadmin ? "conf-adminmenu" : "conf-usermenu"), bridge_channel->chan->language)) {
639                 res = -1;
640                 goto finished;
641         }
642
643         /* Wait for them to enter a digit from the user menu options */
644         digit = ast_waitstream(bridge_channel->chan, AST_DIGIT_ANY);
645         ast_stopstream(bridge_channel->chan);
646
647         if (digit == '1') {
648                 /* 1 - Mute or unmute yourself, note we only allow manipulation if they aren't waiting for a marked user or if marked users exist */
649                 if (!ast_test_flag(&conference_bridge_user->flags, OPTION_WAITMARKED) || conference_bridge->markedusers) {
650                         conference_bridge_user->features.mute = (!conference_bridge_user->features.mute ? 1 : 0);
651                 }
652                 res = ast_stream_and_wait(bridge_channel->chan, (conference_bridge_user->features.mute ? "conf-muted" : "conf-unmuted"), "");
653         } else if (isadmin && digit == '2') {
654                 /* 2 - Unlock or lock conference */
655                 conference_bridge->locked = (!conference_bridge->locked ? 1 : 0);
656                 res = ast_stream_and_wait(bridge_channel->chan, (conference_bridge->locked ? "conf-lockednow" : "conf-unlockednow"), "");
657         } else if (isadmin && digit == '3') {
658                 /* 3 - Eject last user */
659                 struct conference_bridge_user *last_participant = NULL;
660
661                 ao2_lock(conference_bridge);
662                 if (((last_participant = AST_LIST_LAST(&conference_bridge->users_list)) == conference_bridge_user) || (ast_test_flag(&last_participant->flags, OPTION_ADMIN))) {
663                         ao2_unlock(conference_bridge);
664                         res = ast_stream_and_wait(bridge_channel->chan, "conf-errormenu", "");
665                 } else {
666                         last_participant->kicked = 1;
667                         ast_bridge_remove(conference_bridge->bridge, last_participant->chan);
668                         ao2_unlock(conference_bridge);
669                 }
670         } else if (digit == '4') {
671                 /* 4 - Decrease listening volume */
672                 ast_audiohook_volume_adjust(conference_bridge_user->chan, AST_AUDIOHOOK_DIRECTION_WRITE, -1);
673         } else if (digit == '6') {
674                 /* 6 - Increase listening volume */
675                 ast_audiohook_volume_adjust(conference_bridge_user->chan, AST_AUDIOHOOK_DIRECTION_WRITE, 1);
676         } else if (digit == '7') {
677                 /* 7 - Decrease talking volume */
678                 ast_audiohook_volume_adjust(conference_bridge_user->chan, AST_AUDIOHOOK_DIRECTION_READ, -1);
679         } else if (digit == '8') {
680                 /* 8 - Exit the IVR */
681         } else if (digit == '9') {
682                 /* 9 - Increase talking volume */
683                 ast_audiohook_volume_adjust(conference_bridge_user->chan, AST_AUDIOHOOK_DIRECTION_READ, 1);
684         } else {
685                 /* No valid option was selected */
686                 res = ast_stream_and_wait(bridge_channel->chan, "conf-errormenu", "");
687         }
688
689  finished:
690         /* See if music on hold needs to be started back up again */
691         ao2_lock(conference_bridge);
692         if (conference_bridge->users == 1 && ast_test_flag(&conference_bridge_user->flags, OPTION_MUSICONHOLD)) {
693                 ast_moh_start(bridge_channel->chan, conference_bridge_user->opt_args[OPTION_MUSICONHOLD_CLASS], NULL);
694         }
695         ao2_unlock(conference_bridge);
696
697         bridge_channel->state = AST_BRIDGE_CHANNEL_STATE_WAIT;
698
699         return res;
700 }
701
702 /*! \brief The ConfBridge application */
703 static int confbridge_exec(struct ast_channel *chan, const char *data)
704 {
705         int res = 0, volume_adjustments[2];
706         char *parse;
707         struct conference_bridge *conference_bridge = NULL;
708         struct conference_bridge_user conference_bridge_user = {
709                 .chan = chan,
710         };
711         const char *tmp, *join_sound = NULL, *leave_sound = NULL;
712         AST_DECLARE_APP_ARGS(args,
713                 AST_APP_ARG(conf_name);
714                 AST_APP_ARG(options);
715         );
716
717         if (ast_strlen_zero(data)) {
718                 ast_log(LOG_WARNING, "%s requires an argument (conference name[,options])\n", app);
719                 return -1;
720         }
721
722         /* We need to make a copy of the input string if we are going to modify it! */
723         parse = ast_strdupa(data);
724
725         AST_STANDARD_APP_ARGS(args, parse);
726
727         if (args.argc == 2) {
728                 ast_app_parse_options(app_opts, &conference_bridge_user.flags, conference_bridge_user.opt_args, args.options);
729         }
730
731         /* Look for a conference bridge matching the provided name */
732         if (!(conference_bridge = join_conference_bridge(args.conf_name, &conference_bridge_user))) {
733                 return -1;
734         }
735
736         /* Keep a copy of volume adjustments so we can restore them later if need be */
737         volume_adjustments[0] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_READ);
738         volume_adjustments[1] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_WRITE);
739
740         /* Always initialize the features structure, we are in most cases always going to need it. */
741         ast_bridge_features_init(&conference_bridge_user.features);
742
743         /* If the menu option is enabled provide a user or admin menu as a custom feature hook */
744         if (ast_test_flag(&conference_bridge_user.flags, OPTION_MENU)) {
745                 ast_bridge_features_hook(&conference_bridge_user.features, "#", menu_callback, &conference_bridge_user);
746         }
747
748         /* If the caller should be joined already muted, make it so */
749         if (ast_test_flag(&conference_bridge_user.flags, OPTION_STARTMUTED)) {
750                 conference_bridge_user.features.mute = 1;
751         }
752
753         /* Grab join/leave sounds from the channel */
754         ast_channel_lock(chan);
755         if ((tmp = pbx_builtin_getvar_helper(chan, "CONFBRIDGE_JOIN_SOUND"))) {
756                 join_sound = ast_strdupa(tmp);
757         }
758         if ((tmp = pbx_builtin_getvar_helper(chan, "CONFBRIDGE_LEAVE_SOUND"))) {
759                 leave_sound = ast_strdupa(tmp);
760         }
761         ast_channel_unlock(chan);
762
763         /* If there is 1 or more people already in the conference then play our join sound unless overridden */
764         if (!ast_test_flag(&conference_bridge_user.flags, OPTION_QUIET) && !ast_strlen_zero(join_sound) && conference_bridge->users >= 2) {
765                 ast_autoservice_start(chan);
766                 play_sound_file(conference_bridge, join_sound);
767                 ast_autoservice_stop(chan);
768         }
769
770         /* Join our conference bridge for real */
771         ast_bridge_join(conference_bridge->bridge, chan, NULL, &conference_bridge_user.features);
772
773         /* If there is 1 or more people (not including us) already in the conference then play our leave sound unless overridden */
774         if (!ast_test_flag(&conference_bridge_user.flags, OPTION_QUIET) && !ast_strlen_zero(leave_sound) && conference_bridge->users >= 2) {
775                 ast_autoservice_start(chan);
776                 play_sound_file(conference_bridge, leave_sound);
777                 ast_autoservice_stop(chan);
778         }
779
780         /* Easy as pie, depart this channel from the conference bridge */
781         leave_conference_bridge(conference_bridge, &conference_bridge_user);
782         conference_bridge = NULL;
783
784         /* Can't forget to clean up the features structure, or else we risk a memory leak */
785         ast_bridge_features_cleanup(&conference_bridge_user.features);
786
787         /* If the user was kicked from the conference play back the audio prompt for it */
788         if (!ast_test_flag(&conference_bridge_user.flags, OPTION_QUIET) && conference_bridge_user.kicked) {
789                 res = ast_stream_and_wait(chan, "conf-kicked", "");
790         }
791
792         /* Restore volume adjustments to previous values in case they were changed */
793         if (volume_adjustments[0]) {
794                 ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_READ, volume_adjustments[0]);
795         }
796         if (volume_adjustments[1]) {
797                 ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_WRITE, volume_adjustments[1]);
798         }
799
800         return res;
801 }
802
803 static char *complete_confbridge_name(const char *line, const char *word, int pos, int state)
804 {
805         int which = 0;
806         struct conference_bridge *bridge = NULL;
807         char *res = NULL;
808         int wordlen = strlen(word);
809         struct ao2_iterator i;
810
811         i = ao2_iterator_init(conference_bridges, 0);
812         while ((bridge = ao2_iterator_next(&i))) {
813                 if (!strncasecmp(bridge->name, word, wordlen) && ++which > state) {
814                         res = ast_strdup(bridge->name);
815                         ao2_ref(bridge, -1);
816                         break;
817                 }
818                 ao2_ref(bridge, -1);
819         }
820         ao2_iterator_destroy(&i);
821
822         return res;
823 }
824
825 static char *handle_cli_confbridge_kick(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
826 {
827
828         struct conference_bridge *bridge = NULL;
829         struct conference_bridge tmp;
830         struct conference_bridge_user *participant = NULL;
831
832         switch (cmd) {
833         case CLI_INIT:
834                 e->command = "confbridge kick";
835                 e->usage =
836                         "Usage: confbridge kick <name> <channel>\n"
837                         "       Kicks a channel out of the conference bridge.\n";
838                 return NULL;
839         case CLI_GENERATE:
840                 if (a->pos == 2) {
841                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
842                 }
843                 /*
844                 if (a->pos == 3) {
845                         return complete_confbridge_channel(a->line, a->word, a->pos, a->n);
846                 }
847                 */
848                 return NULL;
849         }
850
851         if (a->argc != 4) {
852                 return CLI_SHOWUSAGE;
853         }
854
855         ast_copy_string(tmp.name, a->argv[2], sizeof(tmp.name));
856         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
857         if (!bridge) {
858                 ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
859                 return CLI_SUCCESS;
860         }
861         ao2_lock(bridge);
862         AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
863                 if (!strncmp(a->argv[3], participant->chan->name, strlen(participant->chan->name))) {
864                         break;
865                 }
866         }
867         if (participant) {
868                 ast_cli(a->fd, "Kicking %s from confbridge %s\n", participant->chan->name, bridge->name);
869                 participant->kicked = 1;
870                 ast_bridge_remove(bridge->bridge, participant->chan);
871         }
872         ao2_unlock(bridge);
873         ao2_ref(bridge, -1);
874         return CLI_SUCCESS;
875 }
876
877 static char *handle_cli_confbridge_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
878 {
879         struct ao2_iterator i;
880         struct conference_bridge *bridge = NULL;
881         struct conference_bridge tmp;
882         struct conference_bridge_user *participant = NULL;
883
884         switch (cmd) {
885         case CLI_INIT:
886                 e->command = "confbridge list";
887                 e->usage =
888                         "Usage: confbridge list [<name>]\n"
889                         "       Lists all currently active conference bridges.\n";
890                 return NULL;
891         case CLI_GENERATE:
892                 if (a->pos == 2) {
893                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
894                 }
895                 return NULL;
896         }
897
898         if (a->argc == 2) {
899                 ast_cli(a->fd, "Conference Bridge Name           Users  Marked Locked?\n");
900                 ast_cli(a->fd, "================================ ====== ====== ========\n");
901                 i = ao2_iterator_init(conference_bridges, 0);
902                 while ((bridge = ao2_iterator_next(&i))) {
903                         ast_cli(a->fd, "%-32s %6i %6i %s\n", bridge->name, bridge->users, bridge->markedusers, (bridge->locked ? "locked" : "unlocked"));
904                         ao2_ref(bridge, -1);
905                 }
906                 ao2_iterator_destroy(&i);
907                 return CLI_SUCCESS;
908         }
909
910         if (a->argc == 3) {
911                 ast_copy_string(tmp.name, a->argv[2], sizeof(tmp.name));
912                 bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
913                 if (!bridge) {
914                         ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
915                         return CLI_SUCCESS;
916                 }
917                 ast_cli(a->fd, "Channel                          Flags\n");
918                 ast_cli(a->fd, "================================ ================\n");
919                 ao2_lock(bridge);
920                 AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
921                         ast_cli(a->fd, "%-32s ", participant->chan->name);
922                         if (ast_test_flag(&participant->flags, OPTION_MARKEDUSER)) {
923                                 ast_cli(a->fd, "A");
924                         }
925                         if (ast_test_flag(&participant->flags, OPTION_ADMIN)) {
926                                 ast_cli(a->fd, "a");
927                         }
928                         if (ast_test_flag(&participant->flags, OPTION_ANNOUNCEUSERCOUNT)) {
929                                 ast_cli(a->fd, "c");
930                         }
931                         if (ast_test_flag(&participant->flags, OPTION_MENU)) {
932                                 ast_cli(a->fd, "m");
933                         }
934                         if (ast_test_flag(&participant->flags, OPTION_MUSICONHOLD)) {
935                                 ast_cli(a->fd, "M(%s)", participant->opt_args[OPTION_MUSICONHOLD_CLASS]);
936                         }
937                         if (ast_test_flag(&participant->flags, OPTION_NOONLYPERSON)) {
938                                 ast_cli(a->fd, "1");
939                         }
940                         if (ast_test_flag(&participant->flags, OPTION_STARTMUTED)) {
941                                 ast_cli(a->fd, "s");
942                         }
943                         if (ast_test_flag(&participant->flags, OPTION_WAITMARKED)) {
944                                 ast_cli(a->fd, "w");
945                         }
946                         if (ast_test_flag(&participant->flags, OPTION_QUIET)) {
947                                 ast_cli(a->fd, "q");
948                         }
949                         ast_cli(a->fd, "\n");
950                 }
951                 ao2_unlock(bridge);
952                 ao2_ref(bridge, -1);
953                 return CLI_SUCCESS;
954         }
955
956         return CLI_SHOWUSAGE;
957 }
958
959 static struct ast_cli_entry cli_confbridge[] = {
960         AST_CLI_DEFINE(handle_cli_confbridge_list, "List conference bridges and participants."),
961         AST_CLI_DEFINE(handle_cli_confbridge_kick, "Kick participants out of conference bridges.")
962 };
963
964 /*! \brief Called when module is being unloaded */
965 static int unload_module(void)
966 {
967         int res = ast_unregister_application(app);
968
969         ast_cli_unregister_multiple(cli_confbridge, sizeof(cli_confbridge) / sizeof(struct ast_cli_entry));
970
971         /* Get rid of the conference bridges container. Since we only allow dynamic ones none will be active. */
972         ao2_ref(conference_bridges, -1);
973
974         return res;
975 }
976
977 /*! \brief Called when module is being loaded */
978 static int load_module(void)
979 {
980         /* Create a container to hold the conference bridges */
981         if (!(conference_bridges = ao2_container_alloc(CONFERENCE_BRIDGE_BUCKETS, conference_bridge_hash_cb, conference_bridge_cmp_cb))) {
982                 return AST_MODULE_LOAD_DECLINE;
983         }
984
985         if (ast_register_application_xml(app, confbridge_exec)) {
986                 ao2_ref(conference_bridges, -1);
987                 return AST_MODULE_LOAD_DECLINE;
988         }
989
990         ast_cli_register_multiple(cli_confbridge, sizeof(cli_confbridge) / sizeof(struct ast_cli_entry));
991
992         return AST_MODULE_LOAD_SUCCESS;
993 }
994
995 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Conference Bridge Application",
996         .load = load_module,
997         .unload = unload_module,
998         .load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
999 );