Asterisk - The Open Source Telephony Project  21.4.1
bridge_simple.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2007, 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 Simple two channel bridging module
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  *
25  * \ingroup bridges
26  */
27 
28 /*** MODULEINFO
29  <support_level>core</support_level>
30  ***/
31 
32 #include "asterisk.h"
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 
40 #include "asterisk/module.h"
41 #include "asterisk/channel.h"
42 #include "asterisk/bridge.h"
44 #include "asterisk/frame.h"
45 #include "asterisk/stream.h"
46 
47 static void simple_bridge_stream_topology_changed(struct ast_bridge *bridge,
48  struct ast_bridge_channel *bridge_channel);
49 static int simple_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel);
50 static int simple_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame);
51 
52 static struct ast_bridge_technology simple_bridge = {
53  .name = "simple_bridge",
54  .capabilities = AST_BRIDGE_CAPABILITY_1TO1MIX,
55  .preference = AST_BRIDGE_PREFERENCE_BASE_1TO1MIX,
56  .join = simple_bridge_join,
57  .write = simple_bridge_write,
58  .stream_topology_changed = simple_bridge_stream_topology_changed,
59 };
60 
61 static struct ast_stream_topology *simple_bridge_request_stream_topology_update(
62  struct ast_stream_topology *existing_topology,
63  struct ast_stream_topology *requested_topology)
64 {
65  struct ast_stream *stream;
66  const struct ast_format_cap *audio_formats = NULL;
67  struct ast_stream_topology *new_topology;
68  int i;
69 
70  new_topology = ast_stream_topology_clone(requested_topology);
71  if (!new_topology) {
72  return NULL;
73  }
74 
75  /* We find an existing stream with negotiated audio formats that we can place into
76  * any audio streams in the new topology to ensure that negotiation succeeds. Some
77  * endpoints incorrectly terminate the call if SDP negotiation fails.
78  */
79  for (i = 0; i < ast_stream_topology_get_count(existing_topology); ++i) {
80  stream = ast_stream_topology_get_stream(existing_topology, i);
81 
82  if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_AUDIO ||
84  continue;
85  }
86 
87  audio_formats = ast_stream_get_formats(stream);
88  break;
89  }
90 
91  if (audio_formats) {
92  for (i = 0; i < ast_stream_topology_get_count(new_topology); ++i) {
93  stream = ast_stream_topology_get_stream(new_topology, i);
94 
95  if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_AUDIO ||
97  continue;
98  }
99 
100  /* We haven't actually modified audio_formats so this is safe */
101  ast_stream_set_formats(stream, (struct ast_format_cap *)audio_formats);
102  }
103  }
104 
105  for (i = 0; i < ast_stream_topology_get_count(new_topology); ++i) {
106  stream = ast_stream_topology_get_stream(new_topology, i);
107 
108  /* For both recvonly and sendonly the stream state reflects our state, that is we
109  * are receiving only and we are sending only. Since we are renegotiating a remote
110  * party we need to swap this to reflect what we will be doing. That is, if we are
111  * receiving from Alice then we want to be sending to Bob, so swap recvonly to
112  * sendonly.
113  */
116  } else if (ast_stream_get_state(stream) == AST_STREAM_STATE_SENDONLY) {
118  }
119  }
120 
121  return new_topology;
122 }
123 
124 static int simple_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
125 {
126  struct ast_stream_topology *req_top;
127  struct ast_stream_topology *existing_top;
128  struct ast_stream_topology *new_top;
129  struct ast_channel *c0 = AST_LIST_FIRST(&bridge->channels)->chan;
130  struct ast_channel *c1 = AST_LIST_LAST(&bridge->channels)->chan;
131  int unhold_c0, unhold_c1;
132 
133  /*
134  * If this is the first channel we can't make it compatible...
135  * unless we make it compatible with itself. O.o
136  */
137  if (c0 == c1) {
138  return 0;
139  }
140 
141  if (ast_channel_make_compatible(c0, c1)) {
142  return -1;
143  }
144 
145  /* When both channels are joined we want to try to improve the experience by
146  * raising the number of streams so they match.
147  */
148  ast_channel_lock_both(c0, c1);
149  req_top = ast_channel_get_stream_topology(c0);
150  existing_top = ast_channel_get_stream_topology(c1);
151  if (ast_stream_topology_get_count(req_top) < ast_stream_topology_get_count(existing_top)) {
152  SWAP(req_top, existing_top);
153  SWAP(c0, c1);
154  }
155  new_top = simple_bridge_request_stream_topology_update(existing_top, req_top);
156 
157  /* The ast_channel_hold_state() and ast_channel_name() accessors need to be
158  * called with the associated channel lock held.
159  */
160  if ((unhold_c1 = ast_channel_hold_state(c1) == AST_CONTROL_HOLD)) {
161  ast_debug(1, "Channel %s simulating UNHOLD for bridge simple join.\n", ast_channel_name(c1));
162  }
163 
164  if ((unhold_c0 = ast_channel_hold_state(c0) == AST_CONTROL_HOLD)) {
165  ast_debug(1, "Channel %s simulating UNHOLD for bridge simple join.\n", ast_channel_name(c0));
166  }
167 
168  ast_channel_unlock(c0);
169  ast_channel_unlock(c1);
170 
171  if (unhold_c1) {
173  }
174 
175  if (unhold_c0) {
177  }
178 
179  if (!new_top) {
180  /* Failure. We'll just have to live with the current topology. */
181  return 0;
182  }
183 
184  if (!ast_stream_topology_equal(new_top, existing_top)) {
185  ast_channel_request_stream_topology_change(c1, new_top, &simple_bridge);
186  } else {
187  ast_debug(3, "%s: Topologies already match. Current: %s Requested: %s\n",
188  ast_channel_name(c1),
189  ast_str_tmp(256, ast_stream_topology_to_str(existing_top, &STR_TMP)),
190  ast_str_tmp(256, ast_stream_topology_to_str(new_top, &STR_TMP)));
191  }
192  ast_stream_topology_free(new_top);
193 
194  return 0;
195 }
196 
197 static int simple_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
198 {
199  const struct ast_control_t38_parameters *t38_parameters;
200  int defer = 0;
201 
202  if (!ast_bridge_queue_everyone_else(bridge, bridge_channel, frame)) {
203  /* This frame was successfully queued so no need to defer */
204  return 0;
205  }
206 
207  /* Depending on the frame defer it so when the next channel joins it receives it */
208  switch (frame->frametype) {
209  case AST_FRAME_CONTROL:
210  switch (frame->subclass.integer) {
212  t38_parameters = frame->data.ptr;
213  switch (t38_parameters->request_response) {
215  defer = -1;
216  break;
217  default:
218  break;
219  }
220  break;
221  default:
222  break;
223  }
224  break;
225  default:
226  break;
227  }
228 
229  return defer;
230 }
231 
232 static void simple_bridge_stream_topology_changed(struct ast_bridge *bridge,
233  struct ast_bridge_channel *bridge_channel)
234 {
235  struct ast_channel *c0 = bridge_channel->chan;
236  struct ast_channel *c1 = AST_LIST_FIRST(&bridge->channels)->chan;
237  struct ast_stream_topology *req_top;
238  struct ast_stream_topology *existing_top;
239  struct ast_stream_topology *new_top;
240 
241  ast_bridge_channel_stream_map(bridge_channel);
242 
244  == &simple_bridge) {
245  return;
246  }
247 
248  if (c0 == c1) {
249  c1 = AST_LIST_LAST(&bridge->channels)->chan;
250  }
251 
252  if (c0 == c1) {
253  return;
254  }
255 
256  /* If a party renegotiates we want to renegotiate their counterpart to a matching
257  * topology.
258  */
259  ast_channel_lock_both(c0, c1);
260  req_top = ast_channel_get_stream_topology(c0);
261  existing_top = ast_channel_get_stream_topology(c1);
262  new_top = simple_bridge_request_stream_topology_update(existing_top, req_top);
263  ast_channel_unlock(c0);
264  ast_channel_unlock(c1);
265 
266  if (!new_top) {
267  /* Failure. We'll just have to live with the current topology. */
268  return;
269  }
270 
271  ast_channel_request_stream_topology_change(c1, new_top, &simple_bridge);
272  ast_stream_topology_free(new_top);
273 }
274 
275 static int unload_module(void)
276 {
277  ast_bridge_technology_unregister(&simple_bridge);
278  return 0;
279 }
280 
281 static int load_module(void)
282 {
283  if (ast_bridge_technology_register(&simple_bridge)) {
284  unload_module();
286  }
288 }
289 
290 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple two channel bridging module");
Main Channel structure associated with a channel.
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421
struct ast_stream_topology * ast_channel_get_stream_topology(const struct ast_channel *chan)
Retrieve the topology of streams on a channel.
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4277
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition: stream.c:316
Set when the stream has been removed/declined.
Definition: stream.h:78
enum ast_control_t38 request_response
int ast_channel_request_stream_topology_change(struct ast_channel *chan, struct ast_stream_topology *topology, void *change_source)
Request that the stream topology of a channel change.
Definition: channel.c:10966
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
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_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps)
Set the current negotiated formats of a stream.
Definition: stream.c:365
struct ast_frame_subclass subclass
Media Stream API.
#define ast_str_tmp(init_len, __expr)
Provides a temporary ast_str and returns a copy of its buffer.
Definition: strings.h:1189
int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
Make the frame formats of two channels compatible.
Definition: channel.c:6720
const char * ast_stream_topology_to_str(const struct ast_stream_topology *topology, struct ast_str **buf)
Get a string representing the topology for debugging/display purposes.
Definition: stream.c:936
General Asterisk PBX channel definitions.
Channel Bridging API.
Asterisk internal frame definitions.
#define ast_debug(level,...)
Log a DEBUG message.
const struct ast_format_cap * ast_stream_get_formats(const struct ast_stream *stream)
Get the current negotiated formats of a stream.
Definition: stream.c:330
#define ast_bridge_technology_register(technology)
See __ast_bridge_technology_register()
Structure that contains information about a bridge.
Definition: bridge.h:349
int ast_bridge_technology_unregister(struct ast_bridge_technology *technology)
Unregister a bridge technology from use.
Definition: bridge.c:263
void * ast_channel_get_stream_topology_change_source(struct ast_channel *chan)
Retrieve the source that initiated the last stream topology change.
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
int ast_stream_topology_equal(const struct ast_stream_topology *left, const struct ast_stream_topology *right)
Compare two stream topologies to see if they are equal.
Definition: stream.c:696
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
Definition: linkedlists.h:429
Set when the stream is sending media only.
Definition: stream.h:86
union ast_frame::@224 data
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition: stream.c:380
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
struct ast_stream_topology * ast_stream_topology_clone(const struct ast_stream_topology *topology)
Create a deep clone of an existing stream topology.
Definition: stream.c:667
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2929
struct ast_bridge_channels_list channels
Definition: bridge.h:363
struct ast_channel * chan
Structure that contains information regarding a channel in a bridge.
Structure that is the essence of a bridge technology.
void ast_bridge_channel_stream_map(struct ast_bridge_channel *bridge_channel)
Maps a channel's stream topology to and from the bridge.
Data structure associated with a single frame of data.
enum ast_frame_type frametype
void ast_stream_topology_free(struct ast_stream_topology *topology)
Unreference and destroy a stream topology.
Definition: stream.c:743
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Bridging API.
Asterisk module definitions.
Set when the stream is receiving media only.
Definition: stream.h:90
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373