Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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 <[email protected]>
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 
53  .name = "simple_bridge",
54  .capabilities = AST_BRIDGE_CAPABILITY_1TO1MIX,
56  .join = simple_bridge_join,
57  .write = simple_bridge_write,
58  .stream_topology_changed = simple_bridge_stream_topology_changed,
59 };
60 
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 
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 
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 
132  /*
133  * If this is the first channel we can't make it compatible...
134  * unless we make it compatible with itself. O.o
135  */
136  if (c0 == c1) {
137  return 0;
138  }
139 
140  if (ast_channel_make_compatible(c0, c1)) {
141  return -1;
142  }
143 
144  /* When both channels are joined we want to try to improve the experience by
145  * raising the number of streams so they match.
146  */
147  ast_channel_lock_both(c0, c1);
148  req_top = ast_channel_get_stream_topology(c0);
149  existing_top = ast_channel_get_stream_topology(c1);
150  if (ast_stream_topology_get_count(req_top) < ast_stream_topology_get_count(existing_top)) {
151  SWAP(req_top, existing_top);
152  SWAP(c0, c1);
153  }
154  new_top = simple_bridge_request_stream_topology_update(existing_top, req_top);
155  ast_channel_unlock(c0);
156  ast_channel_unlock(c1);
157 
158  if (!new_top) {
159  /* Failure. We'll just have to live with the current topology. */
160  return 0;
161  }
162 
163  ast_channel_request_stream_topology_change(c1, new_top, &simple_bridge);
164  ast_stream_topology_free(new_top);
165 
166  return 0;
167 }
168 
169 static int simple_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
170 {
171  const struct ast_control_t38_parameters *t38_parameters;
172  int defer = 0;
173 
174  if (!ast_bridge_queue_everyone_else(bridge, bridge_channel, frame)) {
175  /* This frame was successfully queued so no need to defer */
176  return 0;
177  }
178 
179  /* Depending on the frame defer it so when the next channel joins it receives it */
180  switch (frame->frametype) {
181  case AST_FRAME_CONTROL:
182  switch (frame->subclass.integer) {
184  t38_parameters = frame->data.ptr;
185  switch (t38_parameters->request_response) {
187  defer = -1;
188  break;
189  default:
190  break;
191  }
192  break;
193  default:
194  break;
195  }
196  break;
197  default:
198  break;
199  }
200 
201  return defer;
202 }
203 
205  struct ast_bridge_channel *bridge_channel)
206 {
207  struct ast_channel *c0 = bridge_channel->chan;
208  struct ast_channel *c1 = AST_LIST_FIRST(&bridge->channels)->chan;
209  struct ast_stream_topology *req_top;
210  struct ast_stream_topology *existing_top;
211  struct ast_stream_topology *new_top;
212 
213  ast_bridge_channel_stream_map(bridge_channel);
214 
216  == &simple_bridge) {
217  return;
218  }
219 
220  if (c0 == c1) {
221  c1 = AST_LIST_LAST(&bridge->channels)->chan;
222  }
223 
224  if (c0 == c1) {
225  return;
226  }
227 
228  /* If a party renegotiates we want to renegotiate their counterpart to a matching
229  * topology.
230  */
231  ast_channel_lock_both(c0, c1);
232  req_top = ast_channel_get_stream_topology(c0);
233  existing_top = ast_channel_get_stream_topology(c1);
234  new_top = simple_bridge_request_stream_topology_update(existing_top, req_top);
235  ast_channel_unlock(c0);
236  ast_channel_unlock(c1);
237 
238  if (!new_top) {
239  /* Failure. We'll just have to live with the current topology. */
240  return;
241  }
242 
243  ast_channel_request_stream_topology_change(c1, new_top, &simple_bridge);
244  ast_stream_topology_free(new_top);
245 }
246 
247 static int unload_module(void)
248 {
249  ast_bridge_technology_unregister(&simple_bridge);
250  return 0;
251 }
252 
253 static int load_module(void)
254 {
255  if (ast_bridge_technology_register(&simple_bridge)) {
256  unload_module();
258  }
260 }
261 
262 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple two channel bridging module");
Main Channel structure associated with a channel.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
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:420
struct ast_stream_topology * ast_channel_get_stream_topology(const struct ast_channel *chan)
Retrieve the topology of streams on a channel.
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
static struct ast_bridge_technology simple_bridge
Definition: bridge_simple.c:52
enum ast_control_t38 request_response
#define SWAP(a, b)
Definition: utils.h:230
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:11167
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
#define NULL
Definition: resample.c:96
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.
int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
Make the frame formats of two channels compatible.
Definition: channel.c:6817
General Asterisk PBX channel definitions.
Channel Bridging API.
static struct ast_stream_topology * simple_bridge_request_stream_topology_update(struct ast_stream_topology *existing_topology, struct ast_stream_topology *requested_topology)
Definition: bridge_simple.c:61
Asterisk internal frame definitions.
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
static int simple_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
#define ast_bridge_technology_register(technology)
See __ast_bridge_technology_register()
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
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
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
Definition: linkedlists.h:428
#define ast_channel_unlock(chan)
Definition: channel.h:2946
Set when the stream is sending media only.
Definition: stream.h:86
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
static int unload_module(void)
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:2952
struct ast_bridge_channels_list channels
Definition: bridge.h:371
struct ast_channel * chan
Structure that contains information regarding a channel in a bridge.
Structure that is the essence of a bridge technology.
static int load_module(void)
void ast_bridge_channel_stream_map(struct ast_bridge_channel *bridge_channel)
Maps a channel&#39;s stream topology to and from the bridge.
Data structure associated with a single frame of data.
union ast_frame::@263 data
static void simple_bridge_stream_topology_changed(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
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.
static int simple_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
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