Merge in the bridge_construction branch to make the system use the Bridging API.
[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 /* BUGBUG Add IDLE_MODE_HOLD option to put channel on hold using AST_CONTROL_HOLD/AST_CONTROL_UNHOLD while in bridge */
58 /* BUGBUG Add IDLE_MODE_SILENCE to send silence media frames to channel while in bridge (uses a silence generator) */
59 /* BUGBUG A channel without the holding_participant role will assume IDLE_MODE_MOH with the default music class. */
60 enum idle_modes {
61         IDLE_MODE_NONE = 0,
62         IDLE_MODE_MOH,
63         IDLE_MODE_RINGING,
64 };
65
66 /*! \brief Structure which contains per-channel role information */
67 struct holding_channel {
68         struct ast_flags holding_roles;
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         }
89 }
90
91 static void participant_reaction_announcer_join(struct ast_bridge_channel *bridge_channel)
92 {
93         struct ast_channel *chan;
94         chan = bridge_channel->chan;
95         participant_stop_hold_audio(bridge_channel);
96         if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) {
97                 ast_log(LOG_WARNING, "Could not make participant %s compatible.\n", ast_channel_name(chan));
98         }
99 }
100
101 /* This should only be called on verified holding_participants. */
102 static void participant_start_hold_audio(struct ast_bridge_channel *bridge_channel)
103 {
104         struct holding_channel *hc = bridge_channel->tech_pvt;
105         const char *moh_class;
106
107         if (!hc) {
108                 return;
109         }
110
111         switch(hc->idle_mode) {
112         case IDLE_MODE_MOH:
113                 moh_class = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "moh_class");
114                 ast_moh_start(bridge_channel->chan, ast_strlen_zero(moh_class) ? NULL : moh_class, NULL);
115                 break;
116         case IDLE_MODE_RINGING:
117                 ast_indicate(bridge_channel->chan, AST_CONTROL_RINGING);
118                 break;
119         case IDLE_MODE_NONE:
120                 break;
121         }
122 }
123
124 static void handle_participant_join(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *announcer_channel)
125 {
126         struct ast_channel *us = bridge_channel->chan;
127         struct holding_channel *hc = bridge_channel->tech_pvt;
128         const char *idle_mode = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "idle_mode");
129
130
131         if (!hc) {
132                 return;
133         }
134
135         if (ast_strlen_zero(idle_mode)) {
136                 hc->idle_mode = IDLE_MODE_NONE;
137         } else if (!strcmp(idle_mode, "musiconhold")) {
138                 hc->idle_mode = IDLE_MODE_MOH;
139         } else if (!strcmp(idle_mode, "ringing")) {
140                 hc->idle_mode = IDLE_MODE_RINGING;
141         } else {
142                 ast_debug(2, "channel %s idle mode '%s' doesn't match any expected idle mode\n", ast_channel_name(us), idle_mode);
143         }
144
145         /* If the announcer channel isn't present, we need to set up ringing, music on hold, or whatever. */
146         if (!announcer_channel) {
147                 participant_start_hold_audio(bridge_channel);
148                 return;
149         }
150
151         /* If it is present though, we need to establish compatability. */
152         if (ast_set_write_format_by_id(us, AST_FORMAT_SLINEAR)) {
153                 ast_log(LOG_WARNING, "Could not make participant %s compatible.\n", ast_channel_name(us));
154         }
155 }
156
157 static int holding_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
158 {
159         struct ast_bridge_channel *other_channel;
160         struct ast_bridge_channel *announcer_channel;
161         struct holding_channel *hc;
162         struct ast_channel *us = bridge_channel->chan; /* The joining channel */
163
164         if (!(hc = ast_calloc(1, sizeof(*hc)))) {
165                 return -1;
166         }
167
168         bridge_channel->tech_pvt = hc;
169
170         /* The bridge pvt holds the announcer channel if we have one. */
171         announcer_channel = bridge->tech_pvt;
172
173         if (ast_bridge_channel_has_role(bridge_channel, "announcer")) {
174                 /* If another announcer already exists, scrap the holding channel struct so we know to ignore it in the future */
175                 if (announcer_channel) {
176                         bridge_channel->tech_pvt = NULL;
177                         ast_free(hc);
178                         ast_log(LOG_WARNING, "A second announcer channel %s attempted to enter a holding bridge.\n",
179                                 ast_channel_name(announcer_channel->chan));
180                         return -1;
181                 }
182
183                 bridge->tech_pvt = bridge_channel;
184                 ast_set_flag(&hc->holding_roles, HOLDING_ROLE_ANNOUNCER);
185
186                 /* The announcer should always be made compatible with signed linear */
187                 if (ast_set_read_format_by_id(us, AST_FORMAT_SLINEAR)) {
188                         ast_log(LOG_ERROR, "Could not make announcer %s compatible.\n", ast_channel_name(us));
189                 }
190
191                 /* Make everyone compatible. While we are at it we should stop music on hold and ringing. */
192                 AST_LIST_TRAVERSE(&bridge->channels, other_channel, entry) {
193                         /* Skip the reaction if we are the channel in question */
194                         if (bridge_channel == other_channel) {
195                                 continue;
196                         }
197                         participant_reaction_announcer_join(other_channel);
198                 }
199
200                 return 0;
201         }
202
203         /* 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 */
204         ast_set_flag(&hc->holding_roles, HOLDING_ROLE_PARTICIPANT);
205         handle_participant_join(bridge_channel, announcer_channel);
206         return 0;
207 }
208
209 static void participant_reaction_announcer_leave(struct ast_bridge_channel *bridge_channel)
210 {
211         struct holding_channel *hc = bridge_channel->tech_pvt;
212
213         if (!hc) {
214                 /* We are dealing with a channel that failed to join properly. Skip it. */
215                 return;
216         }
217
218         ast_bridge_channel_restore_formats(bridge_channel);
219         if (ast_test_flag(&hc->holding_roles, HOLDING_ROLE_PARTICIPANT)) {
220                 participant_start_hold_audio(bridge_channel);
221         }
222 }
223
224 static void holding_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
225 {
226         struct ast_bridge_channel *other_channel;
227         struct holding_channel *hc = bridge_channel->tech_pvt;
228
229         if (!hc) {
230                 return;
231         }
232
233         if (!ast_test_flag(&hc->holding_roles, HOLDING_ROLE_ANNOUNCER)) {
234                 /* It's not an announcer so nothing needs to react to its departure. Just free the tech_pvt. */
235                 if (!bridge->tech_pvt) {
236                         /* Since no announcer is in the channel, we may be playing MOH/ringing. Stop that. */
237                         participant_stop_hold_audio(bridge_channel);
238                 }
239                 ast_free(hc);
240                 bridge_channel->tech_pvt = NULL;
241                 return;
242         }
243
244         /* When the announcer leaves, the other channels should reset their formats and go back to moh/ringing */
245         AST_LIST_TRAVERSE(&bridge->channels, other_channel, entry) {
246                 participant_reaction_announcer_leave(other_channel);
247         }
248
249         /* Since the announcer is leaving, we should clear the tech_pvt pointing to it */
250         bridge->tech_pvt = NULL;
251
252         ast_free(hc);
253         bridge_channel->tech_pvt = NULL;
254 }
255
256 static int holding_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
257 {
258         struct ast_bridge_channel *cur;
259         struct holding_channel *hc = bridge_channel->tech_pvt;
260
261         /* If there is no tech_pvt, then the channel failed to allocate one when it joined and is borked. Don't listen to him. */
262         if (!hc) {
263                 return -1;
264         }
265
266         /* If we aren't an announcer, we never have any business writing anything. */
267         if (!ast_test_flag(&hc->holding_roles, HOLDING_ROLE_ANNOUNCER)) {
268                 return -1;
269         }
270
271         /* Ok, so we are the announcer and there are one or more people available to receive our writes. Let's do it. */
272         AST_LIST_TRAVERSE(&bridge->channels, cur, entry) {
273                 if (bridge_channel == cur || !cur->tech_pvt) {
274                         continue;
275                 }
276
277                 ast_bridge_channel_queue_frame(cur, frame);
278         }
279
280         return 0;
281 }
282
283 static struct ast_bridge_technology holding_bridge = {
284         .name = "holding_bridge",
285         .capabilities = AST_BRIDGE_CAPABILITY_HOLDING,
286         .preference = AST_BRIDGE_PREFERENCE_BASE_HOLDING,
287         .write = holding_bridge_write,
288         .join = holding_bridge_join,
289         .leave = holding_bridge_leave,
290 };
291
292 static int unload_module(void)
293 {
294         ast_format_cap_destroy(holding_bridge.format_capabilities);
295         return ast_bridge_technology_unregister(&holding_bridge);
296 }
297
298 static int load_module(void)
299 {
300         if (!(holding_bridge.format_capabilities = ast_format_cap_alloc())) {
301                 return AST_MODULE_LOAD_DECLINE;
302         }
303         ast_format_cap_add_all_by_type(holding_bridge.format_capabilities, AST_FORMAT_TYPE_AUDIO);
304         ast_format_cap_add_all_by_type(holding_bridge.format_capabilities, AST_FORMAT_TYPE_VIDEO);
305         ast_format_cap_add_all_by_type(holding_bridge.format_capabilities, AST_FORMAT_TYPE_TEXT);
306
307         return ast_bridge_technology_register(&holding_bridge);
308 }
309
310 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Holding bridge module");
311