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