00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 353126 $")
00029
00030 #include <math.h>
00031
00032 #include "asterisk/channel.h"
00033 #include "asterisk/frame.h"
00034 #include "asterisk/module.h"
00035 #include "asterisk/rtp_engine.h"
00036 #include "asterisk/manager.h"
00037 #include "asterisk/options.h"
00038 #include "asterisk/astobj2.h"
00039 #include "asterisk/pbx.h"
00040 #include "asterisk/translate.h"
00041 #include "asterisk/netsock2.h"
00042 #include "asterisk/framehook.h"
00043
00044 struct ast_srtp_res *res_srtp = NULL;
00045 struct ast_srtp_policy_res *res_srtp_policy = NULL;
00046
00047
00048 struct ast_rtp_instance {
00049
00050 struct ast_rtp_engine *engine;
00051
00052 void *data;
00053
00054 int properties[AST_RTP_PROPERTY_MAX];
00055
00056 struct ast_sockaddr local_address;
00057
00058 struct ast_sockaddr remote_address;
00059
00060 struct ast_sockaddr alt_remote_address;
00061
00062 struct ast_rtp_instance *bridged;
00063
00064 struct ast_rtp_codecs codecs;
00065
00066 int timeout;
00067
00068 int holdtimeout;
00069
00070 int keepalive;
00071
00072 struct ast_rtp_glue *glue;
00073
00074 struct ast_channel *chan;
00075
00076 struct ast_srtp *srtp;
00077 };
00078
00079
00080 static AST_RWLIST_HEAD_STATIC(engines, ast_rtp_engine);
00081
00082
00083 static AST_RWLIST_HEAD_STATIC(glues, ast_rtp_glue);
00084
00085
00086
00087 static const struct ast_rtp_mime_type {
00088 struct ast_rtp_payload_type payload_type;
00089 char *type;
00090 char *subtype;
00091 unsigned int sample_rate;
00092 } ast_rtp_mime_types[] = {
00093 {{1, AST_FORMAT_G723_1}, "audio", "G723", 8000},
00094 {{1, AST_FORMAT_GSM}, "audio", "GSM", 8000},
00095 {{1, AST_FORMAT_ULAW}, "audio", "PCMU", 8000},
00096 {{1, AST_FORMAT_ULAW}, "audio", "G711U", 8000},
00097 {{1, AST_FORMAT_ALAW}, "audio", "PCMA", 8000},
00098 {{1, AST_FORMAT_ALAW}, "audio", "G711A", 8000},
00099 {{1, AST_FORMAT_G726}, "audio", "G726-32", 8000},
00100 {{1, AST_FORMAT_ADPCM}, "audio", "DVI4", 8000},
00101 {{1, AST_FORMAT_SLINEAR}, "audio", "L16", 8000},
00102 {{1, AST_FORMAT_SLINEAR16}, "audio", "L16", 16000},
00103 {{1, AST_FORMAT_SLINEAR16}, "audio", "L16-256", 16000},
00104 {{1, AST_FORMAT_LPC10}, "audio", "LPC", 8000},
00105 {{1, AST_FORMAT_G729A}, "audio", "G729", 8000},
00106 {{1, AST_FORMAT_G729A}, "audio", "G729A", 8000},
00107 {{1, AST_FORMAT_G729A}, "audio", "G.729", 8000},
00108 {{1, AST_FORMAT_SPEEX}, "audio", "speex", 8000},
00109 {{1, AST_FORMAT_SPEEX16}, "audio", "speex", 16000},
00110 {{1, AST_FORMAT_ILBC}, "audio", "iLBC", 8000},
00111
00112
00113
00114 {{1, AST_FORMAT_G722}, "audio", "G722", 8000},
00115 {{1, AST_FORMAT_G726_AAL2}, "audio", "AAL2-G726-32", 8000},
00116 {{0, AST_RTP_DTMF}, "audio", "telephone-event", 8000},
00117 {{0, AST_RTP_CISCO_DTMF}, "audio", "cisco-telephone-event", 8000},
00118 {{0, AST_RTP_CN}, "audio", "CN", 8000},
00119 {{1, AST_FORMAT_JPEG}, "video", "JPEG", 90000},
00120 {{1, AST_FORMAT_PNG}, "video", "PNG", 90000},
00121 {{1, AST_FORMAT_H261}, "video", "H261", 90000},
00122 {{1, AST_FORMAT_H263}, "video", "H263", 90000},
00123 {{1, AST_FORMAT_H263_PLUS}, "video", "h263-1998", 90000},
00124 {{1, AST_FORMAT_H264}, "video", "H264", 90000},
00125 {{1, AST_FORMAT_MP4_VIDEO}, "video", "MP4V-ES", 90000},
00126 {{1, AST_FORMAT_T140RED}, "text", "RED", 1000},
00127 {{1, AST_FORMAT_T140}, "text", "T140", 1000},
00128 {{1, AST_FORMAT_SIREN7}, "audio", "G7221", 16000},
00129 {{1, AST_FORMAT_SIREN14}, "audio", "G7221", 32000},
00130 {{1, AST_FORMAT_G719}, "audio", "G719", 48000},
00131 };
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 static const struct ast_rtp_payload_type static_RTP_PT[AST_RTP_MAX_PT] = {
00144 [0] = {1, AST_FORMAT_ULAW},
00145 #ifdef USE_DEPRECATED_G726
00146 [2] = {1, AST_FORMAT_G726},
00147 #endif
00148 [3] = {1, AST_FORMAT_GSM},
00149 [4] = {1, AST_FORMAT_G723_1},
00150 [5] = {1, AST_FORMAT_ADPCM},
00151 [6] = {1, AST_FORMAT_ADPCM},
00152 [7] = {1, AST_FORMAT_LPC10},
00153 [8] = {1, AST_FORMAT_ALAW},
00154 [9] = {1, AST_FORMAT_G722},
00155 [10] = {1, AST_FORMAT_SLINEAR},
00156 [11] = {1, AST_FORMAT_SLINEAR},
00157 [13] = {0, AST_RTP_CN},
00158 [16] = {1, AST_FORMAT_ADPCM},
00159 [17] = {1, AST_FORMAT_ADPCM},
00160 [18] = {1, AST_FORMAT_G729A},
00161 [19] = {0, AST_RTP_CN},
00162 [26] = {1, AST_FORMAT_JPEG},
00163 [31] = {1, AST_FORMAT_H261},
00164 [34] = {1, AST_FORMAT_H263},
00165 [97] = {1, AST_FORMAT_ILBC},
00166 [98] = {1, AST_FORMAT_H263_PLUS},
00167 [99] = {1, AST_FORMAT_H264},
00168 [101] = {0, AST_RTP_DTMF},
00169 [102] = {1, AST_FORMAT_SIREN7},
00170 [103] = {1, AST_FORMAT_H263_PLUS},
00171 [104] = {1, AST_FORMAT_MP4_VIDEO},
00172 [105] = {1, AST_FORMAT_T140RED},
00173 [106] = {1, AST_FORMAT_T140},
00174 [110] = {1, AST_FORMAT_SPEEX},
00175 [111] = {1, AST_FORMAT_G726},
00176 [112] = {1, AST_FORMAT_G726_AAL2},
00177 [115] = {1, AST_FORMAT_SIREN14},
00178 [116] = {1, AST_FORMAT_G719},
00179 [117] = {1, AST_FORMAT_SPEEX16},
00180 [118] = {1, AST_FORMAT_SLINEAR16},
00181 [121] = {0, AST_RTP_CISCO_DTMF},
00182 };
00183
00184 int ast_rtp_engine_register2(struct ast_rtp_engine *engine, struct ast_module *module)
00185 {
00186 struct ast_rtp_engine *current_engine;
00187
00188
00189 if (ast_strlen_zero(engine->name) || !engine->new || !engine->destroy || !engine->write || !engine->read) {
00190 ast_log(LOG_WARNING, "RTP Engine '%s' failed sanity check so it was not registered.\n", !ast_strlen_zero(engine->name) ? engine->name : "Unknown");
00191 return -1;
00192 }
00193
00194
00195 engine->mod = module;
00196
00197 AST_RWLIST_WRLOCK(&engines);
00198
00199
00200 AST_RWLIST_TRAVERSE(&engines, current_engine, entry) {
00201 if (!strcmp(current_engine->name, engine->name)) {
00202 ast_log(LOG_WARNING, "An RTP engine with the name '%s' has already been registered.\n", engine->name);
00203 AST_RWLIST_UNLOCK(&engines);
00204 return -1;
00205 }
00206 }
00207
00208
00209 AST_RWLIST_INSERT_TAIL(&engines, engine, entry);
00210
00211 AST_RWLIST_UNLOCK(&engines);
00212
00213 ast_verb(2, "Registered RTP engine '%s'\n", engine->name);
00214
00215 return 0;
00216 }
00217
00218 int ast_rtp_engine_unregister(struct ast_rtp_engine *engine)
00219 {
00220 struct ast_rtp_engine *current_engine = NULL;
00221
00222 AST_RWLIST_WRLOCK(&engines);
00223
00224 if ((current_engine = AST_RWLIST_REMOVE(&engines, engine, entry))) {
00225 ast_verb(2, "Unregistered RTP engine '%s'\n", engine->name);
00226 }
00227
00228 AST_RWLIST_UNLOCK(&engines);
00229
00230 return current_engine ? 0 : -1;
00231 }
00232
00233 int ast_rtp_glue_register2(struct ast_rtp_glue *glue, struct ast_module *module)
00234 {
00235 struct ast_rtp_glue *current_glue = NULL;
00236
00237 if (ast_strlen_zero(glue->type)) {
00238 return -1;
00239 }
00240
00241 glue->mod = module;
00242
00243 AST_RWLIST_WRLOCK(&glues);
00244
00245 AST_RWLIST_TRAVERSE(&glues, current_glue, entry) {
00246 if (!strcasecmp(current_glue->type, glue->type)) {
00247 ast_log(LOG_WARNING, "RTP glue with the name '%s' has already been registered.\n", glue->type);
00248 AST_RWLIST_UNLOCK(&glues);
00249 return -1;
00250 }
00251 }
00252
00253 AST_RWLIST_INSERT_TAIL(&glues, glue, entry);
00254
00255 AST_RWLIST_UNLOCK(&glues);
00256
00257 ast_verb(2, "Registered RTP glue '%s'\n", glue->type);
00258
00259 return 0;
00260 }
00261
00262 int ast_rtp_glue_unregister(struct ast_rtp_glue *glue)
00263 {
00264 struct ast_rtp_glue *current_glue = NULL;
00265
00266 AST_RWLIST_WRLOCK(&glues);
00267
00268 if ((current_glue = AST_RWLIST_REMOVE(&glues, glue, entry))) {
00269 ast_verb(2, "Unregistered RTP glue '%s'\n", glue->type);
00270 }
00271
00272 AST_RWLIST_UNLOCK(&glues);
00273
00274 return current_glue ? 0 : -1;
00275 }
00276
00277 static void instance_destructor(void *obj)
00278 {
00279 struct ast_rtp_instance *instance = obj;
00280
00281
00282 if (instance->data && instance->engine->destroy(instance)) {
00283 ast_debug(1, "Engine '%s' failed to destroy RTP instance '%p'\n", instance->engine->name, instance);
00284 return;
00285 }
00286
00287 if (instance->srtp) {
00288 res_srtp->destroy(instance->srtp);
00289 }
00290
00291
00292 ast_module_unref(instance->engine->mod);
00293
00294 ast_debug(1, "Destroyed RTP instance '%p'\n", instance);
00295 }
00296
00297 int ast_rtp_instance_destroy(struct ast_rtp_instance *instance)
00298 {
00299 ao2_ref(instance, -1);
00300
00301 return 0;
00302 }
00303
00304 struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name,
00305 struct sched_context *sched, const struct ast_sockaddr *sa,
00306 void *data)
00307 {
00308 struct ast_sockaddr address = {{0,}};
00309 struct ast_rtp_instance *instance = NULL;
00310 struct ast_rtp_engine *engine = NULL;
00311
00312 AST_RWLIST_RDLOCK(&engines);
00313
00314
00315 if (!ast_strlen_zero(engine_name)) {
00316 AST_RWLIST_TRAVERSE(&engines, engine, entry) {
00317 if (!strcmp(engine->name, engine_name)) {
00318 break;
00319 }
00320 }
00321 } else {
00322 engine = AST_RWLIST_FIRST(&engines);
00323 }
00324
00325
00326 if (!engine) {
00327 ast_log(LOG_ERROR, "No RTP engine was found. Do you have one loaded?\n");
00328 AST_RWLIST_UNLOCK(&engines);
00329 return NULL;
00330 }
00331
00332
00333 ast_module_ref(engine->mod);
00334
00335 AST_RWLIST_UNLOCK(&engines);
00336
00337
00338 if (!(instance = ao2_alloc(sizeof(*instance), instance_destructor))) {
00339 ast_module_unref(engine->mod);
00340 return NULL;
00341 }
00342 instance->engine = engine;
00343 ast_sockaddr_copy(&instance->local_address, sa);
00344 ast_sockaddr_copy(&address, sa);
00345
00346 ast_debug(1, "Using engine '%s' for RTP instance '%p'\n", engine->name, instance);
00347
00348
00349 if (instance->engine->new(instance, sched, &address, data)) {
00350 ast_debug(1, "Engine '%s' failed to setup RTP instance '%p'\n", engine->name, instance);
00351 ao2_ref(instance, -1);
00352 return NULL;
00353 }
00354
00355 ast_debug(1, "RTP instance '%p' is setup and ready to go\n", instance);
00356
00357 return instance;
00358 }
00359
00360 void ast_rtp_instance_set_data(struct ast_rtp_instance *instance, void *data)
00361 {
00362 instance->data = data;
00363 }
00364
00365 void *ast_rtp_instance_get_data(struct ast_rtp_instance *instance)
00366 {
00367 return instance->data;
00368 }
00369
00370 int ast_rtp_instance_write(struct ast_rtp_instance *instance, struct ast_frame *frame)
00371 {
00372 return instance->engine->write(instance, frame);
00373 }
00374
00375 struct ast_frame *ast_rtp_instance_read(struct ast_rtp_instance *instance, int rtcp)
00376 {
00377 return instance->engine->read(instance, rtcp);
00378 }
00379
00380 int ast_rtp_instance_set_local_address(struct ast_rtp_instance *instance,
00381 const struct ast_sockaddr *address)
00382 {
00383 ast_sockaddr_copy(&instance->local_address, address);
00384 return 0;
00385 }
00386
00387 int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance,
00388 const struct ast_sockaddr *address)
00389 {
00390 ast_sockaddr_copy(&instance->remote_address, address);
00391
00392
00393
00394 if (instance->engine->remote_address_set) {
00395 instance->engine->remote_address_set(instance, &instance->remote_address);
00396 }
00397
00398 return 0;
00399 }
00400
00401 int ast_rtp_instance_set_alt_remote_address(struct ast_rtp_instance *instance,
00402 const struct ast_sockaddr *address)
00403 {
00404 ast_sockaddr_copy(&instance->alt_remote_address, address);
00405
00406
00407
00408 if (instance->engine->alt_remote_address_set) {
00409 instance->engine->alt_remote_address_set(instance, &instance->alt_remote_address);
00410 }
00411
00412 return 0;
00413 }
00414
00415 int ast_rtp_instance_get_and_cmp_local_address(struct ast_rtp_instance *instance,
00416 struct ast_sockaddr *address)
00417 {
00418 if (ast_sockaddr_cmp(address, &instance->local_address) != 0) {
00419 ast_sockaddr_copy(address, &instance->local_address);
00420 return 1;
00421 }
00422
00423 return 0;
00424 }
00425
00426 void ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance,
00427 struct ast_sockaddr *address)
00428 {
00429 ast_sockaddr_copy(address, &instance->local_address);
00430 }
00431
00432 int ast_rtp_instance_get_and_cmp_remote_address(struct ast_rtp_instance *instance,
00433 struct ast_sockaddr *address)
00434 {
00435 if (ast_sockaddr_cmp(address, &instance->remote_address) != 0) {
00436 ast_sockaddr_copy(address, &instance->remote_address);
00437 return 1;
00438 }
00439
00440 return 0;
00441 }
00442
00443 void ast_rtp_instance_get_remote_address(struct ast_rtp_instance *instance,
00444 struct ast_sockaddr *address)
00445 {
00446 ast_sockaddr_copy(address, &instance->remote_address);
00447 }
00448
00449 void ast_rtp_instance_set_extended_prop(struct ast_rtp_instance *instance, int property, void *value)
00450 {
00451 if (instance->engine->extended_prop_set) {
00452 instance->engine->extended_prop_set(instance, property, value);
00453 }
00454 }
00455
00456 void *ast_rtp_instance_get_extended_prop(struct ast_rtp_instance *instance, int property)
00457 {
00458 if (instance->engine->extended_prop_get) {
00459 return instance->engine->extended_prop_get(instance, property);
00460 }
00461
00462 return NULL;
00463 }
00464
00465 void ast_rtp_instance_set_prop(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value)
00466 {
00467 instance->properties[property] = value;
00468
00469 if (instance->engine->prop_set) {
00470 instance->engine->prop_set(instance, property, value);
00471 }
00472 }
00473
00474 int ast_rtp_instance_get_prop(struct ast_rtp_instance *instance, enum ast_rtp_property property)
00475 {
00476 return instance->properties[property];
00477 }
00478
00479 struct ast_rtp_codecs *ast_rtp_instance_get_codecs(struct ast_rtp_instance *instance)
00480 {
00481 return &instance->codecs;
00482 }
00483
00484 void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance)
00485 {
00486 int i;
00487
00488 for (i = 0; i < AST_RTP_MAX_PT; i++) {
00489 codecs->payloads[i].asterisk_format = 0;
00490 codecs->payloads[i].code = 0;
00491 if (instance && instance->engine && instance->engine->payload_set) {
00492 instance->engine->payload_set(instance, i, 0, 0);
00493 }
00494 }
00495 }
00496
00497 void ast_rtp_codecs_payloads_default(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance)
00498 {
00499 int i;
00500
00501 for (i = 0; i < AST_RTP_MAX_PT; i++) {
00502 if (static_RTP_PT[i].code) {
00503 codecs->payloads[i].asterisk_format = static_RTP_PT[i].asterisk_format;
00504 codecs->payloads[i].code = static_RTP_PT[i].code;
00505 if (instance && instance->engine && instance->engine->payload_set) {
00506 instance->engine->payload_set(instance, i, codecs->payloads[i].asterisk_format, codecs->payloads[i].code);
00507 }
00508 }
00509 }
00510 }
00511
00512 void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
00513 {
00514 int i;
00515
00516 for (i = 0; i < AST_RTP_MAX_PT; i++) {
00517 if (src->payloads[i].code) {
00518 ast_debug(2, "Copying payload %d from %p to %p\n", i, src, dest);
00519 dest->payloads[i].asterisk_format = src->payloads[i].asterisk_format;
00520 dest->payloads[i].code = src->payloads[i].code;
00521 if (instance && instance->engine && instance->engine->payload_set) {
00522 instance->engine->payload_set(instance, i, dest->payloads[i].asterisk_format, dest->payloads[i].code);
00523 }
00524 }
00525 }
00526 }
00527
00528 void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload)
00529 {
00530 if (payload < 0 || payload >= AST_RTP_MAX_PT || !static_RTP_PT[payload].code) {
00531 return;
00532 }
00533
00534 codecs->payloads[payload].asterisk_format = static_RTP_PT[payload].asterisk_format;
00535 codecs->payloads[payload].code = static_RTP_PT[payload].code;
00536
00537 ast_debug(1, "Setting payload %d based on m type on %p\n", payload, codecs);
00538
00539 if (instance && instance->engine && instance->engine->payload_set) {
00540 instance->engine->payload_set(instance, payload, codecs->payloads[payload].asterisk_format, codecs->payloads[payload].code);
00541 }
00542 }
00543
00544 int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int pt,
00545 char *mimetype, char *mimesubtype,
00546 enum ast_rtp_options options,
00547 unsigned int sample_rate)
00548 {
00549 unsigned int i;
00550 int found = 0;
00551
00552 if (pt < 0 || pt >= AST_RTP_MAX_PT)
00553 return -1;
00554
00555 for (i = 0; i < ARRAY_LEN(ast_rtp_mime_types); ++i) {
00556 const struct ast_rtp_mime_type *t = &ast_rtp_mime_types[i];
00557
00558 if (strcasecmp(mimesubtype, t->subtype)) {
00559 continue;
00560 }
00561
00562 if (strcasecmp(mimetype, t->type)) {
00563 continue;
00564 }
00565
00566
00567
00568
00569 if (sample_rate && t->sample_rate &&
00570 (sample_rate != t->sample_rate)) {
00571 continue;
00572 }
00573
00574 found = 1;
00575 codecs->payloads[pt] = t->payload_type;
00576
00577 if ((t->payload_type.code == AST_FORMAT_G726) &&
00578 t->payload_type.asterisk_format &&
00579 (options & AST_RTP_OPT_G726_NONSTANDARD)) {
00580 codecs->payloads[pt].code = AST_FORMAT_G726_AAL2;
00581 }
00582
00583 if (instance && instance->engine && instance->engine->payload_set) {
00584 instance->engine->payload_set(instance, pt, codecs->payloads[i].asterisk_format, codecs->payloads[i].code);
00585 }
00586
00587 break;
00588 }
00589
00590 return (found ? 0 : -2);
00591 }
00592
00593 int ast_rtp_codecs_payloads_set_rtpmap_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload, char *mimetype, char *mimesubtype, enum ast_rtp_options options)
00594 {
00595 return ast_rtp_codecs_payloads_set_rtpmap_type_rate(codecs, instance, payload, mimetype, mimesubtype, options, 0);
00596 }
00597
00598 void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload)
00599 {
00600 if (payload < 0 || payload >= AST_RTP_MAX_PT) {
00601 return;
00602 }
00603
00604 ast_debug(2, "Unsetting payload %d on %p\n", payload, codecs);
00605
00606 codecs->payloads[payload].asterisk_format = 0;
00607 codecs->payloads[payload].code = 0;
00608
00609 if (instance && instance->engine && instance->engine->payload_set) {
00610 instance->engine->payload_set(instance, payload, 0, 0);
00611 }
00612 }
00613
00614 struct ast_rtp_payload_type ast_rtp_codecs_payload_lookup(struct ast_rtp_codecs *codecs, int payload)
00615 {
00616 struct ast_rtp_payload_type result = { .asterisk_format = 0, };
00617
00618 if (payload < 0 || payload >= AST_RTP_MAX_PT) {
00619 return result;
00620 }
00621
00622 result.asterisk_format = codecs->payloads[payload].asterisk_format;
00623 result.code = codecs->payloads[payload].code;
00624
00625 if (!result.code) {
00626 result = static_RTP_PT[payload];
00627 }
00628
00629 return result;
00630 }
00631
00632 void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, format_t *astformats, int *nonastformats)
00633 {
00634 int i;
00635
00636 *astformats = *nonastformats = 0;
00637
00638 for (i = 0; i < AST_RTP_MAX_PT; i++) {
00639 if (codecs->payloads[i].code) {
00640 ast_debug(1, "Incorporating payload %d on %p\n", i, codecs);
00641 }
00642 if (codecs->payloads[i].asterisk_format) {
00643 *astformats |= codecs->payloads[i].code;
00644 } else {
00645 *nonastformats |= codecs->payloads[i].code;
00646 }
00647 }
00648 }
00649
00650 int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, const int asterisk_format, const format_t code)
00651 {
00652 int i;
00653
00654 for (i = 0; i < AST_RTP_MAX_PT; i++) {
00655 if (codecs->payloads[i].asterisk_format == asterisk_format && codecs->payloads[i].code == code) {
00656 return i;
00657 }
00658 }
00659
00660 for (i = 0; i < AST_RTP_MAX_PT; i++) {
00661 if (static_RTP_PT[i].asterisk_format == asterisk_format && static_RTP_PT[i].code == code) {
00662 return i;
00663 }
00664 }
00665
00666 return -1;
00667 }
00668
00669 const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, const format_t code, enum ast_rtp_options options)
00670 {
00671 int i;
00672
00673 for (i = 0; i < ARRAY_LEN(ast_rtp_mime_types); i++) {
00674 if (ast_rtp_mime_types[i].payload_type.code == code && ast_rtp_mime_types[i].payload_type.asterisk_format == asterisk_format) {
00675 if (asterisk_format && (code == AST_FORMAT_G726_AAL2) && (options & AST_RTP_OPT_G726_NONSTANDARD)) {
00676 return "G726-32";
00677 } else {
00678 return ast_rtp_mime_types[i].subtype;
00679 }
00680 }
00681 }
00682
00683 return "";
00684 }
00685
00686 unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, format_t code)
00687 {
00688 unsigned int i;
00689
00690 for (i = 0; i < ARRAY_LEN(ast_rtp_mime_types); ++i) {
00691 if ((ast_rtp_mime_types[i].payload_type.code == code) && (ast_rtp_mime_types[i].payload_type.asterisk_format == asterisk_format)) {
00692 return ast_rtp_mime_types[i].sample_rate;
00693 }
00694 }
00695
00696 return 0;
00697 }
00698
00699 char *ast_rtp_lookup_mime_multiple2(struct ast_str *buf, const format_t capability, const int asterisk_format, enum ast_rtp_options options)
00700 {
00701 format_t format;
00702 int found = 0;
00703
00704 if (!buf) {
00705 return NULL;
00706 }
00707
00708 ast_str_append(&buf, 0, "0x%llx (", (unsigned long long) capability);
00709
00710 for (format = 1; format < AST_RTP_MAX; format <<= 1) {
00711 if (capability & format) {
00712 const char *name = ast_rtp_lookup_mime_subtype2(asterisk_format, format, options);
00713 ast_str_append(&buf, 0, "%s|", name);
00714 found = 1;
00715 }
00716 }
00717
00718 ast_str_append(&buf, 0, "%s", found ? ")" : "nothing)");
00719
00720 return ast_str_buffer(buf);
00721 }
00722
00723 void ast_rtp_codecs_packetization_set(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, struct ast_codec_pref *prefs)
00724 {
00725 codecs->pref = *prefs;
00726
00727 if (instance && instance->engine->packetization_set) {
00728 instance->engine->packetization_set(instance, &instance->codecs.pref);
00729 }
00730 }
00731
00732 int ast_rtp_instance_dtmf_begin(struct ast_rtp_instance *instance, char digit)
00733 {
00734 return instance->engine->dtmf_begin ? instance->engine->dtmf_begin(instance, digit) : -1;
00735 }
00736
00737 int ast_rtp_instance_dtmf_end(struct ast_rtp_instance *instance, char digit)
00738 {
00739 return instance->engine->dtmf_end ? instance->engine->dtmf_end(instance, digit) : -1;
00740 }
00741 int ast_rtp_instance_dtmf_end_with_duration(struct ast_rtp_instance *instance, char digit, unsigned int duration)
00742 {
00743 return instance->engine->dtmf_end_with_duration ? instance->engine->dtmf_end_with_duration(instance, digit, duration) : -1;
00744 }
00745
00746 int ast_rtp_instance_dtmf_mode_set(struct ast_rtp_instance *instance, enum ast_rtp_dtmf_mode dtmf_mode)
00747 {
00748 return (!instance->engine->dtmf_mode_set || instance->engine->dtmf_mode_set(instance, dtmf_mode)) ? -1 : 0;
00749 }
00750
00751 enum ast_rtp_dtmf_mode ast_rtp_instance_dtmf_mode_get(struct ast_rtp_instance *instance)
00752 {
00753 return instance->engine->dtmf_mode_get ? instance->engine->dtmf_mode_get(instance) : 0;
00754 }
00755
00756 void ast_rtp_instance_update_source(struct ast_rtp_instance *instance)
00757 {
00758 if (instance->engine->update_source) {
00759 instance->engine->update_source(instance);
00760 }
00761 }
00762
00763 void ast_rtp_instance_change_source(struct ast_rtp_instance *instance)
00764 {
00765 if (instance->engine->change_source) {
00766 instance->engine->change_source(instance);
00767 }
00768 }
00769
00770 int ast_rtp_instance_set_qos(struct ast_rtp_instance *instance, int tos, int cos, const char *desc)
00771 {
00772 return instance->engine->qos ? instance->engine->qos(instance, tos, cos, desc) : -1;
00773 }
00774
00775 void ast_rtp_instance_stop(struct ast_rtp_instance *instance)
00776 {
00777 if (instance->engine->stop) {
00778 instance->engine->stop(instance);
00779 }
00780 }
00781
00782 int ast_rtp_instance_fd(struct ast_rtp_instance *instance, int rtcp)
00783 {
00784 return instance->engine->fd ? instance->engine->fd(instance, rtcp) : -1;
00785 }
00786
00787 struct ast_rtp_glue *ast_rtp_instance_get_glue(const char *type)
00788 {
00789 struct ast_rtp_glue *glue = NULL;
00790
00791 AST_RWLIST_RDLOCK(&glues);
00792
00793 AST_RWLIST_TRAVERSE(&glues, glue, entry) {
00794 if (!strcasecmp(glue->type, type)) {
00795 break;
00796 }
00797 }
00798
00799 AST_RWLIST_UNLOCK(&glues);
00800
00801 return glue;
00802 }
00803
00804 static enum ast_bridge_result local_bridge_loop(struct ast_channel *c0, struct ast_channel *c1, struct ast_rtp_instance *instance0, struct ast_rtp_instance *instance1, int timeoutms, int flags, struct ast_frame **fo, struct ast_channel **rc, void *pvt0, void *pvt1)
00805 {
00806 enum ast_bridge_result res = AST_BRIDGE_FAILED;
00807 struct ast_channel *who = NULL, *other = NULL, *cs[3] = { NULL, };
00808 struct ast_frame *fr = NULL;
00809
00810
00811 if (instance0->engine->local_bridge && instance0->engine->local_bridge(instance0, instance1)) {
00812 ast_debug(1, "Failed to locally bridge %s to %s, backing out.\n", c0->name, c1->name);
00813 ast_channel_unlock(c0);
00814 ast_channel_unlock(c1);
00815 return AST_BRIDGE_FAILED_NOWARN;
00816 }
00817 if (instance1->engine->local_bridge && instance1->engine->local_bridge(instance1, instance0)) {
00818 ast_debug(1, "Failed to locally bridge %s to %s, backing out.\n", c1->name, c0->name);
00819 if (instance0->engine->local_bridge) {
00820 instance0->engine->local_bridge(instance0, NULL);
00821 }
00822 ast_channel_unlock(c0);
00823 ast_channel_unlock(c1);
00824 return AST_BRIDGE_FAILED_NOWARN;
00825 }
00826
00827 ast_channel_unlock(c0);
00828 ast_channel_unlock(c1);
00829
00830 instance0->bridged = instance1;
00831 instance1->bridged = instance0;
00832
00833 ast_poll_channel_add(c0, c1);
00834
00835
00836 cs[0] = c0;
00837 cs[1] = c1;
00838 cs[2] = NULL;
00839 for (;;) {
00840
00841 if ((c0->rawreadformat != c1->rawwriteformat) || (c1->rawreadformat != c0->rawwriteformat)) {
00842 ast_debug(1, "rtp-engine-local-bridge: Oooh, formats changed, backing out\n");
00843 res = AST_BRIDGE_FAILED_NOWARN;
00844 break;
00845 }
00846
00847 if ((c0->tech_pvt != pvt0) ||
00848 (c1->tech_pvt != pvt1) ||
00849 (c0->masq || c0->masqr || c1->masq || c1->masqr) ||
00850 (c0->monitor || c0->audiohooks || c1->monitor || c1->audiohooks) ||
00851 (!ast_framehook_list_is_empty(c0->framehooks) || !ast_framehook_list_is_empty(c1->framehooks))) {
00852 ast_debug(1, "rtp-engine-local-bridge: Oooh, something is weird, backing out\n");
00853
00854 if ((c0->masq || c0->masqr) && (fr = ast_read(c0))) {
00855 ast_frfree(fr);
00856 }
00857 if ((c1->masq || c1->masqr) && (fr = ast_read(c1))) {
00858 ast_frfree(fr);
00859 }
00860 res = AST_BRIDGE_RETRY;
00861 break;
00862 }
00863
00864 if (!(who = ast_waitfor_n(cs, 2, &timeoutms))) {
00865 if (!timeoutms) {
00866 res = AST_BRIDGE_RETRY;
00867 break;
00868 }
00869 ast_debug(2, "rtp-engine-local-bridge: Ooh, empty read...\n");
00870 if (ast_check_hangup(c0) || ast_check_hangup(c1)) {
00871 break;
00872 }
00873 continue;
00874 }
00875
00876 fr = ast_read(who);
00877 other = (who == c0) ? c1 : c0;
00878
00879 if (!fr || ((fr->frametype == AST_FRAME_DTMF_BEGIN || fr->frametype == AST_FRAME_DTMF_END) &&
00880 ((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) |
00881 ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1)))) {
00882
00883 *fo = fr;
00884 *rc = who;
00885 ast_debug(1, "rtp-engine-local-bridge: Ooh, got a %s\n", fr ? "digit" : "hangup");
00886 res = AST_BRIDGE_COMPLETE;
00887 break;
00888 } else if ((fr->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
00889 if ((fr->subclass.integer == AST_CONTROL_HOLD) ||
00890 (fr->subclass.integer == AST_CONTROL_UNHOLD) ||
00891 (fr->subclass.integer == AST_CONTROL_VIDUPDATE) ||
00892 (fr->subclass.integer == AST_CONTROL_SRCUPDATE) ||
00893 (fr->subclass.integer == AST_CONTROL_T38_PARAMETERS) ||
00894 (fr->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER)) {
00895
00896 if (fr->subclass.integer == AST_CONTROL_HOLD) {
00897 if (instance0->engine->local_bridge) {
00898 instance0->engine->local_bridge(instance0, NULL);
00899 }
00900 if (instance1->engine->local_bridge) {
00901 instance1->engine->local_bridge(instance1, NULL);
00902 }
00903 instance0->bridged = NULL;
00904 instance1->bridged = NULL;
00905 } else if (fr->subclass.integer == AST_CONTROL_UNHOLD) {
00906 if (instance0->engine->local_bridge) {
00907 instance0->engine->local_bridge(instance0, instance1);
00908 }
00909 if (instance1->engine->local_bridge) {
00910 instance1->engine->local_bridge(instance1, instance0);
00911 }
00912 instance0->bridged = instance1;
00913 instance1->bridged = instance0;
00914 }
00915
00916 if (fr->subclass.integer != AST_CONTROL_UPDATE_RTP_PEER) {
00917 ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
00918 }
00919 ast_frfree(fr);
00920 } else if (fr->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
00921 if (ast_channel_connected_line_macro(who, other, fr, other == c0, 1)) {
00922 ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
00923 }
00924 ast_frfree(fr);
00925 } else if (fr->subclass.integer == AST_CONTROL_REDIRECTING) {
00926 if (ast_channel_redirecting_macro(who, other, fr, other == c0, 1)) {
00927 ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
00928 }
00929 ast_frfree(fr);
00930 } else {
00931 *fo = fr;
00932 *rc = who;
00933 ast_debug(1, "rtp-engine-local-bridge: Got a FRAME_CONTROL (%d) frame on channel %s\n", fr->subclass.integer, who->name);
00934 res = AST_BRIDGE_COMPLETE;
00935 break;
00936 }
00937 } else {
00938 if ((fr->frametype == AST_FRAME_DTMF_BEGIN) ||
00939 (fr->frametype == AST_FRAME_DTMF_END) ||
00940 (fr->frametype == AST_FRAME_VOICE) ||
00941 (fr->frametype == AST_FRAME_VIDEO) ||
00942 (fr->frametype == AST_FRAME_IMAGE) ||
00943 (fr->frametype == AST_FRAME_HTML) ||
00944 (fr->frametype == AST_FRAME_MODEM) ||
00945 (fr->frametype == AST_FRAME_TEXT)) {
00946 ast_write(other, fr);
00947 }
00948
00949 ast_frfree(fr);
00950 }
00951
00952 cs[2] = cs[0];
00953 cs[0] = cs[1];
00954 cs[1] = cs[2];
00955 }
00956
00957
00958 if (instance0->engine->local_bridge) {
00959 instance0->engine->local_bridge(instance0, NULL);
00960 }
00961 if (instance1->engine->local_bridge) {
00962 instance1->engine->local_bridge(instance1, NULL);
00963 }
00964
00965 instance0->bridged = NULL;
00966 instance1->bridged = NULL;
00967
00968 ast_poll_channel_del(c0, c1);
00969
00970 return res;
00971 }
00972
00973 static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct ast_channel *c1, struct ast_rtp_instance *instance0, struct ast_rtp_instance *instance1,
00974 struct ast_rtp_instance *vinstance0, struct ast_rtp_instance *vinstance1, struct ast_rtp_instance *tinstance0,
00975 struct ast_rtp_instance *tinstance1, struct ast_rtp_glue *glue0, struct ast_rtp_glue *glue1, format_t codec0, format_t codec1, int timeoutms,
00976 int flags, struct ast_frame **fo, struct ast_channel **rc, void *pvt0, void *pvt1)
00977 {
00978 enum ast_bridge_result res = AST_BRIDGE_FAILED;
00979 struct ast_channel *who = NULL, *other = NULL, *cs[3] = { NULL, };
00980 format_t oldcodec0 = codec0, oldcodec1 = codec1;
00981 struct ast_sockaddr ac1 = {{0,}}, vac1 = {{0,}}, tac1 = {{0,}}, ac0 = {{0,}}, vac0 = {{0,}}, tac0 = {{0,}};
00982 struct ast_sockaddr t1 = {{0,}}, vt1 = {{0,}}, tt1 = {{0,}}, t0 = {{0,}}, vt0 = {{0,}}, tt0 = {{0,}};
00983 struct ast_frame *fr = NULL;
00984
00985
00986 if (!(glue0->update_peer(c0, instance1, vinstance1, tinstance1, codec1, 0))) {
00987 ast_rtp_instance_get_remote_address(instance1, &ac1);
00988 if (vinstance1) {
00989 ast_rtp_instance_get_remote_address(vinstance1, &vac1);
00990 }
00991 if (tinstance1) {
00992 ast_rtp_instance_get_remote_address(tinstance1, &tac1);
00993 }
00994 } else {
00995 ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name);
00996 }
00997
00998
00999 if (!(glue1->update_peer(c1, instance0, vinstance0, tinstance0, codec0, 0))) {
01000 ast_rtp_instance_get_remote_address(instance0, &ac0);
01001 if (vinstance0) {
01002 ast_rtp_instance_get_remote_address(instance0, &vac0);
01003 }
01004 if (tinstance0) {
01005 ast_rtp_instance_get_remote_address(instance0, &tac0);
01006 }
01007 } else {
01008 ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c1->name, c0->name);
01009 }
01010
01011 ast_channel_unlock(c0);
01012 ast_channel_unlock(c1);
01013
01014 instance0->bridged = instance1;
01015 instance1->bridged = instance0;
01016
01017 ast_poll_channel_add(c0, c1);
01018
01019
01020 cs[0] = c0;
01021 cs[1] = c1;
01022 cs[2] = NULL;
01023 for (;;) {
01024
01025 if ((c0->tech_pvt != pvt0) ||
01026 (c1->tech_pvt != pvt1) ||
01027 (c0->masq || c0->masqr || c1->masq || c1->masqr) ||
01028 (c0->monitor || c0->audiohooks || c1->monitor || c1->audiohooks) ||
01029 (!ast_framehook_list_is_empty(c0->framehooks) || !ast_framehook_list_is_empty(c1->framehooks))) {
01030 ast_debug(1, "Oooh, something is weird, backing out\n");
01031 res = AST_BRIDGE_RETRY;
01032 break;
01033 }
01034
01035
01036 ast_rtp_instance_get_remote_address(instance1, &t1);
01037 if (vinstance1) {
01038 ast_rtp_instance_get_remote_address(vinstance1, &vt1);
01039 }
01040 if (tinstance1) {
01041 ast_rtp_instance_get_remote_address(tinstance1, &tt1);
01042 }
01043 if (glue1->get_codec) {
01044 codec1 = glue1->get_codec(c1);
01045 }
01046
01047 ast_rtp_instance_get_remote_address(instance0, &t0);
01048 if (vinstance0) {
01049 ast_rtp_instance_get_remote_address(vinstance0, &vt0);
01050 }
01051 if (tinstance0) {
01052 ast_rtp_instance_get_remote_address(tinstance0, &tt0);
01053 }
01054 if (glue0->get_codec) {
01055 codec0 = glue0->get_codec(c0);
01056 }
01057
01058 if ((ast_sockaddr_cmp(&t1, &ac1)) ||
01059 (vinstance1 && ast_sockaddr_cmp(&vt1, &vac1)) ||
01060 (tinstance1 && ast_sockaddr_cmp(&tt1, &tac1)) ||
01061 (codec1 != oldcodec1)) {
01062 ast_debug(1, "Oooh, '%s' changed end address to %s (format %s)\n",
01063 c1->name, ast_sockaddr_stringify(&t1),
01064 ast_getformatname(codec1));
01065 ast_debug(1, "Oooh, '%s' changed end vaddress to %s (format %s)\n",
01066 c1->name, ast_sockaddr_stringify(&vt1),
01067 ast_getformatname(codec1));
01068 ast_debug(1, "Oooh, '%s' changed end taddress to %s (format %s)\n",
01069 c1->name, ast_sockaddr_stringify(&tt1),
01070 ast_getformatname(codec1));
01071 ast_debug(1, "Oooh, '%s' was %s/(format %s)\n",
01072 c1->name, ast_sockaddr_stringify(&ac1),
01073 ast_getformatname(oldcodec1));
01074 ast_debug(1, "Oooh, '%s' was %s/(format %s)\n",
01075 c1->name, ast_sockaddr_stringify(&vac1),
01076 ast_getformatname(oldcodec1));
01077 ast_debug(1, "Oooh, '%s' was %s/(format %s)\n",
01078 c1->name, ast_sockaddr_stringify(&tac1),
01079 ast_getformatname(oldcodec1));
01080 if (glue0->update_peer(c0,
01081 ast_sockaddr_isnull(&t1) ? NULL : instance1,
01082 ast_sockaddr_isnull(&vt1) ? NULL : vinstance1,
01083 ast_sockaddr_isnull(&tt1) ? NULL : tinstance1,
01084 codec1, 0)) {
01085 ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c0->name, c1->name);
01086 }
01087 ast_sockaddr_copy(&ac1, &t1);
01088 ast_sockaddr_copy(&vac1, &vt1);
01089 ast_sockaddr_copy(&tac1, &tt1);
01090 oldcodec1 = codec1;
01091 }
01092 if ((ast_sockaddr_cmp(&t0, &ac0)) ||
01093 (vinstance0 && ast_sockaddr_cmp(&vt0, &vac0)) ||
01094 (tinstance0 && ast_sockaddr_cmp(&tt0, &tac0)) ||
01095 (codec0 != oldcodec0)) {
01096 ast_debug(1, "Oooh, '%s' changed end address to %s (format %s)\n",
01097 c0->name, ast_sockaddr_stringify(&t0),
01098 ast_getformatname(codec0));
01099 ast_debug(1, "Oooh, '%s' was %s/(format %s)\n",
01100 c0->name, ast_sockaddr_stringify(&ac0),
01101 ast_getformatname(oldcodec0));
01102 if (glue1->update_peer(c1, t0.len ? instance0 : NULL,
01103 vt0.len ? vinstance0 : NULL,
01104 tt0.len ? tinstance0 : NULL,
01105 codec0, 0)) {
01106 ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c1->name, c0->name);
01107 }
01108 ast_sockaddr_copy(&ac0, &t0);
01109 ast_sockaddr_copy(&vac0, &vt0);
01110 ast_sockaddr_copy(&tac0, &tt0);
01111 oldcodec0 = codec0;
01112 }
01113
01114
01115 if (!(who = ast_waitfor_n(cs, 2, &timeoutms))) {
01116 if (!timeoutms) {
01117 res = AST_BRIDGE_RETRY;
01118 break;
01119 }
01120 ast_debug(1, "Ooh, empty read...\n");
01121 if (ast_check_hangup(c0) || ast_check_hangup(c1)) {
01122 break;
01123 }
01124 continue;
01125 }
01126 fr = ast_read(who);
01127 other = (who == c0) ? c1 : c0;
01128 if (!fr || ((fr->frametype == AST_FRAME_DTMF_BEGIN || fr->frametype == AST_FRAME_DTMF_END) &&
01129 (((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) ||
01130 ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) {
01131
01132 *fo = fr;
01133 *rc = who;
01134 ast_debug(1, "Oooh, got a %s\n", fr ? "digit" : "hangup");
01135 res = AST_BRIDGE_COMPLETE;
01136 break;
01137 } else if ((fr->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
01138 if ((fr->subclass.integer == AST_CONTROL_HOLD) ||
01139 (fr->subclass.integer == AST_CONTROL_UNHOLD) ||
01140 (fr->subclass.integer == AST_CONTROL_VIDUPDATE) ||
01141 (fr->subclass.integer == AST_CONTROL_SRCUPDATE) ||
01142 (fr->subclass.integer == AST_CONTROL_T38_PARAMETERS) ||
01143 (fr->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER)) {
01144 if (fr->subclass.integer == AST_CONTROL_HOLD) {
01145
01146 if (who == c0) {
01147 glue1->update_peer(c1, NULL, NULL, NULL, 0, 0);
01148 } else {
01149 glue0->update_peer(c0, NULL, NULL, NULL, 0, 0);
01150 }
01151 } else if (fr->subclass.integer == AST_CONTROL_UNHOLD ||
01152 fr->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER) {
01153
01154
01155 if (who == c0) {
01156 glue1->update_peer(c1, instance0, vinstance0, tinstance0, codec0, 0);
01157 } else {
01158 glue0->update_peer(c0, instance1, vinstance1, tinstance1, codec1, 0);
01159 }
01160 }
01161
01162 ast_rtp_instance_get_remote_address(instance0, &t0);
01163 ast_sockaddr_copy(&ac0, &t0);
01164 ast_rtp_instance_get_remote_address(instance1, &t1);
01165 ast_sockaddr_copy(&ac1, &t1);
01166
01167 if (glue0->get_codec && c0->tech_pvt) {
01168 oldcodec0 = codec0 = glue0->get_codec(c0);
01169 }
01170 if (glue1->get_codec && c1->tech_pvt) {
01171 oldcodec1 = codec1 = glue1->get_codec(c1);
01172 }
01173
01174 if (fr->subclass.integer != AST_CONTROL_UPDATE_RTP_PEER) {
01175 ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
01176 }
01177 ast_frfree(fr);
01178 } else if (fr->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
01179 if (ast_channel_connected_line_macro(who, other, fr, other == c0, 1)) {
01180 ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
01181 }
01182 ast_frfree(fr);
01183 } else if (fr->subclass.integer == AST_CONTROL_REDIRECTING) {
01184 if (ast_channel_redirecting_macro(who, other, fr, other == c0, 1)) {
01185 ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
01186 }
01187 ast_frfree(fr);
01188 } else {
01189 *fo = fr;
01190 *rc = who;
01191 ast_debug(1, "Got a FRAME_CONTROL (%d) frame on channel %s\n", fr->subclass.integer, who->name);
01192 return AST_BRIDGE_COMPLETE;
01193 }
01194 } else {
01195 if ((fr->frametype == AST_FRAME_DTMF_BEGIN) ||
01196 (fr->frametype == AST_FRAME_DTMF_END) ||
01197 (fr->frametype == AST_FRAME_VOICE) ||
01198 (fr->frametype == AST_FRAME_VIDEO) ||
01199 (fr->frametype == AST_FRAME_IMAGE) ||
01200 (fr->frametype == AST_FRAME_HTML) ||
01201 (fr->frametype == AST_FRAME_MODEM) ||
01202 (fr->frametype == AST_FRAME_TEXT)) {
01203 ast_write(other, fr);
01204 }
01205 ast_frfree(fr);
01206 }
01207
01208 cs[2] = cs[0];
01209 cs[0] = cs[1];
01210 cs[1] = cs[2];
01211 }
01212
01213 if (ast_test_flag(c0, AST_FLAG_ZOMBIE)) {
01214 ast_debug(1, "Channel '%s' Zombie cleardown from bridge\n", c0->name);
01215 } else if (c0->tech_pvt != pvt0) {
01216 ast_debug(1, "Channel c0->'%s' pvt changed, in bridge with c1->'%s'\n", c0->name, c1->name);
01217 } else if (glue0 != ast_rtp_instance_get_glue(c0->tech->type)) {
01218 ast_debug(1, "Channel c0->'%s' technology changed, in bridge with c1->'%s'\n", c0->name, c1->name);
01219 } else if (glue0->update_peer(c0, NULL, NULL, NULL, 0, 0)) {
01220 ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
01221 }
01222 if (ast_test_flag(c1, AST_FLAG_ZOMBIE)) {
01223 ast_debug(1, "Channel '%s' Zombie cleardown from bridge\n", c1->name);
01224 } else if (c1->tech_pvt != pvt1) {
01225 ast_debug(1, "Channel c1->'%s' pvt changed, in bridge with c0->'%s'\n", c1->name, c0->name);
01226 } else if (glue1 != ast_rtp_instance_get_glue(c1->tech->type)) {
01227 ast_debug(1, "Channel c1->'%s' technology changed, in bridge with c0->'%s'\n", c1->name, c0->name);
01228 } else if (glue1->update_peer(c1, NULL, NULL, NULL, 0, 0)) {
01229 ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
01230 }
01231
01232 instance0->bridged = NULL;
01233 instance1->bridged = NULL;
01234
01235 ast_poll_channel_del(c0, c1);
01236
01237 return res;
01238 }
01239
01240
01241
01242
01243 static void unref_instance_cond(struct ast_rtp_instance **instance)
01244 {
01245 if (*instance) {
01246 ao2_ref(*instance, -1);
01247 *instance = NULL;
01248 }
01249 }
01250
01251 enum ast_bridge_result ast_rtp_instance_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
01252 {
01253 struct ast_rtp_instance *instance0 = NULL, *instance1 = NULL,
01254 *vinstance0 = NULL, *vinstance1 = NULL,
01255 *tinstance0 = NULL, *tinstance1 = NULL;
01256 struct ast_rtp_glue *glue0, *glue1;
01257 struct ast_sockaddr addr1 = { {0, }, }, addr2 = { {0, }, };
01258 enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID, video_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
01259 enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID, video_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
01260 enum ast_bridge_result res = AST_BRIDGE_FAILED;
01261 enum ast_rtp_dtmf_mode dmode;
01262 format_t codec0 = 0, codec1 = 0;
01263 int unlock_chans = 1;
01264
01265
01266 ast_channel_lock(c0);
01267 while (ast_channel_trylock(c1)) {
01268 ast_channel_unlock(c0);
01269 usleep(1);
01270 ast_channel_lock(c0);
01271 }
01272
01273
01274 if (ast_check_hangup(c0) || ast_check_hangup(c1)) {
01275 ast_log(LOG_WARNING, "Got hangup while attempting to bridge '%s' and '%s'\n", c0->name, c1->name);
01276 goto done;
01277 }
01278
01279
01280 if (!(glue0 = ast_rtp_instance_get_glue(c0->tech->type)) || !(glue1 = ast_rtp_instance_get_glue(c1->tech->type))) {
01281 ast_debug(1, "Can't find native functions for channel '%s'\n", glue0 ? c1->name : c0->name);
01282 goto done;
01283 }
01284
01285 audio_glue0_res = glue0->get_rtp_info(c0, &instance0);
01286 video_glue0_res = glue0->get_vrtp_info ? glue0->get_vrtp_info(c0, &vinstance0) : AST_RTP_GLUE_RESULT_FORBID;
01287
01288 audio_glue1_res = glue1->get_rtp_info(c1, &instance1);
01289 video_glue1_res = glue1->get_vrtp_info ? glue1->get_vrtp_info(c1, &vinstance1) : AST_RTP_GLUE_RESULT_FORBID;
01290
01291
01292 if (video_glue0_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue0_res != AST_RTP_GLUE_RESULT_REMOTE)) {
01293 audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
01294 }
01295 if (video_glue1_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE)) {
01296 audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
01297 }
01298
01299
01300 if (audio_glue0_res == AST_RTP_GLUE_RESULT_FORBID || audio_glue1_res == AST_RTP_GLUE_RESULT_FORBID) {
01301 res = AST_BRIDGE_FAILED_NOWARN;
01302 goto done;
01303 }
01304
01305
01306
01307 ast_rtp_instance_get_remote_address(instance0, &addr1);
01308 ast_rtp_instance_get_remote_address(instance1, &addr2);
01309
01310 if (addr1.ss.ss_family != addr2.ss.ss_family ||
01311 (ast_sockaddr_is_ipv4_mapped(&addr1) != ast_sockaddr_is_ipv4_mapped(&addr2))) {
01312 audio_glue0_res = AST_RTP_GLUE_RESULT_LOCAL;
01313 audio_glue1_res = AST_RTP_GLUE_RESULT_LOCAL;
01314 }
01315
01316
01317 dmode = ast_rtp_instance_dtmf_mode_get(instance0);
01318 if ((flags & AST_BRIDGE_DTMF_CHANNEL_0) && dmode) {
01319 res = AST_BRIDGE_FAILED_NOWARN;
01320 goto done;
01321 }
01322 dmode = ast_rtp_instance_dtmf_mode_get(instance1);
01323 if ((flags & AST_BRIDGE_DTMF_CHANNEL_1) && dmode) {
01324 res = AST_BRIDGE_FAILED_NOWARN;
01325 goto done;
01326 }
01327
01328
01329 if ((audio_glue0_res == AST_RTP_GLUE_RESULT_LOCAL || audio_glue1_res == AST_RTP_GLUE_RESULT_LOCAL) && ((instance0->engine->local_bridge != instance1->engine->local_bridge) || (instance0->engine->dtmf_compatible && !instance0->engine->dtmf_compatible(c0, instance0, c1, instance1)))) {
01330 res = AST_BRIDGE_FAILED_NOWARN;
01331 goto done;
01332 }
01333
01334
01335 codec0 = glue0->get_codec ? glue0->get_codec(c0) : 0;
01336 codec1 = glue1->get_codec ? glue1->get_codec(c1) : 0;
01337 if (codec0 && codec1 && !(codec0 & codec1)) {
01338 ast_debug(1, "Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP.\n", ast_getformatname(codec0), ast_getformatname(codec1));
01339 res = AST_BRIDGE_FAILED_NOWARN;
01340 goto done;
01341 }
01342
01343 instance0->glue = glue0;
01344 instance1->glue = glue1;
01345 instance0->chan = c0;
01346 instance1->chan = c1;
01347
01348
01349 if (audio_glue0_res == AST_RTP_GLUE_RESULT_LOCAL || audio_glue1_res == AST_RTP_GLUE_RESULT_LOCAL) {
01350 ast_verb(3, "Locally bridging %s and %s\n", c0->name, c1->name);
01351 res = local_bridge_loop(c0, c1, instance0, instance1, timeoutms, flags, fo, rc, c0->tech_pvt, c1->tech_pvt);
01352 } else {
01353 ast_verb(3, "Remotely bridging %s and %s\n", c0->name, c1->name);
01354 res = remote_bridge_loop(c0, c1, instance0, instance1, vinstance0, vinstance1,
01355 tinstance0, tinstance1, glue0, glue1, codec0, codec1, timeoutms, flags,
01356 fo, rc, c0->tech_pvt, c1->tech_pvt);
01357 }
01358
01359 instance0->glue = NULL;
01360 instance1->glue = NULL;
01361 instance0->chan = NULL;
01362 instance1->chan = NULL;
01363
01364 unlock_chans = 0;
01365
01366 done:
01367 if (unlock_chans) {
01368 ast_channel_unlock(c0);
01369 ast_channel_unlock(c1);
01370 }
01371
01372 unref_instance_cond(&instance0);
01373 unref_instance_cond(&instance1);
01374 unref_instance_cond(&vinstance0);
01375 unref_instance_cond(&vinstance1);
01376 unref_instance_cond(&tinstance0);
01377 unref_instance_cond(&tinstance1);
01378
01379 return res;
01380 }
01381
01382 struct ast_rtp_instance *ast_rtp_instance_get_bridged(struct ast_rtp_instance *instance)
01383 {
01384 return instance->bridged;
01385 }
01386
01387 void ast_rtp_instance_early_bridge_make_compatible(struct ast_channel *c0, struct ast_channel *c1)
01388 {
01389 struct ast_rtp_instance *instance0 = NULL, *instance1 = NULL,
01390 *vinstance0 = NULL, *vinstance1 = NULL,
01391 *tinstance0 = NULL, *tinstance1 = NULL;
01392 struct ast_rtp_glue *glue0, *glue1;
01393 enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID, video_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
01394 enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID, video_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
01395 format_t codec0 = 0, codec1 = 0;
01396 int res = 0;
01397
01398
01399 ast_channel_lock(c0);
01400 while (ast_channel_trylock(c1)) {
01401 ast_channel_unlock(c0);
01402 usleep(1);
01403 ast_channel_lock(c0);
01404 }
01405
01406
01407 if (!(glue0 = ast_rtp_instance_get_glue(c0->tech->type)) || !(glue1 = ast_rtp_instance_get_glue(c1->tech->type))) {
01408 ast_debug(1, "Can't find native functions for channel '%s'\n", glue0 ? c1->name : c0->name);
01409 goto done;
01410 }
01411
01412 audio_glue0_res = glue0->get_rtp_info(c0, &instance0);
01413 video_glue0_res = glue0->get_vrtp_info ? glue0->get_vrtp_info(c0, &vinstance0) : AST_RTP_GLUE_RESULT_FORBID;
01414
01415 audio_glue1_res = glue1->get_rtp_info(c1, &instance1);
01416 video_glue1_res = glue1->get_vrtp_info ? glue1->get_vrtp_info(c1, &vinstance1) : AST_RTP_GLUE_RESULT_FORBID;
01417
01418
01419 if (video_glue0_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue0_res != AST_RTP_GLUE_RESULT_REMOTE)) {
01420 audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
01421 }
01422 if (video_glue1_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE)) {
01423 audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
01424 }
01425 if (audio_glue0_res == AST_RTP_GLUE_RESULT_REMOTE && (video_glue0_res == AST_RTP_GLUE_RESULT_FORBID || video_glue0_res == AST_RTP_GLUE_RESULT_REMOTE) && glue0->get_codec) {
01426 codec0 = glue0->get_codec(c0);
01427 }
01428 if (audio_glue1_res == AST_RTP_GLUE_RESULT_REMOTE && (video_glue1_res == AST_RTP_GLUE_RESULT_FORBID || video_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) && glue1->get_codec) {
01429 codec1 = glue1->get_codec(c1);
01430 }
01431
01432
01433 if (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE) {
01434 goto done;
01435 }
01436
01437
01438 if (!(codec0 & codec1)) {
01439 goto done;
01440 }
01441
01442 ast_rtp_codecs_payloads_copy(&instance0->codecs, &instance1->codecs, instance1);
01443
01444 if (vinstance0 && vinstance1) {
01445 ast_rtp_codecs_payloads_copy(&vinstance0->codecs, &vinstance1->codecs, vinstance1);
01446 }
01447 if (tinstance0 && tinstance1) {
01448 ast_rtp_codecs_payloads_copy(&tinstance0->codecs, &tinstance1->codecs, tinstance1);
01449 }
01450
01451 if (glue0->update_peer(c0, instance1, vinstance1, tinstance1, codec1, 0)) {
01452 ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", c0->name, c1 ? c1->name : "<unspecified>");
01453 }
01454
01455 res = 0;
01456
01457 done:
01458 ast_channel_unlock(c0);
01459 ast_channel_unlock(c1);
01460
01461 unref_instance_cond(&instance0);
01462 unref_instance_cond(&instance1);
01463 unref_instance_cond(&vinstance0);
01464 unref_instance_cond(&vinstance1);
01465 unref_instance_cond(&tinstance0);
01466 unref_instance_cond(&tinstance1);
01467
01468 if (!res) {
01469 ast_debug(1, "Seeded SDP of '%s' with that of '%s'\n", c0->name, c1 ? c1->name : "<unspecified>");
01470 }
01471 }
01472
01473 int ast_rtp_instance_early_bridge(struct ast_channel *c0, struct ast_channel *c1)
01474 {
01475 struct ast_rtp_instance *instance0 = NULL, *instance1 = NULL,
01476 *vinstance0 = NULL, *vinstance1 = NULL,
01477 *tinstance0 = NULL, *tinstance1 = NULL;
01478 struct ast_rtp_glue *glue0, *glue1;
01479 enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID, video_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
01480 enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID, video_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
01481 format_t codec0 = 0, codec1 = 0;
01482 int res = 0;
01483
01484
01485 if (!c1) {
01486 return -1;
01487 }
01488
01489
01490 ast_channel_lock(c0);
01491 while (ast_channel_trylock(c1)) {
01492 ast_channel_unlock(c0);
01493 usleep(1);
01494 ast_channel_lock(c0);
01495 }
01496
01497
01498 if (!(glue0 = ast_rtp_instance_get_glue(c0->tech->type)) || !(glue1 = ast_rtp_instance_get_glue(c1->tech->type))) {
01499 ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", glue0 ? c1->name : c0->name);
01500 goto done;
01501 }
01502
01503 audio_glue0_res = glue0->get_rtp_info(c0, &instance0);
01504 video_glue0_res = glue0->get_vrtp_info ? glue0->get_vrtp_info(c0, &vinstance0) : AST_RTP_GLUE_RESULT_FORBID;
01505
01506 audio_glue1_res = glue1->get_rtp_info(c1, &instance1);
01507 video_glue1_res = glue1->get_vrtp_info ? glue1->get_vrtp_info(c1, &vinstance1) : AST_RTP_GLUE_RESULT_FORBID;
01508
01509
01510 if (video_glue0_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue0_res != AST_RTP_GLUE_RESULT_REMOTE)) {
01511 audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
01512 }
01513 if (video_glue1_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE)) {
01514 audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
01515 }
01516 if (audio_glue0_res == AST_RTP_GLUE_RESULT_REMOTE && (video_glue0_res == AST_RTP_GLUE_RESULT_FORBID || video_glue0_res == AST_RTP_GLUE_RESULT_REMOTE) && glue0->get_codec(c0)) {
01517 codec0 = glue0->get_codec(c0);
01518 }
01519 if (audio_glue1_res == AST_RTP_GLUE_RESULT_REMOTE && (video_glue1_res == AST_RTP_GLUE_RESULT_FORBID || video_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) && glue1->get_codec(c1)) {
01520 codec1 = glue1->get_codec(c1);
01521 }
01522
01523
01524 if (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE) {
01525 goto done;
01526 }
01527
01528
01529 if (!(codec0 & codec1)) {
01530 goto done;
01531 }
01532
01533
01534 if (glue0->update_peer(c0, instance1, vinstance1, tinstance1, codec1, 0)) {
01535 ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", c0->name, c1 ? c1->name : "<unspecified>");
01536 }
01537
01538 res = 0;
01539
01540 done:
01541 ast_channel_unlock(c0);
01542 ast_channel_unlock(c1);
01543
01544 unref_instance_cond(&instance0);
01545 unref_instance_cond(&instance1);
01546 unref_instance_cond(&vinstance0);
01547 unref_instance_cond(&vinstance1);
01548 unref_instance_cond(&tinstance0);
01549 unref_instance_cond(&tinstance1);
01550
01551 if (!res) {
01552 ast_debug(1, "Setting early bridge SDP of '%s' with that of '%s'\n", c0->name, c1 ? c1->name : "<unspecified>");
01553 }
01554
01555 return res;
01556 }
01557
01558 int ast_rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations)
01559 {
01560 return instance->engine->red_init ? instance->engine->red_init(instance, buffer_time, payloads, generations) : -1;
01561 }
01562
01563 int ast_rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame)
01564 {
01565 return instance->engine->red_buffer ? instance->engine->red_buffer(instance, frame) : -1;
01566 }
01567
01568 int ast_rtp_instance_get_stats(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat)
01569 {
01570 return instance->engine->get_stat ? instance->engine->get_stat(instance, stats, stat) : -1;
01571 }
01572
01573 char *ast_rtp_instance_get_quality(struct ast_rtp_instance *instance, enum ast_rtp_instance_stat_field field, char *buf, size_t size)
01574 {
01575 struct ast_rtp_instance_stats stats = { 0, };
01576 enum ast_rtp_instance_stat stat;
01577
01578
01579 if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY) {
01580 stat = AST_RTP_INSTANCE_STAT_ALL;
01581 } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER) {
01582 stat = AST_RTP_INSTANCE_STAT_COMBINED_JITTER;
01583 } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS) {
01584 stat = AST_RTP_INSTANCE_STAT_COMBINED_LOSS;
01585 } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT) {
01586 stat = AST_RTP_INSTANCE_STAT_COMBINED_RTT;
01587 } else {
01588 return NULL;
01589 }
01590
01591
01592 if (ast_rtp_instance_get_stats(instance, &stats, stat)) {
01593 return NULL;
01594 }
01595
01596
01597 if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY) {
01598 snprintf(buf, size, "ssrc=%i;themssrc=%u;lp=%u;rxjitter=%f;rxcount=%u;txjitter=%f;txcount=%u;rlp=%u;rtt=%f",
01599 stats.local_ssrc, stats.remote_ssrc, stats.rxploss, stats.txjitter, stats.rxcount, stats.rxjitter, stats.txcount, stats.txploss, stats.rtt);
01600 } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER) {
01601 snprintf(buf, size, "minrxjitter=%f;maxrxjitter=%f;avgrxjitter=%f;stdevrxjitter=%f;reported_minjitter=%f;reported_maxjitter=%f;reported_avgjitter=%f;reported_stdevjitter=%f;",
01602 stats.local_minjitter, stats.local_maxjitter, stats.local_normdevjitter, sqrt(stats.local_stdevjitter), stats.remote_minjitter, stats.remote_maxjitter, stats.remote_normdevjitter, sqrt(stats.remote_stdevjitter));
01603 } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS) {
01604 snprintf(buf, size, "minrxlost=%f;maxrxlost=%f;avgrxlost=%f;stdevrxlost=%f;reported_minlost=%f;reported_maxlost=%f;reported_avglost=%f;reported_stdevlost=%f;",
01605 stats.local_minrxploss, stats.local_maxrxploss, stats.local_normdevrxploss, sqrt(stats.local_stdevrxploss), stats.remote_minrxploss, stats.remote_maxrxploss, stats.remote_normdevrxploss, sqrt(stats.remote_stdevrxploss));
01606 } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT) {
01607 snprintf(buf, size, "minrtt=%f;maxrtt=%f;avgrtt=%f;stdevrtt=%f;", stats.minrtt, stats.maxrtt, stats.normdevrtt, stats.stdevrtt);
01608 }
01609
01610 return buf;
01611 }
01612
01613 void ast_rtp_instance_set_stats_vars(struct ast_channel *chan, struct ast_rtp_instance *instance)
01614 {
01615 char quality_buf[AST_MAX_USER_FIELD], *quality;
01616 struct ast_channel *bridge = ast_bridged_channel(chan);
01617
01618 if ((quality = ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
01619 pbx_builtin_setvar_helper(chan, "RTPAUDIOQOS", quality);
01620 if (bridge) {
01621 pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSBRIDGED", quality);
01622 }
01623 }
01624
01625 if ((quality = ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER, quality_buf, sizeof(quality_buf)))) {
01626 pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSJITTER", quality);
01627 if (bridge) {
01628 pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSJITTERBRIDGED", quality);
01629 }
01630 }
01631
01632 if ((quality = ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS, quality_buf, sizeof(quality_buf)))) {
01633 pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSLOSS", quality);
01634 if (bridge) {
01635 pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSLOSSBRIDGED", quality);
01636 }
01637 }
01638
01639 if ((quality = ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT, quality_buf, sizeof(quality_buf)))) {
01640 pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSRTT", quality);
01641 if (bridge) {
01642 pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSRTTBRIDGED", quality);
01643 }
01644 }
01645 }
01646
01647 int ast_rtp_instance_set_read_format(struct ast_rtp_instance *instance, format_t format)
01648 {
01649 return instance->engine->set_read_format ? instance->engine->set_read_format(instance, format) : -1;
01650 }
01651
01652 int ast_rtp_instance_set_write_format(struct ast_rtp_instance *instance, format_t format)
01653 {
01654 return instance->engine->set_write_format ? instance->engine->set_write_format(instance, format) : -1;
01655 }
01656
01657 int ast_rtp_instance_make_compatible(struct ast_channel *chan, struct ast_rtp_instance *instance, struct ast_channel *peer)
01658 {
01659 struct ast_rtp_glue *glue;
01660 struct ast_rtp_instance *peer_instance = NULL;
01661 int res = -1;
01662
01663 if (!instance->engine->make_compatible) {
01664 return -1;
01665 }
01666
01667 ast_channel_lock(peer);
01668
01669 if (!(glue = ast_rtp_instance_get_glue(peer->tech->type))) {
01670 ast_channel_unlock(peer);
01671 return -1;
01672 }
01673
01674 glue->get_rtp_info(peer, &peer_instance);
01675
01676 if (!peer_instance || peer_instance->engine != instance->engine) {
01677 ast_channel_unlock(peer);
01678 ao2_ref(peer_instance, -1);
01679 peer_instance = NULL;
01680 return -1;
01681 }
01682
01683 res = instance->engine->make_compatible(chan, instance, peer, peer_instance);
01684
01685 ast_channel_unlock(peer);
01686
01687 ao2_ref(peer_instance, -1);
01688 peer_instance = NULL;
01689
01690 return res;
01691 }
01692
01693 format_t ast_rtp_instance_available_formats(struct ast_rtp_instance *instance, format_t to_endpoint, format_t to_asterisk)
01694 {
01695 format_t formats;
01696
01697 if (instance->engine->available_formats && (formats = instance->engine->available_formats(instance, to_endpoint, to_asterisk))) {
01698 return formats;
01699 }
01700
01701 return ast_translate_available_formats(to_endpoint, to_asterisk);
01702 }
01703
01704 int ast_rtp_instance_activate(struct ast_rtp_instance *instance)
01705 {
01706 return instance->engine->activate ? instance->engine->activate(instance) : 0;
01707 }
01708
01709 void ast_rtp_instance_stun_request(struct ast_rtp_instance *instance,
01710 struct ast_sockaddr *suggestion,
01711 const char *username)
01712 {
01713 if (instance->engine->stun_request) {
01714 instance->engine->stun_request(instance, suggestion, username);
01715 }
01716 }
01717
01718 void ast_rtp_instance_set_timeout(struct ast_rtp_instance *instance, int timeout)
01719 {
01720 instance->timeout = timeout;
01721 }
01722
01723 void ast_rtp_instance_set_hold_timeout(struct ast_rtp_instance *instance, int timeout)
01724 {
01725 instance->holdtimeout = timeout;
01726 }
01727
01728 void ast_rtp_instance_set_keepalive(struct ast_rtp_instance *instance, int interval)
01729 {
01730 instance->keepalive = interval;
01731 }
01732
01733 int ast_rtp_instance_get_timeout(struct ast_rtp_instance *instance)
01734 {
01735 return instance->timeout;
01736 }
01737
01738 int ast_rtp_instance_get_hold_timeout(struct ast_rtp_instance *instance)
01739 {
01740 return instance->holdtimeout;
01741 }
01742
01743 int ast_rtp_instance_get_keepalive(struct ast_rtp_instance *instance)
01744 {
01745 return instance->keepalive;
01746 }
01747
01748 struct ast_rtp_engine *ast_rtp_instance_get_engine(struct ast_rtp_instance *instance)
01749 {
01750 return instance->engine;
01751 }
01752
01753 struct ast_rtp_glue *ast_rtp_instance_get_active_glue(struct ast_rtp_instance *instance)
01754 {
01755 return instance->glue;
01756 }
01757
01758 struct ast_channel *ast_rtp_instance_get_chan(struct ast_rtp_instance *instance)
01759 {
01760 return instance->chan;
01761 }
01762
01763 int ast_rtp_engine_register_srtp(struct ast_srtp_res *srtp_res, struct ast_srtp_policy_res *policy_res)
01764 {
01765 if (res_srtp || res_srtp_policy) {
01766 return -1;
01767 }
01768 if (!srtp_res || !policy_res) {
01769 return -1;
01770 }
01771
01772 res_srtp = srtp_res;
01773 res_srtp_policy = policy_res;
01774
01775 return 0;
01776 }
01777
01778 void ast_rtp_engine_unregister_srtp(void)
01779 {
01780 res_srtp = NULL;
01781 res_srtp_policy = NULL;
01782 }
01783
01784 int ast_rtp_engine_srtp_is_registered(void)
01785 {
01786 return res_srtp && res_srtp_policy;
01787 }
01788
01789 int ast_rtp_instance_add_srtp_policy(struct ast_rtp_instance *instance, struct ast_srtp_policy *policy)
01790 {
01791 if (!res_srtp) {
01792 return -1;
01793 }
01794
01795 if (!instance->srtp) {
01796 return res_srtp->create(&instance->srtp, instance, policy);
01797 } else {
01798 return res_srtp->add_stream(instance->srtp, policy);
01799 }
01800 }
01801
01802 struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance)
01803 {
01804 return instance->srtp;
01805 }
01806
01807 int ast_rtp_instance_sendcng(struct ast_rtp_instance *instance, int level)
01808 {
01809 if (instance->engine->sendcng) {
01810 return instance->engine->sendcng(instance, level);
01811 }
01812
01813 return -1;
01814 }