Allow Asterisk to compile under GCC 4.10
[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                         glue0->update_peer(c0->chan, NULL, NULL, NULL, NULL, 0);
234                         if (glue1) {
235                                 glue1->update_peer(c1->chan, NULL, NULL, NULL, NULL, 0);
236                         }
237                 } else {
238                         /*
239                          * If a target was provided, it is being put on hold and should expect to
240                          * receive mediafrom sterisk instead of what it was previously connected to.
241                          */
242                         if (c0->chan == target) {
243                                 glue0->update_peer(c0->chan, NULL, NULL, NULL, NULL, 0);
244                         } else if (glue1) {
245                                 glue1->update_peer(c1->chan, NULL, NULL, NULL, NULL, 0);
246                         }
247                 }
248                 break;
249         case AST_RTP_GLUE_RESULT_FORBID:
250                 break;
251         }
252
253         ast_debug(2, "Discontinued RTP bridging of '%s' and '%s' - media will flow through Asterisk core\n",
254                 ast_channel_name(c0->chan), ast_channel_name(c1->chan));
255
256         ast_channel_unlock(c0->chan);
257         ast_channel_unlock(c1->chan);
258 }
259
260 /*! \brief Frame hook that is called to intercept hold/unhold */
261 static struct ast_frame *native_rtp_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
262 {
263         RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
264
265         if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
266                 return f;
267         }
268
269         bridge = ast_channel_get_bridge(chan);
270
271         if (bridge) {
272                 /* native_rtp_bridge_start/stop are not being called from bridging
273                    core so we need to lock the bridge prior to calling these functions
274                    Unfortunately that means unlocking the channel, but as it
275                    should not be modified this should be okay...hopefully */
276                 ast_channel_unlock(chan);
277                 ast_bridge_lock(bridge);
278                 if (f->subclass.integer == AST_CONTROL_HOLD) {
279                         native_rtp_bridge_stop(bridge, chan);
280                 } else if ((f->subclass.integer == AST_CONTROL_UNHOLD) || (f->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER)) {
281                         native_rtp_bridge_start(bridge, chan);
282                 }
283                 ast_bridge_unlock(bridge);
284                 ast_channel_lock(chan);
285
286         }
287
288         return f;
289 }
290
291 /*! \brief Internal helper function which checks whether the channels are compatible with our native bridging */
292 static int native_rtp_bridge_capable(struct ast_channel *chan)
293 {
294         return !ast_channel_has_audio_frame_or_monitor(chan);
295 }
296
297 static int native_rtp_bridge_compatible(struct ast_bridge *bridge)
298 {
299         struct ast_bridge_channel *c0 = AST_LIST_FIRST(&bridge->channels);
300         struct ast_bridge_channel *c1 = AST_LIST_LAST(&bridge->channels);
301         enum ast_rtp_glue_result native_type;
302         struct ast_rtp_glue *glue0, *glue1;
303         RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup);
304         RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup);
305         RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup);
306         RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup);
307         RAII_VAR(struct ast_format_cap *, cap0, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK), ast_format_cap_destroy);
308         RAII_VAR(struct ast_format_cap *, cap1, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK), ast_format_cap_destroy);
309         int read_ptime0, read_ptime1, write_ptime0, write_ptime1;
310
311         /* We require two channels before even considering native bridging */
312         if (bridge->num_channels != 2) {
313                 ast_debug(1, "Bridge '%s' can not use native RTP bridge as two channels are required\n",
314                         bridge->uniqueid);
315                 return 0;
316         }
317
318         if (!native_rtp_bridge_capable(c0->chan)) {
319                 ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has features which prevent it\n",
320                         bridge->uniqueid, ast_channel_name(c0->chan));
321                 return 0;
322         }
323
324         if (!native_rtp_bridge_capable(c1->chan)) {
325                 ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has features which prevent it\n",
326                         bridge->uniqueid, ast_channel_name(c1->chan));
327                 return 0;
328         }
329
330         if ((native_type = native_rtp_bridge_get(c0->chan, c1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1))
331                 == AST_RTP_GLUE_RESULT_FORBID) {
332                 ast_debug(1, "Bridge '%s' can not use native RTP bridge as it was forbidden while getting details\n",
333                         bridge->uniqueid);
334                 return 0;
335         }
336
337         if (ao2_container_count(c0->features->dtmf_hooks) && ast_rtp_instance_dtmf_mode_get(instance0)) {
338                 ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has DTMF hooks\n",
339                         bridge->uniqueid, ast_channel_name(c0->chan));
340                 return 0;
341         }
342
343         if (ao2_container_count(c1->features->dtmf_hooks) && ast_rtp_instance_dtmf_mode_get(instance1)) {
344                 ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has DTMF hooks\n",
345                         bridge->uniqueid, ast_channel_name(c1->chan));
346                 return 0;
347         }
348
349         if ((native_type == AST_RTP_GLUE_RESULT_LOCAL) && ((ast_rtp_instance_get_engine(instance0)->local_bridge !=
350                 ast_rtp_instance_get_engine(instance1)->local_bridge) ||
351                 (ast_rtp_instance_get_engine(instance0)->dtmf_compatible &&
352                         !ast_rtp_instance_get_engine(instance0)->dtmf_compatible(c0->chan, instance0, c1->chan, instance1)))) {
353                 ast_debug(1, "Bridge '%s' can not use local native RTP bridge as local bridge or DTMF is not compatible\n",
354                         bridge->uniqueid);
355                 return 0;
356         }
357
358         /* Make sure that codecs match */
359         if (glue0->get_codec) {
360                 glue0->get_codec(c0->chan, cap0);
361         }
362         if (glue1->get_codec) {
363                 glue1->get_codec(c1->chan, cap1);
364         }
365         if (!ast_format_cap_is_empty(cap0) && !ast_format_cap_is_empty(cap1) && !ast_format_cap_has_joint(cap0, cap1)) {
366                 char tmp0[256] = { 0, }, tmp1[256] = { 0, };
367
368                 ast_debug(1, "Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP.\n",
369                         ast_getformatname_multiple(tmp0, sizeof(tmp0), cap0),
370                         ast_getformatname_multiple(tmp1, sizeof(tmp1), cap1));
371                 return 0;
372         }
373
374         read_ptime0 = (ast_codec_pref_getsize(&ast_rtp_instance_get_codecs(instance0)->pref, ast_channel_rawreadformat(c0->chan))).cur_ms;
375         read_ptime1 = (ast_codec_pref_getsize(&ast_rtp_instance_get_codecs(instance1)->pref, ast_channel_rawreadformat(c1->chan))).cur_ms;
376         write_ptime0 = (ast_codec_pref_getsize(&ast_rtp_instance_get_codecs(instance0)->pref, ast_channel_rawwriteformat(c0->chan))).cur_ms;
377         write_ptime1 = (ast_codec_pref_getsize(&ast_rtp_instance_get_codecs(instance1)->pref, ast_channel_rawwriteformat(c1->chan))).cur_ms;
378
379         if (read_ptime0 != write_ptime1 || read_ptime1 != write_ptime0) {
380                 ast_debug(1, "Packetization differs between RTP streams (%d != %d or %d != %d). Cannot native bridge in RTP\n",
381                                 read_ptime0, write_ptime1, read_ptime1, write_ptime0);
382                 return 0;
383         }
384
385         return 1;
386 }
387
388 /*! \brief Helper function which adds frame hook to bridge channel */
389 static int native_rtp_bridge_framehook_attach(struct ast_bridge_channel *bridge_channel)
390 {
391         struct native_rtp_bridge_data *data = ao2_alloc(sizeof(*data), NULL);
392         static struct ast_framehook_interface hook = {
393                 .version = AST_FRAMEHOOK_INTERFACE_VERSION,
394                 .event_cb = native_rtp_framehook,
395         };
396
397         if (!data) {
398                 return -1;
399         }
400
401         ast_channel_lock(bridge_channel->chan);
402         data->id = ast_framehook_attach(bridge_channel->chan, &hook);
403         ast_channel_unlock(bridge_channel->chan);
404         if (data->id < 0) {
405                 ao2_cleanup(data);
406                 return -1;
407         }
408
409         bridge_channel->tech_pvt = data;
410
411         return 0;
412 }
413
414 /*! \brief Helper function which removes frame hook from bridge channel */
415 static void native_rtp_bridge_framehook_detach(struct ast_bridge_channel *bridge_channel)
416 {
417         RAII_VAR(struct native_rtp_bridge_data *, data, bridge_channel->tech_pvt, ao2_cleanup);
418
419         if (!data) {
420                 return;
421         }
422
423         ast_channel_lock(bridge_channel->chan);
424         ast_framehook_detach(bridge_channel->chan, data->id);
425         ast_channel_unlock(bridge_channel->chan);
426         bridge_channel->tech_pvt = NULL;
427 }
428
429 static int native_rtp_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
430 {
431         native_rtp_bridge_framehook_detach(bridge_channel);
432         if (native_rtp_bridge_framehook_attach(bridge_channel)) {
433                 return -1;
434         }
435
436         native_rtp_bridge_start(bridge, NULL);
437         return 0;
438 }
439
440 static void native_rtp_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
441 {
442         native_rtp_bridge_join(bridge, bridge_channel);
443 }
444
445 static void native_rtp_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
446 {
447         struct ast_rtp_glue *glue;
448         RAII_VAR(struct ast_rtp_instance *, instance, NULL, ao2_cleanup);
449         RAII_VAR(struct ast_rtp_instance *, vinstance, NULL, ao2_cleanup);
450         RAII_VAR(struct ast_rtp_instance *, tinstance, NULL, ao2_cleanup);
451
452         native_rtp_bridge_framehook_detach(bridge_channel);
453
454         glue = ast_rtp_instance_get_glue(ast_channel_tech(bridge_channel->chan)->type);
455         if (!glue) {
456                 return;
457         }
458
459         glue->get_rtp_info(bridge_channel->chan, &instance);
460
461         if (glue->get_vrtp_info) {
462                 glue->get_vrtp_info(bridge_channel->chan, &vinstance);
463         }
464
465         if (glue->get_trtp_info) {
466                 glue->get_trtp_info(bridge_channel->chan, &tinstance);
467         }
468
469         /* Tear down P2P bridges */
470         if (instance) {
471                 ast_rtp_instance_set_bridged(instance, NULL);
472         }
473         if (vinstance) {
474                 ast_rtp_instance_set_bridged(vinstance, NULL);
475         }
476         if (tinstance) {
477                 ast_rtp_instance_set_bridged(tinstance, NULL);
478         }
479
480         /* Direct RTP may have occurred, tear it down */
481         glue->update_peer(bridge_channel->chan, NULL, NULL, NULL, NULL, 0);
482
483         native_rtp_bridge_stop(bridge, NULL);
484 }
485
486 static int native_rtp_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
487 {
488         return ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
489 }
490
491 static struct ast_bridge_technology native_rtp_bridge = {
492         .name = "native_rtp",
493         .capabilities = AST_BRIDGE_CAPABILITY_NATIVE,
494         .preference = AST_BRIDGE_PREFERENCE_BASE_NATIVE,
495         .join = native_rtp_bridge_join,
496         .unsuspend = native_rtp_bridge_unsuspend,
497         .leave = native_rtp_bridge_leave,
498         .suspend = native_rtp_bridge_leave,
499         .write = native_rtp_bridge_write,
500         .compatible = native_rtp_bridge_compatible,
501 };
502
503 static int unload_module(void)
504 {
505         ast_format_cap_destroy(native_rtp_bridge.format_capabilities);
506         return ast_bridge_technology_unregister(&native_rtp_bridge);
507 }
508
509 static int load_module(void)
510 {
511         if (!(native_rtp_bridge.format_capabilities = ast_format_cap_alloc(0))) {
512                 return AST_MODULE_LOAD_DECLINE;
513         }
514         ast_format_cap_add_all_by_type(native_rtp_bridge.format_capabilities, AST_FORMAT_TYPE_AUDIO);
515         ast_format_cap_add_all_by_type(native_rtp_bridge.format_capabilities, AST_FORMAT_TYPE_VIDEO);
516         ast_format_cap_add_all_by_type(native_rtp_bridge.format_capabilities, AST_FORMAT_TYPE_TEXT);
517
518         return ast_bridge_technology_register(&native_rtp_bridge);
519 }
520
521 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Native RTP bridging module");