Asterisk - The Open Source Telephony Project GIT-master-7e7a603
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
47static void simple_bridge_stream_topology_changed(struct ast_bridge *bridge,
48 struct ast_bridge_channel *bridge_channel);
49static int simple_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel);
50static 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
124static 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);
150 existing_top = ast_channel_get_stream_topology(c1);
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
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)) {
186 } else {
187 ast_debug(3, "%s: Topologies already match. Current: %s Requested: %s\n",
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 }
193
194 return 0;
195}
196
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) {
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
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);
261 existing_top = ast_channel_get_stream_topology(c1);
262 new_top = simple_bridge_request_stream_topology_update(existing_top, req_top);
265
266 if (!new_top) {
267 /* Failure. We'll just have to live with the current topology. */
268 return;
269 }
270
273}
274
275static int unload_module(void)
276{
278 return 0;
279}
280
281static int load_module(void)
282{
286 }
288}
289
290AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple two channel bridging module");
Asterisk main include file. File version handling, generic pbx functions.
Bridging API.
@ AST_BRIDGE_CAPABILITY_1TO1MIX
Definition: bridge.h:92
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_stream_map(struct ast_bridge_channel *bridge_channel)
Maps a channel's stream topology to and from the bridge.
static int simple_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
static void simple_bridge_stream_topology_changed(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
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
static int simple_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
static int load_module(void)
static int unload_module(void)
static struct ast_bridge_technology simple_bridge
Definition: bridge_simple.c:52
Channel Bridging API.
@ AST_BRIDGE_PREFERENCE_BASE_1TO1MIX
#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)
void * ast_channel_get_stream_topology_change_source(struct ast_channel *chan)
Retrieve the source that initiated the last stream topology change.
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
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
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2929
struct ast_stream_topology * ast_channel_get_stream_topology(const struct ast_channel *chan)
Retrieve the topology of streams on a channel.
int ast_channel_hold_state(const struct ast_channel *chan)
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4277
#define ast_channel_unlock(chan)
Definition: channel.h:2923
@ AST_MEDIA_TYPE_AUDIO
Definition: codec.h:32
Asterisk internal frame definitions.
@ AST_T38_REQUEST_NEGOTIATE
@ AST_FRAME_CONTROL
@ AST_CONTROL_UNHOLD
@ AST_CONTROL_T38_PARAMETERS
@ AST_CONTROL_HOLD
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
Definition: linkedlists.h:429
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421
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
#define NULL
Definition: resample.c:96
Media Stream API.
@ AST_STREAM_STATE_RECVONLY
Set when the stream is receiving media only.
Definition: stream.h:90
@ AST_STREAM_STATE_REMOVED
Set when the stream has been removed/declined.
Definition: stream.h:78
@ AST_STREAM_STATE_SENDONLY
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
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
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_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition: stream.c:316
void ast_stream_topology_free(struct ast_stream_topology *topology)
Unreference and destroy a stream topology.
Definition: stream.c:743
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
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
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
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_str_tmp(init_len, __expr)
Provides a temporary ast_str and returns a copy of its buffer.
Definition: strings.h:1189
Structure that contains information regarding a channel in a bridge.
struct ast_channel * chan
Structure that is the essence of a bridge technology.
Structure that contains information about a bridge.
Definition: bridge.h:349
struct ast_bridge_channels_list channels
Definition: bridge.h:363
Main Channel structure associated with a channel.
struct ast_bridge_channel * bridge_channel
struct ast_bridge * bridge
enum ast_control_t38 request_response
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@226 data
enum ast_frame_type frametype
#define SWAP(a, b)
Definition: utils.h:235