diff options
Diffstat (limited to 'main/channel.c')
-rw-r--r-- | main/channel.c | 439 |
1 files changed, 303 insertions, 136 deletions
diff --git a/main/channel.c b/main/channel.c index 0cabf2d7e..796dc8b01 100644 --- a/main/channel.c +++ b/main/channel.c @@ -372,12 +372,12 @@ int ast_channel_data_add_structure(struct ast_data *tree, } } - ast_data_add_codecs(tree, "oldwriteformat", chan->oldwriteformat); + ast_data_add_codec(tree, "oldwriteformat", &chan->oldwriteformat); + ast_data_add_codec(tree, "readformat", &chan->readformat); + ast_data_add_codec(tree, "writeformat", &chan->writeformat); + ast_data_add_codec(tree, "rawreadformat", &chan->rawreadformat); + ast_data_add_codec(tree, "rawwriteformat", &chan->rawwriteformat); ast_data_add_codecs(tree, "nativeformats", chan->nativeformats); - ast_data_add_codecs(tree, "readformat", chan->readformat); - ast_data_add_codecs(tree, "writeformat", chan->writeformat); - ast_data_add_codecs(tree, "rawreadformat", chan->rawreadformat); - ast_data_add_codecs(tree, "rawwriteformat", chan->rawwriteformat); /* state */ enum_node = ast_data_add_node(tree, "state"); @@ -593,7 +593,7 @@ static char *handle_cli_core_show_channeltype(struct ast_cli_entry *e, int cmd, (cl->tech->devicestate) ? "yes" : "no", (cl->tech->indicate) ? "yes" : "no", (cl->tech->transfer) ? "yes" : "no", - ast_getformatname_multiple(buf, sizeof(buf), (cl->tech->capabilities) ? cl->tech->capabilities : -1), + ast_getformatname_multiple(buf, sizeof(buf), cl->tech->capabilities), (cl->tech->send_digit_begin) ? "yes" : "no", (cl->tech->send_digit_end) ? "yes" : "no", (cl->tech->send_html) ? "yes" : "no", @@ -989,12 +989,11 @@ char *ast_transfercapability2str(int transfercapability) } /*! \brief Pick the best audio codec */ -format_t ast_best_codec(format_t fmts) +struct ast_format *ast_best_codec(struct ast_format_cap *cap, struct ast_format *result) { /* This just our opinion, expressed in code. We are asked to choose the best codec to use, given no information */ - int x; - static const format_t prefs[] = + static const enum ast_format_id prefs[] = { /*! Okay, ulaw is used by all telephony equipment, so start with it */ AST_FORMAT_ULAW, @@ -1032,19 +1031,19 @@ format_t ast_best_codec(format_t fmts) AST_FORMAT_G723_1, }; char buf[512]; + int x; - /* Strip out video */ - fmts &= AST_FORMAT_AUDIO_MASK; - /* Find the first preferred codec in the format given */ for (x = 0; x < ARRAY_LEN(prefs); x++) { - if (fmts & prefs[x]) - return prefs[x]; + if (ast_format_cap_iscompatible(cap, ast_format_set(result, prefs[x], 0))) { + return result; + } } - ast_log(LOG_WARNING, "Don't know any of %s formats\n", ast_getformatname_multiple(buf, sizeof(buf), fmts)); + ast_format_clear(result); + ast_log(LOG_WARNING, "Don't know any of %s formats\n", ast_getformatname_multiple(buf, sizeof(buf), cap)); - return 0; + return NULL; } static const struct ast_channel_tech null_tech = { @@ -1087,6 +1086,11 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char /* Channel structure allocation failure. */ return NULL; } + if (!(tmp->nativeformats = ast_format_cap_alloc())) { + ao2_ref(tmp, -1); + /* format capabilities structure allocation failure */ + return NULL; + } /* * Init file descriptors to unopened state so @@ -2426,6 +2430,8 @@ static void ast_channel_destructor(void *obj) */ ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, device_name); } + + chan->nativeformats = ast_format_cap_destroy(chan->nativeformats); } /*! \brief Free a dummy channel structure */ @@ -2658,8 +2664,15 @@ static void free_translation(struct ast_channel *clonechan) ast_translator_free_path(clonechan->readtrans); clonechan->writetrans = NULL; clonechan->readtrans = NULL; - clonechan->rawwriteformat = clonechan->nativeformats; - clonechan->rawreadformat = clonechan->nativeformats; + if (ast_format_cap_is_empty(clonechan->nativeformats)) { + ast_format_clear(&clonechan->rawwriteformat); + ast_format_clear(&clonechan->rawreadformat); + } else { + struct ast_format tmpfmt; + ast_best_codec(clonechan->nativeformats, &tmpfmt); + ast_format_copy(&clonechan->rawwriteformat, &tmpfmt); + ast_format_copy(&clonechan->rawreadformat, &tmpfmt); + } } void ast_set_hangupsource(struct ast_channel *chan, const char *source, int force) @@ -2987,7 +3000,7 @@ static int generator_force(const void *data) if (!tmp || !generate) return 0; - res = generate(chan, tmp, 0, ast_format_rate(chan->writeformat & AST_FORMAT_AUDIO_MASK) / 50); + res = generate(chan, tmp, 0, ast_format_rate(&chan->writeformat) / 50); chan->generatordata = tmp; @@ -3548,9 +3561,9 @@ static void ast_read_generator_actions(struct ast_channel *chan, struct ast_fram chan->generatordata = NULL; /* reset, to let writes go through */ - if (f->subclass.codec != chan->writeformat) { + if (ast_format_cmp(&f->subclass.format, &chan->writeformat) == AST_FORMAT_CMP_NOT_EQUAL) { float factor; - factor = ((float) ast_format_rate(chan->writeformat)) / ((float) ast_format_rate(f->subclass.codec)); + factor = ((float) ast_format_rate(&chan->writeformat)) / ((float) ast_format_rate(&f->subclass.format)); samples = (int) ( ((float) f->samples) * factor ); } else { samples = f->samples; @@ -4066,11 +4079,11 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) ast_frfree(f); f = &ast_null_frame; } - } else if ((f->frametype == AST_FRAME_VOICE) && !(f->subclass.codec & chan->nativeformats)) { + } else if ((f->frametype == AST_FRAME_VOICE) && !ast_format_cap_iscompatible(chan->nativeformats, &f->subclass.format)) { /* This frame is not one of the current native formats -- drop it on the floor */ char to[200]; ast_log(LOG_NOTICE, "Dropping incompatible voice frame on %s of format %s since our native format has changed to %s\n", - chan->name, ast_getformatname(f->subclass.codec), ast_getformatname_multiple(to, sizeof(to), chan->nativeformats)); + chan->name, ast_getformatname(&f->subclass.format), ast_getformatname_multiple(to, sizeof(to), chan->nativeformats)); ast_frfree(f); f = &ast_null_frame; } else if ((f->frametype == AST_FRAME_VOICE)) { @@ -4086,7 +4099,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) #ifndef MONITOR_CONSTANT_DELAY int jump = chan->outsmpl - chan->insmpl - 4 * f->samples; if (jump >= 0) { - jump = calc_monitor_jump((chan->outsmpl - chan->insmpl), ast_format_rate(f->subclass.codec), ast_format_rate(chan->monitor->read_stream->fmt->format)); + jump = calc_monitor_jump((chan->outsmpl - chan->insmpl), ast_format_rate(&f->subclass.format), ast_format_rate(&chan->monitor->read_stream->fmt->format)); if (ast_seekstream(chan->monitor->read_stream, jump, SEEK_FORCECUR) == -1) ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n"); chan->insmpl += (chan->outsmpl - chan->insmpl) + f->samples; @@ -4557,7 +4570,7 @@ int ast_prod(struct ast_channel *chan) /* Send an empty audio frame to get things moving */ if (chan->_state != AST_STATE_UP) { ast_debug(1, "Prodding channel '%s'\n", chan->name); - a.subclass.codec = chan->rawwriteformat; + ast_format_copy(&a.subclass.format, &chan->rawwriteformat); a.data.ptr = nothing + AST_FRIENDLY_OFFSET; a.src = "ast_prod"; /* this better match check in ast_write */ if (ast_write(chan, &a)) @@ -4808,12 +4821,12 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) if (chan->tech->write == NULL) break; /*! \todo XXX should return 0 maybe ? */ - if (ast_opt_generic_plc && fr->subclass.codec == AST_FORMAT_SLINEAR) { + if (ast_opt_generic_plc && fr->subclass.format.id == AST_FORMAT_SLINEAR) { apply_plc(chan, fr); } /* If the frame is in the raw write format, then it's easy... just use the frame - otherwise we will have to translate */ - if (fr->subclass.codec == chan->rawwriteformat) + if (ast_format_cmp(&fr->subclass.format, &chan->rawwriteformat) != AST_FORMAT_CMP_NOT_EQUAL) f = fr; else f = (chan->writetrans) ? ast_translate(chan->writetrans, fr, 0) : fr; @@ -4880,7 +4893,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) #ifndef MONITOR_CONSTANT_DELAY int jump = chan->insmpl - chan->outsmpl - 4 * cur->samples; if (jump >= 0) { - jump = calc_monitor_jump((chan->insmpl - chan->outsmpl), ast_format_rate(f->subclass.codec), ast_format_rate(chan->monitor->read_stream->fmt->format)); + jump = calc_monitor_jump((chan->insmpl - chan->outsmpl), ast_format_rate(&f->subclass.format), ast_format_rate(&chan->monitor->read_stream->fmt->format)); if (ast_seekstream(chan->monitor->write_stream, jump, SEEK_FORCECUR) == -1) ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n"); chan->outsmpl += (chan->insmpl - chan->outsmpl) + cur->samples; @@ -4967,26 +4980,33 @@ done: return res; } -static int set_format(struct ast_channel *chan, format_t fmt, format_t *rawformat, format_t *format, - struct ast_trans_pvt **trans, const int direction) +static int set_format(struct ast_channel *chan, + struct ast_format_cap *cap_set, + struct ast_format *rawformat, + struct ast_format *format, + struct ast_trans_pvt **trans, + const int direction) { - format_t native, native_fmt = ast_best_codec(fmt); + struct ast_format_cap *cap_native = chan->nativeformats; + struct ast_format best_set_fmt; + struct ast_format best_native_fmt; int res; char from[200], to[200]; - - /* Make sure we only consider audio */ - fmt &= AST_FORMAT_AUDIO_MASK; - - native = chan->nativeformats; - if (!fmt || !native) /* No audio requested */ - return 0; /* Let's try a call without any sounds (video, text) */ + ast_best_codec(cap_set, &best_set_fmt); /* See if the underlying channel driver is capable of performing transcoding for us */ - if (!ast_channel_setoption(chan, direction ? AST_OPTION_FORMAT_WRITE : AST_OPTION_FORMAT_READ, &native_fmt, sizeof(int*), 0)) { + if (!ast_channel_setoption(chan, direction ? AST_OPTION_FORMAT_WRITE : AST_OPTION_FORMAT_READ, &best_set_fmt, sizeof(best_set_fmt), 0)) { ast_debug(1, "Channel driver natively set channel %s to %s format %s\n", chan->name, - direction ? "write" : "read", ast_getformatname(native_fmt)); - chan->nativeformats = *rawformat = *format = native_fmt; + direction ? "write" : "read", ast_getformatname(&best_set_fmt)); + + ast_format_copy(format, &best_set_fmt); + ast_format_copy(rawformat, &best_set_fmt); + + ast_channel_lock(chan); + ast_format_cap_set(chan->nativeformats, &best_set_fmt); + ast_channel_unlock(chan); + if (*trans) { ast_translator_free_path(*trans); } @@ -4995,39 +5015,44 @@ static int set_format(struct ast_channel *chan, format_t fmt, format_t *rawforma } /* Find a translation path from the native format to one of the desired formats */ - if (!direction) + if (!direction) { /* reading */ - res = ast_translator_best_choice(&fmt, &native); - else + res = ast_translator_best_choice(cap_set, cap_native, &best_set_fmt, &best_native_fmt); + } else { /* writing */ - res = ast_translator_best_choice(&native, &fmt); + res = ast_translator_best_choice(cap_native, cap_set, &best_native_fmt, &best_set_fmt); + } if (res < 0) { ast_log(LOG_WARNING, "Unable to find a codec translation path from %s to %s\n", - ast_getformatname_multiple(from, sizeof(from), native), - ast_getformatname_multiple(to, sizeof(to), fmt)); + ast_getformatname_multiple(from, sizeof(from), cap_native), + ast_getformatname_multiple(to, sizeof(to), cap_set)); return -1; } - + /* Now we have a good choice for both. */ ast_channel_lock(chan); - if ((*rawformat == native) && (*format == fmt) && ((*rawformat == *format) || (*trans))) { + if ((ast_format_cmp(rawformat, &best_native_fmt) != AST_FORMAT_CMP_NOT_EQUAL) && + (ast_format_cmp(format, &best_set_fmt) != AST_FORMAT_CMP_NOT_EQUAL) && + ((ast_format_cmp(rawformat, format) != AST_FORMAT_CMP_NOT_EQUAL) || (*trans))) { /* the channel is already in these formats, so nothing to do */ ast_channel_unlock(chan); return 0; } - *rawformat = native; + ast_format_copy(rawformat, &best_native_fmt); /* User perspective is fmt */ - *format = fmt; + ast_format_copy(format, &best_set_fmt); + /* Free any read translation we have right now */ if (*trans) { ast_translator_free_path(*trans); *trans = NULL; } + /* Build a translation path from the raw format to the desired format */ - if (*format == *rawformat) { + if (ast_format_cmp(format, rawformat) != AST_FORMAT_CMP_NOT_EQUAL) { /* * If we were able to swap the native format to the format that * has been requested, then there is no need to try to build @@ -5037,29 +5062,122 @@ static int set_format(struct ast_channel *chan, format_t fmt, format_t *rawforma } else { if (!direction) { /* reading */ - *trans = ast_translator_build_path(*format, *rawformat); + *trans = ast_translator_build_path(format, rawformat); } else { /* writing */ - *trans = ast_translator_build_path(*rawformat, *format); + *trans = ast_translator_build_path(rawformat, format); } res = *trans ? 0 : -1; } ast_channel_unlock(chan); - ast_debug(1, "Set channel %s to %s format %s\n", chan->name, - direction ? "write" : "read", ast_getformatname(fmt)); + + ast_debug(1, "Set channel %s to %s format %s\n", + chan->name, + direction ? "write" : "read", + ast_getformatname(&best_set_fmt)); + return res; +} + +int ast_set_read_format(struct ast_channel *chan, struct ast_format *format) +{ + struct ast_format_cap *cap = ast_format_cap_alloc_nolock(); + int res; + if (!cap) { + return -1; + } + ast_format_cap_add(cap, format); + + res = set_format(chan, + cap, + &chan->rawreadformat, + &chan->readformat, + &chan->readtrans, + 0); + + ast_format_cap_destroy(cap); return res; } -int ast_set_read_format(struct ast_channel *chan, format_t fmt) +int ast_set_read_format_by_id(struct ast_channel *chan, enum ast_format_id id) { - return set_format(chan, fmt, &chan->rawreadformat, &chan->readformat, - &chan->readtrans, 0); + struct ast_format_cap *cap = ast_format_cap_alloc_nolock(); + struct ast_format tmp_format; + int res; + if (!cap) { + return -1; + } + ast_format_cap_add(cap, ast_format_set(&tmp_format, id, 0)); + + res = set_format(chan, + cap, + &chan->rawreadformat, + &chan->readformat, + &chan->readtrans, + 0); + + ast_format_cap_destroy(cap); + return res; } -int ast_set_write_format(struct ast_channel *chan, format_t fmt) +int ast_set_read_format_from_cap(struct ast_channel *chan, struct ast_format_cap *cap) { - return set_format(chan, fmt, &chan->rawwriteformat, &chan->writeformat, - &chan->writetrans, 1); + return set_format(chan, + cap, + &chan->rawreadformat, + &chan->readformat, + &chan->readtrans, + 0); +} + +int ast_set_write_format(struct ast_channel *chan, struct ast_format *format) +{ + struct ast_format_cap *cap = ast_format_cap_alloc_nolock(); + int res; + if (!cap) { + return -1; + } + ast_format_cap_add(cap, format); + + res = set_format(chan, + cap, + &chan->rawwriteformat, + &chan->writeformat, + &chan->writetrans, + 1); + + ast_format_cap_destroy(cap); + return res; +} + +int ast_set_write_format_by_id(struct ast_channel *chan, enum ast_format_id id) +{ + struct ast_format_cap *cap = ast_format_cap_alloc_nolock(); + struct ast_format tmp_format; + int res; + if (!cap) { + return -1; + } + ast_format_cap_add(cap, ast_format_set(&tmp_format, id, 0)); + + res = set_format(chan, + cap, + &chan->rawwriteformat, + &chan->writeformat, + &chan->writetrans, + 1); + + ast_format_cap_destroy(cap); + return res; +} + +int ast_set_write_format_from_cap(struct ast_channel *chan, struct ast_format_cap *cap) +{ + return set_format(chan, + cap, + &chan->rawwriteformat, + &chan->writeformat, + &chan->writetrans, + 1); } const char *ast_channel_reason2str(int reason) @@ -5098,7 +5216,7 @@ static void handle_cause(int cause, int *outstate) } } -struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_channel *orig, int *timeout, format_t format, struct outgoing_helper *oh, int *outstate) +struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_channel *orig, int *timeout, struct ast_format_cap *cap, struct outgoing_helper *oh, int *outstate) { char tmpchan[256]; struct ast_channel *new = NULL; @@ -5121,7 +5239,7 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan data = tmpchan; type = "Local"; } - if (!(new = ast_request(type, format, orig, data, &cause))) { + if (!(new = ast_request(type, cap, orig, data, &cause))) { ast_log(LOG_NOTICE, "Unable to create channel for call forward to '%s/%s' (cause = %d)\n", type, data, cause); handle_cause(cause, outstate); ast_hangup(orig); @@ -5179,7 +5297,7 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan return new; } -struct ast_channel *__ast_request_and_dial(const char *type, format_t format, const struct ast_channel *requestor, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh) +struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh) { int dummy_outstate; int cause = 0; @@ -5193,7 +5311,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, format_t format, co else outstate = &dummy_outstate; /* make outstate always a valid pointer */ - chan = ast_request(type, format, requestor, data, &cause); + chan = ast_request(type, cap, requestor, data, &cause); if (!chan) { ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); handle_cause(cause, outstate); @@ -5245,7 +5363,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, format_t format, co if (timeout > -1) timeout = res; if (!ast_strlen_zero(chan->call_forward)) { - if (!(chan = ast_call_forward(NULL, chan, NULL, format, oh, outstate))) { + if (!(chan = ast_call_forward(NULL, chan, NULL, cap, oh, outstate))) { return NULL; } continue; @@ -5338,9 +5456,9 @@ struct ast_channel *__ast_request_and_dial(const char *type, format_t format, co return chan; } -struct ast_channel *ast_request_and_dial(const char *type, format_t format, const struct ast_channel *requestor, void *data, int timeout, int *outstate, const char *cidnum, const char *cidname) +struct ast_channel *ast_request_and_dial(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, void *data, int timeout, int *outstate, const char *cidnum, const char *cidname) { - return __ast_request_and_dial(type, format, requestor, data, timeout, outstate, cidnum, cidname, NULL); + return __ast_request_and_dial(type, cap, requestor, data, timeout, outstate, cidnum, cidname, NULL); } static int set_security_requirements(const struct ast_channel *requestor, struct ast_channel *out) @@ -5383,16 +5501,12 @@ static int set_security_requirements(const struct ast_channel *requestor, struct return 0; } -struct ast_channel *ast_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause) +struct ast_channel *ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_channel *requestor, void *data, int *cause) { struct chanlist *chan; struct ast_channel *c; - format_t capabilities; - format_t fmt; int res; int foo; - format_t videoformat = format & AST_FORMAT_VIDEO_MASK; - format_t textformat = format & AST_FORMAT_TEXT_MASK; if (!cause) cause = &foo; @@ -5404,21 +5518,27 @@ struct ast_channel *ast_request(const char *type, format_t format, const struct } AST_RWLIST_TRAVERSE(&backends, chan, list) { + struct ast_format_cap *tmp_cap; + struct ast_format tmp_fmt; + struct ast_format best_audio_fmt; + struct ast_format_cap *joint_cap; + if (strcasecmp(type, chan->tech->type)) continue; - capabilities = chan->tech->capabilities; - fmt = format & AST_FORMAT_AUDIO_MASK; - if (fmt) { + ast_format_clear(&best_audio_fmt); + /* find the best audio format to use */ + if ((tmp_cap = ast_format_cap_get_type(request_cap, AST_FORMAT_TYPE_AUDIO))) { /* We have audio - is it possible to connect the various calls to each other? (Avoid this check for calls without audio, like text+video calls) */ - res = ast_translator_best_choice(&fmt, &capabilities); + res = ast_translator_best_choice(tmp_cap, chan->tech->capabilities, &tmp_fmt, &best_audio_fmt); + ast_format_cap_destroy(tmp_cap); if (res < 0) { char tmp1[256], tmp2[256]; ast_log(LOG_WARNING, "No translator path exists for channel type %s (native %s) to %s\n", type, ast_getformatname_multiple(tmp1, sizeof(tmp1), chan->tech->capabilities), - ast_getformatname_multiple(tmp2, sizeof(tmp2), format)); + ast_getformatname_multiple(tmp2, sizeof(tmp2), request_cap)); *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL; AST_RWLIST_UNLOCK(&backends); return NULL; @@ -5428,8 +5548,21 @@ struct ast_channel *ast_request(const char *type, format_t format, const struct if (!chan->tech->requester) return NULL; - if (!(c = chan->tech->requester(type, capabilities | videoformat | textformat, requestor, data, cause))) + /* XXX Only the audio format calculated as being the best for translation + * purposes is used for the request. This needs to be re-evaluated. It may be + * a better choice to send all the audio formats capable of being translated + * during the request and allow the channel drivers to pick the best one. */ + if (!(joint_cap = ast_format_cap_dup(request_cap))) { return NULL; + } + ast_format_cap_remove_bytype(joint_cap, AST_FORMAT_TYPE_AUDIO); + ast_format_cap_add(joint_cap, &best_audio_fmt); + + if (!(c = chan->tech->requester(type, joint_cap, requestor, data, cause))) { + ast_format_cap_destroy(joint_cap); + return NULL; + } + joint_cap = ast_format_cap_destroy(joint_cap); if (set_security_requirements(requestor, c)) { ast_log(LOG_WARNING, "Setting security requirements failed\n"); @@ -5610,7 +5743,10 @@ int ast_channel_sendurl(struct ast_channel *chan, const char *url) /*! \brief Set up translation from one channel to another */ static int ast_channel_make_compatible_helper(struct ast_channel *from, struct ast_channel *to) { - format_t src, dst; + struct ast_format_cap *src_cap = from->nativeformats; /* shallow copy, do not destroy */ + struct ast_format_cap *dst_cap = to->nativeformats; /* shallow copy, do not destroy */ + struct ast_format best_src_fmt; + struct ast_format best_dst_fmt; int use_slin; /* See if the channel driver can natively make these two channels compatible */ @@ -5619,20 +5755,17 @@ static int ast_channel_make_compatible_helper(struct ast_channel *from, struct a return 0; } - if (from->readformat == to->writeformat && from->writeformat == to->readformat) { + if ((ast_format_cmp(&from->readformat, &to->writeformat) != AST_FORMAT_CMP_NOT_EQUAL) && + (ast_format_cmp(&to->readformat, &from->writeformat) != AST_FORMAT_CMP_NOT_EQUAL)) { /* Already compatible! Moving on ... */ return 0; } - /* Set up translation from the 'from' channel to the 'to' channel */ - src = from->nativeformats; - dst = to->nativeformats; - /* If there's no audio in this call, don't bother with trying to find a translation path */ - if ((src & AST_FORMAT_AUDIO_MASK) == 0 || (dst & AST_FORMAT_AUDIO_MASK) == 0) + if (!ast_format_cap_has_type(src_cap, AST_FORMAT_TYPE_AUDIO) || !ast_format_cap_has_type(dst_cap, AST_FORMAT_TYPE_AUDIO)) return 0; - if (ast_translator_best_choice(&dst, &src) < 0) { + if (ast_translator_best_choice(dst_cap, src_cap, &best_src_fmt, &best_dst_fmt) < 0) { ast_log(LOG_WARNING, "No path to translate from %s to %s\n", from->name, to->name); return -1; } @@ -5643,16 +5776,20 @@ static int ast_channel_make_compatible_helper(struct ast_channel *from, struct a * no direct conversion available. If generic PLC is * desired, then transcoding via SLINEAR is a requirement */ - use_slin = (src == AST_FORMAT_SLINEAR || dst == AST_FORMAT_SLINEAR); - if ((src != dst) && (ast_opt_generic_plc || ast_opt_transcode_via_slin) && - (ast_translate_path_steps(dst, src) != 1 || use_slin)) - dst = AST_FORMAT_SLINEAR; - if (ast_set_read_format(from, dst) < 0) { - ast_log(LOG_WARNING, "Unable to set read format on channel %s to %s\n", from->name, ast_getformatname(dst)); + use_slin = (best_src_fmt.id == AST_FORMAT_SLINEAR || best_dst_fmt.id == AST_FORMAT_SLINEAR); + if ((ast_format_cmp(&best_src_fmt, &best_dst_fmt) == AST_FORMAT_CMP_NOT_EQUAL) && + (ast_opt_generic_plc || ast_opt_transcode_via_slin) && + (ast_translate_path_steps(&best_dst_fmt, &best_src_fmt) != 1 || use_slin)) { + + ast_format_set(&best_dst_fmt, AST_FORMAT_SLINEAR, 0); + } + + if (ast_set_read_format(from, &best_dst_fmt) < 0) { + ast_log(LOG_WARNING, "Unable to set read format on channel %s to %s\n", from->name, ast_getformatname(&best_dst_fmt)); return -1; } - if (ast_set_write_format(to, dst) < 0) { - ast_log(LOG_WARNING, "Unable to set write format on channel %s to %s\n", to->name, ast_getformatname(dst)); + if (ast_set_write_format(to, &best_dst_fmt) < 0) { + ast_log(LOG_WARNING, "Unable to set write format on channel %s to %s\n", to->name, ast_getformatname(&best_dst_fmt)); return -1; } return 0; @@ -6199,8 +6336,7 @@ static void masquerade_colp_transfer(struct ast_channel *transferee, struct xfer */ int ast_do_masquerade(struct ast_channel *original) { - format_t x; - int i; + int x, i; int res=0; int origstate; int visible_indication; @@ -6218,13 +6354,17 @@ int ast_do_masquerade(struct ast_channel *original) struct ast_cdr *cdr; struct ast_datastore *xfer_ds; struct xfer_masquerade_ds *xfer_colp; - format_t rformat = original->readformat; - format_t wformat = original->writeformat; + struct ast_format rformat; + struct ast_format wformat; + struct ast_format tmp_format; char newn[AST_CHANNEL_NAME]; char orig[AST_CHANNEL_NAME]; char masqn[AST_CHANNEL_NAME]; char zombn[AST_CHANNEL_NAME]; + ast_format_copy(&rformat, &original->readformat); + ast_format_copy(&wformat, &original->writeformat); + /* XXX This operation is a bit odd. We're essentially putting the guts of * the clone channel into the original channel. Start by killing off the * original channel's backend. While the features are nice, which is the @@ -6383,12 +6523,13 @@ int ast_do_masquerade(struct ast_channel *original) } /* Swap the raw formats */ - x = original->rawreadformat; - original->rawreadformat = clonechan->rawreadformat; - clonechan->rawreadformat = x; - x = original->rawwriteformat; - original->rawwriteformat = clonechan->rawwriteformat; - clonechan->rawwriteformat = x; + ast_format_copy(&tmp_format, &original->rawreadformat); + ast_format_copy(&original->rawreadformat, &clonechan->rawreadformat); + ast_format_copy(&clonechan->rawreadformat, &tmp_format); + + ast_format_copy(&tmp_format, &original->rawwriteformat); + ast_format_copy(&original->rawwriteformat, &clonechan->rawwriteformat); + ast_format_copy(&clonechan->rawwriteformat, &tmp_format); clonechan->_softhangup = AST_SOFTHANGUP_DEV; @@ -6486,16 +6627,16 @@ int ast_do_masquerade(struct ast_channel *original) ast_channel_set_fd(original, AST_TIMING_FD, original->timingfd); /* Our native formats are different now */ - original->nativeformats = clonechan->nativeformats; + ast_format_cap_copy(original->nativeformats, clonechan->nativeformats); /* Context, extension, priority, app data, jump table, remain the same */ /* pvt switches. pbx stays the same, as does next */ /* Set the write format */ - ast_set_write_format(original, wformat); + ast_set_write_format(original, &wformat); /* Set the read format */ - ast_set_read_format(original, rformat); + ast_set_read_format(original, &rformat); /* Copy the music class */ ast_string_field_set(original, musicclass, clonechan->musicclass); @@ -6509,7 +6650,7 @@ int ast_do_masquerade(struct ast_channel *original) } ast_debug(1, "Putting channel %s in %s/%s formats\n", original->name, - ast_getformatname(wformat), ast_getformatname(rformat)); + ast_getformatname(&wformat), ast_getformatname(&rformat)); /* Okay. Last thing is to let the channel driver know about all this mess, so he can fix up everything as best as possible */ @@ -6753,8 +6894,8 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct struct ast_channel *cs[3]; struct ast_frame *f; enum ast_bridge_result res = AST_BRIDGE_COMPLETE; - format_t o0nativeformats; - format_t o1nativeformats; + struct ast_format_cap *o0nativeformats; + struct ast_format_cap *o1nativeformats; int watch_c0_dtmf; int watch_c1_dtmf; void *pvt0, *pvt1; @@ -6762,13 +6903,20 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct int frame_put_in_jb = 0; int jb_in_use; int to; - + + o0nativeformats = ast_format_cap_dup(c0->nativeformats); + o1nativeformats = ast_format_cap_dup(c1->nativeformats); + + if (!o0nativeformats || !o1nativeformats) { + ast_format_cap_destroy(o0nativeformats); /* NULL safe */ + ast_format_cap_destroy(o1nativeformats); /* NULL safe */ + return AST_BRIDGE_FAILED; + } + cs[0] = c0; cs[1] = c1; pvt0 = c0->tech_pvt; pvt1 = c1->tech_pvt; - o0nativeformats = c0->nativeformats; - o1nativeformats = c1->nativeformats; watch_c0_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_0; watch_c1_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_1; @@ -6790,8 +6938,8 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct struct ast_channel *who, *other; if ((c0->tech_pvt != pvt0) || (c1->tech_pvt != pvt1) || - (o0nativeformats != c0->nativeformats) || - (o1nativeformats != c1->nativeformats)) { + (!ast_format_cap_identical(o0nativeformats, c0->nativeformats)) || + (!ast_format_cap_identical(o1nativeformats, c1->nativeformats))) { /* Check for Masquerade, codec changes, etc */ res = AST_BRIDGE_RETRY; break; @@ -6941,6 +7089,9 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct ast_poll_channel_del(c0, c1); + ast_format_cap_destroy(o0nativeformats); + ast_format_cap_destroy(o1nativeformats); + return res; } @@ -7050,8 +7201,8 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha { struct ast_channel *chans[2] = { c0, c1 }; enum ast_bridge_result res = AST_BRIDGE_COMPLETE; - format_t o0nativeformats; - format_t o1nativeformats; + struct ast_format_cap *o0nativeformats; + struct ast_format_cap *o1nativeformats; long time_left_ms=0; char caller_warning = 0; char callee_warning = 0; @@ -7072,6 +7223,16 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha ast_test_flag(c1, AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c1)) return -1; + o0nativeformats = ast_format_cap_dup(c0->nativeformats); + o1nativeformats = ast_format_cap_dup(c1->nativeformats); + if (!o0nativeformats || !o1nativeformats) { + ast_format_cap_destroy(o0nativeformats); + ast_format_cap_destroy(o1nativeformats); + ast_log(LOG_WARNING, "failed to copy native formats\n"); + return -1; + } + + *fo = NULL; if (ast_tvzero(config->start_time)) { @@ -7092,9 +7253,6 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha ast_set_owners_and_peers(c0, c1); - o0nativeformats = c0->nativeformats; - o1nativeformats = c1->nativeformats; - if (config->feature_timer && !ast_tvzero(config->nexteventts)) { config->nexteventts = ast_tvadd(config->feature_start_time, ast_samp2tv(config->feature_timer, 1000)); } else if (config->timelimit) { @@ -7245,6 +7403,8 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha c0->_bridge = NULL; c1->_bridge = NULL; + ast_format_cap_destroy(o0nativeformats); + ast_format_cap_destroy(o1nativeformats); return res; } else { ast_clear_flag(c0, AST_FLAG_NBRIDGE); @@ -7264,16 +7424,21 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha } } - if (((c0->writeformat != c1->readformat) || (c0->readformat != c1->writeformat) || - (c0->nativeformats != o0nativeformats) || (c1->nativeformats != o1nativeformats)) && + if (((ast_format_cmp(&c1->readformat, &c0->writeformat) == AST_FORMAT_CMP_NOT_EQUAL) || + (ast_format_cmp(&c0->readformat, &c1->writeformat) == AST_FORMAT_CMP_NOT_EQUAL) || + !ast_format_cap_identical(c0->nativeformats, o0nativeformats) || + !ast_format_cap_identical(c1->nativeformats, o1nativeformats)) && !(c0->generator || c1->generator)) { if (ast_channel_make_compatible(c0, c1)) { ast_log(LOG_WARNING, "Can't make %s and %s compatible\n", c0->name, c1->name); manager_bridge_event(0, 1, c0, c1); + ast_format_cap_destroy(o0nativeformats); + ast_format_cap_destroy(o1nativeformats); return AST_BRIDGE_FAILED; } - o0nativeformats = c0->nativeformats; - o1nativeformats = c1->nativeformats; + + ast_format_cap_copy(o0nativeformats, c0->nativeformats); + ast_format_cap_copy(o1nativeformats, c1->nativeformats); } update_bridge_vars(c0, c1); @@ -7310,6 +7475,8 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha S_COR(c1->caller.id.number.valid, c1->caller.id.number.str, "<unknown>")); ast_debug(1, "Bridge stops bridging channels %s and %s\n", c0->name, c1->name); + ast_format_cap_destroy(o0nativeformats); + ast_format_cap_destroy(o1nativeformats); return res; } @@ -7356,7 +7523,7 @@ struct tonepair_state { int v1_2; int v2_2; int v3_2; - format_t origwfmt; + struct ast_format origwfmt; int pos; int duration; int modulate; @@ -7370,7 +7537,7 @@ static void tonepair_release(struct ast_channel *chan, void *params) struct tonepair_state *ts = params; if (chan) - ast_set_write_format(chan, ts->origwfmt); + ast_set_write_format(chan, &ts->origwfmt); ast_free(ts); } @@ -7381,8 +7548,8 @@ static void *tonepair_alloc(struct ast_channel *chan, void *params) if (!(ts = ast_calloc(1, sizeof(*ts)))) return NULL; - ts->origwfmt = chan->writeformat; - if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) { + ast_format_copy(&ts->origwfmt, &chan->writeformat); + if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) { ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", chan->name); tonepair_release(NULL, ts); ts = NULL; @@ -7436,7 +7603,7 @@ static int tonepair_generator(struct ast_channel *chan, void *data, int len, int ts->data[x] = ts->v3_1 + ts->v3_2; } ts->f.frametype = AST_FRAME_VOICE; - ts->f.subclass.codec = AST_FORMAT_SLINEAR; + ast_format_set(&ts->f.subclass.format, AST_FORMAT_SLINEAR, 0); ts->f.datalen = len; ts->f.samples = samples; ts->f.offset = AST_FRIENDLY_OFFSET; @@ -7778,11 +7945,11 @@ static int silence_generator_generate(struct ast_channel *chan, void *data, int short buf[samples]; struct ast_frame frame = { .frametype = AST_FRAME_VOICE, - .subclass.codec = AST_FORMAT_SLINEAR, .data.ptr = buf, .samples = samples, .datalen = sizeof(buf), }; + ast_format_set(&frame.subclass.format, AST_FORMAT_SLINEAR, 0); memset(buf, 0, sizeof(buf)); @@ -7799,7 +7966,7 @@ static struct ast_generator silence_generator = { }; struct ast_silence_generator { - int old_write_format; + struct ast_format old_write_format; }; struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_channel *chan) @@ -7810,9 +7977,9 @@ struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_cha return NULL; } - state->old_write_format = chan->writeformat; + ast_format_copy(&state->old_write_format, &chan->writeformat); - if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { + if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) { ast_log(LOG_ERROR, "Could not set write format to SLINEAR\n"); ast_free(state); return NULL; @@ -7834,7 +8001,7 @@ void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_sil ast_debug(1, "Stopped silence generator on '%s'\n", chan->name); - if (ast_set_write_format(chan, state->old_write_format) < 0) + if (ast_set_write_format(chan, &state->old_write_format) < 0) ast_log(LOG_ERROR, "Could not return write format to its original state\n"); ast_free(state); |