loader: Correct overly strict startup checks.
[asterisk/asterisk.git] / bridges / bridge_simple.c
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"
43 #include "asterisk/bridge_technology.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
50 static int simple_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
51 {
52         struct ast_channel *c0 = AST_LIST_FIRST(&bridge->channels)->chan;
53         struct ast_channel *c1 = AST_LIST_LAST(&bridge->channels)->chan;
54
55         /*
56          * If this is the first channel we can't make it compatible...
57          * unless we make it compatible with itself.  O.o
58          */
59         if (c0 == c1) {
60                 return 0;
61         }
62
63         if (ast_channel_make_compatible(c0, c1)) {
64                 return -1;
65         }
66
67         /* Align stream topologies */
68         simple_bridge_stream_topology_changed(bridge, NULL);
69         return 0;
70 }
71
72 static int simple_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
73 {
74         const struct ast_control_t38_parameters *t38_parameters;
75         int defer = 0;
76
77         if (!ast_bridge_queue_everyone_else(bridge, bridge_channel, frame)) {
78                 /* This frame was successfully queued so no need to defer */
79                 return 0;
80         }
81
82         /* Depending on the frame defer it so when the next channel joins it receives it */
83         switch (frame->frametype) {
84         case AST_FRAME_CONTROL:
85                 switch (frame->subclass.integer) {
86                 case AST_CONTROL_T38_PARAMETERS:
87                         t38_parameters = frame->data.ptr;
88                         switch (t38_parameters->request_response) {
89                         case AST_T38_REQUEST_NEGOTIATE:
90                                 defer = -1;
91                                 break;
92                         default:
93                                 break;
94                         }
95                         break;
96                 default:
97                         break;
98                 }
99                 break;
100         default:
101                 break;
102         }
103
104         return defer;
105 }
106
107 static struct ast_bridge_technology simple_bridge = {
108         .name = "simple_bridge",
109         .capabilities = AST_BRIDGE_CAPABILITY_1TO1MIX,
110         .preference = AST_BRIDGE_PREFERENCE_BASE_1TO1MIX,
111         .join = simple_bridge_join,
112         .write = simple_bridge_write,
113         .stream_topology_changed = simple_bridge_stream_topology_changed,
114 };
115
116 static void simple_bridge_request_stream_topology_change(struct ast_channel *chan,
117         struct ast_stream_topology *requested_topology)
118 {
119         struct ast_stream_topology *existing_topology = ast_channel_get_stream_topology(chan);
120         struct ast_stream *stream;
121         struct ast_format_cap *audio_formats = NULL;
122         struct ast_stream_topology *new_topology;
123         int i;
124
125         /* We find an existing stream with negotiated audio formats that we can place into
126          * any audio streams in the new topology to ensure that negotiation succeeds. Some
127          * endpoints incorrectly terminate the call if SDP negotiation fails.
128          */
129         for (i = 0; i < ast_stream_topology_get_count(existing_topology); ++i) {
130                 stream = ast_stream_topology_get_stream(existing_topology, i);
131
132                 if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_AUDIO ||
133                         ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) {
134                         continue;
135                 }
136
137                 audio_formats = ast_stream_get_formats(stream);
138                 break;
139         }
140
141         if (!audio_formats) {
142                 ast_channel_request_stream_topology_change(chan, requested_topology, &simple_bridge);
143                 return;
144         }
145
146         new_topology = ast_stream_topology_clone(requested_topology);
147         if (!new_topology) {
148                 ast_channel_request_stream_topology_change(chan, requested_topology, &simple_bridge);
149                 return;
150         }
151
152         for (i = 0; i < ast_stream_topology_get_count(new_topology); ++i) {
153                 stream = ast_stream_topology_get_stream(new_topology, i);
154
155                 if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_AUDIO ||
156                         ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) {
157                         continue;
158                 }
159
160                 ast_format_cap_append_from_cap(ast_stream_get_formats(stream), audio_formats, AST_MEDIA_TYPE_AUDIO);
161         }
162
163         ast_channel_request_stream_topology_change(chan, new_topology, &simple_bridge);
164
165         ast_stream_topology_free(new_topology);
166 }
167
168 static void simple_bridge_stream_topology_changed(struct ast_bridge *bridge,
169                 struct ast_bridge_channel *bridge_channel)
170 {
171         struct ast_channel *c0 = AST_LIST_FIRST(&bridge->channels)->chan;
172         struct ast_channel *c1 = AST_LIST_LAST(&bridge->channels)->chan;
173         struct ast_stream_topology *t0 = ast_channel_get_stream_topology(c0);
174         struct ast_stream_topology *t1 = ast_channel_get_stream_topology(c1);
175
176         if (bridge_channel) {
177                 ast_bridge_channel_stream_map(bridge_channel);
178         }
179         /*
180          * The bridge_channel should only be NULL after both channels join
181          * the bridge and their topologies are being aligned.
182          */
183         if (bridge_channel && ast_channel_get_stream_topology_change_source(
184                     bridge_channel->chan) == &simple_bridge) {
185                 return;
186         }
187
188         /* Align topologies according to size or first channel to join */
189         if (ast_stream_topology_get_count(t0) < ast_stream_topology_get_count(t1)) {
190                 simple_bridge_request_stream_topology_change(c0, t1);
191         } else {
192                 simple_bridge_request_stream_topology_change(c1, t0);
193         }
194 }
195
196 static int unload_module(void)
197 {
198         ast_bridge_technology_unregister(&simple_bridge);
199         return 0;
200 }
201
202 static int load_module(void)
203 {
204         if (ast_bridge_technology_register(&simple_bridge)) {
205                 unload_module();
206                 return AST_MODULE_LOAD_DECLINE;
207         }
208         return AST_MODULE_LOAD_SUCCESS;
209 }
210
211 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple two channel bridging module");