bridge_holding/app_bridgewait: Add new entertainment options
[asterisk/asterisk.git] / bridges / bridge_holding.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Jonathan Rose <jrose@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 Bridging technology for storing channels in a bridge for
22  *        the purpose of holding, parking, queues, and other such
23  *        states where a channel may need to be in a bridge but not
24  *        actually communicating with anything.
25  *
26  * \author Jonathan Rose <jrose@digium.com>
27  *
28  * \ingroup bridges
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 <string.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44
45 #include "asterisk/module.h"
46 #include "asterisk/channel.h"
47 #include "asterisk/bridging.h"
48 #include "asterisk/bridging_technology.h"
49 #include "asterisk/frame.h"
50 #include "asterisk/musiconhold.h"
51
52 enum role_flags {
53         HOLDING_ROLE_PARTICIPANT = (1 << 0),
54         HOLDING_ROLE_ANNOUNCER = (1 << 1),
55 };
56
57 enum idle_modes {
58         IDLE_MODE_NONE = 0,
59         IDLE_MODE_MOH,
60         IDLE_MODE_RINGING,
61         IDLE_MODE_SILENCE,
62         IDLE_MODE_HOLD,
63 };
64
65 /*! \brief Structure which contains per-channel role information */
66 struct holding_channel {
67         struct ast_flags holding_roles;
68         struct ast_silence_generator *silence_generator;
69         enum idle_modes idle_mode;
70 };
71
72 static void participant_stop_hold_audio(struct ast_bridge_channel *bridge_channel)
73 {
74         struct holding_channel *hc = bridge_channel->tech_pvt;
75         if (!hc) {
76                 return;
77         }
78
79         switch (hc->idle_mode) {
80         case IDLE_MODE_MOH:
81                 ast_moh_stop(bridge_channel->chan);
82                 break;
83         case IDLE_MODE_RINGING:
84                 ast_indicate(bridge_channel->chan, -1);
85                 break;
86         case IDLE_MODE_NONE:
87                 break;
88         case IDLE_MODE_SILENCE:
89                 if (hc->silence_generator) {
90                         ast_channel_stop_silence_generator(bridge_channel->chan, hc->silence_generator);
91                         hc->silence_generator = NULL;
92                 }
93                 break;
94         case IDLE_MODE_HOLD:
95                 ast_bridge_channel_queue_control_data(bridge_channel, AST_CONTROL_UNHOLD, NULL, 0);
96                 break;
97         }
98 }
99
100 static void participant_reaction_announcer_join(struct ast_bridge_channel *bridge_channel)
101 {
102         struct ast_channel *chan;
103         chan = bridge_channel->chan;
104         participant_stop_hold_audio(bridge_channel);
105         if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) {
106                 ast_log(LOG_WARNING, "Could not make participant %s compatible.\n", ast_channel_name(chan));
107         }
108 }
109
110 /* This should only be called on verified holding_participants. */
111 static void participant_start_hold_audio(struct ast_bridge_channel *bridge_channel)
112 {
113         struct holding_channel *hc = bridge_channel->tech_pvt;
114         const char *moh_class;
115         size_t moh_length;
116
117         if (!hc) {
118                 return;
119         }
120
121         switch(hc->idle_mode) {
122         case IDLE_MODE_MOH:
123                 moh_class = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "moh_class");
124                 ast_moh_start(bridge_channel->chan, ast_strlen_zero(moh_class) ? NULL : moh_class, NULL);
125                 break;
126         case IDLE_MODE_RINGING:
127                 ast_indicate(bridge_channel->chan, AST_CONTROL_RINGING);
128                 break;
129         case IDLE_MODE_NONE:
130                 break;
131         case IDLE_MODE_SILENCE:
132                 hc->silence_generator = ast_channel_start_silence_generator(bridge_channel->chan);
133                 break;
134         case IDLE_MODE_HOLD:
135                 moh_class = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "moh_class");
136                 moh_length = moh_class ? strlen(moh_class + 1) : 0;
137                 ast_bridge_channel_queue_control_data(bridge_channel, AST_CONTROL_HOLD, moh_class, moh_length);
138                 break;
139         }
140 }
141
142 static void handle_participant_join(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *announcer_channel)
143 {
144         struct ast_channel *us = bridge_channel->chan;
145         struct holding_channel *hc = bridge_channel->tech_pvt;
146         const char *idle_mode = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "idle_mode");
147
148
149         if (!hc) {
150                 return;
151         }
152
153         if (ast_strlen_zero(idle_mode)) {
154                 hc->idle_mode = IDLE_MODE_MOH;
155         } else if (!strcmp(idle_mode, "musiconhold")) {
156                 hc->idle_mode = IDLE_MODE_MOH;
157         } else if (!strcmp(idle_mode, "ringing")) {
158                 hc->idle_mode = IDLE_MODE_RINGING;
159         } else if (!strcmp(idle_mode, "none")) {
160                 hc->idle_mode = IDLE_MODE_NONE;
161         } else if (!strcmp(idle_mode, "silence")) {
162                 hc->idle_mode = IDLE_MODE_SILENCE;
163         } else if (!strcmp(idle_mode, "hold")) {
164                 hc->idle_mode = IDLE_MODE_HOLD;
165         } else {
166                 ast_debug(2, "channel %s idle mode '%s' doesn't match any expected idle mode\n", ast_channel_name(us), idle_mode);
167         }
168
169         /* If the announcer channel isn't present, we need to set up ringing, music on hold, or whatever. */
170         if (!announcer_channel) {
171                 participant_start_hold_audio(bridge_channel);
172                 return;
173         }
174
175         /* If it is present though, we need to establish compatability. */
176         if (ast_set_write_format_by_id(us, AST_FORMAT_SLINEAR)) {
177                 ast_log(LOG_WARNING, "Could not make participant %s compatible.\n", ast_channel_name(us));
178         }
179 }
180
181 static int holding_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
182 {
183         struct ast_bridge_channel *other_channel;
184         struct ast_bridge_channel *announcer_channel;
185         struct holding_channel *hc;
186         struct ast_channel *us = bridge_channel->chan; /* The joining channel */
187
188         if (!(hc = ast_calloc(1, sizeof(*hc)))) {
189                 return -1;
190         }
191
192         bridge_channel->tech_pvt = hc;
193
194         /* The bridge pvt holds the announcer channel if we have one. */
195         announcer_channel = bridge->tech_pvt;
196
197         if (ast_bridge_channel_has_role(bridge_channel, "announcer")) {
198                 /* If another announcer already exists, scrap the holding channel struct so we know to ignore it in the future */
199                 if (announcer_channel) {
200                         bridge_channel->tech_pvt = NULL;
201                         ast_free(hc);
202                         ast_log(LOG_WARNING, "A second announcer channel %s attempted to enter a holding bridge.\n",
203                                 ast_channel_name(announcer_channel->chan));
204                         return -1;
205                 }
206
207                 bridge->tech_pvt = bridge_channel;
208                 ast_set_flag(&hc->holding_roles, HOLDING_ROLE_ANNOUNCER);
209
210                 /* The announcer should always be made compatible with signed linear */
211                 if (ast_set_read_format_by_id(us, AST_FORMAT_SLINEAR)) {
212                         ast_log(LOG_ERROR, "Could not make announcer %s compatible.\n", ast_channel_name(us));
213                 }
214
215                 /* Make everyone compatible. While we are at it we should stop music on hold and ringing. */
216                 AST_LIST_TRAVERSE(&bridge->channels, other_channel, entry) {
217                         /* Skip the reaction if we are the channel in question */
218                         if (bridge_channel == other_channel) {
219                                 continue;
220                         }
221                         participant_reaction_announcer_join(other_channel);
222                 }
223
224                 return 0;
225         }
226
227         /* If the entering channel isn't an announcer then we need to setup it's properties and put it in its holding state if necessary */
228         ast_set_flag(&hc->holding_roles, HOLDING_ROLE_PARTICIPANT);
229         handle_participant_join(bridge_channel, announcer_channel);
230         return 0;
231 }
232
233 static void participant_reaction_announcer_leave(struct ast_bridge_channel *bridge_channel)
234 {
235         struct holding_channel *hc = bridge_channel->tech_pvt;
236
237         if (!hc) {
238                 /* We are dealing with a channel that failed to join properly. Skip it. */
239                 return;
240         }
241
242         ast_bridge_channel_restore_formats(bridge_channel);
243         if (ast_test_flag(&hc->holding_roles, HOLDING_ROLE_PARTICIPANT)) {
244                 participant_start_hold_audio(bridge_channel);
245         }
246 }
247
248 static void holding_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
249 {
250         struct ast_bridge_channel *other_channel;
251         struct holding_channel *hc = bridge_channel->tech_pvt;
252
253         if (!hc) {
254                 return;
255         }
256
257         if (!ast_test_flag(&hc->holding_roles, HOLDING_ROLE_ANNOUNCER)) {
258                 /* It's not an announcer so nothing needs to react to its departure. Just free the tech_pvt. */
259                 if (!bridge->tech_pvt) {
260                         /* Since no announcer is in the channel, we may be playing MOH/ringing. Stop that. */
261                         participant_stop_hold_audio(bridge_channel);
262                 }
263                 ast_free(hc);
264                 bridge_channel->tech_pvt = NULL;
265                 return;
266         }
267
268         /* When the announcer leaves, the other channels should reset their formats and go back to moh/ringing */
269         AST_LIST_TRAVERSE(&bridge->channels, other_channel, entry) {
270                 participant_reaction_announcer_leave(other_channel);
271         }
272
273         /* Since the announcer is leaving, we should clear the tech_pvt pointing to it */
274         bridge->tech_pvt = NULL;
275
276         ast_free(hc);
277         bridge_channel->tech_pvt = NULL;
278 }
279
280 static int holding_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
281 {
282         struct holding_channel *hc = bridge_channel ? bridge_channel->tech_pvt : NULL;
283
284         /* If there is no tech_pvt, then the channel failed to allocate one when it joined and is borked. Don't listen to him. */
285         if (!hc) {
286                 /* "Accept" the frame and discard it. */
287                 return 0;
288         }
289
290         /* If we aren't an announcer, we never have any business writing anything. */
291         if (!ast_test_flag(&hc->holding_roles, HOLDING_ROLE_ANNOUNCER)) {
292                 /* "Accept" the frame and discard it. */
293                 return 0;
294         }
295
296         /*
297          * Ok, so we are the announcer.  Write the frame to all other
298          * channels if any.
299          */
300         ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
301
302         return 0;
303 }
304
305 static struct ast_bridge_technology holding_bridge = {
306         .name = "holding_bridge",
307         .capabilities = AST_BRIDGE_CAPABILITY_HOLDING,
308         .preference = AST_BRIDGE_PREFERENCE_BASE_HOLDING,
309         .write = holding_bridge_write,
310         .join = holding_bridge_join,
311         .leave = holding_bridge_leave,
312 };
313
314 static int unload_module(void)
315 {
316         ast_format_cap_destroy(holding_bridge.format_capabilities);
317         return ast_bridge_technology_unregister(&holding_bridge);
318 }
319
320 static int load_module(void)
321 {
322         if (!(holding_bridge.format_capabilities = ast_format_cap_alloc())) {
323                 return AST_MODULE_LOAD_DECLINE;
324         }
325         ast_format_cap_add_all_by_type(holding_bridge.format_capabilities, AST_FORMAT_TYPE_AUDIO);
326         ast_format_cap_add_all_by_type(holding_bridge.format_capabilities, AST_FORMAT_TYPE_VIDEO);
327         ast_format_cap_add_all_by_type(holding_bridge.format_capabilities, AST_FORMAT_TYPE_TEXT);
328
329         return ast_bridge_technology_register(&holding_bridge);
330 }
331
332 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Holding bridge module");
333