Asterisk - The Open Source Telephony Project GIT-master-a358458
bridge_holding.c
Go to the documentation of this file.
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#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <sys/types.h>
41#include <sys/stat.h>
42
43#include "asterisk/module.h"
44#include "asterisk/channel.h"
45#include "asterisk/bridge.h"
47#include "asterisk/frame.h"
50
54};
55
62};
63
64/*! \brief Structure which contains per-channel role information */
69 /*! TRUE if the entertainment is started. */
70 unsigned int entertainment_active:1;
71};
72
73typedef void (*deferred_cb)(struct ast_bridge_channel *bridge_channel);
74
76 /*! Deferred holding technology callback */
78};
79
80static void deferred_action(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size);
81
82/*!
83 * \internal
84 * \brief Defer an action to a bridge_channel.
85 * \since 12.0.0
86 *
87 * \param bridge_channel Which channel to operate on.
88 * \param callback action to defer.
89 *
90 * \retval 0 on success.
91 * \retval -1 on error.
92 */
93static int defer_action(struct ast_bridge_channel *bridge_channel, deferred_cb callback)
94{
95 struct deferred_data data = { .callback = callback };
96 int res;
97
99 &data, sizeof(data));
100 if (res) {
101 ast_log(LOG_WARNING, "Bridge %s: Could not defer action on %s.\n",
102 bridge_channel->bridge->uniqueid, ast_channel_name(bridge_channel->chan));
103 }
104 return res;
105}
106
107/*!
108 * \internal
109 * \brief Setup participant idle mode from channel.
110 * \since 12.0.0
111 *
112 * \param bridge_channel Channel to setup idle mode.
113 */
114static void participant_idle_mode_setup(struct ast_bridge_channel *bridge_channel)
115{
116 const char *idle_mode = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "idle_mode");
117 struct holding_channel *hc = bridge_channel->tech_pvt;
118
119 ast_assert(hc != NULL);
120
123 } else if (!strcmp(idle_mode, "musiconhold")) {
125 } else if (!strcmp(idle_mode, "ringing")) {
127 } else if (!strcmp(idle_mode, "none")) {
129 } else if (!strcmp(idle_mode, "silence")) {
131 } else if (!strcmp(idle_mode, "hold")) {
133 } else {
134 /* Invalid idle mode requested. */
135 ast_debug(1, "channel %s idle mode '%s' doesn't match any defined idle mode\n",
136 ast_channel_name(bridge_channel->chan), idle_mode);
137 ast_assert(0);
138 }
139}
140
141static void participant_entertainment_stop(struct ast_bridge_channel *bridge_channel)
142{
143 struct holding_channel *hc = bridge_channel->tech_pvt;
144
145 ast_assert(hc != NULL);
146
147 if (!hc->entertainment_active) {
148 /* Already stopped */
149 return;
150 }
151 hc->entertainment_active = 0;
152
153 switch (hc->idle_mode) {
154 case IDLE_MODE_MOH:
155 ast_moh_stop(bridge_channel->chan);
156 break;
158 ast_indicate(bridge_channel->chan, -1);
159 break;
160 case IDLE_MODE_NONE:
161 break;
163 if (hc->silence_generator) {
166 }
167 break;
168 case IDLE_MODE_HOLD:
169 ast_indicate(bridge_channel->chan, AST_CONTROL_UNHOLD);
170 break;
171 }
172}
173
175{
176 struct ast_channel *chan;
177
178 chan = bridge_channel->chan;
181 ast_log(LOG_WARNING, "Could not make participant %s compatible.\n", ast_channel_name(chan));
182 }
183}
184
185/* This should only be called on verified holding_participants. */
187{
188 struct holding_channel *hc = bridge_channel->tech_pvt;
189 const char *moh_class;
190 size_t moh_length;
191
192 ast_assert(hc != NULL);
193
194 if (hc->entertainment_active) {
195 /* Already started */
196 return;
197 }
198 hc->entertainment_active = 1;
199
200 participant_idle_mode_setup(bridge_channel);
201 switch(hc->idle_mode) {
202 case IDLE_MODE_MOH:
203 moh_class = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "moh_class");
204 if (ast_moh_start(bridge_channel->chan, moh_class, NULL)) {
205 ast_log(LOG_WARNING, "Failed to start moh, starting silence generator instead\n");
208 }
209 break;
211 ast_indicate(bridge_channel->chan, AST_CONTROL_RINGING);
212 break;
213 case IDLE_MODE_NONE:
214 break;
217 break;
218 case IDLE_MODE_HOLD:
219 moh_class = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "moh_class");
220 moh_length = moh_class ? strlen(moh_class + 1) : 0;
221 ast_indicate_data(bridge_channel->chan, AST_CONTROL_HOLD, moh_class, moh_length);
222 break;
223 }
224}
225
226static void handle_participant_join(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *announcer_channel)
227{
228 struct ast_channel *us = bridge_channel->chan;
229
230 /* If the announcer channel isn't present, we need to set up ringing, music on hold, or whatever. */
231 if (!announcer_channel) {
233 return;
234 }
235
236 /* We need to get compatible with the announcer. */
238 ast_log(LOG_WARNING, "Could not make participant %s compatible.\n", ast_channel_name(us));
239 }
240}
241
243{
244 struct ast_bridge_channel *other_channel;
245 struct ast_bridge_channel *announcer_channel;
246 struct holding_channel *hc;
247 struct ast_channel *us = bridge_channel->chan; /* The joining channel */
248
250
251 if (!(hc = ast_calloc(1, sizeof(*hc)))) {
252 return -1;
253 }
254
256
257 /* The bridge pvt holds the announcer channel if we have one. */
258 announcer_channel = bridge->tech_pvt;
259
261 if (announcer_channel) {
262 /* Another announcer already exists. */
264 ast_free(hc);
265 ast_log(LOG_WARNING, "Bridge %s: Channel %s tried to be an announcer. Bridge already has one.\n",
267 return -1;
268 }
269
272
273 /* The announcer should always be made compatible with signed linear */
275 ast_log(LOG_ERROR, "Could not make announcer %s compatible.\n", ast_channel_name(us));
276 }
277
278 /* Make everyone listen to the announcer. */
279 AST_LIST_TRAVERSE(&bridge->channels, other_channel, entry) {
280 /* Skip the reaction if we are the channel in question */
281 if (bridge_channel == other_channel) {
282 continue;
283 }
285 }
286
287 return 0;
288 }
289
291 handle_participant_join(bridge_channel, announcer_channel);
292 return 0;
293}
294
296{
299}
300
302{
303 struct ast_bridge_channel *other_channel;
304 struct holding_channel *hc = bridge_channel->tech_pvt;
305
306 if (!hc) {
307 return;
308 }
309
310 switch (hc->role) {
312 /* The announcer is leaving */
313 bridge->tech_pvt = NULL;
314
315 /* Reset the other channels back to moh/ringing. */
316 AST_LIST_TRAVERSE(&bridge->channels, other_channel, entry) {
318 }
319 break;
320 default:
321 /* Nothing needs to react to its departure. */
322 participant_entertainment_stop(bridge_channel);
323 break;
324 }
325 bridge_channel->tech_pvt = NULL;
326 ast_free(hc);
327}
328
329static int holding_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
330{
331 struct holding_channel *hc = bridge_channel ? bridge_channel->tech_pvt : NULL;
332
333 /* If there is no tech_pvt, then the channel failed to allocate one when it joined and is borked. Don't listen to him. */
334 if (!hc) {
335 /* "Accept" the frame and discard it. */
336 return 0;
337 }
338
339 switch (hc->role) {
341 /* Write the frame to all other channels if any. */
342 ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
343 break;
344 default:
345 /* "Accept" the frame and discard it. */
346 break;
347 }
348
349 return 0;
350}
351
352static void holding_bridge_suspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
353{
354 struct holding_channel *hc = bridge_channel->tech_pvt;
355
356 if (!hc) {
357 return;
358 }
359
360 switch (hc->role) {
362 participant_entertainment_stop(bridge_channel);
363 break;
364 default:
365 break;
366 }
367}
368
369static void holding_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
370{
371 struct holding_channel *hc = bridge_channel->tech_pvt;
372 struct ast_bridge_channel *announcer_channel = bridge->tech_pvt;
373
374 if (!hc) {
375 return;
376 }
377
378 switch (hc->role) {
380 if (announcer_channel) {
381 /* There is an announcer channel in the bridge. */
382 break;
383 }
384 /* We need to restart the entertainment. */
385 participant_entertainment_start(bridge_channel);
386 break;
387 default:
388 break;
389 }
390}
391
393 .name = "holding_bridge",
394 .capabilities = AST_BRIDGE_CAPABILITY_HOLDING,
396 .write = holding_bridge_write,
397 .join = holding_bridge_join,
398 .leave = holding_bridge_leave,
399 .suspend = holding_bridge_suspend,
400 .unsuspend = holding_bridge_unsuspend,
401};
402
403/*!
404 * \internal
405 * \brief Deferred action to start/stop participant entertainment.
406 * \since 12.0.0
407 *
408 * \param bridge_channel Which channel to operate on.
409 * \param payload Data to pass to the callback. (NULL if none).
410 * \param payload_size Size of the payload if payload is non-NULL. A number otherwise.
411 */
412static void deferred_action(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)
413{
414 const struct deferred_data *data = payload;
415
416 ast_bridge_channel_lock_bridge(bridge_channel);
417 if (bridge_channel->bridge->technology != &holding_bridge
418 || !bridge_channel->tech_pvt) {
419 /* Not valid anymore. */
420 ast_bridge_unlock(bridge_channel->bridge);
421 return;
422 }
423 data->callback(bridge_channel);
424 ast_bridge_unlock(bridge_channel->bridge);
425}
426
427static int unload_module(void)
428{
430 return 0;
431}
432
433static int load_module(void)
434{
438 }
440}
441
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
Bridging API.
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Definition: bridge.h:481
@ AST_BRIDGE_CAPABILITY_HOLDING
Definition: bridge.h:86
int ast_bridge_queue_everyone_else(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
Queue the given frame to everyone else.
void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel)
Lock the bridge associated with the bridge channel.
void ast_bridge_channel_restore_formats(struct ast_bridge_channel *bridge_channel)
Restore the formats of a bridge channel's channel to how they were before bridge_channel_internal_joi...
int ast_bridge_channel_queue_callback(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_custom_callback_option flags, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size)
Queue a bridge action custom callback frame onto the bridge channel.
static int holding_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
static void participant_idle_mode_setup(struct ast_bridge_channel *bridge_channel)
holding_roles
@ HOLDING_ROLE_PARTICIPANT
@ HOLDING_ROLE_ANNOUNCER
static void participant_entertainment_stop(struct ast_bridge_channel *bridge_channel)
idle_modes
@ IDLE_MODE_MOH
@ IDLE_MODE_RINGING
@ IDLE_MODE_SILENCE
@ IDLE_MODE_HOLD
@ IDLE_MODE_NONE
static void holding_bridge_suspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
static int defer_action(struct ast_bridge_channel *bridge_channel, deferred_cb callback)
static void holding_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
static int holding_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
static void participant_entertainment_start(struct ast_bridge_channel *bridge_channel)
static struct ast_bridge_technology holding_bridge
static void participant_reaction_announcer_join(struct ast_bridge_channel *bridge_channel)
static void handle_participant_join(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *announcer_channel)
static void participant_reaction_announcer_leave(struct ast_bridge_channel *bridge_channel)
void(* deferred_cb)(struct ast_bridge_channel *bridge_channel)
static void holding_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
static int load_module(void)
static int unload_module(void)
static void deferred_action(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)
const char * ast_bridge_channel_get_role_option(struct ast_bridge_channel *bridge_channel, const char *role_name, const char *option)
Retrieve the value of a requested role option from a bridge channel.
Definition: bridge_roles.c:423
int ast_bridge_channel_has_role(struct ast_bridge_channel *bridge_channel, const char *role_name)
Check to see if a bridge channel inherited a specific role from its channel.
Definition: bridge_roles.c:414
Channel Bridging API.
@ AST_BRIDGE_PREFERENCE_BASE_HOLDING
#define ast_bridge_technology_register(technology)
See __ast_bridge_technology_register()
int ast_bridge_technology_unregister(struct ast_bridge_technology *technology)
Unregister a bridge technology from use.
Definition: bridge.c:263
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition: channel.c:8164
void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state)
Stops a previously-started silence generator on the given channel.
Definition: channel.c:8210
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5762
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
Definition: channel.c:4653
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5803
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4277
Media Format Cache API.
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
Asterisk internal frame definitions.
@ AST_CONTROL_UNHOLD
@ AST_CONTROL_RINGING
@ AST_CONTROL_HOLD
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
Music on hold handling.
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7766
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7776
#define NULL
Definition: resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Structure that contains information regarding a channel in a bridge.
void * tech_pvt
Private information unique to the bridge technology.
struct ast_bridge * bridge
Bridge this channel is participating in.
struct ast_channel * chan
Structure that is the essence of a bridge technology.
Structure that contains information about a bridge.
Definition: bridge.h:349
void * tech_pvt
Definition: bridge.h:357
const ast_string_field uniqueid
Definition: bridge.h:401
struct ast_bridge_channels_list channels
Definition: bridge.h:363
struct ast_bridge_technology * technology
Definition: bridge.h:355
Main Channel structure associated with a channel.
struct ast_bridge_channel * bridge_channel
struct ast_bridge * bridge
Data structure associated with a single frame of data.
deferred_cb callback
Definition: search.h:40
Structure which contains per-channel role information.
struct ast_silence_generator * silence_generator
unsigned int entertainment_active
enum holding_roles role
enum idle_modes idle_mode
#define ast_assert(a)
Definition: utils.h:739