Asterisk - The Open Source Telephony Project  GIT-master-b7027de
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"
48 #include "asterisk/musiconhold.h"
49 #include "asterisk/format_cache.h"
50 
54 };
55 
56 enum idle_modes {
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 
73 typedef void (*deferred_cb)(struct ast_bridge_channel *bridge_channel);
74 
75 struct deferred_data {
76  /*! Deferred holding technology callback */
78 };
79 
80 static 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  */
93 static int defer_action(struct ast_bridge_channel *bridge_channel, deferred_cb callback)
94 {
95  struct deferred_data data = { .callback = callback };
96  int res;
97 
98  res = ast_bridge_channel_queue_callback(bridge_channel, 0, deferred_action,
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  *
114  * \return Nothing
115  */
116 static void participant_idle_mode_setup(struct ast_bridge_channel *bridge_channel)
117 {
118  const char *idle_mode = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "idle_mode");
119  struct holding_channel *hc = bridge_channel->tech_pvt;
120 
121  ast_assert(hc != NULL);
122 
123  if (ast_strlen_zero(idle_mode)) {
124  hc->idle_mode = IDLE_MODE_MOH;
125  } else if (!strcmp(idle_mode, "musiconhold")) {
126  hc->idle_mode = IDLE_MODE_MOH;
127  } else if (!strcmp(idle_mode, "ringing")) {
129  } else if (!strcmp(idle_mode, "none")) {
131  } else if (!strcmp(idle_mode, "silence")) {
133  } else if (!strcmp(idle_mode, "hold")) {
135  } else {
136  /* Invalid idle mode requested. */
137  ast_debug(1, "channel %s idle mode '%s' doesn't match any defined idle mode\n",
138  ast_channel_name(bridge_channel->chan), idle_mode);
139  ast_assert(0);
140  }
141 }
142 
143 static void participant_entertainment_stop(struct ast_bridge_channel *bridge_channel)
144 {
145  struct holding_channel *hc = bridge_channel->tech_pvt;
146 
147  ast_assert(hc != NULL);
148 
149  if (!hc->entertainment_active) {
150  /* Already stopped */
151  return;
152  }
153  hc->entertainment_active = 0;
154 
155  switch (hc->idle_mode) {
156  case IDLE_MODE_MOH:
157  ast_moh_stop(bridge_channel->chan);
158  break;
159  case IDLE_MODE_RINGING:
160  ast_indicate(bridge_channel->chan, -1);
161  break;
162  case IDLE_MODE_NONE:
163  break;
164  case IDLE_MODE_SILENCE:
165  if (hc->silence_generator) {
167  hc->silence_generator = NULL;
168  }
169  break;
170  case IDLE_MODE_HOLD:
171  ast_indicate(bridge_channel->chan, AST_CONTROL_UNHOLD);
172  break;
173  }
174 }
175 
176 static void participant_reaction_announcer_join(struct ast_bridge_channel *bridge_channel)
177 {
178  struct ast_channel *chan;
179 
180  chan = bridge_channel->chan;
181  participant_entertainment_stop(bridge_channel);
183  ast_log(LOG_WARNING, "Could not make participant %s compatible.\n", ast_channel_name(chan));
184  }
185 }
186 
187 /* This should only be called on verified holding_participants. */
188 static void participant_entertainment_start(struct ast_bridge_channel *bridge_channel)
189 {
190  struct holding_channel *hc = bridge_channel->tech_pvt;
191  const char *moh_class;
192  size_t moh_length;
193 
194  ast_assert(hc != NULL);
195 
196  if (hc->entertainment_active) {
197  /* Already started */
198  return;
199  }
200  hc->entertainment_active = 1;
201 
202  participant_idle_mode_setup(bridge_channel);
203  switch(hc->idle_mode) {
204  case IDLE_MODE_MOH:
205  moh_class = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "moh_class");
206  if (ast_moh_start(bridge_channel->chan, moh_class, NULL)) {
207  ast_log(LOG_WARNING, "Failed to start moh, starting silence generator instead\n");
210  }
211  break;
212  case IDLE_MODE_RINGING:
213  ast_indicate(bridge_channel->chan, AST_CONTROL_RINGING);
214  break;
215  case IDLE_MODE_NONE:
216  break;
217  case IDLE_MODE_SILENCE:
219  break;
220  case IDLE_MODE_HOLD:
221  moh_class = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "moh_class");
222  moh_length = moh_class ? strlen(moh_class + 1) : 0;
223  ast_indicate_data(bridge_channel->chan, AST_CONTROL_HOLD, moh_class, moh_length);
224  break;
225  }
226 }
227 
228 static void handle_participant_join(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *announcer_channel)
229 {
230  struct ast_channel *us = bridge_channel->chan;
231 
232  /* If the announcer channel isn't present, we need to set up ringing, music on hold, or whatever. */
233  if (!announcer_channel) {
235  return;
236  }
237 
238  /* We need to get compatible with the announcer. */
240  ast_log(LOG_WARNING, "Could not make participant %s compatible.\n", ast_channel_name(us));
241  }
242 }
243 
244 static int holding_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
245 {
246  struct ast_bridge_channel *other_channel;
247  struct ast_bridge_channel *announcer_channel;
248  struct holding_channel *hc;
249  struct ast_channel *us = bridge_channel->chan; /* The joining channel */
250 
251  ast_assert(bridge_channel->tech_pvt == NULL);
252 
253  if (!(hc = ast_calloc(1, sizeof(*hc)))) {
254  return -1;
255  }
256 
257  bridge_channel->tech_pvt = hc;
258 
259  /* The bridge pvt holds the announcer channel if we have one. */
260  announcer_channel = bridge->tech_pvt;
261 
262  if (ast_bridge_channel_has_role(bridge_channel, "announcer")) {
263  if (announcer_channel) {
264  /* Another announcer already exists. */
265  bridge_channel->tech_pvt = NULL;
266  ast_free(hc);
267  ast_log(LOG_WARNING, "Bridge %s: Channel %s tried to be an announcer. Bridge already has one.\n",
268  bridge->uniqueid, ast_channel_name(bridge_channel->chan));
269  return -1;
270  }
271 
272  bridge->tech_pvt = bridge_channel;
274 
275  /* The announcer should always be made compatible with signed linear */
277  ast_log(LOG_ERROR, "Could not make announcer %s compatible.\n", ast_channel_name(us));
278  }
279 
280  /* Make everyone listen to the announcer. */
281  AST_LIST_TRAVERSE(&bridge->channels, other_channel, entry) {
282  /* Skip the reaction if we are the channel in question */
283  if (bridge_channel == other_channel) {
284  continue;
285  }
287  }
288 
289  return 0;
290  }
291 
293  handle_participant_join(bridge_channel, announcer_channel);
294  return 0;
295 }
296 
297 static void participant_reaction_announcer_leave(struct ast_bridge_channel *bridge_channel)
298 {
299  ast_bridge_channel_restore_formats(bridge_channel);
300  participant_entertainment_start(bridge_channel);
301 }
302 
303 static void holding_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
304 {
305  struct ast_bridge_channel *other_channel;
306  struct holding_channel *hc = bridge_channel->tech_pvt;
307 
308  if (!hc) {
309  return;
310  }
311 
312  switch (hc->role) {
314  /* The announcer is leaving */
315  bridge->tech_pvt = NULL;
316 
317  /* Reset the other channels back to moh/ringing. */
318  AST_LIST_TRAVERSE(&bridge->channels, other_channel, entry) {
320  }
321  break;
322  default:
323  /* Nothing needs to react to its departure. */
324  participant_entertainment_stop(bridge_channel);
325  break;
326  }
327  bridge_channel->tech_pvt = NULL;
328  ast_free(hc);
329 }
330 
331 static int holding_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
332 {
333  struct holding_channel *hc = bridge_channel ? bridge_channel->tech_pvt : NULL;
334 
335  /* If there is no tech_pvt, then the channel failed to allocate one when it joined and is borked. Don't listen to him. */
336  if (!hc) {
337  /* "Accept" the frame and discard it. */
338  return 0;
339  }
340 
341  switch (hc->role) {
343  /* Write the frame to all other channels if any. */
344  ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
345  break;
346  default:
347  /* "Accept" the frame and discard it. */
348  break;
349  }
350 
351  return 0;
352 }
353 
354 static void holding_bridge_suspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
355 {
356  struct holding_channel *hc = bridge_channel->tech_pvt;
357 
358  if (!hc) {
359  return;
360  }
361 
362  switch (hc->role) {
364  participant_entertainment_stop(bridge_channel);
365  break;
366  default:
367  break;
368  }
369 }
370 
371 static void holding_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
372 {
373  struct holding_channel *hc = bridge_channel->tech_pvt;
374  struct ast_bridge_channel *announcer_channel = bridge->tech_pvt;
375 
376  if (!hc) {
377  return;
378  }
379 
380  switch (hc->role) {
382  if (announcer_channel) {
383  /* There is an announcer channel in the bridge. */
384  break;
385  }
386  /* We need to restart the entertainment. */
387  participant_entertainment_start(bridge_channel);
388  break;
389  default:
390  break;
391  }
392 }
393 
395  .name = "holding_bridge",
396  .capabilities = AST_BRIDGE_CAPABILITY_HOLDING,
398  .write = holding_bridge_write,
399  .join = holding_bridge_join,
400  .leave = holding_bridge_leave,
401  .suspend = holding_bridge_suspend,
402  .unsuspend = holding_bridge_unsuspend,
403 };
404 
405 /*!
406  * \internal
407  * \brief Deferred action to start/stop participant entertainment.
408  * \since 12.0.0
409  *
410  * \param bridge_channel Which channel to operate on.
411  * \param payload Data to pass to the callback. (NULL if none).
412  * \param payload_size Size of the payload if payload is non-NULL. A number otherwise.
413  *
414  * \return Nothing
415  */
416 static void deferred_action(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)
417 {
418  const struct deferred_data *data = payload;
419 
420  ast_bridge_channel_lock_bridge(bridge_channel);
421  if (bridge_channel->bridge->technology != &holding_bridge
422  || !bridge_channel->tech_pvt) {
423  /* Not valid anymore. */
424  ast_bridge_unlock(bridge_channel->bridge);
425  return;
426  }
427  data->callback(bridge_channel);
428  ast_bridge_unlock(bridge_channel->bridge);
429 }
430 
431 static int unload_module(void)
432 {
433  ast_bridge_technology_unregister(&holding_bridge);
434  return 0;
435 }
436 
437 static int load_module(void)
438 {
439  if (ast_bridge_technology_register(&holding_bridge)) {
440  unload_module();
442  }
444 }
445 
446 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Holding bridge module");
static int holding_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
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:418
Main Channel structure associated with a channel.
Music on hold handling.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
Asterisk main include file. File version handling, generic pbx functions.
const ast_string_field uniqueid
Definition: bridge.h:409
struct ast_silence_generator * silence_generator
static void holding_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
static void participant_entertainment_start(struct ast_bridge_channel *bridge_channel)
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4299
static void holding_bridge_suspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
#define LOG_WARNING
Definition: logger.h:274
static void handle_participant_join(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *announcer_channel)
enum idle_modes idle_mode
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:4675
static int holding_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
#define ast_assert(a)
Definition: utils.h:710
#define NULL
Definition: resample.c:96
static int unload_module(void)
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_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7783
struct ast_bridge * bridge
Bridge this channel is participating in.
struct ast_bridge_technology * technology
Definition: bridge.h:363
static int defer_action(struct ast_bridge_channel *bridge_channel, deferred_cb callback)
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
General Asterisk PBX channel definitions.
static int load_module(void)
Structure which contains per-channel role information.
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5756
Channel Bridging API.
Asterisk internal frame definitions.
void(* deferred_cb)(struct ast_bridge_channel *bridge_channel)
static void participant_reaction_announcer_join(struct ast_bridge_channel *bridge_channel)
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5797
#define ast_bridge_technology_register(technology)
See __ast_bridge_technology_register()
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition: channel.c:8173
static void participant_entertainment_stop(struct ast_bridge_channel *bridge_channel)
Structure that contains information about a bridge.
Definition: bridge.h:357
int ast_bridge_technology_unregister(struct ast_bridge_technology *technology)
Unregister a bridge technology from use.
Definition: bridge.c:265
#define LOG_ERROR
Definition: logger.h:285
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:7773
holding_roles
static struct ast_bridge_technology holding_bridge
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.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_strlen_zero(a)
Definition: muted.c:73
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:8219
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Definition: bridge.h:493
deferred_cb callback
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
void * tech_pvt
Private information unique to the bridge technology.
struct ast_bridge_channels_list channels
Definition: bridge.h:371
struct ast_channel * chan
Structure that contains information regarding a channel in a bridge.
void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel)
Lock the bridge associated with the bridge channel.
static void holding_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
const char * ast_channel_name(const struct ast_channel *chan)
Structure that is the essence of a bridge technology.
idle_modes
Data structure associated with a single frame of data.
void * tech_pvt
Definition: bridge.h:365
Definition: search.h:40
static void participant_reaction_announcer_leave(struct ast_bridge_channel *bridge_channel)
void ast_bridge_channel_restore_formats(struct ast_bridge_channel *bridge_channel)
Restore the formats of a bridge channel&#39;s channel to how they were before bridge_channel_internal_joi...
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Bridging API.
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
Asterisk module definitions.
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:427
static void participant_idle_mode_setup(struct ast_bridge_channel *bridge_channel)
enum holding_roles role
unsigned int entertainment_active
Media Format Cache API.
static void deferred_action(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)