bridge_native_rtp/bridge_channel: Fix direct media issues due to frame hook
[asterisk/asterisk.git] / bridges / bridge_native_rtp.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, 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 Native RTP bridging technology 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 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41
42 #include "asterisk/module.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/bridge.h"
45 #include "asterisk/bridge_technology.h"
46 #include "asterisk/frame.h"
47 #include "asterisk/rtp_engine.h"
48
49 /*! \brief Internal structure which contains information about bridged RTP channels */
50 struct native_rtp_bridge_data {
51         /*! \brief Framehook used to intercept certain control frames */
52         int id;
53 };
54
55 /*! \brief Internal helper function which gets all RTP information (glue and instances) relating to the given channels */
56 static enum ast_rtp_glue_result native_rtp_bridge_get(struct ast_channel *c0, struct ast_channel *c1, struct ast_rtp_glue **glue0,
57         struct ast_rtp_glue **glue1, struct ast_rtp_instance **instance0, struct ast_rtp_instance **instance1,
58         struct ast_rtp_instance **vinstance0, struct ast_rtp_instance **vinstance1)
59 {
60         enum ast_rtp_glue_result audio_glue0_res;
61         enum ast_rtp_glue_result video_glue0_res;
62         enum ast_rtp_glue_result audio_glue1_res;
63         enum ast_rtp_glue_result video_glue1_res;
64
65         if (!(*glue0 = ast_rtp_instance_get_glue(ast_channel_tech(c0)->type)) ||
66                 !(*glue1 = ast_rtp_instance_get_glue(ast_channel_tech(c1)->type))) {
67                 return AST_RTP_GLUE_RESULT_FORBID;
68         }
69
70         audio_glue0_res = (*glue0)->get_rtp_info(c0, instance0);
71         video_glue0_res = (*glue0)->get_vrtp_info ? (*glue0)->get_vrtp_info(c0, vinstance0) : AST_RTP_GLUE_RESULT_FORBID;
72
73         audio_glue1_res = (*glue1)->get_rtp_info(c1, instance1);
74         video_glue1_res = (*glue1)->get_vrtp_info ? (*glue1)->get_vrtp_info(c1, vinstance1) : AST_RTP_GLUE_RESULT_FORBID;
75
76         /* Apply any limitations on direct media bridging that may be present */
77         if (audio_glue0_res == audio_glue1_res && audio_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) {
78                 if ((*glue0)->allow_rtp_remote && !((*glue0)->allow_rtp_remote(c0, *instance1))) {
79                         /* If the allow_rtp_remote indicates that remote isn't allowed, revert to local bridge */
80                         audio_glue0_res = audio_glue1_res = AST_RTP_GLUE_RESULT_LOCAL;
81                 } else if ((*glue1)->allow_rtp_remote && !((*glue1)->allow_rtp_remote(c1, *instance0))) {
82                         audio_glue0_res = audio_glue1_res = AST_RTP_GLUE_RESULT_LOCAL;
83                 }
84         }
85         if (video_glue0_res == video_glue1_res && video_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) {
86                 if ((*glue0)->allow_vrtp_remote && !((*glue0)->allow_vrtp_remote(c0, *instance1))) {
87                         /* if the allow_vrtp_remote indicates that remote isn't allowed, revert to local bridge */
88                         video_glue0_res = video_glue1_res = AST_RTP_GLUE_RESULT_LOCAL;
89                 } else if ((*glue1)->allow_vrtp_remote && !((*glue1)->allow_vrtp_remote(c1, *instance0))) {
90                         video_glue0_res = video_glue1_res = AST_RTP_GLUE_RESULT_LOCAL;
91                 }
92         }
93
94         /* If we are carrying video, and both sides are not going to remotely bridge... fail the native bridge */
95         if (video_glue0_res != AST_RTP_GLUE_RESULT_FORBID
96                 && (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE
97                         || video_glue0_res != AST_RTP_GLUE_RESULT_REMOTE)) {
98                 audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
99         }
100         if (video_glue1_res != AST_RTP_GLUE_RESULT_FORBID
101                 && (audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE
102                         || video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE)) {
103                 audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
104         }
105
106         /* If any sort of bridge is forbidden just completely bail out and go back to generic bridging */
107         if (audio_glue0_res == AST_RTP_GLUE_RESULT_FORBID
108                 || audio_glue1_res == AST_RTP_GLUE_RESULT_FORBID) {
109                 return AST_RTP_GLUE_RESULT_FORBID;
110         }
111
112         return audio_glue0_res;
113 }
114
115 /*!
116  * \internal
117  * \brief Start native RTP bridging of two channels
118  *
119  * \param bridge The bridge that had native RTP bridging happening on it
120  * \param target If remote RTP bridging, the channel that is unheld.
121  *
122  * \note Bridge must be locked when calling this function.
123  */
124 static void native_rtp_bridge_start(struct ast_bridge *bridge, struct ast_channel *target)
125 {
126         struct ast_bridge_channel *c0 = AST_LIST_FIRST(&bridge->channels);
127         struct ast_bridge_channel *c1 = AST_LIST_LAST(&bridge->channels);
128         enum ast_rtp_glue_result native_type;
129         struct ast_rtp_glue *glue0, *glue1;
130         RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup);
131         RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup);
132         RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup);
133         RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup);
134         RAII_VAR(struct ast_rtp_instance *, tinstance0, NULL, ao2_cleanup);
135         RAII_VAR(struct ast_rtp_instance *, tinstance1, NULL, ao2_cleanup);
136         RAII_VAR(struct ast_format_cap *, cap0, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK), ast_format_cap_destroy);
137         RAII_VAR(struct ast_format_cap *, cap1, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK), ast_format_cap_destroy);
138
139         if (c0 == c1) {
140                 return;
141         }
142
143         ast_channel_lock_both(c0->chan, c1->chan);
144         native_type = native_rtp_bridge_get(c0->chan, c1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1);
145
146         switch (native_type) {
147         case AST_RTP_GLUE_RESULT_LOCAL:
148                 if (ast_rtp_instance_get_engine(instance0)->local_bridge) {
149                         ast_rtp_instance_get_engine(instance0)->local_bridge(instance0, instance1);
150                 }
151                 if (ast_rtp_instance_get_engine(instance1)->local_bridge) {
152                         ast_rtp_instance_get_engine(instance1)->local_bridge(instance1, instance0);
153                 }
154                 ast_rtp_instance_set_bridged(instance0, instance1);
155                 ast_rtp_instance_set_bridged(instance1, instance0);
156                 ast_debug(2, "Locally RTP bridged '%s' and '%s' in stack\n",
157                         ast_channel_name(c0->chan), ast_channel_name(c1->chan));
158                 break;
159
160         case AST_RTP_GLUE_RESULT_REMOTE:
161                 if (glue0->get_codec) {
162                         glue0->get_codec(c0->chan, cap0);
163                 }
164                 if (glue1->get_codec) {
165                         glue1->get_codec(c1->chan, cap1);
166                 }
167
168                 /* If we have a target, it's the channel that received the UNHOLD or UPDATE_RTP_PEER frame and was told to resume */
169                 if (!target) {
170                         glue0->update_peer(c0->chan, instance1, vinstance1, tinstance1, cap1, 0);
171                         glue1->update_peer(c1->chan, instance0, vinstance0, tinstance0, cap0, 0);
172                         ast_debug(2, "Remotely bridged '%s' and '%s' - media will flow directly between them\n",
173                                 ast_channel_name(c0->chan), ast_channel_name(c1->chan));
174                 } else {
175                         /*
176                          * If a target was provided, it is the recipient of an unhold or an update and needs to have
177                          * its media redirected to fit the current remote bridging needs. The other channel is either
178                          * already set up to handle the new media path or will have its own set of updates independent
179                          * of this pass.
180                          */
181                         if (c0->chan == target) {
182                                 glue0->update_peer(c0->chan, instance1, vinstance1, tinstance1, cap1, 0);
183                         } else {
184                                 glue1->update_peer(c1->chan, instance0, vinstance0, tinstance0, cap0, 0);
185                         }
186                 }
187                 break;
188         case AST_RTP_GLUE_RESULT_FORBID:
189                 break;
190         }
191
192         ast_channel_unlock(c0->chan);
193         ast_channel_unlock(c1->chan);
194 }
195
196 static void native_rtp_bridge_stop(struct ast_bridge *bridge, struct ast_channel *target)
197 {
198         struct ast_bridge_channel *c0 = AST_LIST_FIRST(&bridge->channels);
199         struct ast_bridge_channel *c1 = AST_LIST_LAST(&bridge->channels);
200         enum ast_rtp_glue_result native_type;
201         struct ast_rtp_glue *glue0, *glue1 = NULL;
202         RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup);
203         RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup);
204         RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup);
205         RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup);
206
207         if (c0 == c1) {
208                 return;
209         }
210
211         if (!c0 || !c1) {
212                 return;
213         }
214
215         ast_channel_lock_both(c0->chan, c1->chan);
216         native_type = native_rtp_bridge_get(c0->chan, c1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1);
217
218         switch (native_type) {
219         case AST_RTP_GLUE_RESULT_LOCAL:
220                 if (ast_rtp_instance_get_engine(instance0)->local_bridge) {
221                         ast_rtp_instance_get_engine(instance0)->local_bridge(instance0, NULL);
222                 }
223                 if (instance1 && ast_rtp_instance_get_engine(instance1)->local_bridge) {
224                         ast_rtp_instance_get_engine(instance1)->local_bridge(instance1, NULL);
225                 }
226                 ast_rtp_instance_set_bridged(instance0, NULL);
227                 if (instance1) {
228                         ast_rtp_instance_set_bridged(instance1, NULL);
229                 }
230                 break;
231         case AST_RTP_GLUE_RESULT_REMOTE:
232                 if (!target) {
233                         if (ast_channel_is_leaving_bridge(c0->chan)) {
234                                 glue0->update_peer(c0->chan, NULL, NULL, NULL, NULL, 0);
235                         }
236                         if (glue1 && ast_channel_is_leaving_bridge(c1->chan)) {
237                                 glue1->update_peer(c1->chan, NULL, NULL, NULL, NULL, 0);
238                         }
239                 } else {
240                         /*
241                          * If a target was provided, it is being put on hold and should expect to
242                          * receive mediafrom sterisk instead of what it was previously connected to.
243                          */
244                         if (c0->chan == target) {
245                                 glue0->update_peer(c0->chan, NULL, NULL, NULL, NULL, 0);
246                         } else if (glue1) {
247                                 glue1->update_peer(c1->chan, NULL, NULL, NULL, NULL, 0);
248                         }
249                 }
250                 break;
251         case AST_RTP_GLUE_RESULT_FORBID:
252                 break;
253         }
254
255         ast_debug(2, "Discontinued RTP bridging of '%s' and '%s' - media will flow through Asterisk core\n",
256                 ast_channel_name(c0->chan), ast_channel_name(c1->chan));
257
258         ast_channel_unlock(c0->chan);
259         ast_channel_unlock(c1->chan);
260 }
261
262 /*! \brief Frame hook that is called to intercept hold/unhold */
263 static struct ast_frame *native_rtp_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
264 {
265         RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
266
267         if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
268                 return f;
269         }
270
271         bridge = ast_channel_get_bridge(chan);
272
273         if (bridge) {
274                 /* native_rtp_bridge_start/stop are not being called from bridging
275                    core so we need to lock the bridge prior to calling these functions
276                    Unfortunately that means unlocking the channel, but as it
277                    should not be modified this should be okay...hopefully */
278                 ast_channel_unlock(chan);
279                 ast_bridge_lock(bridge);
280                 if (f->subclass.integer == AST_CONTROL_HOLD) {
281                         native_rtp_bridge_stop(bridge, chan);
282                 } else if ((f->subclass.integer == AST_CONTROL_UNHOLD) || (f->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER)) {
283                         native_rtp_bridge_start(bridge, chan);
284                 }
285                 ast_bridge_unlock(bridge);
286                 ast_channel_lock(chan);
287
288         }
289
290         return f;
291 }
292
293 /*! \brief Callback function which informs upstream if we are consuming a frame of a specific type */
294 static int native_rtp_framehook_consume(void *data, enum ast_frame_type type)
295 {
296         return (type == AST_FRAME_CONTROL ? 1 : 0);
297 }
298
299 /*! \brief Internal helper function which checks whether the channels are compatible with our native bridging */
300 static int native_rtp_bridge_capable(struct ast_channel *chan)
301 {
302         return !ast_channel_has_hook_requiring_audio(chan);
303 }
304
305 static int native_rtp_bridge_compatible(struct ast_bridge *bridge)
306 {
307         struct ast_bridge_channel *c0 = AST_LIST_FIRST(&bridge->channels);
308         struct ast_bridge_channel *c1 = AST_LIST_LAST(&bridge->channels);
309         enum ast_rtp_glue_result native_type;
310         struct ast_rtp_glue *glue0, *glue1;
311         RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup);
312         RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup);
313         RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup);
314         RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup);
315         RAII_VAR(struct ast_format_cap *, cap0, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK), ast_format_cap_destroy);
316         RAII_VAR(struct ast_format_cap *, cap1, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK), ast_format_cap_destroy);
317         int read_ptime0, read_ptime1, write_ptime0, write_ptime1;
318
319         /* We require two channels before even considering native bridging */
320         if (bridge->num_channels != 2) {
321                 ast_debug(1, "Bridge '%s' can not use native RTP bridge as two channels are required\n",
322                         bridge->uniqueid);
323                 return 0;
324         }
325
326         if (!native_rtp_bridge_capable(c0->chan)) {
327                 ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has features which prevent it\n",
328                         bridge->uniqueid, ast_channel_name(c0->chan));
329                 return 0;
330         }
331
332         if (!native_rtp_bridge_capable(c1->chan)) {
333                 ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has features which prevent it\n",
334                         bridge->uniqueid, ast_channel_name(c1->chan));
335                 return 0;
336         }
337
338         if ((native_type = native_rtp_bridge_get(c0->chan, c1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1))
339                 == AST_RTP_GLUE_RESULT_FORBID) {
340                 ast_debug(1, "Bridge '%s' can not use native RTP bridge as it was forbidden while getting details\n",
341                         bridge->uniqueid);
342                 return 0;
343         }
344
345         if (ao2_container_count(c0->features->dtmf_hooks) && ast_rtp_instance_dtmf_mode_get(instance0)) {
346                 ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has DTMF hooks\n",
347                         bridge->uniqueid, ast_channel_name(c0->chan));
348                 return 0;
349         }
350
351         if (ao2_container_count(c1->features->dtmf_hooks) && ast_rtp_instance_dtmf_mode_get(instance1)) {
352                 ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has DTMF hooks\n",
353                         bridge->uniqueid, ast_channel_name(c1->chan));
354                 return 0;
355         }
356
357         if ((native_type == AST_RTP_GLUE_RESULT_LOCAL) && ((ast_rtp_instance_get_engine(instance0)->local_bridge !=
358                 ast_rtp_instance_get_engine(instance1)->local_bridge) ||
359                 (ast_rtp_instance_get_engine(instance0)->dtmf_compatible &&
360                         !ast_rtp_instance_get_engine(instance0)->dtmf_compatible(c0->chan, instance0, c1->chan, instance1)))) {
361                 ast_debug(1, "Bridge '%s' can not use local native RTP bridge as local bridge or DTMF is not compatible\n",
362                         bridge->uniqueid);
363                 return 0;
364         }
365
366         /* Make sure that codecs match */
367         if (glue0->get_codec) {
368                 glue0->get_codec(c0->chan, cap0);
369         }
370         if (glue1->get_codec) {
371                 glue1->get_codec(c1->chan, cap1);
372         }
373         if (!ast_format_cap_is_empty(cap0) && !ast_format_cap_is_empty(cap1) && !ast_format_cap_has_joint(cap0, cap1)) {
374                 char tmp0[256] = { 0, }, tmp1[256] = { 0, };
375
376                 ast_debug(1, "Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP.\n",
377                         ast_getformatname_multiple(tmp0, sizeof(tmp0), cap0),
378                         ast_getformatname_multiple(tmp1, sizeof(tmp1), cap1));
379                 return 0;
380         }
381
382         read_ptime0 = (ast_codec_pref_getsize(&ast_rtp_instance_get_codecs(instance0)->pref, ast_channel_rawreadformat(c0->chan))).cur_ms;
383         read_ptime1 = (ast_codec_pref_getsize(&ast_rtp_instance_get_codecs(instance1)->pref, ast_channel_rawreadformat(c1->chan))).cur_ms;
384         write_ptime0 = (ast_codec_pref_getsize(&ast_rtp_instance_get_codecs(instance0)->pref, ast_channel_rawwriteformat(c0->chan))).cur_ms;
385         write_ptime1 = (ast_codec_pref_getsize(&ast_rtp_instance_get_codecs(instance1)->pref, ast_channel_rawwriteformat(c1->chan))).cur_ms;
386
387         if (read_ptime0 != write_ptime1 || read_ptime1 != write_ptime0) {
388                 ast_debug(1, "Packetization differs between RTP streams (%d != %d or %d != %d). Cannot native bridge in RTP\n",
389                                 read_ptime0, write_ptime1, read_ptime1, write_ptime0);
390                 return 0;
391         }
392
393         return 1;
394 }
395
396 /*! \brief Helper function which adds frame hook to bridge channel */
397 static int native_rtp_bridge_framehook_attach(struct ast_bridge_channel *bridge_channel)
398 {
399         struct native_rtp_bridge_data *data = ao2_alloc(sizeof(*data), NULL);
400         static struct ast_framehook_interface hook = {
401                 .version = AST_FRAMEHOOK_INTERFACE_VERSION,
402                 .event_cb = native_rtp_framehook,
403                 .consume_cb = native_rtp_framehook_consume,
404         };
405
406         if (!data) {
407                 return -1;
408         }
409
410         ast_channel_lock(bridge_channel->chan);
411         data->id = ast_framehook_attach(bridge_channel->chan, &hook);
412         ast_channel_unlock(bridge_channel->chan);
413         if (data->id < 0) {
414                 ao2_cleanup(data);
415                 return -1;
416         }
417
418         bridge_channel->tech_pvt = data;
419
420         return 0;
421 }
422
423 /*! \brief Helper function which removes frame hook from bridge channel */
424 static void native_rtp_bridge_framehook_detach(struct ast_bridge_channel *bridge_channel)
425 {
426         RAII_VAR(struct native_rtp_bridge_data *, data, bridge_channel->tech_pvt, ao2_cleanup);
427
428         if (!data) {
429                 return;
430         }
431
432         ast_channel_lock(bridge_channel->chan);
433         ast_framehook_detach(bridge_channel->chan, data->id);
434         ast_channel_unlock(bridge_channel->chan);
435         bridge_channel->tech_pvt = NULL;
436 }
437
438 static int native_rtp_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
439 {
440         native_rtp_bridge_framehook_detach(bridge_channel);
441         if (native_rtp_bridge_framehook_attach(bridge_channel)) {
442                 return -1;
443         }
444
445         native_rtp_bridge_start(bridge, NULL);
446         return 0;
447 }
448
449 static void native_rtp_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
450 {
451         native_rtp_bridge_join(bridge, bridge_channel);
452 }
453
454 static void native_rtp_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
455 {
456         struct ast_rtp_glue *glue;
457         RAII_VAR(struct ast_rtp_instance *, instance, NULL, ao2_cleanup);
458         RAII_VAR(struct ast_rtp_instance *, vinstance, NULL, ao2_cleanup);
459         RAII_VAR(struct ast_rtp_instance *, tinstance, NULL, ao2_cleanup);
460
461         native_rtp_bridge_framehook_detach(bridge_channel);
462
463         glue = ast_rtp_instance_get_glue(ast_channel_tech(bridge_channel->chan)->type);
464         if (!glue) {
465                 return;
466         }
467
468         glue->get_rtp_info(bridge_channel->chan, &instance);
469
470         if (glue->get_vrtp_info) {
471                 glue->get_vrtp_info(bridge_channel->chan, &vinstance);
472         }
473
474         if (glue->get_trtp_info) {
475                 glue->get_trtp_info(bridge_channel->chan, &tinstance);
476         }
477
478         /* Tear down P2P bridges */
479         if (instance) {
480                 ast_rtp_instance_set_bridged(instance, NULL);
481         }
482         if (vinstance) {
483                 ast_rtp_instance_set_bridged(vinstance, NULL);
484         }
485         if (tinstance) {
486                 ast_rtp_instance_set_bridged(tinstance, NULL);
487         }
488
489         /* Direct RTP may have occurred, tear it down */
490         if (ast_channel_is_leaving_bridge(bridge_channel->chan)) {
491                 glue->update_peer(bridge_channel->chan, NULL, NULL, NULL, NULL, 0);
492         }
493         native_rtp_bridge_stop(bridge, NULL);
494 }
495
496 static int native_rtp_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
497 {
498         return ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
499 }
500
501 static struct ast_bridge_technology native_rtp_bridge = {
502         .name = "native_rtp",
503         .capabilities = AST_BRIDGE_CAPABILITY_NATIVE,
504         .preference = AST_BRIDGE_PREFERENCE_BASE_NATIVE,
505         .join = native_rtp_bridge_join,
506         .unsuspend = native_rtp_bridge_unsuspend,
507         .leave = native_rtp_bridge_leave,
508         .suspend = native_rtp_bridge_leave,
509         .write = native_rtp_bridge_write,
510         .compatible = native_rtp_bridge_compatible,
511 };
512
513 static int unload_module(void)
514 {
515         ast_format_cap_destroy(native_rtp_bridge.format_capabilities);
516         return ast_bridge_technology_unregister(&native_rtp_bridge);
517 }
518
519 static int load_module(void)
520 {
521         if (!(native_rtp_bridge.format_capabilities = ast_format_cap_alloc(0))) {
522                 return AST_MODULE_LOAD_DECLINE;
523         }
524         ast_format_cap_add_all_by_type(native_rtp_bridge.format_capabilities, AST_FORMAT_TYPE_AUDIO);
525         ast_format_cap_add_all_by_type(native_rtp_bridge.format_capabilities, AST_FORMAT_TYPE_VIDEO);
526         ast_format_cap_add_all_by_type(native_rtp_bridge.format_capabilities, AST_FORMAT_TYPE_TEXT);
527
528         return ast_bridge_technology_register(&native_rtp_bridge);
529 }
530
531 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Native RTP bridging module");