diff options
205 files changed, 13946 insertions, 9541 deletions
diff --git a/UPGRADE.txt b/UPGRADE.txt index 84b3e8d5a..535782a86 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -208,6 +208,32 @@ chan_sip: progress indications into a 180 Ringing (if a 180 has not yet been transmitted) if 'progressinband=never'. + - The codec preference order in an SDP during an offer is slightly different + than previous releases. Prior to Asterisk 13, the preference order of + codecs used to be: + (1) Our preferred codec + (2) Our configured codecs + (3) Any non-audio joint codecs + + One of the ways the new media format architecture in Asterisk 13 improves + performance is by reference counting formats, such that they can be reused + in many places without additional allocation. To not require a large + amount of locking, an instance of a format is immutable by convention. + This works well except for formats with attributes. Since a media format + with an attribute is a different object than the same format without an + attribute, we have to carry over the formats with attributes from an + inbound offer so that the correct attributes are offered in an outgoing + INVITE request. This requires some subtle tweaks to the preference order + to ensure that the media format with attributes is offered to a remote + peer, as opposed to the same media format (but without attributes) that + may be stored in the peer object. + + All of this means that our offer offer list will now be: + (1) Our preferred codec + (2) Any joint codecs offered by the inbound offer + (3) All other codecs that are not the preferred codec and not a joint + codec offered by the inbound offer + CLI commands: - "core show settings" now lists the current console verbosity in addition to the root console verbosity. diff --git a/addons/chan_mobile.c b/addons/chan_mobile.c index a7cbc00e2..75db0fad8 100644 --- a/addons/chan_mobile.c +++ b/addons/chan_mobile.c @@ -73,16 +73,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/manager.h" #include "asterisk/io.h" +#include "asterisk/smoother.h" +#include "asterisk/format_cache.h" #define MBL_CONFIG "chan_mobile.conf" #define MBL_CONFIG_OLD "mobile.conf" #define DEVICE_FRAME_SIZE 48 -#define DEVICE_FRAME_FORMAT AST_FORMAT_SLINEAR +#define DEVICE_FRAME_FORMAT ast_format_slin #define CHANNEL_FRAME_SIZE 320 -static struct ast_format prefformat; - static int discovery_interval = 60; /* The device discovery interval, default 60 seconds. */ static pthread_t discovery_thread = AST_PTHREADT_NULL; /* The discovery thread */ static sdp_session_t *sdp_session; @@ -840,7 +840,6 @@ e_return: static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor) { - struct ast_channel *chn; pvt->answered = 0; @@ -862,11 +861,11 @@ static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num } ast_channel_tech_set(chn, &mbl_tech); - ast_format_cap_add(ast_channel_nativeformats(chn), &prefformat); - ast_format_copy(ast_channel_rawreadformat(chn), &prefformat); - ast_format_copy(ast_channel_rawwriteformat(chn), &prefformat); - ast_format_copy(ast_channel_writeformat(chn), &prefformat); - ast_format_copy(ast_channel_readformat(chn), &prefformat); + ast_channel_nativeformats_set(chn, mbl_tech.capabilities); + ast_channel_set_rawreadformat(chn, DEVICE_FRAME_FORMAT); + ast_channel_set_rawwriteformat(chn, DEVICE_FRAME_FORMAT); + ast_channel_set_writeformat(chn, DEVICE_FRAME_FORMAT); + ast_channel_set_readformat(chn, DEVICE_FRAME_FORMAT); ast_channel_tech_pvt_set(chn, pvt); if (state == AST_STATE_RING) @@ -902,9 +901,9 @@ static struct ast_channel *mbl_request(const char *type, struct ast_format_cap * return NULL; } - if (!(ast_format_cap_iscompatible(cap, &prefformat))) { - char tmp[256]; - ast_log(LOG_WARNING, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap)); + if (ast_format_cap_iscompatible_format(cap, DEVICE_FRAME_FORMAT) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_str *codec_buf = ast_str_alloca(64); + ast_log(LOG_WARNING, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &codec_buf)); *cause = AST_CAUSE_FACILITY_NOT_IMPLEMENTED; return NULL; } @@ -1116,7 +1115,7 @@ static struct ast_frame *mbl_read(struct ast_channel *ast) memset(&pvt->fr, 0x00, sizeof(struct ast_frame)); pvt->fr.frametype = AST_FRAME_VOICE; - ast_format_set(&pvt->fr.subclass.format, DEVICE_FRAME_FORMAT, 0); + pvt->fr.subclass.format = DEVICE_FRAME_FORMAT; pvt->fr.src = "Mobile"; pvt->fr.offset = AST_FRIENDLY_OFFSET; pvt->fr.mallocd = 0; @@ -4697,7 +4696,8 @@ static int unload_module(void) if (sdp_session) sdp_close(sdp_session); - mbl_tech.capabilities = ast_format_cap_destroy(mbl_tech.capabilities); + ao2_ref(mbl_tech.capabilities, -1); + mbl_tech.capabilities = NULL; return 0; } @@ -4706,11 +4706,11 @@ static int load_module(void) int dev_id, s; - if (!(mbl_tech.capabilities = ast_format_cap_alloc(0))) { + if (!(mbl_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_DECLINE; } - ast_format_set(&prefformat, DEVICE_FRAME_FORMAT, 0); - ast_format_cap_add(mbl_tech.capabilities, &prefformat); + + ast_format_cap_append(mbl_tech.capabilities, DEVICE_FRAME_FORMAT, 0); /* Check if we have Bluetooth, no point loading otherwise... */ dev_id = hci_get_route(NULL); s = hci_open_dev(dev_id); diff --git a/addons/chan_ooh323.c b/addons/chan_ooh323.c index 8f1ae76bc..f02002f60 100644 --- a/addons/chan_ooh323.c +++ b/addons/chan_ooh323.c @@ -92,8 +92,6 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance static void ooh323_get_codec(struct ast_channel *chan, struct ast_format_cap *result); void setup_rtp_remote(ooCallData *call, const char *remoteIp, int remotePort); -static void print_codec_to_cli(int fd, struct ast_codec_pref *pref); - struct ooh323_peer *find_friend(const char *name, int port); @@ -174,10 +172,9 @@ static struct ooh323_pvt { char callee_url[AST_MAX_EXTENSION]; int port; - struct ast_format readformat; /* negotiated read format */ - struct ast_format writeformat; /* negotiated write format */ + struct ast_format *readformat; /* negotiated read format */ + struct ast_format *writeformat; /* negotiated write format */ struct ast_format_cap *cap; - struct ast_codec_pref prefs; int dtmfmode; int dtmfcodec; char exten[AST_MAX_EXTENSION]; /* Requested extension */ @@ -212,7 +209,6 @@ struct ooh323_user{ char accountcode[20]; int amaflags; struct ast_format_cap *cap; - struct ast_codec_pref prefs; int dtmfmode; int dtmfcodec; int faxdetect; @@ -239,7 +235,6 @@ struct ooh323_peer{ unsigned outgoinglimit; unsigned outUse; struct ast_format_cap *cap; - struct ast_codec_pref prefs; char accountcode[20]; int amaflags; int dtmfmode; @@ -307,7 +302,6 @@ int v6mode = 0; static char gCallerID[AST_MAX_EXTENSION] = ""; static struct ooAliases *gAliasList; static struct ast_format_cap *gCap; -static struct ast_codec_pref gPrefs; static int gDTMFMode = H323_DTMF_RFC2833; static int gDTMFCodec = 101; static int gFAXdetect = FAXDETECT_CNG; @@ -366,15 +360,17 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state, const char *host, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor) { + struct ast_format_cap *caps = NULL; struct ast_channel *ch = NULL; - struct ast_format tmpfmt; + struct ast_format *tmpfmt = NULL; int features = 0; if (gH323Debug) { ast_verb(0, "--- ooh323_new - %s\n", host); } - ast_format_clear(&tmpfmt); + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + /* Don't hold a h323 pvt lock while we allocate a channel */ ast_mutex_unlock(&i->lock); ast_mutex_lock(&ooh323c_cn_lock); @@ -386,17 +382,25 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state, ast_mutex_lock(&i->lock); - if (ch) { + if (ch && caps) { ast_channel_tech_set(ch, &ooh323_tech); - if (cap) - ast_best_codec(cap, &tmpfmt); - if (!tmpfmt.id) - ast_codec_pref_index(&i->prefs, 0, &tmpfmt); + if (cap) { + tmpfmt = ast_format_cap_get_format(cap, 0); + } + if (!tmpfmt) { + tmpfmt = ast_format_cap_get_format(i->cap, 0); + } + + ast_format_cap_append(caps, tmpfmt, 0); + ast_channel_nativeformats_set(ch, caps); + ao2_ref(caps, -1); - ast_format_cap_add(ast_channel_nativeformats(ch), &tmpfmt); - ast_format_copy(ast_channel_rawwriteformat(ch), &tmpfmt); - ast_format_copy(ast_channel_rawreadformat(ch), &tmpfmt); + ast_channel_set_rawwriteformat(ch, tmpfmt); + ast_channel_set_rawreadformat(ch, tmpfmt); + ast_set_write_format(ch, tmpfmt); + ast_set_read_format(ch, tmpfmt); + ao2_ref(tmpfmt, -1); ast_jb_configure(ch, &global_jbconf); @@ -404,8 +408,6 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state, ast_channel_rings_set(ch, 1); ast_channel_adsicpe_set(ch, AST_ADSI_UNAVAILABLE); - ast_set_write_format(ch, &tmpfmt); - ast_set_read_format(ch, &tmpfmt); ast_channel_tech_pvt_set(ch, i); i->owner = ch; ast_module_ref(myself); @@ -485,8 +487,10 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state, ast_publish_channel_state(ch); } - } else + } else { + ao2_cleanup(caps); ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); + } if(ch) ast_channel_unlock(ch); @@ -512,7 +516,7 @@ static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken) ast_log(LOG_ERROR, "Couldn't allocate private ooh323 structure\n"); return NULL; } - if (!(pvt->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) { + if (!(pvt->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { ast_free(pvt); ast_log(LOG_ERROR, "Couldn't allocate private ooh323 structure\n"); return NULL; @@ -546,8 +550,7 @@ static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken) ast_copy_string(pvt->accountcode, gAccountcode, sizeof(pvt->accountcode)); pvt->amaflags = gAMAFLAGS; - ast_format_cap_copy(pvt->cap, gCap); - memcpy(&pvt->prefs, &gPrefs, sizeof(pvt->prefs)); + ast_format_cap_append_from_cap(pvt->cap, gCap, AST_MEDIA_TYPE_UNKNOWN); pvt->aniasdni = gANIasDNI; @@ -573,21 +576,21 @@ static struct ast_channel *ooh323_request(const char *type, struct ast_format_ca const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause) { + struct ast_str *codec_buf = ast_str_alloca(64); struct ast_channel *chan = NULL; struct ooh323_pvt *p = NULL; struct ooh323_peer *peer = NULL; char *dest = NULL; char *ext = NULL; char tmp[256]; - char formats[FORMAT_STRING_SIZE]; int port = 0; - if (gH323Debug) - ast_verb(0, "--- ooh323_request - data %s format %s\n", data, - ast_getformatname_multiple(formats,FORMAT_STRING_SIZE,cap)); + if (gH323Debug) { + ast_verb(0, "--- ooh323_request - data %s format %s\n", data, ast_format_cap_get_names(cap, &codec_buf)); + } - if (!(ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO))) { - ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(formats,FORMAT_STRING_SIZE,cap)); + if (!(ast_format_cap_has_type(cap, AST_MEDIA_TYPE_AUDIO))) { + ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &codec_buf)); return NULL; } @@ -651,8 +654,7 @@ static struct ast_channel *ooh323_request(const char *type, struct ast_format_ca if (ext) ast_copy_string(p->exten, ext, sizeof(p->exten)); - ast_format_cap_copy(p->cap, peer->cap); - memcpy(&p->prefs, &peer->prefs, sizeof(struct ast_codec_pref)); + ast_format_cap_append_from_cap(p->cap, peer->cap, AST_MEDIA_TYPE_UNKNOWN); p->g729onlyA = peer->g729onlyA; p->dtmfmode |= peer->dtmfmode; p->dtmfcodec = peer->dtmfcodec; @@ -697,7 +699,7 @@ static struct ast_channel *ooh323_request(const char *type, struct ast_format_ca p->t38support = gT38Support; p->rtptimeout = gRTPTimeout; p->nat = gNat; - ast_format_cap_copy(p->cap, gCap); + ast_format_cap_append_from_cap(p->cap, gCap, AST_MEDIA_TYPE_UNKNOWN); p->rtdrinterval = gRTDRInterval; p->rtdrcount = gRTDRCount; p->faststart = gFastStart; @@ -705,7 +707,6 @@ static struct ast_channel *ooh323_request(const char *type, struct ast_format_ca p->directrtp = gDirectRTP; p->earlydirect = gEarlyDirect; - memcpy(&p->prefs, &gPrefs, sizeof(struct ast_codec_pref)); p->username = strdup(dest); p->host = strdup(dest); @@ -1164,7 +1165,6 @@ static int ooh323_write(struct ast_channel *ast, struct ast_frame *f) { struct ooh323_pvt *p = ast_channel_tech_pvt(ast); int res = 0; - char buf[256]; if (p) { ast_mutex_lock(&p->lock); @@ -1190,16 +1190,17 @@ static int ooh323_write(struct ast_channel *ast, struct ast_frame *f) } - if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &f->subclass.format))) { - if (!(ast_format_cap_is_empty(ast_channel_nativeformats(ast)))) { + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_cap_count(ast_channel_nativeformats(ast))) { + struct ast_str *codec_buf = ast_str_alloca(64); ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n", - ast_getformatname(&f->subclass.format), - ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)), - ast_getformatname(ast_channel_readformat(ast)), - ast_getformatname(ast_channel_writeformat(ast))); + ast_format_get_name(f->subclass.format), + ast_format_cap_get_names(ast_channel_nativeformats(ast), &codec_buf), + ast_format_get_name(ast_channel_readformat(ast)), + ast_format_get_name(ast_channel_writeformat(ast))); - ast_set_write_format(ast, &f->subclass.format); + ast_set_write_format(ast, f->subclass.format); } else { /* ast_set_write_format(ast, f->subclass); ast->nativeformats = f->subclass; */ @@ -1508,11 +1509,10 @@ static int ooh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txframes) { struct ooh323_pvt *p = NULL; - char formats[FORMAT_STRING_SIZE]; if (gH323Debug) ast_verb(0, "--- ooh323_update_writeformat %s/%d\n", - ast_getformatname(fmt), txframes); + ast_format_get_name(fmt), txframes); p = find_call(call); if (!p) { @@ -1522,9 +1522,17 @@ void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txfra ast_mutex_lock(&p->lock); - ast_format_copy(&(p->writeformat), fmt); + ao2_replace(p->writeformat, fmt); if (p->owner) { + struct ast_format_cap *caps; + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_log(LOG_ERROR, "Could not allocate capabilities structure\n"); + return; + } + while (p->owner && ast_channel_trylock(p->owner)) { ast_debug(1,"Failed to grab lock, trying again\n"); DEADLOCK_AVOIDANCE(&p->lock); @@ -1532,15 +1540,16 @@ void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txfra if (!p->owner) { ast_mutex_unlock(&p->lock); ast_log(LOG_ERROR, "Channel has no owner\n"); + ao2_ref(caps, -1); return; } - if (gH323Debug) - ast_verb(0, "Writeformat before update %s/%s\n", - ast_getformatname(ast_channel_writeformat(p->owner)), - ast_getformatname_multiple(formats, sizeof(formats), ast_channel_nativeformats(p->owner))); - if (txframes) - ast_codec_pref_setsize(&p->prefs, fmt, txframes); - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &p->prefs); + if (gH323Debug) { + struct ast_str *codec_buf = ast_str_alloca(64); + ast_verb(0, "Writeformat before update %s/%s\n", + ast_format_get_name(ast_channel_writeformat(p->owner)), + ast_format_cap_get_names(ast_channel_nativeformats(p->owner), &codec_buf)); + } + if (p->dtmfmode & H323_DTMF_RFC2833 && p->dtmfcodec) { ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, p->dtmfcodec, "audio", "telephone-event", 0); @@ -1550,7 +1559,12 @@ void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txfra p->rtp, p->dtmfcodec, "audio", "cisco-telephone-event", 0); } - ast_format_cap_set(ast_channel_nativeformats(p->owner), fmt); + if (txframes) { + ast_format_cap_set_framing(caps, txframes); + } + ast_format_cap_append(caps, fmt, 0); + ast_channel_nativeformats_set(p->owner, caps); + ao2_ref(caps, -1); ast_set_write_format(p->owner, ast_channel_writeformat(p->owner)); ast_set_read_format(p->owner, ast_channel_readformat(p->owner)); ast_channel_unlock(p->owner); @@ -1570,7 +1584,7 @@ void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt) if (gH323Debug) ast_verb(0, "--- ooh323_update_readformat %s\n", - ast_getformatname(fmt)); + ast_format_get_name(fmt)); p = find_call(call); if (!p) { @@ -1580,9 +1594,17 @@ void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt) ast_mutex_lock(&p->lock); - ast_format_copy(&(p->readformat), fmt); + ao2_replace(p->readformat, fmt); if (p->owner) { + struct ast_format_cap *caps; + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_log(LOG_ERROR, "Could not allocate capabilities structure\n"); + return; + } + while (p->owner && ast_channel_trylock(p->owner)) { ast_debug(1,"Failed to grab lock, trying again\n"); DEADLOCK_AVOIDANCE(&p->lock); @@ -1590,14 +1612,18 @@ void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt) if (!p->owner) { ast_mutex_unlock(&p->lock); ast_log(LOG_ERROR, "Channel has no owner\n"); + ao2_ref(caps, -1); return; } - if (gH323Debug) - ast_verb(0, "Readformat before update %s\n", - ast_getformatname(ast_channel_readformat(p->owner))); - ast_format_cap_set(ast_channel_nativeformats(p->owner), fmt); - ast_set_read_format(p->owner, ast_channel_readformat(p->owner)); + if (gH323Debug) { + ast_verb(0, "Readformat before update %s\n", + ast_format_get_name(ast_channel_readformat(p->owner))); + } + ast_format_cap_append(caps, fmt, 0); + ast_channel_nativeformats_set(p->owner, caps); + ao2_ref(caps, -1); + ast_set_read_format(p->owner, ast_channel_readformat(p->owner)); ast_channel_unlock(p->owner); } else ast_log(LOG_ERROR, "No owner found\n"); @@ -1854,9 +1880,8 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg) ast_copy_string(p->context, user->context, sizeof(p->context)); ast_copy_string(p->accountcode, user->accountcode, sizeof(p->accountcode)); p->amaflags = user->amaflags; - ast_format_cap_copy(p->cap, user->cap); + ast_format_cap_append_from_cap(p->cap, user->cap, AST_MEDIA_TYPE_UNKNOWN); p->g729onlyA = user->g729onlyA; - memcpy(&p->prefs, &user->prefs, sizeof(struct ast_codec_pref)); p->dtmfmode |= user->dtmfmode; p->dtmfcodec = user->dtmfcodec; p->faxdetect = user->faxdetect; @@ -1914,7 +1939,7 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg) } } - ooh323c_set_capability_for_call(call, &p->prefs, p->cap, p->dtmfmode, p->dtmfcodec, + ooh323c_set_capability_for_call(call, p->cap, p->dtmfmode, p->dtmfcodec, p->t38support, p->g729onlyA); /* Incoming call */ c = ooh323_new(p, AST_STATE_RING, p->username, 0, NULL, NULL); @@ -2088,13 +2113,14 @@ int onNewCallCreated(ooCallData *call) } if (gH323Debug) { - char prefsBuf[256]; - ast_codec_pref_string(&p->prefs, prefsBuf, sizeof(prefsBuf)); + struct ast_str *codec_buf = ast_str_alloca(64); + ast_verb(0, " Outgoing call %s(%s) - Codec prefs - %s\n", - p->username?p->username:"NULL", call->callToken, prefsBuf); + p->username?p->username:"NULL", call->callToken, + ast_format_cap_get_names(p->cap, &codec_buf)); } - ooh323c_set_capability_for_call(call, &p->prefs, p->cap, + ooh323c_set_capability_for_call(call, p->cap, p->dtmfmode, p->dtmfcodec, p->t38support, p->g729onlyA); configure_local_rtp(p, call); @@ -2284,7 +2310,7 @@ void ooh323_delete_peer(struct ooh323_peer *peer) if(peer->url) free(peer->url); if(peer->e164) free(peer->e164); - peer->cap = ast_format_cap_destroy(peer->cap); + ao2_cleanup(peer->cap); free(peer); } @@ -2311,8 +2337,7 @@ static struct ooh323_user *build_user(const char *name, struct ast_variable *v) } ast_mutex_init(&user->lock); ast_copy_string(user->name, name, sizeof(user->name)); - ast_format_cap_copy(user->cap, gCap); - memcpy(&user->prefs, &gPrefs, sizeof(user->prefs)); + ast_format_cap_append_from_cap(user->cap, gCap, AST_MEDIA_TYPE_UNKNOWN); user->rtptimeout = gRTPTimeout; user->nat = gNat; user->dtmfmode = gDTMFMode; @@ -2367,15 +2392,13 @@ static struct ooh323_user *build_user(const char *name, struct ast_variable *v) sizeof(user->rtpmaskstr)); } else user->rtpmask = NULL; } else if (!strcasecmp(v->name, "disallow")) { - ast_parse_allow_disallow(&user->prefs, - user->cap, v->value, 0); + ast_format_cap_update_by_allow_disallow(user->cap, v->value, 0); } else if (!strcasecmp(v->name, "allow")) { const char* tcodecs = v->value; if (!strcasecmp(v->value, "all")) { tcodecs = "ulaw,alaw,g729,g723,gsm"; } - ast_parse_allow_disallow(&user->prefs, - user->cap, tcodecs, 1); + ast_format_cap_update_by_allow_disallow(user->cap, tcodecs, 1); } else if (!strcasecmp(v->name, "amaflags")) { user->amaflags = ast_channel_string2amaflag(v->value); } else if (!strcasecmp(v->name, "ip") || !strcasecmp(v->name, "host")) { @@ -2461,8 +2484,7 @@ static struct ooh323_peer *build_peer(const char *name, struct ast_variable *v, } ast_mutex_init(&peer->lock); ast_copy_string(peer->name, name, sizeof(peer->name)); - ast_format_cap_copy(peer->cap, gCap); - memcpy(&peer->prefs, &gPrefs, sizeof(peer->prefs)); + ast_format_cap_append_from_cap(peer->cap, gCap, AST_MEDIA_TYPE_UNKNOWN); peer->rtptimeout = gRTPTimeout; peer->nat = gNat; ast_copy_string(peer->accountcode, gAccountcode, sizeof(peer->accountcode)); @@ -2565,15 +2587,13 @@ static struct ooh323_peer *build_peer(const char *name, struct ast_variable *v, sizeof(peer->rtpmaskstr)); } else peer->rtpmask = NULL; } else if (!strcasecmp(v->name, "disallow")) { - ast_parse_allow_disallow(&peer->prefs, peer->cap, - v->value, 0); + ast_format_cap_update_by_allow_disallow(peer->cap, v->value, 0); } else if (!strcasecmp(v->name, "allow")) { const char* tcodecs = v->value; if (!strcasecmp(v->value, "all")) { tcodecs = "ulaw,alaw,g729,g723,gsm"; } - ast_parse_allow_disallow(&peer->prefs, peer->cap, - tcodecs, 1); + ast_format_cap_update_by_allow_disallow(peer->cap, tcodecs, 1); } else if (!strcasecmp(v->name, "amaflags")) { peer->amaflags = ast_channel_string2amaflag(v->value); } else if (!strcasecmp(v->name, "roundtrip")) { @@ -2754,7 +2774,6 @@ int reload_config(int reload) struct ooh323_peer *peer = NULL; char *cat; const char *utype; - struct ast_format tmpfmt; if (gH323Debug) ast_verb(0, "--- reload_config\n"); @@ -2790,8 +2809,8 @@ int reload_config(int reload) gPort = 1720; gIP[0] = '\0'; strcpy(gCallerID, DEFAULT_H323ID); - ast_format_cap_set(gCap, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0)); - memset(&gPrefs, 0, sizeof(struct ast_codec_pref)); + ast_format_cap_remove_by_type(gCap, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append(gCap, ast_format_ulaw, 0); gDTMFMode = H323_DTMF_RFC2833; gDTMFCodec = 101; gFAXdetect = FAXDETECT_CNG; @@ -2992,13 +3011,13 @@ int reload_config(int reload) } else if (!strcasecmp(v->name, "accountcode")) { ast_copy_string(gAccountcode, v->value, sizeof(gAccountcode)); } else if (!strcasecmp(v->name, "disallow")) { - ast_parse_allow_disallow(&gPrefs, gCap, v->value, 0); + ast_format_cap_update_by_allow_disallow(gCap, v->value, 0); } else if (!strcasecmp(v->name, "allow")) { const char* tcodecs = v->value; if (!strcasecmp(v->value, "all")) { tcodecs = "ulaw,alaw,g729,g723,gsm"; } - ast_parse_allow_disallow(&gPrefs, gCap, tcodecs, 1); + ast_format_cap_update_by_allow_disallow(gCap, tcodecs, 1); } else if (!strcasecmp(v->name, "dtmfmode")) { if (!strcasecmp(v->value, "inband")) gDTMFMode = H323_DTMF_INBAND; @@ -3150,9 +3169,6 @@ static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struc peer->h245tunneling?"yes":"no"); ast_cli(a->fd, "%-15s%s\n", "DirectRTP", peer->directrtp ? "yes" : "no"); ast_cli(a->fd, "%-15s%s\n", "EarlyDirectRTP", peer->earlydirect ? "yes" : "no"); - ast_cli(a->fd, "%-15.15s%s", "Format Prefs: ", "("); - print_codec_to_cli(a->fd, &peer->prefs); - ast_cli(a->fd, ")\n"); ast_cli(a->fd, "%-15.15s", "DTMF Mode: "); if (peer->dtmfmode & H323_DTMF_CISCO) { ast_cli(a->fd, "%s\n", "cisco"); @@ -3214,7 +3230,7 @@ static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struc static char *handle_cli_ooh323_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct ooh323_peer *prev = NULL, *peer = NULL; - char formats[FORMAT_STRING_SIZE]; + struct ast_str *codec_buf = ast_str_alloca(64); char ip_port[30]; #define FORMAT "%-15.15s %-15.15s %-23.23s %-s\n" @@ -3239,10 +3255,10 @@ static char *handle_cli_ooh323_show_peers(struct ast_cli_entry *e, int cmd, stru while (peer) { ast_mutex_lock(&peer->lock); snprintf(ip_port, sizeof(ip_port), "%s:%d", peer->ip, peer->port); - ast_cli(a->fd, FORMAT, peer->name, + ast_cli(a->fd, FORMAT, peer->name, peer->accountcode, ip_port, - ast_getformatname_multiple(formats,FORMAT_STRING_SIZE,peer->cap)); + ast_format_cap_get_names(peer->cap, &codec_buf)); prev = peer; peer = peer->next; ast_mutex_unlock(&prev->lock); @@ -3253,24 +3269,6 @@ static char *handle_cli_ooh323_show_peers(struct ast_cli_entry *e, int cmd, stru return CLI_SUCCESS; } -/*! \brief Print codec list from preference to CLI/manager */ -static void print_codec_to_cli(int fd, struct ast_codec_pref *pref) -{ - int x; - struct ast_format tmpfmt; - for (x = 0; x < 32; x++) { - ast_codec_pref_index(pref, x, &tmpfmt); - if (!tmpfmt.id) - break; - ast_cli(fd, "%s", ast_getformatname(&tmpfmt)); - ast_cli(fd, ":%d", pref->framing[x]); - if (x < 31 && ast_codec_pref_index(pref, x + 1, &tmpfmt)) - ast_cli(fd, ","); - } - if (!x) - ast_cli(fd, "none"); -} - static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct ooh323_user *prev = NULL, *user = NULL; @@ -3309,9 +3307,6 @@ static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struc user->h245tunneling?"yes":"no"); ast_cli(a->fd, "%-15s%s\n", "DirectRTP", user->directrtp ? "yes" : "no"); ast_cli(a->fd, "%-15s%s\n", "EarlyDirectRTP", user->earlydirect ? "yes" : "no"); - ast_cli(a->fd, "%-15.15s%s", "Format Prefs: ", "("); - print_codec_to_cli(a->fd, &user->prefs); - ast_cli(a->fd, ")\n"); ast_cli(a->fd, "%-15.15s", "DTMF Mode: "); if (user->dtmfmode & H323_DTMF_CISCO) { ast_cli(a->fd, "%s\n", "cisco"); @@ -3374,7 +3369,7 @@ static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struc static char *handle_cli_ooh323_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct ooh323_user *prev = NULL, *user = NULL; - char formats[FORMAT_STRING_SIZE]; + struct ast_str *codec_buf = ast_str_alloca(64); #define FORMAT1 "%-15.15s %-15.15s %-15.15s %-s\n" switch (cmd) { @@ -3401,7 +3396,7 @@ static char *handle_cli_ooh323_show_users(struct ast_cli_entry *e, int cmd, stru ast_mutex_lock(&user->lock); ast_cli(a->fd, FORMAT1, user->name, user->accountcode, user->context, - ast_getformatname_multiple(formats, FORMAT_STRING_SIZE, user->cap)); + ast_format_cap_get_names(user->cap, &codec_buf)); prev = user; user = user->next; ast_mutex_unlock(&prev->lock); @@ -3508,6 +3503,7 @@ static char *handle_cli_ooh323_show_gk(struct ast_cli_entry *e, int cmd, struct static char *handle_cli_ooh323_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { char value[FORMAT_STRING_SIZE]; + struct ast_str *codec_buf = ast_str_alloca(64); ooAliases *pAlias = NULL, *pAliasNext = NULL;; switch (cmd) { @@ -3556,7 +3552,7 @@ static char *handle_cli_ooh323_show_config(struct ast_cli_entry *e, int cmd, str ast_cli(a->fd, "%-20s%s\n", "H.323 LogFile:", gLogFile); ast_cli(a->fd, "%-20s%s\n", "Context:", gContext); ast_cli(a->fd, "%-20s%s\n", "Capability:", - ast_getformatname_multiple(value,FORMAT_STRING_SIZE,gCap)); + ast_format_cap_get_names(gCap, &codec_buf)); ast_cli(a->fd, "%-20s", "DTMF Mode: "); if (gDTMFMode & H323_DTMF_CISCO) { ast_cli(a->fd, "%s\n", "cisco"); @@ -3737,7 +3733,6 @@ static int load_module(void) { struct ooAliases * pNewAlias = NULL; struct ooh323_peer *peer = NULL; - struct ast_format tmpfmt; OOH225MsgCallbacks h225Callbacks = {0, 0, 0, 0}; OOH323CALLBACKS h323Callbacks = { @@ -3753,14 +3748,16 @@ static int load_module(void) .onModeChanged = onModeChanged, .onMediaChanged = (cb_OnMediaChanged) setup_rtp_remote, }; - if (!(gCap = ast_format_cap_alloc(0))) { + if (!(gCap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_FAILURE; } - if (!(ooh323_tech.capabilities = ast_format_cap_alloc(0))) { + if (!(ooh323_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { + ao2_ref(gCap, -1); + gCap = NULL; return AST_MODULE_LOAD_FAILURE; } - ast_format_cap_add(gCap, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0)); - ast_format_cap_add_all(ooh323_tech.capabilities); + ast_format_cap_append(gCap, ast_format_ulaw, 0); + ast_format_cap_append_by_type(ooh323_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN); myself = ast_module_info->self; @@ -3789,12 +3786,20 @@ static int load_module(void) if (OO_OK != ooH323EpInitialize(OO_CALLMODE_AUDIOCALL, gLogFile)) { ast_log(LOG_ERROR, "Failed to initialize OOH323 endpoint-" "OOH323 Disabled\n"); + ao2_ref(gCap, -1); + gCap = NULL; + ao2_ref(ooh323_tech.capabilities, -1); + ooh323_tech.capabilities = NULL; return AST_MODULE_LOAD_FAILURE; } /* Make sure we can register our OOH323 channel type */ if (ast_channel_register(&ooh323_tech)) { ast_log(LOG_ERROR, "Unable to register channel class %s\n", type); + ao2_ref(gCap, -1); + gCap = NULL; + ao2_ref(ooh323_tech.capabilities, -1); + ooh323_tech.capabilities = NULL; return AST_MODULE_LOAD_FAILURE; } ast_rtp_glue_register(&ooh323_rtp); @@ -3876,8 +3881,12 @@ static int load_module(void) ooH323EpSetH323Callbacks(h323Callbacks); /* Add endpoint capabilities */ - if (ooh323c_set_capability(&gPrefs, gCap, gDTMFMode, gDTMFCodec) < 0) { + if (ooh323c_set_capability(gCap, gDTMFMode, gDTMFCodec) < 0) { ast_log(LOG_ERROR, "Capabilities failure for OOH323. OOH323 Disabled.\n"); + ao2_ref(gCap, -1); + gCap = NULL; + ao2_ref(ooh323_tech.capabilities, -1); + ooh323_tech.capabilities = NULL; return 1; } @@ -3887,6 +3896,10 @@ static int load_module(void) "OOH323 DISABLED\n"); ooH323EpDestroy(); + ao2_ref(gCap, -1); + gCap = NULL; + ao2_ref(ooh323_tech.capabilities, -1); + ooh323_tech.capabilities = NULL; return 1; } @@ -3894,6 +3907,10 @@ static int load_module(void) ast_log(LOG_ERROR, "Failed to start OOH323 stack thread. " "OOH323 DISABLED\n"); ooH323EpDestroy(); + ao2_ref(gCap, -1); + gCap = NULL; + ao2_ref(ooh323_tech.capabilities, -1); + ooh323_tech.capabilities = NULL; return 1; } /* And start the monitor for the first time */ @@ -4142,7 +4159,9 @@ int ooh323_destroy(struct ooh323_pvt *p) ast_mutex_unlock(&cur->lock); ast_mutex_destroy(&cur->lock); - cur->cap = ast_format_cap_destroy(cur->cap); + ao2_cleanup(cur->writeformat); + ao2_cleanup(cur->readformat); + ao2_cleanup(cur->cap); ast_free(cur); } @@ -4207,7 +4226,7 @@ int delete_users() free(prev->rtpmask); } } - prev->cap = ast_format_cap_destroy(prev->cap); + ao2_cleanup(prev->cap); free(prev); if (cur == userl.users) { break; @@ -4335,8 +4354,10 @@ static int unload_module(void) ast_verb(0, "+++ ooh323 unload_module \n"); } - gCap = ast_format_cap_destroy(gCap); - ooh323_tech.capabilities = ast_format_cap_destroy(ooh323_tech.capabilities); + ao2_ref(gCap, -1); + gCap = NULL; + ao2_ref(ooh323_tech.capabilities, -1); + ooh323_tech.capabilities = NULL; return 0; } @@ -4348,8 +4369,11 @@ static void ooh323_get_codec(struct ast_channel *chan, struct ast_format_cap *re } if (p) { - ast_format_cap_append(result, ast_format_cap_is_empty(ast_channel_nativeformats(chan)) ? - (ast_format_cap_is_empty(p->cap) ? NULL : p->cap) : ast_channel_nativeformats(chan)); + if (ast_format_cap_count(ast_channel_nativeformats(chan))) { + ast_format_cap_append_from_cap(result, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_UNKNOWN); + } else if (ast_format_cap_count(p->cap)) { + ast_format_cap_append_from_cap(result, p->cap, AST_MEDIA_TYPE_UNKNOWN); + } } if (gH323Debug) { @@ -4423,56 +4447,28 @@ static enum ast_rtp_glue_result ooh323_get_vrtp_peer(struct ast_channel *chan, s return res; } - -int ooh323_update_capPrefsOrderForCall - (ooCallData *call, struct ast_codec_pref *prefs) -{ - int i = 0; - struct ast_format tmpfmt; - - ast_codec_pref_index(prefs, i, &tmpfmt); - - ooResetCapPrefs(call); - while (tmpfmt.id) { - ooAppendCapToCapPrefs(call, ooh323_convertAsteriskCapToH323Cap(&tmpfmt)); - ast_codec_pref_index(prefs, ++i, &tmpfmt); - } - - return 0; -} - - int ooh323_convertAsteriskCapToH323Cap(struct ast_format *format) { - switch (format->id) { - case AST_FORMAT_ULAW: + if (ast_format_cmp(format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) { return OO_G711ULAW64K; - case AST_FORMAT_ALAW: + } else if (ast_format_cmp(format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) { return OO_G711ALAW64K; - case AST_FORMAT_GSM: + } else if (ast_format_cmp(format, ast_format_gsm) == AST_FORMAT_CMP_EQUAL) { return OO_GSMFULLRATE; - -#ifdef AST_FORMAT_AMRNB - case AST_FORMAT_AMRNB: - return OO_AMRNB; -#endif -#ifdef AST_FORMAT_SPEEX - case AST_FORMAT_SPEEX: + } else if (ast_format_cmp(format, ast_format_speex) == AST_FORMAT_CMP_EQUAL) { return OO_SPEEX; -#endif - - case AST_FORMAT_G729A: + } else if (ast_format_cmp(format, ast_format_g729) == AST_FORMAT_CMP_EQUAL) { return OO_G729A; - case AST_FORMAT_G726: + } else if (ast_format_cmp(format, ast_format_g726) == AST_FORMAT_CMP_EQUAL) { return OO_G726; - case AST_FORMAT_G726_AAL2: + } else if (ast_format_cmp(format, ast_format_g726_aal2) == AST_FORMAT_CMP_EQUAL) { return OO_G726AAL2; - case AST_FORMAT_G723_1: + } else if (ast_format_cmp(format, ast_format_g723) == AST_FORMAT_CMP_EQUAL) { return OO_G7231; - case AST_FORMAT_H263: + } else if (ast_format_cmp(format, ast_format_h263) == AST_FORMAT_CMP_EQUAL) { return OO_H263VIDEO; - default: - ast_log(LOG_NOTICE, "Don't know how to deal with mode %s\n", ast_getformatname(format)); + } else { + ast_log(LOG_NOTICE, "Don't know how to deal with mode %s\n", ast_format_get_name(format)); return -1; } } @@ -4551,9 +4547,6 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call) struct ast_sockaddr tmp; ooMediaInfo mediaInfo; int x; - struct ast_format tmpfmt; - - ast_format_clear(&tmpfmt); if (gH323Debug) ast_verb(0, "--- configure_local_rtp\n"); @@ -4599,7 +4592,10 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call) ast_channel_unlock(p->owner); if (p->rtp) { - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &p->prefs); + if (p->cap) { + ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(p->rtp), + ast_format_cap_get_framing(p->cap)); + } if (p->nat) { ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_NAT, 1); } @@ -4636,9 +4632,11 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call) ast_copy_string(mediaInfo.lMediaIP, lhost, sizeof(mediaInfo.lMediaIP)); mediaInfo.lMediaPort = lport; mediaInfo.lMediaCntrlPort = mediaInfo.lMediaPort + 1; - for (x = 0; ast_codec_pref_index(&p->prefs, x, &tmpfmt); x++) { + for (x = 0; x < ast_format_cap_count(p->cap); x++) { + struct ast_format *format = ast_format_cap_get_format(p->cap, x); + strcpy(mediaInfo.dir, "transmit"); - mediaInfo.cap = ooh323_convertAsteriskCapToH323Cap(&tmpfmt); + mediaInfo.cap = ooh323_convertAsteriskCapToH323Cap(format); ooAddMediaInfo(call, mediaInfo); strcpy(mediaInfo.dir, "receive"); ooAddMediaInfo(call, mediaInfo); @@ -4655,6 +4653,8 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call) strcpy(mediaInfo.dir, "receive"); ooAddMediaInfo(call, mediaInfo); } + + ao2_ref(format, -1); } if (p->udptl) { @@ -4738,7 +4738,7 @@ void setup_rtp_connection(ooCallData *call, const char *remoteIp, int remotePort ast_sockaddr_set_port(&tmp, remotePort); ast_rtp_instance_set_remote_address(p->rtp, &tmp); - if (p->writeformat.id == AST_FORMAT_G726_AAL2) { + if (ast_format_cmp(p->writeformat, ast_format_g726_aal2) == AST_FORMAT_CMP_EQUAL) { ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, 2, "audio", "G726-32", AST_RTP_OPT_G726_NONSTANDARD); } @@ -4955,15 +4955,24 @@ struct ast_frame *ooh323_rtp_read(struct ast_channel *ast, struct ooh323_pvt *p) if (f && p->owner && !p->faxmode && (f->frametype == AST_FRAME_VOICE)) { /* We already hold the channel lock */ - if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(p->owner), &f->subclass.format))) { - ast_debug(1, "Oooh, voice format changed to %s\n", ast_getformatname(&f->subclass.format)); - ast_format_cap_set(ast_channel_nativeformats(p->owner), &f->subclass.format); + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(p->owner), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_format_cap *caps; + + ast_debug(1, "Oooh, voice format changed to %s\n", ast_format_get_name(f->subclass.format)); + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (caps) { + ast_format_cap_append(caps, f->subclass.format, 0); + ast_channel_nativeformats_set(p->owner, caps); + ao2_ref(caps, -1); + } ast_set_read_format(p->owner, ast_channel_readformat(p->owner)); ast_set_write_format(p->owner, ast_channel_writeformat(p->owner)); } if (((p->dtmfmode & H323_DTMF_INBAND) || (p->faxdetect & FAXDETECT_CNG)) && p->vad && - (f->subclass.format.id == AST_FORMAT_SLINEAR || f->subclass.format.id == AST_FORMAT_ALAW || - f->subclass.format.id == AST_FORMAT_ULAW)) { + ((ast_format_cmp(f->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) || + (ast_format_cmp(f->subclass.format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) || + (ast_format_cmp(f->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL))) { dfr = ast_frdup(f); dfr = ast_dsp_process(p->owner, p->vad, dfr); } diff --git a/addons/chan_ooh323.h b/addons/chan_ooh323.h index 689adced2..89caaff63 100644 --- a/addons/chan_ooh323.h +++ b/addons/chan_ooh323.h @@ -65,6 +65,7 @@ #include "asterisk/format_cap.h" #include "asterisk/udptl.h" #include "asterisk/stasis_channels.h" +#include "asterisk/format_cache.h" #include "ootypes.h" #include "ooUtils.h" @@ -104,9 +105,6 @@ struct ast_frame *ooh323_rtp_read void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txframes); void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt); -int ooh323_update_capPrefsOrderForCall - (ooCallData *call, struct ast_codec_pref *prefs); - int ooh323_convertAsteriskCapToH323Cap(struct ast_format *format); int ooh323_convert_hangupcause_asteriskToH323(int cause); diff --git a/addons/format_mp3.c b/addons/format_mp3.c index 78fcc28c5..4c98789ab 100644 --- a/addons/format_mp3.c +++ b/addons/format_mp3.c @@ -42,6 +42,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/mod_format.h" #include "asterisk/logger.h" +#include "asterisk/format_cache.h" #define MP3_BUFLEN 320 #define MP3_SCACHE 16384 @@ -229,10 +230,7 @@ static struct ast_frame *mp3_read(struct ast_filestream *s, int *whennext) p->offset += p->buflen; delay = p->buflen / 2; - s->fr.frametype = AST_FRAME_VOICE; - ast_format_set(&s->fr.subclass.format, AST_FORMAT_SLINEAR, 0); AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, p->buflen); - s->fr.mallocd = 0; s->fr.samples = delay; *whennext = delay; return &s->fr; @@ -318,7 +316,7 @@ static struct ast_format_def mp3_f = { static int load_module(void) { - ast_format_set(&mp3_f.format, AST_FORMAT_SLINEAR, 0); + mp3_f.format = ast_format_slin; InitMP3Constants(); return ast_format_def_register(&mp3_f); } diff --git a/addons/ooh323cDriver.c b/addons/ooh323cDriver.c index dd127a499..bceb07745 100644 --- a/addons/ooh323cDriver.c +++ b/addons/ooh323cDriver.c @@ -225,17 +225,17 @@ int ooh323c_stop_stack_thread(void) } int ooh323c_set_capability - (struct ast_codec_pref *prefs, struct ast_format_cap *cap, int dtmf, int dtmfcodec) + (struct ast_format_cap *cap, int dtmf, int dtmfcodec) { int ret = 0, x; - struct ast_format tmpfmt; if (gH323Debug) { ast_verb(0, "\tAdding capabilities to H323 endpoint\n"); } - for(x=0; ast_codec_pref_index(prefs, x, &tmpfmt); x++) + for(x=0; x<ast_format_cap_count(cap); x++) { - if(tmpfmt.id == AST_FORMAT_ULAW) + struct ast_format *format = ast_format_cap_get_format(cap, x); + if(ast_format_cmp(format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding g711 ulaw capability to H323 endpoint\n"); @@ -246,7 +246,7 @@ int ooh323c_set_capability &ooh323c_stop_receive_channel, &ooh323c_stop_transmit_channel); } - if(tmpfmt.id == AST_FORMAT_ALAW) + if(ast_format_cmp(format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding g711 alaw capability to H323 endpoint\n"); @@ -258,7 +258,7 @@ int ooh323c_set_capability &ooh323c_stop_transmit_channel); } - if(tmpfmt.id == AST_FORMAT_G729A) + if(ast_format_cmp(format, ast_format_g729) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding g729A capability to H323 endpoint\n"); @@ -287,7 +287,7 @@ int ooh323c_set_capability &ooh323c_stop_transmit_channel); } - if(tmpfmt.id == AST_FORMAT_G723_1) + if(ast_format_cmp(format, ast_format_g723) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding g7231 capability to H323 endpoint\n"); @@ -300,7 +300,7 @@ int ooh323c_set_capability } - if(tmpfmt.id == AST_FORMAT_G726) + if(ast_format_cmp(format, ast_format_g726) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding g726 capability to H323 endpoint\n"); @@ -313,7 +313,7 @@ int ooh323c_set_capability } - if(tmpfmt.id == AST_FORMAT_G726_AAL2) + if(ast_format_cmp(format, ast_format_g726_aal2) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding g726aal2 capability to H323 endpoint\n"); @@ -326,7 +326,7 @@ int ooh323c_set_capability } - if(tmpfmt.id == AST_FORMAT_H263) + if(ast_format_cmp(format, ast_format_h263) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding h263 capability to H323 endpoint\n"); @@ -339,7 +339,7 @@ int ooh323c_set_capability } - if(tmpfmt.id == AST_FORMAT_GSM) + if(ast_format_cmp(format, ast_format_gsm) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding gsm capability to H323 endpoint\n"); @@ -351,24 +351,8 @@ int ooh323c_set_capability &ooh323c_stop_transmit_channel); } - -#ifdef AST_FORMAT_AMRNB - if(tmpfmt.id == AST_FORMAT_AMRNB) - { - if (gH323Debug) { - ast_verb(0, "\tAdding amr nb capability to H323 endpoint\n"); - } - ret = ooH323EpAddAMRNBCapability(OO_AMRNB, 4, 4, FALSE, - OORXANDTX, &ooh323c_start_receive_channel, - &ooh323c_start_transmit_channel, - &ooh323c_stop_receive_channel, - &ooh323c_stop_transmit_channel); - - } -#endif -#ifdef AST_FORMAT_SPEEX - if(tmpfmt.id == AST_FORMAT_SPEEX) + if(ast_format_cmp(format, ast_format_speex) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding speex capability to H323 endpoint\n"); @@ -380,8 +364,8 @@ int ooh323c_set_capability &ooh323c_stop_transmit_channel); } -#endif - + + ao2_ref(format, -1); } if(dtmf & H323_DTMF_CISCO) @@ -397,11 +381,10 @@ int ooh323c_set_capability } int ooh323c_set_capability_for_call - (ooCallData *call, struct ast_codec_pref *prefs, struct ast_format_cap *cap, int dtmf, int dtmfcodec, + (ooCallData *call, struct ast_format_cap *cap, int dtmf, int dtmfcodec, int t38support, int g729onlyA) { int ret = 0, x, txframes; - struct ast_format tmpfmt; if (gH323Debug) { ast_verb(0, "\tAdding capabilities to call(%s, %s)\n", call->callType, call->callToken); @@ -423,15 +406,16 @@ int ooh323c_set_capability_for_call &ooh323c_stop_transmit_datachannel, 0); - for(x=0; ast_codec_pref_index(prefs, x, &tmpfmt); x++) + for(x=0; x<ast_format_cap_count(cap); x++) { - if(tmpfmt.id == AST_FORMAT_ULAW) + struct ast_format *format = ast_format_cap_get_format(cap, x); + if(ast_format_cmp(format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding g711 ulaw capability to call(%s, %s)\n", call->callType, call->callToken); } - txframes = prefs->framing[x]; + txframes = ast_format_cap_get_format_framing(cap, format); ret= ooCallAddG711Capability(call, OO_G711ULAW64K, txframes, txframes, OORXANDTX, &ooh323c_start_receive_channel, @@ -439,13 +423,13 @@ int ooh323c_set_capability_for_call &ooh323c_stop_receive_channel, &ooh323c_stop_transmit_channel); } - if(tmpfmt.id == AST_FORMAT_ALAW) + if(ast_format_cmp(format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding g711 alaw capability to call(%s, %s)\n", call->callType, call->callToken); } - txframes = prefs->framing[x]; + txframes = ast_format_cap_get_format_framing(cap, format); ret= ooCallAddG711Capability(call, OO_G711ALAW64K, txframes, txframes, OORXANDTX, &ooh323c_start_receive_channel, @@ -454,13 +438,13 @@ int ooh323c_set_capability_for_call &ooh323c_stop_transmit_channel); } - if(tmpfmt.id == AST_FORMAT_G726) + if(ast_format_cmp(format, ast_format_g726) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding g726 capability to call (%s, %s)\n", call->callType, call->callToken); } - txframes = prefs->framing[x]; + txframes = ast_format_cap_get_format_framing(cap, format); ret = ooCallAddG726Capability(call, OO_G726, txframes, grxframes, FALSE, OORXANDTX, &ooh323c_start_receive_channel, &ooh323c_start_transmit_channel, @@ -469,13 +453,13 @@ int ooh323c_set_capability_for_call } - if(tmpfmt.id == AST_FORMAT_G726_AAL2) + if(ast_format_cmp(format, ast_format_g726_aal2) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding g726aal2 capability to call (%s, %s)\n", call->callType, call->callToken); } - txframes = prefs->framing[x]; + txframes = ast_format_cap_get_format_framing(cap, format); ret = ooCallAddG726Capability(call, OO_G726AAL2, txframes, grxframes, FALSE, OORXANDTX, &ooh323c_start_receive_channel, &ooh323c_start_transmit_channel, @@ -484,10 +468,10 @@ int ooh323c_set_capability_for_call } - if(tmpfmt.id == AST_FORMAT_G729A) + if(ast_format_cmp(format, ast_format_g729) == AST_FORMAT_CMP_EQUAL) { - txframes = (prefs->framing[x])/10; + txframes = (ast_format_cap_get_format_framing(cap, format))/10; if (gH323Debug) { ast_verb(0, "\tAdding g729A capability to call(%s, %s)\n", call->callType, call->callToken); @@ -520,7 +504,7 @@ int ooh323c_set_capability_for_call } - if(tmpfmt.id == AST_FORMAT_G723_1) + if(ast_format_cmp(format, ast_format_g723) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding g7231 capability to call (%s, %s)\n", @@ -534,7 +518,7 @@ int ooh323c_set_capability_for_call } - if(tmpfmt.id == AST_FORMAT_H263) + if(ast_format_cmp(format, ast_format_h263) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding h263 capability to call (%s, %s)\n", @@ -548,7 +532,7 @@ int ooh323c_set_capability_for_call } - if(tmpfmt.id == AST_FORMAT_GSM) + if(ast_format_cmp(format, ast_format_gsm) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding gsm capability to call(%s, %s)\n", @@ -561,22 +545,7 @@ int ooh323c_set_capability_for_call &ooh323c_stop_transmit_channel); } -#ifdef AST_FORMAT_AMRNB - if(tmpfmt.id == AST_FORMAT_AMRNB) - { - if (gH323Debug) { - ast_verb(0, "\tAdding AMR capability to call(%s, %s)\n", - call->callType, call->callToken); - } - ret = ooCallAddAMRNBCapability(call, OO_AMRNB, 4, 4, FALSE, - OORXANDTX, &ooh323c_start_receive_channel, - &ooh323c_start_transmit_channel, - &ooh323c_stop_receive_channel, - &ooh323c_stop_transmit_channel); - } -#endif -#ifdef AST_FORMAT_SPEEX - if(tmpfmt.id == AST_FORMAT_SPEEX) + if(ast_format_cmp(format, ast_format_speex) == AST_FORMAT_CMP_EQUAL) { if (gH323Debug) { ast_verb(0, "\tAdding Speex capability to call(%s, %s)\n", @@ -588,7 +557,8 @@ int ooh323c_set_capability_for_call &ooh323c_stop_receive_channel, &ooh323c_stop_transmit_channel); } -#endif + + ao2_ref(format, -1); } return ret; } @@ -622,9 +592,9 @@ int ooh323c_set_aliases(ooAliases * aliases) int ooh323c_start_receive_channel(ooCallData *call, ooLogicalChannel *pChannel) { - struct ast_format tmpfmt; - convertH323CapToAsteriskCap(pChannel->chanCap->cap, &tmpfmt); - if(tmpfmt.id) { + struct ast_format *tmpfmt = NULL; + tmpfmt = convertH323CapToAsteriskCap(pChannel->chanCap->cap); + if(tmpfmt) { /* ooh323_set_read_format(call, fmt); */ }else{ ast_log(LOG_ERROR, "Invalid capability type for receive channel %s\n", @@ -636,19 +606,17 @@ int ooh323c_start_receive_channel(ooCallData *call, ooLogicalChannel *pChannel) int ooh323c_start_transmit_channel(ooCallData *call, ooLogicalChannel *pChannel) { - struct ast_format tmpfmt; - convertH323CapToAsteriskCap(pChannel->chanCap->cap, &tmpfmt); - if(tmpfmt.id) { - switch (tmpfmt.id) { - case AST_FORMAT_ALAW: - case AST_FORMAT_ULAW: - ooh323_set_write_format(call, &tmpfmt, ((OOCapParams *)(pChannel->chanCap->params))->txframes); - break; - case AST_FORMAT_G729A: - ooh323_set_write_format(call, &tmpfmt, ((OOCapParams *)(pChannel->chanCap->params))->txframes*10); - break; - default: - ooh323_set_write_format(call, &tmpfmt, 0); + struct ast_format *tmpfmt = NULL; + tmpfmt = convertH323CapToAsteriskCap(pChannel->chanCap->cap); + + if (tmpfmt) { + if ((ast_format_cmp(tmpfmt, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) || + (ast_format_cmp(tmpfmt, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL)) { + ooh323_set_write_format(call, tmpfmt, ((OOCapParams *)(pChannel->chanCap->params))->txframes); + } else if (ast_format_cmp(tmpfmt, ast_format_g729) == AST_FORMAT_CMP_EQUAL) { + ooh323_set_write_format(call, tmpfmt, ((OOCapParams *)(pChannel->chanCap->params))->txframes*10); + } else { + ooh323_set_write_format(call, tmpfmt, 0); } }else{ ast_log(LOG_ERROR, "Invalid capability type for receive channel %s\n", @@ -693,41 +661,32 @@ int ooh323c_stop_transmit_datachannel(ooCallData *call, ooLogicalChannel *pChann return 1; } -struct ast_format *convertH323CapToAsteriskCap(int cap, struct ast_format *result) +struct ast_format *convertH323CapToAsteriskCap(int cap) { - ast_format_clear(result); switch(cap) { case OO_G711ULAW64K: - return ast_format_set(result, AST_FORMAT_ULAW, 0); + return ast_format_ulaw; case OO_G711ALAW64K: - return ast_format_set(result, AST_FORMAT_ALAW, 0); + return ast_format_alaw; case OO_GSMFULLRATE: - return ast_format_set(result, AST_FORMAT_GSM, 0); - -#ifdef AST_FORMAT_AMRNB - case OO_AMRNB: - return ast_format_set(result, AST_FORMAT_AMRNB, 0); -#endif -#ifdef AST_FORMAT_SPEEX + return ast_format_gsm; case OO_SPEEX: - return ast_format_set(result, AST_FORMAT_SPEEX, 0); -#endif - + return ast_format_speex; case OO_G729: - return ast_format_set(result, AST_FORMAT_G729A, 0); + return ast_format_g729; case OO_G729A: - return ast_format_set(result, AST_FORMAT_G729A, 0); + return ast_format_g729; case OO_G729B: - return ast_format_set(result, AST_FORMAT_G729A, 0); + return ast_format_g729; case OO_G7231: - return ast_format_set(result, AST_FORMAT_G723_1, 0); + return ast_format_g723; case OO_G726: - return ast_format_set(result, AST_FORMAT_G726, 0); + return ast_format_g726; case OO_G726AAL2: - return ast_format_set(result, AST_FORMAT_G726_AAL2, 0); + return ast_format_g726_aal2; case OO_H263VIDEO: - return ast_format_set(result, AST_FORMAT_H263, 0); + return ast_format_h263; default: ast_debug(1, "Cap %d is not supported by driver yet\n", cap); return NULL; diff --git a/addons/ooh323cDriver.h b/addons/ooh323cDriver.h index af03eeaea..98198019a 100644 --- a/addons/ooh323cDriver.h +++ b/addons/ooh323cDriver.h @@ -37,9 +37,9 @@ int ooh323c_stop_stack_thread(void); int ooh323c_start_call_thread(ooCallData *call); int ooh323c_stop_call_thread(ooCallData *call); int ooh323c_set_capability - (struct ast_codec_pref *prefs, struct ast_format_cap *cap, int dtmf, int dtmfcodec); -struct ast_format *convertH323CapToAsteriskCap(int cap, struct ast_format *format); + (struct ast_format_cap *cap, int dtmf, int dtmfcodec); +struct ast_format *convertH323CapToAsteriskCap(int cap); int ooh323c_set_capability_for_call - (ooCallData *call, struct ast_codec_pref *prefs, struct ast_format_cap *cap, int dtmf, int dtmfcodec, + (ooCallData *call, struct ast_format_cap *cap, int dtmf, int dtmfcodec, int t38support, int g729onlyA); #endif diff --git a/apps/app_agent_pool.c b/apps/app_agent_pool.c index 5095001cf..f531c1613 100644 --- a/apps/app_agent_pool.c +++ b/apps/app_agent_pool.c @@ -2136,8 +2136,8 @@ static int agent_login_exec(struct ast_channel *chan, const char *data) } ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", agent->username, - ast_getformatname(ast_channel_readformat(chan)), - ast_getformatname(ast_channel_writeformat(chan))); + ast_format_get_name(ast_channel_readformat(chan)), + ast_format_get_name(ast_channel_writeformat(chan))); ast_channel_lock(chan); send_agent_login(chan, agent->username); ast_channel_unlock(chan); diff --git a/apps/app_alarmreceiver.c b/apps/app_alarmreceiver.c index 9063e1a60..4f9de364d 100644 --- a/apps/app_alarmreceiver.c +++ b/apps/app_alarmreceiver.c @@ -65,6 +65,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/astdb.h" #include "asterisk/utils.h" #include "asterisk/indications.h" +#include "asterisk/format_cache.h" #define ALMRCV_CONFIG "alarmreceiver.conf" #define UNKNOWN_FORMAT "UNKNOWN_FORMAT" @@ -798,19 +799,19 @@ static int alarmreceiver_exec(struct ast_channel *chan, const char *data) char signalling_type[64] = ""; event_node_t *event_head = NULL; - if (ast_channel_writeformat(chan)->id != AST_FORMAT_ALAW - && ast_channel_writeformat(chan)->id != AST_FORMAT_ULAW) { + if ((ast_format_cmp(ast_channel_writeformat(chan), ast_format_ulaw) == AST_FORMAT_CMP_NOT_EQUAL) && + (ast_format_cmp(ast_channel_writeformat(chan), ast_format_alaw) == AST_FORMAT_CMP_NOT_EQUAL)) { ast_verb(4, "AlarmReceiver: Setting write format to Mu-law\n"); - if (ast_set_write_format_by_id(chan,AST_FORMAT_ULAW)) { + if (ast_set_write_format(chan, ast_format_ulaw)) { ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",ast_channel_name(chan)); return -1; } } - if (ast_channel_readformat(chan)->id != AST_FORMAT_ALAW - && ast_channel_readformat(chan)->id != AST_FORMAT_ULAW) { + if ((ast_format_cmp(ast_channel_readformat(chan), ast_format_ulaw) == AST_FORMAT_CMP_NOT_EQUAL) && + (ast_format_cmp(ast_channel_readformat(chan), ast_format_alaw) == AST_FORMAT_CMP_NOT_EQUAL)) { ast_verb(4, "AlarmReceiver: Setting read format to Mu-law\n"); - if (ast_set_read_format_by_id(chan,AST_FORMAT_ULAW)) { + if (ast_set_read_format(chan, ast_format_ulaw)) { ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",ast_channel_name(chan)); return -1; } diff --git a/apps/app_amd.c b/apps/app_amd.c index d8f26b49b..3dd8cc617 100644 --- a/apps/app_amd.c +++ b/apps/app_amd.c @@ -52,6 +52,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/pbx.h" #include "asterisk/config.h" #include "asterisk/app.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <application name="AMD" language="en_US"> @@ -163,7 +164,7 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data) struct ast_frame *f = NULL; struct ast_dsp *silenceDetector = NULL; int dspsilence = 0, framelength = 0; - struct ast_format readFormat; + RAII_VAR(struct ast_format *, readFormat, NULL, ao2_cleanup); int inInitialSilence = 1; int inGreeting = 0; int voiceDuration = 0; @@ -202,11 +203,10 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data) AST_APP_ARG(argMaximumWordLength); ); - ast_format_clear(&readFormat); ast_verb(3, "AMD: %s %s %s (Fmt: %s)\n", ast_channel_name(chan), S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, "(N/A)"), S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, "(N/A)"), - ast_getformatname(ast_channel_readformat(chan))); + ast_format_get_name(ast_channel_readformat(chan))); /* Lets parse the arguments. */ if (!ast_strlen_zero(parse)) { @@ -255,8 +255,8 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data) minimumWordLength, betweenWordsSilence, maximumNumberOfWords, silenceThreshold, maximumWordLength); /* Set read format to signed linear so we get signed linear frames in */ - ast_format_copy(&readFormat, ast_channel_readformat(chan)); - if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR) < 0 ) { + readFormat = ao2_bump(ast_channel_readformat(chan)); + if (ast_set_read_format(chan, ast_format_slin) < 0 ) { ast_log(LOG_WARNING, "AMD: Channel [%s]. Unable to set to linear mode, giving up\n", ast_channel_name(chan)); pbx_builtin_setvar_helper(chan , "AMDSTATUS", ""); pbx_builtin_setvar_helper(chan , "AMDCAUSE", ""); @@ -289,7 +289,7 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data) if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_NULL || f->frametype == AST_FRAME_CNG) { /* If the total time exceeds the analysis time then give up as we are not too sure */ if (f->frametype == AST_FRAME_VOICE) { - framelength = (ast_codec_get_samples(f) / DEFAULT_SAMPLES_PER_MS); + framelength = (ast_codec_samples_count(f) / DEFAULT_SAMPLES_PER_MS); } else { framelength = 2 * maxWaitTimeForFrame; } @@ -412,7 +412,7 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data) pbx_builtin_setvar_helper(chan , "AMDCAUSE" , amdCause); /* Restore channel read format */ - if (readFormat.id && ast_set_read_format(chan, &readFormat)) + if (readFormat && ast_set_read_format(chan, readFormat)) ast_log(LOG_WARNING, "AMD: Unable to restore read format on '%s'\n", ast_channel_name(chan)); /* Free the DSP used to detect silence */ @@ -510,10 +510,10 @@ static int unload_module(void) */ static int load_module(void) { - if (load_config(0)) + if (load_config(0) || ast_register_application_xml(app, amd_exec)) { return AST_MODULE_LOAD_DECLINE; - if (ast_register_application_xml(app, amd_exec)) - return AST_MODULE_LOAD_FAILURE; + } + return AST_MODULE_LOAD_SUCCESS; } diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index 47f755e5f..af69be303 100644 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -57,6 +57,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/autochan.h" #include "asterisk/stasis_channels.h" #include "asterisk/json.h" +#include "asterisk/format_cache.h" #define AST_NAME_STRLEN 256 #define NUM_SPYGROUPS 128 @@ -451,9 +452,6 @@ static int spy_generate(struct ast_channel *chan, void *data, int len, int sampl { struct chanspy_translation_helper *csth = data; struct ast_frame *f, *cur; - struct ast_format format_slin; - - ast_format_set(&format_slin, AST_FORMAT_SLINEAR, 0); ast_audiohook_lock(&csth->spy_audiohook); if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { @@ -464,9 +462,9 @@ static int spy_generate(struct ast_channel *chan, void *data, int len, int sampl if (ast_test_flag(&csth->flags, OPTION_READONLY)) { /* Option 'o' was set, so don't mix channel audio */ - f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, &format_slin); + f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, ast_format_slin); } else { - f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, &format_slin); + f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, ast_format_slin); } ast_audiohook_unlock(&csth->spy_audiohook); @@ -1181,7 +1179,7 @@ static int chanspy_exec(struct ast_channel *chan, const char *data) .volume = '#', .exit = '\0', }; - struct ast_format oldwf; + RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup); int volfactor = 0; int res; char *mailbox = NULL; @@ -1194,7 +1192,6 @@ static int chanspy_exec(struct ast_channel *chan, const char *data) char *parse = ast_strdupa(data); AST_STANDARD_APP_ARGS(args, parse); - ast_format_clear(&oldwf); if (args.spec && !strcmp(args.spec, "all")) args.spec = NULL; @@ -1258,8 +1255,8 @@ static int chanspy_exec(struct ast_channel *chan, const char *data) ast_clear_flag(&flags, AST_FLAGS_ALL); } - ast_format_copy(&oldwf, ast_channel_writeformat(chan)); - if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) { + oldwf = ao2_bump(ast_channel_writeformat(chan)); + if (ast_set_write_format(chan, ast_format_slin) < 0) { ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); return -1; } @@ -1279,7 +1276,7 @@ static int chanspy_exec(struct ast_channel *chan, const char *data) if (fd) close(fd); - if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0) + if (oldwf && ast_set_write_format(chan, oldwf) < 0) ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) { @@ -1301,7 +1298,7 @@ static int extenspy_exec(struct ast_channel *chan, const char *data) .volume = '#', .exit = '\0', }; - struct ast_format oldwf; + RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup); int volfactor = 0; int res; char *mailbox = NULL; @@ -1313,7 +1310,6 @@ static int extenspy_exec(struct ast_channel *chan, const char *data) char *parse = ast_strdupa(data); AST_STANDARD_APP_ARGS(args, parse); - ast_format_clear(&oldwf); if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) { exten = args.context; @@ -1383,8 +1379,8 @@ static int extenspy_exec(struct ast_channel *chan, const char *data) ast_clear_flag(&flags, AST_FLAGS_ALL); } - ast_format_copy(&oldwf, ast_channel_writeformat(chan)); - if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) { + oldwf = ao2_bump(ast_channel_writeformat(chan)); + if (ast_set_write_format(chan, ast_format_slin) < 0) { ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); return -1; } @@ -1405,7 +1401,7 @@ static int extenspy_exec(struct ast_channel *chan, const char *data) if (fd) close(fd); - if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0) + if (oldwf && ast_set_write_format(chan, oldwf) < 0) ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); return res; @@ -1420,13 +1416,13 @@ static int dahdiscan_exec(struct ast_channel *chan, const char *data) .volume = '\0', .exit = '*', }; - struct ast_format oldwf; + struct ast_format *oldwf; int res; char *mygroup = NULL; /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ ast_clear_flag(&flags, AST_FLAGS_ALL); - ast_format_clear(&oldwf); + if (!ast_strlen_zero(data)) { mygroup = ast_strdupa(data); } @@ -1434,16 +1430,18 @@ static int dahdiscan_exec(struct ast_channel *chan, const char *data) ast_set_flag(&flags, OPTION_DTMF_CYCLE); ast_set_flag(&flags, OPTION_DAHDI_SCAN); - ast_format_copy(&oldwf, ast_channel_writeformat(chan)); - if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) { + oldwf = ao2_bump(ast_channel_writeformat(chan)); + if (ast_set_write_format(chan, ast_format_slin) < 0) { ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); + ao2_cleanup(oldwf); return -1; } res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL); - if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0) + if (oldwf && ast_set_write_format(chan, oldwf) < 0) ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); + ao2_cleanup(oldwf); return res; } diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 9a704ac93..445b196d4 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -70,6 +70,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/stasis.h" #include "asterisk/stasis_bridges.h" #include "asterisk/json.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <application name="ConfBridge" language="en_US"> @@ -676,7 +677,6 @@ static int conf_stop_record_thread(struct confbridge_conference *conference) static int conf_start_record(struct confbridge_conference *conference) { struct ast_format_cap *cap; - struct ast_format format; if (conference->record_state != CONF_RECORD_STOP) { return -1; @@ -687,16 +687,16 @@ static int conf_start_record(struct confbridge_conference *conference) return -1; } - cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!cap) { return -1; } - ast_format_cap_add(cap, ast_format_set(&format, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(cap, ast_format_slin, 0); conference->record_chan = ast_request("CBRec", cap, NULL, NULL, conference->name, NULL); - cap = ast_format_cap_destroy(cap); + ao2_ref(cap, -1); if (!conference->record_chan) { return -1; } @@ -1374,16 +1374,15 @@ static void leave_conference(struct confbridge_user *user) static int alloc_playback_chan(struct confbridge_conference *conference) { struct ast_format_cap *cap; - struct ast_format format; - cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!cap) { return -1; } - ast_format_cap_add(cap, ast_format_set(&format, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(cap, ast_format_slin, 0); conference->playback_chan = ast_request("CBAnn", cap, NULL, NULL, conference->name, NULL); - cap = ast_format_cap_destroy(cap); + ao2_ref(cap, -1); if (!conference->playback_chan) { return -1; } @@ -3238,7 +3237,7 @@ void conf_remove_user_waiting(struct confbridge_conference *conference, struct c static void unregister_channel_tech(struct ast_channel_tech *tech) { ast_channel_unregister(tech); - tech->capabilities = ast_format_cap_destroy(tech->capabilities); + ao2_cleanup(tech->capabilities); } /*! @@ -3253,11 +3252,11 @@ static void unregister_channel_tech(struct ast_channel_tech *tech) */ static int register_channel_tech(struct ast_channel_tech *tech) { - tech->capabilities = ast_format_cap_alloc(0); + tech->capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!tech->capabilities) { return -1; } - ast_format_cap_add_all(tech->capabilities); + ast_format_cap_append_by_type(tech->capabilities, AST_MEDIA_TYPE_UNKNOWN); if (ast_channel_register(tech)) { ast_log(LOG_ERROR, "Unable to register channel technology %s(%s).\n", tech->type, tech->description); diff --git a/apps/app_dictate.c b/apps/app_dictate.c index 1820a1f83..8f229f2a9 100644 --- a/apps/app_dictate.c +++ b/apps/app_dictate.c @@ -43,6 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/say.h" #include "asterisk/app.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <application name="Dictate" language="en_US"> @@ -108,8 +109,7 @@ static int dictate_exec(struct ast_channel *chan, const char *data) len = 0, maxlen = 0, mode = 0; - struct ast_format oldr; - ast_format_clear(&oldr); + struct ast_format *oldr; snprintf(dftbase, sizeof(dftbase), "%s/dictate", ast_config_AST_SPOOL_DIR); if (!ast_strlen_zero(data)) { @@ -126,9 +126,10 @@ static int dictate_exec(struct ast_channel *chan, const char *data) if (args.argc > 1 && args.filename) { filename = args.filename; } - ast_format_copy(&oldr, ast_channel_readformat(chan)); - if ((res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) < 0) { + oldr = ao2_bump(ast_channel_readformat(chan)); + if ((res = ast_set_read_format(chan, ast_format_slin)) < 0) { ast_log(LOG_WARNING, "Unable to set to linear mode.\n"); + ao2_cleanup(oldr); return -1; } @@ -335,8 +336,9 @@ static int dictate_exec(struct ast_channel *chan, const char *data) ast_frfree(f); } } - if (oldr.id) { - ast_set_read_format(chan, &oldr); + if (oldr) { + ast_set_read_format(chan, oldr); + ao2_ref(oldr, -1); } return 0; } diff --git a/apps/app_dumpchan.c b/apps/app_dumpchan.c index 5c5be18af..1794c2565 100644 --- a/apps/app_dumpchan.c +++ b/apps/app_dumpchan.c @@ -72,7 +72,7 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size) { long elapsed_seconds = 0; int hour = 0, min = 0, sec = 0; - char nf[256]; + struct ast_str *format_buf = ast_str_alloca(64); char cgrp[256]; char pgrp[256]; struct ast_str *write_transpath = ast_str_alloca(256); @@ -143,11 +143,11 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size) ast_state2str(ast_channel_state(c)), ast_channel_state(c), ast_channel_rings(c), - ast_getformatname_multiple(nf, sizeof(nf), ast_channel_nativeformats(c)), - ast_getformatname(ast_channel_writeformat(c)), - ast_getformatname(ast_channel_readformat(c)), - ast_getformatname(ast_channel_rawwriteformat(c)), - ast_getformatname(ast_channel_rawreadformat(c)), + ast_format_cap_get_names(ast_channel_nativeformats(c), &format_buf), + ast_format_get_name(ast_channel_writeformat(c)), + ast_format_get_name(ast_channel_readformat(c)), + ast_format_get_name(ast_channel_rawwriteformat(c)), + ast_format_get_name(ast_channel_rawreadformat(c)), ast_channel_writetrans(c) ? "Yes" : "No", ast_translate_path_to_str(ast_channel_writetrans(c), &write_transpath), ast_channel_readtrans(c) ? "Yes" : "No", diff --git a/apps/app_echo.c b/apps/app_echo.c index df5a914f1..d8b207967 100644 --- a/apps/app_echo.c +++ b/apps/app_echo.c @@ -58,11 +58,6 @@ static const char app[] = "Echo"; static int echo_exec(struct ast_channel *chan, const char *data) { int res = -1; - struct ast_format format; - - ast_best_codec(ast_channel_nativeformats(chan), &format); - ast_set_write_format(chan, &format); - ast_set_read_format(chan, &format); while (ast_waitfor(chan, -1) > -1) { struct ast_frame *f = ast_read(chan); diff --git a/apps/app_fax.c b/apps/app_fax.c index e23ac431e..ceff38fef 100644 --- a/apps/app_fax.c +++ b/apps/app_fax.c @@ -45,6 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/stasis.h" #include "asterisk/stasis_channels.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <application name="SendFAX" language="en_US" module="app_fax"> @@ -332,9 +333,9 @@ static int fax_generator_generate(struct ast_channel *chan, void *data, int len, struct ast_frame outf = { .frametype = AST_FRAME_VOICE, + .subclass.format = ast_format_slin, .src = __FUNCTION__, }; - ast_format_set(&outf.subclass.format, AST_FORMAT_SLINEAR, 0); if (samples > MAX_SAMPLES) { ast_log(LOG_WARNING, "Only generating %d samples, where %d requested\n", MAX_SAMPLES, samples); @@ -365,8 +366,8 @@ static struct ast_generator generator = { static int transmit_audio(fax_session *s) { int res = -1; - struct ast_format original_read_fmt; - struct ast_format original_write_fmt; + struct ast_format *original_read_fmt; + struct ast_format *original_write_fmt = NULL; fax_state_t fax; t30_state_t *t30state; struct ast_frame *inf = NULL; @@ -386,9 +387,6 @@ static int transmit_audio(fax_session *s) */ }; - ast_format_clear(&original_read_fmt); - ast_format_clear(&original_write_fmt); - /* if in called party mode, try to use T.38 */ if (s->caller_mode == FALSE) { /* check if we are already in T.38 mode (unlikely), or if we can request @@ -461,22 +459,18 @@ static int transmit_audio(fax_session *s) t30state = &fax.t30_state; #endif - ast_format_copy(&original_read_fmt, ast_channel_readformat(s->chan)); - if (original_read_fmt.id != AST_FORMAT_SLINEAR) { - res = ast_set_read_format_by_id(s->chan, AST_FORMAT_SLINEAR); - if (res < 0) { - ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n"); - goto done; - } + original_read_fmt = ao2_bump(ast_channel_readformat(s->chan)); + res = ast_set_read_format(s->chan, ast_format_slin); + if (res < 0) { + ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n"); + goto done; } - ast_format_copy(&original_write_fmt, ast_channel_writeformat(s->chan)); - if (original_write_fmt.id != AST_FORMAT_SLINEAR) { - res = ast_set_write_format_by_id(s->chan, AST_FORMAT_SLINEAR); - if (res < 0) { - ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n"); - goto done; - } + original_write_fmt = ao2_bump(ast_channel_writeformat(s->chan)); + res = ast_set_write_format(s->chan, ast_format_slin); + if (res < 0) { + ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n"); + goto done; } /* Initialize T30 terminal */ @@ -529,12 +523,13 @@ static int transmit_audio(fax_session *s) break; } - ast_debug(10, "frame %d/%u, len=%d\n", inf->frametype, (unsigned int) inf->subclass.format.id, inf->datalen); + ast_debug(10, "frame %d/%s, len=%d\n", inf->frametype, ast_format_get_name(inf->subclass.format), inf->datalen); /* Check the frame type. Format also must be checked because there is a chance that a frame in old format was already queued before we set channel format to slinear so it will still be received by ast_read */ - if (inf->frametype == AST_FRAME_VOICE && inf->subclass.format.id == AST_FORMAT_SLINEAR) { + if (inf->frametype == AST_FRAME_VOICE && + (ast_format_cmp(inf->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) { if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) { /* I know fax_rx never returns errors. The check here is for good style only */ ast_log(LOG_WARNING, "fax_rx returned error\n"); @@ -588,14 +583,16 @@ static int transmit_audio(fax_session *s) fax_release(&fax); done: - if (original_write_fmt.id != AST_FORMAT_SLINEAR) { - if (ast_set_write_format(s->chan, &original_write_fmt) < 0) + if (original_write_fmt) { + if (ast_set_write_format(s->chan, original_write_fmt) < 0) ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", ast_channel_name(s->chan)); + ao2_ref(original_write_fmt, -1); } - if (original_read_fmt.id != AST_FORMAT_SLINEAR) { - if (ast_set_read_format(s->chan, &original_read_fmt) < 0) + if (original_read_fmt) { + if (ast_set_read_format(s->chan, original_read_fmt) < 0) ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(s->chan)); + ao2_ref(original_read_fmt, -1); } return res; diff --git a/apps/app_festival.c b/apps/app_festival.c index 3ccacb195..3626563c6 100644 --- a/apps/app_festival.c +++ b/apps/app_festival.c @@ -63,6 +63,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/lock.h" #include "asterisk/app.h" #include "asterisk/endian.h" +#include "asterisk/format_cache.h" #define FESTIVAL_CONFIG "festival.conf" #define MAXLEN 180 @@ -177,7 +178,7 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in int res = 0; int fds[2]; int needed = 0; - struct ast_format owriteformat; + struct ast_format *owriteformat; struct ast_frame *f; struct myframe { struct ast_frame f; @@ -187,7 +188,6 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in .f = { 0, }, }; - ast_format_clear(&owriteformat); if (pipe(fds)) { ast_log(LOG_WARNING, "Unable to create pipe\n"); return -1; @@ -199,12 +199,19 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in ast_stopstream(chan); ast_indicate(chan, -1); - ast_format_copy(&owriteformat, ast_channel_writeformat(chan)); - res = ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR); + owriteformat = ao2_bump(ast_channel_writeformat(chan)); + res = ast_set_write_format(chan, ast_format_slin); if (res < 0) { ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); + ao2_cleanup(owriteformat); return -1; } + + myf.f.frametype = AST_FRAME_VOICE; + myf.f.subclass.format = ast_format_slin; + myf.f.offset = AST_FRIENDLY_OFFSET; + myf.f.src = __PRETTY_FUNCTION__; + myf.f.data.ptr = myf.frdata; res = send_waveform_to_fd(waveform, length, fds[1]); if (res >= 0) { @@ -240,13 +247,8 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in } res = read(fds[0], myf.frdata, needed); if (res > 0) { - myf.f.frametype = AST_FRAME_VOICE; - ast_format_set(&myf.f.subclass.format, AST_FORMAT_SLINEAR, 0); myf.f.datalen = res; myf.f.samples = res / 2; - myf.f.offset = AST_FRIENDLY_OFFSET; - myf.f.src = __PRETTY_FUNCTION__; - myf.f.data.ptr = myf.frdata; if (ast_write(chan, &myf.f) < 0) { res = -1; ast_frfree(f); @@ -269,8 +271,10 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in close(fds[0]); close(fds[1]); - if (!res && owriteformat.id) - ast_set_write_format(chan, &owriteformat); + if (!res && owriteformat) + ast_set_write_format(chan, owriteformat); + ao2_cleanup(owriteformat); + return res; } diff --git a/apps/app_ices.c b/apps/app_ices.c index bdccff43f..3122273c7 100644 --- a/apps/app_ices.c +++ b/apps/app_ices.c @@ -48,6 +48,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/translate.h" #include "asterisk/app.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <application name="ICES" language="en_US"> @@ -115,12 +116,11 @@ static int ices_exec(struct ast_channel *chan, const char *data) int ms = -1; int pid = -1; int flags; - struct ast_format oreadformat; + struct ast_format *oreadformat; struct ast_frame *f; char filename[256]=""; char *c; - ast_format_clear(&oreadformat); if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "ICES requires an argument (configfile.xml)\n"); return -1; @@ -145,12 +145,13 @@ static int ices_exec(struct ast_channel *chan, const char *data) return -1; } - ast_format_copy(&oreadformat, ast_channel_readformat(chan)); - res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR); + oreadformat = ao2_bump(ast_channel_readformat(chan)); + res = ast_set_read_format(chan, ast_format_slin); if (res < 0) { close(fds[0]); close(fds[1]); ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); + ao2_cleanup(oreadformat); return -1; } if (((char *)data)[0] == '/') @@ -197,8 +198,9 @@ static int ices_exec(struct ast_channel *chan, const char *data) if (pid > -1) kill(pid, SIGKILL); - if (!res && oreadformat.id) - ast_set_read_format(chan, &oreadformat); + if (!res && oreadformat) + ast_set_read_format(chan, oreadformat); + ao2_cleanup(oreadformat); return res; } diff --git a/apps/app_jack.c b/apps/app_jack.c index 9c59ceaf4..8adfbc4cb 100644 --- a/apps/app_jack.c +++ b/apps/app_jack.c @@ -58,6 +58,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/pbx.h" #include "asterisk/audiohook.h" +#include "asterisk/format_cache.h" #define RESAMPLE_QUALITY 1 @@ -129,7 +130,7 @@ struct jack_data { jack_port_t *output_port; jack_ringbuffer_t *input_rb; jack_ringbuffer_t *output_rb; - enum ast_format_id audiohook_format_id; + struct ast_format *audiohook_format; unsigned int audiohook_rate; unsigned int frame_datalen; void *output_resampler; @@ -394,7 +395,6 @@ static int init_jack_data(struct ast_channel *chan, struct jack_data *jack_data) jack_status_t status = 0; jack_options_t jack_options = JackNullOption; - struct ast_format format_slin; unsigned int channel_rate; unsigned int ringbuffer_size; @@ -402,19 +402,17 @@ static int init_jack_data(struct ast_channel *chan, struct jack_data *jack_data) /* Deducing audiohook sample rate from channel format ATTENTION: Might be problematic, if channel has different sampling than used by audiohook! */ - channel_rate = ast_format_rate(ast_channel_readformat(chan)); - jack_data->audiohook_format_id = ast_format_slin_by_rate(channel_rate); - - ast_format_set(&format_slin, jack_data->audiohook_format_id, 0); - jack_data->audiohook_rate = ast_format_rate(&format_slin); + channel_rate = ast_format_get_sample_rate(ast_channel_readformat(chan)); + jack_data->audiohook_format = ast_format_cache_get_slin_by_rate(channel_rate); + jack_data->audiohook_rate = ast_format_get_sample_rate(jack_data->audiohook_format); /* Guessing frame->datalen assuming a ptime of 20ms */ jack_data->frame_datalen = jack_data->audiohook_rate / 50; ringbuffer_size = jack_data->frame_datalen * RINGBUFFER_FRAME_CAPACITY; - ast_debug(1, "Audiohook parameters: slin-format:%d, rate:%d, frame-len:%d, ringbuffer_size: %d\n", - jack_data->audiohook_format_id, jack_data->audiohook_rate, jack_data->frame_datalen, ringbuffer_size); + ast_debug(1, "Audiohook parameters: slin-format:%s, rate:%d, frame-len:%d, ringbuffer_size: %d\n", + ast_format_get_name(jack_data->audiohook_format), jack_data->audiohook_rate, jack_data->frame_datalen, ringbuffer_size); if (!ast_strlen_zero(jack_data->client_name)) { client_name = jack_data->client_name; @@ -628,12 +626,12 @@ static void handle_jack_audio(struct ast_channel *chan, struct jack_data *jack_d short buf[jack_data->frame_datalen]; struct ast_frame f = { .frametype = AST_FRAME_VOICE, + .subclass.format = jack_data->audiohook_format, .src = "JACK", .data.ptr = buf, .datalen = sizeof(buf), .samples = ARRAY_LEN(buf), }; - ast_format_set(&f.subclass.format, jack_data->audiohook_format_id, 0); for (;;) { size_t res, read_len; @@ -778,12 +776,12 @@ static int jack_exec(struct ast_channel *chan, const char *data) return -1; } - if (ast_set_read_format_by_id(chan, jack_data->audiohook_format_id)) { + if (ast_set_read_format(chan, jack_data->audiohook_format)) { destroy_jack_data(jack_data); return -1; } - if (ast_set_write_format_by_id(chan, jack_data->audiohook_format_id)) { + if (ast_set_write_format(chan, jack_data->audiohook_format)) { destroy_jack_data(jack_data); return -1; } @@ -859,9 +857,10 @@ static int jack_hook_callback(struct ast_audiohook *audiohook, struct ast_channe jack_data = datastore->data; - if (frame->subclass.format.id != jack_data->audiohook_format_id) { - ast_log(LOG_WARNING, "Expected frame in SLINEAR with id %d for the audiohook, but got format %s\n", - jack_data->audiohook_format_id, ast_getformatname(&frame->subclass.format)); + if (ast_format_cmp(frame->subclass.format, jack_data->audiohook_format) == AST_FORMAT_CMP_NOT_EQUAL) { + ast_log(LOG_WARNING, "Expected frame in %s for the audiohook, but got format %s\n", + ast_format_get_name(jack_data->audiohook_format), + ast_format_get_name(frame->subclass.format)); ast_channel_unlock(chan); return 0; } diff --git a/apps/app_meetme.c b/apps/app_meetme.c index 1a780e6ff..6d0b5ac1b 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -77,6 +77,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/stasis_channels.h" #include "asterisk/stasis_message_router.h" #include "asterisk/json.h" +#include "asterisk/format_compatibility.h" #include "enter.h" #include "leave.h" @@ -1606,8 +1607,7 @@ static struct ast_conference *build_conf(const char *confno, const char *pin, struct ast_conference *cnf; struct dahdi_confinfo dahdic = { 0, }; int confno_int = 0; - struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - struct ast_format tmp_fmt; + struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); AST_LIST_LOCK(&confs); @@ -1619,7 +1619,7 @@ static struct ast_conference *build_conf(const char *confno, const char *pin, if (cnf || (!make && !dynamic) || !cap_slin) goto cnfout; - ast_format_cap_add(cap_slin, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(cap_slin, ast_format_slin, 0); /* Make a new one */ if (!(cnf = ast_calloc(1, sizeof(*cnf))) || !(cnf->usercontainer = ao2_container_alloc(1, NULL, user_no_cmp))) { @@ -1667,8 +1667,8 @@ static struct ast_conference *build_conf(const char *confno, const char *pin, /* Setup a new channel for playback of audio files */ cnf->chan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL); if (cnf->chan) { - ast_set_read_format_by_id(cnf->chan, AST_FORMAT_SLINEAR); - ast_set_write_format_by_id(cnf->chan, AST_FORMAT_SLINEAR); + ast_set_read_format(cnf->chan, ast_format_slin); + ast_set_write_format(cnf->chan, ast_format_slin); dahdic.chan = 0; dahdic.confno = cnf->dahdiconf; dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON; @@ -1704,7 +1704,7 @@ static struct ast_conference *build_conf(const char *confno, const char *pin, conf_map[confno_int] = 1; cnfout: - cap_slin = ast_format_cap_destroy(cap_slin); + ao2_cleanup(cap_slin); if (cnf) ast_atomic_fetchadd_int(&cnf->refcount, refcount); @@ -3089,8 +3089,8 @@ static void meetme_menu_admin_extended(enum menu_modes *menu_mode, int *dtmf, if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) { struct dahdi_confinfo dahdic; - ast_set_read_format_by_id(conf->lchan, AST_FORMAT_SLINEAR); - ast_set_write_format_by_id(conf->lchan, AST_FORMAT_SLINEAR); + ast_set_read_format(conf->lchan, ast_format_slin); + ast_set_write_format(conf->lchan, ast_format_slin); dahdic.chan = 0; dahdic.confno = conf->dahdiconf; dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON; @@ -3217,13 +3217,12 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc int setusercount = 0; int confsilence = 0, totalsilence = 0; char *mailbox, *context; - struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - struct ast_format tmpfmt; + struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!cap_slin) { goto conf_run_cleanup; } - ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(cap_slin, ast_format_slin, 0); if (!(user = ao2_alloc(sizeof(*user), NULL))) { goto conf_run_cleanup; @@ -3345,8 +3344,8 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc ast_mutex_lock(&conf->recordthreadlock); if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) { - ast_set_read_format_by_id(conf->lchan, AST_FORMAT_SLINEAR); - ast_set_write_format_by_id(conf->lchan, AST_FORMAT_SLINEAR); + ast_set_read_format(conf->lchan, ast_format_slin); + ast_set_write_format(conf->lchan, ast_format_slin); dahdic.chan = 0; dahdic.confno = conf->dahdiconf; dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON; @@ -3572,12 +3571,12 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc ast_indicate(chan, -1); } - if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) { + if (ast_set_write_format(chan, ast_format_slin) < 0) { ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", ast_channel_name(chan)); goto outrun; } - if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) { + if (ast_set_read_format(chan, ast_format_slin) < 0) { ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", ast_channel_name(chan)); goto outrun; } @@ -4131,7 +4130,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc dtmfstr[1] = '\0'; } - if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id == AST_FORMAT_SLINEAR)) { + if ((f->frametype == AST_FRAME_VOICE) && (ast_format_cmp(f->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) { if (user->talk.actual) { ast_frame_adjust_volume(f, user->talk.actual); } @@ -4289,7 +4288,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc if (res > 0) { memset(&fr, 0, sizeof(fr)); fr.frametype = AST_FRAME_VOICE; - ast_format_set(&fr.subclass.format, AST_FORMAT_SLINEAR, 0); + fr.subclass.format = ast_format_slin; fr.datalen = res; fr.samples = res / 2; fr.data.ptr = buf; @@ -4301,7 +4300,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc )) { int idx; for (idx = 0; idx < AST_FRAME_BITS; idx++) { - if (ast_format_to_old_bitfield(ast_channel_rawwriteformat(chan)) & (1 << idx)) { + if (ast_format_compatibility_format2bitfield(ast_channel_rawwriteformat(chan)) & (1 << idx)) { break; } } @@ -4319,11 +4318,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc mohtempstopped = 1; } if (!conf->transpath[idx]) { - struct ast_format src; - struct ast_format dst; - ast_format_set(&src, AST_FORMAT_SLINEAR, 0); - ast_format_from_old_bitfield(&dst, (1 << idx)); - conf->transpath[idx] = ast_translator_build_path(&dst, &src); + conf->transpath[idx] = ast_translator_build_path(ast_channel_rawwriteformat(chan), ast_format_slin); } if (conf->transpath[idx]) { conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0); @@ -4485,7 +4480,7 @@ bailoutandtrynormal: conf_run_cleanup: - cap_slin = ast_format_cap_destroy(cap_slin); + ao2_cleanup(cap_slin); return ret; } diff --git a/apps/app_milliwatt.c b/apps/app_milliwatt.c index a4adc08c5..a3509581d 100644 --- a/apps/app_milliwatt.c +++ b/apps/app_milliwatt.c @@ -37,6 +37,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/channel.h" #include "asterisk/pbx.h" #include "asterisk/indications.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <application name="Milliwatt" language="en_US"> @@ -79,13 +80,14 @@ static int milliwatt_generate(struct ast_channel *chan, void *data, int len, int { unsigned char buf[AST_FRIENDLY_OFFSET + 640]; const int maxsamples = ARRAY_LEN(buf) - (AST_FRIENDLY_OFFSET / sizeof(buf[0])); - int i, *indexp = (int *) data; + int i, *indexp = (int *) data, res; struct ast_frame wf = { .frametype = AST_FRAME_VOICE, .offset = AST_FRIENDLY_OFFSET, .src = __FUNCTION__, }; - ast_format_set(&wf.subclass.format, AST_FORMAT_ULAW, 0); + + wf.subclass.format = ast_format_ulaw; wf.data.ptr = buf + AST_FRIENDLY_OFFSET; /* Instead of len, use samples, because channel.c generator_force @@ -108,7 +110,10 @@ static int milliwatt_generate(struct ast_channel *chan, void *data, int len, int *indexp &= 7; } - if (ast_write(chan,&wf) < 0) { + res = ast_write(chan, &wf); + ast_frfree(&wf); + + if (res < 0) { ast_log(LOG_WARNING,"Failed to write frame to '%s': %s\n",ast_channel_name(chan),strerror(errno)); return -1; } @@ -124,8 +129,8 @@ static struct ast_generator milliwattgen = { static int old_milliwatt_exec(struct ast_channel *chan) { - ast_set_write_format_by_id(chan, AST_FORMAT_ULAW); - ast_set_read_format_by_id(chan, AST_FORMAT_ULAW); + ast_set_write_format(chan, ast_format_ulaw); + ast_set_read_format(chan, ast_format_ulaw); if (ast_channel_state(chan) != AST_STATE_UP) { ast_answer(chan); diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c index ab1d0bad1..1e7833cea 100644 --- a/apps/app_mixmonitor.c +++ b/apps/app_mixmonitor.c @@ -57,6 +57,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/linkedlists.h" #include "asterisk/test.h" #include "asterisk/mixmonitor.h" +#include "asterisk/format_cache.h" #include "asterisk/beep.h" /*** DOCUMENTATION @@ -616,7 +617,7 @@ static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, *errflag = 1; } else { struct ast_filestream *tmp = *fs; - mixmonitor->mixmonitor_ds->samp_rate = MAX(mixmonitor->mixmonitor_ds->samp_rate, ast_format_rate(&tmp->fmt->format)); + mixmonitor->mixmonitor_ds->samp_rate = MAX(mixmonitor->mixmonitor_ds->samp_rate, ast_format_get_sample_rate(tmp->fmt->format)); } } } @@ -635,7 +636,7 @@ static void *mixmonitor_thread(void *obj) unsigned int oflags; int errflag = 0; - struct ast_format format_slin; + struct ast_format *format_slin; /* Keep callid association before any log messages */ if (mixmonitor->callid) { @@ -653,11 +654,10 @@ static void *mixmonitor_thread(void *obj) mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag, &fs_read_ext); mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag, &fs_write_ext); - ast_format_set(&format_slin, ast_format_slin_by_rate(mixmonitor->mixmonitor_ds->samp_rate), 0); + format_slin = ast_format_cache_get_slin_by_rate(mixmonitor->mixmonitor_ds->samp_rate); ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); - /* The audiohook must enter and exit the loop locked */ ast_audiohook_lock(&mixmonitor->audiohook); while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) { @@ -665,7 +665,7 @@ static void *mixmonitor_thread(void *obj) struct ast_frame *fr_read = NULL; struct ast_frame *fr_write = NULL; - if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, &format_slin, + if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, format_slin, &fr_read, &fr_write))) { ast_audiohook_trigger_wait(&mixmonitor->audiohook); diff --git a/apps/app_mp3.c b/apps/app_mp3.c index 463a91906..7e4e8e490 100644 --- a/apps/app_mp3.c +++ b/apps/app_mp3.c @@ -47,6 +47,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/translate.h" #include "asterisk/app.h" +#include "asterisk/format_cache.h" #define LOCAL_MPG_123 "/usr/local/bin/mpg123" #define MPG_123 "/usr/bin/mpg123" @@ -143,7 +144,7 @@ static int mp3_exec(struct ast_channel *chan, const char *data) int fds[2]; int ms = -1; int pid = -1; - struct ast_format owriteformat; + RAII_VAR(struct ast_format *, owriteformat, NULL, ao2_cleanup); int timeout = 2000; struct timeval next; struct ast_frame *f; @@ -155,7 +156,6 @@ static int mp3_exec(struct ast_channel *chan, const char *data) .f = { 0, }, }; - ast_format_clear(&owriteformat); if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n"); return -1; @@ -168,12 +168,21 @@ static int mp3_exec(struct ast_channel *chan, const char *data) ast_stopstream(chan); - ast_format_copy(&owriteformat, ast_channel_writeformat(chan)); - res = ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR); + owriteformat = ao2_bump(ast_channel_writeformat(chan)); + res = ast_set_write_format(chan, ast_format_slin); if (res < 0) { ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); return -1; } + + myf.f.frametype = AST_FRAME_VOICE; + myf.f.subclass.format = ast_format_slin; + myf.f.mallocd = 0; + myf.f.offset = AST_FRIENDLY_OFFSET; + myf.f.src = __PRETTY_FUNCTION__; + myf.f.delivery.tv_sec = 0; + myf.f.delivery.tv_usec = 0; + myf.f.data.ptr = myf.frdata; res = mp3play(data, fds[1]); if (!strncasecmp(data, "http://", 7)) { @@ -191,16 +200,8 @@ static int mp3_exec(struct ast_channel *chan, const char *data) if (ms <= 0) { res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout); if (res > 0) { - myf.f.frametype = AST_FRAME_VOICE; - ast_format_set(&myf.f.subclass.format, AST_FORMAT_SLINEAR, 0); myf.f.datalen = res; myf.f.samples = res / 2; - myf.f.mallocd = 0; - myf.f.offset = AST_FRIENDLY_OFFSET; - myf.f.src = __PRETTY_FUNCTION__; - myf.f.delivery.tv_sec = 0; - myf.f.delivery.tv_usec = 0; - myf.f.data.ptr = myf.frdata; if (ast_write(chan, &myf.f) < 0) { res = -1; break; @@ -241,8 +242,10 @@ static int mp3_exec(struct ast_channel *chan, const char *data) if (pid > -1) kill(pid, SIGKILL); - if (!res && owriteformat.id) - ast_set_write_format(chan, &owriteformat); + if (!res && owriteformat) + ast_set_write_format(chan, owriteformat); + + ast_frfree(&myf.f); return res; } diff --git a/apps/app_nbscat.c b/apps/app_nbscat.c index 8cf02b369..435af8a29 100644 --- a/apps/app_nbscat.c +++ b/apps/app_nbscat.c @@ -46,6 +46,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/translate.h" #include "asterisk/app.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <application name="NBScat" language="en_US"> @@ -115,7 +116,7 @@ static int NBScat_exec(struct ast_channel *chan, const char *data) int fds[2]; int ms = -1; int pid = -1; - struct ast_format owriteformat; + struct ast_format *owriteformat; struct timeval next; struct ast_frame *f; struct myframe { @@ -124,7 +125,6 @@ static int NBScat_exec(struct ast_channel *chan, const char *data) short frdata[160]; } myf; - ast_format_clear(&owriteformat); if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds)) { ast_log(LOG_WARNING, "Unable to create socketpair\n"); return -1; @@ -132,12 +132,22 @@ static int NBScat_exec(struct ast_channel *chan, const char *data) ast_stopstream(chan); - ast_format_copy(&owriteformat, ast_channel_writeformat(chan)); - res = ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR); + owriteformat = ao2_bump(ast_channel_writeformat(chan)); + res = ast_set_write_format(chan, ast_format_slin); if (res < 0) { ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); + ao2_cleanup(owriteformat); return -1; } + + myf.f.frametype = AST_FRAME_VOICE; + myf.f.subclass.format = ast_format_slin; + myf.f.mallocd = 0; + myf.f.offset = AST_FRIENDLY_OFFSET; + myf.f.src = __PRETTY_FUNCTION__; + myf.f.delivery.tv_sec = 0; + myf.f.delivery.tv_usec = 0; + myf.f.data.ptr = myf.frdata; res = NBScatplay(fds[1]); /* Wait 1000 ms first */ @@ -152,16 +162,8 @@ static int NBScat_exec(struct ast_channel *chan, const char *data) if (ms <= 0) { res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata)); if (res > 0) { - myf.f.frametype = AST_FRAME_VOICE; - ast_format_set(&myf.f.subclass.format, AST_FORMAT_SLINEAR, 0); myf.f.datalen = res; myf.f.samples = res / 2; - myf.f.mallocd = 0; - myf.f.offset = AST_FRIENDLY_OFFSET; - myf.f.src = __PRETTY_FUNCTION__; - myf.f.delivery.tv_sec = 0; - myf.f.delivery.tv_usec = 0; - myf.f.data.ptr = myf.frdata; if (ast_write(chan, &myf.f) < 0) { res = -1; break; @@ -199,11 +201,13 @@ static int NBScat_exec(struct ast_channel *chan, const char *data) } close(fds[0]); close(fds[1]); + ast_frfree(&myf.f); if (pid > -1) kill(pid, SIGKILL); - if (!res && owriteformat.id) - ast_set_write_format(chan, &owriteformat); + if (!res && owriteformat) + ast_set_write_format(chan, owriteformat); + ao2_cleanup(owriteformat); return res; } diff --git a/apps/app_originate.c b/apps/app_originate.c index 9fceb0849..15898b240 100644 --- a/apps/app_originate.c +++ b/apps/app_originate.c @@ -45,6 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/pbx.h" #include "asterisk/module.h" #include "asterisk/app.h" +#include "asterisk/format_cache.h" static const char app_originate[] = "Originate"; @@ -112,22 +113,22 @@ static int originate_exec(struct ast_channel *chan, const char *data) int outgoing_status = 0; unsigned int timeout = 30; static const char default_exten[] = "s"; - struct ast_format tmpfmt; - struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); ast_autoservice_start(chan); if (!cap_slin) { goto return_cleanup; } - ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)); - ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR12, 0)); - ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR16, 0)); - ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR24, 0)); - ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR32, 0)); - ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR44, 0)); - ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR48, 0)); - ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR96, 0)); - ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR192, 0)); + + ast_format_cap_append(cap_slin, ast_format_slin, 0); + ast_format_cap_append(cap_slin, ast_format_slin12, 0); + ast_format_cap_append(cap_slin, ast_format_slin16, 0); + ast_format_cap_append(cap_slin, ast_format_slin24, 0); + ast_format_cap_append(cap_slin, ast_format_slin32, 0); + ast_format_cap_append(cap_slin, ast_format_slin44, 0); + ast_format_cap_append(cap_slin, ast_format_slin48, 0); + ast_format_cap_append(cap_slin, ast_format_slin96, 0); + ast_format_cap_append(cap_slin, ast_format_slin192, 0); if (ast_strlen_zero(data)) { ast_log(LOG_ERROR, "Originate() requires arguments\n"); @@ -222,7 +223,7 @@ return_cleanup: break; } } - cap_slin = ast_format_cap_destroy(cap_slin); + ao2_cleanup(cap_slin); ast_autoservice_stop(chan); return res; diff --git a/apps/app_record.c b/apps/app_record.c index 45f1d8602..4008fc012 100644 --- a/apps/app_record.c +++ b/apps/app_record.c @@ -39,6 +39,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/channel.h" #include "asterisk/dsp.h" /* use dsp routines for silence detection */ +#include "asterisk/format_cache.h" /*** DOCUMENTATION <application name="Record" language="en_US"> @@ -196,7 +197,7 @@ static int record_exec(struct ast_channel *chan, const char *data) int maxduration = 0; /* max duration of recording in milliseconds */ int gottimeout = 0; /* did we timeout for maxduration exceeded? */ int terminator = '#'; - struct ast_format rfmt; + RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup); int ioflags; struct ast_silence_generator *silgen = NULL; struct ast_flags flags = { 0, }; @@ -209,8 +210,6 @@ static int record_exec(struct ast_channel *chan, const char *data) int ms; struct timeval start; - ast_format_clear(&rfmt); - /* The next few lines of code parse out the filename and header from the input string */ if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */ ast_log(LOG_WARNING, "Record requires an argument (filename)\n"); @@ -331,8 +330,8 @@ static int record_exec(struct ast_channel *chan, const char *data) /* The end of beep code. Now the recording starts */ if (silence > 0) { - ast_format_copy(&rfmt, ast_channel_readformat(chan)); - res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR); + rfmt = ao2_bump(ast_channel_readformat(chan)); + res = ast_set_read_format(chan, ast_format_slin); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR"); @@ -459,8 +458,8 @@ static int record_exec(struct ast_channel *chan, const char *data) ast_channel_stop_silence_generator(chan, silgen); out: - if ((silence > 0) && rfmt.id) { - res = ast_set_read_format(chan, &rfmt); + if ((silence > 0) && rfmt) { + res = ast_set_read_format(chan, rfmt); if (res) { ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(chan)); } diff --git a/apps/app_sms.c b/apps/app_sms.c index b7d247818..266f8abdc 100644 --- a/apps/app_sms.c +++ b/apps/app_sms.c @@ -56,6 +56,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/callerid.h" #include "asterisk/utils.h" #include "asterisk/app.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <application name="SMS" language="en_US"> @@ -140,11 +141,11 @@ static const signed short wave[] = { static unsigned char wavea[80]; typedef unsigned char output_t; static const output_t *wave_out = wavea; /* outgoing samples */ -#define __OUT_FMT AST_FORMAT_ALAW; +#define __OUT_FMT ast_format_alaw #else typedef signed short output_t; static const output_t *wave_out = wave; /* outgoing samples */ -#define __OUT_FMT AST_FORMAT_SLINEAR +#define __OUT_FMT ast_format_slin #endif #define OSYNC_BITS 80 /* initial sync bits */ @@ -1599,7 +1600,7 @@ static int sms_generate(struct ast_channel *chan, void *data, int len, int sampl #define MAXSAMPLES (800) output_t *buf; sms_t *h = data; - int i; + int i, res; if (samples > MAXSAMPLES) { ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n", @@ -1610,7 +1611,7 @@ static int sms_generate(struct ast_channel *chan, void *data, int len, int sampl buf = ast_alloca(len); f.frametype = AST_FRAME_VOICE; - ast_format_set(&f.subclass.format, __OUT_FMT, 0); + f.subclass.format = __OUT_FMT; f.datalen = samples * sizeof(*buf); f.offset = AST_FRIENDLY_OFFSET; f.mallocd = 0; @@ -1660,7 +1661,9 @@ static int sms_generate(struct ast_channel *chan, void *data, int len, int sampl } } } - if (ast_write(chan, &f) < 0) { + res = ast_write(chan, &f); + ast_frfree(&f); + if (res < 0) { ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno)); return -1; } @@ -2012,9 +2015,9 @@ static int sms_exec(struct ast_channel *chan, const char *data) sms_messagetx(&h); } - res = ast_set_write_format_by_id(chan, __OUT_FMT); + res = ast_set_write_format(chan, __OUT_FMT); if (res >= 0) { - res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR); + res = ast_set_read_format(chan, ast_format_slin); } if (res < 0) { ast_log(LOG_ERROR, "Unable to set to linear mode, giving up\n"); diff --git a/apps/app_speech_utils.c b/apps/app_speech_utils.c index e9ca63ea9..e52425d6a 100644 --- a/apps/app_speech_utils.c +++ b/apps/app_speech_utils.c @@ -672,7 +672,7 @@ static int speech_background(struct ast_channel *chan, const char *data) int res = 0, done = 0, started = 0, quieted = 0, max_dtmf_len = 0; struct ast_speech *speech = find_speech(chan); struct ast_frame *f = NULL; - struct ast_format oldreadformat; + RAII_VAR(struct ast_format *, oldreadformat, NULL, ao2_cleanup); char dtmf[AST_MAX_EXTENSION] = ""; struct timeval start = { 0, 0 }, current; struct ast_datastore *datastore = NULL; @@ -688,7 +688,6 @@ static int speech_background(struct ast_channel *chan, const char *data) parse = ast_strdupa(data); AST_STANDARD_APP_ARGS(args, parse); - ast_format_clear(&oldreadformat); if (speech == NULL) return -1; @@ -704,10 +703,10 @@ static int speech_background(struct ast_channel *chan, const char *data) } /* Record old read format */ - ast_format_copy(&oldreadformat, ast_channel_readformat(chan)); + oldreadformat = ao2_bump(ast_channel_readformat(chan)); /* Change read format to be signed linear */ - if (ast_set_read_format(chan, &speech->format)) + if (ast_set_read_format(chan, speech->format)) return -1; if (!ast_strlen_zero(args.soundfile)) { @@ -912,7 +911,7 @@ static int speech_background(struct ast_channel *chan, const char *data) ast_channel_datastore_remove(chan, datastore); } else { /* Channel is okay so restore read format */ - ast_set_read_format(chan, &oldreadformat); + ast_set_read_format(chan, oldreadformat); } return 0; diff --git a/apps/app_talkdetect.c b/apps/app_talkdetect.c index 5ef80c33c..5ccf2607e 100644 --- a/apps/app_talkdetect.c +++ b/apps/app_talkdetect.c @@ -42,6 +42,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/dsp.h" #include "asterisk/app.h" +#include "asterisk/format.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <application name="BackgroundDetect" language="en_US"> @@ -91,7 +93,7 @@ static int background_detect_exec(struct ast_channel *chan, const char *data) int analysistime = -1; int continue_analysis = 1; int x; - struct ast_format origrformat; + RAII_VAR(struct ast_format *, origrformat, NULL, ao2_cleanup); struct ast_dsp *dsp = NULL; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(filename); @@ -101,7 +103,6 @@ static int background_detect_exec(struct ast_channel *chan, const char *data) AST_APP_ARG(analysistime); ); - ast_format_clear(&origrformat); if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "BackgroundDetect requires an argument (filename)\n"); return -1; @@ -131,8 +132,8 @@ static int background_detect_exec(struct ast_channel *chan, const char *data) } } - ast_format_copy(&origrformat, ast_channel_readformat(chan)); - if ((ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR))) { + origrformat = ao2_bump(ast_channel_readformat(chan)); + if ((ast_set_read_format(chan, ast_format_slin))) { ast_log(LOG_WARNING, "Unable to set read format to linear!\n"); res = -1; break; @@ -187,7 +188,8 @@ static int background_detect_exec(struct ast_channel *chan, const char *data) ast_frfree(fr); break; } - } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass.format.id == AST_FORMAT_SLINEAR) && continue_analysis) { + } else if ((fr->frametype == AST_FRAME_VOICE) && + (ast_format_cmp(fr->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) && continue_analysis) { int totalsilence; int ms; res = ast_dsp_silence(dsp, fr, &totalsilence); @@ -233,9 +235,9 @@ static int background_detect_exec(struct ast_channel *chan, const char *data) } while (0); if (res > -1) { - if (origrformat.id && ast_set_read_format(chan, &origrformat)) { + if (origrformat && ast_set_read_format(chan, origrformat)) { ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", - ast_channel_name(chan), ast_getformatname(&origrformat)); + ast_channel_name(chan), ast_format_get_name(origrformat)); } } if (dsp) { diff --git a/apps/app_test.c b/apps/app_test.c index 5b7b979e6..54139ba80 100644 --- a/apps/app_test.c +++ b/apps/app_test.c @@ -44,6 +44,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/pbx.h" #include "asterisk/utils.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <application name="TestServer" language="en_US"> @@ -91,11 +92,12 @@ static int measurenoise(struct ast_channel *chan, int ms, char *who) short *foo; struct timeval start; struct ast_frame *f; - struct ast_format rformat; + struct ast_format *rformat; - ast_format_copy(&rformat, ast_channel_readformat(chan)); - if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) { + rformat = ao2_bump(ast_channel_readformat(chan)); + if (ast_set_read_format(chan, ast_format_slin)) { ast_log(LOG_NOTICE, "Unable to set to linear mode!\n"); + ao2_cleanup(rformat); return -1; } start = ast_tvnow(); @@ -111,7 +113,8 @@ static int measurenoise(struct ast_channel *chan, int ms, char *who) res = -1; break; } - if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id == AST_FORMAT_SLINEAR)) { + if ((f->frametype == AST_FRAME_VOICE) && + (ast_format_cmp(f->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) { foo = (short *)f->data.ptr; for (x=0;x<f->samples;x++) { noise += abs(foo[x]); @@ -121,11 +124,13 @@ static int measurenoise(struct ast_channel *chan, int ms, char *who) ast_frfree(f); } - if (rformat.id) { - if (ast_set_read_format(chan, &rformat)) { + if (rformat) { + if (ast_set_read_format(chan, rformat)) { ast_log(LOG_NOTICE, "Unable to restore original format!\n"); + ao2_ref(rformat, -1); return -1; } + ao2_ref(rformat, -1); } if (res < 0) return res; diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 9c8a4b8ad..8a9c0f3ca 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -135,6 +135,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/astobj2.h" #include "asterisk/taskprocessor.h" #include "asterisk/test.h" +#include "asterisk/format_cache.h" #ifdef ODBC_STORAGE #include "asterisk/res_odbc.h" @@ -6112,13 +6113,16 @@ static int msg_create_from_file(struct ast_vm_recording_data *recdata) if ((recording_fs = ast_readfile(recdata->recording_file, recdata->recording_ext, NULL, 0, 0, VOICEMAIL_DIR_MODE))) { if (!ast_seekstream(recording_fs, 0, SEEK_END)) { long framelength = ast_tellstream(recording_fs); - struct ast_format result = {0,}; + struct ast_format *result; /* XXX This use of ast_getformatbyname seems incorrect here. The file extension does not necessarily correspond * to the name of the format. For instance, if "raw" were passed in, I don't think ast_getformatbyname would * find the slinear format */ - ast_getformatbyname(recdata->recording_ext, &result); - duration = (int) (framelength / ast_format_rate(&result)); + result = ast_format_cache_get(recdata->recording_ext); + if (result) { + duration = (int) (framelength / ast_format_get_sample_rate(result)); + ao2_ref(result, -1); + } } } @@ -14026,7 +14030,7 @@ AST_TEST_DEFINE(test_voicemail_vmsayname) struct ast_channel *test_channel1 = NULL; int res = -1; - struct ast_format_cap *nativeformats; + struct ast_format_cap *capabilities; static const struct ast_channel_tech fake_tech = { .write = fake_write, @@ -14051,12 +14055,17 @@ AST_TEST_DEFINE(test_voicemail_vmsayname) } /* normally this is done in the channel driver */ - ast_format_set(ast_channel_writeformat(test_channel1), AST_FORMAT_GSM, 0); - nativeformats = ast_channel_nativeformats(test_channel1); - ast_format_cap_add(nativeformats, ast_channel_writeformat(test_channel1)); - ast_format_set(ast_channel_rawwriteformat(test_channel1), AST_FORMAT_GSM, 0); - ast_format_set(ast_channel_readformat(test_channel1), AST_FORMAT_GSM, 0); - ast_format_set(ast_channel_rawreadformat(test_channel1), AST_FORMAT_GSM, 0); + capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!capabilities) { + goto exit_vmsayname_test; + } + ast_format_cap_append(capabilities, ast_format_gsm, 0); + ast_channel_nativeformats_set(test_channel1, capabilities); + ao2_ref(capabilities, -1); + ast_channel_set_writeformat(test_channel1, ast_format_gsm); + ast_channel_set_rawwriteformat(test_channel1, ast_format_gsm); + ast_channel_set_readformat(test_channel1, ast_format_gsm); + ast_channel_set_rawreadformat(test_channel1, ast_format_gsm); ast_channel_tech_set(test_channel1, &fake_tech); ast_channel_unlock(test_channel1); diff --git a/apps/app_waitforsilence.c b/apps/app_waitforsilence.c index 53870df30..f2111d720 100644 --- a/apps/app_waitforsilence.c +++ b/apps/app_waitforsilence.c @@ -51,6 +51,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/pbx.h" #include "asterisk/dsp.h" #include "asterisk/module.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <application name="WaitForSilence" language="en_US"> @@ -129,7 +130,7 @@ static char *app_noise = "WaitForNoise"; static int do_waiting(struct ast_channel *chan, int timereqd, time_t waitstart, int timeout, int wait_for_silence) { struct ast_frame *f = NULL; int dsptime = 0; - struct ast_format rfmt; + RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup); int res = 0; struct ast_dsp *sildet; /* silence detector dsp */ time_t now; @@ -138,8 +139,8 @@ static int do_waiting(struct ast_channel *chan, int timereqd, time_t waitstart, int (*ast_dsp_func)(struct ast_dsp*, struct ast_frame*, int*) = wait_for_silence ? ast_dsp_silence : ast_dsp_noise; - ast_format_copy(&rfmt, ast_channel_readformat(chan)); /* Set to linear mode */ - if ((res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) < 0) { + rfmt = ao2_bump(ast_channel_readformat(chan)); + if ((res = ast_set_read_format(chan, ast_format_slin)) < 0) { ast_log(LOG_WARNING, "Unable to set channel to linear mode, giving up\n"); return -1; } @@ -199,8 +200,8 @@ static int do_waiting(struct ast_channel *chan, int timereqd, time_t waitstart, } - if (rfmt.id && ast_set_read_format(chan, &rfmt)) { - ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(&rfmt), ast_channel_name(chan)); + if (rfmt && ast_set_read_format(chan, rfmt)) { + ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_format_get_name(rfmt), ast_channel_name(chan)); } ast_dsp_free(sildet); return res; diff --git a/apps/confbridge/conf_chan_record.c b/apps/confbridge/conf_chan_record.c index 34de5af3b..0e298e78d 100644 --- a/apps/confbridge/conf_chan_record.c +++ b/apps/confbridge/conf_chan_record.c @@ -33,6 +33,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/channel.h" #include "asterisk/bridge.h" +#include "asterisk/format_cache.h" #include "include/confbridge.h" /* ------------------------------------------------------------------- */ @@ -56,8 +57,14 @@ static int rec_write(struct ast_channel *ast, struct ast_frame *f) static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause) { struct ast_channel *chan; - struct ast_format format; const char *conf_name = data; + RAII_VAR(struct ast_format_cap *, capabilities, NULL, ao2_cleanup); + + capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!capabilities) { + return NULL; + } + ast_format_cap_append_by_type(capabilities, AST_MEDIA_TYPE_UNKNOWN); chan = ast_channel_alloc(1, AST_STATE_UP, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "CBRec/conf-%s-uid-%d", @@ -70,13 +77,13 @@ static struct ast_channel *rec_request(const char *type, struct ast_format_cap * ast_channel_release(chan); return NULL; } - ast_format_set(&format, AST_FORMAT_SLINEAR, 0); + ast_channel_tech_set(chan, conf_record_get_tech()); - ast_format_cap_add_all(ast_channel_nativeformats(chan)); - ast_format_copy(ast_channel_writeformat(chan), &format); - ast_format_copy(ast_channel_rawwriteformat(chan), &format); - ast_format_copy(ast_channel_readformat(chan), &format); - ast_format_copy(ast_channel_rawreadformat(chan), &format); + ast_channel_nativeformats_set(chan, capabilities); + ast_channel_set_writeformat(chan, ast_format_slin); + ast_channel_set_rawwriteformat(chan, ast_format_slin); + ast_channel_set_readformat(chan, ast_format_slin); + ast_channel_set_rawreadformat(chan, ast_format_slin); ast_channel_unlock(chan); return chan; } diff --git a/bridges/bridge_holding.c b/bridges/bridge_holding.c index 5eeb4708d..c343cc624 100644 --- a/bridges/bridge_holding.c +++ b/bridges/bridge_holding.c @@ -48,6 +48,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/bridge_technology.h" #include "asterisk/frame.h" #include "asterisk/musiconhold.h" +#include "asterisk/format_cache.h" enum holding_roles { HOLDING_ROLE_PARTICIPANT, @@ -180,7 +181,7 @@ static void participant_reaction_announcer_join(struct ast_bridge_channel *bridg chan = bridge_channel->chan; participant_entertainment_stop(bridge_channel); - if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) { + if (ast_set_write_format(chan, ast_format_slin)) { ast_log(LOG_WARNING, "Could not make participant %s compatible.\n", ast_channel_name(chan)); } } @@ -233,7 +234,7 @@ static void handle_participant_join(struct ast_bridge_channel *bridge_channel, s } /* We need to get compatible with the announcer. */ - if (ast_set_write_format_by_id(us, AST_FORMAT_SLINEAR)) { + if (ast_set_write_format(us, ast_format_slin)) { ast_log(LOG_WARNING, "Could not make participant %s compatible.\n", ast_channel_name(us)); } } @@ -270,7 +271,7 @@ static int holding_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chan hc->role = HOLDING_ROLE_ANNOUNCER; /* The announcer should always be made compatible with signed linear */ - if (ast_set_read_format_by_id(us, AST_FORMAT_SLINEAR)) { + if (ast_set_read_format(us, ast_format_slin)) { ast_log(LOG_ERROR, "Could not make announcer %s compatible.\n", ast_channel_name(us)); } @@ -427,18 +428,19 @@ static void deferred_action(struct ast_bridge_channel *bridge_channel, const voi static int unload_module(void) { - ast_format_cap_destroy(holding_bridge.format_capabilities); + ao2_cleanup(holding_bridge.format_capabilities); + holding_bridge.format_capabilities = NULL; return ast_bridge_technology_unregister(&holding_bridge); } static int load_module(void) { - if (!(holding_bridge.format_capabilities = ast_format_cap_alloc(0))) { + if (!(holding_bridge.format_capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_DECLINE; } - ast_format_cap_add_all_by_type(holding_bridge.format_capabilities, AST_FORMAT_TYPE_AUDIO); - ast_format_cap_add_all_by_type(holding_bridge.format_capabilities, AST_FORMAT_TYPE_VIDEO); - ast_format_cap_add_all_by_type(holding_bridge.format_capabilities, AST_FORMAT_TYPE_TEXT); + ast_format_cap_append_by_type(holding_bridge.format_capabilities, AST_MEDIA_TYPE_AUDIO); + ast_format_cap_append_by_type(holding_bridge.format_capabilities, AST_MEDIA_TYPE_VIDEO); + ast_format_cap_append_by_type(holding_bridge.format_capabilities, AST_MEDIA_TYPE_TEXT); return ast_bridge_technology_register(&holding_bridge); } diff --git a/bridges/bridge_native_rtp.c b/bridges/bridge_native_rtp.c index 2362ad296..4655efeae 100644 --- a/bridges/bridge_native_rtp.c +++ b/bridges/bridge_native_rtp.c @@ -137,8 +137,8 @@ static void native_rtp_bridge_start(struct ast_bridge *bridge, struct ast_channe RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup); RAII_VAR(struct ast_rtp_instance *, tinstance0, NULL, ao2_cleanup); RAII_VAR(struct ast_rtp_instance *, tinstance1, NULL, ao2_cleanup); - RAII_VAR(struct ast_format_cap *, cap0, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK), ast_format_cap_destroy); - RAII_VAR(struct ast_format_cap *, cap1, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK), ast_format_cap_destroy); + RAII_VAR(struct ast_format_cap *, cap0, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup); + RAII_VAR(struct ast_format_cap *, cap1, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup); if (c0 == c1) { return; @@ -316,8 +316,8 @@ static int native_rtp_bridge_compatible(struct ast_bridge *bridge) RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup); RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup); RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup); - RAII_VAR(struct ast_format_cap *, cap0, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK), ast_format_cap_destroy); - RAII_VAR(struct ast_format_cap *, cap1, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK), ast_format_cap_destroy); + RAII_VAR(struct ast_format_cap *, cap0, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup); + RAII_VAR(struct ast_format_cap *, cap1, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup); int read_ptime0, read_ptime1, write_ptime0, write_ptime1; /* We require two channels before even considering native bridging */ @@ -374,19 +374,18 @@ static int native_rtp_bridge_compatible(struct ast_bridge *bridge) if (glue1->get_codec) { glue1->get_codec(c1->chan, cap1); } - if (!ast_format_cap_is_empty(cap0) && !ast_format_cap_is_empty(cap1) && !ast_format_cap_has_joint(cap0, cap1)) { - char tmp0[256] = { 0, }, tmp1[256] = { 0, }; - + if (ast_format_cap_count(cap0) != 0 && ast_format_cap_count(cap1) != 0 && !ast_format_cap_iscompatible(cap0, cap1)) { + struct ast_str *codec_buf0 = ast_str_alloca(64); + struct ast_str *codec_buf1 = ast_str_alloca(64); ast_debug(1, "Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP.\n", - ast_getformatname_multiple(tmp0, sizeof(tmp0), cap0), - ast_getformatname_multiple(tmp1, sizeof(tmp1), cap1)); + ast_format_cap_get_names(cap0, &codec_buf0), ast_format_cap_get_names(cap1, &codec_buf1)); return 0; } - read_ptime0 = (ast_codec_pref_getsize(&ast_rtp_instance_get_codecs(instance0)->pref, ast_channel_rawreadformat(c0->chan))).cur_ms; - read_ptime1 = (ast_codec_pref_getsize(&ast_rtp_instance_get_codecs(instance1)->pref, ast_channel_rawreadformat(c1->chan))).cur_ms; - write_ptime0 = (ast_codec_pref_getsize(&ast_rtp_instance_get_codecs(instance0)->pref, ast_channel_rawwriteformat(c0->chan))).cur_ms; - write_ptime1 = (ast_codec_pref_getsize(&ast_rtp_instance_get_codecs(instance1)->pref, ast_channel_rawwriteformat(c1->chan))).cur_ms; + read_ptime0 = ast_format_cap_get_format_framing(cap0, ast_channel_rawreadformat(c0->chan)); + read_ptime1 = ast_format_cap_get_format_framing(cap1, ast_channel_rawreadformat(c1->chan)); + write_ptime0 = ast_format_cap_get_format_framing(cap0, ast_channel_rawwriteformat(c0->chan)); + write_ptime1 = ast_format_cap_get_format_framing(cap1, ast_channel_rawwriteformat(c1->chan)); if (read_ptime0 != write_ptime1 || read_ptime1 != write_ptime0) { ast_debug(1, "Packetization differs between RTP streams (%d != %d or %d != %d). Cannot native bridge in RTP\n", @@ -518,7 +517,7 @@ static struct ast_bridge_technology native_rtp_bridge = { static int unload_module(void) { - ast_format_cap_destroy(native_rtp_bridge.format_capabilities); + ao2_t_ref(native_rtp_bridge.format_capabilities, -1, "Dispose of capabilities in module unload"); return ast_bridge_technology_unregister(&native_rtp_bridge); } @@ -527,9 +526,9 @@ static int load_module(void) if (!(native_rtp_bridge.format_capabilities = ast_format_cap_alloc(0))) { return AST_MODULE_LOAD_DECLINE; } - ast_format_cap_add_all_by_type(native_rtp_bridge.format_capabilities, AST_FORMAT_TYPE_AUDIO); - ast_format_cap_add_all_by_type(native_rtp_bridge.format_capabilities, AST_FORMAT_TYPE_VIDEO); - ast_format_cap_add_all_by_type(native_rtp_bridge.format_capabilities, AST_FORMAT_TYPE_TEXT); + ast_format_cap_append_by_type(native_rtp_bridge.format_capabilities, AST_MEDIA_TYPE_AUDIO); + ast_format_cap_append_by_type(native_rtp_bridge.format_capabilities, AST_MEDIA_TYPE_VIDEO); + ast_format_cap_append_by_type(native_rtp_bridge.format_capabilities, AST_MEDIA_TYPE_TEXT); return ast_bridge_technology_register(&native_rtp_bridge); } diff --git a/bridges/bridge_simple.c b/bridges/bridge_simple.c index 4a03dbe10..1626a3993 100644 --- a/bridges/bridge_simple.c +++ b/bridges/bridge_simple.c @@ -76,18 +76,19 @@ static struct ast_bridge_technology simple_bridge = { static int unload_module(void) { - ast_format_cap_destroy(simple_bridge.format_capabilities); + ao2_cleanup(simple_bridge.format_capabilities); + simple_bridge.format_capabilities = NULL; return ast_bridge_technology_unregister(&simple_bridge); } static int load_module(void) { - if (!(simple_bridge.format_capabilities = ast_format_cap_alloc(0))) { + if (!(simple_bridge.format_capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_DECLINE; } - ast_format_cap_add_all_by_type(simple_bridge.format_capabilities, AST_FORMAT_TYPE_AUDIO); - ast_format_cap_add_all_by_type(simple_bridge.format_capabilities, AST_FORMAT_TYPE_VIDEO); - ast_format_cap_add_all_by_type(simple_bridge.format_capabilities, AST_FORMAT_TYPE_TEXT); + ast_format_cap_append_by_type(simple_bridge.format_capabilities, AST_MEDIA_TYPE_AUDIO); + ast_format_cap_append_by_type(simple_bridge.format_capabilities, AST_MEDIA_TYPE_VIDEO); + ast_format_cap_append_by_type(simple_bridge.format_capabilities, AST_MEDIA_TYPE_TEXT); return ast_bridge_technology_register(&simple_bridge); } diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index 3f743550c..f5f4c2b16 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -163,14 +163,14 @@ struct softmix_mixing_array { struct softmix_translate_helper_entry { int num_times_requested; /*!< Once this entry is no longer requested, free the trans_pvt and re-init if it was usable. */ - struct ast_format dst_format; /*!< The destination format for this helper */ + struct ast_format *dst_format; /*!< The destination format for this helper */ struct ast_trans_pvt *trans_pvt; /*!< the translator for this slot. */ struct ast_frame *out_frame; /*!< The output frame from the last translation */ AST_LIST_ENTRY(softmix_translate_helper_entry) entry; }; struct softmix_translate_helper { - struct ast_format slin_src; /*!< the source format expected for all the translators */ + struct ast_format *slin_src; /*!< the source format expected for all the translators */ AST_LIST_HEAD_NOLOCK(, softmix_translate_helper_entry) entries; }; @@ -180,12 +180,14 @@ static struct softmix_translate_helper_entry *softmix_translate_helper_entry_all if (!(entry = ast_calloc(1, sizeof(*entry)))) { return NULL; } - ast_format_copy(&entry->dst_format, dst); + entry->dst_format = ao2_bump(dst); return entry; } static void *softmix_translate_helper_free_entry(struct softmix_translate_helper_entry *entry) { + ao2_cleanup(entry->dst_format); + if (entry->trans_pvt) { ast_translator_free_path(entry->trans_pvt); } @@ -199,7 +201,7 @@ static void *softmix_translate_helper_free_entry(struct softmix_translate_helper static void softmix_translate_helper_init(struct softmix_translate_helper *trans_helper, unsigned int sample_rate) { memset(trans_helper, 0, sizeof(*trans_helper)); - ast_format_set(&trans_helper->slin_src, ast_format_slin_by_rate(sample_rate), 0); + trans_helper->slin_src = ast_format_cache_get_slin_by_rate(sample_rate); } static void softmix_translate_helper_destroy(struct softmix_translate_helper *trans_helper) @@ -215,11 +217,11 @@ static void softmix_translate_helper_change_rate(struct softmix_translate_helper { struct softmix_translate_helper_entry *entry; - ast_format_set(&trans_helper->slin_src, ast_format_slin_by_rate(sample_rate), 0); + trans_helper->slin_src = ast_format_cache_get_slin_by_rate(sample_rate); AST_LIST_TRAVERSE_SAFE_BEGIN(&trans_helper->entries, entry, entry) { if (entry->trans_pvt) { ast_translator_free_path(entry->trans_pvt); - if (!(entry->trans_pvt = ast_translator_build_path(&entry->dst_format, &trans_helper->slin_src))) { + if (!(entry->trans_pvt = ast_translator_build_path(entry->dst_format, trans_helper->slin_src))) { AST_LIST_REMOVE_CURRENT(entry); entry = softmix_translate_helper_free_entry(entry); } @@ -274,19 +276,19 @@ static void softmix_process_write_audio(struct softmix_translate_helper *trans_h } AST_LIST_TRAVERSE(&trans_helper->entries, entry, entry) { - if (ast_format_cmp(&entry->dst_format, raw_write_fmt) == AST_FORMAT_CMP_EQUAL) { + if (ast_format_cmp(entry->dst_format, raw_write_fmt) == AST_FORMAT_CMP_EQUAL) { entry->num_times_requested++; } else { continue; } if (!entry->trans_pvt && (entry->num_times_requested > 1)) { - entry->trans_pvt = ast_translator_build_path(&entry->dst_format, &trans_helper->slin_src); + entry->trans_pvt = ast_translator_build_path(entry->dst_format, trans_helper->slin_src); } if (entry->trans_pvt && !entry->out_frame) { entry->out_frame = ast_translate(entry->trans_pvt, &sc->write_frame, 0); } if (entry->out_frame && (entry->out_frame->datalen < MAX_DATALEN)) { - ast_format_copy(&sc->write_frame.subclass.format, &entry->out_frame->subclass.format); + ao2_replace(sc->write_frame.subclass.format, entry->out_frame->subclass.format); memcpy(sc->final_buf, entry->out_frame->data.ptr, entry->out_frame->datalen); sc->write_frame.datalen = entry->out_frame->datalen; sc->write_frame.samples = entry->out_frame->samples; @@ -316,32 +318,45 @@ static void softmix_translate_helper_cleanup(struct softmix_translate_helper *tr static void set_softmix_bridge_data(int rate, int interval, struct ast_bridge_channel *bridge_channel, int reset) { struct softmix_channel *sc = bridge_channel->tech_pvt; - unsigned int channel_read_rate = ast_format_rate(ast_channel_rawreadformat(bridge_channel->chan)); + unsigned int channel_read_rate = ast_format_get_sample_rate(ast_channel_rawreadformat(bridge_channel->chan)); ast_mutex_lock(&sc->lock); if (reset) { ast_slinfactory_destroy(&sc->factory); ast_dsp_free(sc->dsp); } - /* Setup read/write frame parameters */ + + /* Setup write frame parameters */ sc->write_frame.frametype = AST_FRAME_VOICE; - ast_format_set(&sc->write_frame.subclass.format, ast_format_slin_by_rate(rate), 0); + ao2_cleanup(sc->write_frame.subclass.format); + /* + * NOTE: The format is bumped here because translation could + * be needed and the format changed to the translated format + * for the channel. The translated format may not be a + * static cached format. + */ + sc->write_frame.subclass.format = ao2_bump(ast_format_cache_get_slin_by_rate(rate)); sc->write_frame.data.ptr = sc->final_buf; sc->write_frame.datalen = SOFTMIX_DATALEN(rate, interval); sc->write_frame.samples = SOFTMIX_SAMPLES(rate, interval); + /* Setup read frame parameters */ sc->read_frame.frametype = AST_FRAME_VOICE; - ast_format_set(&sc->read_frame.subclass.format, ast_format_slin_by_rate(channel_read_rate), 0); + /* + * NOTE: The format is not bumbed here because it will always + * be a signed linear format. + */ + sc->read_frame.subclass.format = ast_format_cache_get_slin_by_rate(channel_read_rate); sc->read_frame.data.ptr = sc->our_buf; sc->read_frame.datalen = SOFTMIX_DATALEN(channel_read_rate, interval); sc->read_frame.samples = SOFTMIX_SAMPLES(channel_read_rate, interval); /* Setup smoother */ - ast_slinfactory_init_with_format(&sc->factory, &sc->write_frame.subclass.format); + ast_slinfactory_init_with_format(&sc->factory, sc->write_frame.subclass.format); /* set new read and write formats on channel. */ - ast_set_read_format(bridge_channel->chan, &sc->read_frame.subclass.format); - ast_set_write_format(bridge_channel->chan, &sc->write_frame.subclass.format); + ast_set_read_format(bridge_channel->chan, sc->read_frame.subclass.format); + ast_set_write_format(bridge_channel->chan, sc->write_frame.subclass.format); /* set up new DSP. This is on the read side only right before the read frame enters the smoother. */ sc->dsp = ast_dsp_new_with_rate(channel_read_rate); @@ -446,6 +461,9 @@ static void softmix_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_ch /* Drop the factory */ ast_slinfactory_destroy(&sc->factory); + /* Drop any formats on the frames */ + ao2_cleanup(sc->write_frame.subclass.format); + /* Drop the DSP */ ast_dsp_free(sc->dsp); @@ -500,7 +518,7 @@ static void softmix_bridge_write_video(struct ast_bridge *bridge, struct ast_bri ast_mutex_lock(&sc->lock); ast_bridge_update_talker_src_video_mode(bridge, bridge_channel->chan, sc->video_talker.energy_average, - ast_format_get_video_mark(&frame->subclass.format)); + frame->subclass.frame_ending); ast_mutex_unlock(&sc->lock); video_src_priority = ast_bridge_is_video_src(bridge, bridge_channel->chan); if (video_src_priority == 1) { @@ -575,8 +593,7 @@ static void softmix_bridge_write_voice(struct ast_bridge *bridge, struct ast_bri /* If a frame was provided add it to the smoother, unless drop silence is enabled and this frame * is not determined to be talking. */ - if (!(bridge_channel->tech_args.drop_silence && !sc->talking) && - (frame->frametype == AST_FRAME_VOICE && ast_format_is_slinear(&frame->subclass.format))) { + if (!(bridge_channel->tech_args.drop_silence && !sc->talking)) { ast_slinfactory_feed(&sc->factory, frame); } @@ -680,8 +697,8 @@ static void gather_softmix_stats(struct softmix_stats *stats, int channel_native_rate; int i; /* Gather stats about channel sample rates. */ - channel_native_rate = MAX(ast_format_rate(ast_channel_rawwriteformat(bridge_channel->chan)), - ast_format_rate(ast_channel_rawreadformat(bridge_channel->chan))); + channel_native_rate = MAX(ast_format_get_sample_rate(ast_channel_rawwriteformat(bridge_channel->chan)), + ast_format_get_sample_rate(ast_channel_rawreadformat(bridge_channel->chan))); if (channel_native_rate > stats->highest_supported_rate) { stats->highest_supported_rate = channel_native_rate; @@ -845,7 +862,7 @@ static int softmix_mixing_loop(struct ast_bridge *bridge) while (!softmix_data->stop && bridge->num_active) { struct ast_bridge_channel *bridge_channel; int timeout = -1; - enum ast_format_id cur_slin_id = ast_format_slin_by_rate(softmix_data->internal_rate); + struct ast_format *cur_slin = ast_format_cache_get_slin_by_rate(softmix_data->internal_rate); unsigned int softmix_samples = SOFTMIX_SAMPLES(softmix_data->internal_rate, softmix_data->internal_mixing_interval); unsigned int softmix_datalen = SOFTMIX_DATALEN(softmix_data->internal_rate, softmix_data->internal_mixing_interval); @@ -927,9 +944,8 @@ static int softmix_mixing_loop(struct ast_bridge *bridge) ast_mutex_lock(&sc->lock); /* Make SLINEAR write frame from local buffer */ - if (sc->write_frame.subclass.format.id != cur_slin_id) { - ast_format_set(&sc->write_frame.subclass.format, cur_slin_id, 0); - } + ao2_t_replace(sc->write_frame.subclass.format, cur_slin, + "Replace softmix channel slin format"); sc->write_frame.datalen = softmix_datalen; sc->write_frame.samples = softmix_samples; memcpy(sc->final_buf, buf, softmix_datalen); @@ -1144,17 +1160,17 @@ static struct ast_bridge_technology softmix_bridge = { static int unload_module(void) { - ast_format_cap_destroy(softmix_bridge.format_capabilities); + ao2_cleanup(softmix_bridge.format_capabilities); + softmix_bridge.format_capabilities = NULL; return ast_bridge_technology_unregister(&softmix_bridge); } static int load_module(void) { - struct ast_format tmp; - if (!(softmix_bridge.format_capabilities = ast_format_cap_alloc(0))) { + if (!(softmix_bridge.format_capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_DECLINE; } - ast_format_cap_add(softmix_bridge.format_capabilities, ast_format_set(&tmp, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(softmix_bridge.format_capabilities, ast_format_slin, 0); return ast_bridge_technology_register(&softmix_bridge); } diff --git a/channels/chan_alsa.c b/channels/chan_alsa.c index 9d43ba139..f74e78fd6 100644 --- a/channels/chan_alsa.c +++ b/channels/chan_alsa.c @@ -63,6 +63,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/musiconhold.h" #include "asterisk/poll-compat.h" #include "asterisk/stasis_channels.h" +#include "asterisk/format_cache.h" /*! Global jitterbuffer configuration - by default, jb is disabled * \note Values shown here match the defaults shown in alsa.conf.sample */ @@ -511,7 +512,7 @@ static struct ast_frame *alsa_read(struct ast_channel *chan) } f.frametype = AST_FRAME_VOICE; - ast_format_set(&f.subclass.format, AST_FORMAT_SLINEAR, 0); + f.subclass.format = ast_format_slin; f.samples = FRAME_SIZE; f.datalen = FRAME_SIZE * 2; f.data.ptr = buf; @@ -585,9 +586,9 @@ static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state, const st ast_channel_tech_set(tmp, &alsa_tech); ast_channel_set_fd(tmp, 0, readdev); - ast_format_set(ast_channel_readformat(tmp), AST_FORMAT_SLINEAR, 0); - ast_format_set(ast_channel_writeformat(tmp), AST_FORMAT_SLINEAR, 0); - ast_format_cap_add(ast_channel_nativeformats(tmp), ast_channel_writeformat(tmp)); + ast_channel_set_readformat(tmp, ast_format_slin); + ast_channel_set_writeformat(tmp, ast_format_slin); + ast_channel_nativeformats_set(tmp, alsa_tech.capabilities); ast_channel_tech_pvt_set(tmp, p); if (!ast_strlen_zero(p->context)) @@ -616,14 +617,11 @@ static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state, const st static struct ast_channel *alsa_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause) { - struct ast_format tmpfmt; - char buf[256]; struct ast_channel *tmp = NULL; - ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0); - - if (!(ast_format_cap_iscompatible(cap, &tmpfmt))) { - ast_log(LOG_NOTICE, "Asked to get a channel of format '%s'\n", ast_getformatname_multiple(buf, sizeof(buf), cap)); + if (ast_format_cap_iscompatible_format(cap, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_str *codec_buf = ast_str_alloca(64); + ast_log(LOG_NOTICE, "Asked to get a channel of format '%s'\n", ast_format_cap_get_names(cap, &codec_buf)); return NULL; } @@ -959,12 +957,11 @@ static int load_module(void) struct ast_config *cfg; struct ast_variable *v; struct ast_flags config_flags = { 0 }; - struct ast_format tmpfmt; - if (!(alsa_tech.capabilities = ast_format_cap_alloc(0))) { + if (!(alsa_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_DECLINE; } - ast_format_cap_add(alsa_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(alsa_tech.capabilities, ast_format_slin, 0); /* Copy the default jb config over global_jbconf */ memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); @@ -1042,7 +1039,9 @@ static int unload_module(void) if (alsa.owner) return -1; - alsa_tech.capabilities = ast_format_cap_destroy(alsa_tech.capabilities); + ao2_cleanup(alsa_tech.capabilities); + alsa_tech.capabilities = NULL; + return 0; } diff --git a/channels/chan_bridge_media.c b/channels/chan_bridge_media.c index ac15e7d70..6502b5c77 100644 --- a/channels/chan_bridge_media.c +++ b/channels/chan_bridge_media.c @@ -164,11 +164,13 @@ static struct ast_channel *record_request(const char *type, struct ast_format_ca static void cleanup_capabilities(void) { if (announce_tech.capabilities) { - announce_tech.capabilities = ast_format_cap_destroy(announce_tech.capabilities); + ao2_ref(announce_tech.capabilities, -1); + announce_tech.capabilities = NULL; } if (record_tech.capabilities) { - record_tech.capabilities = ast_format_cap_destroy(record_tech.capabilities); + ao2_ref(record_tech.capabilities, -1); + record_tech.capabilities = NULL; } } @@ -182,18 +184,18 @@ static int unload_module(void) static int load_module(void) { - announce_tech.capabilities = ast_format_cap_alloc(0); + announce_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!announce_tech.capabilities) { return AST_MODULE_LOAD_DECLINE; } - record_tech.capabilities = ast_format_cap_alloc(0); + record_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!record_tech.capabilities) { return AST_MODULE_LOAD_DECLINE; } - ast_format_cap_add_all(announce_tech.capabilities); - ast_format_cap_add_all(record_tech.capabilities); + ast_format_cap_append_by_type(announce_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_by_type(record_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN); if (ast_channel_register(&announce_tech)) { ast_log(LOG_ERROR, "Unable to register channel technology %s(%s).\n", diff --git a/channels/chan_console.c b/channels/chan_console.c index b1f5cdf7c..3aeda931a 100644 --- a/channels/chan_console.c +++ b/channels/chan_console.c @@ -77,6 +77,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/callerid.h" #include "asterisk/astobj2.h" #include "asterisk/stasis_channels.h" +#include "asterisk/format_cache.h" /*! * \brief The sample rate to request from PortAudio @@ -270,12 +271,12 @@ static void *stream_monitor(void *data) PaError res; struct ast_frame f = { .frametype = AST_FRAME_VOICE, + .subclass.format = ast_format_slin16, .src = "console_stream_monitor", .data.ptr = buf, .datalen = sizeof(buf), .samples = sizeof(buf) / sizeof(int16_t), }; - ast_format_set(&f.subclass.format, AST_FORMAT_SLINEAR16, 0); for (;;) { pthread_testcancel(); @@ -421,19 +422,28 @@ static int stop_stream(struct console_pvt *pvt) */ static struct ast_channel *console_new(struct console_pvt *pvt, const char *ext, const char *ctx, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor) { + struct ast_format_cap *caps; struct ast_channel *chan; + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + return NULL; + } + if (!(chan = ast_channel_alloc(1, state, pvt->cid_num, pvt->cid_name, NULL, ext, ctx, assignedids, requestor, 0, "Console/%s", pvt->name))) { + ao2_ref(caps, -1); return NULL; } ast_channel_stage_snapshot(chan); ast_channel_tech_set(chan, &console_tech); - ast_format_set(ast_channel_readformat(chan), AST_FORMAT_SLINEAR16, 0); - ast_format_set(ast_channel_writeformat(chan), AST_FORMAT_SLINEAR16, 0); - ast_format_cap_add(ast_channel_nativeformats(chan), ast_channel_readformat(chan)); + ast_channel_set_readformat(chan, ast_format_slin16); + ast_channel_set_writeformat(chan, ast_format_slin16); + ast_format_cap_append(caps, ast_format_slin16, 0); + ast_channel_nativeformats_set(chan, caps); + ao2_ref(caps, -1); ast_channel_tech_pvt_set(chan, ref_pvt(pvt)); pvt->owner = chan; @@ -462,15 +472,16 @@ static struct ast_channel *console_request(const char *type, struct ast_format_c { struct ast_channel *chan = NULL; struct console_pvt *pvt; - char buf[512]; if (!(pvt = find_pvt(data))) { ast_log(LOG_ERROR, "Console device '%s' not found\n", data); return NULL; } - if (!(ast_format_cap_has_joint(cap, console_tech.capabilities))) { - ast_log(LOG_NOTICE, "Channel requested with unsupported format(s): '%s'\n", ast_getformatname_multiple(buf, sizeof(buf), cap)); + if (!(ast_format_cap_iscompatible(cap, console_tech.capabilities))) { + struct ast_str *cap_buf = ast_str_alloca(64); + ast_log(LOG_NOTICE, "Channel requested with unsupported format(s): '%s'\n", + ast_format_cap_get_names(cap, &cap_buf)); goto return_unref; } @@ -1467,7 +1478,8 @@ static void stop_streams(void) static int unload_module(void) { - console_tech.capabilities = ast_format_cap_destroy(console_tech.capabilities); + ao2_ref(console_tech.capabilities, -1); + console_tech.capabilities = NULL; ast_channel_unregister(&console_tech); ast_cli_unregister_multiple(cli_console, ARRAY_LEN(cli_console)); @@ -1495,13 +1507,12 @@ static int unload_module(void) */ static int load_module(void) { - struct ast_format tmpfmt; PaError res; - if (!(console_tech.capabilities = ast_format_cap_alloc(0))) { + if (!(console_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_DECLINE; } - ast_format_cap_add(console_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR16, 0)); + ast_format_cap_append(console_tech.capabilities, ast_format_slin16, 0); init_pvt(&globals, NULL); @@ -1538,6 +1549,8 @@ return_error: if (pvts) ao2_ref(pvts, -1); pvts = NULL; + ao2_ref(console_tech.capabilities, -1); + console_tech.capabilities = NULL; pvt_destructor(&globals); return AST_MODULE_LOAD_DECLINE; diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 81242533e..c22833da5 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -129,6 +129,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/bridge.h" #include "asterisk/stasis_channels.h" #include "asterisk/parking.h" +#include "asterisk/format_cache.h" #include "chan_dahdi.h" #include "dahdi/bridge_native_dahdi.h" @@ -461,7 +462,7 @@ static struct ast_jb_conf global_jbconf; /*! \brief Typically, how many rings before we should send Caller*ID */ #define DEFAULT_CIDRINGS 1 -#define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? AST_FORMAT_ALAW : AST_FORMAT_ULAW) +#define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? ast_format_alaw : ast_format_ulaw) /*! \brief Signaling types that need to use MF detection should be placed in this macro */ @@ -1321,7 +1322,6 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e int res; unsigned char buf[256]; int flags; - struct ast_format tmpfmt; poller.fd = p->subs[SUB_REAL].dfd; poller.events = POLLPRI | POLLIN; @@ -1354,9 +1354,9 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e } if (p->cid_signalling == CID_SIG_V23_JP) { - res = callerid_feed_jp(p->cs, buf, res, ast_format_set(&tmpfmt, AST_LAW(p), 0)); + res = callerid_feed_jp(p->cs, buf, res, AST_LAW(p)); } else { - res = callerid_feed(p->cs, buf, res, ast_format_set(&tmpfmt, AST_LAW(p), 0)); + res = callerid_feed(p->cs, buf, res, AST_LAW(p)); } if (res < 0) { /* @@ -1525,7 +1525,7 @@ static int restore_conference(struct dahdi_pvt *p); static int my_callwait(void *pvt) { struct dahdi_pvt *p = pvt; - struct ast_format tmpfmt; + p->callwaitingrepeat = CALLWAITING_REPEAT_SAMPLES; if (p->cidspill) { ast_log(LOG_WARNING, "Spill already exists?!?\n"); @@ -1542,11 +1542,11 @@ static int my_callwait(void *pvt) /* Silence */ memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4); if (!p->callwaitrings && p->callwaitingcallerid) { - ast_gen_cas(p->cidspill, 1, 2400 + 680, ast_format_set(&tmpfmt, AST_LAW(p), 0)); + ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p)); p->callwaitcas = 1; p->cidlen = 2400 + 680 + READ_SIZE * 4; } else { - ast_gen_cas(p->cidspill, 1, 2400, ast_format_set(&tmpfmt, AST_LAW(p), 0)); + ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p)); p->callwaitcas = 0; p->cidlen = 2400 + READ_SIZE * 4; } @@ -1559,7 +1559,6 @@ static int my_callwait(void *pvt) static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *caller) { struct dahdi_pvt *p = pvt; - struct ast_format tmpfmt; ast_debug(2, "Starting cid spill\n"); @@ -1573,7 +1572,7 @@ static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *calle p->cidlen = ast_callerid_generate(p->cidspill, caller->id.name.str, caller->id.number.str, - ast_format_set(&tmpfmt, AST_LAW(p), 0)); + AST_LAW(p)); } else { ast_verb(3, "CPE supports Call Waiting Caller*ID. Sending '%s/%s'\n", caller->id.name.str, caller->id.number.str); @@ -1582,7 +1581,7 @@ static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *calle p->cidlen = ast_callerid_callwaiting_generate(p->cidspill, caller->id.name.str, caller->id.number.str, - ast_format_set(&tmpfmt, AST_LAW(p), 0)); + AST_LAW(p)); p->cidlen += READ_SIZE * 4; } p->cidpos = 0; @@ -4965,14 +4964,12 @@ static int restore_conference(struct dahdi_pvt *p) static int send_cwcidspill(struct dahdi_pvt *p) { - struct ast_format tmpfmt; - p->callwaitcas = 0; p->cidcwexpire = 0; p->cid_suppress_expire = 0; if (!(p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) return -1; - p->cidlen = ast_callerid_callwaiting_generate(p->cidspill, p->callwait_name, p->callwait_num, ast_format_set(&tmpfmt, AST_LAW(p), 0)); + p->cidlen = ast_callerid_callwaiting_generate(p->cidspill, p->callwait_name, p->callwait_num, AST_LAW(p)); /* Make sure we account for the end */ p->cidlen += READ_SIZE * 4; p->cidpos = 0; @@ -5038,7 +5035,7 @@ static int send_callerid(struct dahdi_pvt *p) static int dahdi_callwait(struct ast_channel *ast) { struct dahdi_pvt *p = ast_channel_tech_pvt(ast); - struct ast_format tmpfmt; + p->callwaitingrepeat = CALLWAITING_REPEAT_SAMPLES; if (p->cidspill) { ast_log(LOG_WARNING, "Spill already exists?!?\n"); @@ -5055,11 +5052,11 @@ static int dahdi_callwait(struct ast_channel *ast) /* Silence */ memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4); if (!p->callwaitrings && p->callwaitingcallerid) { - ast_gen_cas(p->cidspill, 1, 2400 + 680, ast_format_set(&tmpfmt, AST_LAW(p), 0)); + ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p)); p->callwaitcas = 1; p->cidlen = 2400 + 680 + READ_SIZE * 4; } else { - ast_gen_cas(p->cidspill, 1, 2400, ast_format_set(&tmpfmt, AST_LAW(p), 0)); + ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p)); p->callwaitcas = 0; p->cidlen = 2400 + READ_SIZE * 4; } @@ -8504,25 +8501,20 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast) return f; } - if (ast_channel_rawreadformat(ast)->id == AST_FORMAT_SLINEAR) { + if (ast_format_cmp(ast_channel_rawreadformat(ast), ast_format_slin) == AST_FORMAT_CMP_EQUAL) { if (!p->subs[idx].linear) { p->subs[idx].linear = 1; res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear); if (res) ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to linear mode.\n", p->channel, idx); } - } else if ((ast_channel_rawreadformat(ast)->id == AST_FORMAT_ULAW) || - (ast_channel_rawreadformat(ast)->id == AST_FORMAT_ALAW)) { + } else { if (p->subs[idx].linear) { p->subs[idx].linear = 0; res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear); if (res) ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to companded mode.\n", p->channel, idx); } - } else { - ast_log(LOG_WARNING, "Don't know how to read frames in format %s\n", ast_getformatname(ast_channel_rawreadformat(ast))); - ast_mutex_unlock(&p->lock); - return NULL; } readbuf = ((unsigned char *)p->subs[idx].buffer) + AST_FRIENDLY_OFFSET; CHECK_BLOCKING(ast); @@ -8612,7 +8604,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast) } p->subs[idx].f.frametype = AST_FRAME_VOICE; - ast_format_copy(&p->subs[idx].f.subclass.format, ast_channel_rawreadformat(ast)); + p->subs[idx].f.subclass.format = ast_channel_rawreadformat(ast); p->subs[idx].f.samples = READ_SIZE; p->subs[idx].f.mallocd = 0; p->subs[idx].f.offset = AST_FRIENDLY_OFFSET; @@ -8795,12 +8787,6 @@ static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame) ast_log(LOG_WARNING, "Don't know what to do with frame type '%u'\n", frame->frametype); return 0; } - if ((frame->subclass.format.id != AST_FORMAT_SLINEAR) && - (frame->subclass.format.id != AST_FORMAT_ULAW) && - (frame->subclass.format.id != AST_FORMAT_ALAW)) { - ast_log(LOG_WARNING, "Cannot handle frames in %s format\n", ast_getformatname(&frame->subclass.format)); - return -1; - } if (p->dialing) { ast_debug(5, "Dropping frame since I'm still dialing on %s...\n",ast_channel_name(ast)); return 0; @@ -8818,7 +8804,7 @@ static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame) if (!frame->data.ptr || !frame->datalen) return 0; - if (frame->subclass.format.id == AST_FORMAT_SLINEAR) { + if (ast_format_cmp(frame->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) { if (!p->subs[idx].linear) { p->subs[idx].linear = 1; res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear); @@ -8826,7 +8812,8 @@ static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame) ast_log(LOG_WARNING, "Unable to set linear mode on channel %d\n", p->channel); } res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 1); - } else { + } else if (ast_format_cmp(frame->subclass.format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL + || ast_format_cmp(frame->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) { /* x-law already */ if (p->subs[idx].linear) { p->subs[idx].linear = 0; @@ -8835,6 +8822,10 @@ static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame) ast_log(LOG_WARNING, "Unable to set companded mode on channel %d\n", p->channel); } res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 0); + } else { + ast_log(LOG_WARNING, "Cannot handle frames in %s format\n", + ast_format_get_name(frame->subclass.format)); + return -1; } if (res < 0) { ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno)); @@ -9024,7 +9015,8 @@ static struct ast_channel *dahdi_new_callid_clean(struct dahdi_pvt *i, int state static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, struct ast_callid *callid) { struct ast_channel *tmp; - struct ast_format deflaw; + struct ast_format_cap *caps; + struct ast_format *deflaw; int x; int features; struct ast_str *chan_name; @@ -9037,7 +9029,6 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb return NULL; } - ast_format_clear(&deflaw); #if defined(HAVE_PRI) /* * The dnid has been stuffed with the called-number[:subaddress] @@ -9051,9 +9042,16 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb return NULL; } + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_free(chan_name); + return NULL; + } + tmp = ast_channel_alloc(0, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, assignedids, requestor, i->amaflags, "DAHDI/%s", ast_str_buffer(chan_name)); ast_free(chan_name); if (!tmp) { + ao2_ref(caps, -1); return NULL; } @@ -9073,9 +9071,9 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb if (law) { i->law = law; if (law == DAHDI_LAW_ALAW) { - ast_format_set(&deflaw, AST_FORMAT_ALAW, 0); + deflaw = ast_format_alaw; } else { - ast_format_set(&deflaw, AST_FORMAT_ULAW, 0); + deflaw = ast_format_ulaw; } } else { switch (i->sig) { @@ -9089,18 +9087,20 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb break; } if (i->law_default == DAHDI_LAW_ALAW) { - ast_format_set(&deflaw, AST_FORMAT_ALAW, 0); + deflaw = ast_format_alaw; } else { - ast_format_set(&deflaw, AST_FORMAT_ULAW, 0); + deflaw = ast_format_ulaw; } } ast_channel_set_fd(tmp, 0, i->subs[idx].dfd); - ast_format_cap_add(ast_channel_nativeformats(tmp), &deflaw); + ast_format_cap_append(caps, deflaw, 0); + ast_channel_nativeformats_set(tmp, caps); + ao2_ref(caps, -1); /* Start out assuming ulaw since it's smaller :) */ - ast_format_copy(ast_channel_rawreadformat(tmp), &deflaw); - ast_format_copy(ast_channel_readformat(tmp), &deflaw); - ast_format_copy(ast_channel_rawwriteformat(tmp), &deflaw); - ast_format_copy(ast_channel_writeformat(tmp), &deflaw); + ast_channel_set_rawreadformat(tmp, deflaw); + ast_channel_set_readformat(tmp, deflaw); + ast_channel_set_rawwriteformat(tmp, deflaw); + ast_channel_set_writeformat(tmp, deflaw); i->subs[idx].linear = 0; dahdi_setlinear(i->subs[idx].dfd, i->subs[idx].linear); features = 0; @@ -9397,7 +9397,6 @@ static void *analog_ss_thread(void *data) int len = 0; int res; int idx; - struct ast_format tmpfmt; RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup); const char *pickupexten; @@ -10114,9 +10113,9 @@ static void *analog_ss_thread(void *data) samples += res; if (p->cid_signalling == CID_SIG_V23_JP) { - res = callerid_feed_jp(cs, buf, res, ast_format_set(&tmpfmt, AST_LAW(p), 0)); + res = callerid_feed_jp(cs, buf, res, AST_LAW(p)); } else { - res = callerid_feed(cs, buf, res, ast_format_set(&tmpfmt, AST_LAW(p), 0)); + res = callerid_feed(cs, buf, res, AST_LAW(p)); } if (res < 0) { /* @@ -10399,7 +10398,7 @@ static void *analog_ss_thread(void *data) } } samples += res; - res = callerid_feed(cs, buf, res, ast_format_set(&tmpfmt, AST_LAW(p), 0)); + res = callerid_feed(cs, buf, res, AST_LAW(p)); if (res < 0) { /* * The previous diagnostic message output likely @@ -10569,7 +10568,7 @@ struct mwi_thread_data { size_t len; }; -static int calc_energy(const unsigned char *buf, int len, enum ast_format_id law) +static int calc_energy(const unsigned char *buf, int len, struct ast_format *law) { int x; int sum = 0; @@ -10578,7 +10577,7 @@ static int calc_energy(const unsigned char *buf, int len, enum ast_format_id law return 0; for (x = 0; x < len; x++) - sum += abs(law == AST_FORMAT_ULAW ? AST_MULAW(buf[x]) : AST_ALAW(buf[x])); + sum += abs(law == ast_format_ulaw ? AST_MULAW(buf[x]) : AST_ALAW(buf[x])); return sum / len; } @@ -10594,13 +10593,12 @@ static void *mwi_thread(void *data) int i, res; unsigned int spill_done = 0; int spill_result = -1; - struct ast_format tmpfmt; if (!(cs = callerid_new(mtd->pvt->cid_signalling))) { goto quit_no_clean; } - callerid_feed(cs, mtd->buf, mtd->len, ast_format_set(&tmpfmt, AST_LAW(mtd->pvt), 0)); + callerid_feed(cs, mtd->buf, mtd->len, AST_LAW(mtd->pvt)); bump_gains(mtd->pvt); @@ -10686,7 +10684,7 @@ static void *mwi_thread(void *data) } samples += res; if (!spill_done) { - if ((spill_result = callerid_feed(cs, mtd->buf, res, ast_format_set(&tmpfmt, AST_LAW(mtd->pvt), 0))) < 0) { + if ((spill_result = callerid_feed(cs, mtd->buf, res, AST_LAW(mtd->pvt))) < 0) { /* * The previous diagnostic message output likely * explains why it failed. @@ -10744,7 +10742,6 @@ quit_no_clean: static int mwi_send_init(struct dahdi_pvt * pvt) { int x; - struct ast_format tmpfmt; #ifdef HAVE_DAHDI_LINEREVERSE_VMWI /* Determine how this spill is to be sent */ @@ -10786,8 +10783,8 @@ static int mwi_send_init(struct dahdi_pvt * pvt) #ifdef HAVE_DAHDI_LINEREVERSE_VMWI if (pvt->mwisend_fsk) { #endif - pvt->cidlen = ast_callerid_vmwi_generate(pvt->cidspill, has_voicemail(pvt), CID_MWI_TYPE_MDMF_FULL, - ast_format_set(&tmpfmt, AST_LAW(pvt), 0), pvt->cid_name, pvt->cid_num, 0); + pvt->cidlen = ast_callerid_vmwi_generate(pvt->cidspill, has_voicemail(pvt), + CID_MWI_TYPE_MDMF_FULL, AST_LAW(pvt), pvt->cid_name, pvt->cid_num, 0); pvt->cidpos = 0; #ifdef HAVE_DAHDI_LINEREVERSE_VMWI } @@ -17314,7 +17311,8 @@ static int __unload_module(void) dahdi_native_unload(); - dahdi_tech.capabilities = ast_format_cap_destroy(dahdi_tech.capabilities); + ao2_cleanup(dahdi_tech.capabilities); + dahdi_tech.capabilities = NULL; STASIS_MESSAGE_TYPE_CLEANUP(dahdichannel_type); return 0; } @@ -19496,7 +19494,6 @@ static const struct ast_data_entry dahdi_data_providers[] = { static int load_module(void) { int res; - struct ast_format tmpfmt; #if defined(HAVE_PRI) || defined(HAVE_SS7) int y; #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */ @@ -19505,14 +19502,15 @@ static int load_module(void) return AST_MODULE_LOAD_FAILURE; } - if (!(dahdi_tech.capabilities = ast_format_cap_alloc(0))) { + if (!(dahdi_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_FAILURE; } - ast_format_cap_add(dahdi_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)); - ast_format_cap_add(dahdi_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0)); - ast_format_cap_add(dahdi_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0)); + ast_format_cap_append(dahdi_tech.capabilities, ast_format_slin, 0); + ast_format_cap_append(dahdi_tech.capabilities, ast_format_ulaw, 0); + ast_format_cap_append(dahdi_tech.capabilities, ast_format_alaw, 0); if (dahdi_native_load(ast_module_info->self, &dahdi_tech)) { + ao2_ref(dahdi_tech.capabilities, -1); return AST_MODULE_LOAD_FAILURE; } @@ -19558,8 +19556,10 @@ static int load_module(void) #endif /* defined(HAVE_SS7) */ res = setup_dahdi(0); /* Make sure we can register our DAHDI channel type */ - if (res) + if (res) { + __unload_module(); return AST_MODULE_LOAD_DECLINE; + } if (ast_channel_register(&dahdi_tech)) { ast_log(LOG_ERROR, "Unable to register channel class 'DAHDI'\n"); __unload_module(); @@ -19652,10 +19652,9 @@ static int dahdi_sendtext(struct ast_channel *c, const char *text) return -1; mybuf = buf; if (p->mate) { - struct ast_format tmp; /* PUT_CLI_MARKMS is a macro and requires a format ptr called codec to be present */ - struct ast_format *codec = &tmp; - ast_format_set(codec, AST_LAW(p), 0); + struct ast_format *codec = AST_LAW(p); + for (x = 0; x < HEADER_MS; x++) { /* 50 ms of Mark */ PUT_CLID_MARKMS; } diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 4beacfb22..be5b4c751 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -116,11 +116,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/stasis.h" #include "asterisk/stasis_system.h" #include "asterisk/stasis_channels.h" +#include "asterisk/format_cache.h" +#include "asterisk/format_compatibility.h" +#include "asterisk/format_cap.h" #include "iax2/include/iax2.h" #include "iax2/include/firmware.h" #include "iax2/include/parser.h" #include "iax2/include/provision.h" +#include "iax2/include/codec_pref.h" +#include "iax2/include/format_compatibility.h" + #include "jitterbuf.h" /*** DOCUMENTATION @@ -279,7 +285,7 @@ static int nochecksums = 0; /* Sample over last 100 units to determine historic jitter */ #define GAMMA (0.01) -static struct ast_codec_pref prefs; +static struct iax2_codec_pref prefs; static const char tdesc[] = "Inter Asterisk eXchange Driver (Ver 2)"; @@ -347,22 +353,22 @@ static int (*iax2_regfunk)(const char *username, int onoff) = NULL; #define IAX_CAPABILITY_FULLBANDWIDTH 0xFFFF /* T1, maybe ISDN */ #define IAX_CAPABILITY_MEDBANDWIDTH (IAX_CAPABILITY_FULLBANDWIDTH & \ - ~ast_format_id_to_old_bitfield(AST_FORMAT_SLINEAR) & \ - ~ast_format_id_to_old_bitfield(AST_FORMAT_SLINEAR16) & \ - ~ast_format_id_to_old_bitfield(AST_FORMAT_SIREN7) & \ - ~ast_format_id_to_old_bitfield(AST_FORMAT_SIREN14) & \ - ~ast_format_id_to_old_bitfield(AST_FORMAT_G719) & \ - ~ast_format_id_to_old_bitfield(AST_FORMAT_ULAW) & \ - ~ast_format_id_to_old_bitfield(AST_FORMAT_ALAW) & \ - ~ast_format_id_to_old_bitfield(AST_FORMAT_G722)) + ~ast_format_compatibility_format2bitfield(ast_format_slin) & \ + ~ast_format_compatibility_format2bitfield(ast_format_slin16) & \ + ~ast_format_compatibility_format2bitfield(ast_format_siren7) & \ + ~ast_format_compatibility_format2bitfield(ast_format_siren14) & \ + ~ast_format_compatibility_format2bitfield(ast_format_g719) & \ + ~ast_format_compatibility_format2bitfield(ast_format_ulaw) & \ + ~ast_format_compatibility_format2bitfield(ast_format_alaw) & \ + ~ast_format_compatibility_format2bitfield(ast_format_g722)) /* A modem */ #define IAX_CAPABILITY_LOWBANDWIDTH (IAX_CAPABILITY_MEDBANDWIDTH & \ - ~ast_format_id_to_old_bitfield(AST_FORMAT_G726) & \ - ~ast_format_id_to_old_bitfield(AST_FORMAT_G726_AAL2) & \ - ~ast_format_id_to_old_bitfield(AST_FORMAT_ADPCM)) + ~ast_format_compatibility_format2bitfield(ast_format_g726) & \ + ~ast_format_compatibility_format2bitfield(ast_format_g726_aal2) & \ + ~ast_format_compatibility_format2bitfield(ast_format_adpcm)) #define IAX_CAPABILITY_LOWFREE (IAX_CAPABILITY_LOWBANDWIDTH & \ - ~ast_format_id_to_old_bitfield(AST_FORMAT_G723_1)) + ~ast_format_compatibility_format2bitfield(ast_format_g723)) #define DEFAULT_MAXMS 2000 /* Must be faster than 2 seconds by default */ @@ -503,7 +509,7 @@ struct iax2_user { iax2_format capability; int maxauthreq; /*!< Maximum allowed outstanding AUTHREQs */ int curauthreq; /*!< Current number of outstanding AUTHREQs */ - struct ast_codec_pref prefs; + struct iax2_codec_pref prefs; struct ast_acl_list *acl; struct iax2_context *contexts; struct ast_variable *vars; @@ -532,7 +538,7 @@ struct iax2_peer { AST_STRING_FIELD(zonetag); /*!< Time Zone */ AST_STRING_FIELD(parkinglot); /*!< Default parkinglot for device */ ); - struct ast_codec_pref prefs; + struct iax2_codec_pref prefs; struct ast_dnsmgr_entry *dnsmgr; /*!< DNS refresh manager */ struct ast_sockaddr addr; int formats; @@ -708,9 +714,9 @@ struct chan_iax2_pvt { /*! Peer Address */ struct ast_sockaddr addr; /*! Actual used codec preferences */ - struct ast_codec_pref prefs; + struct iax2_codec_pref prefs; /*! Requested codec preferences */ - struct ast_codec_pref rprefs; + struct iax2_codec_pref rprefs; /*! Our call number */ unsigned short callno; /*! Our callno_entry entry */ @@ -1809,17 +1815,18 @@ static iax2_format uncompress_subclass(unsigned char csub) return csub; } -static iax2_format iax2_codec_choose(struct ast_codec_pref *pref, iax2_format formats, int find_best) +static iax2_format iax2_codec_choose(struct iax2_codec_pref *pref, iax2_format formats, int find_best) { struct ast_format_cap *cap; - struct ast_format tmpfmt; + struct ast_format *tmpfmt; iax2_format format = 0; - if ((cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) { - ast_format_clear(&tmpfmt); - ast_format_cap_from_old_bitfield(cap, formats); - ast_codec_choose(pref, cap, find_best, &tmpfmt); - format = ast_format_to_old_bitfield(&tmpfmt); - cap = ast_format_cap_destroy(cap); + + if ((cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { + iax2_format_compatibility_bitfield2cap(formats, cap); + tmpfmt = ast_format_cap_get_format(cap, 0); + format = ast_format_compatibility_format2bitfield(tmpfmt); + ao2_ref(tmpfmt, -1); + ao2_ref(cap, -1); } return format; @@ -1827,55 +1834,84 @@ static iax2_format iax2_codec_choose(struct ast_codec_pref *pref, iax2_format fo static iax2_format iax2_best_codec(iax2_format formats) { - struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - struct ast_format tmpfmt; + struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + struct ast_format *tmpfmt; + iax2_format format; + if (!cap) { return 0; } - ast_format_clear(&tmpfmt); - ast_format_cap_from_old_bitfield(cap, formats); - ast_best_codec(cap, &tmpfmt); - cap = ast_format_cap_destroy(cap); - return ast_format_to_old_bitfield(&tmpfmt); + iax2_format_compatibility_bitfield2cap(formats, cap); + tmpfmt = ast_format_cap_get_format(cap, 0); + format = ast_format_compatibility_format2bitfield(tmpfmt); + ao2_ref(tmpfmt, -1); + ao2_ref(cap, -1); + + return format; } const char *iax2_getformatname(iax2_format format) { - struct ast_format tmpfmt; - if (!(ast_format_from_old_bitfield(&tmpfmt, format))) { + struct ast_format *tmpfmt; + + tmpfmt = ast_format_compatibility_bitfield2format(format); + if (!tmpfmt) { return "Unknown"; } - return ast_getformatname(&tmpfmt); + return ast_format_get_name(tmpfmt); } -static char *iax2_getformatname_multiple(char *codec_buf, size_t len, iax2_format format) +static const char *iax2_getformatname_multiple(iax2_format format, struct ast_str **codec_buf) { - struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!cap) { return "(Nothing)"; } - ast_format_cap_from_old_bitfield(cap, format); - ast_getformatname_multiple(codec_buf, len, cap); - cap = ast_format_cap_destroy(cap); + iax2_format_compatibility_bitfield2cap(format, cap); + ast_format_cap_get_names(cap, codec_buf); + ao2_ref(cap, -1); - return codec_buf; + return ast_str_buffer(*codec_buf); } -static int iax2_parse_allow_disallow(struct ast_codec_pref *pref, iax2_format *formats, const char *list, int allowing) +static int iax2_parse_allow_disallow(struct iax2_codec_pref *pref, iax2_format *formats, const char *list, int allowing) { - int res; - struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + int res, i; + struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!cap) { return 1; } - ast_format_cap_from_old_bitfield(cap, *formats); - res = ast_parse_allow_disallow(pref, cap, list, allowing); - *formats = ast_format_cap_to_old_bitfield(cap); - cap = ast_format_cap_destroy(cap); + /* We want to add the formats to the cap in the preferred order */ + for (i = 0; i < IAX2_CODEC_PREF_SIZE; i++) { + uint64_t pref_as_bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[i]); + + if (!pref_as_bitfield) { + break; + } + + if (iax2_format_compatibility_bitfield2cap(pref_as_bitfield, cap)) { + ao2_ref(cap, -1); + return 1; + } + } + + res = ast_format_cap_update_by_allow_disallow(cap, list, allowing); + *formats = iax2_format_compatibility_cap2bitfield(cap); + + iax2_codec_pref_remove_missing(pref, *formats); + + for (i = 0; i < ast_format_cap_count(cap); i++) { + struct ast_format *fmt = ast_format_cap_get_format(cap, i); + iax2_codec_pref_append(pref, fmt, ast_format_cap_get_format_framing(cap, fmt)); + ao2_ref(fmt, -1); + } + + ao2_ref(cap, -1); return res; } @@ -1883,13 +1919,13 @@ static int iax2_parse_allow_disallow(struct ast_codec_pref *pref, iax2_format *f static int iax2_data_add_codecs(struct ast_data *root, const char *node_name, iax2_format formats) { int res; - struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!cap) { return -1; } - ast_format_cap_from_old_bitfield(cap, formats); + iax2_format_compatibility_bitfield2cap(formats, cap); res = ast_data_add_codecs(root, node_name, cap); - cap = ast_format_cap_destroy(cap); + ao2_ref(cap, -1); return res; } @@ -3737,9 +3773,9 @@ static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct char status[30]; char cbuf[256]; struct iax2_peer *peer; - char codec_buf[512]; + struct ast_str *codec_buf = ast_str_alloca(64); struct ast_str *encmethods = ast_str_alloca(256); - int x = 0, load_realtime = 0; + int load_realtime = 0; switch (cmd) { case CLI_INIT: @@ -3789,23 +3825,13 @@ static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct ast_cli(a->fd, " Defaddr->IP : %s Port %s\n", str_defaddr, str_defport); ast_cli(a->fd, " Username : %s\n", peer->username); ast_cli(a->fd, " Codecs : "); - iax2_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability); - ast_cli(a->fd, "%s\n", codec_buf); + ast_cli(a->fd, "%s\n", iax2_getformatname_multiple(peer->capability, &codec_buf)); - ast_cli(a->fd, " Codec Order : ("); - for(x = 0; x < AST_CODEC_PREF_SIZE; x++) { - struct ast_format tmpfmt; - if(!(ast_codec_pref_index(&peer->prefs, x, &tmpfmt))) - break; - ast_cli(a->fd, "%s", ast_getformatname(&tmpfmt)); - if(x < 31 && ast_codec_pref_index(&peer->prefs, x+1, &tmpfmt)) - ast_cli(a->fd, "|"); + ast_cli(a->fd, " Codec Order : "); + if (iax2_codec_pref_string(&peer->prefs, cbuf, sizeof(cbuf)) != -1) { + ast_cli(a->fd, "%s\n", cbuf); } - if (!x) - ast_cli(a->fd, "none"); - ast_cli(a->fd, ")\n"); - ast_cli(a->fd, " Status : "); peer_status(peer, status, sizeof(status)); ast_cli(a->fd, "%s\n",status); @@ -4084,9 +4110,9 @@ static void __get_from_jb(const void *p) ms = ast_tvdiff_ms(now, pvt->rxcore); if(ms >= (next = jb_next(pvt->jb))) { - struct ast_format voicefmt; - ast_format_from_old_bitfield(&voicefmt, pvt->voiceformat); - ret = jb_get(pvt->jb, &frame, ms, ast_codec_interp_len(&voicefmt)); + struct ast_format *voicefmt; + voicefmt = ast_format_compatibility_bitfield2format(pvt->voiceformat); + ret = jb_get(pvt->jb, &frame, ms, ast_format_get_default_ms(voicefmt)); switch(ret) { case JB_OK: fr = frame.data; @@ -4100,8 +4126,8 @@ static void __get_from_jb(const void *p) /* create an interpolation frame */ af.frametype = AST_FRAME_VOICE; - ast_format_copy(&af.subclass.format, &voicefmt); - af.samples = frame.ms * (ast_format_rate(&voicefmt) / 1000); + af.subclass.format = voicefmt; + af.samples = frame.ms * (ast_format_get_sample_rate(voicefmt) / 1000); af.src = "IAX2 JB interpolation"; af.delivery = ast_tvadd(pvt->rxcore, ast_samp2tv(next, 1000)); af.offset = AST_FRIENDLY_OFFSET; @@ -4182,7 +4208,7 @@ static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtr if(fr->af.frametype == AST_FRAME_VOICE) { type = JB_TYPE_VOICE; - len = ast_codec_get_samples(&fr->af) / (ast_format_rate(&fr->af.subclass.format) / 1000); + len = ast_codec_samples_count(&fr->af) / (ast_format_get_sample_rate(fr->af.subclass.format) / 1000); } else if(fr->af.frametype == AST_FRAME_CNG) { type = JB_TYPE_SILENCE; } @@ -4579,7 +4605,7 @@ static int create_addr(const char *peername, struct ast_channel *c, struct ast_s { struct iax2_peer *peer; int res = -1; - struct ast_codec_pref ourprefs; + struct iax2_codec_pref ourprefs; ast_clear_flag64(cai, IAX_SENDANI | IAX_TRUNK); cai->sockfd = defaultsockfd; @@ -4604,14 +4630,16 @@ static int create_addr(const char *peername, struct ast_channel *c, struct ast_s /* But move the calling channel's native codec to the top of the preference list */ memcpy(&ourprefs, &prefs, sizeof(ourprefs)); if (c) { - struct ast_format tmpfmt; - ast_format_cap_iter_start(ast_channel_nativeformats(c)); - while (!(ast_format_cap_iter_next(ast_channel_nativeformats(c), &tmpfmt))) { - ast_codec_pref_prepend(&ourprefs, &tmpfmt, 1); + int i; + + for (i = 0; i < ast_format_cap_count(ast_channel_nativeformats(c)); i++) { + struct ast_format *format = ast_format_cap_get_format( + ast_channel_nativeformats(c), i); + iax2_codec_pref_prepend(&ourprefs, format, ast_format_cap_get_format_framing(ast_channel_nativeformats(c), format), 1); + ao2_ref(format, -1); } - ast_format_cap_iter_end(ast_channel_nativeformats(c)); } - ast_codec_pref_convert(&ourprefs, cai->prefs, sizeof(cai->prefs), 1); + iax2_codec_pref_convert(&ourprefs, cai->prefs, sizeof(cai->prefs), 1); return 0; } @@ -4635,15 +4663,16 @@ static int create_addr(const char *peername, struct ast_channel *c, struct ast_s memcpy(&ourprefs, &peer->prefs, sizeof(ourprefs)); /* Move the calling channel's native codec to the top of the preference list */ if (c) { - struct ast_format tmpfmt; - ast_format_cap_iter_start(ast_channel_nativeformats(c)); - while (!(ast_format_cap_iter_next(ast_channel_nativeformats(c), &tmpfmt))) { - ast_debug(1, "prepending %s to prefs\n", ast_getformatname(&tmpfmt)); - ast_codec_pref_prepend(&ourprefs, &tmpfmt, 1); + int i; + + for (i = 0; i < ast_format_cap_count(ast_channel_nativeformats(c)); i++) { + struct ast_format *tmpfmt = ast_format_cap_get_format( + ast_channel_nativeformats(c), i); + iax2_codec_pref_prepend(&ourprefs, tmpfmt, ast_format_cap_get_format_framing(ast_channel_nativeformats(c), tmpfmt), 1); + ao2_ref(tmpfmt, -1); } - ast_format_cap_iter_end(ast_channel_nativeformats(c)); } - ast_codec_pref_convert(&ourprefs, cai->prefs, sizeof(cai->prefs), 1); + iax2_codec_pref_convert(&ourprefs, cai->prefs, sizeof(cai->prefs), 1); ast_copy_string(cai->context, peer->context, sizeof(cai->context)); ast_copy_string(cai->peercontext, peer->peercontext, sizeof(cai->peercontext)); ast_copy_string(cai->username, peer->username, sizeof(cai->username)); @@ -5181,7 +5210,7 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout) if (pds.password) ast_string_field_set(iaxs[callno], secret, pds.password); - iax2_tmpfmt = ast_format_cap_to_old_bitfield(ast_channel_nativeformats(c)); + iax2_tmpfmt = iax2_format_compatibility_cap2bitfield(ast_channel_nativeformats(c)); iax_ie_append_int(&ied, IAX_IE_FORMAT, (int) iax2_tmpfmt); iax_ie_append_versioned_uint64(&ied, IAX_IE_FORMAT2, 0, iax2_tmpfmt); @@ -5551,11 +5580,13 @@ static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_cha return AST_BRIDGE_FAILED_NOWARN; } if (!(ast_format_cap_identical(ast_channel_nativeformats(c0), ast_channel_nativeformats(c1)))) { - char buf0[256]; - char buf1[256]; - ast_getformatname_multiple(buf0, sizeof(buf0), ast_channel_nativeformats(c0)); - ast_getformatname_multiple(buf1, sizeof(buf1), ast_channel_nativeformats(c1)); - ast_verb(3, "Operating with different codecs [%s] [%s] , can't native bridge...\n", buf0, buf1); + struct ast_str *c0_buf = ast_str_alloca(64); + struct ast_str *c1_buf = ast_str_alloca(64); + + ast_verb(3, "Operating with different codecs [%s] [%s] , can't native bridge...\n", + ast_format_cap_get_names(ast_channel_nativeformats(c0), &c0_buf), + ast_format_cap_get_names(ast_channel_nativeformats(c1), &c1_buf)); + /* Remove from native mode */ lock_both(callno0, callno1); if (iaxs[callno0]) @@ -5780,7 +5811,8 @@ static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capab struct ast_channel *tmp; struct chan_iax2_pvt *i; struct ast_variable *v = NULL; - struct ast_format tmpfmt; + struct ast_format_cap *native; + struct ast_format *tmpfmt; struct ast_callid *callid; if (!(i = iaxs[callno])) { @@ -5788,6 +5820,11 @@ static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capab return NULL; } + native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!native) { + return NULL; + } + /* Don't hold call lock */ ast_mutex_unlock(&iaxsl[callno]); tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, assignedids, requestor, i->amaflags, "IAX2/%s-%d", i->host, i->callno); @@ -5800,9 +5837,11 @@ static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capab tmp = ast_channel_release(tmp); ast_mutex_lock(&iaxsl[callno]); } + ao2_ref(native, -1); return NULL; } if (!tmp) { + ao2_ref(native, -1); return NULL; } @@ -5813,14 +5852,19 @@ static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capab } ast_channel_tech_set(tmp, &iax2_tech); + /* We can support any format by default, until we get restricted */ - ast_format_cap_from_old_bitfield(ast_channel_nativeformats(tmp), capability); - ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt); + iax2_format_compatibility_bitfield2cap(capability, native); + ast_channel_nativeformats_set(tmp, native); + tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(tmp), 0); - ast_format_copy(ast_channel_readformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt); + ast_channel_set_readformat(tmp, tmpfmt); + ast_channel_set_rawreadformat(tmp, tmpfmt); + ast_channel_set_writeformat(tmp, tmpfmt); + ast_channel_set_rawwriteformat(tmp, tmpfmt); + + ao2_ref(tmpfmt, -1); + ao2_ref(native, -1); ast_channel_tech_pvt_set(tmp, CALLNO_TO_PTR(i->callno)); @@ -5971,7 +6015,7 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str int voice = 0; int genuine = 0; int adjust; - int rate = ast_format_rate(&f->subclass.format) / 1000; + int rate = 0; struct timeval *delivery = NULL; @@ -5983,6 +6027,7 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str */ if (f->frametype == AST_FRAME_VOICE) { voice = 1; + rate = ast_format_get_sample_rate(f->subclass.format) / 1000; delivery = &f->delivery; } else if (f->frametype == AST_FRAME_IAX) { genuine = 1; @@ -6092,8 +6137,9 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str } } p->lastsent = ms; - if (voice) + if (voice) { p->nextpred = p->nextpred + f->samples / rate; + } return ms; } @@ -6344,9 +6390,9 @@ static int decode_frame(ast_aes_decrypt_key *dcx, struct ast_iax2_full_hdr *fh, memcpy(efh->encdata, workspace + padding, *datalen - sizeof(struct ast_iax2_full_enc_hdr)); f->frametype = fh->type; if (f->frametype == AST_FRAME_VIDEO) { - ast_format_from_old_bitfield(&f->subclass.format, (uncompress_subclass(fh->csub & ~0x40) | ((fh->csub >> 6) & 0x1))); + f->subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub & ~0x40) | ((fh->csub >> 6) & 0x1)); } else if (f->frametype == AST_FRAME_VOICE) { - ast_format_from_old_bitfield(&f->subclass.format, uncompress_subclass(fh->csub)); + f->subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub)); } else { f->subclass.integer = uncompress_subclass(fh->csub); } @@ -6487,7 +6533,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in /* High two bytes are the same on timestamp, or sending on a trunk */ && (f->frametype == AST_FRAME_VOICE) /* is a voice frame */ && - (f->subclass.format.id == ast_format_id_from_old_bitfield(pvt->svoiceformat)) + (ast_format_cmp(f->subclass.format, ast_format_compatibility_bitfield2format(pvt->svoiceformat))) /* is the same type */ ) { /* Force immediate rather than delayed transmission */ now = 1; @@ -6501,7 +6547,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in * Otherwise send a mini video frame */ if (((fts & 0xFFFF8000L) == (pvt->lastvsent & 0xFFFF8000L)) && - ((f->subclass.format.id) == ast_format_id_from_old_bitfield(pvt->svideoformat)) + (ast_format_cmp(f->subclass.format, ast_format_compatibility_bitfield2format(pvt->svideoformat))) ) { now = 1; sendmini = 1; @@ -6556,11 +6602,11 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in fh->type = fr->af.frametype & 0xFF; if (fr->af.frametype == AST_FRAME_VIDEO) { - iax2_format tmpfmt = ast_format_to_old_bitfield(&fr->af.subclass.format); - tmpfmt |= ast_format_get_video_mark(&fr->af.subclass.format) ? 0x1LL : 0; + iax2_format tmpfmt = ast_format_compatibility_format2bitfield(fr->af.subclass.format); + tmpfmt |= fr->af.subclass.frame_ending ? 0x1LL : 0; fh->csub = compress_subclass(tmpfmt | ((tmpfmt & 0x1LL) << 6)); } else if (fr->af.frametype == AST_FRAME_VOICE) { - fh->csub = compress_subclass(ast_format_to_old_bitfield(&fr->af.subclass.format)); + fh->csub = compress_subclass(ast_format_compatibility_format2bitfield(fr->af.subclass.format)); } else { fh->csub = compress_subclass(fr->af.subclass.integer); } @@ -6583,9 +6629,9 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in if ((f->frametype == AST_FRAME_IAX) && (f->subclass.integer == IAX_COMMAND_ACK)) fr->retries = -1; else if (f->frametype == AST_FRAME_VOICE) - pvt->svoiceformat = ast_format_to_old_bitfield(&f->subclass.format); + pvt->svoiceformat = ast_format_compatibility_format2bitfield(f->subclass.format); else if (f->frametype == AST_FRAME_VIDEO) - pvt->svideoformat = ast_format_to_old_bitfield(&f->subclass.format); + pvt->svideoformat = ast_format_compatibility_format2bitfield(f->subclass.format); if (ast_test_flag64(pvt, IAX_ENCRYPTED)) { if (ast_test_flag64(pvt, IAX_KEYPOPULATED)) { if (fr->transfer) @@ -6616,7 +6662,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in vh = (struct ast_iax2_video_hdr *)(fr->af.data.ptr - sizeof(struct ast_iax2_video_hdr)); vh->zeros = 0; vh->callno = htons(0x8000 | fr->callno); - vh->ts = htons((fr->ts & 0x7FFF) | (ast_format_get_video_mark(&fr->af.subclass.format) ? 0x8000 : 0)); + vh->ts = htons((fr->ts & 0x7FFF) | (fr->af.subclass.frame_ending ? 0x8000 : 0)); fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_video_hdr); fr->data = vh; fr->retries = -1; @@ -7767,8 +7813,8 @@ static int check_access(int callno, struct ast_sockaddr *addr, struct iax_ies *i /* Use provided preferences until told otherwise for actual preferences */ if (ies->codec_prefs) { - ast_codec_pref_convert(&iaxs[callno]->rprefs, ies->codec_prefs, 32, 0); - ast_codec_pref_convert(&iaxs[callno]->prefs, ies->codec_prefs, 32, 0); + iax2_codec_pref_convert(&iaxs[callno]->rprefs, ies->codec_prefs, 32, 0); + iax2_codec_pref_convert(&iaxs[callno]->prefs, ies->codec_prefs, 32, 0); } if (!gotcapability) { @@ -9827,7 +9873,7 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s ast_log(LOG_WARNING, "Received trunked frame before first full voice frame\n"); iax2_vnak(fr->callno); } else { - ast_format_from_old_bitfield(&f.subclass.format, iaxs[fr->callno]->voiceformat); + f.subclass.format = ast_format_compatibility_bitfield2format(iaxs[fr->callno]->voiceformat); f.datalen = len; if (f.datalen >= 0) { if (f.datalen) @@ -9847,7 +9893,7 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s f.mallocd = 0; f.offset = 0; if (f.datalen && (f.frametype == AST_FRAME_VOICE)) - f.samples = ast_codec_get_samples(&f); + f.samples = ast_codec_samples_count(&f); else f.samples = 0; fr->outoforder = 0; @@ -10004,7 +10050,7 @@ static int socket_process_helper(struct iax2_thread *thread) struct iax_frame *duped_fr; char host_pref_buf[128]; char caller_pref_buf[128]; - struct ast_codec_pref pref; + struct iax2_codec_pref pref; char *using_prefs = "mine"; /* allocate an iax_frame with 4096 bytes of data buffer */ @@ -10069,12 +10115,12 @@ static int socket_process_helper(struct iax2_thread *thread) /* Retrieve the type and subclass */ f.frametype = fh->type; if (f.frametype == AST_FRAME_VIDEO) { - ast_format_from_old_bitfield(&f.subclass.format, (uncompress_subclass(fh->csub & ~0x40))); + f.subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub & ~0x40)); if ((fh->csub >> 6) & 0x1) { - ast_format_set_video_mark(&f.subclass.format); + f.subclass.frame_ending = 1; } } else if (f.frametype == AST_FRAME_VOICE) { - ast_format_from_old_bitfield(&f.subclass.format, uncompress_subclass(fh->csub)); + f.subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub)); } else { f.subclass.integer = uncompress_subclass(fh->csub); } @@ -10498,22 +10544,21 @@ static int socket_process_helper(struct iax2_thread *thread) } if (f.frametype == AST_FRAME_VOICE) { - if (ast_format_to_old_bitfield(&f.subclass.format) != iaxs[fr->callno]->voiceformat) { - iaxs[fr->callno]->voiceformat = ast_format_to_old_bitfield(&f.subclass.format); - ast_debug(1, "Ooh, voice format changed to '%s'\n", ast_getformatname(&f.subclass.format)); + if (ast_format_compatibility_format2bitfield(f.subclass.format) != iaxs[fr->callno]->voiceformat) { + iaxs[fr->callno]->voiceformat = ast_format_compatibility_format2bitfield(f.subclass.format); + ast_debug(1, "Ooh, voice format changed to '%s'\n", ast_format_get_name(f.subclass.format)); if (iaxs[fr->callno]->owner) { iax2_lock_owner(fr->callno); if (iaxs[fr->callno]) { if (iaxs[fr->callno]->owner) { - struct ast_format_cap *orignative = ast_format_cap_dup(ast_channel_nativeformats(iaxs[fr->callno]->owner)); - struct ast_format_cap *native = ast_channel_nativeformats(iaxs[fr->callno]->owner); - if (orignative) { - ast_format_cap_set(native, &f.subclass.format); - if (ast_channel_readformat(iaxs[fr->callno]->owner)->id) { + struct ast_format_cap *native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (native) { + ast_format_cap_append(native, f.subclass.format, 0); + ast_channel_nativeformats_set(iaxs[fr->callno]->owner, native); + if (ast_channel_readformat(iaxs[fr->callno]->owner)) { ast_set_read_format(iaxs[fr->callno]->owner, ast_channel_readformat(iaxs[fr->callno]->owner)); } - ast_format_cap_copy(native, orignative); - orignative = ast_format_cap_destroy(orignative); + ao2_ref(native, -1); } ast_channel_unlock(iaxs[fr->callno]->owner); } @@ -10532,9 +10577,9 @@ static int socket_process_helper(struct iax2_thread *thread) } } if (f.frametype == AST_FRAME_VIDEO) { - if (f.subclass.format.id != ast_format_id_from_old_bitfield(iaxs[fr->callno]->videoformat)) { - ast_debug(1, "Ooh, video format changed to %s\n", ast_getformatname(&f.subclass.format)); - iaxs[fr->callno]->videoformat = ast_format_to_old_bitfield(&f.subclass.format); + if (ast_format_compatibility_format2bitfield(f.subclass.format) != iaxs[fr->callno]->videoformat) { + ast_debug(1, "Ooh, video format changed to %s\n", ast_format_get_name(f.subclass.format)); + iaxs[fr->callno]->videoformat = ast_format_compatibility_format2bitfield(f.subclass.format); } } if (f.frametype == AST_FRAME_IAX) { @@ -10697,12 +10742,12 @@ static int socket_process_helper(struct iax2_thread *thread) strcpy(caller_pref_buf, "disabled"); strcpy(host_pref_buf, "disabled"); } else { - struct ast_format tmpfmt; + struct ast_format *tmpfmt; using_prefs = "mine"; /* If the information elements are in here... use them */ if (ies.codec_prefs) - ast_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0); - if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) { + iax2_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0); + if (iax2_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) { /* If we are codec_first_choice we let the caller have the 1st shot at picking the codec.*/ if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) { pref = iaxs[fr->callno]->rprefs; @@ -10714,8 +10759,8 @@ static int socket_process_helper(struct iax2_thread *thread) pref = iaxs[fr->callno]->prefs; format = iax2_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability, 0); - ast_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1); - ast_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1); + iax2_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1); + iax2_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1); } if (!format) { if(!ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) @@ -10729,18 +10774,21 @@ static int socket_process_helper(struct iax2_thread *thread) break; } if (authdebug) { - char tmp[256], tmp2[256], tmp3[256]; + struct ast_str *peer_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *peer_form_buf = ast_str_alloca(64); + if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) { ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n", ast_sockaddr_stringify(&addr), - iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat), - iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability)); + iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf), + iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf)); } else { ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n", ast_sockaddr_stringify(&addr), - iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat), - iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability), - iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability)); + iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf), + iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf), + iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf)); } } } else { @@ -10756,9 +10804,9 @@ static int socket_process_helper(struct iax2_thread *thread) strcpy(caller_pref_buf,"disabled"); strcpy(host_pref_buf,"disabled"); } else { - struct ast_format tmpfmt; + struct ast_format *tmpfmt; using_prefs = "mine"; - if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) { + if (iax2_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) { /* Do the opposite of what we tried above. */ if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) { pref = iaxs[fr->callno]->prefs; @@ -10773,11 +10821,14 @@ static int socket_process_helper(struct iax2_thread *thread) } if (!format) { - char tmp[256], tmp2[256], tmp3[256]; + struct ast_str *peer_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *peer_form_buf = ast_str_alloca(64); + memset(&ied0, 0, sizeof(ied0)); iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec"); iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL); - ast_log(LOG_ERROR, "No best format in '%s'???\n", iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability)); + ast_log(LOG_ERROR, "No best format in '%s'???\n", iax2_getformatname_multiple(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, &cap_buf)); send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1); if (!iaxs[fr->callno]) { break; @@ -10785,9 +10836,9 @@ static int socket_process_helper(struct iax2_thread *thread) if (authdebug) { ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n", ast_sockaddr_stringify(&addr), - iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat), - iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability), - iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability)); + iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf), + iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf), + iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf)); } ast_set_flag64(iaxs[fr->callno], IAX_ALREADYGONE); break; @@ -10935,7 +10986,7 @@ static int socket_process_helper(struct iax2_thread *thread) iaxs[fr->callno]->peerformat = ies.format; } else { if (iaxs[fr->callno]->owner) - iaxs[fr->callno]->peerformat = ast_format_cap_to_old_bitfield(ast_channel_nativeformats(iaxs[fr->callno]->owner)); + iaxs[fr->callno]->peerformat = iax2_format_compatibility_cap2bitfield(ast_channel_nativeformats(iaxs[fr->callno]->owner)); else iaxs[fr->callno]->peerformat = iaxs[fr->callno]->capability; } @@ -10950,28 +11001,36 @@ static int socket_process_helper(struct iax2_thread *thread) break; } if (authdebug) { - char tmp1[256], tmp2[256]; + struct ast_str *peer_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(64); + ast_log(LOG_NOTICE, "Rejected call to %s, format %s incompatible with our capability %s.\n", ast_sockaddr_stringify(&addr), - iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat), - iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability)); + iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_buf), + iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf)); } } else { + struct ast_format_cap *native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED); iax2_lock_owner(fr->callno); - if (iaxs[fr->callno] && iaxs[fr->callno]->owner) { - char tmp[256]; + if (iaxs[fr->callno] && iaxs[fr->callno]->owner && native) { + struct ast_str *cap_buf = ast_str_alloca(64); + /* Switch us to use a compatible format */ - ast_format_cap_from_old_bitfield(ast_channel_nativeformats(iaxs[fr->callno]->owner), iaxs[fr->callno]->peerformat); - ast_verb(3, "Format for call is %s\n", ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(iaxs[fr->callno]->owner))); + iax2_format_compatibility_bitfield2cap(iaxs[fr->callno]->peerformat, native); + ast_channel_nativeformats_set(iaxs[fr->callno]->owner, native); + ast_verb(3, "Format for call is %s\n", ast_format_cap_get_names(ast_channel_nativeformats(iaxs[fr->callno]->owner), &cap_buf)); /* Setup read/write formats properly. */ - if (ast_channel_writeformat(iaxs[fr->callno]->owner)->id) + if (ast_channel_writeformat(iaxs[fr->callno]->owner)) ast_set_write_format(iaxs[fr->callno]->owner, ast_channel_writeformat(iaxs[fr->callno]->owner)); - if (ast_channel_readformat(iaxs[fr->callno]->owner)->id) + if (ast_channel_readformat(iaxs[fr->callno]->owner)) ast_set_read_format(iaxs[fr->callno]->owner, ast_channel_readformat(iaxs[fr->callno]->owner)); ast_channel_unlock(iaxs[fr->callno]->owner); } + + ao2_cleanup(native); } if (iaxs[fr->callno]) { AST_LIST_LOCK(&dpcache); @@ -11140,11 +11199,11 @@ static int socket_process_helper(struct iax2_thread *thread) strcpy(caller_pref_buf, "disabled"); strcpy(host_pref_buf, "disabled"); } else { - struct ast_format tmpfmt; + struct ast_format *tmpfmt; using_prefs = "mine"; if (ies.codec_prefs) - ast_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0); - if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) { + iax2_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0); + if (iax2_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) { if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) { pref = iaxs[fr->callno]->rprefs; using_prefs = "caller"; @@ -11154,15 +11213,18 @@ static int socket_process_helper(struct iax2_thread *thread) } else /* if no codec_prefs IE do it the old way */ pref = iaxs[fr->callno]->prefs; format = iax2_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability, 0); - ast_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1); - ast_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1); + iax2_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1); + iax2_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1); } if (!format) { - char tmp1[256], tmp2[256], tmp3[256]; + struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *peer_buf = ast_str_alloca(64); + struct ast_str *peer_form_buf = ast_str_alloca(64); + if(!ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) { ast_debug(1, "We don't do requested format %s, falling back to peer capability '%s'\n", iax2_getformatname(iaxs[fr->callno]->peerformat), - iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peercapability)); + iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf)); format = iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability; } if (!format) { @@ -11170,14 +11232,14 @@ static int socket_process_helper(struct iax2_thread *thread) if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) { ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n", ast_sockaddr_stringify(&addr), - iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat), - iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability)); + iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf), + iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf)); } else { ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n", ast_sockaddr_stringify(&addr), - iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat), - iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability), - iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability)); + iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf), + iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf), + iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf)); } } memset(&ied0, 0, sizeof(ied0)); @@ -11201,9 +11263,9 @@ static int socket_process_helper(struct iax2_thread *thread) strcpy(caller_pref_buf,"disabled"); strcpy(host_pref_buf,"disabled"); } else { - struct ast_format tmpfmt; + struct ast_format *tmpfmt; using_prefs = "mine"; - if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) { + if (iax2_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) { /* Do the opposite of what we tried above. */ if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) { pref = iaxs[fr->callno]->prefs; @@ -11217,21 +11279,24 @@ static int socket_process_helper(struct iax2_thread *thread) } } if (!format) { - char tmp1[256], tmp2[256], tmp3[256]; + struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *peer_buf = ast_str_alloca(64); + struct ast_str *peer_form_buf = ast_str_alloca(64); + ast_log(LOG_ERROR, "No best format in %s???\n", - iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability)); + iax2_getformatname_multiple(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, &cap_buf)); if (authdebug) { if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) { ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n", ast_sockaddr_stringify(&addr), - iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat), - iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability)); + iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf), + iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf)); } else { ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n", ast_sockaddr_stringify(&addr), - iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat), - iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability), - iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability)); + iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf), + iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf), + iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf)); } } memset(&ied0, 0, sizeof(ied0)); @@ -11338,11 +11403,11 @@ immediatedial: break; } } else { - char tmp[256]; + struct ast_str *cap_buf = ast_str_alloca(64); ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED); ast_verb(3, "Accepting DIAL from %s, formats = %s\n", ast_sockaddr_stringify(&addr), - iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat)); + iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &cap_buf)); ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED); send_command(iaxs[fr->callno], AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, 0, NULL, 0, -1); if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat, NULL, NULL, 1))) @@ -11662,9 +11727,9 @@ immediatedial: f.frametype = AST_FRAME_VIDEO; if (iaxs[fr->callno]->videoformat > 0) { if (ntohs(vh->ts) & 0x8000LL) { - ast_format_set_video_mark(&f.subclass.format); + f.subclass.frame_ending = 1; } - ast_format_from_old_bitfield(&f.subclass.format, iaxs[fr->callno]->videoformat); + f.subclass.format = ast_format_compatibility_bitfield2format(iaxs[fr->callno]->videoformat); } else { ast_log(LOG_WARNING, "Received mini frame before first full video frame\n"); iax2_vnak(fr->callno); @@ -11687,7 +11752,7 @@ immediatedial: /* A mini frame */ f.frametype = AST_FRAME_VOICE; if (iaxs[fr->callno]->voiceformat > 0) - ast_format_from_old_bitfield(&f.subclass.format, iaxs[fr->callno]->voiceformat); + f.subclass.format = ast_format_compatibility_bitfield2format(iaxs[fr->callno]->voiceformat); else { ast_debug(1, "Received mini frame before first full voice frame\n"); iax2_vnak(fr->callno); @@ -11795,9 +11860,9 @@ immediatedial: f.offset = 0; f.len = 0; if (f.datalen && (f.frametype == AST_FRAME_VOICE)) { - f.samples = ast_codec_get_samples(&f); + f.samples = ast_codec_samples_count(&f); /* We need to byteswap incoming slinear samples from network byte order */ - if (f.subclass.format.id == AST_FORMAT_SLINEAR) + if (ast_format_cmp(f.subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) ast_frame_byteswap_be(&f); } else f.samples = 0; @@ -12376,32 +12441,48 @@ static struct ast_channel *iax2_request(const char *type, struct ast_format_cap if (c) { struct ast_format_cap *joint; + struct ast_format *format; if (callid) { ast_channel_lock(c); ast_channel_callid_set(c, callid); ast_channel_unlock(c); } - /* Choose a format we can live with */ - if ((joint = ast_format_cap_joint(ast_channel_nativeformats(c), cap))) { - ast_format_cap_copy(ast_channel_nativeformats(c), joint); - joint = ast_format_cap_destroy(joint); - } else { - struct ast_format best_fmt_cap; - struct ast_format best_fmt_native; + joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!joint) { + ast_hangup(c); + return NULL; + } + + ast_format_cap_get_compatible(ast_channel_nativeformats(c), cap, joint); + + /* If there is no joint format find one through translation */ + if (!ast_format_cap_count(joint)) { + struct ast_format *best_fmt_cap = NULL; + struct ast_format *best_fmt_native = NULL; res = ast_translator_best_choice(cap, ast_channel_nativeformats(c), &best_fmt_cap, &best_fmt_native); if (res < 0) { - char tmp[256]; - char tmp2[256]; + struct ast_str *native_cap_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(64); + ast_log(LOG_WARNING, "Unable to create translator path for %s to %s on %s\n", - ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(c)), ast_getformatname_multiple(tmp2, sizeof(tmp2), cap), ast_channel_name(c)); + ast_format_cap_get_names(ast_channel_nativeformats(c), &native_cap_buf), + ast_format_cap_get_names(cap, &cap_buf), + ast_channel_name(c)); ast_hangup(c); return NULL; } - ast_format_cap_set(ast_channel_nativeformats(c), &best_fmt_native); + ast_format_cap_append(joint, best_fmt_native, 0); + ao2_ref(best_fmt_cap, -1); + ao2_ref(best_fmt_native, -1); } - ast_best_codec(ast_channel_nativeformats(c), ast_channel_readformat(c)); - ast_format_copy(ast_channel_writeformat(c), ast_channel_readformat(c)); + ast_channel_nativeformats_set(c, joint); + format = ast_format_cap_get_format(ast_channel_nativeformats(c), 0); + ast_channel_set_readformat(c, format); + ast_channel_set_writeformat(c, format); + + ao2_ref(joint, -1); + ao2_ref(format, -1); } if (callid) { @@ -13355,7 +13436,7 @@ static int set_config(const char *config_file, int reload, int forced) ast_sockaddr_parse(&bindaddr, "0.0.0.0:0", 0); /* Reset global codec prefs */ - memset(&prefs, 0 , sizeof(struct ast_codec_pref)); + memset(&prefs, 0 , sizeof(struct iax2_codec_pref)); /* Reset Global Flags */ memset(&globalflags, 0, sizeof(globalflags)); @@ -14234,10 +14315,13 @@ static int function_iaxpeer(struct ast_channel *chan, const char *cmd, char *dat } else if (!strcasecmp(colname, "callerid_num")) { ast_copy_string(buf, peer->cid_num, len); } else if (!strcasecmp(colname, "codecs")) { - iax2_getformatname_multiple(buf, len -1, peer->capability); + struct ast_str *codec_buf; + + iax2_getformatname_multiple(peer->capability, &codec_buf); + ast_copy_string(buf, ast_str_buffer(codec_buf), len); } else if (!strncasecmp(colname, "codec[", 6)) { char *codecnum, *ptr; - struct ast_format tmpfmt; + struct ast_format *tmpfmt; /* skip over "codec" to the '[' */ codecnum = colname + 5; @@ -14246,8 +14330,8 @@ static int function_iaxpeer(struct ast_channel *chan, const char *cmd, char *dat if ((ptr = strchr(codecnum, ']'))) { *ptr = '\0'; } - if((ast_codec_pref_index(&peer->prefs, atoi(codecnum), &tmpfmt))) { - ast_copy_string(buf, ast_getformatname(&tmpfmt), len); + if((iax2_codec_pref_index(&peer->prefs, atoi(codecnum), &tmpfmt))) { + ast_copy_string(buf, ast_format_get_name(tmpfmt), len); } else { buf[0] = '\0'; } @@ -14604,7 +14688,8 @@ static int __unload_module(void) ast_context_destroy(con, "IAX2"); ast_unload_realtime("iaxpeers"); - iax2_tech.capabilities = ast_format_cap_destroy(iax2_tech.capabilities); + ao2_ref(iax2_tech.capabilities, -1); + iax2_tech.capabilities = NULL; return 0; } @@ -14914,10 +14999,10 @@ static int load_module(void) int x = 0; struct iax2_registry *reg = NULL; - if (!(iax2_tech.capabilities = ast_format_cap_alloc(0))) { + if (!(iax2_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_FAILURE; } - ast_format_cap_add_all(iax2_tech.capabilities); + ast_format_cap_append_by_type(iax2_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN); if (load_objects()) { return AST_MODULE_LOAD_FAILURE; diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index 2d0afe29d..6021b6c1d 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -86,6 +86,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/features_config.h" #include "asterisk/parking.h" #include "asterisk/stasis_channels.h" +#include "asterisk/format_cache.h" /* * Define to work around buggy dlink MGCP phone firmware which @@ -1199,9 +1200,20 @@ static struct ast_frame *mgcp_rtp_read(struct mgcp_subchannel *sub) if (sub->owner) { /* We already hold the channel lock */ if (f->frametype == AST_FRAME_VOICE) { - if (!ast_format_cap_iscompatible(ast_channel_nativeformats(sub->owner), &f->subclass.format)) { - ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format)); - ast_format_cap_set(ast_channel_nativeformats(sub->owner), &f->subclass.format); + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(sub->owner), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_format_cap *caps; + + ast_debug(1, "Oooh, format changed to %s\n", ast_format_get_name(f->subclass.format)); + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (caps) { + ast_format_cap_append(caps, f->subclass.format, 0); + ast_channel_nativeformats_set(sub->owner, caps); + ao2_ref(caps, -1); + } else { + return &ast_null_frame; + } + ast_set_read_format(sub->owner, ast_channel_readformat(sub->owner)); ast_set_write_format(sub->owner, ast_channel_writeformat(sub->owner)); } @@ -1239,7 +1251,6 @@ static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame) { struct mgcp_subchannel *sub = ast_channel_tech_pvt(ast); int res = 0; - char buf[256]; if (frame->frametype != AST_FRAME_VOICE) { if (frame->frametype == AST_FRAME_IMAGE) @@ -1249,12 +1260,14 @@ static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame) return 0; } } else { - if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) { + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_str *cap_buf = ast_str_alloca(64); + ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n", - ast_getformatname(&frame->subclass.format), - ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)), - ast_getformatname(ast_channel_readformat(ast)), - ast_getformatname(ast_channel_writeformat(ast))); + ast_format_get_name(frame->subclass.format), + ast_format_cap_get_names(ast_channel_nativeformats(ast), &cap_buf), + ast_format_get_name(ast_channel_readformat(ast)), + ast_format_get_name(ast_channel_writeformat(ast))); /* return -1; */ } } @@ -1490,90 +1503,103 @@ static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, siz static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor) { + struct ast_format_cap *caps = NULL; struct ast_channel *tmp; struct ast_variable *v = NULL; struct mgcp_endpoint *i = sub->parent; - struct ast_format tmpfmt; + struct ast_format *tmpfmt; + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_log(LOG_ERROR, "Format capabilities could not be created\n"); + return NULL; + } tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, assignedids, requestor, i->amaflags, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id); - if (tmp) { - ast_channel_stage_snapshot(tmp); - ast_channel_tech_set(tmp, &mgcp_tech); - ast_format_cap_copy(ast_channel_nativeformats(tmp), i->cap); - if (ast_format_cap_is_empty(ast_channel_nativeformats(tmp))) { - ast_format_cap_copy(ast_channel_nativeformats(tmp), global_capability); - } - if (sub->rtp) { - ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0)); - } - if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) { - i->dsp = ast_dsp_new(); - ast_dsp_set_features(i->dsp, DSP_FEATURE_DIGIT_DETECT); - /* this is to prevent clipping of dtmf tones during dsp processing */ - ast_dsp_set_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH); - } else { - i->dsp = NULL; - } - if (state == AST_STATE_RING) - ast_channel_rings_set(tmp, 1); - - ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt); - ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_readformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt); - ast_channel_tech_pvt_set(tmp, sub); - if (!ast_strlen_zero(i->language)) - ast_channel_language_set(tmp, i->language); - if (!ast_strlen_zero(i->accountcode)) - ast_channel_accountcode_set(tmp, i->accountcode); - if (i->amaflags) - ast_channel_amaflags_set(tmp, i->amaflags); - mgcp_set_owner(sub, tmp); - ast_module_ref(ast_module_info->self); - ast_channel_callgroup_set(tmp, i->callgroup); - ast_channel_pickupgroup_set(tmp, i->pickupgroup); - ast_channel_call_forward_set(tmp, i->call_forward); - ast_channel_context_set(tmp, i->context); - ast_channel_exten_set(tmp, i->exten); - - /* Don't use ast_set_callerid() here because it will - * generate a needless NewCallerID event */ - if (!ast_strlen_zero(i->cid_num)) { - ast_channel_caller(tmp)->ani.number.valid = 1; - ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_num); - } - - if (!i->adsi) { - ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE); - } - ast_channel_priority_set(tmp, 1); + if (!tmp) { + ast_log(LOG_WARNING, "Channel could not be created\n"); + ao2_ref(caps, -1); + return NULL; + } - /* Set channel variables for this call from configuration */ - for (v = i->chanvars ; v ; v = v->next) { - char valuebuf[1024]; - pbx_builtin_setvar_helper(tmp, v->name, ast_get_encoded_str(v->value, valuebuf, sizeof(valuebuf))); - } + ast_channel_stage_snapshot(tmp); + ast_channel_tech_set(tmp, &mgcp_tech); + if (ast_format_cap_count(i->cap)) { + ast_format_cap_append_from_cap(caps, i->cap, AST_MEDIA_TYPE_UNKNOWN); + } else { + ast_format_cap_append_from_cap(caps, global_capability, AST_MEDIA_TYPE_UNKNOWN); + } + ast_channel_nativeformats_set(tmp, caps); + ao2_ref(caps, -1); + if (sub->rtp) { + ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0)); + } + if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) { + i->dsp = ast_dsp_new(); + ast_dsp_set_features(i->dsp, DSP_FEATURE_DIGIT_DETECT); + /* this is to prevent clipping of dtmf tones during dsp processing */ + ast_dsp_set_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH); + } else { + i->dsp = NULL; + } + if (state == AST_STATE_RING) { + ast_channel_rings_set(tmp, 1); + } + + tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(tmp), 0); + ast_channel_set_writeformat(tmp, tmpfmt); + ast_channel_set_rawwriteformat(tmp, tmpfmt); + ast_channel_set_readformat(tmp, tmpfmt); + ast_channel_set_rawreadformat(tmp, tmpfmt); + ao2_ref(tmpfmt, -1); + ast_channel_tech_pvt_set(tmp, sub); + if (!ast_strlen_zero(i->language)) + ast_channel_language_set(tmp, i->language); + if (!ast_strlen_zero(i->accountcode)) + ast_channel_accountcode_set(tmp, i->accountcode); + if (i->amaflags) + ast_channel_amaflags_set(tmp, i->amaflags); + mgcp_set_owner(sub, tmp); + ast_module_ref(ast_module_info->self); + ast_channel_callgroup_set(tmp, i->callgroup); + ast_channel_pickupgroup_set(tmp, i->pickupgroup); + ast_channel_call_forward_set(tmp, i->call_forward); + ast_channel_context_set(tmp, i->context); + ast_channel_exten_set(tmp, i->exten); + /* Don't use ast_set_callerid() here because it will + * generate a needless NewCallerID event */ + if (!ast_strlen_zero(i->cid_num)) { + ast_channel_caller(tmp)->ani.number.valid = 1; + ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_num); + } + + if (!i->adsi) { + ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE); + } + ast_channel_priority_set(tmp, 1); + + /* Set channel variables for this call from configuration */ + for (v = i->chanvars ; v ; v = v->next) { + char valuebuf[1024]; + pbx_builtin_setvar_helper(tmp, v->name, ast_get_encoded_str(v->value, valuebuf, sizeof(valuebuf))); + } - if (sub->rtp) { - ast_jb_configure(tmp, &global_jbconf); - } + if (sub->rtp) { + ast_jb_configure(tmp, &global_jbconf); + } - ast_channel_stage_snapshot_done(tmp); - ast_channel_unlock(tmp); + ast_channel_stage_snapshot_done(tmp); + ast_channel_unlock(tmp); - if (state != AST_STATE_DOWN) { - if (ast_pbx_start(tmp)) { - ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp)); - ast_hangup(tmp); - tmp = NULL; - } + if (state != AST_STATE_DOWN) { + if (ast_pbx_start(tmp)) { + ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp)); + ast_hangup(tmp); + tmp = NULL; } - ast_verb(3, "MGCP mgcp_new(%s) created in state: %s\n", - ast_channel_name(tmp), ast_state2str(state)); - } else { - ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); } + ast_verb(3, "MGCP mgcp_new(%s) created in state: %s\n", + ast_channel_name(tmp), ast_state2str(state)); + return tmp; } @@ -1973,7 +1999,9 @@ static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req) int codec, codec_count=0; int iterator; struct mgcp_endpoint *p = sub->parent; - char tmp1[256], tmp2[256], tmp3[256]; + struct ast_str *global_buf = ast_str_alloca(64); + struct ast_str *peer_buf = ast_str_alloca(64); + struct ast_str *pvt_buf = ast_str_alloca(64); /* Get codec and RTP info from SDP */ m = get_sdp(req, "m"); @@ -2030,20 +2058,20 @@ static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req) } /* Now gather all of the codecs that were asked for: */ - if (!(peercap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) { + if (!(peercap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return -1; } ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(sub->rtp), peercap, &peerNonCodecCapability); - ast_format_cap_joint_copy(global_capability, peercap, p->cap); + ast_format_cap_get_compatible(global_capability, peercap, p->cap); ast_debug(1, "Capabilities: us - %s, them - %s, combined - %s\n", - ast_getformatname_multiple(tmp1, sizeof(tmp1), global_capability), - ast_getformatname_multiple(tmp2, sizeof(tmp2), peercap), - ast_getformatname_multiple(tmp3, sizeof(tmp3), p->cap)); - peercap = ast_format_cap_destroy(peercap); + ast_format_cap_get_names(global_capability, &global_buf), + ast_format_cap_get_names(peercap, &peer_buf), + ast_format_cap_get_names(p->cap, &pvt_buf)); + ao2_ref(peercap, -1); ast_debug(1, "Non-codec capabilities: us - %d, them - %d, combined - %d\n", nonCodecCapability, peerNonCodecCapability, p->nonCodecCapability); - if (ast_format_cap_is_empty(p->cap)) { + if (!ast_format_cap_count(p->cap)) { ast_log(LOG_WARNING, "No compatible codecs!\n"); return -1; } @@ -2201,7 +2229,6 @@ static int add_sdp(struct mgcp_request *resp, struct mgcp_subchannel *sub, struc char m[256] = ""; char a[1024] = ""; int x; - struct ast_format tmpfmt; struct sockaddr_in dest = { 0, }; struct ast_sockaddr dest_tmp; struct mgcp_endpoint *p = sub->parent; @@ -2236,24 +2263,25 @@ static int add_sdp(struct mgcp_request *resp, struct mgcp_subchannel *sub, struc ast_copy_string(t, "t=0 0\r\n", sizeof(t)); snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port)); - ast_format_cap_iter_start(p->cap); - while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) { - if (AST_FORMAT_GET_TYPE(tmpfmt.id) != AST_FORMAT_TYPE_AUDIO) { - /* Audio is now discontiguous */ + for (x = 0; x < ast_format_cap_count(p->cap); x++) { + struct ast_format *format = ast_format_cap_get_format(p->cap, x); + + if (ast_format_get_type(format) != AST_MEDIA_TYPE_AUDIO) { + ao2_ref(format, -1); continue; } - if (ast_format_cap_iscompatible(p->cap, &tmpfmt)) { - ast_debug(1, "Answering with capability %s\n", ast_getformatname(&tmpfmt)); - codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, &tmpfmt, 0); - if (codec > -1) { - snprintf(costr, sizeof(costr), " %d", codec); - strncat(m, costr, sizeof(m) - strlen(m) - 1); - snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0)); - strncat(a, costr, sizeof(a) - strlen(a) - 1); - } + + ast_debug(1, "Answering with capability %s\n", ast_format_get_name(format)); + codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, format, 0); + if (codec > -1) { + snprintf(costr, sizeof(costr), " %d", codec); + strncat(m, costr, sizeof(m) - strlen(m) - 1); + snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype2(1, format, 0, 0)); + strncat(a, costr, sizeof(a) - strlen(a) - 1); } + + ao2_ref(format, -1); } - ast_format_cap_iter_end(p->cap); for (x = 1LL; x <= AST_RTP_MAX; x <<= 1) { if (p->nonCodecCapability & x) { @@ -2292,7 +2320,7 @@ static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp_ char local[256]; char tmp[80]; struct mgcp_endpoint *p = sub->parent; - struct ast_format tmpfmt; + int i; struct ast_sockaddr sub_tmpdest_tmp; unsigned int oseq; @@ -2304,18 +2332,20 @@ static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp_ return 0; } ast_copy_string(local, "e:on, s:off, p:20", sizeof(local)); - ast_format_cap_iter_start(p->cap); - while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) { - if (AST_FORMAT_GET_TYPE(tmpfmt.id) != AST_FORMAT_TYPE_AUDIO) { - /* Audio is now discontiguous */ + + for (i = 0; i < ast_format_cap_count(p->cap); i++) { + struct ast_format *format = ast_format_cap_get_format(p->cap, i); + + if (ast_format_get_type(format) != AST_MEDIA_TYPE_AUDIO) { + ao2_ref(format, -1); continue; } - if (ast_format_cap_iscompatible(p->cap, &tmpfmt)) { - snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0)); - strncat(local, tmp, sizeof(local) - strlen(local) - 1); - } + + snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, format, 0, 0)); + strncat(local, tmp, sizeof(local) - strlen(local) - 1); + + ao2_ref(format, -1); } - ast_format_cap_iter_end(p->cap); if (sub->gate) { if (sub->gate->state == GATE_ALLOCATED || sub->gate->state == GATE_OPEN) { @@ -2351,7 +2381,7 @@ static int transmit_connect_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp struct mgcp_request resp; char local[256]; char tmp[80]; - struct ast_format tmpfmt; + int i; struct mgcp_endpoint *p = sub->parent; unsigned int oseq; @@ -2360,18 +2390,19 @@ static int transmit_connect_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp ast_copy_string(local, "e:on, s:off, p:20", sizeof(local)); - ast_format_cap_iter_start(p->cap); - while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) { - if (AST_FORMAT_GET_TYPE(tmpfmt.id) != AST_FORMAT_TYPE_AUDIO) { - /* Audio is now discontiguous */ + for (i = 0; i < ast_format_cap_count(p->cap); i++) { + struct ast_format *format = ast_format_cap_get_format(p->cap, i); + + if (ast_format_get_type(format) != AST_MEDIA_TYPE_AUDIO) { + ao2_ref(format, -1); continue; } - if (ast_format_cap_iscompatible(p->cap, &tmpfmt)) { - snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0)); - strncat(local, tmp, sizeof(local) - strlen(local) - 1); - } + + snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, format, 0, 0)); + strncat(local, tmp, sizeof(local) - strlen(local) - 1); + + ao2_ref(format, -1); } - ast_format_cap_iter_end(p->cap); if (sub->gate) { if(sub->gate->state == GATE_ALLOCATED) { @@ -2447,22 +2478,23 @@ static int mgcp_alloc_pktcgate(struct mgcp_subchannel *sub) static int transmit_connect(struct mgcp_subchannel *sub) { struct mgcp_request resp; + int x; char local[256]; char tmp[80]; - struct ast_format tmpfmt; + struct ast_format *tmpfmt; struct mgcp_endpoint *p = sub->parent; unsigned int oseq; ast_copy_string(local, "p:20, s:off, e:on", sizeof(local)); - ast_format_cap_iter_start(p->cap); - while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) { - if (ast_format_cap_iscompatible(p->cap, &tmpfmt)) { - snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0)); - strncat(local, tmp, sizeof(local) - strlen(local) - 1); - } + for (x = 0; x < ast_format_cap_count(p->cap); x++) { + tmpfmt = ast_format_cap_get_format(p->cap, x); + + snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, tmpfmt, 0, 0)); + strncat(local, tmp, sizeof(local) - strlen(local) - 1); + + ao2_ref(tmpfmt, -1); } - ast_format_cap_iter_end(p->cap); ast_debug(3, "Creating connection for %s@%s-%d in cxmode: %s callid: %s\n", p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid); @@ -2557,7 +2589,7 @@ static int transmit_modify_request(struct mgcp_subchannel *sub) { struct mgcp_request resp; struct mgcp_endpoint *p = sub->parent; - struct ast_format tmpfmt; + int i; int fc = 1; char local[256]; char tmp[80]; @@ -2572,18 +2604,22 @@ static int transmit_modify_request(struct mgcp_subchannel *sub) p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid); ast_copy_string(local, "", sizeof(local)); - ast_format_cap_iter_start(p->cap); - while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) { + for (i = 0; i < ast_format_cap_count(p->cap); i++) { + struct ast_format *format = ast_format_cap_get_format(p->cap, i); + if (p->ncs && !fc) { - ast_format_cap_set(p->cap, &tmpfmt); /* sb5120e bug */ + ast_format_cap_remove_by_type(p->cap, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append(p->cap, format, 0); /* sb5120e bug */ + ao2_ref(format, -1); break; } else { fc = 0; - snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0)); + snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, format, 0, 0)); } strncat(local, tmp, sizeof(local) - strlen(local) - 1); + + ao2_ref(format, -1); } - ast_format_cap_iter_end(p->cap); if (!sub->sdpsent) { if (sub->gate) { @@ -3948,8 +3984,10 @@ static struct ast_channel *mgcp_request(const char *type, struct ast_format_cap struct ast_channel *tmpc = NULL; char tmp[256]; - if (!(ast_format_cap_has_joint(cap, global_capability))) { - ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap)); + if (!(ast_format_cap_iscompatible(cap, global_capability))) { + struct ast_str *cap_buf = ast_str_alloca(64); + ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", + ast_format_cap_get_names(cap, &cap_buf)); /*return NULL;*/ } ast_copy_string(tmp, dest, sizeof(tmp)); @@ -4185,7 +4223,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v) ast_mutex_init(&e->lock); ast_mutex_init(&e->rqnt_queue_lock); ast_mutex_init(&e->cmd_queue_lock); - e->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + e->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); ast_copy_string(e->name, v->value, sizeof(e->name)); e->needaudit = 1; } @@ -4210,7 +4248,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v) snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", (unsigned long)ast_random()); e->msgstate = -1; e->amaflags = amaflags; - ast_format_cap_copy(e->cap, global_capability); + ast_format_cap_append_from_cap(e->cap, global_capability, AST_MEDIA_TYPE_UNKNOWN); e->parent = gw; e->ncs = ncs; e->dtmfmode = dtmfmode; @@ -4292,7 +4330,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v) ast_mutex_init(&e->lock); ast_mutex_init(&e->rqnt_queue_lock); ast_mutex_init(&e->cmd_queue_lock); - e->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + e->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); ast_copy_string(e->name, v->value, sizeof(e->name)); e->needaudit = 1; } @@ -4314,7 +4352,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v) e->parent = gw; } e->amaflags = amaflags; - ast_format_cap_copy(e->cap, global_capability); + ast_format_cap_append_from_cap(e->cap, global_capability, AST_MEDIA_TYPE_UNKNOWN); e->dtmfmode = dtmfmode; e->ncs = ncs; e->pktcgatealloc = pktcgatealloc; @@ -4470,7 +4508,8 @@ static void mgcp_get_codec(struct ast_channel *chan, struct ast_format_cap *resu { struct mgcp_subchannel *sub = ast_channel_tech_pvt(chan); struct mgcp_endpoint *p = sub->parent; - ast_format_cap_copy(result, p->cap); + + ast_format_cap_append_from_cap(result, p->cap, AST_MEDIA_TYPE_UNKNOWN); } static struct ast_rtp_glue mgcp_rtp_glue = { @@ -4556,7 +4595,7 @@ static void destroy_endpoint(struct mgcp_endpoint *e) ast_mutex_destroy(&e->lock); ast_mutex_destroy(&e->rqnt_queue_lock); ast_mutex_destroy(&e->cmd_queue_lock); - e->cap = ast_format_cap_destroy(e->cap); + ao2_ref(e->cap, -1); ast_free(e); } @@ -4654,7 +4693,6 @@ static int reload_config(int reload) char *cat; struct ast_hostent ahp; struct hostent *hp; - struct ast_format format; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; if (gethostname(ourhost, sizeof(ourhost)-1)) { @@ -4694,19 +4732,9 @@ static int reload_config(int reload) memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr)); } } else if (!strcasecmp(v->name, "allow")) { - ast_getformatbyname(v->value, &format); - if (!format.id) { - ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value); - } else { - ast_format_cap_add(global_capability, &format); - } + ast_format_cap_update_by_allow_disallow(global_capability, v->value, 1); } else if (!strcasecmp(v->name, "disallow")) { - ast_getformatbyname(v->value, &format); - if (!format.id) { - ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value); - } else { - ast_format_cap_remove(global_capability, &format); - } + ast_format_cap_update_by_allow_disallow(global_capability, v->value, 0); } else if (!strcasecmp(v->name, "tos")) { if (ast_str2tos(v->value, &qos.tos)) { ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno); @@ -4831,36 +4859,44 @@ static int reload_config(int reload) */ static int load_module(void) { - struct ast_format tmpfmt; - - if (!(global_capability = ast_format_cap_alloc(0))) { + if (!(global_capability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_FAILURE; } - if (!(mgcp_tech.capabilities = ast_format_cap_alloc(0))) { + if (!(mgcp_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { + ao2_ref(global_capability, -1); return AST_MODULE_LOAD_FAILURE; } - ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0)); - ast_format_cap_add(mgcp_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0)); - ast_format_cap_add(mgcp_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0)); + ast_format_cap_append(global_capability, ast_format_ulaw, 0); + ast_format_cap_append(mgcp_tech.capabilities, ast_format_ulaw, 0); + ast_format_cap_append(mgcp_tech.capabilities, ast_format_alaw, 0); if (!(sched = ast_sched_context_create())) { ast_log(LOG_WARNING, "Unable to create schedule context\n"); + ao2_ref(global_capability, -1); + ao2_ref(mgcp_tech.capabilities, -1); return AST_MODULE_LOAD_FAILURE; } if (!(io = io_context_create())) { ast_log(LOG_WARNING, "Unable to create I/O context\n"); ast_sched_context_destroy(sched); + ao2_ref(global_capability, -1); + ao2_ref(mgcp_tech.capabilities, -1); return AST_MODULE_LOAD_FAILURE; } - if (reload_config(0)) + if (reload_config(0)) { + ao2_ref(global_capability, -1); + ao2_ref(mgcp_tech.capabilities, -1); return AST_MODULE_LOAD_DECLINE; + } /* Make sure we can register our mgcp channel type */ if (ast_channel_register(&mgcp_tech)) { ast_log(LOG_ERROR, "Unable to register channel class 'MGCP'\n"); io_context_destroy(io); ast_sched_context_destroy(sched); + ao2_ref(global_capability, -1); + ao2_ref(mgcp_tech.capabilities, -1); return AST_MODULE_LOAD_FAILURE; } @@ -4973,8 +5009,10 @@ static int unload_module(void) ast_cli_unregister_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry)); ast_sched_context_destroy(sched); - global_capability = ast_format_cap_destroy(global_capability); - mgcp_tech.capabilities = ast_format_cap_destroy(mgcp_tech.capabilities); + ao2_ref(global_capability, -1); + global_capability = NULL; + ao2_ref(mgcp_tech.capabilities, -1); + mgcp_tech.capabilities = NULL; return 0; } diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c index 47d5947c3..0774e3c15 100644 --- a/channels/chan_misdn.c +++ b/channels/chan_misdn.c @@ -120,6 +120,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/features_config.h" #include "asterisk/bridge.h" #include "asterisk/pickup.h" +#include "asterisk/format_cache.h" #include "chan_misdn_config.h" #include "isdn_lib.h" @@ -691,9 +692,6 @@ static const char misdn_type[] = "mISDN"; static int tracing = 0; -/*! \brief Only alaw and mulaw is allowed for now */ -static struct ast_format prefformat; /* AST_FORMAT_SLINEAR ; AST_FORMAT_ULAW | */ - static int *misdn_debug; static int *misdn_debug_only; static int max_ports; @@ -7436,7 +7434,7 @@ static struct ast_frame *misdn_read(struct ast_channel *ast) } tmp->frame.frametype = AST_FRAME_VOICE; - ast_format_set(&tmp->frame.subclass.format, AST_FORMAT_ALAW, 0); + tmp->frame.subclass.format = ast_format_alaw; tmp->frame.datalen = len; tmp->frame.samples = len; tmp->frame.mallocd = 0; @@ -7501,13 +7499,14 @@ static int misdn_write(struct ast_channel *ast, struct ast_frame *frame) } - if (!frame->subclass.format.id) { + if (!frame->subclass.format) { chan_misdn_log(4, ch->bc->port, "misdn_write: * prods us\n"); return 0; } - if (ast_format_cmp(&frame->subclass.format, &prefformat) == AST_FORMAT_CMP_NOT_EQUAL) { - chan_misdn_log(-1, ch->bc->port, "Got Unsupported Frame with Format:%s\n", ast_getformatname(&frame->subclass.format)); + if (ast_format_cmp(frame->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_NOT_EQUAL) { + chan_misdn_log(-1, ch->bc->port, "Got Unsupported Frame with Format:%s\n", + ast_format_get_name(frame->subclass.format)); return 0; } @@ -8174,12 +8173,18 @@ static void update_name(struct ast_channel *tmp, int port, int c) static struct ast_channel *misdn_new(struct chan_list *chlist, int state, char *exten, char *callerid, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, int port, int c) { + struct ast_format_cap *native; struct ast_channel *tmp; char *cid_name = NULL; char *cid_num = NULL; int chan_offset = 0; int tmp_port = misdn_cfg_get_next_port(0); - struct ast_format tmpfmt; + struct ast_format *tmpfmt; + + native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!native) { + return NULL; + } for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) { if (tmp_port == port) { @@ -8199,12 +8204,15 @@ static struct ast_channel *misdn_new(struct chan_list *chlist, int state, char if (tmp) { chan_misdn_log(2, port, " --> * NEW CHANNEL dialed:%s caller:%s\n", exten, callerid); - ast_best_codec(cap, &tmpfmt); - ast_format_cap_add(ast_channel_nativeformats(tmp), &prefformat); - ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_readformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt); + tmpfmt = ast_format_cap_get_format(cap, 0); + ast_format_cap_append(native, ast_format_alaw, 0); + ast_channel_nativeformats_set(tmp, native); + ast_channel_set_writeformat(tmp, tmpfmt); + ast_channel_set_rawwriteformat(tmp, tmpfmt); + ast_channel_set_readformat(tmp, tmpfmt); + ast_channel_set_rawreadformat(tmp, tmpfmt); + + ao2_ref(tmpfmt, -1); /* Link the channel and private together */ chan_list_ref(chlist, "Give a reference to ast_channel"); @@ -8242,6 +8250,8 @@ static struct ast_channel *misdn_new(struct chan_list *chlist, int state, char chan_misdn_log(-1, 0, "Unable to allocate channel structure\n"); } + ao2_ref(native, -1); + return tmp; } @@ -10207,14 +10217,13 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) ch->addr = bc->addr; { - struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - struct ast_format tmpfmt; + struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!(cap)) { return RESPONSE_ERR; } - ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0)); + ast_format_cap_append(cap, ast_format_alaw, 0); chan = misdn_new(ch, AST_STATE_RESERVED, bc->dialed.number, bc->caller.number, cap, NULL, NULL, bc->port, bc->channel); - cap = ast_format_cap_destroy(cap); + ao2_ref(cap, -1); } if (!chan) { chan_list_unref(ch, "Failed to create a new channel"); @@ -10849,7 +10858,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) /* In Data Modes we queue frames */ memset(&frame, 0, sizeof(frame)); frame.frametype = AST_FRAME_VOICE; /* we have no data frames yet */ - ast_format_set(&frame.subclass.format, AST_FORMAT_ALAW, 0); + frame.subclass.format = ast_format_alaw; frame.datalen = bc->bframe_len; frame.samples = bc->bframe_len; frame.mallocd = 0; @@ -11287,7 +11296,8 @@ static int unload_module(void) #if defined(AST_MISDN_ENHANCEMENTS) misdn_cc_destroy(); #endif /* defined(AST_MISDN_ENHANCEMENTS) */ - misdn_tech.capabilities = ast_format_cap_destroy(misdn_tech.capabilities); + ao2_cleanup(misdn_tech.capabilities); + misdn_tech.capabilities = NULL; return 0; } @@ -11316,11 +11326,10 @@ static int load_module(void) }; - if (!(misdn_tech.capabilities = ast_format_cap_alloc(0))) { + if (!(misdn_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_DECLINE; } - ast_format_set(&prefformat, AST_FORMAT_ALAW, 0); - ast_format_cap_add(misdn_tech.capabilities, &prefformat); + ast_format_cap_append(misdn_tech.capabilities, ast_format_alaw, 0); max_ports = misdn_lib_maxports_get(); diff --git a/channels/chan_motif.c b/channels/chan_motif.c index d853839ab..4b1d7d26b 100644 --- a/channels/chan_motif.c +++ b/channels/chan_motif.c @@ -77,6 +77,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/abstract_jb.h" #include "asterisk/xmpp.h" #include "asterisk/stasis_channels.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <configInfo name="chan_motif" language="en_US"> @@ -286,7 +287,6 @@ struct jingle_endpoint { iksrule *rule; /*!< Active matching rule */ unsigned int maxicecandidates; /*!< Maximum number of ICE candidates we will offer */ unsigned int maxpayloads; /*!< Maximum number of payloads we will offer */ - struct ast_codec_pref prefs; /*!< Codec preferences */ struct ast_format_cap *cap; /*!< Formats to use */ ast_group_t callgroup; /*!< Call group */ ast_group_t pickupgroup; /*!< Pickup group */ @@ -309,7 +309,6 @@ struct jingle_session { char remote_original[XMPP_MAX_JIDLEN];/*!< Identifier of the original remote party (remote may have changed due to redirect) */ char remote[XMPP_MAX_JIDLEN]; /*!< Identifier of the remote party */ iksrule *rule; /*!< Session matching rule */ - struct ast_codec_pref prefs; /*!< Codec preferences */ struct ast_channel *owner; /*!< Master Channel */ struct ast_rtp_instance *rtp; /*!< RTP audio session */ struct ast_rtp_instance *vrtp; /*!< RTP video session */ @@ -454,8 +453,7 @@ static void jingle_endpoint_destructor(void *obj) ast_xmpp_client_unref(endpoint->connection); } - ast_format_cap_destroy(endpoint->cap); - + ao2_cleanup(endpoint->cap); ao2_ref(endpoint->state, -1); ast_string_field_free_memory(endpoint); @@ -519,7 +517,7 @@ static void *jingle_endpoint_alloc(const char *cat) ast_string_field_set(endpoint, name, cat); - endpoint->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + endpoint->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); endpoint->transport = JINGLE_TRANSPORT_ICE_UDP; return endpoint; @@ -583,9 +581,9 @@ static void jingle_session_destructor(void *obj) ast_rtp_instance_destroy(session->vrtp); } - ast_format_cap_destroy(session->cap); - ast_format_cap_destroy(session->jointcap); - ast_format_cap_destroy(session->peercap); + ao2_cleanup(session->cap); + ao2_cleanup(session->jointcap); + ao2_cleanup(session->peercap); if (session->callid) { ast_callid_unref(session->callid); @@ -681,7 +679,7 @@ static void jingle_enable_video(struct jingle_session *session) } /* If there are no configured video codecs do not turn video support on, it just won't work */ - if (!ast_format_cap_has_type(session->cap, AST_FORMAT_TYPE_VIDEO)) { + if (!ast_format_cap_has_type(session->cap, AST_MEDIA_TYPE_VIDEO)) { return; } @@ -695,8 +693,8 @@ static void jingle_enable_video(struct jingle_session *session) ast_rtp_instance_set_channel_id(session->vrtp, ast_channel_uniqueid(session->owner)); ast_channel_set_fd(session->owner, 2, ast_rtp_instance_fd(session->vrtp, 0)); ast_channel_set_fd(session->owner, 3, ast_rtp_instance_fd(session->vrtp, 1)); - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->vrtp), session->vrtp, &session->prefs); - + ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(session->vrtp), + ast_format_cap_get_framing(session->cap)); if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2 && (ice = ast_rtp_instance_get_ice(session->vrtp))) { ice->stop(session->vrtp); } @@ -741,15 +739,15 @@ static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, con session->connection = endpoint->connection; session->transport = endpoint->transport; - if (!(session->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK)) || - !(session->jointcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK)) || - !(session->peercap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK)) || + if (!(session->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) || + !(session->jointcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) || + !(session->peercap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) || !session->callid) { ao2_ref(session, -1); return NULL; } - ast_format_cap_copy(session->cap, endpoint->cap); + ast_format_cap_append_from_cap(session->cap, endpoint->cap, AST_MEDIA_TYPE_UNKNOWN); /* While we rely on res_xmpp for communication we still need a temporary ast_sockaddr to tell the RTP engine * that we want IPv4 */ @@ -763,8 +761,6 @@ static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, con ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_RTCP, 1); ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_DTMF, 1); - memcpy(&session->prefs, &endpoint->prefs, sizeof(session->prefs)); - session->maxicecandidates = endpoint->maxicecandidates; session->maxpayloads = endpoint->maxpayloads; @@ -776,13 +772,20 @@ static struct ast_channel *jingle_new(struct jingle_endpoint *endpoint, struct j { struct ast_channel *chan; const char *str = S_OR(title, session->remote); - struct ast_format tmpfmt; + struct ast_format_cap *caps; + struct ast_format *tmpfmt; + + if (!ast_format_cap_count(session->cap)) { + return NULL; + } - if (ast_format_cap_is_empty(session->cap)) { + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { return NULL; } if (!(chan = ast_channel_alloc(1, state, S_OR(title, ""), S_OR(cid_name, ""), "", "", "", assignedids, requestor, 0, "Motif/%s-%04lx", str, (unsigned long)(ast_random() & 0xffff)))) { + ao2_ref(caps, -1); return NULL; } @@ -794,15 +797,17 @@ static struct ast_channel *jingle_new(struct jingle_endpoint *endpoint, struct j ast_channel_callid_set(chan, session->callid); - ast_format_cap_copy(ast_channel_nativeformats(chan), session->cap); - ast_codec_choose(&session->prefs, session->cap, 1, &tmpfmt); + ast_format_cap_append_from_cap(caps, session->cap, AST_MEDIA_TYPE_UNKNOWN); + ast_channel_nativeformats_set(chan, caps); + ao2_ref(caps, -1); if (session->rtp) { struct ast_rtp_engine_ice *ice; ast_channel_set_fd(chan, 0, ast_rtp_instance_fd(session->rtp, 0)); ast_channel_set_fd(chan, 1, ast_rtp_instance_fd(session->rtp, 1)); - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->rtp), session->rtp, &session->prefs); + ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(session->rtp), + ast_format_cap_get_framing(session->cap)); if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) || (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) && @@ -818,11 +823,12 @@ static struct ast_channel *jingle_new(struct jingle_endpoint *endpoint, struct j ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE); - ast_best_codec(ast_channel_nativeformats(chan), &tmpfmt); - ast_format_copy(ast_channel_writeformat(chan), &tmpfmt); - ast_format_copy(ast_channel_rawwriteformat(chan), &tmpfmt); - ast_format_copy(ast_channel_readformat(chan), &tmpfmt); - ast_format_copy(ast_channel_rawreadformat(chan), &tmpfmt); + tmpfmt = ast_format_cap_get_format(session->cap, 0); + ast_channel_set_writeformat(chan, tmpfmt); + ast_channel_set_rawwriteformat(chan, tmpfmt); + ast_channel_set_readformat(chan, tmpfmt); + ast_channel_set_rawreadformat(chan, tmpfmt); + ao2_ref(tmpfmt, -1); ao2_lock(endpoint); @@ -1300,30 +1306,24 @@ static void jingle_send_transport_info(struct jingle_session *session, const cha } /*! \brief Internal helper function which adds payloads to a description */ -static int jingle_add_payloads_to_description(struct jingle_session *session, struct ast_rtp_instance *rtp, iks *description, iks **payloads, enum ast_format_type type) +static int jingle_add_payloads_to_description(struct jingle_session *session, struct ast_rtp_instance *rtp, iks *description, iks **payloads, enum ast_media_type type) { - struct ast_format format; int x = 0, i = 0, res = 0; - for (x = 0; (x < AST_CODEC_PREF_SIZE) && (i < (session->maxpayloads - 2)); x++) { + for (x = 0; (x < ast_format_cap_count(session->jointcap)) && (i < (session->maxpayloads - 2)); x++) { + struct ast_format *format = ast_format_cap_get_format(session->jointcap, x); int rtp_code; iks *payload; char tmp[32]; - if (!ast_codec_pref_index(&session->prefs, x, &format)) { - break; - } - - if (AST_FORMAT_GET_TYPE(format.id) != type) { - continue; - } - - if (!ast_format_cap_iscompatible(session->jointcap, &format)) { + if (ast_format_get_type(format) != type) { + ao2_ref(format, -1); continue; } - if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, &format, 0)) == -1) || + if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, format, 0)) == -1) || (!(payload = iks_new("payload-type")))) { + ao2_ref(format, -1); return -1; } @@ -1333,17 +1333,18 @@ static int jingle_add_payloads_to_description(struct jingle_session *session, st snprintf(tmp, sizeof(tmp), "%d", rtp_code); iks_insert_attrib(payload, "id", tmp); - iks_insert_attrib(payload, "name", ast_rtp_lookup_mime_subtype2(1, &format, 0, 0)); + iks_insert_attrib(payload, "name", ast_rtp_lookup_mime_subtype2(1, format, 0, 0)); iks_insert_attrib(payload, "channels", "1"); - if ((format.id == AST_FORMAT_G722) && ((session->transport == JINGLE_TRANSPORT_GOOGLE_V1) || (session->transport == JINGLE_TRANSPORT_GOOGLE_V2))) { + if ((ast_format_cmp(format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) && + ((session->transport == JINGLE_TRANSPORT_GOOGLE_V1) || (session->transport == JINGLE_TRANSPORT_GOOGLE_V2))) { iks_insert_attrib(payload, "clockrate", "16000"); } else { - snprintf(tmp, sizeof(tmp), "%u", ast_rtp_lookup_sample_rate2(1, &format, 0)); + snprintf(tmp, sizeof(tmp), "%u", ast_rtp_lookup_sample_rate2(1, format, 0)); iks_insert_attrib(payload, "clockrate", tmp); } - if ((type == AST_FORMAT_TYPE_VIDEO) && (session->transport == JINGLE_TRANSPORT_GOOGLE_V2)) { + if ((type == AST_MEDIA_TYPE_VIDEO) && (session->transport == JINGLE_TRANSPORT_GOOGLE_V2)) { iks *parameter; /* Google requires these parameters to be set, but alas we can not give accurate values so use some safe defaults */ @@ -1366,9 +1367,11 @@ static int jingle_add_payloads_to_description(struct jingle_session *session, st iks_insert_node(description, payload); payloads[i++] = payload; + + ao2_ref(format, -1); } /* If this is for audio and there is room for RFC2833 add it in */ - if ((type == AST_FORMAT_TYPE_AUDIO) && (i < session->maxpayloads)) { + if ((type == AST_MEDIA_TYPE_AUDIO) && (i < session->maxpayloads)) { iks *payload; if ((payload = iks_new("payload-type"))) { @@ -1390,7 +1393,7 @@ static int jingle_add_payloads_to_description(struct jingle_session *session, st /*! \brief Helper function which adds content to a description */ static int jingle_add_content(struct jingle_session *session, iks *jingle, iks *content, iks *description, iks *transport, - const char *name, enum ast_format_type type, struct ast_rtp_instance *rtp, iks **payloads) + const char *name, enum ast_media_type type, struct ast_rtp_instance *rtp, iks **payloads) { int res = 0; @@ -1400,9 +1403,9 @@ static int jingle_add_content(struct jingle_session *session, iks *jingle, iks * iks_insert_node(jingle, content); iks_insert_attrib(description, "xmlns", JINGLE_RTP_NS); - if (type == AST_FORMAT_TYPE_AUDIO) { + if (type == AST_MEDIA_TYPE_AUDIO) { iks_insert_attrib(description, "media", "audio"); - } else if (type == AST_FORMAT_TYPE_VIDEO) { + } else if (type == AST_MEDIA_TYPE_VIDEO) { iks_insert_attrib(description, "media", "video"); } else { return -1; @@ -1469,7 +1472,7 @@ static void jingle_send_session_action(struct jingle_session *session, const cha if (session->rtp && (audio = iks_new("content")) && (audio_description = iks_new("description")) && (audio_transport = iks_new("transport"))) { res = jingle_add_content(session, jingle, audio, audio_description, audio_transport, session->audio_name, - AST_FORMAT_TYPE_AUDIO, session->rtp, audio_payloads); + AST_MEDIA_TYPE_AUDIO, session->rtp, audio_payloads); } else { ast_log(LOG_ERROR, "Failed to allocate audio content stanzas for session '%s', hanging up\n", session->sid); res = -1; @@ -1479,7 +1482,7 @@ static void jingle_send_session_action(struct jingle_session *session, const cha if ((video = iks_new("content")) && (video_description = iks_new("description")) && (video_transport = iks_new("transport"))) { res = jingle_add_content(session, jingle, video, video_description, video_transport, session->video_name, - AST_FORMAT_TYPE_VIDEO, session->vrtp, video_payloads); + AST_MEDIA_TYPE_VIDEO, session->vrtp, video_payloads); } else { ast_log(LOG_ERROR, "Failed to allocate video content stanzas for session '%s', hanging up\n", session->sid); res = -1; @@ -1668,17 +1671,24 @@ static struct ast_frame *jingle_read(struct ast_channel *ast) } if (frame && frame->frametype == AST_FRAME_VOICE && - !ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format)) { - if (!ast_format_cap_iscompatible(session->jointcap, &frame->subclass.format)) { + ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_cap_iscompatible_format(session->jointcap, frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n", - ast_getformatname(&frame->subclass.format), ast_channel_name(ast)); + ast_format_get_name(frame->subclass.format), ast_channel_name(ast)); ast_frfree(frame); frame = &ast_null_frame; } else { + struct ast_format_cap *caps; + ast_debug(1, "Oooh, format changed to %s\n", - ast_getformatname(&frame->subclass.format)); - ast_format_cap_remove_bytype(ast_channel_nativeformats(ast), AST_FORMAT_TYPE_AUDIO); - ast_format_cap_add(ast_channel_nativeformats(ast), &frame->subclass.format); + ast_format_get_name(frame->subclass.format)); + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (caps) { + ast_format_cap_append(caps, frame->subclass.format, 0); + ast_channel_nativeformats_set(ast, caps); + ao2_ref(caps, -1); + } ast_set_read_format(ast, ast_channel_readformat(ast)); ast_set_write_format(ast, ast_channel_writeformat(ast)); } @@ -1692,17 +1702,18 @@ static int jingle_write(struct ast_channel *ast, struct ast_frame *frame) { struct jingle_session *session = ast_channel_tech_pvt(ast); int res = 0; - char buf[256]; switch (frame->frametype) { case AST_FRAME_VOICE: - if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) { + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_str *codec_buf = ast_str_alloca(64); + ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n", - ast_getformatname(&frame->subclass.format), - ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)), - ast_getformatname(ast_channel_readformat(ast)), - ast_getformatname(ast_channel_writeformat(ast))); + ast_format_get_name(frame->subclass.format), + ast_format_cap_get_names(ast_channel_nativeformats(ast), &codec_buf), + ast_format_get_name(ast_channel_readformat(ast)), + ast_format_get_name(ast_channel_writeformat(ast))); return 0; } if (session && session->rtp) { @@ -1845,7 +1856,7 @@ static int jingle_call(struct ast_channel *ast, const char *dest, int timeout) ast_setstate(ast, AST_STATE_RING); /* Since we have no idea of the remote capabilities use ours for now */ - ast_format_cap_copy(session->jointcap, session->cap); + ast_format_cap_append_from_cap(session->jointcap, session->cap, AST_MEDIA_TYPE_UNKNOWN); /* We set up a hook so we can know when our session-initiate message was accepted or rejected */ session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session, @@ -1908,7 +1919,7 @@ static struct ast_channel *jingle_request(const char *type, struct ast_format_ca ); /* We require at a minimum one audio format to be requested */ - if (!ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO)) { + if (!ast_format_cap_has_type(cap, AST_MEDIA_TYPE_AUDIO)) { ast_log(LOG_ERROR, "Motif channel driver requires an audio format when dialing a destination\n"); *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL; return NULL; @@ -2001,7 +2012,7 @@ static struct ast_channel *jingle_request(const char *type, struct ast_format_ca } /* If video was requested try to enable it on the session */ - if (ast_format_cap_has_type(cap, AST_FORMAT_TYPE_VIDEO)) { + if (ast_format_cap_has_type(cap, AST_MEDIA_TYPE_VIDEO)) { jingle_enable_video(session); } @@ -2043,8 +2054,8 @@ static int jingle_interpret_description(struct jingle_session *session, iks *des ast_string_field_set(session, audio_name, name); } *rtp = session->rtp; - ast_format_cap_remove_bytype(session->peercap, AST_FORMAT_TYPE_AUDIO); - ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_AUDIO); + ast_format_cap_remove_by_type(session->peercap, AST_MEDIA_TYPE_AUDIO); + ast_format_cap_remove_by_type(session->jointcap, AST_MEDIA_TYPE_AUDIO); } else if (!strcasecmp(media, "video")) { if (!ast_strlen_zero(name)) { ast_string_field_set(session, video_name, name); @@ -2060,8 +2071,8 @@ static int jingle_interpret_description(struct jingle_session *session, iks *des return -1; } - ast_format_cap_remove_bytype(session->peercap, AST_FORMAT_TYPE_VIDEO); - ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_VIDEO); + ast_format_cap_remove_by_type(session->peercap, AST_MEDIA_TYPE_VIDEO); + ast_format_cap_remove_by_type(session->jointcap, AST_MEDIA_TYPE_VIDEO); } else { /* Unknown media type */ jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL); @@ -2082,8 +2093,6 @@ static int jingle_interpret_description(struct jingle_session *session, iks *des int rtp_id, rtp_clockrate; if (!ast_strlen_zero(id) && !ast_strlen_zero(name) && (sscanf(id, "%30d", &rtp_id) == 1)) { - ast_rtp_codecs_payloads_set_m_type(&codecs, NULL, rtp_id); - if (!ast_strlen_zero(clockrate) && (sscanf(clockrate, "%30d", &rtp_clockrate) == 1)) { ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, rtp_id, media, name, 0, rtp_clockrate); } else { @@ -2093,9 +2102,9 @@ static int jingle_interpret_description(struct jingle_session *session, iks *des } ast_rtp_codecs_payload_formats(&codecs, session->peercap, &othercapability); - ast_format_cap_joint_append(session->cap, session->peercap, session->jointcap); + ast_format_cap_get_compatible(session->cap, session->peercap, session->jointcap); - if (ast_format_cap_is_empty(session->jointcap)) { + if (!ast_format_cap_count(session->jointcap)) { /* We have no compatible codecs, so terminate the session appropriately */ jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL); ast_rtp_codecs_payloads_destroy(&codecs); @@ -2355,12 +2364,20 @@ static int jingle_interpret_content(struct jingle_session *session, ikspak *pak) } if ((chan = jingle_session_lock_full(session))) { - struct ast_format fmt; + struct ast_format_cap *caps; + struct ast_format *fmt; + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (caps) { + ast_format_cap_append_from_cap(caps, session->jointcap, AST_MEDIA_TYPE_UNKNOWN); + ast_channel_nativeformats_set(chan, caps); + ao2_ref(caps, -1); + } - ast_format_cap_copy(ast_channel_nativeformats(chan), session->jointcap); - ast_codec_choose(&session->prefs, session->jointcap, 1, &fmt); - ast_set_read_format(chan, &fmt); - ast_set_write_format(chan, &fmt); + fmt = ast_format_cap_get_format(session->jointcap, 0); + ast_set_read_format(chan, fmt); + ast_set_write_format(chan, fmt); + ao2_ref(fmt, -1); ast_channel_unlock(chan); ast_channel_unref(chan); @@ -2710,7 +2727,7 @@ static int custom_transport_handler(const struct aco_option *opt, struct ast_var */ static int load_module(void) { - if (!(jingle_tech.capabilities = ast_format_cap_alloc(0))) { + if (!(jingle_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_DECLINE; } @@ -2726,8 +2743,8 @@ static int load_module(void) aco_option_register(&cfg_info, "musicclass", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, musicclass)); aco_option_register(&cfg_info, "parkinglot", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, parkinglot)); aco_option_register(&cfg_info, "accountcode", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, accountcode)); - aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, prefs, cap)); - aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, prefs, cap)); + aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, cap)); + aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, cap)); aco_option_register_custom(&cfg_info, "connection", ACO_EXACT, endpoint_options, NULL, custom_connection_handler, 0); aco_option_register_custom(&cfg_info, "transport", ACO_EXACT, endpoint_options, NULL, custom_transport_handler, 0); aco_option_register(&cfg_info, "maxicecandidates", ACO_EXACT, endpoint_options, DEFAULT_MAX_ICE_CANDIDATES, OPT_UINT_T, PARSE_DEFAULT, @@ -2735,9 +2752,10 @@ static int load_module(void) aco_option_register(&cfg_info, "maxpayloads", ACO_EXACT, endpoint_options, DEFAULT_MAX_PAYLOADS, OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct jingle_endpoint, maxpayloads), DEFAULT_MAX_PAYLOADS); - ast_format_cap_add_all_by_type(jingle_tech.capabilities, AST_FORMAT_TYPE_AUDIO); + ast_format_cap_append_by_type(jingle_tech.capabilities, AST_MEDIA_TYPE_AUDIO); if (aco_process_config(&cfg_info, 0)) { + ao2_ref(jingle_tech.capabilities, -1); ast_log(LOG_ERROR, "Unable to read config file motif.conf. Module loaded but not running.\n"); aco_info_destroy(&cfg_info); return AST_MODULE_LOAD_DECLINE; @@ -2763,6 +2781,7 @@ static int load_module(void) return 0; end: + ao2_cleanup(jingle_tech.capabilities); ast_rtp_glue_unregister(&jingle_rtp_glue); if (sched) { @@ -2784,7 +2803,7 @@ static int reload(void) static int unload_module(void) { ast_channel_unregister(&jingle_tech); - ast_format_cap_destroy(jingle_tech.capabilities); + ao2_cleanup(jingle_tech.capabilities); jingle_tech.capabilities = NULL; ast_rtp_glue_unregister(&jingle_rtp_glue); ast_sched_context_destroy(sched); diff --git a/channels/chan_multicast_rtp.c b/channels/chan_multicast_rtp.c index 730b2f459..ae6022cb6 100644 --- a/channels/chan_multicast_rtp.c +++ b/channels/chan_multicast_rtp.c @@ -117,8 +117,10 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo struct ast_sockaddr control_address; struct ast_sockaddr destination_address; struct ast_channel *chan; - struct ast_format fmt; - ast_best_codec(cap, &fmt); + struct ast_format_cap *caps = NULL; + struct ast_format *fmt = NULL; + + fmt = ast_format_cap_get_format(cap, 0); ast_sockaddr_setnull(&control_address); @@ -145,6 +147,11 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo goto failure; } + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + goto failure; + } + if (!(instance = ast_rtp_instance_new("multicast", NULL, &control_address, multicast_type))) { goto failure; } @@ -158,19 +165,25 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo ast_channel_tech_set(chan, &multicast_rtp_tech); - ast_format_cap_add(ast_channel_nativeformats(chan), &fmt); - ast_format_copy(ast_channel_writeformat(chan), &fmt); - ast_format_copy(ast_channel_rawwriteformat(chan), &fmt); - ast_format_copy(ast_channel_readformat(chan), &fmt); - ast_format_copy(ast_channel_rawreadformat(chan), &fmt); + ast_format_cap_append(caps, fmt, 0); + ast_channel_nativeformats_set(chan, caps); + ast_channel_set_writeformat(chan, fmt); + ast_channel_set_rawwriteformat(chan, fmt); + ast_channel_set_readformat(chan, fmt); + ast_channel_set_rawreadformat(chan, fmt); ast_channel_tech_pvt_set(chan, instance); ast_channel_unlock(chan); + ao2_ref(fmt, -1); + ao2_ref(caps, -1); + return chan; failure: + ao2_cleanup(fmt); + ao2_cleanup(caps); *cause = AST_CAUSE_FAILURE; return NULL; } @@ -178,12 +191,14 @@ failure: /*! \brief Function called when our module is loaded */ static int load_module(void) { - if (!(multicast_rtp_tech.capabilities = ast_format_cap_alloc(0))) { + if (!(multicast_rtp_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_DECLINE; } - ast_format_cap_add_all(multicast_rtp_tech.capabilities); + ast_format_cap_append_by_type(multicast_rtp_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN); if (ast_channel_register(&multicast_rtp_tech)) { ast_log(LOG_ERROR, "Unable to register channel class 'MulticastRTP'\n"); + ao2_ref(multicast_rtp_tech.capabilities, -1); + multicast_rtp_tech.capabilities = NULL; return AST_MODULE_LOAD_DECLINE; } @@ -194,7 +209,8 @@ static int load_module(void) static int unload_module(void) { ast_channel_unregister(&multicast_rtp_tech); - multicast_rtp_tech.capabilities = ast_format_cap_destroy(multicast_rtp_tech.capabilities); + ao2_ref(multicast_rtp_tech.capabilities, -1); + multicast_rtp_tech.capabilities = NULL; return 0; } diff --git a/channels/chan_nbs.c b/channels/chan_nbs.c index cbfb6b3c4..1be9bffeb 100644 --- a/channels/chan_nbs.c +++ b/channels/chan_nbs.c @@ -47,12 +47,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/pbx.h" #include "asterisk/utils.h" +#include "asterisk/format_cache.h" static const char tdesc[] = "Network Broadcast Sound Driver"; -/* Only linear is allowed */ -static struct ast_format prefformat; - static char context[AST_MAX_EXTENSION] = "default"; static const char type[] = "NBS"; @@ -63,7 +61,6 @@ struct nbs_pvt { struct ast_channel *owner; /* Channel we belong to, possibly NULL */ char app[16]; /* Our app */ char stream[80]; /* Our stream */ - struct ast_frame fr; /* "null" frame */ struct ast_module_user *u; /*! for holding a reference to this module */ }; @@ -178,37 +175,14 @@ static int nbs_hangup(struct ast_channel *ast) static struct ast_frame *nbs_xread(struct ast_channel *ast) { - struct nbs_pvt *p = ast_channel_tech_pvt(ast); - - - /* Some nice norms */ - p->fr.datalen = 0; - p->fr.samples = 0; - p->fr.data.ptr = NULL; - p->fr.src = type; - p->fr.offset = 0; - p->fr.mallocd=0; - p->fr.delivery.tv_sec = 0; - p->fr.delivery.tv_usec = 0; - ast_debug(1, "Returning null frame on %s\n", ast_channel_name(ast)); - return &p->fr; + return &ast_null_frame; } static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame) { struct nbs_pvt *p = ast_channel_tech_pvt(ast); - /* Write a frame of (presumably voice) data */ - if (frame->frametype != AST_FRAME_VOICE) { - if (frame->frametype != AST_FRAME_IMAGE) - ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype); - return 0; - } - if (frame->subclass.format.id != (AST_FORMAT_SLINEAR)) { - ast_log(LOG_WARNING, "Cannot handle frames in %s format\n", ast_getformatname(&frame->subclass.format)); - return 0; - } if (ast_channel_state(ast) != AST_STATE_UP) { /* Don't try tos end audio on-hook */ return 0; @@ -226,11 +200,11 @@ static struct ast_channel *nbs_new(struct nbs_pvt *i, int state, const struct as ast_channel_tech_set(tmp, &nbs_tech); ast_channel_set_fd(tmp, 0, nbs_fd(i->nbs)); - ast_format_cap_add(ast_channel_nativeformats(tmp), &prefformat); - ast_format_copy(ast_channel_rawreadformat(tmp), &prefformat); - ast_format_copy(ast_channel_rawwriteformat(tmp), &prefformat); - ast_format_copy(ast_channel_writeformat(tmp), &prefformat); - ast_format_copy(ast_channel_readformat(tmp), &prefformat); + ast_channel_nativeformats_set(tmp, nbs_tech.capabilities); + ast_channel_set_rawreadformat(tmp, ast_format_slin); + ast_channel_set_rawwriteformat(tmp, ast_format_slin); + ast_channel_set_writeformat(tmp, ast_format_slin); + ast_channel_set_readformat(tmp, ast_format_slin); if (state == AST_STATE_RING) ast_channel_rings_set(tmp, 1); ast_channel_tech_pvt_set(tmp, i); @@ -257,9 +231,11 @@ static struct ast_channel *nbs_request(const char *type, struct ast_format_cap * struct nbs_pvt *p; struct ast_channel *tmp = NULL; - if (!(ast_format_cap_iscompatible(cap, &prefformat))) { - char tmp[256]; - ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap)); + if (ast_format_cap_iscompatible_format(cap, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_str *cap_buf = ast_str_alloca(64); + + ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", + ast_format_cap_get_names(cap, &cap_buf)); return NULL; } p = nbs_alloc(data); @@ -275,17 +251,17 @@ static int unload_module(void) { /* First, take us out of the channel loop */ ast_channel_unregister(&nbs_tech); - nbs_tech.capabilities = ast_format_cap_destroy(nbs_tech.capabilities); + ao2_ref(nbs_tech.capabilities, -1); + nbs_tech.capabilities = NULL; return 0; } static int load_module(void) { - ast_format_set(&prefformat, AST_FORMAT_SLINEAR, 0); - if (!(nbs_tech.capabilities = ast_format_cap_alloc(0))) { + if (!(nbs_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_FAILURE; } - ast_format_cap_add(nbs_tech.capabilities, &prefformat); + ast_format_cap_append(nbs_tech.capabilities, ast_format_slin, 0); /* Make sure we can register our channel type */ if (ast_channel_register(&nbs_tech)) { ast_log(LOG_ERROR, "Unable to register channel class %s\n", type); diff --git a/channels/chan_oss.c b/channels/chan_oss.c index 4459b4b6f..46b751d7c 100644 --- a/channels/chan_oss.c +++ b/channels/chan_oss.c @@ -69,6 +69,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/musiconhold.h" #include "asterisk/app.h" #include "asterisk/bridge.h" +#include "asterisk/format_cache.h" #include "console_video.h" @@ -726,7 +727,7 @@ static struct ast_frame *oss_read(struct ast_channel *c) return f; /* ok we can build and deliver the frame to the caller */ f->frametype = AST_FRAME_VOICE; - ast_format_set(&f->subclass.format, AST_FORMAT_SLINEAR, 0); + f->subclass.format = ao2_bump(ast_format_slin); f->samples = FRAME_SIZE; f->datalen = FRAME_SIZE * 2; f->data.ptr = o->oss_read_buf + AST_FRIENDLY_OFFSET; @@ -804,9 +805,9 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx, setformat(o, O_RDWR); ast_channel_set_fd(c, 0, o->sounddev); /* -1 if device closed, override later */ - ast_format_set(ast_channel_readformat(c), AST_FORMAT_SLINEAR, 0); - ast_format_set(ast_channel_writeformat(c), AST_FORMAT_SLINEAR, 0); - ast_format_cap_add(ast_channel_nativeformats(c), ast_channel_readformat(c)); + ast_channel_set_readformat(c, ast_format_slin); + ast_channel_set_writeformat(c, ast_format_slin); + ast_channel_nativeformats_set(c, oss_tech.capabilities); /* if the console makes the call, add video to the offer */ /* if (state == AST_STATE_RINGING) TODO XXX CONSOLE VIDEO IS DISABLED UNTIL IT GETS A MAINTAINER @@ -851,8 +852,6 @@ static struct ast_channel *oss_request(const char *type, struct ast_format_cap * AST_APP_ARG(flags); ); char *parse = ast_strdupa(data); - char buf[256]; - struct ast_format tmpfmt; AST_NONSTANDARD_APP_ARGS(args, parse, '/'); o = find_desc(args.name); @@ -863,8 +862,9 @@ static struct ast_channel *oss_request(const char *type, struct ast_format_cap * /* XXX we could default to 'dsp' perhaps ? */ return NULL; } - if (!(ast_format_cap_iscompatible(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)))) { - ast_log(LOG_NOTICE, "Format %s unsupported\n", ast_getformatname_multiple(buf, sizeof(buf), cap)); + if (ast_format_cap_iscompatible_format(cap, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_str *codec_buf = ast_str_alloca(64); + ast_log(LOG_NOTICE, "Format %s unsupported\n", ast_format_cap_get_names(cap, &codec_buf)); return NULL; } if (o->owner) { @@ -1452,7 +1452,6 @@ static int load_module(void) struct ast_config *cfg = NULL; char *ctg = NULL; struct ast_flags config_flags = { 0 }; - struct ast_format tmpfmt; /* Copy the default jb config over global_jbconf */ memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); @@ -1482,7 +1481,7 @@ static int load_module(void) if (!(oss_tech.capabilities = ast_format_cap_alloc(0))) { return AST_MODULE_LOAD_FAILURE; } - ast_format_cap_add(oss_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(oss_tech.capabilities, ast_format_slin, 0); /* TODO XXX CONSOLE VIDEO IS DISABLE UNTIL IT HAS A MAINTAINER * add console_video_formats to oss_tech.capabilities once this occurs. */ @@ -1517,7 +1516,9 @@ static int unload_module(void) ast_free(o); o = next; } - oss_tech.capabilities = ast_format_cap_destroy(oss_tech.capabilities); + ao2_cleanup(oss_tech.capabilities); + oss_tech.capabilities = NULL; + return 0; } diff --git a/channels/chan_phone.c b/channels/chan_phone.c index 1e5e19d57..72f38291b 100644 --- a/channels/chan_phone.c +++ b/channels/chan_phone.c @@ -67,6 +67,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/causes.h" #include "asterisk/stringfields.h" #include "asterisk/musiconhold.h" +#include "asterisk/format_cache.h" +#include "asterisk/format_compatibility.h" #include "chan_phone.h" @@ -134,8 +136,8 @@ static struct phone_pvt { int fd; /* Raw file descriptor for this device */ struct ast_channel *owner; /* Channel we belong to, possibly NULL */ int mode; /* Is this in the */ - struct ast_format lastformat; /* Last output format */ - struct ast_format lastinput; /* Last input format */ + struct ast_format *lastformat; /* Last output format */ + struct ast_format *lastinput; /* Last input format */ int ministate; /* Miniature state, for dialtone mode */ char dev[256]; /* Device name */ struct phone_pvt *next; /* Next channel in list */ @@ -218,7 +220,8 @@ static int phone_indicate(struct ast_channel *chan, int condition, const void *d ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK); usleep(320000); ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK); - ast_format_clear(&p->lastformat); + ao2_cleanup(p->lastformat); + p->lastformat = NULL; res = 0; break; case AST_CONTROL_HOLD: @@ -282,7 +285,8 @@ static int phone_digit_end(struct ast_channel *ast, char digit, unsigned int dur ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK); usleep(320000); ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK); - ast_format_clear(&p->lastformat); + ao2_cleanup(p->lastformat); + p->lastformat = NULL; return 0; default: ast_log(LOG_WARNING, "Unknown digit '%c'\n", digit); @@ -290,7 +294,8 @@ static int phone_digit_end(struct ast_channel *ast, char digit, unsigned int dur } ast_debug(1, "Dialed %d\n", outdigit); ioctl(p->fd, PHONE_PLAY_TONE, outdigit); - ast_format_clear(&p->lastformat); + ao2_cleanup(p->lastformat); + p->lastformat = NULL; return 0; } @@ -381,8 +386,10 @@ static int phone_hangup(struct ast_channel *ast) ioctl(p->fd, PHONE_BUSY); p->cpt = 1; } - ast_format_clear(&p->lastformat); - ast_format_clear(&p->lastinput); + ao2_cleanup(p->lastformat); + p->lastformat = NULL; + ao2_cleanup(p->lastinput); + p->lastinput = NULL; p->ministate = 0; p->obuflen = 0; p->dialtone = 0; @@ -402,38 +409,38 @@ static int phone_setup(struct ast_channel *ast) p = ast_channel_tech_pvt(ast); ioctl(p->fd, PHONE_CPT_STOP); /* Nothing to answering really, just start recording */ - if (ast_channel_rawreadformat(ast)->id == AST_FORMAT_G729A) { + if (ast_format_cmp(ast_channel_rawreadformat(ast), ast_format_g729) == AST_FORMAT_CMP_EQUAL) { /* Prefer g729 */ ioctl(p->fd, PHONE_REC_STOP); - if (p->lastinput.id != AST_FORMAT_G729A) { - ast_format_set(&p->lastinput, AST_FORMAT_G729A, 0); + if (!p->lastinput || (ast_format_cmp(p->lastinput, ast_format_g729) != AST_FORMAT_CMP_EQUAL)) { + ao2_replace(p->lastinput, ast_format_g729); if (ioctl(p->fd, PHONE_REC_CODEC, G729)) { ast_log(LOG_WARNING, "Failed to set codec to g729\n"); return -1; } } - } else if (ast_channel_rawreadformat(ast)->id == AST_FORMAT_G723_1) { + } else if (ast_format_cmp(ast_channel_rawreadformat(ast), ast_format_g723) == AST_FORMAT_CMP_EQUAL) { ioctl(p->fd, PHONE_REC_STOP); - if (p->lastinput.id != AST_FORMAT_G723_1) { - ast_format_set(&p->lastinput, AST_FORMAT_G723_1, 0); + if (!p->lastinput || (ast_format_cmp(p->lastinput, ast_format_g723) != AST_FORMAT_CMP_EQUAL)) { + ao2_replace(p->lastinput, ast_format_g723); if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) { ast_log(LOG_WARNING, "Failed to set codec to g723.1\n"); return -1; } } - } else if (ast_channel_rawreadformat(ast)->id == AST_FORMAT_SLINEAR) { + } else if (ast_format_cmp(ast_channel_rawreadformat(ast), ast_format_slin) == AST_FORMAT_CMP_EQUAL) { ioctl(p->fd, PHONE_REC_STOP); - if (p->lastinput.id != AST_FORMAT_SLINEAR) { - ast_format_set(&p->lastinput, AST_FORMAT_SLINEAR, 0); + if (!p->lastinput || (ast_format_cmp(p->lastinput, ast_format_slin) != AST_FORMAT_CMP_EQUAL)) { + ao2_replace(p->lastinput, ast_format_slin); if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) { ast_log(LOG_WARNING, "Failed to set codec to signed linear 16\n"); return -1; } } - } else if (ast_channel_rawreadformat(ast)->id == AST_FORMAT_ULAW) { + } else if (ast_format_cmp(ast_channel_rawreadformat(ast), ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) { ioctl(p->fd, PHONE_REC_STOP); - if (p->lastinput.id != AST_FORMAT_ULAW) { - ast_format_set(&p->lastinput, AST_FORMAT_ULAW, 0); + if (!p->lastinput || (ast_format_cmp(p->lastinput, ast_format_ulaw) != AST_FORMAT_CMP_EQUAL)) { + ao2_replace(p->lastinput, ast_format_ulaw); if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) { ast_log(LOG_WARNING, "Failed to set codec to uLaw\n"); return -1; @@ -441,16 +448,16 @@ static int phone_setup(struct ast_channel *ast) } } else if (p->mode == MODE_FXS) { ioctl(p->fd, PHONE_REC_STOP); - if (ast_format_cmp(&p->lastinput, ast_channel_rawreadformat(ast)) == AST_FORMAT_CMP_NOT_EQUAL) { - ast_format_copy(&p->lastinput, ast_channel_rawreadformat(ast)); + if (!p->lastinput || (ast_format_cmp(p->lastinput, ast_channel_rawreadformat(ast)) == AST_FORMAT_CMP_NOT_EQUAL)) { + ao2_replace(p->lastinput, ast_channel_rawreadformat(ast)); if (ioctl(p->fd, PHONE_REC_CODEC, ast_channel_rawreadformat(ast))) { ast_log(LOG_WARNING, "Failed to set codec to %s\n", - ast_getformatname(ast_channel_rawreadformat(ast))); + ast_format_get_name(ast_channel_rawreadformat(ast))); return -1; } } } else { - ast_log(LOG_WARNING, "Can't do format %s\n", ast_getformatname(ast_channel_rawreadformat(ast))); + ast_log(LOG_WARNING, "Can't do format %s\n", ast_format_get_name(ast_channel_rawreadformat(ast))); return -1; } if (ioctl(p->fd, PHONE_REC_START)) { @@ -601,13 +608,13 @@ static struct ast_frame *phone_read(struct ast_channel *ast) } p->fr.samples = 240; p->fr.datalen = res; - p->fr.frametype = AST_FORMAT_GET_TYPE(p->lastinput.id) == AST_FORMAT_TYPE_AUDIO ? - AST_FRAME_VOICE : AST_FORMAT_GET_TYPE(p->lastinput.id) == AST_FORMAT_TYPE_IMAGE ? + p->fr.frametype = ast_format_get_type(p->lastinput) == AST_MEDIA_TYPE_AUDIO ? + AST_FRAME_VOICE : ast_format_get_type(p->lastinput) == AST_MEDIA_TYPE_IMAGE ? AST_FRAME_IMAGE : AST_FRAME_VIDEO; - ast_format_copy(&p->fr.subclass.format, &p->lastinput); + p->fr.subclass.format = p->lastinput; p->fr.offset = AST_FRIENDLY_OFFSET; /* Byteswap from little-endian to native-endian */ - if (p->fr.subclass.format.id == AST_FORMAT_SLINEAR) + if (ast_format_cmp(p->fr.subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) ast_frame_byteswap_le(&p->fr); return &p->fr; } @@ -669,14 +676,6 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame) ast_log(LOG_WARNING, "Don't know what to do with frame type '%u'\n", frame->frametype); return 0; } - if (!(frame->subclass.format.id == AST_FORMAT_G723_1 || - frame->subclass.format.id == AST_FORMAT_SLINEAR || - frame->subclass.format.id == AST_FORMAT_ULAW || - frame->subclass.format.id == AST_FORMAT_G729A) && - p->mode != MODE_FXS) { - ast_log(LOG_WARNING, "Cannot handle frames in %s format\n", ast_getformatname(&frame->subclass.format)); - return -1; - } #if 0 /* If we're not in up mode, go into up mode now */ if (ast->_state != AST_STATE_UP) { @@ -689,8 +688,8 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame) return 0; } #endif - if (frame->subclass.format.id == AST_FORMAT_G729A) { - if (p->lastformat.id != AST_FORMAT_G729A) { + if (ast_format_cmp(frame->subclass.format, ast_format_g729) == AST_FORMAT_CMP_EQUAL) { + if (!p->lastformat || (ast_format_cmp(p->lastformat, ast_format_g729) != AST_FORMAT_CMP_EQUAL)) { ioctl(p->fd, PHONE_PLAY_STOP); ioctl(p->fd, PHONE_REC_STOP); if (ioctl(p->fd, PHONE_PLAY_CODEC, G729)) { @@ -701,8 +700,8 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame) ast_log(LOG_WARNING, "Unable to set G729 mode\n"); return -1; } - ast_format_set(&p->lastformat, AST_FORMAT_G729A, 0); - ast_format_set(&p->lastinput, AST_FORMAT_G729A, 0); + ao2_replace(p->lastformat, ast_format_g729); + ao2_replace(p->lastinput, ast_format_g729); /* Reset output buffer */ p->obuflen = 0; codecset = 1; @@ -712,8 +711,8 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame) return -1; } maxfr = 80; - } else if (frame->subclass.format.id == AST_FORMAT_G723_1) { - if (p->lastformat.id != AST_FORMAT_G723_1) { + } else if (ast_format_cmp(frame->subclass.format, ast_format_g723) == AST_FORMAT_CMP_EQUAL) { + if (!p->lastformat || (ast_format_cmp(p->lastformat, ast_format_g723) != AST_FORMAT_CMP_EQUAL)) { ioctl(p->fd, PHONE_PLAY_STOP); ioctl(p->fd, PHONE_REC_STOP); if (ioctl(p->fd, PHONE_PLAY_CODEC, G723_63)) { @@ -724,8 +723,8 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame) ast_log(LOG_WARNING, "Unable to set G723.1 mode\n"); return -1; } - ast_format_set(&p->lastformat, AST_FORMAT_G723_1, 0); - ast_format_set(&p->lastinput, AST_FORMAT_G723_1, 0); + ao2_replace(p->lastformat, ast_format_g723); + ao2_replace(p->lastinput, ast_format_g723); /* Reset output buffer */ p->obuflen = 0; codecset = 1; @@ -735,8 +734,8 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame) return -1; } maxfr = 24; - } else if (frame->subclass.format.id == AST_FORMAT_SLINEAR) { - if (p->lastformat.id != AST_FORMAT_SLINEAR) { + } else if (ast_format_cmp(frame->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) { + if (!p->lastformat || (ast_format_cmp(p->lastformat, ast_format_slin) != AST_FORMAT_CMP_EQUAL)) { ioctl(p->fd, PHONE_PLAY_STOP); ioctl(p->fd, PHONE_REC_STOP); if (ioctl(p->fd, PHONE_PLAY_CODEC, LINEAR16)) { @@ -747,15 +746,15 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame) ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n"); return -1; } - ast_format_set(&p->lastformat, AST_FORMAT_SLINEAR, 0); - ast_format_set(&p->lastinput, AST_FORMAT_SLINEAR, 0); + ao2_replace(p->lastformat, ast_format_slin); + ao2_replace(p->lastinput, ast_format_slin); codecset = 1; /* Reset output buffer */ p->obuflen = 0; } maxfr = 480; - } else if (frame->subclass.format.id == AST_FORMAT_ULAW) { - if (p->lastformat.id != AST_FORMAT_ULAW) { + } else if (ast_format_cmp(frame->subclass.format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) { + if (!p->lastformat || (ast_format_cmp(p->lastformat, ast_format_ulaw) != AST_FORMAT_CMP_EQUAL)) { ioctl(p->fd, PHONE_PLAY_STOP); ioctl(p->fd, PHONE_REC_STOP); if (ioctl(p->fd, PHONE_PLAY_CODEC, ULAW)) { @@ -766,29 +765,29 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame) ast_log(LOG_WARNING, "Unable to set uLaw mode\n"); return -1; } - ast_format_set(&p->lastformat, AST_FORMAT_ULAW, 0); - ast_format_set(&p->lastinput, AST_FORMAT_ULAW, 0); + ao2_replace(p->lastformat, ast_format_ulaw); + ao2_replace(p->lastinput, ast_format_ulaw); codecset = 1; /* Reset output buffer */ p->obuflen = 0; } maxfr = 240; } else { - if (ast_format_cmp(&p->lastformat, &frame->subclass.format) != AST_FORMAT_CMP_EQUAL) { + if (!p->lastformat || (ast_format_cmp(p->lastformat, frame->subclass.format) != AST_FORMAT_CMP_EQUAL)) { ioctl(p->fd, PHONE_PLAY_STOP); ioctl(p->fd, PHONE_REC_STOP); - if (ioctl(p->fd, PHONE_PLAY_CODEC, (int) frame->subclass.format.id)) { + if (ioctl(p->fd, PHONE_PLAY_CODEC, ast_format_compatibility_format2bitfield(frame->subclass.format))) { ast_log(LOG_WARNING, "Unable to set %s mode\n", - ast_getformatname(&frame->subclass.format)); + ast_format_get_name(frame->subclass.format)); return -1; } - if (ioctl(p->fd, PHONE_REC_CODEC, (int) frame->subclass.format.id)) { + if (ioctl(p->fd, PHONE_REC_CODEC, ast_format_compatibility_format2bitfield(frame->subclass.format))) { ast_log(LOG_WARNING, "Unable to set %s mode\n", - ast_getformatname(&frame->subclass.format)); + ast_format_get_name(frame->subclass.format)); return -1; } - ast_format_copy(&p->lastformat, &frame->subclass.format); - ast_format_copy(&p->lastinput, &frame->subclass.format); + ao2_replace(p->lastformat, frame->subclass.format); + ao2_replace(p->lastinput, frame->subclass.format); codecset = 1; /* Reset output buffer */ p->obuflen = 0; @@ -857,11 +856,13 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame) static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *cntx, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor) { + struct ast_format_cap *caps = NULL; struct ast_channel *tmp; struct phone_codec_data queried_codec; - struct ast_format tmpfmt; + struct ast_format *tmpfmt; + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, "", i->ext, i->context, assignedids, requestor, 0, "Phone/%s", i->dev + 5); - if (tmp) { + if (tmp && caps) { ast_channel_lock(tmp); ast_channel_tech_set(tmp, cur_tech); ast_channel_set_fd(tmp, 0, i->fd); @@ -869,18 +870,20 @@ static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *cntx, if (i->mode == MODE_FXS && ioctl(i->fd, PHONE_QUERY_CODEC, &queried_codec) == 0) { if (queried_codec.type == LINEAR16) { - ast_format_cap_add(ast_channel_nativeformats(tmp), ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)); - ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt); + ast_format_cap_append(caps, ast_format_slin, 0); } else { - ast_format_cap_remove(prefcap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_remove(prefcap, ast_format_slin); + ast_format_cap_append_from_cap(caps, prefcap, AST_MEDIA_TYPE_UNKNOWN); } } else { - ast_format_cap_copy(ast_channel_nativeformats(tmp), prefcap); - ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt); + ast_format_cap_append_from_cap(caps, prefcap, AST_MEDIA_TYPE_UNKNOWN); } + tmpfmt = ast_format_cap_get_format(caps, 0); + ast_channel_nativeformats_set(tmp, caps); + ao2_ref(caps, -1); + ast_channel_set_rawreadformat(tmp, tmpfmt); + ast_channel_set_rawwriteformat(tmp, tmpfmt); + ao2_ref(tmpfmt, -1); /* no need to call ast_setstate: the channel_alloc already did its job */ if (state == AST_STATE_RING) ast_channel_rings_set(tmp, 1); @@ -913,8 +916,10 @@ static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *cntx, ast_hangup(tmp); } } - } else + } else { + ao2_cleanup(caps); ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); + } return tmp; } @@ -989,7 +994,8 @@ static void phone_check_exception(struct phone_pvt *i) ioctl(i->fd, PHONE_PLAY_STOP); ioctl(i->fd, PHONE_PLAY_CODEC, ULAW); ioctl(i->fd, PHONE_PLAY_START); - ast_format_clear(&i->lastformat); + ao2_cleanup(i->lastformat); + i->lastformat = NULL; } else if (i->mode == MODE_SIGMA) { ast_module_ref(ast_module_info->self); /* Reset the extension */ @@ -1010,7 +1016,8 @@ static void phone_check_exception(struct phone_pvt *i) ioctl(i->fd, PHONE_PLAY_STOP); ioctl(i->fd, PHONE_REC_STOP); i->dialtone = 0; - ast_format_clear(&i->lastformat); + ao2_cleanup(i->lastformat); + i->lastformat = NULL; } } if (phonee.bits.pstn_ring) { @@ -1222,8 +1229,10 @@ static struct phone_pvt *mkif(const char *iface, int mode, int txgain, int rxgai flags = fcntl(tmp->fd, F_GETFL); fcntl(tmp->fd, F_SETFL, flags | O_NONBLOCK); tmp->owner = NULL; - ast_format_clear(&tmp->lastformat); - ast_format_clear(&tmp->lastinput); + ao2_cleanup(tmp->lastformat); + tmp->lastformat = NULL; + ao2_cleanup(tmp->lastinput); + tmp->lastinput = NULL; tmp->ministate = 0; memset(tmp->ext, 0, sizeof(tmp->ext)); ast_copy_string(tmp->language, language, sizeof(tmp->language)); @@ -1256,7 +1265,7 @@ static struct ast_channel *phone_request(const char *type, struct ast_format_cap } p = iflist; while(p) { - if (p->mode == MODE_FXS || (ast_format_cap_has_joint(cap, phone_tech.capabilities))) { + if (p->mode == MODE_FXS || (ast_format_cap_iscompatible(cap, phone_tech.capabilities))) { size_t length = strlen(p->dev + 5); if (strncmp(name, p->dev + 5, length) == 0 && !isalnum(name[length])) { @@ -1272,9 +1281,10 @@ static struct ast_channel *phone_request(const char *type, struct ast_format_cap ast_mutex_unlock(&iflock); restart_monitor(); if (tmp == NULL) { - if (!(ast_format_cap_has_joint(cap, phone_tech.capabilities))) { - char buf[256]; - ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(buf, sizeof(buf), cap)); + if (!(ast_format_cap_iscompatible(cap, phone_tech.capabilities))) { + struct ast_str *codec_buf = ast_str_alloca(64); + ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", + ast_format_cap_get_names(cap, &codec_buf)); return NULL; } } @@ -1357,9 +1367,10 @@ static int __unload_module(void) return -1; } - phone_tech.capabilities = ast_format_cap_destroy(phone_tech.capabilities); - phone_tech_fxs.capabilities = ast_format_cap_destroy(phone_tech_fxs.capabilities); - prefcap = ast_format_cap_destroy(prefcap); + ao2_ref(phone_tech.capabilities, -1); + ao2_ref(phone_tech_fxs.capabilities, -1); + ao2_ref(prefcap, -1); + return 0; } @@ -1376,21 +1387,21 @@ static int load_module(void) int mode = MODE_IMMEDIATE; int txgain = DEFAULT_GAIN, rxgain = DEFAULT_GAIN; /* default gain 1.0 */ struct ast_flags config_flags = { 0 }; - struct ast_format tmpfmt; - if (!(phone_tech.capabilities = ast_format_cap_alloc(0))) { + if (!(phone_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_DECLINE; } - ast_format_cap_add(phone_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0)); - ast_format_cap_add(phone_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)); - ast_format_cap_add(phone_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0)); - ast_format_cap_add(phone_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0)); - if (!(prefcap = ast_format_cap_alloc(0))) { + ast_format_cap_append(phone_tech.capabilities, ast_format_g723, 0); + ast_format_cap_append(phone_tech.capabilities, ast_format_slin, 0); + ast_format_cap_append(phone_tech.capabilities, ast_format_ulaw, 0); + ast_format_cap_append(phone_tech.capabilities, ast_format_g729, 0); + + if (!(prefcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_DECLINE; } - ast_format_cap_copy(prefcap, phone_tech.capabilities); - if (!(phone_tech_fxs.capabilities = ast_format_cap_alloc(0))) { + ast_format_cap_append_from_cap(prefcap, phone_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN); + if (!(phone_tech_fxs.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_DECLINE; } @@ -1440,7 +1451,7 @@ static int load_module(void) mode = MODE_IMMEDIATE; else if (!strncasecmp(v->value, "fxs", 3)) { mode = MODE_FXS; - ast_format_cap_remove_bytype(prefcap, AST_FORMAT_TYPE_AUDIO); /* All non-voice */ + ast_format_cap_remove_by_type(prefcap, AST_MEDIA_TYPE_AUDIO); /* All non-voice */ } else if (!strncasecmp(v->value, "fx", 2)) mode = MODE_FXO; @@ -1450,18 +1461,21 @@ static int load_module(void) ast_copy_string(context, v->value, sizeof(context)); } else if (!strcasecmp(v->name, "format")) { if (!strcasecmp(v->value, "g729")) { - ast_format_cap_set(prefcap, ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0)); + ast_format_cap_remove_by_type(prefcap, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append(prefcap, ast_format_g729, 0); } else if (!strcasecmp(v->value, "g723.1")) { - ast_format_cap_set(prefcap, ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0)); + ast_format_cap_remove_by_type(prefcap, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append(prefcap, ast_format_g723, 0); } else if (!strcasecmp(v->value, "slinear")) { - ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0); if (mode == MODE_FXS) { - ast_format_cap_add(prefcap, &tmpfmt); + ast_format_cap_append(prefcap, ast_format_slin, 0); } else { - ast_format_cap_set(prefcap, &tmpfmt); + ast_format_cap_remove_by_type(prefcap, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append(prefcap, ast_format_slin, 0); } } else if (!strcasecmp(v->value, "ulaw")) { - ast_format_cap_set(prefcap, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0)); + ast_format_cap_remove_by_type(prefcap, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append(prefcap, ast_format_ulaw, 0); } else ast_log(LOG_WARNING, "Unknown format '%s'\n", v->value); } else if (!strcasecmp(v->name, "echocancel")) { @@ -1485,7 +1499,7 @@ static int load_module(void) ast_mutex_unlock(&iflock); if (mode == MODE_FXS) { - ast_format_cap_copy(phone_tech_fxs.capabilities, prefcap); + ast_format_cap_append_from_cap(phone_tech_fxs.capabilities, prefcap, AST_MEDIA_TYPE_UNKNOWN); cur_tech = &phone_tech_fxs; } else cur_tech = (struct ast_channel_tech *) &phone_tech; diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 695211480..5812360c5 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -57,6 +57,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/stasis_endpoints.h" #include "asterisk/stasis_channels.h" #include "asterisk/indications.h" +#include "asterisk/format_cache.h" #include "asterisk/threadstorage.h" #include "asterisk/features_config.h" #include "asterisk/pickup.h" @@ -210,7 +211,7 @@ static void chan_pjsip_get_codec(struct ast_channel *chan, struct ast_format_cap { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan); - ast_format_cap_copy(result, channel->session->endpoint->media.codecs); + ast_format_cap_append_from_cap(result, channel->session->endpoint->media.codecs, AST_MEDIA_TYPE_UNKNOWN); } static int send_direct_media_request(void *data) @@ -325,8 +326,9 @@ static int chan_pjsip_set_rtp_peer(struct ast_channel *chan, return 0; } - if (cap && !ast_format_cap_is_empty(cap) && !ast_format_cap_identical(session->direct_media_cap, cap)) { - ast_format_cap_copy(session->direct_media_cap, cap); + if (cap && ast_format_cap_count(cap) && !ast_format_cap_identical(session->direct_media_cap, cap)) { + ast_format_cap_remove_by_type(session->direct_media_cap, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_from_cap(session->direct_media_cap, cap, AST_MEDIA_TYPE_UNKNOWN); changed = 1; } @@ -355,7 +357,8 @@ static struct ast_rtp_glue chan_pjsip_rtp_glue = { static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int state, const char *exten, const char *title, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *cid_name) { struct ast_channel *chan; - struct ast_format fmt; + struct ast_format_cap *caps; + struct ast_format *fmt; RAII_VAR(struct chan_pjsip_pvt *, pvt, NULL, ao2_cleanup); struct ast_sip_channel_pvt *channel; struct ast_variable *var; @@ -363,19 +366,21 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s if (!(pvt = ao2_alloc(sizeof(*pvt), chan_pjsip_pvt_dtor))) { return NULL; } + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + return NULL; + } - - chan = ast_channel_alloc(1, state, S_OR(session->id.number.str, ""), S_OR(session->id.name.str, ""), - session->endpoint->accountcode, "", "", assignedids, - requestor, 0, "PJSIP/%s-%08x", ast_sorcery_object_get_id(session->endpoint), - (unsigned)ast_atomic_fetchadd_int((int *)&chan_idx, +1)); - if (!chan) { + if (!(chan = ast_channel_alloc(1, state, S_OR(session->id.number.str, ""), S_OR(session->id.name.str, ""), session->endpoint->accountcode, "", "", assignedids, requestor, 0, "PJSIP/%s-%08x", ast_sorcery_object_get_id(session->endpoint), + (unsigned)ast_atomic_fetchadd_int((int *)&chan_idx, +1)))) { + ao2_ref(caps, -1); return NULL; } ast_channel_tech_set(chan, &chan_pjsip_tech); if (!(channel = ast_sip_channel_pvt_alloc(pvt, session))) { + ao2_ref(caps, -1); ast_channel_unlock(chan); ast_hangup(chan); return NULL; @@ -391,17 +396,21 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s ast_channel_tech_pvt_set(chan, channel); - if (ast_format_cap_is_empty(session->req_caps) || !ast_format_cap_has_joint(session->req_caps, session->endpoint->media.codecs)) { - ast_format_cap_copy(ast_channel_nativeformats(chan), session->endpoint->media.codecs); + if (!ast_format_cap_count(session->req_caps) || + !ast_format_cap_iscompatible(session->req_caps, session->endpoint->media.codecs)) { + ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, AST_MEDIA_TYPE_UNKNOWN); } else { - ast_format_cap_copy(ast_channel_nativeformats(chan), session->req_caps); + ast_format_cap_append_from_cap(caps, session->req_caps, AST_MEDIA_TYPE_UNKNOWN); } - ast_codec_choose(&session->endpoint->media.prefs, ast_channel_nativeformats(chan), 1, &fmt); - ast_format_copy(ast_channel_writeformat(chan), &fmt); - ast_format_copy(ast_channel_rawwriteformat(chan), &fmt); - ast_format_copy(ast_channel_readformat(chan), &fmt); - ast_format_copy(ast_channel_rawreadformat(chan), &fmt); + ast_channel_nativeformats_set(chan, caps); + fmt = ast_format_cap_get_format(caps, 0); + ast_channel_set_writeformat(chan, fmt); + ast_channel_set_rawwriteformat(chan, fmt); + ast_channel_set_readformat(chan, fmt); + ast_channel_set_rawreadformat(chan, fmt); + ao2_ref(fmt, -1); + ao2_ref(caps, -1); if (state == AST_STATE_RING) { ast_channel_rings_set(chan, 1); @@ -584,9 +593,18 @@ static struct ast_frame *chan_pjsip_read(struct ast_channel *ast) return f; } - if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &f->subclass.format))) { - ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format)); - ast_format_cap_set(ast_channel_nativeformats(ast), &f->subclass.format); + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_format_cap *caps; + + ast_debug(1, "Oooh, format changed to %s\n", ast_format_get_name(f->subclass.format)); + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (caps) { + ast_format_cap_append(caps, f->subclass.format, 0); + ast_channel_nativeformats_set(ast, caps); + ao2_ref(caps, -1); + } + ast_set_read_format(ast, ast_channel_readformat(ast)); ast_set_write_format(ast, ast_channel_writeformat(ast)); } @@ -623,15 +641,15 @@ static int chan_pjsip_write(struct ast_channel *ast, struct ast_frame *frame) if (!media) { return 0; } - if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) { - char buf[256]; + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_str *cap_buf = ast_str_alloca(64); ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n", - ast_getformatname(&frame->subclass.format), - ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)), - ast_getformatname(ast_channel_readformat(ast)), - ast_getformatname(ast_channel_writeformat(ast))); + ast_format_get_name(frame->subclass.format), + ast_format_cap_get_names(ast_channel_nativeformats(ast), &cap_buf), + ast_format_get_name(ast_channel_readformat(ast)), + ast_format_get_name(ast_channel_writeformat(ast))); return 0; } if (media->rtp) { @@ -1127,10 +1145,8 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi if (media && media->rtp) { /* FIXME: Only use this for VP8. Additional work would have to be done to * fully support other video codecs */ - struct ast_format_cap *fcap = ast_channel_nativeformats(ast); - struct ast_format vp8; - ast_format_set(&vp8, AST_FORMAT_VP8, 0); - if (ast_format_cap_iscompatible(fcap, &vp8)) { + + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_vp8) != AST_FORMAT_CMP_NOT_EQUAL) { /* FIXME Fake RTP write, this will be sent as an RTCP packet. Ideally the * RTP engine would provide a way to externally write/schedule RTCP * packets */ @@ -2162,11 +2178,11 @@ static int load_module(void) { struct ao2_container *endpoints; - if (!(chan_pjsip_tech.capabilities = ast_format_cap_alloc(0))) { + if (!(chan_pjsip_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_DECLINE; } - ast_format_cap_add_all_by_type(chan_pjsip_tech.capabilities, AST_FORMAT_TYPE_AUDIO); + ast_format_cap_append_by_type(chan_pjsip_tech.capabilities, AST_MEDIA_TYPE_AUDIO); ast_rtp_glue_register(&chan_pjsip_rtp_glue); @@ -2259,6 +2275,7 @@ static int unload_module(void) ast_custom_function_unregister(&chan_pjsip_dial_contacts_function); ast_channel_unregister(&chan_pjsip_tech); + ao2_ref(chan_pjsip_tech.capabilities, -1); ast_rtp_glue_unregister(&chan_pjsip_rtp_glue); return 0; diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 095b5a763..44629dc3d 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -285,6 +285,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/stasis_channels.h" #include "asterisk/features_config.h" #include "asterisk/http_websocket.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <application name="SIPDtmfMode" language="en_US"> @@ -747,7 +748,6 @@ static char default_mohsuggest[MAX_MUSICCLASS]; /*!< Global setting for moh c static char default_parkinglot[AST_MAX_CONTEXT]; /*!< Parkinglot */ static char default_engine[256]; /*!< Default RTP engine */ static int default_maxcallbitrate; /*!< Maximum bitrate for call */ -static struct ast_codec_pref default_prefs; /*!< Default codec prefs */ static char default_zone[MAX_TONEZONE_COUNTRY]; /*!< Default tone zone for channels created from the SIP driver */ static unsigned int default_transports; /*!< Default Transports (enum ast_transport) that are acceptable */ static unsigned int default_primary_transport; /*!< Default primary Transport (enum ast_transport) for outbound connections to devices */ @@ -1295,7 +1295,6 @@ static int str2dtmfmode(const char *str) attribute_unused; static const char *insecure2str(int mode) attribute_const; static const char *allowoverlap2str(int mode) attribute_const; static void cleanup_stale_contexts(char *new, char *old); -static void print_codec_to_cli(int fd, struct ast_codec_pref *pref); static const char *domain_mode_to_text(const enum domain_mode mode); static char *sip_show_domains(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[]); @@ -1764,7 +1763,7 @@ static void destroy_escs(void) { int i; for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) { - ao2_ref(event_state_compositors[i].compositor, -1); + ao2_cleanup(event_state_compositors[i].compositor); } } @@ -3385,7 +3384,7 @@ static void unlink_peers_from_tables(peer_unlink_flag_t flag) ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, match_and_cleanup_peer_sched, &flag, "initiating callback to remove marked peers"); ao2_t_callback(peers_by_ip, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, - match_and_cleanup_peer_sched, &flag, "initiating callback to remove marked peers"); + match_and_cleanup_peer_sched, &flag, "initiating callback to remove marked peers_by_ip"); } /* \brief Unlink all marked peers from ao2 containers */ @@ -5308,7 +5307,7 @@ static void sip_destroy_peer(struct sip_peer *peer) ast_string_field_free_memory(peer); - peer->caps = ast_format_cap_destroy(peer->caps); + ao2_cleanup(peer->caps); ast_rtp_dtls_cfg_free(&peer->dtls_cfg); @@ -5967,7 +5966,7 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog) } if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT_ALWAYS) || - (ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT) && (ast_format_cap_has_type(dialog->caps, AST_FORMAT_TYPE_VIDEO)))) { + (ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT) && (ast_format_cap_has_type(dialog->caps, AST_MEDIA_TYPE_VIDEO)))) { if (!(dialog->vrtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr_tmp, NULL))) { return -1; } @@ -6053,8 +6052,11 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) ast_copy_flags(&dialog->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY); ast_copy_flags(&dialog->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY); ast_copy_flags(&dialog->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY); - ast_format_cap_copy(dialog->caps, peer->caps); - dialog->prefs = peer->prefs; + /* Take the peer's caps */ + if (peer->caps) { + ast_format_cap_remove_by_type(dialog->caps, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_from_cap(dialog->caps, peer->caps, AST_MEDIA_TYPE_UNKNOWN); + } dialog->amaflags = peer->amaflags; ast_string_field_set(dialog, engine, peer->engine); @@ -6078,8 +6080,8 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833); ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE)); /* Set Frame packetization */ - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(dialog->rtp), dialog->rtp, &dialog->prefs); dialog->autoframing = peer->autoframing; + ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(dialog->rtp), ast_format_cap_get_framing(dialog->caps)); } /* XXX TODO: get fields directly from peer only as they are needed using dialog->relatedpeer */ @@ -6456,7 +6458,7 @@ static int sip_call(struct ast_channel *ast, const char *dest, int timeout) p->jointnoncodeccapability = p->noncodeccapability; /* If there are no audio formats left to offer, punt */ - if (!(ast_format_cap_has_type(p->jointcaps, AST_FORMAT_TYPE_AUDIO))) { + if (!(ast_format_cap_has_type(p->jointcaps, AST_MEDIA_TYPE_AUDIO))) { ast_log(LOG_WARNING, "No audio format found to offer. Cancelling call to %s\n", p->username); res = -1; } else { @@ -6721,11 +6723,11 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist) p->named_callgroups = ast_unref_namedgroups(p->named_callgroups); p->named_pickupgroups = ast_unref_namedgroups(p->named_pickupgroups); - p->caps = ast_format_cap_destroy(p->caps); - p->jointcaps = ast_format_cap_destroy(p->jointcaps); - p->peercaps = ast_format_cap_destroy(p->peercaps); - p->redircaps = ast_format_cap_destroy(p->redircaps); - p->prefcaps = ast_format_cap_destroy(p->prefcaps); + ao2_cleanup(p->caps); + ao2_cleanup(p->jointcaps); + ao2_cleanup(p->peercaps); + ao2_cleanup(p->redircaps); + ao2_cleanup(p->prefcaps); ast_rtp_dtls_cfg_free(&p->dtls_cfg); @@ -7308,7 +7310,6 @@ static int sip_hangup(struct ast_channel *ast) /*! \brief Try setting the codecs suggested by the SIP_CODEC channel variable */ static void try_suggested_sip_codec(struct sip_pvt *p) { - struct ast_format fmt; const char *codec_list; char *codec_list_copy; struct ast_format_cap *original_jointcaps; @@ -7328,31 +7329,44 @@ static void try_suggested_sip_codec(struct sip_pvt *p) } codec_list_copy = ast_strdupa(codec_list); - original_jointcaps = ast_format_cap_dup(p->jointcaps); + + original_jointcaps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!original_jointcaps) { + return; + } + ast_format_cap_append_from_cap(original_jointcaps, p->jointcaps, AST_MEDIA_TYPE_UNKNOWN); for (codec = strtok_r(codec_list_copy, ",", &strtok_ptr); codec; codec = strtok_r(NULL, ",", &strtok_ptr)) { + struct ast_format *fmt; + codec = ast_strip(codec); - if (!ast_getformatbyname(codec, &fmt)) { + fmt = ast_format_cache_get(codec); + if (!fmt) { ast_log(AST_LOG_NOTICE, "Ignoring ${SIP_CODEC*} variable because of unrecognized/not configured codec %s (check allow/disallow in sip.conf)\n", codec); continue; } - if (ast_format_cap_iscompatible(original_jointcaps, &fmt)) { + if (ast_format_cap_iscompatible_format(original_jointcaps, fmt) != AST_FORMAT_CMP_NOT_EQUAL) { if (first_codec) { ast_verb(4, "Set codec to '%s' for this call because of ${SIP_CODEC*} variable\n", codec); - ast_format_cap_set(p->jointcaps, &fmt); - ast_format_cap_set(p->caps, &fmt); + ast_format_cap_remove_by_type(p->jointcaps, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append(p->jointcaps, fmt, 0); + ast_format_cap_remove_by_type(p->caps, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append(p->caps, fmt, 0); first_codec = 0; } else { ast_verb(4, "Add codec to '%s' for this call because of ${SIP_CODEC*} variable\n", codec); - ast_format_cap_add(p->jointcaps, &fmt); - ast_format_cap_add(p->caps, &fmt); + /* Add the format to the capabilities structure */ + ast_format_cap_append(p->jointcaps, fmt, 0); + ast_format_cap_append(p->caps, fmt, 0); } } else { ast_log(AST_LOG_NOTICE, "Ignoring ${SIP_CODEC*} variable because it is not shared by both ends: %s\n", codec); } + + ao2_ref(fmt, -1); } - ast_format_cap_destroy(original_jointcaps); + ao2_ref(original_jointcaps, -1); return; } @@ -7401,13 +7415,13 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame) switch (frame->frametype) { case AST_FRAME_VOICE: - if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) { - char s1[512]; + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_str *codec_buf = ast_str_alloca(64); ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s read/write = %s/%s\n", - ast_getformatname(&frame->subclass.format), - ast_getformatname_multiple(s1, sizeof(s1), ast_channel_nativeformats(ast)), - ast_getformatname(ast_channel_readformat(ast)), - ast_getformatname(ast_channel_writeformat(ast))); + ast_format_get_name(frame->subclass.format), + ast_format_cap_get_names(ast_channel_nativeformats(ast), &codec_buf), + ast_format_get_name(ast_channel_readformat(ast)), + ast_format_get_name(ast_channel_writeformat(ast))); return 0; } if (p) { @@ -7929,10 +7943,7 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data if (p->vrtp && !p->novideo) { /* FIXME: Only use this for VP8. Additional work would have to be done to * fully support other video codecs */ - struct ast_format_cap *fcap = ast_channel_nativeformats(ast); - struct ast_format vp8; - ast_format_set(&vp8, AST_FORMAT_VP8, 0); - if (ast_format_cap_iscompatible(fcap, &vp8)) { + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_vp8) != AST_FORMAT_CMP_NOT_EQUAL) { /* FIXME Fake RTP write, this will be sent as an RTCP packet. Ideally the * RTP engine would provide a way to externally write/schedule RTCP * packets */ @@ -8036,15 +8047,21 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data */ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *title, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, struct ast_callid *callid) { + struct ast_format_cap *caps; struct ast_channel *tmp; struct ast_variable *v = NULL; - struct ast_format fmt; + struct ast_format *fmt; struct ast_format_cap *what = NULL; /* SHALLOW COPY DO NOT DESTROY! */ + struct ast_str *codec_buf = ast_str_alloca(64); int needvideo = 0; int needtext = 0; - char buf[SIPBUFSIZE]; char *exten; + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + return NULL; + } + { const char *my_name; /* pick a good name */ @@ -8060,6 +8077,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit } if (!tmp) { ast_log(LOG_WARNING, "Unable to allocate AST channel structure for SIP channel\n"); + ao2_ref(caps, -1); sip_pvt_lock(i); return NULL; } @@ -8068,6 +8086,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit if (ast_endpoint_add_channel(i->relatedpeer->endpoint, tmp)) { ast_channel_unlock(tmp); ast_channel_unref(tmp); + ao2_ref(caps, -1); sip_pvt_lock(i); return NULL; } @@ -8088,27 +8107,40 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit /* Select our native format based on codec preference until we receive something from another device to the contrary. */ - if (!(ast_format_cap_is_empty(i->jointcaps))) { /* The joint capabilities of us and peer */ + if (ast_format_cap_count(i->jointcaps)) { /* The joint capabilities of us and peer */ what = i->jointcaps; - } else if (!(ast_format_cap_is_empty(i->caps))) { /* Our configured capability for this peer */ + } else if (ast_format_cap_count(i->caps)) { /* Our configured capability for this peer */ what = i->caps; } else { what = sip_cfg.caps; } /* Set the native formats */ - ast_format_cap_copy(ast_channel_nativeformats(tmp), what); - /* choose and use only the best audio format for our native formats */ - ast_codec_choose(&i->prefs, ast_channel_nativeformats(tmp), 1, &fmt); /* get the best audio format */ - ast_format_cap_remove_bytype(ast_channel_nativeformats(tmp), AST_FORMAT_TYPE_AUDIO); /* remove only the other audio formats */ - ast_format_cap_add(ast_channel_nativeformats(tmp), &fmt); /* add our best choice back */ + ast_format_cap_append_from_cap(caps, what, AST_MEDIA_TYPE_UNKNOWN); + /* Use only the preferred audio format, which is stored at the '0' index */ + fmt = ast_format_cap_get_best_by_type(what, AST_MEDIA_TYPE_AUDIO); /* get the best audio format */ + if (fmt) { + ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_AUDIO); /* remove only the other audio formats */ + ast_format_cap_append(caps, fmt, 0); /* add our best choice back */ + } else { + /* If we don't have an audio format, try to get something */ + fmt = ast_format_cap_get_format(caps, 0); + if (!fmt) { + ast_log(LOG_WARNING, "No compatible formats could be found for %s\n", ast_channel_name(tmp)); + ao2_ref(caps, -1); + tmp = ast_channel_unref(tmp); + return NULL; + } + } + ast_channel_nativeformats_set(tmp, caps); + ao2_ref(caps, -1); - ast_debug(3, "*** Our native formats are %s \n", ast_getformatname_multiple(buf, SIPBUFSIZE, ast_channel_nativeformats(tmp))); - ast_debug(3, "*** Joint capabilities are %s \n", ast_getformatname_multiple(buf, SIPBUFSIZE, i->jointcaps)); - ast_debug(3, "*** Our capabilities are %s \n", ast_getformatname_multiple(buf, SIPBUFSIZE, i->caps)); - ast_debug(3, "*** AST_CODEC_CHOOSE formats are %s \n", ast_getformatname(&fmt)); - if (!ast_format_cap_is_empty(i->prefcaps)) { - ast_debug(3, "*** Our preferred formats from the incoming channel are %s \n", ast_getformatname_multiple(buf, SIPBUFSIZE, i->prefcaps)); + ast_debug(3, "*** Our native formats are %s \n", ast_format_cap_get_names(ast_channel_nativeformats(tmp), &codec_buf)); + ast_debug(3, "*** Joint capabilities are %s \n", ast_format_cap_get_names(i->jointcaps, &codec_buf)); + ast_debug(3, "*** Our capabilities are %s \n", ast_format_cap_get_names(i->caps, &codec_buf)); + ast_debug(3, "*** AST_CODEC_CHOOSE formats are %s \n", ast_format_get_name(fmt)); + if (ast_format_cap_count(i->prefcaps)) { + ast_debug(3, "*** Our preferred formats from the incoming channel are %s \n", ast_format_cap_get_names(i->prefcaps, &codec_buf)); } /* If we have a prefcodec setting, we have an inbound channel that set a @@ -8118,17 +8150,17 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit if (i->vrtp) { if (ast_test_flag(&i->flags[1], SIP_PAGE2_VIDEOSUPPORT)) needvideo = 1; - else if (!ast_format_cap_is_empty(i->prefcaps)) - needvideo = ast_format_cap_has_type(i->prefcaps, AST_FORMAT_TYPE_VIDEO); /* Outbound call */ + else if (ast_format_cap_count(i->prefcaps)) + needvideo = ast_format_cap_has_type(i->prefcaps, AST_MEDIA_TYPE_VIDEO); /* Outbound call */ else - needvideo = ast_format_cap_has_type(i->jointcaps, AST_FORMAT_TYPE_VIDEO); /* Inbound call */ + needvideo = ast_format_cap_has_type(i->jointcaps, AST_MEDIA_TYPE_VIDEO); /* Inbound call */ } if (i->trtp) { - if (!ast_format_cap_is_empty(i->prefcaps)) - needtext = ast_format_cap_has_type(i->prefcaps, AST_FORMAT_TYPE_TEXT); /* Outbound call */ + if (ast_format_cap_count(i->prefcaps)) + needtext = ast_format_cap_has_type(i->prefcaps, AST_MEDIA_TYPE_TEXT); /* Outbound call */ else - needtext = ast_format_cap_has_type(i->jointcaps, AST_FORMAT_TYPE_TEXT); /* Inbound call */ + needtext = ast_format_cap_has_type(i->jointcaps, AST_MEDIA_TYPE_TEXT); /* Inbound call */ } if (needvideo) { @@ -8156,8 +8188,8 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit if (i->rtp) { ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0)); ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1)); - ast_rtp_instance_set_write_format(i->rtp, &fmt); - ast_rtp_instance_set_read_format(i->rtp, &fmt); + ast_rtp_instance_set_write_format(i->rtp, fmt); + ast_rtp_instance_set_read_format(i->rtp, fmt); } if (needvideo && i->vrtp) { ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0)); @@ -8175,11 +8207,13 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit } ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE); - ast_format_copy(ast_channel_writeformat(tmp), &fmt); - ast_format_copy(ast_channel_rawwriteformat(tmp), &fmt); + ast_channel_set_writeformat(tmp, fmt); + ast_channel_set_rawwriteformat(tmp, fmt); + + ast_channel_set_readformat(tmp, fmt); + ast_channel_set_rawreadformat(tmp, fmt); - ast_format_copy(ast_channel_readformat(tmp), &fmt); - ast_format_copy(ast_channel_rawreadformat(tmp), &fmt); + ao2_ref(fmt, -1); ast_channel_tech_pvt_set(tmp, dialog_ref(i, "sip_new: set chan->tech_pvt to i")); @@ -8534,17 +8568,26 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p return f; } - if (f && !ast_format_cap_iscompatible(ast_channel_nativeformats(p->owner), &f->subclass.format)) { - if (!ast_format_cap_iscompatible(p->jointcaps, &f->subclass.format)) { + if (f && ast_format_cap_iscompatible_format(ast_channel_nativeformats(p->owner), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_format_cap *caps; + + if (ast_format_cap_iscompatible_format(p->jointcaps, f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n", - ast_getformatname(&f->subclass.format), ast_channel_name(p->owner)); + ast_format_get_name(f->subclass.format), ast_channel_name(p->owner)); ast_frfree(f); return &ast_null_frame; } ast_debug(1, "Oooh, format changed to %s\n", - ast_getformatname(&f->subclass.format)); - ast_format_cap_remove_bytype(ast_channel_nativeformats(p->owner), AST_FORMAT_TYPE_AUDIO); - ast_format_cap_add(ast_channel_nativeformats(p->owner), &f->subclass.format); + ast_format_get_name(f->subclass.format)); + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (caps) { + ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(p->owner), AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_AUDIO); + ast_format_cap_append(caps, f->subclass.format, 0); + ast_channel_nativeformats_set(p->owner, caps); + ao2_ref(caps, -1); + } ast_set_read_format(p->owner, ast_channel_readformat(p->owner)); ast_set_write_format(p->owner, ast_channel_writeformat(p->owner)); } @@ -8796,18 +8839,18 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr, sip_pvt_callid_set(p, logger_callid); } - p->caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - p->jointcaps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - p->peercaps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - p->redircaps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - p->prefcaps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + p->caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + p->jointcaps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + p->peercaps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + p->redircaps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + p->prefcaps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - if (!p->caps|| !p->jointcaps || !p->peercaps || !p->redircaps) { - p->caps = ast_format_cap_destroy(p->caps); - p->jointcaps = ast_format_cap_destroy(p->jointcaps); - p->peercaps = ast_format_cap_destroy(p->peercaps); - p->redircaps = ast_format_cap_destroy(p->redircaps); - p->prefcaps = ast_format_cap_destroy(p->prefcaps); + if (!p->caps|| !p->jointcaps || !p->peercaps || !p->redircaps || !p->prefcaps) { + ao2_cleanup(p->caps); + ao2_cleanup(p->jointcaps); + ao2_cleanup(p->peercaps); + ao2_cleanup(p->redircaps); + ao2_cleanup(p->prefcaps); ao2_t_ref(p, -1, "Yuck, couldn't allocate format capabilities. Get rid o' p"); return NULL; } @@ -8857,7 +8900,6 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr, p->sessionversion_remote = -1; p->session_modify = TRUE; p->stimer = NULL; - p->prefs = default_prefs; /* Set default codecs for this call */ ast_copy_string(p->zone, default_zone, sizeof(p->zone)); p->maxforwards = sip_cfg.default_max_forwards; @@ -8909,7 +8951,7 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr, /* Assign default music on hold class */ ast_string_field_set(p, mohinterpret, default_mohinterpret); ast_string_field_set(p, mohsuggest, default_mohsuggest); - ast_format_cap_copy(p->caps, sip_cfg.caps); + ast_format_cap_append_from_cap(p->caps, sip_cfg.caps, AST_MEDIA_TYPE_UNKNOWN); p->allowtransfer = sip_cfg.allowtransfer; if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) || (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) { @@ -10034,15 +10076,17 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action int udptlportno = -1; /*!< UDPTL image destination port number */ /* Peer capability is the capability in the SDP, non codec is RFC2833 DTMF (101) */ - struct ast_format_cap *peercapability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - struct ast_format_cap *vpeercapability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - struct ast_format_cap *tpeercapability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + struct ast_format_cap *peercapability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + struct ast_format_cap *vpeercapability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + struct ast_format_cap *tpeercapability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); int peernoncodeccapability = 0, vpeernoncodeccapability = 0, tpeernoncodeccapability = 0; - struct ast_rtp_codecs newaudiortp = { 0, }, newvideortp = { 0, }, newtextrtp = { 0, }; - struct ast_format_cap *newjointcapability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); /* Negotiated capability */ - struct ast_format_cap *newpeercapability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + struct ast_rtp_codecs newaudiortp = AST_RTP_CODECS_NULL_INIT; + struct ast_rtp_codecs newvideortp = AST_RTP_CODECS_NULL_INIT; + struct ast_rtp_codecs newtextrtp = AST_RTP_CODECS_NULL_INIT; + struct ast_format_cap *newjointcapability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); /* Negotiated capability */ + struct ast_format_cap *newpeercapability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); int newnoncodeccapability; const char *codecs; @@ -10062,8 +10106,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action int debug = sip_debug_test_pvt(p); /* START UNKNOWN */ - char buf[SIPBUFSIZE]; - struct ast_format tmp_fmt; + struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_format *tmp_fmt; /* END UNKNOWN */ /* Initial check */ @@ -10625,10 +10669,12 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action /* Ensure crypto lines are provided where necessary */ if (audio && secure_audio && !processed_crypto) { ast_log(LOG_WARNING, "Rejecting secure audio stream without encryption details: %s\n", m); - return -1; + res = -1; + goto process_sdp_cleanup; } else if (video && secure_video && !processed_crypto) { ast_log(LOG_WARNING, "Rejecting secure video stream without encryption details: %s\n", m); - return -1; + res = -1; + goto process_sdp_cleanup; } } @@ -10687,12 +10733,12 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action ast_rtp_codecs_payload_formats(&newvideortp, vpeercapability, &vpeernoncodeccapability); ast_rtp_codecs_payload_formats(&newtextrtp, tpeercapability, &tpeernoncodeccapability); - ast_format_cap_append(newpeercapability, peercapability); - ast_format_cap_append(newpeercapability, vpeercapability); - ast_format_cap_append(newpeercapability, tpeercapability); + ast_format_cap_append_from_cap(newpeercapability, peercapability, AST_MEDIA_TYPE_AUDIO); + ast_format_cap_append_from_cap(newpeercapability, vpeercapability, AST_MEDIA_TYPE_VIDEO); + ast_format_cap_append_from_cap(newpeercapability, tpeercapability, AST_MEDIA_TYPE_TEXT); - ast_format_cap_joint_copy(p->caps, newpeercapability, newjointcapability); - if (ast_format_cap_is_empty(newjointcapability) && udptlportno == -1) { + ast_format_cap_get_compatible(p->caps, newpeercapability, newjointcapability); + if (!ast_format_cap_count(newjointcapability) && udptlportno == -1) { ast_log(LOG_NOTICE, "No compatible codecs, not accepting this offer!\n"); /* Do NOT Change current setting */ res = -1; @@ -10703,14 +10749,18 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action if (debug) { /* shame on whoever coded this.... */ - char s1[SIPBUFSIZE], s2[SIPBUFSIZE], s3[SIPBUFSIZE], s4[SIPBUFSIZE], s5[SIPBUFSIZE]; + struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *peer_buf = ast_str_alloca(64); + struct ast_str *vpeer_buf = ast_str_alloca(64); + struct ast_str *tpeer_buf = ast_str_alloca(64); + struct ast_str *joint_buf = ast_str_alloca(64); ast_verbose("Capabilities: us - %s, peer - audio=%s/video=%s/text=%s, combined - %s\n", - ast_getformatname_multiple(s1, SIPBUFSIZE, p->caps), - ast_getformatname_multiple(s2, SIPBUFSIZE, peercapability), - ast_getformatname_multiple(s3, SIPBUFSIZE, vpeercapability), - ast_getformatname_multiple(s4, SIPBUFSIZE, tpeercapability), - ast_getformatname_multiple(s5, SIPBUFSIZE, newjointcapability)); + ast_format_cap_get_names(p->caps, &cap_buf), + ast_format_cap_get_names(peercapability, &peer_buf), + ast_format_cap_get_names(vpeercapability, &vpeer_buf), + ast_format_cap_get_names(tpeercapability, &tpeer_buf), + ast_format_cap_get_names(newjointcapability, &joint_buf)); } if (debug) { struct ast_str *s1 = ast_str_alloca(SIPBUFSIZE); @@ -10726,14 +10776,21 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action if (portno != -1 || vportno != -1 || tportno != -1) { /* We are now ready to change the sip session and RTP structures with the offered codecs, since they are acceptable */ - ast_format_cap_copy(p->jointcaps, newjointcapability); /* Our joint codec profile for this call */ - ast_format_cap_copy(p->peercaps, newpeercapability); /* The other side's capability in latest offer */ + ast_format_cap_remove_by_type(p->jointcaps, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_from_cap(p->jointcaps, newjointcapability, AST_MEDIA_TYPE_UNKNOWN); /* Our joint codec profile for this call */ + ast_format_cap_remove_by_type(p->peercaps, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_from_cap(p->peercaps, newpeercapability, AST_MEDIA_TYPE_UNKNOWN); /* The other side's capability in latest offer */ p->jointnoncodeccapability = newnoncodeccapability; /* DTMF capabilities */ /* respond with single most preferred joint codec, limiting the other side's choice */ if (ast_test_flag(&p->flags[1], SIP_PAGE2_PREFERRED_CODEC)) { - ast_codec_choose(&p->prefs, p->jointcaps, 1, &tmp_fmt); - ast_format_cap_set(p->jointcaps, &tmp_fmt); + unsigned int framing; + + tmp_fmt = ast_format_cap_get_format(p->jointcaps, 0); + framing = ast_format_cap_get_format_framing(p->jointcaps, tmp_fmt); + ast_format_cap_remove_by_type(p->jointcaps, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append(p->jointcaps, tmp_fmt, framing); + ao2_ref(tmp_fmt, -1); } } @@ -10813,7 +10870,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action ast_verbose("Peer T.140 RTP is at port %s\n", ast_sockaddr_stringify(tsa)); } - if (ast_format_cap_iscompatible(p->jointcaps, ast_format_set(&tmp_fmt, AST_FORMAT_T140RED, 0))) { + if (ast_format_cap_iscompatible_format(p->jointcaps, ast_format_t140_red) != AST_FORMAT_CMP_NOT_EQUAL) { p->red = 1; ast_rtp_red_init(p->trtp, 300, red_data_pt, 2); } else { @@ -10890,7 +10947,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action } /* Ok, we're going with this offer */ - ast_debug(2, "We're settling with these formats: %s\n", ast_getformatname_multiple(buf, SIPBUFSIZE, p->jointcaps)); + ast_debug(2, "We're settling with these formats: %s\n", ast_format_cap_get_names(p->jointcaps, &codec_buf)); if (!p->owner) { /* There's no open channel owning us so we can return here. For a re-invite or so, we proceed */ res = 0; @@ -10898,19 +10955,30 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action } ast_debug(4, "We have an owner, now see if we need to change this call\n"); - if (ast_format_cap_has_type(p->jointcaps, AST_FORMAT_TYPE_AUDIO)) { + if (ast_format_cap_has_type(p->jointcaps, AST_MEDIA_TYPE_AUDIO)) { + struct ast_format_cap *caps; + unsigned int framing; + if (debug) { - char s1[SIPBUFSIZE], s2[SIPBUFSIZE]; + struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *joint_buf = ast_str_alloca(64); + ast_debug(1, "Setting native formats after processing SDP. peer joint formats %s, old nativeformats %s\n", - ast_getformatname_multiple(s1, SIPBUFSIZE, p->jointcaps), - ast_getformatname_multiple(s2, SIPBUFSIZE, ast_channel_nativeformats(p->owner))); + ast_format_cap_get_names(p->jointcaps, &joint_buf), + ast_format_cap_get_names(ast_channel_nativeformats(p->owner), &cap_buf)); } - ast_codec_choose(&p->prefs, p->jointcaps, 1, &tmp_fmt); - - ast_format_cap_set(ast_channel_nativeformats(p->owner), &tmp_fmt); - ast_format_cap_joint_append(p->caps, vpeercapability, ast_channel_nativeformats(p->owner)); - ast_format_cap_joint_append(p->caps, tpeercapability, ast_channel_nativeformats(p->owner)); + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (caps) { + tmp_fmt = ast_format_cap_get_format(p->jointcaps, 0); + framing = ast_format_cap_get_format_framing(p->jointcaps, tmp_fmt); + ast_format_cap_append(caps, tmp_fmt, framing); + ast_format_cap_append_from_cap(caps, vpeercapability, AST_MEDIA_TYPE_VIDEO); + ast_format_cap_append_from_cap(caps, tpeercapability, AST_MEDIA_TYPE_TEXT); + ast_channel_nativeformats_set(p->owner, caps); + ao2_ref(caps, -1); + ao2_ref(tmp_fmt, -1); + } ast_set_read_format(p->owner, ast_channel_readformat(p->owner)); ast_set_write_format(p->owner, ast_channel_writeformat(p->owner)); @@ -10942,11 +11010,11 @@ process_sdp_cleanup: ast_rtp_codecs_payloads_destroy(&newtextrtp); ast_rtp_codecs_payloads_destroy(&newvideortp); ast_rtp_codecs_payloads_destroy(&newaudiortp); - ast_format_cap_destroy(peercapability); - ast_format_cap_destroy(vpeercapability); - ast_format_cap_destroy(tpeercapability); - ast_format_cap_destroy(newjointcapability); - ast_format_cap_destroy(newpeercapability); + ao2_cleanup(peercapability); + ao2_cleanup(vpeercapability); + ao2_cleanup(tpeercapability); + ao2_cleanup(newjointcapability); + ao2_cleanup(newpeercapability); return res; } @@ -11203,17 +11271,10 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_ ast_debug(1, "Can't read framing from SDP: %s\n", a); } } + if (framing && p->autoframing) { - struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(p->rtp)->pref; - int codec_n; - for (codec_n = 0; codec_n < AST_RTP_MAX_PT; codec_n++) { - struct ast_rtp_payload_type format = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(p->rtp), codec_n); - if (!format.asterisk_format) /* non-codec or not found */ - continue; - ast_debug(1, "Setting framing for %s to %ld\n", ast_getformatname(&format.format), framing); - ast_codec_pref_setsize(pref, &format.format, framing); - } - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, pref); + ast_debug(1, "Setting framing to %ld\n", framing); + ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(p->rtp), framing); } found = TRUE; } else if (sscanf(a, "rtpmap: %30u %127[^/]/%30u", &codec, mimeSubtype, &sample_rate) == 3) { @@ -11240,15 +11301,19 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_ if ((format = ast_rtp_codecs_get_payload_format(newaudiortp, codec))) { unsigned int bit_rate; + struct ast_format *format_parsed; - if (!ast_format_sdp_parse(format, fmtp_string)) { + format_parsed = ast_format_parse_sdp_fmtp(format, fmtp_string); + if (format_parsed) { + ast_rtp_codecs_payload_replace_format(newaudiortp, codec, format_parsed); + ao2_replace(format, format_parsed); + ao2_ref(format_parsed, -1); found = TRUE; } else { ast_rtp_codecs_payloads_unset(newaudiortp, NULL, codec); } - switch ((int) format->id) { - case AST_FORMAT_SIREN7: + if (ast_format_cmp(format, ast_format_siren7) == AST_FORMAT_CMP_EQUAL) { if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) { if (bit_rate != 32000) { ast_log(LOG_WARNING, "Got Siren7 offer at %u bps, but only 32000 bps supported; ignoring.\n", bit_rate); @@ -11257,8 +11322,7 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_ found = TRUE; } } - break; - case AST_FORMAT_SIREN14: + } else if (ast_format_cmp(format, ast_format_siren14) == AST_FORMAT_CMP_EQUAL) { if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) { if (bit_rate != 48000) { ast_log(LOG_WARNING, "Got Siren14 offer at %u bps, but only 48000 bps supported; ignoring.\n", bit_rate); @@ -11267,8 +11331,7 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_ found = TRUE; } } - break; - case AST_FORMAT_G719: + } else if (ast_format_cmp(format, ast_format_g719) == AST_FORMAT_CMP_EQUAL) { if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) { if (bit_rate != 64000) { ast_log(LOG_WARNING, "Got G.719 offer at %u bps, but only 64000 bps supported; ignoring.\n", bit_rate); @@ -11277,8 +11340,8 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_ found = TRUE; } } - break; } + ao2_ref(format, -1); } } @@ -11320,11 +11383,19 @@ static int process_sdp_a_video(const char *a, struct sip_pvt *p, struct ast_rtp_ struct ast_format *format; if ((format = ast_rtp_codecs_get_payload_format(newvideortp, codec))) { - if (!ast_format_sdp_parse(format, fmtp_string)) { + struct ast_format *format_parsed; + + format_parsed = ast_format_parse_sdp_fmtp(format, fmtp_string); + + if (format_parsed) { + ast_rtp_codecs_payload_replace_format(newvideortp, codec, format_parsed); + ao2_replace(format, format_parsed); + ao2_ref(format_parsed, -1); found = TRUE; } else { ast_rtp_codecs_payloads_unset(newvideortp, NULL, codec); } + ao2_ref(format, -1); } } @@ -12890,12 +12961,11 @@ static void add_codec_to_sdp(const struct sip_pvt *p, int *max_packet_size) { int rtp_code; - struct ast_format_list fmt; const char *mime; - unsigned int rate; + unsigned int rate, framing; if (debug) - ast_verbose("Adding codec %u (%s) to SDP\n", format->id, ast_getformatname(format)); + ast_verbose("Adding codec %s to SDP\n", ast_format_get_name(format)); if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(p->rtp), 1, format, 0)) == -1) || !(mime = ast_rtp_lookup_mime_subtype2(1, format, 0, ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0)) || @@ -12903,63 +12973,54 @@ static void add_codec_to_sdp(const struct sip_pvt *p, return; } - if (p->rtp) { - struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(p->rtp)->pref; - fmt = ast_codec_pref_getsize(pref, format); - } else /* I don't see how you couldn't have p->rtp, but good to check for and error out if not there like earlier code */ - return; ast_str_append(m_buf, 0, " %d", rtp_code); /* Opus mandates 2 channels in rtpmap */ - if ((int)format->id == AST_FORMAT_OPUS) { + if (ast_format_cmp(format, ast_format_opus) == AST_FORMAT_CMP_EQUAL) { ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%u/2\r\n", rtp_code, mime, rate); } else { ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%u\r\n", rtp_code, mime, rate); } - ast_format_sdp_generate(format, rtp_code, a_buf); + ast_format_generate_sdp_fmtp(format, rtp_code, a_buf); + + framing = ast_format_cap_get_format_framing(p->caps, format); - switch ((int) format->id) { - case AST_FORMAT_G729A: + if (ast_format_cmp(format, ast_format_g729) == AST_FORMAT_CMP_EQUAL) { /* Indicate that we don't support VAD (G.729 annex B) */ ast_str_append(a_buf, 0, "a=fmtp:%d annexb=no\r\n", rtp_code); - break; - case AST_FORMAT_G723_1: + } else if (ast_format_cmp(format, ast_format_g723) == AST_FORMAT_CMP_EQUAL) { /* Indicate that we don't support VAD (G.723.1 annex A) */ ast_str_append(a_buf, 0, "a=fmtp:%d annexa=no\r\n", rtp_code); - break; - case AST_FORMAT_ILBC: + } else if (ast_format_cmp(format, ast_format_ilbc) == AST_FORMAT_CMP_EQUAL) { /* Add information about us using only 20/30 ms packetization */ - ast_str_append(a_buf, 0, "a=fmtp:%d mode=%d\r\n", rtp_code, fmt.cur_ms); - break; - case AST_FORMAT_SIREN7: + ast_str_append(a_buf, 0, "a=fmtp:%d mode=%u\r\n", rtp_code, framing); + } else if (ast_format_cmp(format, ast_format_siren7) == AST_FORMAT_CMP_EQUAL) { /* Indicate that we only expect 32Kbps */ ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=32000\r\n", rtp_code); - break; - case AST_FORMAT_SIREN14: + } else if (ast_format_cmp(format, ast_format_siren14) == AST_FORMAT_CMP_EQUAL) { /* Indicate that we only expect 48Kbps */ ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=48000\r\n", rtp_code); - break; - case AST_FORMAT_G719: + } else if (ast_format_cmp(format, ast_format_g719) == AST_FORMAT_CMP_EQUAL) { /* Indicate that we only expect 64Kbps */ ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=64000\r\n", rtp_code); - break; } - if (max_packet_size && fmt.max_ms && (fmt.max_ms < *max_packet_size)) { - *max_packet_size = fmt.max_ms; + if (max_packet_size && ast_format_get_maximum_ms(format) && + (ast_format_get_maximum_ms(format) < *max_packet_size)) { + *max_packet_size = ast_format_get_maximum_ms(format); } - if (fmt.cur_ms && (fmt.cur_ms < *min_packet_size)) { - *min_packet_size = fmt.cur_ms; + if (framing && (framing < *min_packet_size)) { + *min_packet_size = framing; } /* Our first codec packetization processed cannot be zero */ - if ((*min_packet_size) == 0 && fmt.cur_ms) { - *min_packet_size = fmt.cur_ms; + if ((*min_packet_size) == 0 && framing) { + *min_packet_size = framing; } - if ((*max_packet_size) == 0 && fmt.max_ms) { - *max_packet_size = fmt.max_ms; + if ((*max_packet_size) == 0 && ast_format_get_maximum_ms(format)) { + *max_packet_size = ast_format_get_maximum_ms(format); } } @@ -12977,7 +13038,7 @@ static void add_vcodec_to_sdp(const struct sip_pvt *p, struct ast_format *format return; if (debug) - ast_verbose("Adding video codec %u (%s) to SDP\n", format->id, ast_getformatname(format)); + ast_verbose("Adding video codec %s to SDP\n", ast_format_get_name(format)); if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(p->vrtp), 1, format, 0)) == -1) || !(subtype = ast_rtp_lookup_mime_subtype2(1, format, 0, 0)) || @@ -12988,11 +13049,11 @@ static void add_vcodec_to_sdp(const struct sip_pvt *p, struct ast_format *format ast_str_append(m_buf, 0, " %d", rtp_code); ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%u\r\n", rtp_code, subtype, rate); /* VP8: add RTCP FIR support */ - if ((int)format->id == AST_FORMAT_VP8) { + if (ast_format_cmp(format, ast_format_vp8) == AST_FORMAT_CMP_EQUAL) { ast_str_append(a_buf, 0, "a=rtcp-fb:* ccm fir\r\n"); } - ast_format_sdp_generate(format, rtp_code, a_buf); + ast_format_generate_sdp_fmtp(format, rtp_code, a_buf); } /*! \brief Add text codec offer to SDP offer/answer body in INVITE or 200 OK */ @@ -13006,7 +13067,7 @@ static void add_tcodec_to_sdp(const struct sip_pvt *p, struct ast_format *format return; if (debug) - ast_verbose("Adding text codec %u (%s) to SDP\n", format->id, ast_getformatname(format)); + ast_verbose("Adding text codec %s to SDP\n", ast_format_get_name(format)); if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(p->trtp), 1, format, 0)) == -1) return; @@ -13017,9 +13078,8 @@ static void add_tcodec_to_sdp(const struct sip_pvt *p, struct ast_format *format ast_rtp_lookup_sample_rate2(1, format, 0)); /* Add fmtp code here */ - if (format->id == AST_FORMAT_T140RED) { - struct ast_format tmp_fmt; - int t140code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(p->trtp), 1, ast_format_set(&tmp_fmt, AST_FORMAT_T140, 0), 0); + if (ast_format_cmp(format, ast_format_t140_red) == AST_FORMAT_CMP_EQUAL) { + int t140code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(p->trtp), 1, ast_format_t140, 0); ast_str_append(a_buf, 0, "a=fmtp:%d %d/%d/%d\r\n", rtp_code, t140code, t140code, @@ -13194,8 +13254,8 @@ static char *crypto_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int */ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp, int add_audio, int add_t38) { - struct ast_format_cap *alreadysent = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - struct ast_format_cap *tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + struct ast_format_cap *alreadysent = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + struct ast_format_cap *tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); int res = AST_SUCCESS; int doing_directmedia = FALSE; struct ast_sockaddr addr = { {0,} }; @@ -13229,7 +13289,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int RAII_VAR(char *, t_a_crypto, NULL, ast_free); int x; - struct ast_format tmp_fmt; + struct ast_format *tmp_fmt; int needaudio = FALSE; int needvideo = FALSE; int needtext = FALSE; @@ -13239,8 +13299,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int int min_video_packet_size = 0; int min_text_packet_size = 0; - char codecbuf[SIPBUFSIZE]; - char buf[SIPBUFSIZE]; + struct ast_str *codec_buf = ast_str_alloca(64); /* Set the SDP session name */ snprintf(subject, sizeof(subject), "s=%s\r\n", ast_strlen_zero(global_sdpsession) ? "-" : global_sdpsession); @@ -13268,11 +13327,24 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int } if (add_audio) { - doing_directmedia = (!ast_sockaddr_isnull(&p->redirip) && !(ast_format_cap_is_empty(p->redircaps))) ? TRUE : FALSE; + doing_directmedia = (!ast_sockaddr_isnull(&p->redirip) && (ast_format_cap_count(p->redircaps))) ? TRUE : FALSE; + + if (doing_directmedia) { + ast_format_cap_get_compatible(p->jointcaps, p->redircaps, tmpcap); + ast_debug(1, "** Our native-bridge filtered capablity: %s\n", ast_format_cap_get_names(tmpcap, &codec_buf)); + } else { + ast_format_cap_append_from_cap(tmpcap, p->jointcaps, AST_MEDIA_TYPE_UNKNOWN); + } + + /* Check if we need audio */ + if (ast_format_cap_has_type(tmpcap, AST_MEDIA_TYPE_AUDIO) + || ast_format_cap_has_type(p->caps, AST_MEDIA_TYPE_AUDIO)) { + needaudio = TRUE; + } + /* Check if we need video in this call */ - if ((ast_format_cap_has_type(p->jointcaps, AST_FORMAT_TYPE_VIDEO)) && !p->novideo) { - ast_format_cap_joint_copy(p->jointcaps, p->redircaps, tmpcap); - if (doing_directmedia && !ast_format_cap_has_type(tmpcap, AST_FORMAT_TYPE_VIDEO)) { + if ((ast_format_cap_has_type(tmpcap, AST_MEDIA_TYPE_VIDEO)) && !p->novideo) { + if (doing_directmedia && !ast_format_cap_has_type(tmpcap, AST_MEDIA_TYPE_VIDEO)) { ast_debug(2, "This call needs video offers, but caller probably did not offer it!\n"); } else if (p->vrtp) { needvideo = TRUE; @@ -13281,8 +13353,9 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int ast_debug(2, "This call needs video offers, but there's no video support enabled!\n"); } } + /* Check if we need text in this call */ - if ((ast_format_cap_has_type(p->jointcaps, AST_FORMAT_TYPE_TEXT)) && !p->notext) { + if ((ast_format_cap_has_type(p->jointcaps, AST_MEDIA_TYPE_TEXT)) && !p->notext) { if (sipdebug_text) ast_verbose("We think we can do text\n"); if (p->trtp) { @@ -13295,6 +13368,12 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int ast_debug(2, "This call needs text offers, but there's no text support enabled ! \n"); } } + + /* XXX note, Video and Text are negated - 'true' means 'no' */ + ast_debug(1, "** Our capability: %s Video flag: %s Text flag: %s\n", + ast_format_cap_get_names(tmpcap, &codec_buf), + p->novideo ? "True" : "False", p->notext ? "True" : "False"); + ast_debug(1, "** Our prefcodec: %s \n", ast_format_cap_get_names(p->prefcaps, &codec_buf)); } get_our_media_address(p, needvideo, needtext, &addr, &vaddr, &taddr, &dest, &vdest, &tdest); @@ -13322,22 +13401,6 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int hold = "a=sendrecv\r\n"; } - ast_format_cap_copy(tmpcap, p->jointcaps); - - /* XXX note, Video and Text are negated - 'true' means 'no' */ - ast_debug(1, "** Our capability: %s Video flag: %s Text flag: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), tmpcap), - p->novideo ? "True" : "False", p->notext ? "True" : "False"); - ast_debug(1, "** Our prefcodec: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), p->prefcaps)); - - if (doing_directmedia) { - ast_format_cap_joint_copy(p->jointcaps, p->redircaps, tmpcap); - ast_debug(1, "** Our native-bridge filtered capablity: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), tmpcap)); - } - - /* Check if we need audio */ - if (ast_format_cap_has_type(tmpcap, AST_FORMAT_TYPE_AUDIO)) - needaudio = TRUE; - if (debug) { ast_verbose("Audio is at %s\n", ast_sockaddr_stringify_port(&addr)); } @@ -13406,8 +13469,8 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int /* Now, start adding audio codecs. These are added in this order: - First what was requested by the calling channel + - Then our mutually shared capabilities, determined previous in tmpcap - Then preferences in order from sip.conf device config for this peer/user - - Then other codecs in capabilities, including video */ @@ -13415,57 +13478,62 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int * configured codecs. */ if (!ast_test_flag(&p->flags[2], SIP_PAGE3_IGNORE_PREFCAPS)) { - ast_format_cap_iter_start(p->prefcaps); - while (!(ast_format_cap_iter_next(p->prefcaps, &tmp_fmt))) { - if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_AUDIO || - !ast_format_cap_iscompatible(tmpcap, &tmp_fmt)) { + for (x = 0; x < ast_format_cap_count(p->prefcaps); x++) { + tmp_fmt = ast_format_cap_get_format(p->prefcaps, x); + + if ((ast_format_get_type(tmp_fmt) != AST_MEDIA_TYPE_AUDIO) || + (ast_format_cap_iscompatible_format(tmpcap, tmp_fmt) == AST_FORMAT_CMP_NOT_EQUAL)) { + ao2_ref(tmp_fmt, -1); continue; } - add_codec_to_sdp(p, &tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size, &max_audio_packet_size); - ast_format_cap_add(alreadysent, &tmp_fmt); + + add_codec_to_sdp(p, tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size, &max_audio_packet_size); + ast_format_cap_append(alreadysent, tmp_fmt, 0); + ao2_ref(tmp_fmt, -1); } - ast_format_cap_iter_end(p->prefcaps); } - /* Start by sending our preferred audio/video codecs */ - for (x = 0; x < AST_CODEC_PREF_SIZE; x++) { - struct ast_format pref; - - if (!(ast_codec_pref_index(&p->prefs, x, &pref))) - break; - - if (!ast_format_cap_get_compatible_format(tmpcap, &pref, &tmp_fmt)) - continue; + /* Now send any other common codecs */ + for (x = 0; x < ast_format_cap_count(tmpcap); x++) { + tmp_fmt = ast_format_cap_get_format(tmpcap, x); - if (ast_format_cap_iscompatible(alreadysent, &tmp_fmt)) + if (ast_format_cap_iscompatible_format(alreadysent, tmp_fmt) != AST_FORMAT_CMP_NOT_EQUAL) { + ao2_ref(tmp_fmt, -1); continue; + } - if (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_AUDIO) { - add_codec_to_sdp(p, &tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size, &max_audio_packet_size); - } else if (needvideo && (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_VIDEO)) { - add_vcodec_to_sdp(p, &tmp_fmt, &m_video, &a_video, debug, &min_video_packet_size); - } else if (needtext && (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_TEXT)) { - add_tcodec_to_sdp(p, &tmp_fmt, &m_text, &a_text, debug, &min_text_packet_size); + if (ast_format_get_type(tmp_fmt) == AST_MEDIA_TYPE_AUDIO) { + add_codec_to_sdp(p, tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size, &max_audio_packet_size); + } else if (needvideo && ast_format_get_type(tmp_fmt) == AST_MEDIA_TYPE_VIDEO) { + add_vcodec_to_sdp(p, tmp_fmt, &m_video, &a_video, debug, &min_video_packet_size); + } else if (needtext && ast_format_get_type(tmp_fmt) == AST_MEDIA_TYPE_TEXT) { + add_tcodec_to_sdp(p, tmp_fmt, &m_text, &a_text, debug, &min_text_packet_size); } - ast_format_cap_add(alreadysent, &tmp_fmt); + ast_format_cap_append(alreadysent, tmp_fmt, 0); + ao2_ref(tmp_fmt, -1); } - /* Now send any other common audio and video codecs, and non-codec formats: */ - ast_format_cap_iter_start(tmpcap); - while (!(ast_format_cap_iter_next(tmpcap, &tmp_fmt))) { - if (ast_format_cap_iscompatible(alreadysent, &tmp_fmt)) + /* Finally our remaining audio/video codecs */ + for (x = 0; x < ast_format_cap_count(p->caps); x++) { + tmp_fmt = ast_format_cap_get_format(p->caps, x); + + if (ast_format_cap_iscompatible_format(alreadysent, tmp_fmt) != AST_FORMAT_CMP_NOT_EQUAL) { + ao2_ref(tmp_fmt, -1); continue; + } - if (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_AUDIO) { - add_codec_to_sdp(p, &tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size, &max_audio_packet_size); - } else if (needvideo && (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_VIDEO)) { - add_vcodec_to_sdp(p, &tmp_fmt, &m_video, &a_video, debug, &min_video_packet_size); - } else if (needtext && (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_TEXT)) { - add_tcodec_to_sdp(p, &tmp_fmt, &m_text, &a_text, debug, &min_text_packet_size); + if (ast_format_get_type(tmp_fmt) == AST_MEDIA_TYPE_AUDIO) { + add_codec_to_sdp(p, tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size, &max_audio_packet_size); + } else if (needvideo && ast_format_get_type(tmp_fmt) == AST_MEDIA_TYPE_VIDEO) { + add_vcodec_to_sdp(p, tmp_fmt, &m_video, &a_video, debug, &min_video_packet_size); + } else if (needtext && ast_format_get_type(tmp_fmt) == AST_MEDIA_TYPE_TEXT) { + add_tcodec_to_sdp(p, tmp_fmt, &m_text, &a_text, debug, &min_text_packet_size); } + + ast_format_cap_append(alreadysent, tmp_fmt, 0); + ao2_ref(tmp_fmt, -1); } - ast_format_cap_iter_end(tmpcap); /* Now add DTMF RFC2833 telephony-event as a codec */ for (x = 1LL; x <= AST_RTP_MAX; x <<= 1) { @@ -13677,14 +13745,15 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int ao2_t_link(dialogs_rtpcheck, p, "link pvt into dialogs_rtpcheck container"); ao2_unlock(dialogs_rtpcheck); - ast_debug(3, "Done building SDP. Settling with this capability: %s\n", ast_getformatname_multiple(buf, SIPBUFSIZE, tmpcap)); + ast_debug(3, "Done building SDP. Settling with this capability: %s\n", + ast_format_cap_get_names(tmpcap, &codec_buf)); add_sdp_cleanup: ast_free(a_text); ast_free(a_video); ast_free(a_audio); - alreadysent = ast_format_cap_destroy(alreadysent); - tmpcap = ast_format_cap_destroy(tmpcap); + ao2_cleanup(alreadysent); + ao2_cleanup(tmpcap); return res; } @@ -13792,7 +13861,7 @@ static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const if (p->rtp) { if (!p->autoframing && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) { ast_debug(1, "Setting framing from config on incoming call\n"); - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &p->prefs); + ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(p->rtp), ast_format_cap_get_framing(p->caps)); } ast_rtp_instance_activate(p->rtp); try_suggested_sip_codec(p); @@ -18475,10 +18544,9 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, peer->name, of, ast_sockaddr_stringify(&p->recv)); } - /* XXX what about p->prefs = peer->prefs; ? */ /* Set Frame packetization */ if (p->rtp) { - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &peer->prefs); + ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(p->rtp), ast_format_cap_get_framing(peer->caps)); p->autoframing = peer->autoframing; } @@ -18595,20 +18663,22 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, p->named_callgroups = ast_ref_namedgroups(peer->named_callgroups); ast_unref_namedgroups(p->named_pickupgroups); p->named_pickupgroups = ast_ref_namedgroups(peer->named_pickupgroups); - ast_format_cap_copy(p->caps, peer->caps); - ast_format_cap_copy(p->jointcaps, peer->caps); - p->prefs = peer->prefs; + ast_format_cap_remove_by_type(p->caps, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_from_cap(p->caps, peer->caps, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_remove_by_type(p->jointcaps, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_from_cap(p->jointcaps, peer->caps, AST_MEDIA_TYPE_UNKNOWN); ast_copy_string(p->zone, peer->zone, sizeof(p->zone)); if (peer->maxforwards > 0) { p->maxforwards = peer->maxforwards; } - if (!(ast_format_cap_is_empty(p->peercaps))) { - struct ast_format_cap *tmp = ast_format_cap_joint(p->jointcaps, p->peercaps); - struct ast_format_cap *tmp2; - if (tmp) { - tmp2 = p->jointcaps; - p->jointcaps = tmp; - ast_format_cap_destroy(tmp2); + if (ast_format_cap_count(p->peercaps)) { + struct ast_format_cap *joint; + + joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (joint) { + ast_format_cap_get_compatible(p->jointcaps, p->peercaps, joint); + ao2_ref(p->jointcaps, -1); + p->jointcaps = joint; } } p->maxcallbitrate = peer->maxcallbitrate; @@ -18623,7 +18693,7 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, p->rtpkeepalive = peer->rtpkeepalive; if (!dialog_initialize_rtp(p)) { if (p->rtp) { - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &peer->prefs); + ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(p->rtp), ast_format_cap_get_framing(peer->caps)); p->autoframing = peer->autoframing; } } else { @@ -19959,25 +20029,6 @@ static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli return CLI_SUCCESS; } -/*! \brief Print codec list from preference to CLI/manager */ -static void print_codec_to_cli(int fd, struct ast_codec_pref *pref) -{ - int x; - struct ast_format codec; - - for(x = 0; x < AST_CODEC_PREF_SIZE; x++) { - if (!(ast_codec_pref_index(pref, x, &codec))) { - break; - } - ast_cli(fd, "%s", ast_getformatname(&codec)); - ast_cli(fd, ":%d", pref->framing[x]); - if (x < 31 && ast_codec_pref_index(pref, x + 1, &codec)) - ast_cli(fd, ","); - } - if (!x) - ast_cli(fd, "none"); -} - /*! \brief Print domain mode to cli */ static const char *domain_mode_to_text(const enum domain_mode mode) { @@ -20262,11 +20313,9 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct char status[30] = ""; char cbuf[256]; struct sip_peer *peer; - char codec_buf[512]; - struct ast_codec_pref *pref; + struct ast_str *codec_buf = ast_str_alloca(64); struct ast_variable *v; int x = 0, load_realtime; - struct ast_format codec; int realtimepeers; realtimepeers = ast_check_realtime("sippeers"); @@ -20415,12 +20464,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct ast_cli(fd, "(none)"); ast_cli(fd, "\n"); - ast_cli(fd, " Codecs : "); - ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->caps); - ast_cli(fd, "%s\n", codec_buf); - ast_cli(fd, " Codec Order : ("); - print_codec_to_cli(fd, &peer->prefs); - ast_cli(fd, ")\n"); + ast_cli(fd, " Codecs : %s\n", ast_format_cap_get_names(peer->caps, &codec_buf)); ast_cli(fd, " Auto-Framing : %s\n", AST_CLI_YESNO(peer->autoframing)); ast_cli(fd, " Status : "); @@ -20523,21 +20567,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct astman_append(s, "Default-Username: %s\r\n", peer->username); if (!ast_strlen_zero(sip_cfg.regcontext)) astman_append(s, "RegExtension: %s\r\n", peer->regexten); - astman_append(s, "Codecs: "); - ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->caps); - astman_append(s, "%s\r\n", codec_buf); - astman_append(s, "CodecOrder: "); - pref = &peer->prefs; - for(x = 0; x < AST_CODEC_PREF_SIZE ; x++) { - if (!(ast_codec_pref_index(pref, x, &codec))) { - break; - } - astman_append(s, "%s", ast_getformatname(&codec)); - if ((x < (AST_CODEC_PREF_SIZE - 1)) && ast_codec_pref_index(pref, x+1, &codec)) - astman_append(s, ","); - } - - astman_append(s, "\r\n"); + astman_append(s, "Codecs: %s\r\n", ast_format_cap_get_names(peer->caps, &codec_buf)); astman_append(s, "Status: "); peer_status(peer, status, sizeof(status)); astman_append(s, "%s\r\n", status); @@ -20660,10 +20690,6 @@ static char *sip_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args ast_cli(a->fd, " Sess-Min-SE : %d secs\n", user->stimer.st_min_se); ast_cli(a->fd, " RTP Engine : %s\n", user->engine); - ast_cli(a->fd, " Codec Order : ("); - print_codec_to_cli(a->fd, &user->prefs); - ast_cli(a->fd, ")\n"); - ast_cli(a->fd, " Auto-Framing: %s \n", AST_CLI_YESNO(user->autoframing)); if (user->chanvars) { ast_cli(a->fd, " Variables :\n"); @@ -20916,7 +20942,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ { int realtimepeers; int realtimeregs; - char codec_buf[SIPBUFSIZE]; + struct ast_str *codec_buf = ast_str_alloca(64); const char *msg; /* temporary msg pointer */ struct sip_auth_container *credentials; @@ -21069,12 +21095,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ } ast_cli(a->fd, "\nGlobal Signalling Settings:\n"); ast_cli(a->fd, "---------------------------\n"); - ast_cli(a->fd, " Codecs: "); - ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, sip_cfg.caps); - ast_cli(a->fd, "%s\n", codec_buf); - ast_cli(a->fd, " Codec Order: "); - print_codec_to_cli(a->fd, &default_prefs); - ast_cli(a->fd, "\n"); + ast_cli(a->fd, " Codecs: %s\n", ast_format_cap_get_names(sip_cfg.caps, &codec_buf)); ast_cli(a->fd, " Relax DTMF: %s\n", AST_CLI_YESNO(global_relaxdtmf)); ast_cli(a->fd, " RFC2833 Compensation: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_RFC2833_COMPENSATE))); ast_cli(a->fd, " Symmetric RTP: %s\n", comedia_string(global_flags)); @@ -21233,12 +21254,12 @@ static int show_channels_cb(void *__cur, void *__arg, int flags) if (cur->subscribed == NONE && !arg->subscriptions) { /* set if SIP transfer in progress */ const char *referstatus = cur->refer ? referstatus2str(cur->refer->status) : ""; - char formatbuf[SIPBUFSIZE/2]; + struct ast_str *codec_buf = ast_str_alloca(64); ast_cli(arg->fd, FORMAT, ast_sockaddr_stringify_addr(dst), S_OR(cur->username, S_OR(cur->cid_num, "(None)")), cur->callid, - cur->owner ? ast_getformatname_multiple(formatbuf, sizeof(formatbuf), ast_channel_nativeformats(cur->owner)) : "(nothing)", + cur->owner ? ast_format_cap_get_names(ast_channel_nativeformats(cur->owner), &codec_buf) : "(nothing)", AST_CLI_YESNO(ast_test_flag(&cur->flags[1], SIP_PAGE2_CALL_ONHOLD)), cur->needdestroy ? "(d)" : "", cur->lastmsg , @@ -21479,7 +21500,8 @@ static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_a if (!strncasecmp(cur->callid, a->argv[3], len)) { struct ast_str *strbuf; - char formatbuf[SIPBUFSIZE/2]; + struct ast_str *codec_buf = ast_str_alloca(64); + ast_cli(a->fd, "\n"); if (cur->subscribed != NONE) { ast_cli(a->fd, " * Subscription (type: %s)\n", subscription_type2str(cur->subscribed)); @@ -21489,11 +21511,11 @@ static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_a ast_cli(a->fd, " Curr. trans. direction: %s\n", ast_test_flag(&cur->flags[0], SIP_OUTGOING) ? "Outgoing" : "Incoming"); ast_cli(a->fd, " Call-ID: %s\n", cur->callid); ast_cli(a->fd, " Owner channel ID: %s\n", cur->owner ? ast_channel_name(cur->owner) : "<none>"); - ast_cli(a->fd, " Our Codec Capability: %s\n", ast_getformatname_multiple(formatbuf, sizeof(formatbuf), cur->caps)); + ast_cli(a->fd, " Our Codec Capability: %s\n", ast_format_cap_get_names(cur->caps, &codec_buf)); ast_cli(a->fd, " Non-Codec Capability (DTMF): %d\n", cur->noncodeccapability); - ast_cli(a->fd, " Their Codec Capability: %s\n", ast_getformatname_multiple(formatbuf, sizeof(formatbuf), cur->peercaps)); - ast_cli(a->fd, " Joint Codec Capability: %s\n", ast_getformatname_multiple(formatbuf, sizeof(formatbuf), cur->jointcaps)); - ast_cli(a->fd, " Format: %s\n", cur->owner ? ast_getformatname_multiple(formatbuf, sizeof(formatbuf), ast_channel_nativeformats(cur->owner)) : "(nothing)" ); + ast_cli(a->fd, " Their Codec Capability: %s\n", ast_format_cap_get_names(cur->peercaps, &codec_buf)); + ast_cli(a->fd, " Joint Codec Capability: %s\n", ast_format_cap_get_names(cur->jointcaps, &codec_buf)); + ast_cli(a->fd, " Format: %s\n", cur->owner ? ast_format_cap_get_names(ast_channel_nativeformats(cur->owner), &codec_buf) : "(nothing)" ); ast_cli(a->fd, " T.38 support %s\n", AST_CLI_YESNO(cur->udptl != NULL)); ast_cli(a->fd, " Video support %s\n", AST_CLI_YESNO(cur->vrtp != NULL)); ast_cli(a->fd, " MaxCallBR: %d kbps\n", cur->maxcallbitrate); @@ -22437,7 +22459,9 @@ static int function_sippeer(struct ast_channel *chan, const char *cmd, char *dat } else if (!strcasecmp(colname, "callerid_num")) { ast_copy_string(buf, peer->cid_num, len); } else if (!strcasecmp(colname, "codecs")) { - ast_getformatname_multiple(buf, len -1, peer->caps); + struct ast_str *codec_buf = ast_str_alloca(64); + ast_format_cap_get_names(peer->caps, &codec_buf); + ast_copy_string(buf, ast_str_buffer(codec_buf), len); } else if (!strcasecmp(colname, "encryption")) { snprintf(buf, len, "%u", ast_test_flag(&peer->flags[1], SIP_PAGE2_USE_SRTP)); } else if (!strncasecmp(colname, "chanvar[", 8)) { @@ -22452,12 +22476,14 @@ static int function_sippeer(struct ast_channel *chan, const char *cmd, char *dat } } else if (!strncasecmp(colname, "codec[", 6)) { char *codecnum; - struct ast_format codec; + struct ast_format *codec; codecnum = colname + 6; /* move past the '[' */ codecnum = strsep(&codecnum, "]"); /* trim trailing ']' if any */ - if((ast_codec_pref_index(&peer->prefs, atoi(codecnum), &codec))) { - ast_copy_string(buf, ast_getformatname(&codec), len); + codec = ast_format_cap_get_format(peer->caps, atoi(codecnum)); + if (codec) { + ast_copy_string(buf, ast_format_get_name(codec), len); + ao2_ref(codec, -1); } else { buf[0] = '\0'; } @@ -25476,7 +25502,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str } ast_queue_control(p->owner, AST_CONTROL_SRCUPDATE); } else { - ast_format_cap_copy(p->jointcaps, p->caps); + ast_format_cap_remove_by_type(p->jointcaps, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_from_cap(p->jointcaps, p->caps, AST_MEDIA_TYPE_UNKNOWN); ast_debug(1, "Hm.... No sdp for the moment\n"); /* Some devices signal they want to be put off hold by sending a re-invite *without* an SDP, which is supposed to mean "Go back to your state" @@ -25541,7 +25568,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str goto request_invite_cleanup; } } else { /* No SDP in invite, call control session */ - ast_format_cap_copy(p->jointcaps, p->caps); + ast_format_cap_remove_by_type(p->jointcaps, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_from_cap(p->jointcaps, p->caps, AST_MEDIA_TYPE_UNKNOWN); ast_debug(2, "No SDP in Invite, third party call control\n"); } @@ -25855,7 +25883,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str if (p && (p->autokillid == -1)) { const char *msg; - if ((ast_format_cap_is_empty(p->jointcaps))) + if ((!ast_format_cap_count(p->jointcaps))) msg = "488 Not Acceptable Here (codec error)"; else { ast_log(LOG_NOTICE, "Unable to create/find SIP channel for this INVITE\n"); @@ -29539,7 +29567,8 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_ struct ast_channel *tmpc = NULL; char *ext = NULL, *host; char tmp[256]; - char tmp2[256]; + struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(64); char *dnid; char *secret = NULL; char *md5secret = NULL; @@ -29562,14 +29591,14 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_ * configured from sip.conf, and sip_tech.capabilities, which is * hardwired to all audio formats. */ - if (!(ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO))) { + if (!(ast_format_cap_has_type(cap, AST_MEDIA_TYPE_AUDIO))) { ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format %s while capability is %s\n", - ast_getformatname_multiple(tmp, sizeof(tmp), cap), - ast_getformatname_multiple(tmp2, sizeof(tmp2), sip_cfg.caps)); + ast_format_cap_get_names(cap, &codec_buf), + ast_format_cap_get_names(sip_cfg.caps, &cap_buf)); *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL; /* Can't find codec to connect to host */ return NULL; } - ast_debug(1, "Asked to create a SIP channel with formats: %s\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap)); + ast_debug(1, "Asked to create a SIP channel with formats: %s\n", ast_format_cap_get_names(cap, &codec_buf)); if (ast_strlen_zero(dest)) { ast_log(LOG_ERROR, "Unable to create channel with empty destination.\n"); @@ -29739,8 +29768,8 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_ #if 0 printf("Setting up to call extension '%s' at '%s'\n", ext ? ext : "<none>", host); #endif - ast_format_cap_append(p->prefcaps, cap); - ast_format_cap_joint_copy(cap, p->caps, p->jointcaps); + ast_format_cap_append_from_cap(p->prefcaps, cap, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_get_compatible(cap, p->caps, p->jointcaps); sip_pvt_lock(p); @@ -30217,7 +30246,7 @@ static void set_peer_defaults(struct sip_peer *peer) ast_string_field_set(peer, engine, default_engine); ast_sockaddr_setnull(&peer->addr); ast_sockaddr_setnull(&peer->defaddr); - ast_format_cap_copy(peer->caps, sip_cfg.caps); + ast_format_cap_append_from_cap(peer->caps, sip_cfg.caps, AST_MEDIA_TYPE_UNKNOWN); peer->maxcallbitrate = default_maxcallbitrate; peer->rtptimeout = global_rtptimeout; peer->rtpholdtimeout = global_rtpholdtimeout; @@ -30243,7 +30272,6 @@ static void set_peer_defaults(struct sip_peer *peer) peer->pickupgroup = 0; peer->maxms = default_qualify; peer->keepalive = default_keepalive; - peer->prefs = default_prefs; ast_string_field_set(peer, zone, default_zone); peer->stimer.st_mode_oper = global_st_mode; /* Session-Timers */ peer->stimer.st_ref = global_st_refresher; @@ -30279,7 +30307,7 @@ static struct sip_peer *temp_peer(const char *name) return NULL; } - if (!(peer->caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) { + if (!(peer->caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { ao2_t_ref(peer, -1, "failed to allocate format capabilities, drop peer"); return NULL; } @@ -30291,7 +30319,6 @@ static struct sip_peer *temp_peer(const char *name) peer->selfdestruct = TRUE; peer->host_dynamic = TRUE; - peer->prefs = default_prefs; reg_source_db(peer); return peer; @@ -30384,7 +30411,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str if (!(peer->endpoint = ast_endpoint_create("SIP", name))) { return NULL; } - if (!(peer->caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) { + if (!(peer->caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { ao2_t_ref(peer, -1, "failed to allocate format capabilities, drop peer"); return NULL; } @@ -30705,12 +30732,12 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str } else if (!strcasecmp(v->name, "namedpickupgroup")) { peer->named_pickupgroups = ast_get_namedgroups(v->value); } else if (!strcasecmp(v->name, "allow")) { - int error = ast_parse_allow_disallow(&peer->prefs, peer->caps, v->value, TRUE); + int error = ast_format_cap_update_by_allow_disallow(peer->caps, v->value, TRUE); if (error) { ast_log(LOG_WARNING, "Codec configuration errors found in line %d : %s = %s\n", v->lineno, v->name, v->value); } } else if (!strcasecmp(v->name, "disallow")) { - int error = ast_parse_allow_disallow(&peer->prefs, peer->caps, v->value, FALSE); + int error = ast_format_cap_update_by_allow_disallow(peer->caps, v->value, FALSE); if (error) { ast_log(LOG_WARNING, "Codec configuration errors found in line %d : %s = %s\n", v->lineno, v->name, v->value); } @@ -31104,14 +31131,11 @@ static int peer_markall_autopeers_func(void *device, void *arg, int flags) */ static void sip_set_default_format_capabilities(struct ast_format_cap *cap) { - struct ast_format tmp_fmt; - - ast_format_cap_remove_all(cap); - ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_ULAW, 0)); - ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_TESTLAW, 0)); - ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_ALAW, 0)); - ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_GSM, 0)); - ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_H263, 0)); + ast_format_cap_remove_by_type(cap, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append(cap, ast_format_ulaw, 0); + ast_format_cap_append(cap, ast_format_alaw, 0); + ast_format_cap_append(cap, ast_format_gsm, 0); + ast_format_cap_append(cap, ast_format_h263, 0); } static void display_nat_warning(const char *cat, int reason, struct ast_flags *flags) { @@ -31276,7 +31300,6 @@ static int reload_config(enum channelreloadreason reason) memset(&localaddr, 0, sizeof(localaddr)); memset(&externaddr, 0, sizeof(externaddr)); memset(&media_address, 0, sizeof(media_address)); - memset(&default_prefs, 0 , sizeof(default_prefs)); memset(&sip_cfg.outboundproxy, 0, sizeof(struct sip_proxy)); sip_cfg.outboundproxy.force = FALSE; /*!< Don't force proxy usage, use route: headers */ default_transports = AST_TRANSPORT_UDP; @@ -31768,12 +31791,12 @@ static int reload_config(enum channelreloadreason reason) ast_log(LOG_WARNING, "Invalid externtlsport value, must be a positive integer between 1 and 65535 at line %d\n", v->lineno); } } else if (!strcasecmp(v->name, "allow")) { - int error = ast_parse_allow_disallow(&default_prefs, sip_cfg.caps, v->value, TRUE); + int error = ast_format_cap_update_by_allow_disallow(sip_cfg.caps, v->value, TRUE); if (error) { ast_log(LOG_WARNING, "Codec configuration errors found in line %d : %s = %s\n", v->lineno, v->name, v->value); } } else if (!strcasecmp(v->name, "disallow")) { - int error = ast_parse_allow_disallow(&default_prefs, sip_cfg.caps, v->value, FALSE); + int error = ast_format_cap_update_by_allow_disallow(sip_cfg.caps, v->value, FALSE); if (error) { ast_log(LOG_WARNING, "Codec configuration errors found in line %d : %s = %s\n", v->lineno, v->name, v->value); } @@ -32565,8 +32588,9 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i memset(&p->tredirip, 0, sizeof(p->tredirip)); changed = 1; } - if (cap && !ast_format_cap_is_empty(cap) && !ast_format_cap_identical(p->redircaps, cap)) { - ast_format_cap_copy(p->redircaps, cap); + if (cap && ast_format_cap_count(cap) && !ast_format_cap_identical(cap, p->redircaps)) { + ast_format_cap_remove_by_type(p->redircaps, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_from_cap(p->redircaps, cap, AST_MEDIA_TYPE_UNKNOWN); changed = 1; } @@ -32603,7 +32627,8 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i static void sip_get_codec(struct ast_channel *chan, struct ast_format_cap *result) { struct sip_pvt *p = ast_channel_tech_pvt(chan); - ast_format_cap_append(result, ast_format_cap_is_empty(p->peercaps) ? p->caps : p->peercaps); + + ast_format_cap_append_from_cap(result, !ast_format_cap_count(p->peercaps) ? p->caps : p->peercaps, AST_MEDIA_TYPE_UNKNOWN); } static struct ast_rtp_glue sip_rtp_glue = { @@ -34217,6 +34242,8 @@ static const struct ast_sip_api_tech chan_sip_api_provider = { .sipinfo_send = sipinfo_send, }; +static int unload_module(void); + /*! * \brief Load the module * @@ -34232,14 +34259,17 @@ static int load_module(void) ast_verbose("SIP channel loading...\n"); if (STASIS_MESSAGE_TYPE_INIT(session_timeout_type)) { + unload_module(); return AST_MODULE_LOAD_FAILURE; } if (!(sip_tech.capabilities = ast_format_cap_alloc(0))) { + unload_module(); return AST_MODULE_LOAD_FAILURE; } if (ast_sip_api_provider_register(&chan_sip_api_provider)) { + unload_module(); return AST_MODULE_LOAD_FAILURE; } @@ -34254,24 +34284,28 @@ static int load_module(void) if (!peers || !peers_by_ip || !dialogs || !dialogs_needdestroy || !dialogs_rtpcheck || !threadt) { ast_log(LOG_ERROR, "Unable to create primary SIP container(s)\n"); + unload_module(); return AST_MODULE_LOAD_FAILURE; } - if (!(sip_cfg.caps = ast_format_cap_alloc(0))) { + if (!(sip_cfg.caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { + unload_module(); return AST_MODULE_LOAD_FAILURE; } - ast_format_cap_add_all_by_type(sip_tech.capabilities, AST_FORMAT_TYPE_AUDIO); + ast_format_cap_append_by_type(sip_tech.capabilities, AST_MEDIA_TYPE_AUDIO); ASTOBJ_CONTAINER_INIT(®l); /* Registry object list -- not searched for anything */ ASTOBJ_CONTAINER_INIT(&submwil); /* MWI subscription object list */ if (!(sched = ast_sched_context_create())) { ast_log(LOG_ERROR, "Unable to create scheduler context\n"); + unload_module(); return AST_MODULE_LOAD_FAILURE; } if (!(io = io_context_create())) { ast_log(LOG_ERROR, "Unable to create I/O context\n"); + unload_module(); return AST_MODULE_LOAD_FAILURE; } @@ -34279,15 +34313,14 @@ static int load_module(void) can_parse_xml = sip_is_xml_parsable(); if (reload_config(sip_reloadreason)) { /* Load the configuration from sip.conf */ - ast_sip_api_provider_unregister(); + unload_module(); return AST_MODULE_LOAD_DECLINE; } /* Initialize bogus peer. Can be done first after reload_config() */ if (!(bogus_peer = temp_peer("(bogus_peer)"))) { ast_log(LOG_ERROR, "Unable to create bogus_peer for authentication\n"); - io_context_destroy(io); - ast_sched_context_destroy(sched); + unload_module(); return AST_MODULE_LOAD_FAILURE; } /* Make sure the auth will always fail. */ @@ -34302,16 +34335,14 @@ static int load_module(void) memset((void *) &sip_tech_info.send_digit_begin, 0, sizeof(sip_tech_info.send_digit_begin)); if (ast_msg_tech_register(&sip_msg_tech)) { - /* LOAD_FAILURE stops Asterisk, so cleanup is a moot point. */ + unload_module(); return AST_MODULE_LOAD_FAILURE; } /* Make sure we can register our sip channel type */ if (ast_channel_register(&sip_tech)) { ast_log(LOG_ERROR, "Unable to register channel type 'SIP'\n"); - ao2_t_ref(bogus_peer, -1, "unref the bogus_peer"); - io_context_destroy(io); - ast_sched_context_destroy(sched); + unload_module(); return AST_MODULE_LOAD_FAILURE; } @@ -34358,13 +34389,13 @@ static int load_module(void) initialize_escs(); if (sip_epa_register(&cc_epa_static_data)) { - ast_sip_api_provider_unregister(); + unload_module(); return AST_MODULE_LOAD_DECLINE; } if (sip_reqresp_parser_init() == -1) { ast_log(LOG_ERROR, "Unable to initialize the SIP request and response parser\n"); - ast_sip_api_provider_unregister(); + unload_module(); return AST_MODULE_LOAD_DECLINE; } @@ -34373,16 +34404,16 @@ static int load_module(void) * in incoming PUBLISH requests */ if (ast_cc_agent_register(&sip_cc_agent_callbacks)) { - ast_sip_api_provider_unregister(); + unload_module(); return AST_MODULE_LOAD_DECLINE; } } if (ast_cc_monitor_register(&sip_cc_monitor_callbacks)) { - ast_sip_api_provider_unregister(); + unload_module(); return AST_MODULE_LOAD_DECLINE; } if (!(sip_monitor_instances = ao2_container_alloc(37, sip_monitor_instance_hash_fn, sip_monitor_instance_cmp_fn))) { - ast_sip_api_provider_unregister(); + unload_module(); return AST_MODULE_LOAD_DECLINE; } @@ -34523,7 +34554,7 @@ static int unload_module(void) ast_mutex_lock(&authl_lock); if (authl) { - ao2_t_ref(authl, -1, "Removing global authentication"); + ao2_t_cleanup(authl, "Removing global authentication"); authl = NULL; } ast_mutex_unlock(&authl_lock); @@ -34568,15 +34599,15 @@ static int unload_module(void) ast_debug(2, "TCP/TLS thread container did not become empty :(\n"); } - ao2_t_ref(bogus_peer, -1, "unref the bogus_peer"); + ao2_t_cleanup(bogus_peer, "unref the bogus_peer"); - ao2_t_ref(peers, -1, "unref the peers table"); - ao2_t_ref(peers_by_ip, -1, "unref the peers_by_ip table"); - ao2_t_ref(dialogs, -1, "unref the dialogs table"); - ao2_t_ref(dialogs_needdestroy, -1, "unref dialogs_needdestroy"); - ao2_t_ref(dialogs_rtpcheck, -1, "unref dialogs_rtpcheck"); - ao2_t_ref(threadt, -1, "unref the thread table"); - ao2_t_ref(sip_monitor_instances, -1, "unref the sip_monitor_instances table"); + ao2_t_cleanup(peers, "unref the peers table"); + ao2_t_cleanup(peers_by_ip, "unref the peers_by_ip table"); + ao2_t_cleanup(dialogs, "unref the dialogs table"); + ao2_t_cleanup(dialogs_needdestroy, "unref dialogs_needdestroy"); + ao2_t_cleanup(dialogs_rtpcheck, "unref dialogs_rtpcheck"); + ao2_t_cleanup(threadt, "unref the thread table"); + ao2_t_cleanup(sip_monitor_instances, "unref the sip_monitor_instances table"); clear_sip_domains(); sip_cfg.contact_acl = ast_free_acl_list(sip_cfg.contact_acl); @@ -34604,8 +34635,10 @@ static int unload_module(void) notify_types = NULL; } - ast_format_cap_destroy(sip_tech.capabilities); - sip_cfg.caps = ast_format_cap_destroy(sip_cfg.caps); + ao2_cleanup(sip_tech.capabilities); + sip_tech.capabilities = NULL; + ao2_cleanup(sip_cfg.caps); + sip_cfg.caps = NULL; STASIS_MESSAGE_TYPE_CLEANUP(session_timeout_type); diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index 49ff8d548..e4882dbba 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -84,6 +84,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/bridge.h" #include "asterisk/parking.h" #include "asterisk/stasis_channels.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <manager name="SKINNYdevices" language="en_US"> @@ -146,8 +147,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #ifdef AST_DEVMODE static int skinnydebug = 0; char dbgcli_buf[256]; -char dbgreg_buf[256]; -char dbgsub_buf[256]; #define DEBUG_GENERAL (1 << 1) #define DEBUG_SUB (1 << 2) #define DEBUG_PACKET (1 << 3) @@ -174,7 +173,6 @@ static const char tdesc[] = "Skinny Client Control Protocol (Skinny)"; static const char config[] = "skinny.conf"; static struct ast_format_cap *default_cap; -static struct ast_codec_pref default_prefs; enum skinny_codecs { SKINNY_CODEC_ALAW = 2, @@ -1454,8 +1452,6 @@ struct skinny_subchannel { int amaflags; \ int instance; \ int group; \ - struct ast_codec_pref confprefs; \ - struct ast_codec_pref prefs; \ int nonCodecCapability; \ int immediate; \ int nat; \ @@ -1568,7 +1564,6 @@ struct skinny_addon { int hookstate; \ int lastlineinstance; \ int lastcallreference; \ - struct ast_codec_pref confprefs; \ int earlyrtp; \ int transfer; \ int callwaiting; \ @@ -1679,11 +1674,11 @@ static struct skinny_line *skinny_line_alloc(void) return NULL; } - l->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - l->confcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + l->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + l->confcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!l->cap || !l->confcap) { - l->cap = ast_format_cap_destroy(l->cap); - l->confcap = ast_format_cap_destroy(l->confcap); + ao2_cleanup(l->cap); + ao2_cleanup(l->confcap); ast_free(l); return NULL; } @@ -1691,8 +1686,8 @@ static struct skinny_line *skinny_line_alloc(void) } static struct skinny_line *skinny_line_destroy(struct skinny_line *l) { - l->cap = ast_format_cap_destroy(l->cap); - l->confcap = ast_format_cap_destroy(l->confcap); + ao2_ref(l->cap, -1); + ao2_ref(l->confcap, -1); l->named_callgroups = ast_unref_namedgroups(l->named_callgroups); l->named_pickupgroups = ast_unref_namedgroups(l->named_pickupgroups); ast_free(l->container); @@ -1706,12 +1701,12 @@ static struct skinny_device *skinny_device_alloc(const char *dname) return NULL; } - d->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - d->confcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + d->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + d->confcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); d->endpoint = ast_endpoint_create("Skinny", dname); if (!d->cap || !d->confcap || !d->endpoint) { - d->cap = ast_format_cap_destroy(d->cap); - d->confcap = ast_format_cap_destroy(d->confcap); + ao2_cleanup(d->cap); + ao2_cleanup(d->confcap); ast_free(d); return NULL; } @@ -1722,8 +1717,8 @@ static struct skinny_device *skinny_device_alloc(const char *dname) } static struct skinny_device *skinny_device_destroy(struct skinny_device *d) { - d->cap = ast_format_cap_destroy(d->cap); - d->confcap = ast_format_cap_destroy(d->confcap); + ao2_ref(d->cap, -1); + ao2_ref(d->confcap, -1); ast_endpoint_shutdown(d->endpoint); ast_free(d); return NULL; @@ -2103,51 +2098,49 @@ static struct skinny_speeddial *find_speeddial_by_instance(struct skinny_device return sd; } -static struct ast_format *codec_skinny2ast(enum skinny_codecs skinnycodec, struct ast_format *result) +static struct ast_format *codec_skinny2ast(enum skinny_codecs skinnycodec) { switch (skinnycodec) { case SKINNY_CODEC_ALAW: - return ast_format_set(result, AST_FORMAT_ALAW, 0); + return ast_format_alaw; case SKINNY_CODEC_ULAW: - return ast_format_set(result, AST_FORMAT_ULAW, 0); + return ast_format_ulaw; case SKINNY_CODEC_G722: - return ast_format_set(result, AST_FORMAT_G722, 0); + return ast_format_g722; case SKINNY_CODEC_G723_1: - return ast_format_set(result, AST_FORMAT_G723_1, 0); + return ast_format_g723; case SKINNY_CODEC_G729A: - return ast_format_set(result, AST_FORMAT_G729A, 0); + return ast_format_g729; case SKINNY_CODEC_G726_32: - return ast_format_set(result, AST_FORMAT_G726_AAL2, 0); /* XXX Is this right? */ + return ast_format_g726; /* XXX Is this right? */ case SKINNY_CODEC_H261: - return ast_format_set(result, AST_FORMAT_H261, 0); + return ast_format_h261; case SKINNY_CODEC_H263: - return ast_format_set(result, AST_FORMAT_H263 ,0); + return ast_format_h263; default: - ast_format_clear(result); - return result; + return ast_format_none; } } static int codec_ast2skinny(const struct ast_format *astcodec) { - switch (astcodec->id) { - case AST_FORMAT_ALAW: + if (ast_format_cmp(astcodec, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) { return SKINNY_CODEC_ALAW; - case AST_FORMAT_ULAW: + } else if (ast_format_cmp(astcodec, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) { return SKINNY_CODEC_ULAW; - case AST_FORMAT_G722: + } else if (ast_format_cmp(astcodec, ast_format_g722) == AST_FORMAT_CMP_EQUAL) { return SKINNY_CODEC_G722; - case AST_FORMAT_G723_1: + } else if (ast_format_cmp(astcodec, ast_format_g723) == AST_FORMAT_CMP_EQUAL) { return SKINNY_CODEC_G723_1; - case AST_FORMAT_G729A: + } else if (ast_format_cmp(astcodec, ast_format_g729) == AST_FORMAT_CMP_EQUAL) { return SKINNY_CODEC_G729A; - case AST_FORMAT_G726_AAL2: /* XXX Is this right? */ + } else if (ast_format_cmp(astcodec, ast_format_g726) == AST_FORMAT_CMP_EQUAL) { return SKINNY_CODEC_G726_32; - case AST_FORMAT_H261: + } else if (ast_format_cmp(astcodec, ast_format_h261) == AST_FORMAT_CMP_EQUAL) { return SKINNY_CODEC_H261; - case AST_FORMAT_H263: + } else if (ast_format_cmp(astcodec, ast_format_h263) == AST_FORMAT_CMP_EQUAL) { return SKINNY_CODEC_H263; - default: + } else { return 0; } } @@ -2312,13 +2305,8 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s) instance++; } AST_LIST_TRAVERSE(&d->lines, l, list) { - ast_format_cap_joint_copy(l->confcap, d->cap, l->cap); - l->prefs = l->confprefs; - if (!l->prefs.order[0]) { - l->prefs = d->confprefs; - } - /* l->capability = d->capability; - l->prefs = d->prefs; */ + ast_format_cap_get_compatible(l->confcap, d->cap, l->cap); + /* l->capability = d->capability; */ l->instance = instance; l->newmsgs = ast_app_has_voicemail(l->mailbox, NULL); set_callforwards(l, NULL, SKINNY_CFWD_ALL|SKINNY_CFWD_BUSY|SKINNY_CFWD_NOANSWER); @@ -2656,23 +2644,27 @@ static void transmit_connect(struct skinny_device *d, struct skinny_subchannel * { struct skinny_req *req; struct skinny_line *l = sub->line; - struct ast_format_list fmt; - struct ast_format tmpfmt; + struct ast_format *tmpfmt; + unsigned int framing; if (!(req = req_alloc(sizeof(struct open_receive_channel_message), OPEN_RECEIVE_CHANNEL_MESSAGE))) return; - ast_best_codec(l->cap, &tmpfmt); - fmt = ast_codec_pref_getsize(&l->prefs, &tmpfmt); + + tmpfmt = ast_format_cap_get_format(l->cap, 0); + framing = ast_format_cap_get_format_framing(l->cap, tmpfmt); req->data.openreceivechannel.conferenceId = htolel(sub->callid); req->data.openreceivechannel.partyId = htolel(sub->callid); - req->data.openreceivechannel.packets = htolel(fmt.cur_ms); - req->data.openreceivechannel.capability = htolel(codec_ast2skinny(&fmt.format)); + req->data.openreceivechannel.packets = htolel(framing); + req->data.openreceivechannel.capability = htolel(codec_ast2skinny(tmpfmt)); req->data.openreceivechannel.echo = htolel(0); req->data.openreceivechannel.bitrate = htolel(0); SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting OPEN_RECEIVE_CHANNEL_MESSAGE to %s, confid %u, partyid %u, ms %d, fmt %d, echo %d, brate %d\n", - d->name, sub->callid, sub->callid, fmt.cur_ms, codec_ast2skinny(&fmt.format), 0, 0); + d->name, sub->callid, sub->callid, framing, codec_ast2skinny(tmpfmt), 0, 0); + + ao2_ref(tmpfmt, -1); + transmit_response(d, req); } @@ -3033,7 +3025,8 @@ static void transmit_stopmediatransmission(struct skinny_device *d, struct skinn transmit_response(d, req); } -static void transmit_startmediatransmission(struct skinny_device *d, struct skinny_subchannel *sub, struct sockaddr_in dest, struct ast_format_list fmt) +static void transmit_startmediatransmission(struct skinny_device *d, struct skinny_subchannel *sub, struct sockaddr_in dest, + struct ast_format *format, unsigned int framing) { struct skinny_req *req; @@ -3044,8 +3037,8 @@ static void transmit_startmediatransmission(struct skinny_device *d, struct skin req->data.startmedia_ip4.passThruPartyId = htolel(sub->callid); req->data.startmedia_ip4.remoteIp = dest.sin_addr.s_addr; req->data.startmedia_ip4.remotePort = htolel(ntohs(dest.sin_port)); - req->data.startmedia_ip4.packetSize = htolel(fmt.cur_ms); - req->data.startmedia_ip4.payloadType = htolel(codec_ast2skinny(&fmt.format)); + req->data.startmedia_ip4.packetSize = htolel(framing); + req->data.startmedia_ip4.payloadType = htolel(codec_ast2skinny(format)); req->data.startmedia_ip4.qualifier.precedence = htolel(127); req->data.startmedia_ip4.qualifier.vad = htolel(0); req->data.startmedia_ip4.qualifier.packets = htolel(0); @@ -3057,8 +3050,8 @@ static void transmit_startmediatransmission(struct skinny_device *d, struct skin req->data.startmedia_ip6.passThruPartyId = htolel(sub->callid); memcpy(req->data.startmedia_ip6.remoteIp, &dest.sin_addr.s_addr, sizeof(dest.sin_addr.s_addr)); req->data.startmedia_ip6.remotePort = htolel(ntohs(dest.sin_port)); - req->data.startmedia_ip6.packetSize = htolel(fmt.cur_ms); - req->data.startmedia_ip6.payloadType = htolel(codec_ast2skinny(&fmt.format)); + req->data.startmedia_ip6.packetSize = htolel(framing); + req->data.startmedia_ip6.payloadType = htolel(codec_ast2skinny(format)); req->data.startmedia_ip6.qualifier.precedence = htolel(127); req->data.startmedia_ip6.qualifier.vad = htolel(0); req->data.startmedia_ip6.qualifier.packets = htolel(0); @@ -3066,7 +3059,7 @@ static void transmit_startmediatransmission(struct skinny_device *d, struct skin } SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting START_MEDIA_TRANSMISSION_MESSAGE to %s, callid %u, passthrupartyid %u, ip %s:%d, ms %d, fmt %d, prec 127\n", - d->name, sub->callid, sub->callid, ast_inet_ntoa(dest.sin_addr), dest.sin_port, fmt.cur_ms, codec_ast2skinny(&fmt.format)); + d->name, sub->callid, sub->callid, ast_inet_ntoa(dest.sin_addr), dest.sin_port, framing, codec_ast2skinny(format)); transmit_response(d, req); } @@ -3643,7 +3636,6 @@ static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp_instance *r struct skinny_subchannel *sub; struct skinny_line *l; struct skinny_device *d; - struct ast_format_list fmt; struct sockaddr_in us = { 0, }; struct sockaddr_in them = { 0, }; struct ast_sockaddr them_tmp; @@ -3662,7 +3654,8 @@ static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp_instance *r d = l->device; if (rtp){ - struct ast_format tmpfmt; + struct ast_format *tmpfmt; + unsigned int framing; ast_rtp_instance_get_remote_address(rtp, &them_tmp); ast_sockaddr_to_sin(&them_tmp, &them); @@ -3671,20 +3664,22 @@ static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp_instance *r SKINNY_DEBUG(DEBUG_AUDIO, 4, "Peerip = %s:%d\n", ast_inet_ntoa(them.sin_addr), ntohs(them.sin_port)); - ast_best_codec(l->cap, &tmpfmt); - fmt = ast_codec_pref_getsize(&l->prefs, &tmpfmt); + tmpfmt = ast_format_cap_get_format(l->cap, 0); + framing = ast_format_cap_get_format_framing(l->cap, tmpfmt); - SKINNY_DEBUG(DEBUG_AUDIO, 4, "Setting payloadType to '%s' (%d ms)\n", ast_getformatname(&fmt.format), fmt.cur_ms); + SKINNY_DEBUG(DEBUG_AUDIO, 4, "Setting payloadType to '%s' (%d ms)\n", ast_format_get_name(tmpfmt), framing); if (!(l->directmedia) || (l->nat)){ ast_rtp_instance_get_local_address(rtp, &us_tmp); ast_sockaddr_to_sin(&us_tmp, &us); us.sin_addr.s_addr = us.sin_addr.s_addr ? us.sin_addr.s_addr : d->ourip.s_addr; - transmit_startmediatransmission(d, sub, us, fmt); + transmit_startmediatransmission(d, sub, us, tmpfmt, framing); } else { - transmit_startmediatransmission(d, sub, them, fmt); + transmit_startmediatransmission(d, sub, them, tmpfmt, framing); } + ao2_ref(tmpfmt, -1); + return 0; } /* Need a return here to break the bridge */ @@ -4067,25 +4062,6 @@ static char *device2str(int type) } } -/*! \brief Print codec list from preference to CLI/manager */ -static void print_codec_to_cli(int fd, struct ast_codec_pref *pref) -{ - int x; - struct ast_format tmpfmt; - - for(x = 0; x < 32 ; x++) { - ast_codec_pref_index(pref, x, &tmpfmt); - if (!tmpfmt.id) - break; - ast_cli(fd, "%s", ast_getformatname(&tmpfmt)); - ast_cli(fd, ":%d", pref->framing[x]); - if (x < 31 && ast_codec_pref_index(pref, x + 1, &tmpfmt)) - ast_cli(fd, ","); - } - if (!x) - ast_cli(fd, "none"); -} - static char *_skinny_show_devices(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char * const *argv) { struct skinny_device *d; @@ -4204,7 +4180,7 @@ static char *_skinny_show_device(int type, int fd, struct mansession *s, const s struct skinny_speeddial *sd; struct skinny_addon *sa; struct skinny_serviceurl *surl; - char codec_buf[512]; + struct ast_str *codec_buf = ast_str_alloca(64); if (argc < 4) { return CLI_SHOWUSAGE; @@ -4238,12 +4214,8 @@ static char *_skinny_show_device(int type, int fd, struct mansession *s, const s ast_cli(fd, "Ip address: %s\n", (d->session ? ast_inet_ntoa(d->session->sin.sin_addr) : "Unknown")); ast_cli(fd, "Port: %d\n", (d->session ? ntohs(d->session->sin.sin_port) : 0)); ast_cli(fd, "Device Type: %s\n", device2str(d->type)); - ast_cli(fd, "Conf Codecs:"); - ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, d->confcap); - ast_cli(fd, "%s\n", codec_buf); - ast_cli(fd, "Neg Codecs: "); - ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, d->cap); - ast_cli(fd, "%s\n", codec_buf); + ast_cli(fd, "Conf Codecs: %s\n", ast_format_cap_get_names(d->confcap, &codec_buf)); + ast_cli(fd, "Neg Codecs: %s\n", ast_format_cap_get_names(d->cap, &codec_buf)); ast_cli(fd, "Registered: %s\n", (d->session ? "Yes" : "No")); ast_cli(fd, "Lines: %d\n", numlines); AST_LIST_TRAVERSE(&d->lines, l, list) { @@ -4270,12 +4242,8 @@ static char *_skinny_show_device(int type, int fd, struct mansession *s, const s astman_append(s, "Ipaddress: %s\r\n", (d->session ? ast_inet_ntoa(d->session->sin.sin_addr) : "Unknown")); astman_append(s, "Port: %d\r\n", (d->session ? ntohs(d->session->sin.sin_port) : 0)); astman_append(s, "DeviceType: %s\r\n", device2str(d->type)); - astman_append(s, "Codecs: "); - ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, d->confcap); - astman_append(s, "%s\r\n", codec_buf); - astman_append(s, "CodecOrder: "); - ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, d->cap); - astman_append(s, "%s\r\n", codec_buf); + astman_append(s, "Codecs: %s\r\n", ast_format_cap_get_names(d->confcap, &codec_buf)); + astman_append(s, "CodecOrder: %s\r\n", ast_format_cap_get_names(d->cap, &codec_buf)); astman_append(s, "Devicestatus: %s\r\n", (d->session?"registered":"unregistered")); astman_append(s, "NumberOfLines: %d\r\n", numlines); AST_LIST_TRAVERSE(&d->lines, l, list) { @@ -4468,9 +4436,7 @@ static char *_skinny_show_line(int type, int fd, struct mansession *s, const str struct skinny_device *d; struct skinny_line *l; struct skinny_subline *subline; - struct ast_codec_pref *pref; - int x = 0; - char codec_buf[512]; + struct ast_str *codec_buf = ast_str_alloca(64); char group_buf[256]; char cbuf[256]; @@ -4536,15 +4502,8 @@ static char *_skinny_show_line(int type, int fd, struct mansession *s, const str ast_cli(fd, "immediate: %s\n", (l->immediate ? "Yes" : "No")); ast_cli(fd, "Group: %d\n", l->group); ast_cli(fd, "Parkinglot: %s\n", S_OR(l->parkinglot, "<not set>")); - ast_cli(fd, "Conf Codecs: "); - ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->confcap); - ast_cli(fd, "%s\n", codec_buf); - ast_cli(fd, "Neg Codecs: "); - ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->cap); - ast_cli(fd, "%s\n", codec_buf); - ast_cli(fd, "Codec Order: ("); - print_codec_to_cli(fd, &l->prefs); - ast_cli(fd, ")\n"); + ast_cli(fd, "Conf Codecs: %s\n", ast_format_cap_get_names(l->confcap, &codec_buf)); + ast_cli(fd, "Neg Codecs: %s\n", ast_format_cap_get_names(l->cap, &codec_buf)); if (AST_LIST_FIRST(&l->sublines)) { ast_cli(fd, "Sublines:\n"); AST_LIST_TRAVERSE(&l->sublines, subline, list) { @@ -4592,19 +4551,7 @@ static char *_skinny_show_line(int type, int fd, struct mansession *s, const str astman_append(s, "immediate: %s\r\n", (l->immediate ? "Yes" : "No")); astman_append(s, "Group: %d\r\n", l->group); astman_append(s, "Parkinglot: %s\r\n", S_OR(l->parkinglot, "<not set>")); - ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->confcap); - astman_append(s, "Codecs: %s\r\n", codec_buf); - astman_append(s, "CodecOrder: "); - pref = &l->prefs; - for(x = 0; x < 32 ; x++) { - struct ast_format tmpfmt; - ast_codec_pref_index(pref, x, &tmpfmt); - if (!tmpfmt.id) - break; - astman_append(s, "%s", ast_getformatname(&tmpfmt)); - if (x < 31 && ast_codec_pref_index(pref, x+1, &tmpfmt)) - astman_append(s, ","); - } + astman_append(s, "Codecs: %s\r\n", ast_format_cap_get_names(l->confcap, &codec_buf)); astman_append(s, "\r\n"); } } @@ -4802,7 +4749,7 @@ static void start_rtp(struct skinny_subchannel *sub) struct ast_sockaddr bindaddr_tmp; skinny_locksub(sub); - /* Allocate the RTP */ + SKINNY_DEBUG(DEBUG_AUDIO, 3, "Sub %u - Starting RTP\n", sub->callid); ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr); sub->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL); if (hasvideo) @@ -4828,14 +4775,14 @@ static void start_rtp(struct skinny_subchannel *sub) if (sub->rtp) { ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "Skinny RTP"); ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_NAT, l->nat); + /* Set frame packetization */ + ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(sub->rtp), + ast_format_cap_get_framing(l->cap)); } if (sub->vrtp) { ast_rtp_instance_set_qos(sub->vrtp, qos.tos_video, qos.cos_video, "Skinny VRTP"); ast_rtp_instance_set_prop(sub->vrtp, AST_RTP_PROPERTY_NAT, l->nat); } - /* Set Frame packetization */ - if (sub->rtp) - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp, &l->prefs); /* Create the RTP connection */ transmit_connect(d, sub); @@ -5097,9 +5044,17 @@ static struct ast_frame *skinny_rtp_read(struct skinny_subchannel *sub) if (ast) { /* We already hold the channel lock */ if (f->frametype == AST_FRAME_VOICE) { - if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &f->subclass.format))) { - ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format)); - ast_format_cap_set(ast_channel_nativeformats(ast), &f->subclass.format); + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_format_cap *caps; + + ast_debug(1, "Oooh, format changed to %s\n", ast_format_get_name(f->subclass.format)); + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (caps) { + ast_format_cap_append(caps, f->subclass.format, 0); + ast_channel_nativeformats_set(ast, caps); + ao2_ref(caps, -1); + } ast_set_read_format(ast, ast_channel_readformat(ast)); ast_set_write_format(ast, ast_channel_writeformat(ast)); } @@ -5130,13 +5085,13 @@ static int skinny_write(struct ast_channel *ast, struct ast_frame *frame) return 0; } } else { - if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) { - char buf[256]; + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_str *codec_buf = ast_str_alloca(64); ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n", - ast_getformatname(&frame->subclass.format), - ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)), - ast_getformatname(ast_channel_readformat(ast)), - ast_getformatname(ast_channel_writeformat(ast))); + ast_format_get_name(frame->subclass.format), + ast_format_cap_get_names(ast_channel_nativeformats(ast), &codec_buf), + ast_format_get_name(ast_channel_readformat(ast)), + ast_format_get_name(ast_channel_writeformat(ast))); return -1; } } @@ -5403,23 +5358,33 @@ static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subli struct skinny_subchannel *sub; struct skinny_device *d = l->device; struct ast_variable *v = NULL; - struct ast_format tmpfmt; + struct ast_format *tmpfmt; + struct ast_format_cap *caps; if (!l->device || !l->device->session) { ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name); return NULL; } + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + return NULL; + } + tmp = ast_channel_alloc(1, state, l->cid_num, l->cid_name, l->accountcode, l->exten, l->context, assignedids, requestor, l->amaflags, "Skinny/%s@%s-%d", l->name, d->name, callnums); if (!tmp) { ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); + ao2_ref(caps, -1); return NULL; } else { + struct ast_str *codec_buf = ast_str_alloca(64); + sub = ast_calloc(1, sizeof(*sub)); if (!sub) { ast_log(LOG_WARNING, "Unable to allocate Skinny subchannel\n"); ast_channel_unlock(tmp); ast_channel_unref(tmp); + ao2_ref(caps, -1); return NULL; } else { skinny_set_owner(sub, tmp); @@ -5452,25 +5417,28 @@ static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subli ast_channel_stage_snapshot(tmp); ast_channel_tech_set(tmp, &skinny_tech); ast_channel_tech_pvt_set(tmp, sub); - ast_format_cap_copy(ast_channel_nativeformats(tmp), l->cap); - if (ast_format_cap_is_empty(ast_channel_nativeformats(tmp))) { - // Should throw an error - ast_format_cap_copy(ast_channel_nativeformats(tmp), default_cap); + if (!ast_format_cap_count(l->cap)) { + ast_format_cap_append_from_cap(caps, l->cap, AST_MEDIA_TYPE_UNKNOWN); + } else { + ast_format_cap_append_from_cap(caps, default_cap, AST_MEDIA_TYPE_UNKNOWN); } - ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt); + ast_channel_nativeformats_set(tmp, caps); + ao2_ref(caps, -1); + tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(tmp), 0); SKINNY_DEBUG(DEBUG_SUB, 3, "skinny_new: tmp->nativeformats=%s fmt=%s\n", - ast_getformatname_multiple(dbgsub_buf, sizeof(dbgsub_buf), ast_channel_nativeformats(tmp)), - ast_getformatname(&tmpfmt)); + ast_format_cap_get_names(ast_channel_nativeformats(tmp), &codec_buf), + ast_format_get_name(tmpfmt)); if (sub->rtp) { ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0)); } if (state == AST_STATE_RING) { ast_channel_rings_set(tmp, 1); } - ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_readformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt); + ast_channel_set_writeformat(tmp, tmpfmt); + ast_channel_set_rawwriteformat(tmp, tmpfmt); + ast_channel_set_readformat(tmp, tmpfmt); + ast_channel_set_rawreadformat(tmp, tmpfmt); + ao2_ref(tmpfmt, -1); if (!ast_strlen_zero(l->language)) ast_channel_language_set(tmp, l->language); @@ -6676,7 +6644,8 @@ static int handle_capabilities_res_message(struct skinny_req *req, struct skinny struct skinny_device *d = s->device; struct skinny_line *l; uint32_t count = 0; - struct ast_format_cap *codecs = ast_format_cap_alloc(0); + struct ast_format_cap *codecs = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + struct ast_str *codec_buf = ast_str_alloca(64); int i; if (!codecs) { @@ -6690,23 +6659,23 @@ static int handle_capabilities_res_message(struct skinny_req *req, struct skinny } for (i = 0; i < count; i++) { - struct ast_format acodec; + struct ast_format *acodec; int scodec = 0; scodec = letohl(req->data.caps.caps[i].codec); - codec_skinny2ast(scodec, &acodec); - SKINNY_DEBUG(DEBUG_AUDIO, 4, "Adding codec capability %s (%d)\n", ast_getformatname(&acodec), scodec); - ast_format_cap_add(codecs, &acodec); + acodec = codec_skinny2ast(scodec); + SKINNY_DEBUG(DEBUG_AUDIO, 4, "Adding codec capability %s (%d)\n", ast_format_get_name(acodec), scodec); + ast_format_cap_append(codecs, acodec, 0); } - ast_format_cap_joint_copy(d->confcap, codecs, d->cap); - SKINNY_DEBUG(DEBUG_AUDIO, 4, "Device capability set to '%s'\n", ast_getformatname_multiple(dbgreg_buf, sizeof(dbgreg_buf), d->cap)); + ast_format_cap_get_compatible(d->confcap, codecs, d->cap); + SKINNY_DEBUG(DEBUG_AUDIO, 4, "Device capability set to '%s'\n", ast_format_cap_get_names(d->cap, &codec_buf)); AST_LIST_TRAVERSE(&d->lines, l, list) { ast_mutex_lock(&l->lock); - ast_format_cap_joint_copy(l->confcap, d->cap, l->cap); + ast_format_cap_get_compatible(l->confcap, d->cap, l->cap); ast_mutex_unlock(&l->lock); } - codecs = ast_format_cap_destroy(codecs); + ao2_ref(codecs, -1); return 1; } @@ -6877,16 +6846,16 @@ static int handle_open_receive_channel_ack_message(struct skinny_req *req, struc struct skinny_device *d = s->device; struct skinny_line *l; struct skinny_subchannel *sub; - struct ast_format_list fmt; struct sockaddr_in sin = { 0, }; struct sockaddr_in us = { 0, }; struct ast_sockaddr sin_tmp; struct ast_sockaddr us_tmp; - struct ast_format tmpfmt; + struct ast_format *tmpfmt; uint32_t addr; int port; int status; int callid; + unsigned int framing; status = (d->protocolversion<17) ? letohl(req->data.openreceivechannelack_ip4.status) : letohl(req->data.openreceivechannelack_ip6.status); @@ -6937,12 +6906,14 @@ static int handle_open_receive_channel_ack_message(struct skinny_req *req, struc SKINNY_DEBUG(DEBUG_PACKET, 4, "device ipaddr = %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); SKINNY_DEBUG(DEBUG_PACKET, 4, "asterisk ipaddr = %s:%d\n", ast_inet_ntoa(us.sin_addr), ntohs(us.sin_port)); - ast_best_codec(l->cap, &tmpfmt); - fmt = ast_codec_pref_getsize(&l->prefs, &tmpfmt); + tmpfmt = ast_format_cap_get_format(l->cap, 0); + framing = ast_format_cap_get_format_framing(l->cap, tmpfmt); - SKINNY_DEBUG(DEBUG_PACKET, 4, "Setting payloadType to '%s' (%d ms)\n", ast_getformatname(&fmt.format), fmt.cur_ms); + SKINNY_DEBUG(DEBUG_PACKET, 4, "Setting payloadType to '%s' (%d ms)\n", ast_format_get_name(tmpfmt), framing); - transmit_startmediatransmission(d, sub, us, fmt); + transmit_startmediatransmission(d, sub, us, tmpfmt, framing); + + ao2_ref(tmpfmt, -1); return 1; } @@ -7496,8 +7467,8 @@ static void skinny_session_cleanup(void *data) if (l->device != d) { continue; } - ast_format_cap_remove_all(l->cap); - ast_parse_allow_disallow(&l->prefs, l->cap, "all", 0); + ast_format_cap_remove_by_type(l->cap, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_update_by_allow_disallow(l->cap, "all", 0); l->instance = 0; unregister_exten(l); ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name); @@ -7713,8 +7684,9 @@ static struct ast_channel *skinny_request(const char *type, struct ast_format_ca struct ast_channel *tmpc = NULL; char tmp[256]; - if (!(ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO))) { - ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap)); + if (!(ast_format_cap_has_type(cap, AST_MEDIA_TYPE_AUDIO))) { + struct ast_str *codec_buf = ast_str_alloca(64); + ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &codec_buf)); return NULL; } @@ -7870,10 +7842,10 @@ static void config_parse_variables(int type, void *item, struct ast_variable *vp } continue; } else if (!strcasecmp(v->name, "allow")) { - ast_parse_allow_disallow(&default_prefs, default_cap, v->value, 1); + ast_format_cap_update_by_allow_disallow(default_cap, v->value, 1); continue; } else if (!strcasecmp(v->name, "disallow")) { - ast_parse_allow_disallow(&default_prefs, default_cap, v->value, 0); + ast_format_cap_update_by_allow_disallow(default_cap, v->value, 0); continue; } } @@ -8080,20 +8052,20 @@ static void config_parse_variables(int type, void *item, struct ast_variable *vp } } else if (!strcasecmp(v->name, "allow")) { if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) { - ast_parse_allow_disallow(&CDEV->confprefs, CDEV->confcap, v->value, 1); + ast_format_cap_update_by_allow_disallow(CDEV->confcap, v->value, 1); continue; } if (type & (TYPE_DEF_LINE | TYPE_LINE)) { - ast_parse_allow_disallow(&CLINE->confprefs, CLINE->confcap, v->value, 1); + ast_format_cap_update_by_allow_disallow(CLINE->confcap, v->value, 1); continue; } } else if (!strcasecmp(v->name, "disallow")) { if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) { - ast_parse_allow_disallow(&CDEV->confprefs, CDEV->confcap, v->value, 0); + ast_format_cap_update_by_allow_disallow(CDEV->confcap, v->value, 0); continue; } if (type & (TYPE_DEF_LINE | TYPE_LINE)) { - ast_parse_allow_disallow(&CLINE->confprefs, CLINE->confcap, v->value, 0); + ast_format_cap_update_by_allow_disallow(CLINE->confcap, v->value, 0); continue; } } else if (!strcasecmp(v->name, "version")) { @@ -8303,7 +8275,7 @@ static struct skinny_line *config_line(const char *lname, struct ast_variable *v memcpy(l, default_line, sizeof(*default_line)); ast_mutex_init(&l->lock); ast_copy_string(l->name, lname, sizeof(l->name)); - ast_format_cap_copy(l->confcap, default_cap); + ast_format_cap_append_from_cap(l->confcap, default_cap, AST_MEDIA_TYPE_UNKNOWN); AST_LIST_INSERT_TAIL(&lines, l, all); ast_mutex_lock(&l->lock); @@ -8362,7 +8334,7 @@ static struct skinny_device *config_device(const char *dname, struct ast_variabl memcpy(d, default_device, sizeof(*default_device)); ast_mutex_init(&d->lock); ast_copy_string(d->name, dname, sizeof(d->name)); - ast_format_cap_copy(d->confcap, default_cap); + ast_format_cap_append_from_cap(d->confcap, default_cap, AST_MEDIA_TYPE_UNKNOWN); AST_LIST_INSERT_TAIL(&devices, d, list); ast_mutex_lock(&d->lock); @@ -8453,7 +8425,6 @@ static int config_load(void) } memset(&bindaddr, 0, sizeof(bindaddr)); - memset(&default_prefs, 0, sizeof(default_prefs)); immed_dialchar = '\0'; memset(&vmexten, '\0', sizeof(vmexten)); @@ -8482,7 +8453,6 @@ static int config_load(void) bindaddr.sin_family = AF_INET; /* load the lines sections */ - default_line->confprefs = default_prefs; config_parse_variables(TYPE_DEF_LINE, default_line, ast_variable_browse(cfg, "lines")); cat = ast_category_browse(cfg, "lines"); while (cat && strcasecmp(cat, "general") && strcasecmp(cat, "devices")) { @@ -8491,7 +8461,6 @@ static int config_load(void) } /* load the devices sections */ - default_device->confprefs = default_prefs; config_parse_variables(TYPE_DEF_DEVICE, default_device, ast_variable_browse(cfg, "devices")); cat = ast_category_browse(cfg, "devices"); while (cat && strcasecmp(cat, "general") && strcasecmp(cat, "lines")) { @@ -8678,17 +8647,18 @@ int skinny_reload(void) static int load_module(void) { int res = 0; - struct ast_format tmpfmt; - if (!(default_cap = ast_format_cap_alloc(0))) { + + if (!(default_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return AST_MODULE_LOAD_DECLINE; } - if (!(skinny_tech.capabilities = ast_format_cap_alloc(0))) { + if (!(skinny_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { + ao2_ref(default_cap, -1); return AST_MODULE_LOAD_DECLINE; } - ast_format_cap_add_all_by_type(skinny_tech.capabilities, AST_FORMAT_TYPE_AUDIO); - ast_format_cap_add(default_cap, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0)); - ast_format_cap_add(default_cap, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0)); + ast_format_cap_append_by_type(skinny_tech.capabilities, AST_MEDIA_TYPE_AUDIO); + ast_format_cap_append(default_cap, ast_format_ulaw, 0); + ast_format_cap_append(default_cap, ast_format_alaw, 0); for (; res < ARRAY_LEN(soft_key_template_default); res++) { soft_key_template_default[res].softKeyEvent = htolel(soft_key_template_default[res].softKeyEvent); @@ -8696,11 +8666,23 @@ static int load_module(void) /* load and parse config */ res = config_load(); if (res == -1) { + ao2_ref(skinny_tech.capabilities, -1); + ao2_ref(default_cap, -1); return AST_MODULE_LOAD_DECLINE; } + sched = ast_sched_context_create(); + if (!sched) { + ao2_ref(skinny_tech.capabilities, -1); + ao2_ref(default_cap, -1); + ast_log(LOG_WARNING, "Unable to create schedule context\n"); + return AST_MODULE_LOAD_FAILURE; + } + /* Make sure we can register our skinny channel type */ if (ast_channel_register(&skinny_tech)) { + ao2_ref(default_cap, -1); + ao2_ref(skinny_tech.capabilities, -1); ast_log(LOG_ERROR, "Unable to register channel class 'Skinny'\n"); return -1; } @@ -8713,14 +8695,12 @@ static int load_module(void) ast_manager_register_xml("SKINNYlines", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_lines); ast_manager_register_xml("SKINNYshowline", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_line); - sched = ast_sched_context_create(); - if (!sched) { - ast_log(LOG_WARNING, "Unable to create schedule context\n"); - return AST_MODULE_LOAD_FAILURE; - } if (ast_sched_start_thread(sched)) { ast_sched_context_destroy(sched); sched = NULL; + ast_channel_unregister(&skinny_tech); + ao2_ref(default_cap, -1); + ao2_ref(skinny_tech.capabilities, -1); return AST_MODULE_LOAD_FAILURE; } @@ -8738,6 +8718,7 @@ static int unload_module(void) ast_rtp_glue_unregister(&skinny_rtp_glue); ast_channel_unregister(&skinny_tech); + ao2_cleanup(skinny_tech.capabilities); ast_cli_unregister_multiple(cli_skinny, ARRAY_LEN(cli_skinny)); ast_manager_unregister("SKINNYdevices"); @@ -8797,8 +8778,7 @@ static int unload_module(void) if (con) ast_context_destroy(con, "Skinny"); - default_cap = ast_format_cap_destroy(default_cap); - skinny_tech.capabilities = ast_format_cap_destroy(skinny_tech.capabilities); + ao2_ref(default_cap, -1); return 0; } diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c index 7525f3921..3f6fd01c8 100644 --- a/channels/chan_unistim.c +++ b/channels/chan_unistim.c @@ -78,6 +78,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/features_config.h" #include "asterisk/bridge.h" #include "asterisk/stasis_channels.h" +#include "asterisk/format_cache.h" #define DEFAULTCONTEXT "default" #define DEFAULTCALLERID "Unknown" @@ -1933,7 +1934,7 @@ static void unistim_line_copy(struct unistim_line *dst, struct unistim_line *src struct ast_format_cap *tmp = src->cap; memcpy(dst, src, sizeof(*dst)); /* this over writes the cap ptr, so we have to reset it */ src->cap = tmp; - ast_format_cap_copy(src->cap, dst->cap); + ast_format_cap_append_from_cap(src->cap, dst->cap, AST_MEDIA_TYPE_UNKNOWN); } static struct unistim_line *unistim_line_destroy(struct unistim_line *l) @@ -1941,7 +1942,7 @@ static struct unistim_line *unistim_line_destroy(struct unistim_line *l) if (!l) { return NULL; } - l->cap = ast_format_cap_destroy(l->cap); + ao2_ref(l->cap, -1); ast_free(l); return NULL; } @@ -1953,7 +1954,7 @@ static struct unistim_line *unistim_line_alloc(void) return NULL; } - if (!(l->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) { + if (!(l->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { ast_free(l); return NULL; } @@ -2699,15 +2700,15 @@ static void send_start_rtp(struct unistim_subchannel *sub) if (unistimdebug) { ast_verb(0, "RTP started : Our IP/port is : %s:%hd with codec %s\n", ast_inet_ntoa(us.sin_addr), - htons(us.sin_port), ast_getformatname(ast_channel_readformat(sub->owner))); + htons(us.sin_port), ast_format_get_name(ast_channel_readformat(sub->owner))); ast_verb(0, "Starting phone RTP stack. Our public IP is %s\n", ast_inet_ntoa(public.sin_addr)); } pte = sub->parent->parent->session; codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, ast_channel_readformat(sub->owner), 0); - if ((ast_channel_readformat(sub->owner)->id == AST_FORMAT_ULAW) || - (ast_channel_readformat(sub->owner)->id == AST_FORMAT_ALAW)) { + if ((ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) || + (ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_alaw) == AST_FORMAT_CMP_EQUAL)) { if (unistimdebug) { ast_verb(0, "Sending packet_send_rtp_packet_size for codec %d\n", codec); } @@ -2804,17 +2805,17 @@ static void send_start_rtp(struct unistim_subchannel *sub) /* Codec */ buffsend[40] = codec; buffsend[41] = codec; - if (ast_channel_readformat(sub->owner)->id == AST_FORMAT_ULAW) { + if (ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) { buffsend[42] = 1; /* 1 = 20ms (160 bytes), 2 = 40ms (320 bytes) */ - } else if (ast_channel_readformat(sub->owner)->id == AST_FORMAT_ALAW) { + } else if (ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_alaw) == AST_FORMAT_CMP_EQUAL) { buffsend[42] = 1; /* 1 = 20ms (160 bytes), 2 = 40ms (320 bytes) */ - } else if (ast_channel_readformat(sub->owner)->id == AST_FORMAT_G723_1) { + } else if (ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_g723) == AST_FORMAT_CMP_EQUAL) { buffsend[42] = 2; /* 1 = 30ms (24 bytes), 2 = 60 ms (48 bytes) */ - } else if (ast_channel_readformat(sub->owner)->id == AST_FORMAT_G729A) { + } else if (ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_g729) == AST_FORMAT_CMP_EQUAL) { buffsend[42] = 2; /* 1 = 10ms (10 bytes), 2 = 20ms (20 bytes) */ } else { ast_log(LOG_WARNING, "Unsupported codec %s!\n", - ast_getformatname(ast_channel_readformat(sub->owner))); + ast_format_get_name(ast_channel_readformat(sub->owner))); } /* Source port for transmit RTP and Destination port for receiving RTP */ buffsend[45] = (htons(sin.sin_port) & 0xff00) >> 8; @@ -2883,18 +2884,20 @@ static void start_rtp(struct unistim_subchannel *sub) sin.sin_port = htons(find_rtp_port(sub)); ast_sockaddr_from_sin(&sin_tmp, &sin); ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp); - if (!ast_format_cap_iscompatible(ast_channel_nativeformats(sub->owner), ast_channel_readformat(sub->owner))) { - struct ast_format tmpfmt; - char tmp[256]; - ast_best_codec(ast_channel_nativeformats(sub->owner), &tmpfmt); + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(sub->owner), ast_channel_readformat(sub->owner)) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_format *tmpfmt; + struct ast_str *cap_buf = ast_str_alloca(64); + + tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(sub->owner), 0); ast_log(LOG_WARNING, "Our read/writeformat has been changed to something incompatible: %s, using %s best codec from %s\n", - ast_getformatname(ast_channel_readformat(sub->owner)), - ast_getformatname(&tmpfmt), - ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(sub->owner))); + ast_format_get_name(ast_channel_readformat(sub->owner)), + ast_format_get_name(tmpfmt), + ast_format_cap_get_names(ast_channel_nativeformats(sub->owner), &cap_buf)); - ast_format_copy(ast_channel_readformat(sub->owner), &tmpfmt); - ast_format_copy(ast_channel_writeformat(sub->owner), &tmpfmt); + ast_channel_set_readformat(sub->owner, tmpfmt); + ast_channel_set_writeformat(sub->owner, tmpfmt); + ao2_ref(tmpfmt, -1); } send_start_rtp(sub); ast_mutex_unlock(&sub->lock); @@ -5132,14 +5135,21 @@ static struct ast_frame *unistim_rtp_read(const struct ast_channel *ast, if (sub->owner) { /* We already hold the channel lock */ if (f->frametype == AST_FRAME_VOICE) { - if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(sub->owner), &f->subclass.format))) { - char tmp[256]; + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(sub->owner), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_format_cap *caps; + ast_debug(1, "Oooh, format changed from %s to %s\n", - ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(sub->owner)), - ast_getformatname(&f->subclass.format)); - - ast_format_cap_set(ast_channel_nativeformats(sub->owner), &f->subclass.format); + ast_format_cap_get_names(ast_channel_nativeformats(sub->owner), &cap_buf), + ast_format_get_name(f->subclass.format)); + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (caps) { + ast_format_cap_append(caps, f->subclass.format, 0); + ast_channel_nativeformats_set(sub->owner, caps); + ao2_ref(caps, -1); + } ast_set_read_format(sub->owner, ast_channel_readformat(sub->owner)); ast_set_write_format(sub->owner, ast_channel_writeformat(sub->owner)); } @@ -5175,14 +5185,15 @@ static int unistim_write(struct ast_channel *ast, struct ast_frame *frame) return 0; } } else { - if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) { - char tmp[256]; + if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + struct ast_str *cap_buf = ast_str_alloca(64); + ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = (%s/%s)\n", - ast_getformatname(&frame->subclass.format), - ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(ast)), - ast_getformatname(ast_channel_readformat(ast)), - ast_getformatname(ast_channel_writeformat(ast))); + ast_format_get_name(frame->subclass.format), + ast_format_cap_get_names(ast_channel_nativeformats(ast), &cap_buf), + ast_format_get_name(ast_channel_readformat(ast)), + ast_format_get_name(ast_channel_writeformat(ast))); return -1; } } @@ -5661,9 +5672,10 @@ static int unistim_send_mwi_to_peer(struct unistim_line *peer, unsigned int tick /* called from unistim_request (calls from the pbx ) */ static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor) { + struct ast_format_cap *caps; struct ast_channel *tmp; struct unistim_line *l; - struct ast_format tmpfmt; + struct ast_format *tmpfmt; if (!sub) { ast_log(LOG_WARNING, "subchannel null in unistim_new\n"); @@ -5673,6 +5685,12 @@ static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state ast_log(LOG_WARNING, "no line for subchannel %p\n", sub); return NULL; } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + return NULL; + } + l = sub->parent; tmp = ast_channel_alloc(1, state, l->cid_num, NULL, l->accountcode, l->exten, l->parent->context, assignedids, requestor, l->amaflags, "USTM/%s@%s-%p", l->name, l->parent->name, sub); @@ -5681,24 +5699,32 @@ static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state } if (!tmp) { ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); + ao2_ref(caps, -1); return NULL; } ast_channel_stage_snapshot(tmp); - ast_format_cap_copy(ast_channel_nativeformats(tmp), l->cap); - if (ast_format_cap_is_empty(ast_channel_nativeformats(tmp))) { - ast_format_cap_copy(ast_channel_nativeformats(tmp), global_cap); + if (ast_format_cap_count(l->cap)) { + ast_format_cap_append_from_cap(caps, l->cap, AST_MEDIA_TYPE_UNKNOWN); + } else { + ast_format_cap_append_from_cap(caps, global_cap, AST_MEDIA_TYPE_UNKNOWN); } - ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt); + ast_channel_nativeformats_set(tmp, caps); + ao2_ref(caps, -1); + + tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(tmp), 0); if (unistimdebug) { - char tmp1[256], tmp2[256], tmp3[256]; + struct ast_str *native_buf = ast_str_alloca(64); + struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *global_buf = ast_str_alloca(64); + ast_verb(0, "Best codec = %s from nativeformats %s (line cap=%s global=%s)\n", - ast_getformatname(&tmpfmt), - ast_getformatname_multiple(tmp1, sizeof(tmp1), ast_channel_nativeformats(tmp)), - ast_getformatname_multiple(tmp2, sizeof(tmp2), l->cap), - ast_getformatname_multiple(tmp3, sizeof(tmp3), global_cap)); + ast_format_get_name(tmpfmt), + ast_format_cap_get_names(ast_channel_nativeformats(tmp), &native_buf), + ast_format_cap_get_names(l->cap, &cap_buf), + ast_format_cap_get_names(global_cap, &global_buf)); } if ((sub->rtp) && (sub->subtype == 0)) { if (unistimdebug) { @@ -5716,10 +5742,13 @@ static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state ast_channel_rings_set(tmp, 1); } ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE); - ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_readformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt); + + ast_channel_set_writeformat(tmp, tmpfmt); + ast_channel_set_rawwriteformat(tmp, tmpfmt); + ast_channel_set_readformat(tmp, tmpfmt); + ast_channel_set_rawreadformat(tmp, tmpfmt); + ao2_ref(tmpfmt, -1); + ast_channel_tech_pvt_set(tmp, sub); ast_channel_tech_set(tmp, &unistim_tech); @@ -5900,12 +5929,14 @@ static struct ast_channel *unistim_request(const char *type, struct ast_format_c struct unistim_device *d; struct ast_channel *tmpc = NULL; char tmp[256]; - char tmp2[256]; - if (!(ast_format_cap_has_joint(cap, global_cap))) { + if (!(ast_format_cap_iscompatible(cap, global_cap))) { + struct ast_str *cap_buf = ast_str_alloca(64); + struct ast_str *global_buf = ast_str_alloca(64); ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format %s while capability is %s\n", - ast_getformatname_multiple(tmp2, sizeof(tmp2), cap), ast_getformatname_multiple(tmp, sizeof(tmp), global_cap)); + ast_format_cap_get_names(cap, &cap_buf), + ast_format_cap_get_names(global_cap, &global_buf)); return NULL; } @@ -5956,7 +5987,8 @@ static struct ast_channel *unistim_request(const char *type, struct ast_format_c } sub->subtype = SUB_RING; sub->softkey = -1; - ast_format_cap_copy(sub->parent->cap, cap); + + ast_format_cap_append_from_cap(sub->parent->cap, cap, AST_MEDIA_TYPE_UNKNOWN); tmpc = unistim_new(sub, AST_STATE_DOWN, assignedids, requestor); if (!tmpc) { ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp); @@ -5975,6 +6007,7 @@ static char *unistim_show_info(struct ast_cli_entry *e, int cmd, struct ast_cli_ struct unistim_line *line; struct unistim_subchannel *sub; struct unistimsession *s; + struct ast_str *cap_buf = ast_str_alloca(64); switch (cmd) { case CLI_INIT: @@ -6005,11 +6038,10 @@ static char *unistim_show_info(struct ast_cli_entry *e, int cmd, struct ast_cli_ device, device->selected, device->height); AST_LIST_LOCK(&device->lines); AST_LIST_TRAVERSE(&device->lines,line,list) { - char tmp2[256]; ast_cli(a->fd, "->name=%s fullname=%s exten=%s callid=%s cap=%s line=%p\n", line->name, line->fullname, line->exten, line->cid_num, - ast_getformatname_multiple(tmp2, sizeof(tmp2), line->cap), line); + ast_format_cap_get_names(line->cap, &cap_buf), line); } AST_LIST_UNLOCK(&device->lines); @@ -6595,7 +6627,7 @@ static struct unistim_device *build_device(const char *cat, const struct ast_var ast_verb(3, "Setting mailbox '%s' on %s@%s\n", l->mailbox, d->name, l->name); } } - ast_format_cap_copy(l->cap, global_cap); + ast_format_cap_append_from_cap(l->cap, global_cap, AST_MEDIA_TYPE_UNKNOWN); l->parent = d; linecnt++; AST_LIST_LOCK(&d->lines); @@ -7011,17 +7043,18 @@ static struct ast_rtp_glue unistim_rtp_glue = { int load_module(void) { int res; - struct ast_format tmpfmt; - if (!(global_cap = ast_format_cap_alloc(0))) { + + if (!(global_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { goto buff_failed; } - if (!(unistim_tech.capabilities = ast_format_cap_alloc(0))) { + if (!(unistim_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { goto buff_failed; } - ast_format_cap_add(global_cap, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0)); - ast_format_cap_add(global_cap, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0)); - ast_format_cap_copy(unistim_tech.capabilities, global_cap); + ast_format_cap_append(global_cap, ast_format_ulaw, 0); + ast_format_cap_append(global_cap, ast_format_alaw, 0); + ast_format_cap_append_from_cap(unistim_tech.capabilities, global_cap, AST_MEDIA_TYPE_AUDIO); + if (!(buff = ast_malloc(SIZE_PAGE))) { goto buff_failed; } @@ -7040,6 +7073,10 @@ int load_module(void) res = reload_config(); if (res) { + ao2_ref(unistim_tech.capabilities, -1); + ao2_ref(global_cap, -1); + ast_sched_context_destroy(sched); + io_context_destroy(io); return AST_MODULE_LOAD_DECLINE; } /* Make sure we can register our unistim channel type */ @@ -7066,9 +7103,11 @@ sched_failed: io_failed: ast_free(buff); buff = NULL; - global_cap = ast_format_cap_destroy(global_cap); - unistim_tech.capabilities = ast_format_cap_destroy(unistim_tech.capabilities); buff_failed: + ao2_cleanup(global_cap); + global_cap = NULL; + ao2_cleanup(unistim_tech.capabilities); + unistim_tech.capabilities = NULL; return AST_MODULE_LOAD_FAILURE; } @@ -7082,6 +7121,7 @@ static int unload_module(void) ast_cli_unregister_multiple(unistim_cli, ARRAY_LEN(unistim_cli)); ast_channel_unregister(&unistim_tech); + ao2_cleanup(unistim_tech.capabilities); ast_rtp_glue_unregister(&unistim_rtp_glue); ast_mutex_lock(&monlock); @@ -7099,8 +7139,7 @@ static int unload_module(void) if (unistimsock > -1) { close(unistimsock); } - global_cap = ast_format_cap_destroy(global_cap); - unistim_tech.capabilities = ast_format_cap_destroy(unistim_tech.capabilities); + ao2_ref(global_cap, -1); return 0; } diff --git a/channels/chan_vpb.cc b/channels/chan_vpb.cc index f1a45ab63..181e50aee 100644 --- a/channels/chan_vpb.cc +++ b/channels/chan_vpb.cc @@ -71,6 +71,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/dsp.h" #include "asterisk/features.h" #include "asterisk/musiconhold.h" +#include "asterisk/format_cache.h" } #include <sys/socket.h> @@ -766,11 +767,10 @@ static void get_callerid_ast(struct vpb_pvt *p) #endif vpb_record_buf_start(p->handle, VPB_MULAW); while ((rc == 0) && (sam_count < 8000 * 3)) { - struct ast_format tmpfmt; vrc = vpb_record_buf_sync(p->handle, (char*)buf, sizeof(buf)); if (vrc != VPB_OK) ast_log(LOG_ERROR, "%s: Caller ID couldn't read audio buffer!\n", p->dev); - rc = callerid_feed(cs, (unsigned char *)buf, sizeof(buf), ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0)); + rc = callerid_feed(cs, (unsigned char *)buf, sizeof(buf), ast_format_ulaw); #ifdef ANALYSE_CID vpb_wave_write(ws, (char *)buf, sizeof(buf)); #endif @@ -2070,46 +2070,41 @@ static struct ast_frame *vpb_read(struct ast_channel *ast) static inline AudioCompress ast2vpbformat(struct ast_format *format) { - switch (format->id) { - case AST_FORMAT_ALAW: + if (ast_format_cmp(format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) { return VPB_ALAW; - case AST_FORMAT_SLINEAR: + } else if (ast_format_cmp(format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) { return VPB_LINEAR; - case AST_FORMAT_ULAW: + } else if (ast_format_cmp(format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) { return VPB_MULAW; - case AST_FORMAT_ADPCM: + } else if (ast_format_cmp(format, ast_format_adpcm) == AST_FORMAT_CMP_EQUAL) { return VPB_OKIADPCM; - default: + } else { return VPB_RAW; } } static inline const char * ast2vpbformatname(struct ast_format *format) { - switch(format->id) { - case AST_FORMAT_ALAW: + if (ast_format_cmp(format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) { return "AST_FORMAT_ALAW:VPB_ALAW"; - case AST_FORMAT_SLINEAR: + } else if (ast_format_cmp(format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) { return "AST_FORMAT_SLINEAR:VPB_LINEAR"; - case AST_FORMAT_ULAW: + } else if (ast_format_cmp(format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) { return "AST_FORMAT_ULAW:VPB_MULAW"; - case AST_FORMAT_ADPCM: + } else if (ast_format_cmp(format, ast_format_adpcm) == AST_FORMAT_CMP_EQUAL) { return "AST_FORMAT_ADPCM:VPB_OKIADPCM"; - default: + } else { return "UNKN:UNKN"; } } static inline int astformatbits(struct ast_format *format) { - switch (format->id) { - case AST_FORMAT_SLINEAR: + if (ast_format_cmp(format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) { return 16; - case AST_FORMAT_ADPCM: + } else if (ast_format_cmp(format, ast_format_adpcm) == AST_FORMAT_CMP_EQUAL) { return 4; - case AST_FORMAT_ALAW: - case AST_FORMAT_ULAW: - default: + } else { return 8; } } @@ -2146,7 +2141,8 @@ static int vpb_write(struct ast_channel *ast, struct ast_frame *frame) /* ast_mutex_unlock(&p->lock); */ return 0; } else if (ast_channel_state(ast) != AST_STATE_UP) { - ast_verb(4, "%s: vpb_write: Attempt to Write frame type[%d]subclass[%s] on not up chan(state[%d])\n", ast_channel_name(ast), frame->frametype, ast_getformatname(&frame->subclass.format), ast_channel_state(ast)); + ast_verb(4, "%s: vpb_write: Attempt to Write frame type[%d]subclass[%s] on not up chan(state[%d])\n", + ast_channel_name(ast), frame->frametype, ast_format_get_name(frame->subclass.format), ast_channel_state(ast)); p->lastoutput = -1; /* ast_mutex_unlock(&p->lock); */ return 0; @@ -2154,9 +2150,10 @@ static int vpb_write(struct ast_channel *ast, struct ast_frame *frame) /* ast_debug(1, "%s: vpb_write: Checked frame type..\n", p->dev); */ - fmt = ast2vpbformat(&frame->subclass.format); + fmt = ast2vpbformat(frame->subclass.format); if (fmt < 0) { - ast_log(LOG_WARNING, "%s: vpb_write: Cannot handle frames of %s format!\n", ast_channel_name(ast), ast_getformatname(&frame->subclass.format)); + ast_log(LOG_WARNING, "%s: vpb_write: Cannot handle frames of %s format!\n", ast_channel_name(ast), + ast_format_get_name(frame->subclass.format)); return -1; } @@ -2180,7 +2177,7 @@ static int vpb_write(struct ast_channel *ast, struct ast_frame *frame) /* Check if we have set up the play_buf */ if (p->lastoutput == -1) { vpb_play_buf_start(p->handle, fmt); - ast_verb(2, "%s: vpb_write: Starting play mode (codec=%d)[%s]\n", p->dev, fmt, ast2vpbformatname(&frame->subclass.format)); + ast_verb(2, "%s: vpb_write: Starting play mode (codec=%d)[%s]\n", p->dev, fmt, ast2vpbformatname(frame->subclass.format)); p->lastoutput = fmt; ast_mutex_unlock(&p->play_lock); return 0; @@ -2230,7 +2227,7 @@ static void *do_chanreads(void *pvt) struct ast_frame *fr = &p->fr; char *readbuf = ((char *)p->buf) + AST_FRIENDLY_OFFSET; int bridgerec = 0; - struct ast_format tmpfmt; + struct ast_format *tmpfmt; int readlen, res, trycnt=0; AudioCompress fmt; int ignore_dtmf; @@ -2315,22 +2312,22 @@ static void *do_chanreads(void *pvt) ast_mutex_unlock(&p->play_dtmf_lock); if (p->owner) { - ast_format_copy(&tmpfmt, ast_channel_rawreadformat(p->owner)); + tmpfmt = ast_channel_rawreadformat(p->owner); } else { - ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0); + tmpfmt = ast_format_slin; } - fmt = ast2vpbformat(&tmpfmt); + fmt = ast2vpbformat(tmpfmt); if (fmt < 0) { - ast_log(LOG_WARNING, "%s: Record failure (unsupported format %s)\n", p->dev, ast_getformatname(&tmpfmt)); + ast_log(LOG_WARNING, "%s: Record failure (unsupported format %s)\n", p->dev, ast_format_get_name(tmpfmt)); return NULL; } - readlen = VPB_SAMPLES * astformatbits(&tmpfmt) / 8; + readlen = VPB_SAMPLES * astformatbits(tmpfmt) / 8; if (p->lastinput == -1) { vpb_record_buf_start(p->handle, fmt); /* vpb_reset_record_fifo_alarm(p->handle); */ p->lastinput = fmt; - ast_verb(2, "%s: Starting record mode (codec=%d)[%s]\n", p->dev, fmt, ast2vpbformatname(&tmpfmt)); + ast_verb(2, "%s: Starting record mode (codec=%d)[%s]\n", p->dev, fmt, ast2vpbformatname(tmpfmt)); continue; } else if (p->lastinput != fmt) { vpb_record_buf_finish(p->handle); @@ -2349,7 +2346,7 @@ static void *do_chanreads(void *pvt) a_gain_vector(p->rxswgain - MAX_VPB_GAIN, (short *)readbuf, readlen / sizeof(short)); ast_verb(6, "%s: chanreads: applied gain\n", p->dev); - ast_format_copy(&fr->subclass.format, &tmpfmt); + fr->subclass.format = tmpfmt; fr->data.ptr = readbuf; fr->datalen = readlen; fr->frametype = AST_FRAME_VOICE; @@ -2429,7 +2426,6 @@ static struct ast_channel *vpb_new(struct vpb_pvt *me, enum ast_channel_state st struct ast_channel *tmp; char cid_num[256]; char cid_name[256]; - struct ast_format tmpfmt; if (me->owner) { ast_log(LOG_WARNING, "Called vpb_new on owned channel (%s) ?!\n", me->dev); @@ -2452,9 +2448,9 @@ static struct ast_channel *vpb_new(struct vpb_pvt *me, enum ast_channel_state st * they are all converted to/from linear in the vpb code. Best for us to use * linear since we can then adjust volume in this modules. */ - ast_format_cap_add(ast_channel_nativeformats(tmp), ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)); - ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt); - ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt); + ast_channel_nativeformats_set(tmp, vpb_tech.capabilities); + ast_channel_set_rawreadformat(tmp, ast_format_slin); + ast_channel_set_rawwriteformat(tmp, ast_format_slin); if (state == AST_STATE_RING) { ast_channel_rings_set(tmp, 1); cid_name[0] = '\0'; @@ -2508,13 +2504,17 @@ static struct ast_channel *vpb_request(const char *type, struct ast_format_cap * char *sepstr, *name; const char *s; int group = -1; - struct ast_format slin; - ast_format_set(&slin, AST_FORMAT_SLINEAR, 0); + if (!(ast_format_cap_iscompatible_format(cap, ast_format_slin))) { + struct ast_str *buf; - if (!(ast_format_cap_iscompatible(cap, &slin))) { - char tmp[256]; - ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap)); + buf = ast_str_create(256); + if (!buf) { + return NULL; + } + ast_log(LOG_NOTICE, "Asked to create a channel for unsupported formats: %s\n", + ast_format_cap_get_names(cap, &buf)); + ast_free(buf); return NULL; } @@ -2636,8 +2636,10 @@ static int unload_module(void) ast_free(bridges); } - ast_format_cap_destroy(vpb_tech.capabilities); - ast_format_cap_destroy(vpb_tech_indicate.capabilities); + ao2_cleanup(vpb_tech.capabilities); + vpb_tech.capabilities = NULL; + ao2_cleanup(vpb_tech_indicate.capabilities); + vpb_tech_indicate.capabilities = NULL; return 0; } @@ -2671,19 +2673,18 @@ static enum ast_module_load_result load_module() int bal2 = -1; int bal3 = -1; char * callerid = NULL; - struct ast_format tmpfmt; int num_cards = 0; - vpb_tech.capabilities = ast_format_cap_alloc((enum ast_format_cap_flags) 0); + vpb_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!vpb_tech.capabilities) { return AST_MODULE_LOAD_DECLINE; } - vpb_tech_indicate.capabilities = ast_format_cap_alloc((enum ast_format_cap_flags) 0); + vpb_tech_indicate.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!vpb_tech_indicate.capabilities) { return AST_MODULE_LOAD_DECLINE; } - ast_format_cap_add(vpb_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)); - ast_format_cap_add(vpb_tech_indicate.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(vpb_tech.capabilities, ast_format_slin, 0); + ast_format_cap_append(vpb_tech_indicate.capabilities, ast_format_slin, 0); try { num_cards = vpb_get_num_cards(); } catch (std::exception e) { diff --git a/channels/dahdi/bridge_native_dahdi.c b/channels/dahdi/bridge_native_dahdi.c index 2f4fd170e..85cb4bfef 100644 --- a/channels/dahdi/bridge_native_dahdi.c +++ b/channels/dahdi/bridge_native_dahdi.c @@ -44,6 +44,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/bridge.h" #include "asterisk/bridge_technology.h" #include "asterisk/frame.h" +#include "asterisk/format_cache.h" /* ------------------------------------------------------------------- */ @@ -892,7 +893,7 @@ static struct ast_bridge_technology native_bridge = { void dahdi_native_unload(void) { ast_bridge_technology_unregister(&native_bridge); - ast_format_cap_destroy(native_bridge.format_capabilities); + ao2_cleanup(native_bridge.format_capabilities); } /*! @@ -905,11 +906,9 @@ void dahdi_native_unload(void) */ int dahdi_native_load(struct ast_module *mod, const struct ast_channel_tech *tech) { - struct ast_format format; - dahdi_tech = tech; - native_bridge.format_capabilities = ast_format_cap_alloc(0); + native_bridge.format_capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!native_bridge.format_capabilities) { return -1; } @@ -918,9 +917,9 @@ int dahdi_native_load(struct ast_module *mod, const struct ast_channel_tech *tec * This is used to make channels compatible with the bridge * itself not with each other. */ - ast_format_cap_add(native_bridge.format_capabilities, ast_format_set(&format, AST_FORMAT_SLINEAR, 0)); - ast_format_cap_add(native_bridge.format_capabilities, ast_format_set(&format, AST_FORMAT_ULAW, 0)); - ast_format_cap_add(native_bridge.format_capabilities, ast_format_set(&format, AST_FORMAT_ALAW, 0)); + ast_format_cap_append(native_bridge.format_capabilities, ast_format_slin, 0); + ast_format_cap_append(native_bridge.format_capabilities, ast_format_ulaw, 0); + ast_format_cap_append(native_bridge.format_capabilities, ast_format_alaw, 0); return __ast_bridge_technology_register(&native_bridge, mod); } diff --git a/channels/iax2/codec_pref.c b/channels/iax2/codec_pref.c new file mode 100644 index 000000000..903dca4cc --- /dev/null +++ b/channels/iax2/codec_pref.c @@ -0,0 +1,333 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Joshua Colp <jcolp@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Media Format Bitfield Compatibility API + * + * \author Joshua Colp <jcolp@digium.com> + */ + +/*** MODULEINFO + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/logger.h" +#include "asterisk/astobj2.h" +#include "asterisk/codec.h" +#include "asterisk/format.h" +#include "asterisk/format_compatibility.h" +#include "asterisk/format_cache.h" +#include "asterisk/format_cap.h" + +#include "include/codec_pref.h" +#include "include/format_compatibility.h" + +void iax2_codec_pref_convert(struct iax2_codec_pref *pref, char *buf, size_t size, int right) +{ + static int differential = (int) 'A'; + int x; + + if (right) { + for (x = 0; x < IAX2_CODEC_PREF_SIZE && x < size; x++) { + if (!pref->order[x]) { + break; + } + + buf[x] = pref->order[x] + differential; + } + + buf[x] = '\0'; + } else { + for (x = 0; x < IAX2_CODEC_PREF_SIZE && x < size; x++) { + if (buf[x] == '\0') { + break; + } + + pref->order[x] = buf[x] - differential; + } + + if (x < size) { + pref->order[x] = 0; + } + } +} + +struct ast_format *iax2_codec_pref_index(struct iax2_codec_pref *pref, int idx, struct ast_format **result) +{ + if ((idx >= 0) && (idx < sizeof(pref->order)) && pref->order[idx]) { + *result = ast_format_compatibility_bitfield2format(pref->order[idx]); + } else { + *result = NULL; + } + + return *result; +} + +void iax2_codec_pref_to_cap(struct iax2_codec_pref *pref, struct ast_format_cap *cap) +{ + int idx; + + for (idx = 0; idx < sizeof(pref->order); idx++) { + if (!pref->order[idx]) { + break; + } + ast_format_cap_append(cap, ast_format_compatibility_bitfield2format(pref->order[idx]), pref->framing[idx]); + } +} + +int iax2_codec_pref_string(struct iax2_codec_pref *pref, char *buf, size_t size) +{ + int x; + struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + size_t total_len; + char *cur; + + if (!cap) { + return -1; + } + + /* This function is useless if you have less than a 6 character buffer. + * '(...)' is six characters. */ + if (size < 6) { + return -1; + } + + /* Convert the preferences into a format cap so that we can read the formst names */ + for (x = 0; x < IAX2_CODEC_PREF_SIZE; x++) { + uint64_t bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[x]); + if (!bitfield) { + break; + } + + iax2_format_compatibility_bitfield2cap(bitfield, cap); + } + + /* We know that at a minimum, 3 characters are used - (, ), and \0 */ + total_len = size - 3; + + memset(buf, 0, size); + + /* This character has already been accounted for total_len purposes */ + buf[0] = '('; + cur = buf + 1; + + /* Loop through the formats and write as many into the buffer as we can */ + for (x = 0; x < ast_format_cap_count(cap); x++) { + size_t name_len; + struct ast_format *fmt = ast_format_cap_get_format(cap, x); + const char *name = ast_format_get_name(fmt); + + name_len = strlen(name); + + /* all entries after the first need a delimiter character */ + if (x) { + name_len++; + } + + /* Terminate the list early if we don't have room for the entry. + * If it's not the last entry in the list, save enough room to write '...'. + */ + if (((x == ast_format_cap_count(cap) - 1) && (total_len < name_len)) || + ((x < ast_format_cap_count(cap) - 1) && (total_len < name_len + 3))) { + strcpy(cur, "..."); + cur += 3; + total_len -= 3; + ao2_ref(fmt, -1); + break; + } + + sprintf(cur, "%s%s", x ? "|" : "", name); + cur += name_len; + total_len -= name_len; + + ao2_ref(fmt, -1); + } + ao2_ref(cap, -1); + + /* These two characters have already been accounted for total_len purposes */ + cur[0] = ')'; + cur[1] = '\0'; + + return size - total_len; +} + +static void codec_pref_remove_index(struct iax2_codec_pref *pref, int codec_pref_index) +{ + int x; + + for (x = codec_pref_index; x < IAX2_CODEC_PREF_SIZE; x++) { + pref->order[x] = pref->order[x + 1]; + pref->framing[x] = pref->framing[x + 1]; + if (!pref->order[x]) { + return; + } + } +} + +/*! \brief Remove codec from pref list */ +static void codec_pref_remove(struct iax2_codec_pref *pref, int format_index) +{ + int x; + + if (!pref->order[0]) { + return; + } + + for (x = 0; x < IAX2_CODEC_PREF_SIZE; x++) { + if (!pref->order[x]) { + break; + } + + if (pref->order[x] == format_index) { + codec_pref_remove_index(pref, x); + break; + } + } +} + +void iax2_codec_pref_remove_missing(struct iax2_codec_pref *pref, uint64_t bitfield) +{ + int x; + + if (!pref->order[0]) { + return; + } + + for (x = 0; x < IAX2_CODEC_PREF_SIZE; x++) { + uint64_t format_as_bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[x]); + if (!pref->order[x]) { + break; + } + + /* If this format isn't in the bitfield, remove it from the prefs. */ + if (!(format_as_bitfield & bitfield)) { + codec_pref_remove_index(pref, x); + } + } +} + +uint64_t iax2_codec_pref_order_value_to_format_bitfield(uint64_t order_value) +{ + if (!order_value) { + return 0; + } + + return 1 << (order_value - 1); +} + +uint64_t iax2_codec_pref_format_bitfield_to_order_value(uint64_t bitfield) +{ + int format_index = 1; + + if (!bitfield) { + return 0; + } + + while (bitfield > 1) { + bitfield = bitfield >> 1; + format_index++; + } + + return format_index; +} + +/*! \brief Append codec to list */ +int iax2_codec_pref_append(struct iax2_codec_pref *pref, struct ast_format *format, unsigned int framing) +{ + uint64_t bitfield = ast_format_compatibility_format2bitfield(format); + int format_index = iax2_codec_pref_format_bitfield_to_order_value(bitfield); + int x; + + codec_pref_remove(pref, format_index); + + for (x = 0; x < IAX2_CODEC_PREF_SIZE; x++) { + if (!pref->order[x]) { + pref->order[x] = format_index; + pref->framing[x] = framing; + break; + } + } + + return x; +} + +/*! \brief Prepend codec to list */ +void iax2_codec_pref_prepend(struct iax2_codec_pref *pref, struct ast_format *format, unsigned int framing, + int only_if_existing) +{ + uint64_t bitfield = ast_format_compatibility_format2bitfield(format); + int x; + + /* Now find any existing occurrence, or the end */ + for (x = 0; x < IAX2_CODEC_PREF_SIZE; x++) { + if (!pref->order[x] || pref->order[x] == bitfield) + break; + } + + /* If we failed to find any occurrence, set to the end */ + if (x == IAX2_CODEC_PREF_SIZE) { + --x; + } + + if (only_if_existing && !pref->order[x]) { + return; + } + + /* Move down to make space to insert - either all the way to the end, + or as far as the existing location (which will be overwritten) */ + for (; x > 0; x--) { + pref->order[x] = pref->order[x - 1]; + pref->framing[x] = pref->framing[x - 1]; + } + + /* And insert the new entry */ + pref->order[0] = bitfield; + pref->framing[0] = framing; +} + +unsigned int iax2_codec_pref_getsize(struct iax2_codec_pref *pref, int idx) +{ + if ((idx >= 0) && (idx < sizeof(pref->order)) && pref->order[idx]) { + return pref->framing[idx]; + } else { + return 0; + } +} + +int iax2_codec_pref_setsize(struct iax2_codec_pref *pref, struct ast_format *format, int framems) +{ + int idx; + + for (idx = 0; idx < sizeof(pref->order); idx++) { + if (!pref->order[idx]) { + break; + } else if (ast_format_cmp(ast_format_compatibility_bitfield2format(pref->order[idx]), + format) != AST_FORMAT_CMP_EQUAL) { + continue; + } + pref->framing[idx] = framems; + return 0; + } + + return -1; +} diff --git a/channels/iax2/format_compatibility.c b/channels/iax2/format_compatibility.c new file mode 100644 index 000000000..8085c2c26 --- /dev/null +++ b/channels/iax2/format_compatibility.c @@ -0,0 +1,73 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Joshua Colp <jcolp@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Media Format Bitfield Compatibility API + * + * \author Joshua Colp <jcolp@digium.com> + */ + +/*** MODULEINFO + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/logger.h" +#include "asterisk/astobj2.h" +#include "asterisk/codec.h" +#include "asterisk/format.h" +#include "asterisk/format_compatibility.h" +#include "asterisk/format_cache.h" +#include "asterisk/format_cap.h" + +#include "include/format_compatibility.h" + +uint64_t iax2_format_compatibility_cap2bitfield(const struct ast_format_cap *cap) +{ + uint64_t bitfield = 0; + int x; + + for (x = 0; x < ast_format_cap_count(cap); x++) { + struct ast_format *format = ast_format_cap_get_format(cap, x); + + bitfield |= ast_format_compatibility_format2bitfield(format); + + ao2_ref(format, -1); + } + + return bitfield; +} + +int iax2_format_compatibility_bitfield2cap(uint64_t bitfield, struct ast_format_cap *cap) +{ + int x; + + for (x = 0; x < 64; x++) { + uint64_t tmp = (1ULL << x); + + if ((tmp & bitfield) && ast_format_cap_append(cap, ast_format_compatibility_bitfield2format(tmp), 0)) { + return -1; + } + } + + return 0; +} diff --git a/channels/iax2/include/codec_pref.h b/channels/iax2/include/codec_pref.h new file mode 100644 index 000000000..bfb889164 --- /dev/null +++ b/channels/iax2/include/codec_pref.h @@ -0,0 +1,123 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Joshua Colp <jcolp@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Media Format Bitfield Compatibility API + * + * \author Joshua Colp <jcolp@digium.com> + */ + +#ifndef _IAX2_CODEC_PREF_H_ +#define _IAX2_CODEC_PREF_H_ + +struct ast_format; +struct ast_codec; +struct ast_format_cap; + +#define IAX2_CODEC_PREF_SIZE 64 +struct iax2_codec_pref { + /*! This array is ordered by preference and contains the codec bitfield. */ + uint64_t order[IAX2_CODEC_PREF_SIZE]; + /*! Framing size of the codec */ + unsigned int framing[IAX2_CODEC_PREF_SIZE]; +}; + +/*! + * \brief Convert an iax2_codec_pref order value into a format bitfield + * + * \param order_value value being converted + * + * \return the bitfield value of the order_value format + */ +uint64_t iax2_codec_pref_order_value_to_format_bitfield(uint64_t order_value); + +/*! + * \brief Convert a format bitfield into an iax2_codec_pref order value + * + * \param bitfield value being converted + * + * \return the iax2_codec_pref order value of the most significant format + * in the bitfield. + * + * \note This is really meant to be used on single format bitfields. + * It will work with multiformat bitfields, but it can only return the + * index of the most significant one if that is the case. + */ +uint64_t iax2_codec_pref_format_bitfield_to_order_value(uint64_t bitfield); + +/*! + * \brief Codec located at a particular place in the preference index. + * \param pref preference structure to get the codec out of + * \param index to retrieve from + * \param result ast_format structure to store the index value in + * \return pointer to input ast_format on success, NULL on failure +*/ +struct ast_format *iax2_codec_pref_index(struct iax2_codec_pref *pref, int index, struct ast_format **result); + +/*! \brief Convert a preference structure to a capabilities structure */ +void iax2_codec_pref_to_cap(struct iax2_codec_pref *pref, struct ast_format_cap *cap); + +/*! \brief Removes format from the pref list that aren't in the bitfield */ +void iax2_codec_pref_remove_missing(struct iax2_codec_pref *pref, uint64_t bitfield); + +/*! + * \brief Dump audio codec preference list into a string + * + * \param pref preference structure to dump string representation of order for + * \param buf character buffer to put string into + * \param size size of the character buffer + * + * \return -1 on error. Otherwise returns the remaining spaaaaaace in the buffer. + * + * \note Format is (codec1|codec2|codec3|...) -- if the list is too long for the + * size of the buffer, codecs will be written until they exceed the length + * remaining in which case the list will be closed with '...)' after the last + * writable codec. + */ +int iax2_codec_pref_string(struct iax2_codec_pref *pref, char *buf, size_t size); + +/*! \brief Append a audio codec to a preference list, removing it first if it was already there +*/ +int iax2_codec_pref_append(struct iax2_codec_pref *pref, struct ast_format *format, unsigned int framing); + +/*! \brief Prepend an audio codec to a preference list, removing it first if it was already there +*/ +void iax2_codec_pref_prepend(struct iax2_codec_pref *pref, struct ast_format *format, unsigned int framing, + int only_if_existing); + +/*! \brief Get packet size for codec +*/ +unsigned int iax2_codec_pref_getsize(struct iax2_codec_pref *pref, int index); + +/*! \brief Set packet size for codec +*/ +int iax2_codec_pref_setsize(struct iax2_codec_pref *pref, struct ast_format *format, int framems); + +/*! \brief Shift an audio codec preference list up or down 65 bytes so that it becomes an ASCII string + * \note Due to a misunderstanding in how codec preferences are stored, this + * list starts at 'B', not 'A'. For backwards compatibility reasons, this + * cannot change. + * \param pref A codec preference list structure + * \param buf A string denoting codec preference, appropriate for use in line transmission + * \param size Size of \a buf + * \param right Boolean: if 0, convert from \a buf to \a pref; if 1, convert from \a pref to \a buf. + */ +void iax2_codec_pref_convert(struct iax2_codec_pref *pref, char *buf, size_t size, int right); + +#endif /* _IAX2_CODEC_PREF_H_ */ diff --git a/channels/iax2/include/format_compatibility.h b/channels/iax2/include/format_compatibility.h new file mode 100644 index 000000000..aa29cfa2c --- /dev/null +++ b/channels/iax2/include/format_compatibility.h @@ -0,0 +1,55 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Joshua Colp <jcolp@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Media Format Bitfield Compatibility API + * + * \author Joshua Colp <jcolp@digium.com> + */ + +#ifndef _IAX2_FORMAT_COMPATIBILITY_H_ +#define _IAX2_FORMAT_COMPATIBILITY_H_ + +struct ast_format; +struct ast_format_cap; + +/*! + * \brief Convert a format capabilities structure to a bitfield + * + * \param cap Capabilities structure containing formats + * + * \retval non-zero success + * \retval zero no formats present or no formats supported + */ +uint64_t iax2_format_compatibility_cap2bitfield(const struct ast_format_cap *cap); + +/*! + * \brief Convert a bitfield to a format capabilities structure + * + * \param bitfield The bitfield for the media formats + * \param cap Capabilities structure to place formats into + * + * \retval non-NULL success + * \retval NULL failure + * + * \note If failure occurs the capabilities structure may contain a partial set of formats + */ +int iax2_format_compatibility_bitfield2cap(uint64_t bitfield, struct ast_format_cap *cap); + +#endif /* _IAX2_FORMAT_COMPATIBILITY_H */ diff --git a/channels/iax2/parser.c b/channels/iax2/parser.c index f5c7ba05d..f1fc8f82d 100644 --- a/channels/iax2/parser.c +++ b/channels/iax2/parser.c @@ -42,10 +42,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/lock.h" #include "asterisk/threadstorage.h" #include "asterisk/netsock2.h" +#include "asterisk/format_cache.h" +#include "asterisk/format_compatibility.h" #include "include/iax2.h" #include "include/parser.h" #include "include/provision.h" +#include "include/codec_pref.h" static int frames = 0; static int iframes = 0; @@ -124,7 +127,7 @@ static void dump_string(char *output, int maxlen, void *value, int len) static void dump_prefs(char *output, int maxlen, void *value, int len) { - struct ast_codec_pref pref; + struct iax2_codec_pref pref; int total_len = 0; maxlen--; @@ -136,9 +139,9 @@ static void dump_prefs(char *output, int maxlen, void *value, int len) strncpy(output, value, maxlen); output[maxlen] = '\0'; - ast_codec_pref_convert(&pref, output, total_len, 0); + iax2_codec_pref_convert(&pref, output, total_len, 0); memset(output,0,total_len); - ast_codec_pref_string(&pref, output, total_len); + iax2_codec_pref_string(&pref, output, total_len); } static void dump_int(char *output, int maxlen, void *value, int len) @@ -1180,7 +1183,8 @@ int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen) void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f) { fr->af.frametype = f->frametype; - ast_format_copy(&fr->af.subclass.format, &f->subclass.format); + fr->af.subclass.format = f->subclass.format; + fr->af.subclass.integer = f->subclass.integer; fr->af.mallocd = 0; /* Our frame is static relative to the container */ fr->af.datalen = f->datalen; fr->af.samples = f->samples; @@ -1199,7 +1203,8 @@ void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f) } #if __BYTE_ORDER == __LITTLE_ENDIAN /* We need to byte-swap slinear samples from network byte order */ - if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass.format.id == AST_FORMAT_SLINEAR)) { + if ((fr->af.frametype == AST_FRAME_VOICE) && + (ast_format_cmp(fr->af.subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) { /* 2 bytes / sample for SLINEAR */ ast_swapcopy_samples(fr->af.data.ptr, f->data.ptr, copy_len / 2); } else diff --git a/channels/iax2/provision.c b/channels/iax2/provision.c index 78e0b1b3d..85dfe9448 100644 --- a/channels/iax2/provision.c +++ b/channels/iax2/provision.c @@ -45,6 +45,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/astdb.h" #include "asterisk/utils.h" #include "asterisk/acl.h" +#include "asterisk/format_cache.h" +#include "asterisk/format_compatibility.h" #include "include/iax2.h" #include "include/provision.h" @@ -345,9 +347,10 @@ static int iax_template_parse(struct iax_template *cur, struct ast_config *cfg, } else ast_log(LOG_WARNING, "Ignoring invalid %s '%s' for '%s' at line %d\n", v->name, v->value, s, v->lineno); } else if (!strcasecmp(v->name, "codec")) { - struct ast_format tmpfmt; - if ((ast_getformatbyname(v->value, &tmpfmt)) > 0) { - cur->format = ast_format_to_old_bitfield(&tmpfmt); + struct ast_format *tmpfmt; + if ((tmpfmt = ast_format_cache_get(v->value))) { + cur->format = ast_format_compatibility_format2bitfield(tmpfmt); + ao2_ref(tmpfmt, -1); } else ast_log(LOG_WARNING, "Ignoring invalid codec '%s' for '%s' at line %d\n", v->value, s, v->lineno); } else if (!strcasecmp(v->name, "tos")) { diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index c50dbf3fc..054552b5a 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -806,35 +806,32 @@ int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char } static int media_offer_read_av(struct ast_sip_session *session, char *buf, - size_t len, enum ast_format_type media_type) + size_t len, enum ast_media_type media_type) { int i, size = 0; - struct ast_format fmt; - const char *name; - for (i = 0; ast_codec_pref_index(&session->override_prefs, i, &fmt); ++i) { - if (AST_FORMAT_GET_TYPE(fmt.id) != media_type) { - continue; - } + for (i = 0; i < ast_format_cap_count(session->req_caps); i++) { + struct ast_format *fmt = ast_format_cap_get_format(session->req_caps, i); - name = ast_getformatname(&fmt); - - if (ast_strlen_zero(name)) { - ast_log(LOG_WARNING, "PJSIP_MEDIA_OFFER unrecognized format %s\n", name); + if (ast_format_get_type(fmt) != media_type) { + ao2_ref(fmt, -1); continue; } /* add one since we'll include a comma */ - size = strlen(name) + 1; + size = strlen(ast_format_get_name(fmt)) + 1; len -= size; if ((len) < 0) { + ao2_ref(fmt, -1); break; } /* no reason to use strncat here since we have already ensured buf has enough space, so strcat can be safely used */ - strcat(buf, name); + strcat(buf, ast_format_get_name(fmt)); strcat(buf, ","); + + ao2_ref(fmt, -1); } if (size) { @@ -846,23 +843,16 @@ static int media_offer_read_av(struct ast_sip_session *session, char *buf, struct media_offer_data { struct ast_sip_session *session; - enum ast_format_type media_type; + enum ast_media_type media_type; const char *value; }; static int media_offer_write_av(void *obj) { struct media_offer_data *data = obj; - int i; - struct ast_format fmt; - /* remove all of the given media type first */ - for (i = 0; ast_codec_pref_index(&data->session->override_prefs, i, &fmt); ++i) { - if (AST_FORMAT_GET_TYPE(fmt.id) == data->media_type) { - ast_codec_pref_remove(&data->session->override_prefs, &fmt); - } - } - ast_format_cap_remove_bytype(data->session->req_caps, data->media_type); - ast_parse_allow_disallow(&data->session->override_prefs, data->session->req_caps, data->value, 1); + + ast_format_cap_remove_by_type(data->session->req_caps, data->media_type); + ast_format_cap_update_by_allow_disallow(data->session->req_caps, data->value, 1); return 0; } @@ -879,9 +869,9 @@ int pjsip_acf_media_offer_read(struct ast_channel *chan, const char *cmd, char * channel = ast_channel_tech_pvt(chan); if (!strcmp(data, "audio")) { - return media_offer_read_av(channel->session, buf, len, AST_FORMAT_TYPE_AUDIO); + return media_offer_read_av(channel->session, buf, len, AST_MEDIA_TYPE_AUDIO); } else if (!strcmp(data, "video")) { - return media_offer_read_av(channel->session, buf, len, AST_FORMAT_TYPE_VIDEO); + return media_offer_read_av(channel->session, buf, len, AST_MEDIA_TYPE_VIDEO); } return 0; @@ -903,9 +893,9 @@ int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char mdata.session = channel->session; if (!strcmp(data, "audio")) { - mdata.media_type = AST_FORMAT_TYPE_AUDIO; + mdata.media_type = AST_MEDIA_TYPE_AUDIO; } else if (!strcmp(data, "video")) { - mdata.media_type = AST_FORMAT_TYPE_VIDEO; + mdata.media_type = AST_MEDIA_TYPE_VIDEO; } return ast_sip_push_task_synchronous(channel->session->serializer, media_offer_write_av, &mdata); diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index 11078d5b7..8ce63ee9d 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -1082,7 +1082,6 @@ struct sip_pvt { int timer_b; /*!< SIP timer B, ms */ unsigned int sipoptions; /*!< Supported SIP options on the other end */ unsigned int reqsipoptions; /*!< Required SIP options on the other end */ - struct ast_codec_pref prefs; /*!< codec prefs */ struct ast_format_cap *caps; /*!< Special capability (codec) */ struct ast_format_cap *jointcaps; /*!< Supported capability at both ends (codecs) */ struct ast_format_cap *peercaps; /*!< Supported peer capability */ @@ -1310,7 +1309,6 @@ struct sip_peer { int busy_level; /*!< Level of active channels where we signal busy */ int maxforwards; /*!< SIP Loop prevention */ enum transfermodes allowtransfer; /*! SIP Refer restriction scheme */ - struct ast_codec_pref prefs; /*!< codec prefs */ int lastmsgssent; /*!< The last known VM message counts (new/old) */ unsigned int sipoptions; /*!< Supported SIP options */ struct ast_flags flags[3]; /*!< SIP_ flags */ diff --git a/codecs/codec_a_mu.c b/codecs/codec_a_mu.c index 470f363e7..c21c706f5 100644 --- a/codecs/codec_a_mu.c +++ b/codecs/codec_a_mu.c @@ -80,6 +80,17 @@ static int ulawtoalaw_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) static struct ast_translator alawtoulaw = { .name = "alawtoulaw", + .src_codec = { + .name = "alaw", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "ulaw", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "ulaw", .framein = alawtoulaw_framein, .sample = alaw_sample, .buffer_samples = BUFFER_SAMPLES, @@ -88,6 +99,17 @@ static struct ast_translator alawtoulaw = { static struct ast_translator ulawtoalaw = { .name = "ulawtoalaw", + .src_codec = { + .name = "ulaw", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "alaw", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "alaw", .framein = ulawtoalaw_framein, .sample = ulaw_sample, .buffer_samples = BUFFER_SAMPLES, @@ -111,23 +133,19 @@ static int load_module(void) int res; int x; - ast_format_set(&alawtoulaw.src_format, AST_FORMAT_ALAW, 0); - ast_format_set(&alawtoulaw.dst_format, AST_FORMAT_ULAW, 0); - - ast_format_set(&ulawtoalaw.src_format, AST_FORMAT_ULAW, 0); - ast_format_set(&ulawtoalaw.dst_format, AST_FORMAT_ALAW, 0); - for (x=0;x<256;x++) { mu2a[x] = AST_LIN2A(AST_MULAW(x)); a2mu[x] = AST_LIN2MU(AST_ALAW(x)); } + res = ast_register_translator(&alawtoulaw); - if (!res) - res = ast_register_translator(&ulawtoalaw); - else - ast_unregister_translator(&alawtoulaw); - if (res) + res |= ast_register_translator(&ulawtoalaw); + + if (res) { + unload_module(); return AST_MODULE_LOAD_FAILURE; + } + return AST_MODULE_LOAD_SUCCESS; } diff --git a/codecs/codec_adpcm.c b/codecs/codec_adpcm.c index c48eb1ab2..03d2a4ab3 100644 --- a/codecs/codec_adpcm.c +++ b/codecs/codec_adpcm.c @@ -290,6 +290,17 @@ static struct ast_frame *lintoadpcm_frameout(struct ast_trans_pvt *pvt) static struct ast_translator adpcmtolin = { .name = "adpcmtolin", + .src_codec = { + .name = "adpcm", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "slin", .framein = adpcmtolin_framein, .sample = adpcm_sample, .desc_size = sizeof(struct adpcm_decoder_pvt), @@ -299,6 +310,17 @@ static struct ast_translator adpcmtolin = { static struct ast_translator lintoadpcm = { .name = "lintoadpcm", + .src_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "adpcm", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "adpcm", .framein = lintoadpcm_framein, .frameout = lintoadpcm_frameout, .sample = slin8_sample, @@ -307,12 +329,6 @@ static struct ast_translator lintoadpcm = { .buf_size = BUFFER_SAMPLES/ 2, /* 2 samples per byte */ }; -/*! \brief standard module glue */ -static int reload(void) -{ - return AST_MODULE_LOAD_SUCCESS; -} - static int unload_module(void) { int res; @@ -325,26 +341,20 @@ static int unload_module(void) static int load_module(void) { - int res; - - ast_format_set(&adpcmtolin.src_format, AST_FORMAT_ADPCM, 0); - ast_format_set(&adpcmtolin.dst_format, AST_FORMAT_SLINEAR, 0); - - ast_format_set(&lintoadpcm.src_format, AST_FORMAT_SLINEAR, 0); - ast_format_set(&lintoadpcm.dst_format, AST_FORMAT_ADPCM, 0); + int res = 0; res = ast_register_translator(&adpcmtolin); - if (!res) - res = ast_register_translator(&lintoadpcm); - else - ast_unregister_translator(&adpcmtolin); - if (res) + res |= ast_register_translator(&lintoadpcm); + + if (res) { + unload_module(); return AST_MODULE_LOAD_FAILURE; + } + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Adaptive Differential PCM Coder/Decoder", .load = load_module, .unload = unload_module, - .reload = reload, ); diff --git a/codecs/codec_alaw.c b/codecs/codec_alaw.c index 34a71388e..2ca577d7f 100644 --- a/codecs/codec_alaw.c +++ b/codecs/codec_alaw.c @@ -77,6 +77,17 @@ static int lintoalaw_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) static struct ast_translator alawtolin = { .name = "alawtolin", + .src_codec = { + .name = "alaw", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "slin", .framein = alawtolin_framein, .sample = alaw_sample, .buffer_samples = BUFFER_SAMPLES, @@ -84,20 +95,24 @@ static struct ast_translator alawtolin = { }; static struct ast_translator lintoalaw = { - "lintoalaw", + .name = "lintoalaw", + .src_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "alaw", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "alaw", .framein = lintoalaw_framein, .sample = slin8_sample, .buffer_samples = BUFFER_SAMPLES, .buf_size = BUFFER_SAMPLES, }; -/*! \brief standard module stuff */ - -static int reload(void) -{ - return AST_MODULE_LOAD_SUCCESS; -} - static int unload_module(void) { int res; @@ -112,24 +127,18 @@ static int load_module(void) { int res; - ast_format_set(&lintoalaw.src_format, AST_FORMAT_SLINEAR, 0); - ast_format_set(&lintoalaw.dst_format, AST_FORMAT_ALAW, 0); - - ast_format_set(&alawtolin.src_format, AST_FORMAT_ALAW, 0); - ast_format_set(&alawtolin.dst_format, AST_FORMAT_SLINEAR, 0); - res = ast_register_translator(&alawtolin); - if (!res) - res = ast_register_translator(&lintoalaw); - else - ast_unregister_translator(&alawtolin); - if (res) + res |= ast_register_translator(&lintoalaw); + + if (res) { + unload_module(); return AST_MODULE_LOAD_FAILURE; + } + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "A-law Coder/Decoder", .load = load_module, .unload = unload_module, - .reload = reload, ); diff --git a/codecs/codec_dahdi.c b/codecs/codec_dahdi.c index caaf99cdf..64f220eef 100644 --- a/codecs/codec_dahdi.c +++ b/codecs/codec_dahdi.c @@ -51,6 +51,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/linkedlists.h" #include "asterisk/ulaw.h" +#include "asterisk/format_compatibility.h" #define BUFFER_SIZE 8000 @@ -58,17 +59,29 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define G729_SAMPLES 160 #define ULAW_SAMPLES 160 +/* Defines from DAHDI. */ #ifndef DAHDI_FORMAT_MAX_AUDIO +/*! G.723.1 compression */ #define DAHDI_FORMAT_G723_1 (1 << 0) +/*! GSM compression */ #define DAHDI_FORMAT_GSM (1 << 1) +/*! Raw mu-law data (G.711) */ #define DAHDI_FORMAT_ULAW (1 << 2) +/*! Raw A-law data (G.711) */ #define DAHDI_FORMAT_ALAW (1 << 3) +/*! ADPCM (G.726, 32kbps) */ #define DAHDI_FORMAT_G726 (1 << 4) +/*! ADPCM (IMA) */ #define DAHDI_FORMAT_ADPCM (1 << 5) +/*! Raw 16-bit Signed Linear (8000 Hz) PCM */ #define DAHDI_FORMAT_SLINEAR (1 << 6) +/*! LPC10, 180 samples/frame */ #define DAHDI_FORMAT_LPC10 (1 << 7) +/*! G.729A audio */ #define DAHDI_FORMAT_G729A (1 << 8) +/*! SpeeX Free Compression */ #define DAHDI_FORMAT_SPEEX (1 << 9) +/*! iLBC Free Compression */ #define DAHDI_FORMAT_ILBC (1 << 10) #endif @@ -78,6 +91,233 @@ static struct channel_usage { int decoders; } channels; +#if defined(NOT_NEEDED) +/*! + * \internal + * \brief Convert DAHDI format bitfield to old Asterisk format bitfield. + * \since 13.0.0 + * + * \param dahdi Bitfield from DAHDI to convert. + * + * \note They should be the same values but they don't have to be. + * + * \return Old Asterisk bitfield equivalent. + */ +static uint64_t bitfield_dahdi2ast(unsigned dahdi) +{ + uint64_t ast; + + switch (dahdi) { + case DAHDI_FORMAT_G723_1: + ast = AST_FORMAT_G723; + break; + case DAHDI_FORMAT_GSM: + ast = AST_FORMAT_GSM; + break; + case DAHDI_FORMAT_ULAW: + ast = AST_FORMAT_ULAW; + break; + case DAHDI_FORMAT_ALAW: + ast = AST_FORMAT_ALAW; + break; + case DAHDI_FORMAT_G726: + ast = AST_FORMAT_G726_AAL2; + break; + case DAHDI_FORMAT_ADPCM: + ast = AST_FORMAT_ADPCM; + break; + case DAHDI_FORMAT_SLINEAR: + ast = AST_FORMAT_SLIN; + break; + case DAHDI_FORMAT_LPC10: + ast = AST_FORMAT_LPC10; + break; + case DAHDI_FORMAT_G729A: + ast = AST_FORMAT_G729; + break; + case DAHDI_FORMAT_SPEEX: + ast = AST_FORMAT_SPEEX; + break; + case DAHDI_FORMAT_ILBC: + ast = AST_FORMAT_ILBC; + break; + default: + ast = 0; + break; + } + + return ast; +} +#endif /* defined(NOT_NEEDED) */ + +/*! + * \internal + * \brief Convert old Asterisk format bitfield to DAHDI format bitfield. + * \since 13.0.0 + * + * \param ast Old Asterisk bitfield to convert. + * + * \note They should be the same values but they don't have to be. + * + * \return DAHDI bitfield equivalent. + */ +static unsigned bitfield_ast2dahdi(uint64_t ast) +{ + unsigned dahdi; + + switch (ast) { + case AST_FORMAT_G723: + dahdi = DAHDI_FORMAT_G723_1; + break; + case AST_FORMAT_GSM: + dahdi = DAHDI_FORMAT_GSM; + break; + case AST_FORMAT_ULAW: + dahdi = DAHDI_FORMAT_ULAW; + break; + case AST_FORMAT_ALAW: + dahdi = DAHDI_FORMAT_ALAW; + break; + case AST_FORMAT_G726_AAL2: + dahdi = DAHDI_FORMAT_G726; + break; + case AST_FORMAT_ADPCM: + dahdi = DAHDI_FORMAT_ADPCM; + break; + case AST_FORMAT_SLIN: + dahdi = DAHDI_FORMAT_SLINEAR; + break; + case AST_FORMAT_LPC10: + dahdi = DAHDI_FORMAT_LPC10; + break; + case AST_FORMAT_G729: + dahdi = DAHDI_FORMAT_G729A; + break; + case AST_FORMAT_SPEEX: + dahdi = DAHDI_FORMAT_SPEEX; + break; + case AST_FORMAT_ILBC: + dahdi = DAHDI_FORMAT_ILBC; + break; + default: + dahdi = 0; + break; + } + + return dahdi; +} + +/*! + * \internal + * \brief Get the DAHDI codec by index. + * \since 13.0.0 + * + * \param idx Codex index (0-31). + * + * \return Specified codec if exists otherwise NULL. + */ +static const struct ast_codec *get_dahdi_codec(unsigned idx) +{ + const struct ast_codec *codec; + + static const struct ast_codec dahdi_g723_1 = { + .name = "g723", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }; + static const struct ast_codec dahdi_gsm = { + .name = "gsm", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }; + static const struct ast_codec dahdi_ulaw = { + .name = "ulaw", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }; + static const struct ast_codec dahdi_alaw = { + .name = "alaw", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }; + static const struct ast_codec dahdi_g726 = { + .name = "g726", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }; + static const struct ast_codec dahdi_adpcm = { + .name = "adpcm", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }; + static const struct ast_codec dahdi_slinear = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }; + static const struct ast_codec dahdi_lpc10 = { + .name = "lpc10", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }; + static const struct ast_codec dahdi_g729a = { + .name = "g729", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }; + static const struct ast_codec dahdi_speex = { + .name = "speex", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }; + static const struct ast_codec dahdi_ilbc = { + .name = "ilbc", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }; + + switch (1UL << idx) { + case DAHDI_FORMAT_G723_1: + codec = &dahdi_g723_1; + break; + case DAHDI_FORMAT_GSM: + codec = &dahdi_gsm; + break; + case DAHDI_FORMAT_ULAW: + codec = &dahdi_ulaw; + break; + case DAHDI_FORMAT_ALAW: + codec = &dahdi_alaw; + break; + case DAHDI_FORMAT_G726: + codec = &dahdi_g726; + break; + case DAHDI_FORMAT_ADPCM: + codec = &dahdi_adpcm; + break; + case DAHDI_FORMAT_SLINEAR: + codec = &dahdi_slinear; + break; + case DAHDI_FORMAT_LPC10: + codec = &dahdi_lpc10; + break; + case DAHDI_FORMAT_G729A: + codec = &dahdi_g729a; + break; + case DAHDI_FORMAT_SPEEX: + codec = &dahdi_speex; + break; + case DAHDI_FORMAT_ILBC: + codec = &dahdi_ilbc; + break; + default: + codec = NULL; + break; + } + + return codec; +} + static char *handle_cli_transcoder_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); static struct ast_cli_entry cli[] = { @@ -190,7 +430,7 @@ static int dahdi_encoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) { struct codec_dahdi_pvt *dahdip = pvt->pvt; - if (!f->subclass.format.id) { + if (!f->subclass.format) { /* We're just faking a return for calculation purposes. */ dahdip->fake = 2; pvt->samples = f->samples; @@ -245,18 +485,16 @@ static struct ast_frame *dahdi_encoder_frameout(struct ast_trans_pvt *pvt) int res; if (2 == dahdip->fake) { + struct ast_frame frm = { + .frametype = AST_FRAME_VOICE, + .samples = dahdip->required_samples, + .src = pvt->t->name, + }; + dahdip->fake = 1; - pvt->f.frametype = AST_FRAME_VOICE; - ast_format_clear(&pvt->f.subclass.format); - pvt->f.samples = dahdip->required_samples; - pvt->f.data.ptr = NULL; - pvt->f.offset = 0; - pvt->f.datalen = 0; - pvt->f.mallocd = 0; pvt->samples = 0; - return ast_frisolate(&pvt->f); - + return ast_frisolate(&frm); } else if (1 == dahdip->fake) { dahdip->fake = 0; return NULL; @@ -277,13 +515,7 @@ static struct ast_frame *dahdi_encoder_frameout(struct ast_trans_pvt *pvt) } } else { pvt->f.datalen = res; - pvt->f.frametype = AST_FRAME_VOICE; - ast_format_copy(&pvt->f.subclass.format, &pvt->t->dst_format); - pvt->f.mallocd = 0; - pvt->f.offset = AST_FRIENDLY_OFFSET; - pvt->f.src = pvt->t->name; - pvt->f.data.ptr = pvt->outbuf.c; - pvt->f.samples = ast_codec_get_samples(&pvt->f); + pvt->f.samples = ast_codec_samples_count(&pvt->f); dahdip->samples_written_to_hardware = (dahdip->samples_written_to_hardware >= pvt->f.samples) ? @@ -302,7 +534,7 @@ static int dahdi_decoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) { struct codec_dahdi_pvt *dahdip = pvt->pvt; - if (!f->subclass.format.id) { + if (!f->subclass.format) { /* We're just faking a return for calculation purposes. */ dahdip->fake = 2; pvt->samples = f->samples; @@ -327,16 +559,16 @@ static struct ast_frame *dahdi_decoder_frameout(struct ast_trans_pvt *pvt) struct codec_dahdi_pvt *dahdip = pvt->pvt; if (2 == dahdip->fake) { + struct ast_frame frm = { + .frametype = AST_FRAME_VOICE, + .samples = dahdip->required_samples, + .src = pvt->t->name, + }; + dahdip->fake = 1; - pvt->f.frametype = AST_FRAME_VOICE; - ast_format_clear(&pvt->f.subclass.format); - pvt->f.samples = dahdip->required_samples; - pvt->f.data.ptr = NULL; - pvt->f.offset = 0; - pvt->f.datalen = 0; - pvt->f.mallocd = 0; pvt->samples = 0; - return ast_frisolate(&pvt->f); + + return ast_frisolate(&frm); } else if (1 == dahdip->fake) { pvt->samples = 0; dahdip->fake = 0; @@ -370,12 +602,6 @@ static struct ast_frame *dahdi_decoder_frameout(struct ast_trans_pvt *pvt) pvt->f.datalen = res; } pvt->datalen = 0; - pvt->f.frametype = AST_FRAME_VOICE; - ast_format_copy(&pvt->f.subclass.format, &pvt->t->dst_format); - pvt->f.mallocd = 0; - pvt->f.offset = AST_FRIENDLY_OFFSET; - pvt->f.src = pvt->t->name; - pvt->f.data.ptr = pvt->outbuf.c; pvt->f.samples = res; pvt->samples = 0; dahdip->samples_written_to_hardware = @@ -394,9 +620,9 @@ static void dahdi_destroy(struct ast_trans_pvt *pvt) { struct codec_dahdi_pvt *dahdip = pvt->pvt; - switch (ast_format_id_from_old_bitfield(dahdip->fmts.dstfmt)) { - case AST_FORMAT_G729A: - case AST_FORMAT_G723_1: + switch (dahdip->fmts.dstfmt) { + case DAHDI_FORMAT_G729A: + case DAHDI_FORMAT_G723_1: ast_atomic_fetchadd_int(&channels.encoders, -1); break; default: @@ -407,7 +633,39 @@ static void dahdi_destroy(struct ast_trans_pvt *pvt) close(dahdip->fd); } -static int dahdi_translate(struct ast_trans_pvt *pvt, struct ast_format *dst_format, struct ast_format *src_format) +static struct ast_format *dahdi_format_to_cached(int format) +{ + switch (format) { + case DAHDI_FORMAT_G723_1: + return ast_format_g723; + case DAHDI_FORMAT_GSM: + return ast_format_gsm; + case DAHDI_FORMAT_ULAW: + return ast_format_ulaw; + case DAHDI_FORMAT_ALAW: + return ast_format_alaw; + case DAHDI_FORMAT_G726: + return ast_format_g726; + case DAHDI_FORMAT_ADPCM: + return ast_format_adpcm; + case DAHDI_FORMAT_SLINEAR: + return ast_format_slin; + case DAHDI_FORMAT_LPC10: + return ast_format_lpc10; + case DAHDI_FORMAT_G729A: + return ast_format_g729; + case DAHDI_FORMAT_SPEEX: + return ast_format_speex; + case DAHDI_FORMAT_ILBC: + return ast_format_ilbc; + } + + /* This will never be reached */ + ast_assert(0); + return NULL; +} + +static int dahdi_translate(struct ast_trans_pvt *pvt, struct ast_codec *dst_codec, struct ast_codec *src_codec) { /* Request translation through zap if possible */ int fd; @@ -421,10 +679,13 @@ static int dahdi_translate(struct ast_trans_pvt *pvt, struct ast_format *dst_for return -1; } - dahdip->fmts.srcfmt = ast_format_to_old_bitfield(src_format); - dahdip->fmts.dstfmt = ast_format_to_old_bitfield(dst_format); + dahdip->fmts.srcfmt = bitfield_ast2dahdi(ast_format_compatibility_codec2bitfield(src_codec)); + dahdip->fmts.dstfmt = bitfield_ast2dahdi(ast_format_compatibility_codec2bitfield(dst_codec)); + + ast_assert(pvt->f.subclass.format == NULL); + pvt->f.subclass.format = ao2_bump(dahdi_format_to_cached(dahdip->fmts.dstfmt)); - ast_debug(1, "Opening transcoder channel from %s to %s.\n", ast_getformatname(src_format), ast_getformatname(dst_format)); + ast_debug(1, "Opening transcoder channel from %s to %s.\n", src_codec->name, dst_codec->name); retry: if (ioctl(fd, DAHDI_TC_ALLOCATE, &dahdip->fmts)) { @@ -437,14 +698,14 @@ retry: * support for ULAW instead of signed linear and then * we'll just convert from ulaw to signed linear in * software. */ - if (AST_FORMAT_SLINEAR == ast_format_id_from_old_bitfield(dahdip->fmts.srcfmt)) { + if (dahdip->fmts.srcfmt == DAHDI_FORMAT_SLINEAR) { ast_debug(1, "Using soft_slin support on source\n"); dahdip->softslin = 1; - dahdip->fmts.srcfmt = ast_format_id_to_old_bitfield(AST_FORMAT_ULAW); - } else if (AST_FORMAT_SLINEAR == ast_format_id_from_old_bitfield(dahdip->fmts.dstfmt)) { + dahdip->fmts.srcfmt = DAHDI_FORMAT_ULAW; + } else if (dahdip->fmts.dstfmt == DAHDI_FORMAT_SLINEAR) { ast_debug(1, "Using soft_slin support on destination\n"); dahdip->softslin = 1; - dahdip->fmts.dstfmt = ast_format_id_to_old_bitfield(AST_FORMAT_ULAW); + dahdip->fmts.dstfmt = DAHDI_FORMAT_ULAW; } tried_once = 1; goto retry; @@ -463,13 +724,13 @@ retry: dahdip->fd = fd; - dahdip->required_samples = ((dahdip->fmts.dstfmt|dahdip->fmts.srcfmt) & (ast_format_id_to_old_bitfield(AST_FORMAT_G723_1))) ? G723_SAMPLES : G729_SAMPLES; + dahdip->required_samples = ((dahdip->fmts.dstfmt|dahdip->fmts.srcfmt) & (DAHDI_FORMAT_G723_1)) ? G723_SAMPLES : G729_SAMPLES; - switch (ast_format_id_from_old_bitfield(dahdip->fmts.dstfmt)) { - case AST_FORMAT_G729A: + switch (dahdip->fmts.dstfmt) { + case DAHDI_FORMAT_G729A: ast_atomic_fetchadd_int(&channels.encoders, +1); break; - case AST_FORMAT_G723_1: + case DAHDI_FORMAT_G723_1: ast_atomic_fetchadd_int(&channels.encoders, +1); break; default: @@ -483,8 +744,8 @@ retry: static int dahdi_new(struct ast_trans_pvt *pvt) { return dahdi_translate(pvt, - &pvt->t->dst_format, - &pvt->t->src_format); + pvt->t->core_dst_codec, + pvt->t->core_src_codec); } static struct ast_frame *fakesrc_sample(void) @@ -501,33 +762,37 @@ static struct ast_frame *fakesrc_sample(void) static int is_encoder(struct translator *zt) { - if ((zt->t.src_format.id == AST_FORMAT_ULAW) || - (zt->t.src_format.id == AST_FORMAT_ALAW) || - (zt->t.src_format.id == AST_FORMAT_SLINEAR)) { + if ((zt->t.core_src_codec->id == ast_format_get_codec_id(ast_format_ulaw)) || + (zt->t.core_src_codec->id == ast_format_get_codec_id(ast_format_alaw)) || + (zt->t.core_src_codec->id == ast_format_get_codec_id(ast_format_slin))) { return 1; } else { return 0; } } -static int register_translator(int dst, int src) +static int register_translator(unsigned dst, unsigned src) { + const struct ast_codec *dst_codec; + const struct ast_codec *src_codec; struct translator *zt; int res; - struct ast_format dst_format; - struct ast_format src_format; - ast_format_from_old_bitfield(&dst_format, (1 << dst)); - ast_format_from_old_bitfield(&src_format, (1 << src)); + dst_codec = get_dahdi_codec(dst); + src_codec = get_dahdi_codec(src); + if (!dst_codec || !src_codec) { + return -1; + } if (!(zt = ast_calloc(1, sizeof(*zt)))) { return -1; } - snprintf((char *) (zt->t.name), sizeof(zt->t.name), "zap%sto%s", - ast_getformatname(&src_format), ast_getformatname(&dst_format)); - ast_format_copy(&zt->t.src_format, &src_format); - ast_format_copy(&zt->t.dst_format, &dst_format); + snprintf(zt->t.name, sizeof(zt->t.name), "dahdi_%s_to_%s", + src_codec->name, dst_codec->name); + + memcpy(&zt->t.src_codec, src_codec, sizeof(*src_codec)); + memcpy(&zt->t.dst_codec, dst_codec, sizeof(*dst_codec)); zt->t.buf_size = BUFFER_SIZE; if (is_encoder(zt)) { zt->t.framein = dahdi_encoder_framein; @@ -557,17 +822,20 @@ static int register_translator(int dst, int src) return res; } -static void drop_translator(int dst, int src) +static void drop_translator(unsigned dst, unsigned src) { struct translator *cur; AST_LIST_LOCK(&translators); AST_LIST_TRAVERSE_SAFE_BEGIN(&translators, cur, entry) { - if (cur->t.src_format.id != ast_format_id_from_old_bitfield((1 << src))) + if (bitfield_ast2dahdi(ast_format_compatibility_codec2bitfield(cur->t.core_src_codec)) + != (1U << src)) { continue; - - if (cur->t.dst_format.id != ast_format_id_from_old_bitfield((1 << dst))) + } + if (bitfield_ast2dahdi(ast_format_compatibility_codec2bitfield(cur->t.core_dst_codec)) + != (1U << dst)) { continue; + } AST_LIST_REMOVE_CURRENT(entry); ast_unregister_translator(&cur->t); @@ -678,7 +946,6 @@ static int unload_module(void) static int load_module(void) { - ast_ulaw_init(); find_transcoders(); ast_cli_register_multiple(cli, ARRAY_LEN(cli)); return AST_MODULE_LOAD_SUCCESS; diff --git a/codecs/codec_g722.c b/codecs/codec_g722.c index 89641f175..1eba8067f 100644 --- a/codecs/codec_g722.c +++ b/codecs/codec_g722.c @@ -138,6 +138,17 @@ static int lintog722_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) static struct ast_translator g722tolin = { .name = "g722tolin", + .src_codec = { + .name = "g722", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + }, + .dst_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "slin", .newpvt = g722tolin_new, /* same for both directions */ .framein = g722tolin_framein, .sample = g722_sample, @@ -148,6 +159,17 @@ static struct ast_translator g722tolin = { static struct ast_translator lintog722 = { .name = "lintog722", + .src_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "g722", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + }, + .format = "g722", .newpvt = lintog722_new, /* same for both directions */ .framein = lintog722_framein, .sample = slin8_sample, @@ -158,6 +180,17 @@ static struct ast_translator lintog722 = { static struct ast_translator g722tolin16 = { .name = "g722tolin16", + .src_codec = { + .name = "g722", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + }, + .dst_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + }, + .format = "slin16", .newpvt = g722tolin16_new, /* same for both directions */ .framein = g722tolin_framein, .sample = g722_sample, @@ -168,6 +201,17 @@ static struct ast_translator g722tolin16 = { static struct ast_translator lin16tog722 = { .name = "lin16tog722", + .src_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + }, + .dst_codec = { + .name = "g722", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + }, + .format = "g722", .newpvt = lin16tog722_new, /* same for both directions */ .framein = lintog722_framein, .sample = slin16_sample, @@ -176,11 +220,6 @@ static struct ast_translator lin16tog722 = { .buf_size = BUFFER_SAMPLES, }; -static int reload(void) -{ - return AST_MODULE_LOAD_SUCCESS; -} - static int unload_module(void) { int res = 0; @@ -197,18 +236,6 @@ static int load_module(void) { int res = 0; - ast_format_set(&g722tolin.src_format, AST_FORMAT_G722, 0); - ast_format_set(&g722tolin.dst_format, AST_FORMAT_SLINEAR, 0); - - ast_format_set(&lintog722.src_format, AST_FORMAT_SLINEAR, 0); - ast_format_set(&lintog722.dst_format, AST_FORMAT_G722, 0); - - ast_format_set(&g722tolin16.src_format, AST_FORMAT_G722, 0); - ast_format_set(&g722tolin16.dst_format, AST_FORMAT_SLINEAR16, 0); - - ast_format_set(&lin16tog722.src_format, AST_FORMAT_SLINEAR16, 0); - ast_format_set(&lin16tog722.dst_format, AST_FORMAT_G722, 0); - res |= ast_register_translator(&g722tolin); res |= ast_register_translator(&lintog722); res |= ast_register_translator(&g722tolin16); @@ -225,5 +252,4 @@ static int load_module(void) AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ITU G.722-64kbps G722 Transcoder", .load = load_module, .unload = unload_module, - .reload = reload, ); diff --git a/codecs/codec_g726.c b/codecs/codec_g726.c index 72e77f955..a41039d53 100644 --- a/codecs/codec_g726.c +++ b/codecs/codec_g726.c @@ -785,6 +785,17 @@ static int lintog726_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) static struct ast_translator g726tolin = { .name = "g726tolin", + .src_codec = { + .name = "g726", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "slin", .newpvt = lintog726_new, /* same for both directions */ .framein = g726tolin_framein, .sample = g726_sample, @@ -795,6 +806,17 @@ static struct ast_translator g726tolin = { static struct ast_translator lintog726 = { .name = "lintog726", + .src_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "g726", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "g726", .newpvt = lintog726_new, /* same for both directions */ .framein = lintog726_framein, .sample = slin8_sample, @@ -805,6 +827,17 @@ static struct ast_translator lintog726 = { static struct ast_translator g726aal2tolin = { .name = "g726aal2tolin", + .src_codec = { + .name = "g726aal2", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "slin", .newpvt = lintog726_new, /* same for both directions */ .framein = g726aal2tolin_framein, .sample = g726_sample, @@ -815,6 +848,17 @@ static struct ast_translator g726aal2tolin = { static struct ast_translator lintog726aal2 = { .name = "lintog726aal2", + .src_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "g726aal2", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "g726aal2", .newpvt = lintog726_new, /* same for both directions */ .framein = lintog726aal2_framein, .sample = slin8_sample, @@ -823,11 +867,6 @@ static struct ast_translator lintog726aal2 = { .buf_size = BUFFER_SAMPLES / 2, }; -static int reload(void) -{ - return AST_MODULE_LOAD_SUCCESS; -} - static int unload_module(void) { int res = 0; @@ -845,18 +884,6 @@ static int load_module(void) { int res = 0; - ast_format_set(&g726tolin.src_format, AST_FORMAT_G726, 0); - ast_format_set(&g726tolin.dst_format, AST_FORMAT_SLINEAR, 0); - - ast_format_set(&lintog726.src_format, AST_FORMAT_SLINEAR, 0); - ast_format_set(&lintog726.dst_format, AST_FORMAT_G726, 0); - - ast_format_set(&g726aal2tolin.src_format, AST_FORMAT_G726_AAL2, 0); - ast_format_set(&g726aal2tolin.dst_format, AST_FORMAT_SLINEAR, 0); - - ast_format_set(&lintog726aal2.src_format, AST_FORMAT_SLINEAR, 0); - ast_format_set(&lintog726aal2.dst_format, AST_FORMAT_G726_AAL2, 0); - res |= ast_register_translator(&g726tolin); res |= ast_register_translator(&lintog726); @@ -874,5 +901,4 @@ static int load_module(void) AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ITU G.726-32kbps G726 Transcoder", .load = load_module, .unload = unload_module, - .reload = reload, ); diff --git a/codecs/codec_gsm.c b/codecs/codec_gsm.c index f42a5f1bd..49f672adb 100644 --- a/codecs/codec_gsm.c +++ b/codecs/codec_gsm.c @@ -168,7 +168,18 @@ static void gsm_destroy_stuff(struct ast_trans_pvt *pvt) } static struct ast_translator gsmtolin = { - .name = "gsmtolin", + .name = "gsmtolin", + .src_codec = { + .name = "gsm", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "slin", .newpvt = gsm_new, .framein = gsmtolin_framein, .destroy = gsm_destroy_stuff, @@ -179,7 +190,18 @@ static struct ast_translator gsmtolin = { }; static struct ast_translator lintogsm = { - .name = "lintogsm", + .name = "lintogsm", + .src_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "gsm", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "gsm", .newpvt = gsm_new, .framein = lintogsm_framein, .frameout = lintogsm_frameout, @@ -189,19 +211,12 @@ static struct ast_translator lintogsm = { .buf_size = (BUFFER_SAMPLES * GSM_FRAME_LEN + GSM_SAMPLES - 1)/GSM_SAMPLES, }; -/*! \brief standard module glue */ -static int reload(void) -{ - return AST_MODULE_LOAD_SUCCESS; -} - static int unload_module(void) { int res; res = ast_unregister_translator(&lintogsm); - if (!res) - res = ast_unregister_translator(&gsmtolin); + res |= ast_unregister_translator(&gsmtolin); return res; } @@ -210,24 +225,18 @@ static int load_module(void) { int res; - ast_format_set(&gsmtolin.src_format, AST_FORMAT_GSM, 0); - ast_format_set(&gsmtolin.dst_format, AST_FORMAT_SLINEAR, 0); - - ast_format_set(&lintogsm.src_format, AST_FORMAT_SLINEAR, 0); - ast_format_set(&lintogsm.dst_format, AST_FORMAT_GSM, 0); - res = ast_register_translator(&gsmtolin); - if (!res) - res=ast_register_translator(&lintogsm); - else - ast_unregister_translator(&gsmtolin); - if (res) + res |= ast_register_translator(&lintogsm); + + if (res) { + unload_module(); return AST_MODULE_LOAD_FAILURE; + } + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "GSM Coder/Decoder", .load = load_module, .unload = unload_module, - .reload = reload, ); diff --git a/codecs/codec_ilbc.c b/codecs/codec_ilbc.c index 632169589..af23b906d 100644 --- a/codecs/codec_ilbc.c +++ b/codecs/codec_ilbc.c @@ -178,7 +178,18 @@ static struct ast_frame *lintoilbc_frameout(struct ast_trans_pvt *pvt) } static struct ast_translator ilbctolin = { - .name = "ilbctolin", + .name = "ilbctolin", + .src_codec = { + .name = "ilbc", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "slin", .newpvt = ilbctolin_new, .framein = ilbctolin_framein, .sample = ilbc_sample, @@ -188,7 +199,18 @@ static struct ast_translator ilbctolin = { }; static struct ast_translator lintoilbc = { - .name = "lintoilbc", + .name = "lintoilbc", + .src_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "ilbc", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "ilbc", .newpvt = lintoilbc_new, .framein = lintoilbc_framein, .frameout = lintoilbc_frameout, @@ -211,20 +233,14 @@ static int load_module(void) { int res; - ast_format_set(&ilbctolin.src_format, AST_FORMAT_ILBC, 0); - ast_format_set(&ilbctolin.dst_format, AST_FORMAT_SLINEAR, 0); - - ast_format_set(&lintoilbc.src_format, AST_FORMAT_SLINEAR, 0); - ast_format_set(&lintoilbc.dst_format, AST_FORMAT_ILBC, 0); - - res = ast_register_translator(&ilbctolin); - if (!res) - res=ast_register_translator(&lintoilbc); - else - ast_unregister_translator(&ilbctolin); - if (res) + res |= ast_register_translator(&lintoilbc); + + if (res) { + unload_module(); return AST_MODULE_LOAD_FAILURE; + } + return AST_MODULE_LOAD_SUCCESS; } diff --git a/codecs/codec_lpc10.c b/codecs/codec_lpc10.c index 5f2047a3f..0ef8856ff 100644 --- a/codecs/codec_lpc10.c +++ b/codecs/codec_lpc10.c @@ -196,7 +196,18 @@ static void lpc10_destroy(struct ast_trans_pvt *arg) } static struct ast_translator lpc10tolin = { - .name = "lpc10tolin", + .name = "lpc10tolin", + .src_codec = { + .name = "lpc10", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "slin", .newpvt = lpc10_dec_new, .framein = lpc10tolin_framein, .destroy = lpc10_destroy, @@ -207,7 +218,18 @@ static struct ast_translator lpc10tolin = { }; static struct ast_translator lintolpc10 = { - .name = "lintolpc10", + .name = "lintolpc10", + .src_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "lpc10", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "lpc10", .newpvt = lpc10_enc_new, .framein = lintolpc10_framein, .frameout = lintolpc10_frameout, @@ -218,12 +240,6 @@ static struct ast_translator lintolpc10 = { .buf_size = LPC10_BYTES_IN_COMPRESSED_FRAME * (1 + BUFFER_SAMPLES / LPC10_SAMPLES_PER_FRAME), }; -static int reload(void) -{ - return AST_MODULE_LOAD_SUCCESS; -} - - static int unload_module(void) { int res; @@ -238,24 +254,18 @@ static int load_module(void) { int res; - ast_format_set(&lpc10tolin.src_format, AST_FORMAT_LPC10, 0); - ast_format_set(&lpc10tolin.dst_format, AST_FORMAT_SLINEAR, 0); - - ast_format_set(&lintolpc10.src_format, AST_FORMAT_SLINEAR, 0); - ast_format_set(&lintolpc10.dst_format, AST_FORMAT_LPC10, 0); - res = ast_register_translator(&lpc10tolin); - if (!res) - res = ast_register_translator(&lintolpc10); - else - ast_unregister_translator(&lpc10tolin); - if (res) + res |= ast_register_translator(&lintolpc10); + + if (res) { + unload_module(); return AST_MODULE_LOAD_FAILURE; + } + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "LPC10 2.4kbps Coder/Decoder", .load = load_module, .unload = unload_module, - .reload = reload, ); diff --git a/codecs/codec_resample.c b/codecs/codec_resample.c index 29d95a798..26b1f0e08 100644 --- a/codecs/codec_resample.c +++ b/codecs/codec_resample.c @@ -42,32 +42,72 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") static struct ast_translator *translators; static int trans_size; -static int id_list[] = { - AST_FORMAT_SLINEAR, - AST_FORMAT_SLINEAR12, - AST_FORMAT_SLINEAR16, - AST_FORMAT_SLINEAR24, - AST_FORMAT_SLINEAR32, - AST_FORMAT_SLINEAR44, - AST_FORMAT_SLINEAR48, - AST_FORMAT_SLINEAR96, - AST_FORMAT_SLINEAR192, +static struct ast_codec codec_list[] = { + { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 12000, + }, + { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + }, + { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 24000, + }, + { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 32000, + }, + { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 44100, + }, + { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 48000, + }, + { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 96000, + }, + { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 192000, + }, }; static int resamp_new(struct ast_trans_pvt *pvt) { int err; - if (!(pvt->pvt = speex_resampler_init(1, ast_format_rate(&pvt->t->src_format), ast_format_rate(&pvt->t->dst_format), 5, &err))) { + if (!(pvt->pvt = speex_resampler_init(1, pvt->t->src_codec.sample_rate, pvt->t->dst_codec.sample_rate, 5, &err))) { return -1; } + ast_assert(pvt->f.subclass.format == NULL); + pvt->f.subclass.format = ao2_bump(ast_format_cache_get_slin_by_rate(pvt->t->dst_codec.sample_rate)); + return 0; } static void resamp_destroy(struct ast_trans_pvt *pvt) { SpeexResamplerState *resamp_pvt = pvt->pvt; + speex_resampler_destroy(resamp_pvt); } @@ -113,13 +153,13 @@ static int load_module(void) int res = 0; int x, y, idx = 0; - trans_size = ARRAY_LEN(id_list) * (ARRAY_LEN(id_list) - 1); + trans_size = ARRAY_LEN(codec_list) * (ARRAY_LEN(codec_list) - 1); if (!(translators = ast_calloc(1, sizeof(struct ast_translator) * trans_size))) { return AST_MODULE_LOAD_FAILURE; } - for (x = 0; x < ARRAY_LEN(id_list); x++) { - for (y = 0; y < ARRAY_LEN(id_list); y++) { + for (x = 0; x < ARRAY_LEN(codec_list); x++) { + for (y = 0; y < ARRAY_LEN(codec_list); y++) { if (x == y) { continue; } @@ -129,10 +169,10 @@ static int load_module(void) translators[idx].desc_size = 0; translators[idx].buffer_samples = (OUTBUF_SIZE / sizeof(int16_t)); translators[idx].buf_size = OUTBUF_SIZE; - ast_format_set(&translators[idx].src_format, id_list[x], 0); - ast_format_set(&translators[idx].dst_format, id_list[y], 0); - snprintf(translators[idx].name, sizeof(translators[idx].name), "slin %dkhz -> %dkhz", - ast_format_rate(&translators[idx].src_format), ast_format_rate(&translators[idx].dst_format)); + memcpy(&translators[idx].src_codec, &codec_list[x], sizeof(struct ast_codec)); + memcpy(&translators[idx].dst_codec, &codec_list[y], sizeof(struct ast_codec)); + snprintf(translators[idx].name, sizeof(translators[idx].name), "slin %ukhz -> %ukhz", + translators[idx].src_codec.sample_rate, translators[idx].dst_codec.sample_rate); res |= ast_register_translator(&translators[idx]); idx++; } diff --git a/codecs/codec_speex.c b/codecs/codec_speex.c index 72e948057..8c2c3f395 100644 --- a/codecs/codec_speex.c +++ b/codecs/codec_speex.c @@ -308,10 +308,14 @@ static struct ast_frame *lintospeex_frameout(struct ast_trans_pvt *pvt) } else { tmp->silent_state = 1; speex_bits_reset(&tmp->bits); + +/* BUGBUG need to setup a new static frame to prevent destroying the translators normal static frame. */ + ao2_cleanup(pvt->f.subclass.format); memset(&pvt->f, 0, sizeof(pvt->f)); pvt->f.frametype = AST_FRAME_CNG; pvt->f.samples = samples; /* XXX what now ? format etc... */ +/* BUGBUG should return ast_frisolate(setup local static frame) here */ } } @@ -341,7 +345,18 @@ static void lintospeex_destroy(struct ast_trans_pvt *arg) } static struct ast_translator speextolin = { - .name = "speextolin", + .name = "speextolin", + .src_codec = { + .name = "speex", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "slin", .newpvt = speextolin_new, .framein = speextolin_framein, .destroy = speextolin_destroy, @@ -354,6 +369,17 @@ static struct ast_translator speextolin = { static struct ast_translator lintospeex = { .name = "lintospeex", + .src_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "speex", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "speex", .newpvt = lintospeex_new, .framein = lintospeex_framein, .frameout = lintospeex_frameout, @@ -365,7 +391,18 @@ static struct ast_translator lintospeex = { }; static struct ast_translator speexwbtolin16 = { - .name = "speexwbtolin16", + .name = "speexwbtolin16", + .src_codec = { + .name = "speex", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + }, + .dst_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + }, + .format = "slin16", .newpvt = speexwbtolin16_new, .framein = speextolin_framein, .destroy = speextolin_destroy, @@ -377,7 +414,18 @@ static struct ast_translator speexwbtolin16 = { }; static struct ast_translator lin16tospeexwb = { - .name = "lin16tospeexwb", + .name = "lin16tospeexwb", + .src_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + }, + .dst_codec = { + .name = "speex", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + }, + .format = "speex16", .newpvt = lin16tospeexwb_new, .framein = lintospeex_framein, .frameout = lintospeex_frameout, @@ -389,7 +437,18 @@ static struct ast_translator lin16tospeexwb = { }; static struct ast_translator speexuwbtolin32 = { - .name = "speexuwbtolin32", + .name = "speexuwbtolin32", + .src_codec = { + .name = "speex", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 32000, + }, + .dst_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 32000, + }, + .format = "slin32", .newpvt = speexuwbtolin32_new, .framein = speextolin_framein, .destroy = speextolin_destroy, @@ -400,7 +459,18 @@ static struct ast_translator speexuwbtolin32 = { }; static struct ast_translator lin32tospeexuwb = { - .name = "lin32tospeexuwb", + .name = "lin32tospeexuwb", + .src_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 32000, + }, + .dst_codec = { + .name = "speex", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 32000, + }, + .format = "speex32", .newpvt = lin32tospeexuwb_new, .framein = lintospeex_framein, .frameout = lintospeex_frameout, @@ -534,25 +604,6 @@ static int load_module(void) if (parse_config(0)) return AST_MODULE_LOAD_DECLINE; - - ast_format_set(&speextolin.src_format, AST_FORMAT_SPEEX, 0); - ast_format_set(&speextolin.dst_format, AST_FORMAT_SLINEAR, 0); - - ast_format_set(&lintospeex.src_format, AST_FORMAT_SLINEAR, 0); - ast_format_set(&lintospeex.dst_format, AST_FORMAT_SPEEX, 0); - - ast_format_set(&speexwbtolin16.src_format, AST_FORMAT_SPEEX16, 0); - ast_format_set(&speexwbtolin16.dst_format, AST_FORMAT_SLINEAR16, 0); - - ast_format_set(&lin16tospeexwb.src_format, AST_FORMAT_SLINEAR16, 0); - ast_format_set(&lin16tospeexwb.dst_format, AST_FORMAT_SPEEX16, 0); - - ast_format_set(&speexuwbtolin32.src_format, AST_FORMAT_SPEEX32, 0); - ast_format_set(&speexuwbtolin32.dst_format, AST_FORMAT_SLINEAR32, 0); - - ast_format_set(&lin32tospeexuwb.src_format, AST_FORMAT_SLINEAR32, 0); - ast_format_set(&lin32tospeexuwb.dst_format, AST_FORMAT_SPEEX32, 0); - res |= ast_register_translator(&speextolin); res |= ast_register_translator(&lintospeex); res |= ast_register_translator(&speexwbtolin16); @@ -560,6 +611,10 @@ static int load_module(void) res |= ast_register_translator(&speexuwbtolin32); res |= ast_register_translator(&lin32tospeexuwb); + if (res) { + unload_module(); + return res; + } return res; } diff --git a/codecs/codec_ulaw.c b/codecs/codec_ulaw.c index 86a0706c4..9d0aa3c14 100644 --- a/codecs/codec_ulaw.c +++ b/codecs/codec_ulaw.c @@ -82,6 +82,17 @@ static int lintoulaw_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) static struct ast_translator ulawtolin = { .name = "ulawtolin", + .src_codec = { + .name = "ulaw", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "slin", .framein = ulawtolin_framein, .sample = ulaw_sample, .buffer_samples = BUFFER_SAMPLES, @@ -90,6 +101,17 @@ static struct ast_translator ulawtolin = { static struct ast_translator testlawtolin = { .name = "testlawtolin", + .src_codec = { + .name = "testlaw", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "slin", .framein = ulawtolin_framein, .sample = ulaw_sample, .buffer_samples = BUFFER_SAMPLES, @@ -102,6 +124,17 @@ static struct ast_translator testlawtolin = { static struct ast_translator lintoulaw = { .name = "lintoulaw", + .src_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "ulaw", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "ulaw", .framein = lintoulaw_framein, .sample = slin8_sample, .buf_size = BUFFER_SAMPLES, @@ -110,17 +143,23 @@ static struct ast_translator lintoulaw = { static struct ast_translator lintotestlaw = { .name = "lintotestlaw", + .src_codec = { + .name = "slin", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .dst_codec = { + .name = "testlaw", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + }, + .format = "testlaw", .framein = lintoulaw_framein, .sample = slin8_sample, .buf_size = BUFFER_SAMPLES, .buffer_samples = BUFFER_SAMPLES, }; -static int reload(void) -{ - return AST_MODULE_LOAD_SUCCESS; -} - static int unload_module(void) { int res; @@ -137,32 +176,20 @@ static int load_module(void) { int res; - ast_format_set(&lintoulaw.src_format, AST_FORMAT_SLINEAR, 0); - ast_format_set(&lintoulaw.dst_format, AST_FORMAT_ULAW, 0); - - ast_format_set(&lintotestlaw.src_format, AST_FORMAT_SLINEAR, 0); - ast_format_set(&lintotestlaw.dst_format, AST_FORMAT_TESTLAW, 0); - - ast_format_set(&ulawtolin.src_format, AST_FORMAT_ULAW, 0); - ast_format_set(&ulawtolin.dst_format, AST_FORMAT_SLINEAR, 0); - - ast_format_set(&testlawtolin.src_format, AST_FORMAT_TESTLAW, 0); - ast_format_set(&testlawtolin.dst_format, AST_FORMAT_SLINEAR, 0); - res = ast_register_translator(&ulawtolin); - if (!res) { - res = ast_register_translator(&lintoulaw); - res |= ast_register_translator(&lintotestlaw); - res |= ast_register_translator(&testlawtolin); - } else - ast_unregister_translator(&ulawtolin); - if (res) + res |= ast_register_translator(&lintoulaw); + res |= ast_register_translator(&lintotestlaw); + res |= ast_register_translator(&testlawtolin); + + if (res) { + unload_module(); return AST_MODULE_LOAD_FAILURE; + } + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "mu-Law Coder/Decoder", .load = load_module, .unload = unload_module, - .reload = reload, ); diff --git a/codecs/ex_adpcm.h b/codecs/ex_adpcm.h index 96b7c51f8..360239789 100644 --- a/codecs/ex_adpcm.h +++ b/codecs/ex_adpcm.h @@ -26,7 +26,8 @@ static struct ast_frame *adpcm_sample(void) .src = __PRETTY_FUNCTION__, .data.ptr = ex_adpcm, }; - ast_format_set(&f.subclass.format, AST_FORMAT_ADPCM, 0); + + f.subclass.format = ast_format_adpcm; return &f; } diff --git a/codecs/ex_alaw.h b/codecs/ex_alaw.h index bbf8ad982..e8629be5e 100644 --- a/codecs/ex_alaw.h +++ b/codecs/ex_alaw.h @@ -31,6 +31,6 @@ static struct ast_frame *alaw_sample(void) .src = __PRETTY_FUNCTION__, .data.ptr = ex_alaw, }; - ast_format_set(&f.subclass.format, AST_FORMAT_ALAW, 0); + f.subclass.format = ast_format_alaw; return &f; } diff --git a/codecs/ex_g722.h b/codecs/ex_g722.h index 0e9f22686..390cc7b5c 100644 --- a/codecs/ex_g722.h +++ b/codecs/ex_g722.h @@ -42,7 +42,7 @@ static struct ast_frame *g722_sample(void) .data.ptr = ex_g722, }; - ast_format_set(&f.subclass.format, AST_FORMAT_G722, 0); + f.subclass.format = ast_format_slin; return &f; } diff --git a/codecs/ex_g726.h b/codecs/ex_g726.h index d5438c91a..f125253ee 100644 --- a/codecs/ex_g726.h +++ b/codecs/ex_g726.h @@ -27,7 +27,7 @@ static struct ast_frame *g726_sample(void) .data.ptr = ex_g726, }; - ast_format_set(&f.subclass.format, AST_FORMAT_G726, 0); + f.subclass.format = ast_format_g726; return &f; } diff --git a/codecs/ex_gsm.h b/codecs/ex_gsm.h index 8f8b4f9fe..006706038 100644 --- a/codecs/ex_gsm.h +++ b/codecs/ex_gsm.h @@ -27,6 +27,7 @@ static struct ast_frame *gsm_sample(void) .data.ptr = ex_gsm, }; - ast_format_set(&f.subclass.format, AST_FORMAT_GSM, 0); + f.subclass.format = ast_format_gsm; + return &f; } diff --git a/codecs/ex_ilbc.h b/codecs/ex_ilbc.h index 93cf5eacf..3a79b0918 100644 --- a/codecs/ex_ilbc.h +++ b/codecs/ex_ilbc.h @@ -28,6 +28,7 @@ static struct ast_frame *ilbc_sample(void) .data.ptr = ex_ilbc, }; - ast_format_set(&f.subclass.format, AST_FORMAT_ILBC, 0); + f.subclass.format = ast_format_ilbc; + return &f; } diff --git a/codecs/ex_lpc10.h b/codecs/ex_lpc10.h index a36e06add..2e271c005 100644 --- a/codecs/ex_lpc10.h +++ b/codecs/ex_lpc10.h @@ -25,7 +25,7 @@ static struct ast_frame *lpc10_sample(void) .data.ptr = ex_lpc10, }; - ast_format_set(&f.subclass.format, AST_FORMAT_LPC10, 0); + f.subclass.format = ast_format_lpc10; return &f; } diff --git a/codecs/ex_speex.h b/codecs/ex_speex.h index e9411e5d7..76e5925b8 100644 --- a/codecs/ex_speex.h +++ b/codecs/ex_speex.h @@ -27,7 +27,7 @@ static struct ast_frame *speex_sample(void) .data.ptr = ex_speex, }; - ast_format_set(&f.subclass.format, AST_FORMAT_SPEEX, 0); + f.subclass.format = ast_format_speex; return &f; } @@ -58,7 +58,8 @@ static struct ast_frame *speex16_sample(void) .src = __PRETTY_FUNCTION__, .data.ptr = ex_speex16, }; - ast_format_set(&f.subclass.format, AST_FORMAT_SPEEX16, 0); + + f.subclass.format = ast_format_speex16; return &f; } diff --git a/codecs/ex_ulaw.h b/codecs/ex_ulaw.h index 2ab9222fb..d18a08e9c 100644 --- a/codecs/ex_ulaw.h +++ b/codecs/ex_ulaw.h @@ -32,6 +32,7 @@ static struct ast_frame *ulaw_sample(void) .data.ptr = ex_ulaw, }; - ast_format_set(&f.subclass.format, AST_FORMAT_ULAW, 0); + f.subclass.format = ast_format_ulaw; + return &f; } diff --git a/formats/format_g719.c b/formats/format_g719.c index ee9221230..8d508f0e3 100644 --- a/formats/format_g719.c +++ b/formats/format_g719.c @@ -34,6 +34,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" +#include "asterisk/format_cache.h" #define BUF_SIZE 160 /* 20 milliseconds == 160 bytes, 960 samples */ #define SAMPLES_TO_BYTES(x) ((typeof(x)) x / ((float) 960 / 160)) @@ -44,9 +45,6 @@ static struct ast_frame *g719read(struct ast_filestream *s, int *whennext) int res; /* Send a frame from the file to the appropriate channel */ - s->fr.frametype = AST_FRAME_VOICE; - ast_format_set(&s->fr.subclass.format, AST_FORMAT_G719, 0); - s->fr.mallocd = 0; AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (res) @@ -61,14 +59,6 @@ static int g719write(struct ast_filestream *fs, struct ast_frame *f) { int res; - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); - return -1; - } - if (f->subclass.format.id != AST_FORMAT_G719) { - ast_log(LOG_WARNING, "Asked to write non-G.719 frame (%s)!\n", ast_getformatname(&f->subclass.format)); - return -1; - } if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) { ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno)); return -1; @@ -147,7 +137,8 @@ static struct ast_format_def g719_f = { static int load_module(void) { - ast_format_set(&g719_f.format, AST_FORMAT_G719, 0); + g719_f.format = ast_format_g719; + if (ast_format_def_register(&g719_f)) return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_SUCCESS; diff --git a/formats/format_g723.c b/formats/format_g723.c index c3c194d15..51fe6b049 100644 --- a/formats/format_g723.c +++ b/formats/format_g723.c @@ -35,6 +35,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/mod_format.h" #include "asterisk/module.h" +#include "asterisk/format_cache.h" #define G723_MAX_SIZE 1024 @@ -64,9 +65,6 @@ static struct ast_frame *g723_read(struct ast_filestream *s, int *whennext) return NULL; } /* Read the data into the buffer */ - s->fr.frametype = AST_FRAME_VOICE; - ast_format_set(&s->fr.subclass.format, AST_FORMAT_G723_1, 0); - s->fr.mallocd = 0; AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, size); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != size) { ast_log(LOG_WARNING, "Short read (%d of %d bytes) (%s)!\n", res, size, strerror(errno)); @@ -82,14 +80,6 @@ static int g723_write(struct ast_filestream *s, struct ast_frame *f) uint16_t size; int res; /* XXX there used to be a check s->fr means a read stream */ - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); - return -1; - } - if (f->subclass.format.id != AST_FORMAT_G723_1) { - ast_log(LOG_WARNING, "Asked to write non-g723 frame!\n"); - return -1; - } delay = 0; if (f->datalen <= 0) { ast_log(LOG_WARNING, "Short frame ignored (%d bytes long?)\n", f->datalen); @@ -151,7 +141,7 @@ static struct ast_format_def g723_1_f = { static int load_module(void) { - ast_format_set(&g723_1_f.format, AST_FORMAT_G723_1, 0); + g723_1_f.format = ast_format_g723; if (ast_format_def_register(&g723_1_f)) return AST_MODULE_LOAD_FAILURE; diff --git a/formats/format_g726.c b/formats/format_g726.c index 636aff091..bde3e2d06 100644 --- a/formats/format_g726.c +++ b/formats/format_g726.c @@ -39,6 +39,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" +#include "asterisk/format_cache.h" #define RATE_40 0 #define RATE_32 1 @@ -122,9 +123,6 @@ static struct ast_frame *g726_read(struct ast_filestream *s, int *whennext) struct g726_desc *fs = (struct g726_desc *)s->_private; /* Send a frame from the file to the appropriate channel */ - s->fr.frametype = AST_FRAME_VOICE; - ast_format_set(&s->fr.subclass.format, AST_FORMAT_G726, 0); - s->fr.mallocd = 0; AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, frame_size[fs->rate]); s->fr.samples = 8 * FRAME_TIME; if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { @@ -141,15 +139,6 @@ static int g726_write(struct ast_filestream *s, struct ast_frame *f) int res; struct g726_desc *fs = (struct g726_desc *)s->_private; - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); - return -1; - } - if (f->subclass.format.id != AST_FORMAT_G726) { - ast_log(LOG_WARNING, "Asked to write non-G726 frame (%s)!\n", - ast_getformatname(&f->subclass.format)); - return -1; - } if (f->datalen % frame_size[fs->rate]) { ast_log(LOG_WARNING, "Invalid data length %d, should be multiple of %d\n", f->datalen, frame_size[fs->rate]); @@ -239,7 +228,7 @@ static int load_module(void) int i; for (i = 0; f[i].desc_size ; i++) { - ast_format_set(&f[i].format, AST_FORMAT_G726, 0); + f[i].format = ast_format_g726; if (ast_format_def_register(&f[i])) { /* errors are fatal */ ast_log(LOG_WARNING, "Failed to register format %s.\n", f[i].name); return AST_MODULE_LOAD_FAILURE; diff --git a/formats/format_g729.c b/formats/format_g729.c index f11fa97d9..7d562ede7 100644 --- a/formats/format_g729.c +++ b/formats/format_g729.c @@ -37,6 +37,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" +#include "asterisk/format_cache.h" /* Some Ideas for this code came from makeg729e.c by Jeffrey Chilton */ @@ -49,9 +50,6 @@ static struct ast_frame *g729_read(struct ast_filestream *s, int *whennext) { int res; /* Send a frame from the file to the appropriate channel */ - s->fr.frametype = AST_FRAME_VOICE; - ast_format_set(&s->fr.subclass.format, AST_FORMAT_G729A, 0); - s->fr.mallocd = 0; s->fr.samples = G729A_SAMPLES; AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { @@ -66,14 +64,7 @@ static struct ast_frame *g729_read(struct ast_filestream *s, int *whennext) static int g729_write(struct ast_filestream *fs, struct ast_frame *f) { int res; - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); - return -1; - } - if (f->subclass.format.id != AST_FORMAT_G729A) { - ast_log(LOG_WARNING, "Asked to write non-G729 frame (%s)!\n", ast_getformatname(&f->subclass.format)); - return -1; - } + if (f->datalen % 10) { ast_log(LOG_WARNING, "Invalid data length, %d, should be multiple of 10\n", f->datalen); return -1; @@ -147,7 +138,7 @@ static struct ast_format_def g729_f = { static int load_module(void) { - ast_format_set(&g729_f.format, AST_FORMAT_G729A, 0); + g729_f.format = ast_format_g729; if (ast_format_def_register(&g729_f)) return AST_MODULE_LOAD_FAILURE; return AST_MODULE_LOAD_SUCCESS; diff --git a/formats/format_gsm.c b/formats/format_gsm.c index 47ed41c3a..fe1e55c7a 100644 --- a/formats/format_gsm.c +++ b/formats/format_gsm.c @@ -34,6 +34,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" +#include "asterisk/format_cache.h" #include "msgsm.h" @@ -56,10 +57,7 @@ static struct ast_frame *gsm_read(struct ast_filestream *s, int *whennext) { int res; - s->fr.frametype = AST_FRAME_VOICE; - ast_format_set(&s->fr.subclass.format, AST_FORMAT_GSM, 0); AST_FRAME_SET_BUFFER(&(s->fr), s->buf, AST_FRIENDLY_OFFSET, GSM_FRAME_SIZE) - s->fr.mallocd = 0; if ((res = fread(s->fr.data.ptr, 1, GSM_FRAME_SIZE, s->f)) != GSM_FRAME_SIZE) { if (res) ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); @@ -74,14 +72,6 @@ static int gsm_write(struct ast_filestream *fs, struct ast_frame *f) int res; unsigned char gsm[2*GSM_FRAME_SIZE]; - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); - return -1; - } - if (f->subclass.format.id != AST_FORMAT_GSM) { - ast_log(LOG_WARNING, "Asked to write non-GSM frame (%s)!\n", ast_getformatname(&f->subclass.format)); - return -1; - } if (!(f->datalen % 65)) { /* This is in MSGSM format, need to be converted */ int len=0; @@ -193,7 +183,7 @@ static struct ast_format_def gsm_f = { static int load_module(void) { - ast_format_set(&gsm_f.format, AST_FORMAT_GSM, 0); + gsm_f.format = ast_format_gsm; if (ast_format_def_register(&gsm_f)) return AST_MODULE_LOAD_FAILURE; return AST_MODULE_LOAD_SUCCESS; diff --git a/formats/format_h263.c b/formats/format_h263.c index 56e9b3aa0..6511cef04 100644 --- a/formats/format_h263.c +++ b/formats/format_h263.c @@ -35,6 +35,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" +#include "asterisk/format_cache.h" /* Some Ideas for this code came from makeh263e.c by Jeffrey Chilton */ @@ -48,6 +49,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") * ridiculously large). */ #define BUF_SIZE 32768 /* Four real h.263 Frames */ +#define FRAME_ENDED 0x8000 + struct h263_desc { unsigned int lastts; }; @@ -76,15 +79,12 @@ static struct ast_frame *h263_read(struct ast_filestream *s, int *whennext) if ((res = fread(&len, 1, sizeof(len), s->f)) < 1) return NULL; len = ntohs(len); - mark = (len & 0x8000) ? 1 : 0; + mark = (len & FRAME_ENDED) ? 1 : 0; len &= 0x7fff; if (len > BUF_SIZE) { ast_log(LOG_WARNING, "Length %d is too long\n", len); return NULL; } - s->fr.frametype = AST_FRAME_VIDEO; - ast_format_set(&s->fr.subclass.format, AST_FORMAT_H263, 0); - s->fr.mallocd = 0; AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, len); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (res) @@ -93,11 +93,7 @@ static struct ast_frame *h263_read(struct ast_filestream *s, int *whennext) } s->fr.samples = fs->lastts; /* XXX what ? */ s->fr.datalen = len; - if (mark) { - ast_format_set_video_mark(&s->fr.subclass.format); - } - s->fr.delivery.tv_sec = 0; - s->fr.delivery.tv_usec = 0; + s->fr.subclass.frame_ending = mark; if ((res = fread(&ts, 1, sizeof(ts), s->f)) == sizeof(ts)) { fs->lastts = ntohl(ts); *whennext = fs->lastts * 4/45; @@ -112,15 +108,7 @@ static int h263_write(struct ast_filestream *fs, struct ast_frame *f) unsigned int ts; unsigned short len; uint32_t mark = 0; - if (f->frametype != AST_FRAME_VIDEO) { - ast_log(LOG_WARNING, "Asked to write non-video frame!\n"); - return -1; - } - mark = ast_format_get_video_mark(&f->subclass.format) ? 0x8000 : 0; - if (f->subclass.format.id != AST_FORMAT_H263) { - ast_log(LOG_WARNING, "Asked to write non-h263 frame (%s)!\n", ast_getformatname(&f->subclass.format)); - return -1; - } + mark = f->subclass.frame_ending ? FRAME_ENDED : 0; ts = htonl(f->samples); if ((res = fwrite(&ts, 1, sizeof(ts), fs->f)) != sizeof(ts)) { ast_log(LOG_WARNING, "Bad write (%d/4): %s\n", res, strerror(errno)); @@ -182,7 +170,7 @@ static struct ast_format_def h263_f = { static int load_module(void) { - ast_format_set(&h263_f.format, AST_FORMAT_H263, 0); + h263_f.format = ast_format_h263; if (ast_format_def_register(&h263_f)) return AST_MODULE_LOAD_FAILURE; return AST_MODULE_LOAD_SUCCESS; diff --git a/formats/format_h264.c b/formats/format_h264.c index e090c2bac..56ec007c0 100644 --- a/formats/format_h264.c +++ b/formats/format_h264.c @@ -35,12 +35,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" +#include "asterisk/format_cache.h" /* Some Ideas for this code came from makeh264e.c by Jeffrey Chilton */ /* Portions of the conversion code are by guido@sienanet.it */ /*! \todo Check this buf size estimate, it may be totally wrong for large frame video */ +#define FRAME_ENDED 0x8000 + #define BUF_SIZE 4096 /* Two Real h264 Frames */ struct h264_desc { unsigned int lastts; @@ -68,15 +71,12 @@ static struct ast_frame *h264_read(struct ast_filestream *s, int *whennext) if ((res = fread(&len, 1, sizeof(len), s->f)) < 1) return NULL; len = ntohs(len); - mark = (len & 0x8000) ? 1 : 0; + mark = (len & FRAME_ENDED) ? 1 : 0; len &= 0x7fff; if (len > BUF_SIZE) { ast_log(LOG_WARNING, "Length %d is too long\n", len); len = BUF_SIZE; /* XXX truncate */ } - s->fr.frametype = AST_FRAME_VIDEO; - ast_format_set(&s->fr.subclass.format, AST_FORMAT_H264, 0); - s->fr.mallocd = 0; AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, len); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (res) @@ -85,11 +85,7 @@ static struct ast_frame *h264_read(struct ast_filestream *s, int *whennext) } s->fr.samples = fs->lastts; s->fr.datalen = len; - if (mark) { - ast_format_set_video_mark(&s->fr.subclass.format); - } - s->fr.delivery.tv_sec = 0; - s->fr.delivery.tv_usec = 0; + s->fr.subclass.frame_ending = mark; if ((res = fread(&ts, 1, sizeof(ts), s->f)) == sizeof(ts)) { fs->lastts = ntohl(ts); *whennext = fs->lastts * 4/45; @@ -105,15 +101,7 @@ static int h264_write(struct ast_filestream *s, struct ast_frame *f) unsigned short len; int mark; - if (f->frametype != AST_FRAME_VIDEO) { - ast_log(LOG_WARNING, "Asked to write non-video frame!\n"); - return -1; - } - mark = ast_format_get_video_mark(&f->subclass.format) ? 0x8000 : 0; - if (f->subclass.format.id != AST_FORMAT_H264) { - ast_log(LOG_WARNING, "Asked to write non-h264 frame (%s)!\n", ast_getformatname(&f->subclass.format)); - return -1; - } + mark = f->subclass.frame_ending ? FRAME_ENDED : 0; ts = htonl(f->samples); if ((res = fwrite(&ts, 1, sizeof(ts), s->f)) != sizeof(ts)) { ast_log(LOG_WARNING, "Bad write (%d/4): %s\n", res, strerror(errno)); @@ -175,7 +163,7 @@ static struct ast_format_def h264_f = { static int load_module(void) { - ast_format_set(&h264_f.format, AST_FORMAT_H264, 0); + h264_f.format = ast_format_h264; if (ast_format_def_register(&h264_f)) return AST_MODULE_LOAD_FAILURE; return AST_MODULE_LOAD_SUCCESS; diff --git a/formats/format_ilbc.c b/formats/format_ilbc.c index 07155b717..ce5135f7b 100644 --- a/formats/format_ilbc.c +++ b/formats/format_ilbc.c @@ -36,6 +36,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" +#include "asterisk/format_cache.h" /* Some Ideas for this code came from makeg729e.c by Jeffrey Chilton */ @@ -48,9 +49,6 @@ static struct ast_frame *ilbc_read(struct ast_filestream *s, int *whennext) { int res; /* Send a frame from the file to the appropriate channel */ - s->fr.frametype = AST_FRAME_VOICE; - ast_format_set(&s->fr.subclass.format, AST_FORMAT_ILBC, 0); - s->fr.mallocd = 0; AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, ILBC_BUF_SIZE); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (res) @@ -64,14 +62,6 @@ static struct ast_frame *ilbc_read(struct ast_filestream *s, int *whennext) static int ilbc_write(struct ast_filestream *fs, struct ast_frame *f) { int res; - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); - return -1; - } - if (f->subclass.format.id != AST_FORMAT_ILBC) { - ast_log(LOG_WARNING, "Asked to write non-iLBC frame (%s)!\n", ast_getformatname(&f->subclass.format)); - return -1; - } if (f->datalen % 50) { ast_log(LOG_WARNING, "Invalid data length, %d, should be multiple of 50\n", f->datalen); return -1; @@ -145,7 +135,7 @@ static struct ast_format_def ilbc_f = { static int load_module(void) { - ast_format_set(&ilbc_f.format, AST_FORMAT_ILBC, 0); + ilbc_f.format = ast_format_ilbc; if (ast_format_def_register(&ilbc_f)) return AST_MODULE_LOAD_FAILURE; return AST_MODULE_LOAD_SUCCESS; diff --git a/formats/format_jpeg.c b/formats/format_jpeg.c index d6733020e..1e91482f7 100644 --- a/formats/format_jpeg.c +++ b/formats/format_jpeg.c @@ -36,6 +36,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/image.h" #include "asterisk/endian.h" +#include "asterisk/format_cache.h" static struct ast_frame *jpeg_read_image(int fd, int len) { @@ -52,7 +53,7 @@ static struct ast_frame *jpeg_read_image(int fd, int len) } memset(&fr, 0, sizeof(fr)); fr.frametype = AST_FRAME_IMAGE; - ast_format_set(&fr.subclass.format, AST_FORMAT_JPEG, 0); + fr.subclass.format = ast_format_jpeg; fr.data.ptr = buf; fr.src = "JPEG Read"; fr.datalen = len; @@ -74,14 +75,6 @@ static int jpeg_identify(int fd) static int jpeg_write_image(int fd, struct ast_frame *fr) { int res=0; - if (fr->frametype != AST_FRAME_IMAGE) { - ast_log(LOG_WARNING, "Not an image\n"); - return -1; - } - if (fr->subclass.format.id != AST_FORMAT_JPEG) { - ast_log(LOG_WARNING, "Not a jpeg image\n"); - return -1; - } if (fr->datalen) { res = write(fd, fr->data.ptr, fr->datalen); if (res != fr->datalen) { @@ -103,7 +96,7 @@ static struct ast_imager jpeg_format = { static int load_module(void) { - ast_format_set(&jpeg_format.format, AST_FORMAT_JPEG, 0); + jpeg_format.format = ast_format_jpeg; if (ast_image_register(&jpeg_format)) return AST_MODULE_LOAD_FAILURE; return AST_MODULE_LOAD_SUCCESS; diff --git a/formats/format_ogg_vorbis.c b/formats/format_ogg_vorbis.c index 9eb390066..6171491a8 100644 --- a/formats/format_ogg_vorbis.c +++ b/formats/format_ogg_vorbis.c @@ -45,6 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/mod_format.h" #include "asterisk/module.h" +#include "asterisk/format_cache.h" /* * this is the number of samples we deal with. Samples are converted @@ -242,16 +243,6 @@ static int ogg_vorbis_write(struct ast_filestream *fs, struct ast_frame *f) ast_log(LOG_ERROR, "This stream is not set up for writing!\n"); return -1; } - - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); - return -1; - } - if (f->subclass.format.id != AST_FORMAT_SLINEAR) { - ast_log(LOG_WARNING, "Asked to write non-SLINEAR frame (%s)!\n", - ast_getformatname(&f->subclass.format)); - return -1; - } if (!f->datalen) return -1; @@ -310,9 +301,6 @@ static struct ast_frame *ogg_vorbis_read(struct ast_filestream *fs, } /* initialize frame */ - fs->fr.frametype = AST_FRAME_VOICE; - ast_format_set(&fs->fr.subclass.format, AST_FORMAT_SLINEAR, 0); - fs->fr.mallocd = 0; AST_FRAME_SET_BUFFER(&fs->fr, fs->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); out_buf = (char *) (fs->fr.data.ptr); /* SLIN data buffer */ @@ -435,7 +423,7 @@ static struct ast_format_def vorbis_f = { static int load_module(void) { - ast_format_set(&vorbis_f.format, AST_FORMAT_SLINEAR, 0); + vorbis_f.format = ast_format_slin; if (ast_format_def_register(&vorbis_f)) return AST_MODULE_LOAD_FAILURE; return AST_MODULE_LOAD_SUCCESS; diff --git a/formats/format_pcm.c b/formats/format_pcm.c index 1ee333fba..2d864078e 100644 --- a/formats/format_pcm.c +++ b/formats/format_pcm.c @@ -37,6 +37,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/endian.h" #include "asterisk/ulaw.h" #include "asterisk/alaw.h" +#include "asterisk/format_cache.h" #define BUF_SIZE 160 /* 160 bytes, and same number of samples */ @@ -66,7 +67,7 @@ static unsigned long get_time(void) static int pcma_open(struct ast_filestream *s) { - if (s->fmt->format == AST_FORMAT_ALAW) + if (ast_format_cmp(s->fmt->format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) pd->starttime = get_time(); return 0; } @@ -83,9 +84,6 @@ static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext) /* Send a frame from the file to the appropriate channel */ - s->fr.frametype = AST_FRAME_VOICE; - ast_format_copy(&s->fr.subclass.format, &s->fmt->format); - s->fr.mallocd = 0; AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) < 1) { if (res) @@ -93,7 +91,7 @@ static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext) return NULL; } s->fr.datalen = res; - if (s->fmt->format.id == AST_FORMAT_G722) + if (ast_format_cmp(s->fmt->format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) *whennext = s->fr.samples = res * 2; else *whennext = s->fr.samples = res; @@ -141,7 +139,7 @@ static int pcm_seek(struct ast_filestream *fs, off_t sample_offset, int whence) } if (whence == SEEK_FORCECUR && offset > max) { /* extend the file */ size_t left = offset - max; - const char *src = (fs->fmt->format.id == AST_FORMAT_ALAW) ? alaw_silence : ulaw_silence; + const char *src = (ast_format_cmp(fs->fmt->format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) ? alaw_silence : ulaw_silence; while (left) { size_t written = fwrite(src, 1, (left > BUF_SIZE) ? BUF_SIZE : left, fs->f); @@ -185,17 +183,8 @@ static int pcm_write(struct ast_filestream *fs, struct ast_frame *f) { int res; - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); - return -1; - } - if (ast_format_cmp(&f->subclass.format, &fs->fmt->format) == AST_FORMAT_CMP_NOT_EQUAL) { - ast_log(LOG_WARNING, "Asked to write incompatible format frame (%s)!\n", ast_getformatname(&f->subclass.format)); - return -1; - } - #ifdef REALTIME_WRITE - if (s->fmt->format == AST_FORMAT_ALAW) { + if (ast_format_cmp(s->fmt->format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) { struct pcm_desc *pd = (struct pcm_desc *)fs->_private; struct stat stat_buf; unsigned long cur_time = get_time(); @@ -399,7 +388,7 @@ static int au_seek(struct ast_filestream *fs, off_t sample_offset, int whence) off_t min = AU_HEADER_SIZE, max, cur; long offset = 0, bytes; - if (fs->fmt->format.id == AST_FORMAT_G722) + if (ast_format_cmp(fs->fmt->format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) bytes = sample_offset / 2; else bytes = sample_offset; @@ -523,10 +512,10 @@ static int load_module(void) for (i = 0; i < ARRAY_LEN(alaw_silence); i++) alaw_silence[i] = AST_LIN2A(0); - ast_format_set(&pcm_f.format, AST_FORMAT_ULAW, 0); - ast_format_set(&alaw_f.format, AST_FORMAT_ALAW, 0); - ast_format_set(&au_f.format, AST_FORMAT_ULAW, 0); - ast_format_set(&g722_f.format, AST_FORMAT_G722, 0); + pcm_f.format = ast_format_ulaw; + alaw_f.format = ast_format_alaw; + au_f.format = ast_format_ulaw; + g722_f.format = ast_format_g722; if ( ast_format_def_register(&pcm_f) || ast_format_def_register(&alaw_f) || ast_format_def_register(&au_f) diff --git a/formats/format_siren14.c b/formats/format_siren14.c index 77a9fe3ef..b7e2de1ec 100644 --- a/formats/format_siren14.c +++ b/formats/format_siren14.c @@ -34,6 +34,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" +#include "asterisk/format_cache.h" #define BUF_SIZE 120 /* 20 milliseconds == 120 bytes, 640 samples */ #define SAMPLES_TO_BYTES(x) ((typeof(x)) x / ((float) 640 / 120)) @@ -44,9 +45,6 @@ static struct ast_frame *siren14read(struct ast_filestream *s, int *whennext) int res; /* Send a frame from the file to the appropriate channel */ - s->fr.frametype = AST_FRAME_VOICE; - ast_format_set(&s->fr.subclass.format, AST_FORMAT_SIREN14, 0); - s->fr.mallocd = 0; AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (res) @@ -61,14 +59,6 @@ static int siren14write(struct ast_filestream *fs, struct ast_frame *f) { int res; - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); - return -1; - } - if (f->subclass.format.id != AST_FORMAT_SIREN14) { - ast_log(LOG_WARNING, "Asked to write non-Siren14 frame (%s)!\n", ast_getformatname(&f->subclass.format)); - return -1; - } if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) { ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno)); return -1; @@ -148,7 +138,7 @@ static struct ast_format_def siren14_f = { static int load_module(void) { - ast_format_set(&siren14_f.format, AST_FORMAT_SIREN14, 0); + siren14_f.format = ast_format_siren14; if (ast_format_def_register(&siren14_f)) return AST_MODULE_LOAD_DECLINE; diff --git a/formats/format_siren7.c b/formats/format_siren7.c index 35e2a3460..0b3c75d9c 100644 --- a/formats/format_siren7.c +++ b/formats/format_siren7.c @@ -34,6 +34,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" +#include "asterisk/format_cache.h" #define BUF_SIZE 80 /* 20 milliseconds == 80 bytes, 320 samples */ #define SAMPLES_TO_BYTES(x) x / (320 / 80) @@ -44,9 +45,6 @@ static struct ast_frame *siren7read(struct ast_filestream *s, int *whennext) int res; /* Send a frame from the file to the appropriate channel */ - s->fr.frametype = AST_FRAME_VOICE; - ast_format_set(&s->fr.subclass.format, AST_FORMAT_SIREN7, 0); - s->fr.mallocd = 0; AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (res) @@ -61,14 +59,6 @@ static int siren7write(struct ast_filestream *fs, struct ast_frame *f) { int res; - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); - return -1; - } - if (f->subclass.format.id != AST_FORMAT_SIREN7) { - ast_log(LOG_WARNING, "Asked to write non-Siren7 frame (%s)!\n", ast_getformatname(&f->subclass.format)); - return -1; - } if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) { ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno)); return -1; @@ -148,7 +138,7 @@ static struct ast_format_def siren7_f = { static int load_module(void) { - ast_format_set(&siren7_f.format, AST_FORMAT_SIREN7, 0); + siren7_f.format = ast_format_siren7; if (ast_format_def_register(&siren7_f)) return AST_MODULE_LOAD_DECLINE; diff --git a/formats/format_sln.c b/formats/format_sln.c index 30a1ebe31..a3230637c 100644 --- a/formats/format_sln.c +++ b/formats/format_sln.c @@ -32,15 +32,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" +#include "asterisk/format_cache.h" -static struct ast_frame *generic_read(struct ast_filestream *s, int *whennext, unsigned int buf_size, enum ast_format_id id) +static struct ast_frame *generic_read(struct ast_filestream *s, int *whennext, unsigned int buf_size) { int res; /* Send a frame from the file to the appropriate channel */ - s->fr.frametype = AST_FRAME_VOICE; - ast_format_set(&s->fr.subclass.format, id, 0); - s->fr.mallocd = 0; AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, buf_size); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) < 1) { if (res) @@ -52,17 +50,9 @@ static struct ast_frame *generic_read(struct ast_filestream *s, int *whennext, u return &s->fr; } -static int generic_write(struct ast_filestream *fs, struct ast_frame *f, enum ast_format_id id) +static int slinear_write(struct ast_filestream *fs, struct ast_frame *f) { int res; - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); - return -1; - } - if (f->subclass.format.id != id) { - ast_log(LOG_WARNING, "Asked to write non-slinear frame (%s)!\n", ast_getformatname(&f->subclass.format)); - return -1; - } if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) { ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno)); return -1; @@ -127,8 +117,7 @@ static off_t slinear_tell(struct ast_filestream *fs) return ftello(fs->f) / 2; } -static int slinear_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR);} -static struct ast_frame *slinear_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 320, AST_FORMAT_SLINEAR);} +static struct ast_frame *slinear_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 320);} static struct ast_format_def slin_f = { .name = "sln", .exts = "sln|raw", @@ -140,12 +129,11 @@ static struct ast_format_def slin_f = { .buf_size = 320 + AST_FRIENDLY_OFFSET, }; -static int slinear12_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR12);} -static struct ast_frame *slinear12_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 480, AST_FORMAT_SLINEAR12);} +static struct ast_frame *slinear12_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 480);} static struct ast_format_def slin12_f = { .name = "sln12", .exts = "sln12", - .write = slinear12_write, + .write = slinear_write, .seek = slinear_seek, .trunc = slinear_trunc, .tell = slinear_tell, @@ -153,12 +141,11 @@ static struct ast_format_def slin12_f = { .buf_size = 480 + AST_FRIENDLY_OFFSET, }; -static int slinear16_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR16);} -static struct ast_frame *slinear16_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 640, AST_FORMAT_SLINEAR16);} +static struct ast_frame *slinear16_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 640);} static struct ast_format_def slin16_f = { .name = "sln16", .exts = "sln16", - .write = slinear16_write, + .write = slinear_write, .seek = slinear_seek, .trunc = slinear_trunc, .tell = slinear_tell, @@ -166,12 +153,11 @@ static struct ast_format_def slin16_f = { .buf_size = 640 + AST_FRIENDLY_OFFSET, }; -static int slinear24_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR24);} -static struct ast_frame *slinear24_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 960, AST_FORMAT_SLINEAR24);} +static struct ast_frame *slinear24_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 960);} static struct ast_format_def slin24_f = { .name = "sln24", .exts = "sln24", - .write = slinear24_write, + .write = slinear_write, .seek = slinear_seek, .trunc = slinear_trunc, .tell = slinear_tell, @@ -179,12 +165,11 @@ static struct ast_format_def slin24_f = { .buf_size = 960 + AST_FRIENDLY_OFFSET, }; -static int slinear32_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR32);} -static struct ast_frame *slinear32_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 1280, AST_FORMAT_SLINEAR32);} +static struct ast_frame *slinear32_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 1280);} static struct ast_format_def slin32_f = { .name = "sln32", .exts = "sln32", - .write = slinear32_write, + .write = slinear_write, .seek = slinear_seek, .trunc = slinear_trunc, .tell = slinear_tell, @@ -192,12 +177,11 @@ static struct ast_format_def slin32_f = { .buf_size = 1280 + AST_FRIENDLY_OFFSET, }; -static int slinear44_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR44);} -static struct ast_frame *slinear44_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 1764, AST_FORMAT_SLINEAR44);} +static struct ast_frame *slinear44_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 1764);} static struct ast_format_def slin44_f = { .name = "sln44", .exts = "sln44", - .write = slinear44_write, + .write = slinear_write, .seek = slinear_seek, .trunc = slinear_trunc, .tell = slinear_tell, @@ -205,12 +189,11 @@ static struct ast_format_def slin44_f = { .buf_size = 1764 + AST_FRIENDLY_OFFSET, }; -static int slinear48_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR48);} -static struct ast_frame *slinear48_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 1920, AST_FORMAT_SLINEAR48);} +static struct ast_frame *slinear48_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 1920);} static struct ast_format_def slin48_f = { .name = "sln48", .exts = "sln48", - .write = slinear48_write, + .write = slinear_write, .seek = slinear_seek, .trunc = slinear_trunc, .tell = slinear_tell, @@ -218,12 +201,11 @@ static struct ast_format_def slin48_f = { .buf_size = 1920 + AST_FRIENDLY_OFFSET, }; -static int slinear96_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR96);} -static struct ast_frame *slinear96_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 3840, AST_FORMAT_SLINEAR96);} +static struct ast_frame *slinear96_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 3840);} static struct ast_format_def slin96_f = { .name = "sln96", .exts = "sln96", - .write = slinear96_write, + .write = slinear_write, .seek = slinear_seek, .trunc = slinear_trunc, .tell = slinear_tell, @@ -231,12 +213,11 @@ static struct ast_format_def slin96_f = { .buf_size = 3840 + AST_FRIENDLY_OFFSET, }; -static int slinear192_write(struct ast_filestream *fs, struct ast_frame *f){return generic_write(fs, f, AST_FORMAT_SLINEAR192);} -static struct ast_frame *slinear192_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 7680, AST_FORMAT_SLINEAR192);} +static struct ast_frame *slinear192_read(struct ast_filestream *s, int *whennext){return generic_read(s, whennext, 7680);} static struct ast_format_def slin192_f = { .name = "sln192", .exts = "sln192", - .write = slinear192_write, + .write = slinear_write, .seek = slinear_seek, .trunc = slinear_trunc, .tell = slinear_tell, @@ -259,15 +240,16 @@ static struct ast_format_def *slin_list[] = { static int load_module(void) { int i; - ast_format_set(&slin_f.format, AST_FORMAT_SLINEAR, 0); - ast_format_set(&slin12_f.format, AST_FORMAT_SLINEAR12, 0); - ast_format_set(&slin16_f.format, AST_FORMAT_SLINEAR16, 0); - ast_format_set(&slin24_f.format, AST_FORMAT_SLINEAR24, 0); - ast_format_set(&slin32_f.format, AST_FORMAT_SLINEAR32, 0); - ast_format_set(&slin44_f.format, AST_FORMAT_SLINEAR44, 0); - ast_format_set(&slin48_f.format, AST_FORMAT_SLINEAR48, 0); - ast_format_set(&slin96_f.format, AST_FORMAT_SLINEAR96, 0); - ast_format_set(&slin192_f.format, AST_FORMAT_SLINEAR192, 0); + + slin_f.format = ast_format_slin; + slin12_f.format = ast_format_slin12; + slin16_f.format = ast_format_slin16; + slin24_f.format = ast_format_slin24; + slin32_f.format = ast_format_slin32; + slin44_f.format = ast_format_slin44; + slin48_f.format = ast_format_slin48; + slin96_f.format = ast_format_slin96; + slin192_f.format = ast_format_slin192; for (i = 0; i < ARRAY_LEN(slin_list); i++) { if (ast_format_def_register(slin_list[i])) { diff --git a/formats/format_vox.c b/formats/format_vox.c index f640021d8..7beec5e6a 100644 --- a/formats/format_vox.c +++ b/formats/format_vox.c @@ -35,6 +35,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" +#include "asterisk/format_cache.h" #define BUF_SIZE 80 /* 80 bytes, 160 samples */ #define VOX_SAMPLES 160 @@ -44,9 +45,6 @@ static struct ast_frame *vox_read(struct ast_filestream *s, int *whennext) int res; /* Send a frame from the file to the appropriate channel */ - s->fr.frametype = AST_FRAME_VOICE; - ast_format_set(&s->fr.subclass.format, AST_FORMAT_ADPCM, 0); - s->fr.mallocd = 0; AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) < 1) { if (res) @@ -61,14 +59,6 @@ static struct ast_frame *vox_read(struct ast_filestream *s, int *whennext) static int vox_write(struct ast_filestream *s, struct ast_frame *f) { int res; - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); - return -1; - } - if (f->subclass.format.id != AST_FORMAT_ADPCM) { - ast_log(LOG_WARNING, "Asked to write non-ADPCM frame (%s)!\n", ast_getformatname(&f->subclass.format)); - return -1; - } if ((res = fwrite(f->data.ptr, 1, f->datalen, s->f)) != f->datalen) { ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno)); return -1; @@ -147,7 +137,7 @@ static struct ast_format_def vox_f = { static int load_module(void) { - ast_format_set(&vox_f.format, AST_FORMAT_ADPCM, 0); + vox_f.format = ast_format_adpcm; if (ast_format_def_register(&vox_f)) return AST_MODULE_LOAD_FAILURE; return AST_MODULE_LOAD_SUCCESS; diff --git a/formats/format_wav.c b/formats/format_wav.c index 06d6ae12d..fb810625f 100644 --- a/formats/format_wav.c +++ b/formats/format_wav.c @@ -35,6 +35,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" +#include "asterisk/format_cache.h" +#include "asterisk/format.h" +#include "asterisk/codec.h" /* Some Ideas for this code came from makewave.c by Jeffrey Chilton */ @@ -319,7 +322,7 @@ static int wav_open(struct ast_filestream *s) if we did, it would go here. We also might want to check and be sure it's a valid file. */ struct wav_desc *tmp = (struct wav_desc *)s->_private; - if ((tmp->maxlen = check_header(s->f, (s->fmt->format.id == AST_FORMAT_SLINEAR16 ? 16000 : 8000))) < 0) + if ((tmp->maxlen = check_header(s->f, ast_format_get_sample_rate(s->fmt->format))) < 0) return -1; return 0; } @@ -331,7 +334,7 @@ static int wav_rewrite(struct ast_filestream *s, const char *comment) and be sure it's a valid file. */ struct wav_desc *tmp = (struct wav_desc *)s->_private; - tmp->hz = (s->fmt->format.id == AST_FORMAT_SLINEAR16 ? 16000 : 8000); + tmp->hz = ast_format_get_sample_rate(s->fmt->format); if (write_header(s->f,tmp->hz)) return -1; return 0; @@ -379,9 +382,6 @@ static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext) if (bytes < 0) bytes = 0; /* ast_debug(1, "here: %d, maxlen: %d, bytes: %d\n", here, s->maxlen, bytes); */ - s->fr.frametype = AST_FRAME_VOICE; - ast_format_set(&s->fr.subclass.format, (fs->hz == 16000 ? AST_FORMAT_SLINEAR16 : AST_FORMAT_SLINEAR), 0); - s->fr.mallocd = 0; AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, bytes); if ( (res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) <= 0 ) { @@ -412,18 +412,6 @@ static int wav_write(struct ast_filestream *fs, struct ast_frame *f) struct wav_desc *s = (struct wav_desc *)fs->_private; int res; - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); - return -1; - } - if ((f->subclass.format.id != AST_FORMAT_SLINEAR) && (f->subclass.format.id != AST_FORMAT_SLINEAR16)) { - ast_log(LOG_WARNING, "Asked to write non-SLINEAR%s frame (%s)!\n", s->hz == 16000 ? "16" : "", ast_getformatname(&f->subclass.format)); - return -1; - } - if (ast_format_cmp(&f->subclass.format, &fs->fmt->format) == AST_FORMAT_CMP_NOT_EQUAL) { - ast_log(LOG_WARNING, "Can't change SLINEAR frequency during write\n"); - return -1; - } if (!f->datalen) return -1; @@ -547,8 +535,8 @@ static struct ast_format_def wav_f = { static int load_module(void) { - ast_format_set(&wav_f.format, AST_FORMAT_SLINEAR, 0); - ast_format_set(&wav16_f.format, AST_FORMAT_SLINEAR16, 0); + wav_f.format = ast_format_slin; + wav16_f.format = ast_format_slin16; if (ast_format_def_register(&wav_f) || ast_format_def_register(&wav16_f)) return AST_MODULE_LOAD_FAILURE; diff --git a/formats/format_wav_gsm.c b/formats/format_wav_gsm.c index c8d83ff4c..bbb1977a9 100644 --- a/formats/format_wav_gsm.c +++ b/formats/format_wav_gsm.c @@ -38,6 +38,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/mod_format.h" #include "asterisk/module.h" #include "asterisk/endian.h" +#include "asterisk/format_cache.h" #include "msgsm.h" @@ -409,11 +410,7 @@ static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext) /* Send a frame from the file to the appropriate channel */ struct wavg_desc *fs = (struct wavg_desc *)s->_private; - s->fr.frametype = AST_FRAME_VOICE; - ast_format_set(&s->fr.subclass.format, AST_FORMAT_GSM, 0); - s->fr.offset = AST_FRIENDLY_OFFSET; s->fr.samples = GSM_SAMPLES; - s->fr.mallocd = 0; AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, GSM_FRAME_SIZE); if (fs->secondhalf) { /* Just return a frame based on the second GSM frame */ @@ -443,14 +440,6 @@ static int wav_write(struct ast_filestream *s, struct ast_frame *f) int size; struct wavg_desc *fs = (struct wavg_desc *)s->_private; - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); - return -1; - } - if (f->subclass.format.id != AST_FORMAT_GSM) { - ast_log(LOG_WARNING, "Asked to write non-GSM frame (%s)!\n", ast_getformatname(&f->subclass.format)); - return -1; - } /* XXX this might fail... if the input is a multiple of MSGSM_FRAME_SIZE * we assume it is already in the correct format. */ @@ -577,7 +566,7 @@ static struct ast_format_def wav49_f = { static int load_module(void) { - ast_format_set(&wav49_f.format, AST_FORMAT_GSM, 0); + wav49_f.format = ast_format_gsm; if (ast_format_def_register(&wav49_f)) return AST_MODULE_LOAD_FAILURE; return AST_MODULE_LOAD_SUCCESS; diff --git a/funcs/func_channel.c b/funcs/func_channel.c index 82fb4c348..3f756f0b5 100644 --- a/funcs/func_channel.c +++ b/funcs/func_channel.c @@ -427,23 +427,27 @@ static int func_channel_read(struct ast_channel *chan, const char *function, } if (!strcasecmp(data, "audionativeformat")) { - char tmp[512]; + tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (tmpcap) { + struct ast_str *codec_buf = ast_str_alloca(64); - if ((tmpcap = ast_format_cap_get_type(ast_channel_nativeformats(chan), AST_FORMAT_TYPE_AUDIO))) { - ast_copy_string(buf, ast_getformatname_multiple(tmp, sizeof(tmp), tmpcap), len); - tmpcap = ast_format_cap_destroy(tmpcap); + ast_format_cap_append_from_cap(tmpcap, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_AUDIO); + ast_copy_string(buf, ast_format_cap_get_names(tmpcap, &codec_buf), len); + ao2_ref(tmpcap, -1); } } else if (!strcasecmp(data, "videonativeformat")) { - char tmp[512]; + tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (tmpcap) { + struct ast_str *codec_buf = ast_str_alloca(64); - if ((tmpcap = ast_format_cap_get_type(ast_channel_nativeformats(chan), AST_FORMAT_TYPE_VIDEO))) { - ast_copy_string(buf, ast_getformatname_multiple(tmp, sizeof(tmp), tmpcap), len); - tmpcap = ast_format_cap_destroy(tmpcap); + ast_format_cap_append_from_cap(tmpcap, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_VIDEO); + ast_copy_string(buf, ast_format_cap_get_names(tmpcap, &codec_buf), len); + ao2_ref(tmpcap, -1); } } else if (!strcasecmp(data, "audioreadformat")) { - ast_copy_string(buf, ast_getformatname(ast_channel_readformat(chan)), len); + ast_copy_string(buf, ast_format_get_name(ast_channel_readformat(chan)), len); } else if (!strcasecmp(data, "audiowriteformat")) { - ast_copy_string(buf, ast_getformatname(ast_channel_writeformat(chan)), len); + ast_copy_string(buf, ast_format_get_name(ast_channel_writeformat(chan)), len); #ifdef CHANNEL_TRACE } else if (!strcasecmp(data, "trace")) { ast_channel_lock(chan); diff --git a/funcs/func_frame_trace.c b/funcs/func_frame_trace.c index ecebde4df..681a96924 100644 --- a/funcs/func_frame_trace.c +++ b/funcs/func_frame_trace.c @@ -219,14 +219,14 @@ static void print_frame(struct ast_frame *frame) break; case AST_FRAME_VOICE: ast_verbose("FrameType: VOICE\n"); - ast_verbose("Codec: %s\n", ast_getformatname(&frame->subclass.format)); + ast_verbose("Codec: %s\n", ast_format_get_name(frame->subclass.format)); ast_verbose("MS: %ld\n", frame->len); ast_verbose("Samples: %d\n", frame->samples); ast_verbose("Bytes: %d\n", frame->datalen); break; case AST_FRAME_VIDEO: ast_verbose("FrameType: VIDEO\n"); - ast_verbose("Codec: %s\n", ast_getformatname(&frame->subclass.format)); + ast_verbose("Codec: %s\n", ast_format_get_name(frame->subclass.format)); ast_verbose("MS: %ld\n", frame->len); ast_verbose("Samples: %d\n", frame->samples); ast_verbose("Bytes: %d\n", frame->datalen); diff --git a/funcs/func_pitchshift.c b/funcs/func_pitchshift.c index e5091d95d..0aaa2b602 100644 --- a/funcs/func_pitchshift.c +++ b/funcs/func_pitchshift.c @@ -172,9 +172,7 @@ static int pitchshift_cb(struct ast_audiohook *audiohook, struct ast_channel *ch if (!f) { return 0; } - if ((audiohook->status == AST_AUDIOHOOK_STATUS_DONE) || - (f->frametype != AST_FRAME_VOICE) || - !(ast_format_is_slinear(&f->subclass.format))) { + if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) { return -1; } @@ -489,7 +487,7 @@ static int pitch_shift(struct ast_frame *f, float amount, struct fft_data *fft) return 0; } for (samples = 0; samples < f->samples; samples += 32) { - smb_pitch_shift(amount, 32, MAX_FRAME_LENGTH, 32, ast_format_rate(&f->subclass.format), fun+samples, fun+samples, fft); + smb_pitch_shift(amount, 32, MAX_FRAME_LENGTH, 32, ast_format_get_sample_rate(f->subclass.format), fun+samples, fun+samples, fft); } return 0; diff --git a/funcs/func_speex.c b/funcs/func_speex.c index 4e3c13b87..d0d451bd1 100644 --- a/funcs/func_speex.c +++ b/funcs/func_speex.c @@ -165,8 +165,8 @@ static int speex_callback(struct ast_audiohook *audiohook, struct ast_channel *c return -1; } - if ((sdi->samples != frame->samples) || (ast_format_rate(&frame->subclass.format) != si->lastrate)) { - si->lastrate = ast_format_rate(&frame->subclass.format); + if ((sdi->samples != frame->samples) || (ast_format_get_sample_rate(frame->subclass.format) != si->lastrate)) { + si->lastrate = ast_format_get_sample_rate(frame->subclass.format); if (sdi->state) { speex_preprocess_state_destroy(sdi->state); } diff --git a/funcs/func_talkdetect.c b/funcs/func_talkdetect.c index c4783f51f..f127fa3d7 100644 --- a/funcs/func_talkdetect.c +++ b/funcs/func_talkdetect.c @@ -284,7 +284,7 @@ static int set_talk_detect(struct ast_channel *chan, int dsp_silence_threshold, td_params->audiohook.manipulate_callback = talk_detect_audiohook_cb; ast_set_flag(&td_params->audiohook, AST_AUDIOHOOK_TRIGGER_READ); - td_params->dsp = ast_dsp_new_with_rate(ast_format_rate(ast_channel_rawreadformat(chan))); + td_params->dsp = ast_dsp_new_with_rate(ast_format_get_sample_rate(ast_channel_rawreadformat(chan))); if (!td_params->dsp) { ast_datastore_free(datastore); ast_free(td_params); diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h index 67d17382b..01a8352fc 100644 --- a/include/asterisk/_private.h +++ b/include/asterisk/_private.h @@ -121,16 +121,6 @@ int ast_xmldoc_load_documentation(void); */ int ast_plc_reload(void); -/*! - * \brief Init the ast_format attribute interface register container. - */ -int ast_format_attr_init(void); - -/*! - * \brief Init the Asterisk global format list after all format attribute modules have been loaded - */ -int ast_format_list_init(void); - /*! \brief initializes the rtp engine arrays */ int ast_rtp_engine_init(void); diff --git a/include/asterisk/abstract_jb.h b/include/asterisk/abstract_jb.h index 6a4d0610d..8a5e3d27f 100644 --- a/include/asterisk/abstract_jb.h +++ b/include/asterisk/abstract_jb.h @@ -145,7 +145,7 @@ struct ast_jb /*! \brief The time the next frame should be played. */ long next; /*! \brief Voice format of the last frame in. */ - struct ast_format last_format; + struct ast_format *last_format; /*! \brief File for frame timestamp tracing. */ FILE *logfile; /*! \brief Jitterbuffer internal state flags. */ diff --git a/include/asterisk/audiohook.h b/include/asterisk/audiohook.h index 6b0716092..375b2dd9d 100644 --- a/include/asterisk/audiohook.h +++ b/include/asterisk/audiohook.h @@ -109,7 +109,7 @@ struct ast_audiohook { struct ast_slinfactory write_factory; /*!< Factory where frames written to the channel will go through */ struct timeval read_time; /*!< Last time read factory was fed */ struct timeval write_time; /*!< Last time write factory was fed */ - struct ast_format format; /*!< Format translation path is setup as */ + struct ast_format *format; /*!< Format translation path is setup as */ struct ast_trans_pvt *trans_pvt; /*!< Translation path for reading frames */ ast_audiohook_manipulate_callback manipulate_callback; /*!< Manipulation callback */ struct ast_audiohook_options options; /*!< Applicable options */ diff --git a/include/asterisk/bridge_channel.h b/include/asterisk/bridge_channel.h index ae8369d15..387c048f8 100644 --- a/include/asterisk/bridge_channel.h +++ b/include/asterisk/bridge_channel.h @@ -133,9 +133,9 @@ struct ast_bridge_channel { * optimizing based upon talk detection. */ struct ast_bridge_tech_optimizations tech_args; /*! Copy of read format used by chan before join */ - struct ast_format read_format; + struct ast_format *read_format; /*! Copy of write format used by chan before join */ - struct ast_format write_format; + struct ast_format *write_format; /*! Call ID associated with bridge channel */ struct ast_callid *callid; /*! A clone of the roles living on chan when the bridge channel joins the bridge. This may require some opacification */ diff --git a/include/asterisk/callerid.h b/include/asterisk/callerid.h index 4f32dbf66..f7d7719d2 100644 --- a/include/asterisk/callerid.h +++ b/include/asterisk/callerid.h @@ -75,8 +75,8 @@ /*! MWI MDMF format -- generate name, callerid, date and MWI fields */ #define CID_MWI_TYPE_MDMF_FULL 0x02 -#define AST_LIN2X(a) ((codec->id == AST_FORMAT_ALAW) ? (AST_LIN2A(a)) : (AST_LIN2MU(a))) -#define AST_XLAW(a) ((codec->id == AST_FORMAT_ALAW) ? (AST_ALAW(a)) : (AST_MULAW(a))) +#define AST_LIN2X(a) ((ast_format_cmp(codec, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) ? (AST_LIN2A(a)) : (AST_LIN2MU(a))) +#define AST_XLAW(a) ((ast_format_cmp(codec, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) ? (AST_ALAW(a)) : (AST_MULAW(a))) struct callerid_state; diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index dec19cba0..d118bc81f 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -1883,14 +1883,6 @@ int ast_set_read_format_from_cap(struct ast_channel *chan, struct ast_format_cap int ast_set_read_format(struct ast_channel *chan, struct ast_format *format); /*! - * \brief Sets read format on channel chan by id - * \param chan channel to change - * \param id format id to set for reading, only used for formats without attributes - * \return Returns 0 on success, -1 on failure - */ -int ast_set_read_format_by_id(struct ast_channel *chan, enum ast_format_id id); - -/*! * \brief Sets write format on channel chan * Set write format for channel to whichever component of "format" is best. * \param chan channel to change @@ -1908,14 +1900,6 @@ int ast_set_write_format_from_cap(struct ast_channel *chan, struct ast_format_ca int ast_set_write_format(struct ast_channel *chan, struct ast_format *format); /*! - * \brief Sets write format on channel chan - * \param chan channel to change - * \param id format id to set for writing, only used for formats without attributes - * \return Returns 0 on success, -1 on failure - */ -int ast_set_write_format_by_id(struct ast_channel *chan, enum ast_format_id id); - -/*! * \brief Sends text to a channel * * \param chan channel to act upon @@ -2103,17 +2087,6 @@ char *ast_transfercapability2str(int transfercapability) attribute_const; int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block); /*! - * \brief Pick the best codec - * - * \param cap capabilities to pick best codec out of - * \param result stucture to store the best codec in. - * \retval on success, pointer to result structure - * \retval on failure, NULL - */ -struct ast_format *ast_best_codec(struct ast_format_cap *cap, struct ast_format *result); - - -/*! * \brief Checks the value of an option * * Query the value of an option @@ -4008,6 +3981,13 @@ struct ast_format *ast_channel_rawwriteformat(struct ast_channel *chan); struct ast_format *ast_channel_readformat(struct ast_channel *chan); struct ast_format *ast_channel_writeformat(struct ast_channel *chan); +/* Format setters - all of these functions will increment the reference count of the format passed in */ +void ast_channel_set_oldwriteformat(struct ast_channel *chan, struct ast_format *format); +void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format); +void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format); +void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format); +void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format); + /* Other struct getters */ struct ast_frame *ast_channel_dtmff(struct ast_channel *chan); struct ast_jb *ast_channel_jb(struct ast_channel *chan); diff --git a/include/asterisk/codec.h b/include/asterisk/codec.h new file mode 100644 index 000000000..28befec50 --- /dev/null +++ b/include/asterisk/codec.h @@ -0,0 +1,186 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Joshua Colp <jcolp@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Codec API + * + * \author Joshua Colp <jcolp@digium.com> + */ + +#ifndef _AST_CODEC_H_ +#define _AST_CODEC_H_ + +/*! \brief Types of media */ +enum ast_media_type { + AST_MEDIA_TYPE_UNKNOWN = 0, + AST_MEDIA_TYPE_AUDIO, + AST_MEDIA_TYPE_VIDEO, + AST_MEDIA_TYPE_IMAGE, + AST_MEDIA_TYPE_TEXT, +}; + +struct ast_module; + +/*! \brief Represents a media codec within Asterisk. */ +struct ast_codec { + /*! \brief Internal unique identifier for this codec, set at registration time (starts at 1) */ + unsigned int id; + /*! \brief Name for this codec */ + const char *name; + /*! \brief Brief description */ + const char *description; + /*! \brief Type of media this codec contains */ + enum ast_media_type type; + /*! \brief Sample rate (number of samples carried in a second) */ + unsigned int sample_rate; + /*! \brief Minimum length of media that can be carried (in milliseconds) in a frame */ + unsigned int minimum_ms; + /*! \brief Maximum length of media that can be carried (in milliseconds) in a frame */ + unsigned int maximum_ms; + /*! \brief Default length of media carried (in milliseconds) in a frame */ + unsigned int default_ms; + /*! \brief Length in bytes of the data payload of a minimum_ms frame */ + unsigned int minimum_bytes; + /*! + * \brief Retrieve the number of samples in a frame + * + * \param frame The frame to examine + * + * \return the number of samples + */ + int (*samples_count)(struct ast_frame *frame); + /*! + * \brief Retrieve the length of media from number of samples + * + * \param samples The number of samples + * + * \return The length of media in milliseconds + */ + int (*get_length)(unsigned int samples); + /*! \brief Whether the media can be smoothed or not */ + unsigned int smooth; + /*! \brief The module that registered this codec */ + struct ast_module *mod; +}; + +/*! + * \brief Initialize codec support within the core. + * + * \retval 0 success + * \retval -1 failure + */ +int ast_codec_init(void); + +/*! + * \brief Initialize built-in codecs within the core. + * + * \retval 0 success + * \retval -1 failure + */ +int ast_codec_builtin_init(void); + +/*! + * \brief This function is used to register a codec with the Asterisk core. Registering + * allows it to be passed through in frames and configured in channel drivers. + * + * \param codec to register + * \param mod the module this codec is provided by + * + * \retval 0 success + * \retval -1 failure + */ +int __ast_codec_register(struct ast_codec *codec, struct ast_module *mod); + +/*! + * \brief This function is used to register a codec with the Asterisk core. Registering + * allows it to be passed through in frames and configured in channel drivers. + * + * \param codec to register + * + * \retval 0 success + * \retval -1 failure + */ +#define ast_codec_register(codec) __ast_codec_register(codec, ast_module_info->self) + +/*! + * \brief Retrieve a codec given a name, type, and sample rate + * + * \param name The name of the codec + * \param type The type of the codec + * \param sample_rate Optional sample rate, may not be applicable for some types + * + * \retval non-NULL success + * \retval NULL failure + * + * \note The returned codec is reference counted and ao2_ref or ao2_cleanup + * must be used to release the reference. + */ +struct ast_codec *ast_codec_get(const char *name, enum ast_media_type type, unsigned int sample_rate); + +/*! + * \brief Retrieve a codec given the unique identifier + * + * \param id The unique identifier + * + * \retval non-NULL success + * \retval NULL failure + * + * \note Identifiers start at 1 so if iterating don't start at 0. + * + * \note The returned codec is reference counted and ao2_ref or ao2_cleanup + * must be used to release the reference. + */ +struct ast_codec *ast_codec_get_by_id(int id); + +/*! + * \brief Retrieve the current maximum identifier for codec iteration + * + * \return Maximum codec identifier + */ +int ast_codec_get_max(void); + +/*! + * \brief Conversion function to take a media type and turn it into a string + * + * \param type The media type + * + * \retval string representation of the media type + */ +const char *ast_codec_media_type2str(enum ast_media_type type); + +/*! + * \brief Get the number of samples contained within a frame + * + * \param frame The frame itself + * + * \retval number of samples in the frame + */ +unsigned int ast_codec_samples_count(struct ast_frame *frame); + +/*! + * \brief Get the length of media (in milliseconds) given a number of samples + * + * \param codec The codec itself + * \param samples The number of samples + * + * \retval length of media (in milliseconds) + */ +unsigned int ast_codec_determine_length(const struct ast_codec *codec, unsigned int samples); + +#endif /* _AST_CODEC_H */ diff --git a/include/asterisk/config_options.h b/include/asterisk/config_options.h index 11a8c5bf9..30c042176 100644 --- a/include/asterisk/config_options.h +++ b/include/asterisk/config_options.h @@ -317,21 +317,20 @@ enum aco_option_type { */ OPT_CHAR_ARRAY_T, - /*! \brief Type for default option handler for codec preferences/capabilities + /*! \brief Type for default option handler for format capabilities * \note aco_option_register flags: * non-zero : This is an "allow" style option * 0 : This is a "disallow" style option * aco_option_register varargs: - * FLDSET macro with fields representing a struct ast_codec_pref and a struct ast_format_cap * + * FLDSET macro with field representing a struct ast_format_cap * * * Example: * {code} * struct test_item { - * struct ast_codec_pref pref; * struct ast_format cap *cap; * }; - * aco_option_register(&cfg_info, "allow", ACO_EXACT, my_types, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct test_item, pref, cap)); - * aco_option_register(&cfg_info, "disallow", ACO_EXACT, my_types, "all", OPT_CODEC_T, 0, FLDSET(struct test_item, pref, cap)); + * aco_option_register(&cfg_info, "allow", ACO_EXACT, my_types, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct test_item, cap)); + * aco_option_register(&cfg_info, "disallow", ACO_EXACT, my_types, "all", OPT_CODEC_T, 0, FLDSET(struct test_item, cap)); * {endcode} */ OPT_CODEC_T, diff --git a/include/asterisk/data.h b/include/asterisk/data.h index e3253377e..3676b8df5 100644 --- a/include/asterisk/data.h +++ b/include/asterisk/data.h @@ -26,6 +26,7 @@ #define ASTERISK_DATA_H #include "asterisk/frame.h" +#include "asterisk/format_cap.h" /*! * \page AstDataRetrieval The Asterisk DATA retrieval API. diff --git a/include/asterisk/file.h b/include/asterisk/file.h index 372c0f7ed..3d8d2c97c 100644 --- a/include/asterisk/file.h +++ b/include/asterisk/file.h @@ -385,7 +385,7 @@ char *ast_format_str_reduce(char *fmts); * \retval NULL if not found * \retval A pointer to the ast_format associated with this file extension */ -const struct ast_format *ast_get_format_for_file_ext(const char *file_ext); +struct ast_format *ast_get_format_for_file_ext(const char *file_ext); #if defined(__cplusplus) || defined(c_plusplus) } diff --git a/include/asterisk/format.h b/include/asterisk/format.h index 885c62b2d..32f9f2b40 100644 --- a/include/asterisk/format.h +++ b/include/asterisk/format.h @@ -1,9 +1,9 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 2010, Digium, Inc. + * Copyright (C) 2014, Digium, Inc. * - * David Vossel <dvossel@digium.com> + * Joshua Colp <jcolp@digium.com> * * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact @@ -18,464 +18,354 @@ /*! * \file - * \brief Format API + * \brief Media Format API * - * \author David Vossel <dvossel@digium.com> + * \author Joshua Colp <jcolp@digium.com> */ +#include "asterisk/codec.h" + #ifndef _AST_FORMAT_H_ #define _AST_FORMAT_H_ -#include "asterisk/astobj2.h" -#include "asterisk/silk.h" -#include "asterisk/celt.h" -#include "asterisk/opus.h" -#define AST_FORMAT_ATTR_SIZE 64 -#define AST_FORMAT_INC 100000 - -/*! This is the value that ends a var list of format attribute - * key value pairs. */ -#define AST_FORMAT_ATTR_END -1 - -/* \brief Format Categories*/ -enum ast_format_type { - AST_FORMAT_TYPE_AUDIO = 1 * AST_FORMAT_INC, - AST_FORMAT_TYPE_VIDEO = 2 * AST_FORMAT_INC, - AST_FORMAT_TYPE_IMAGE = 3 * AST_FORMAT_INC, - AST_FORMAT_TYPE_TEXT = 4 * AST_FORMAT_INC, -}; - -enum ast_format_id { - /*! G.723.1 compression */ - AST_FORMAT_G723_1 = 1 + AST_FORMAT_TYPE_AUDIO, - /*! GSM compression */ - AST_FORMAT_GSM = 2 + AST_FORMAT_TYPE_AUDIO, - /*! Raw mu-law data (G.711) */ - AST_FORMAT_ULAW = 3 + AST_FORMAT_TYPE_AUDIO, - /*! Raw A-law data (G.711) */ - AST_FORMAT_ALAW = 4 + AST_FORMAT_TYPE_AUDIO, - /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */ - AST_FORMAT_G726_AAL2 = 5 + AST_FORMAT_TYPE_AUDIO, - /*! ADPCM (IMA) */ - AST_FORMAT_ADPCM = 6 + AST_FORMAT_TYPE_AUDIO, - /*! LPC10, 180 samples/frame */ - AST_FORMAT_LPC10 = 7 + AST_FORMAT_TYPE_AUDIO, - /*! G.729A audio */ - AST_FORMAT_G729A = 8 + AST_FORMAT_TYPE_AUDIO, - /*! SpeeX Free Compression */ - AST_FORMAT_SPEEX = 9 + AST_FORMAT_TYPE_AUDIO, - /*! iLBC Free Compression */ - AST_FORMAT_ILBC = 10 + AST_FORMAT_TYPE_AUDIO, - /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */ - AST_FORMAT_G726 = 11 + AST_FORMAT_TYPE_AUDIO, - /*! G.722 */ - AST_FORMAT_G722 = 12 + AST_FORMAT_TYPE_AUDIO, - /*! G.722.1 (also known as Siren7, 32kbps assumed) */ - AST_FORMAT_SIREN7 = 13 + AST_FORMAT_TYPE_AUDIO, - /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */ - AST_FORMAT_SIREN14 = 14 + AST_FORMAT_TYPE_AUDIO, - /*! G.719 (64 kbps assumed) */ - AST_FORMAT_G719 = 15 + AST_FORMAT_TYPE_AUDIO, - /*! SpeeX Wideband (16kHz) Free Compression */ - AST_FORMAT_SPEEX16 = 16 + AST_FORMAT_TYPE_AUDIO, - /*! Raw mu-law data (G.711) */ - AST_FORMAT_TESTLAW = 17 + AST_FORMAT_TYPE_AUDIO, - /*! SILK format */ - AST_FORMAT_SILK = 18 + AST_FORMAT_TYPE_AUDIO, - /*! Raw 16-bit Signed Linear (8000 Hz) PCM */ - AST_FORMAT_SLINEAR = 19 + AST_FORMAT_TYPE_AUDIO, - /*! Raw 16-bit Signed Linear (12000 Hz) PCM */ - AST_FORMAT_SLINEAR12 = 20 + AST_FORMAT_TYPE_AUDIO, - /*! Raw 16-bit Signed Linear (16000 Hz) PCM */ - AST_FORMAT_SLINEAR16 = 21 + AST_FORMAT_TYPE_AUDIO, - /*! Raw 16-bit Signed Linear (24000 Hz) PCM */ - AST_FORMAT_SLINEAR24 = 22 + AST_FORMAT_TYPE_AUDIO, - /*! Raw 16-bit Signed Linear (32000 Hz) PCM */ - AST_FORMAT_SLINEAR32 = 23 + AST_FORMAT_TYPE_AUDIO, - /*! Raw 16-bit Signed Linear (44100 Hz) PCM just because we can. */ - AST_FORMAT_SLINEAR44 = 24 + AST_FORMAT_TYPE_AUDIO, - /*! Raw 16-bit Signed Linear (48000 Hz) PCM */ - AST_FORMAT_SLINEAR48 = 25 + AST_FORMAT_TYPE_AUDIO, - /*! Raw 16-bit Signed Linear (96000 Hz) PCM */ - AST_FORMAT_SLINEAR96 = 26 + AST_FORMAT_TYPE_AUDIO, - /*! Raw 16-bit Signed Linear (192000 Hz) PCM. maybe we're taking this too far. */ - AST_FORMAT_SLINEAR192 = 27 + AST_FORMAT_TYPE_AUDIO, - AST_FORMAT_SPEEX32 = 28 + AST_FORMAT_TYPE_AUDIO, - AST_FORMAT_CELT = 29 + AST_FORMAT_TYPE_AUDIO, - /*! Opus */ - AST_FORMAT_OPUS = 30 + AST_FORMAT_TYPE_AUDIO, - - /*! H.261 Video */ - AST_FORMAT_H261 = 1 + AST_FORMAT_TYPE_VIDEO, - /*! H.263 Video */ - AST_FORMAT_H263 = 2 + AST_FORMAT_TYPE_VIDEO, - /*! H.263+ Video */ - AST_FORMAT_H263_PLUS = 3 + AST_FORMAT_TYPE_VIDEO, - /*! H.264 Video */ - AST_FORMAT_H264 = 4 + AST_FORMAT_TYPE_VIDEO, - /*! MPEG4 Video */ - AST_FORMAT_MP4_VIDEO = 5 + AST_FORMAT_TYPE_VIDEO, - /*! VP8 */ - AST_FORMAT_VP8 = 6 + AST_FORMAT_TYPE_VIDEO, - - /*! JPEG Images */ - AST_FORMAT_JPEG = 1 + AST_FORMAT_TYPE_IMAGE, - /*! PNG Images */ - AST_FORMAT_PNG = 2 + AST_FORMAT_TYPE_IMAGE, - - /*! T.140 RED Text format RFC 4103 */ - AST_FORMAT_T140RED = 1 + AST_FORMAT_TYPE_TEXT, - /*! T.140 Text format - ITU T.140, RFC 4103 */ - AST_FORMAT_T140 = 2 + AST_FORMAT_TYPE_TEXT, -}; - -/*! Determine what type of media a ast_format_id is. */ -#define AST_FORMAT_GET_TYPE(id) (((int) (id / AST_FORMAT_INC)) * AST_FORMAT_INC) - - -/*! \brief This structure contains the buffer used for format attributes */ -struct ast_format_attr { - /*! The buffer formats can use to represent attributes */ - uint32_t format_attr[AST_FORMAT_ATTR_SIZE]; - /*! If a format's payload needs to pass through that a new marker is required - * for RTP, this variable will be set. */ - uint8_t rtp_marker_bit; -}; - -/*! \brief Represents a media format within Asterisk. */ -struct ast_format { - /*! The unique id representing this format from all the other formats. */ - enum ast_format_id id; - /*! Attribute structure used to associate attributes with a format. */ - struct ast_format_attr fattr; -}; +struct ast_format; +/*! \brief Format comparison results */ enum ast_format_cmp_res { - /*! structure 1 is identical to structure 2. */ + /*! Both formats are equivalent to eachother */ AST_FORMAT_CMP_EQUAL = 0, - /*! structure 1 contains elements not in structure 2. */ + /*! Both formats are completely different and not the same in any way */ AST_FORMAT_CMP_NOT_EQUAL, - /*! structure 1 is a proper subset of the elements in structure 2.*/ + /*! Both formats are similar but not equivalent */ AST_FORMAT_CMP_SUBSET, }; -/*! \brief Definition of supported media formats (codecs) */ -struct ast_format_list { - struct ast_format format; /*!< The unique format. */ - char name[64]; /*!< short name */ - unsigned int samplespersecond; /*!< Number of samples per second (8000/16000) */ - char desc[128]; /*!< Description */ - int fr_len; /*!< Single frame length in bytes */ - int min_ms; /*!< Min value */ - int max_ms; /*!< Max value */ - int inc_ms; /*!< Increment */ - int def_ms; /*!< Default value */ - unsigned int flags; /*!< Smoother flags */ - int cur_ms; /*!< Current value */ - int custom_entry; -}; - -/*! \brief A format must register an attribute interface if it requires the use of the format attributes void pointer */ -struct ast_format_attr_interface { - /*! format type */ - enum ast_format_id id; - - /*! \brief Determine if format_attr 1 is a subset of format_attr 2. +/*! \brief Optional format interface to extend format operations */ +struct ast_format_interface { + /*! + * \brief Callback for when the format is destroyed, used to release attribute resources * - * \retval ast_format_cmp_res representing the result of comparing fattr1 and fattr2. + * \param format The format structure to destroy */ - enum ast_format_cmp_res (* const format_attr_cmp)(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2); + void (*const format_destroy)(struct ast_format *format); - /*! \brief Get joint attributes of same format type if they exist. + /*! + * \brief Callback for when the format is cloned, used to clone attributes + * + * \param src Source format of attributes + * \param dst Destination format for attributes * - * \retval 0 if joint attributes exist - * \retval -1 if no joint attributes are present + * \retval 0 success + * \retval -1 failure */ - int (* const format_attr_get_joint)(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result); - - /*! \brief Set format capabilities from a list of key value pairs ending with AST_FORMAT_ATTR_END. - * \note This function does not need to call va_end of the va_list. */ - void (* const format_attr_set)(struct ast_format_attr *format_attr, va_list ap); + int (*const format_clone)(const struct ast_format *src, struct ast_format *dst); /*! - * \brief Find out if format capabilities in va_list are in format. - * \note This function does not need to call va_end of the va_list. + * \brief Determine if format 1 is a subset of format 2. * - * \note This function is optional. In many cases the format_attr_cmp - * function can be used to derive these results. If it is possible - * that some format attributes have no bearing on the equality of two formats, this - * function must exist. + * \param format1 First format to compare + * \param format2 Second format which the first is compared against * - * \retval 0 if all attributes exist - * \retval -1 if any of the attributes not present + * \retval ast_format_cmp_res representing the result of comparing format1 and format2. */ - int (* const format_attr_isset)(const struct ast_format_attr *format_attr, va_list ap); + enum ast_format_cmp_res (* const format_cmp)(const struct ast_format *format1, + const struct ast_format *format2); - /* - * \brief Return a value for a specific format key. Return that value in the void pointer. + /*! + * \brief Get a format with the joint compatible attributes of both provided formats. + * + * \param format1 The first format + * \param format2 The second format + * + * \retval non-NULL if joint format + * \retval NULL if no joint format * - * \note It is not expected that all key value pairs can be returned, but those that can should - * be documented as such. + * \note The returned format has its reference count incremented and must be released using + * ao2_ref or ao2_cleanup. + */ + struct ast_format *(* const format_get_joint)(const struct ast_format *format1, + const struct ast_format *format2); + + /*! + * \brief Set an attribute on a format * - * \note This function is optional if key value pairs are not allowed to be accessed. This - * will result in -1 always being returned. + * \param name The name of the attribute + * \param value The value of the attribute * - * \retval 0 Success, value was found and copied into void pointer. - * \retval -1 failure, Value was either not found, or not allowed to be accessed. + * \retval non-NULL success + * \retval NULL failure */ - int (* const format_attr_get_val)(const struct ast_format_attr *format_attr, int key, void *val); + struct ast_format *(* const format_attribute_set)(const struct ast_format *format, + const char *name, const char *value); - /* - * \brief Parse SDP attribute information, interpret it, and store it in ast_format_attr structure. + /*! + * \brief Parse SDP attribute information, interpret it, and store it in the format structure. + * + * \param format Format to set attributes on + * \param attributes A string containing only the attributes from the fmtp line * - * \retval 0 Success, values were valid - * \retval -1 Failure, some values were not acceptable + * \retval non-NULL Success, values were valid + * \retval NULL Failure, some values were not acceptable */ - int (* const format_attr_sdp_parse)(struct ast_format_attr *format_attr, const char *attributes); + struct ast_format *(* const format_parse_sdp_fmtp)(const struct ast_format *format, const char *attributes); /*! * \brief Generate SDP attribute information from an ast_format_attr structure. * + * \param format The format containing attributes + * \param payload The payload number to place into the fmtp line + * \param str The generated fmtp line + * * \note This callback should generate a full fmtp line using the provided payload number. */ - void (* const format_attr_sdp_generate)(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str); + void (* const format_generate_sdp_fmtp)(const struct ast_format *format, unsigned int payload, + struct ast_str **str); }; /*! - * \brief This function is used to have a media format aware module parse and interpret - * SDP attribute information. Once interpreted this information is stored on the format - * itself using Asterisk format attributes. + * \brief Initialize media format support * - * \param format to set - * \param attributes string containing the fmtp line from the SDP - * - * \retval 0 success, attribute values were valid - * \retval -1 failure, values were not acceptable + * \retval 0 success + * \retval -1 failure */ -int ast_format_sdp_parse(struct ast_format *format, const char *attributes); +int ast_format_init(void); /*! - * \brief This function is used to produce an fmtp SDP line for an Asterisk format. The - * attributes present on the Asterisk format are translated into the SDP equivalent. + * \brief Create a new media format * - * \param format to generate an fmtp line for - * \param payload numerical payload for the fmtp line - * \param str structure that the fmtp line will be appended to + * \param codec The codec to use + * + * \retval non-NULL success + * \retval NULL failure + * + * \note The format is returned with reference count incremented. It must be released using + * ao2_ref or ao2_cleanup. */ -void ast_format_sdp_generate(const struct ast_format *format, unsigned int payload, struct ast_str **str); +struct ast_format *ast_format_create(struct ast_codec *codec); /*! - * \brief This function is used to set an ast_format object to represent a media format - * with optional format attributes represented by format specific key value pairs. - * - * \param format to set - * \param id format id to set on format - * \param set_attributes are there attributes to set on this format. 0 == false, 1 == True. - * \param ... var list of attribute key value pairs, must end with AST_FORMAT_ATTR_END; + * \brief Create a new media format with a specific name * - * \details Example usage. - * ast_format_set(format, AST_FORMAT_ULAW, 0); // no capability attributes are needed for ULAW + * \param format_name The name to use for the format + * \param codec The codec to use * - * ast_format_set(format, AST_FORMAT_SILK, 1, // SILK has capability attributes. - * AST_FORMAT_SILK_ATTR_RATE, 24000, - * AST_FORMAT_SILK_ATTR_RATE, 16000, - * AST_FORMAT_SILK_ATTR_RATE, 12000, - * AST_FORMAT_SILK_ATTR_RATE, 8000, - * AST_FORMAT_ATTR_END); + * \note This creation function should be used when the name of the \c codec + * cannot be explicitly used for the name of the format. This is the case for + * codecs with multiple sample rates * - * \note This function will initialize the ast_format structure. + * \note The format is returned with reference count incremented. It must be released using + * ao2_ref or ao2_cleanup. * - * \return Pointer to ast_format object, same pointer that is passed in - * by the first argument. + * \retval non-NULL success + * \retval NULL failure */ -struct ast_format *ast_format_set(struct ast_format *format, enum ast_format_id id, int set_attributes, ... ); +struct ast_format *ast_format_create_named(const char *format_name, struct ast_codec *codec); /*! - * \brief After ast_format_set has been used on a function, this function can be used to - * set additional format attributes to the structure. + * \brief Clone an existing media format so it can be modified * - * \param format to set - * \param ... var list of attribute key value pairs, must end with AST_FORMAT_ATTR_END; - * - * \details Example usage. - * ast_format_set(format, AST_FORMAT_SILK, 0); - * ast_format_append(format, // SILK has capability attributes. - * AST_FORMAT_SILK_ATTR_RATE, 24000, - * AST_FORMAT_SILK_ATTR_RATE, 16000, - * AST_FORMAT_SILK_ATTR_RATE, 12000, - * AST_FORMAT_SILK_ATTR_RATE, 8000, - * AST_FORMAT_ATTR_END); - * - * \return Pointer to ast_format object, same pointer that is passed in - * by the first argument. + * \param format The existing media format + * + * \note The returned format is a new ao2 object. It must be released using ao2_cleanup. + * + * \retval non-NULL success + * \retval NULL failure */ -struct ast_format *ast_format_append(struct ast_format *format, ... ); +struct ast_format *ast_format_clone(const struct ast_format *format); /*! - * \brief Clears the format stucture. + * \brief Compare two formats + * + * \retval ast_format_cmp_res representing the result of comparing format1 and format2. */ -void ast_format_clear(struct ast_format *format); +enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2); /*! - * \brief This function is used to set an ast_format object to represent a media format - * with optional capability attributes represented by format specific key value pairs. + * \brief Get a common joint capability between two formats * - * \details Example usage. Is this SILK format capable of 8khz - * is_8khz = ast_format_isset(format, AST_FORMAT_SILK_CAP_RATE, 8000); + * \retval non-NULL if joint capability exists + * \retval NULL if no joint capability exists * - * \return 0, The format key value pairs are within the capabilities defined in this structure. - * \return -1, The format key value pairs are _NOT_ within the capabilities of this structure. + * \note The returned format must be treated as immutable. */ -int ast_format_isset(const struct ast_format *format, ... ); +struct ast_format *ast_format_joint(const struct ast_format *format1, const struct ast_format *format2); /*! - * \brief Get a value from a format containing attributes. - * \note The key represents the format attribute to be retrieved, and the void pointer - * is to the structure that value will be stored in. It must be known what structure a - * key represents. + * \brief Set an attribute on a format to a specific value * - * \retval 0, success - * \retval -1, failure - */ -int ast_format_get_value(const struct ast_format *format, int key, void *value); - -/*! - * \brief Compare ast_formats structures + * \param format The format to set the attribute on + * \param name Attribute name + * \param value Attribute value * - * \retval ast_format_cmp_res representing the result of comparing format1 and format2. + * \retval non-NULL success + * \retval NULL failure */ -enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2); +struct ast_format *ast_format_attribute_set(const struct ast_format *format, const char *name, + const char *value); /*! - * \brief Find joint format attributes of two ast_format - * structures containing the same uid and return the intersection in the - * result structure. + * \brief This function is used to have a media format aware module parse and interpret + * SDP attribute information. Once interpreted this information is stored on the format + * itself using Asterisk format attributes. * - * retval 0, joint attribute capabilities exist. - * retval -1, no joint attribute capabilities exist. + * \param format to set + * \param attributes string containing the fmtp line from the SDP + * + * \retval non-NULL success, attribute values were valid + * \retval NULL failure, values were not acceptable */ -int ast_format_joint(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result); +struct ast_format *ast_format_parse_sdp_fmtp(const struct ast_format *format, const char *attributes); /*! - * \brief copy format src into format dst. + * \brief This function is used to produce an fmtp SDP line for an Asterisk format. The + * attributes present on the Asterisk format are translated into the SDP equivalent. + * + * \param format to generate an fmtp line for + * \param payload numerical payload for the fmtp line + * \param str structure that the fmtp line will be appended to */ -void ast_format_copy(struct ast_format *dst, const struct ast_format *src); +void ast_format_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str); /*! - * \brief Set the rtp mark value on the format to indicate to the interface - * writing this format's payload that a new RTP marker is necessary. + * \brief Register a format interface for use with the provided codec + * + * \param codec The name of codec the interface is applicable to + * \param interface A pointer to the interface implementation + * \param mod The module this format interface is provided by + * + * \retval 0 success + * \retval -1 failure */ -void ast_format_set_video_mark(struct ast_format *format); +int __ast_format_interface_register(const char *codec, const struct ast_format_interface *interface, struct ast_module *mod); /*! - * \brief Determine of the marker bit is set or not on this format. + * \brief Register a format interface for use with the provided codec * - * \retval 1, true - * \retval 0, false + * \param codec The name of codec the interface is applicable to + * \param interface A pointer to the interface implementation + * + * \retval 0 success + * \retval -1 failure */ -int ast_format_get_video_mark(const struct ast_format *format); +#define ast_format_interface_register(codec, interface) __ast_format_interface_register(codec, interface, ast_module_info->self) /*! - * \brief ast_format to old bitfield format represenatation + * \brief Get the attribute data on a format * - * \note This is only to be used for IAX2 compatibility + * \param format The media format * - * \retval iax2 representation of ast_format - * \retval 0, if no representation existis for iax2 + * \return Currently set attribute data */ -uint64_t ast_format_to_old_bitfield(const struct ast_format *format); +void *ast_format_get_attribute_data(const struct ast_format *format); /*! - * \brief ast_format_id to old bitfield format represenatation + * \brief Set the attribute data on a format * + * \param format The media format + * \param attribute_data The attribute data */ -uint64_t ast_format_id_to_old_bitfield(enum ast_format_id id); +void ast_format_set_attribute_data(struct ast_format *format, void *attribute_data); /*! - * \brief convert old bitfield format to ast_format represenatation - * \note This is only to be used for IAX2 compatibility + * \brief Get the name associated with a format * - * \retval on success, pointer to the dst format in the input parameters - * \retval on failure, NULL + * \param format The media format + * + * \return The name of the format */ -struct ast_format *ast_format_from_old_bitfield(struct ast_format *dst, uint64_t src); +const char *ast_format_get_name(const struct ast_format *format); /*! - * \brief convert old bitfield format to ast_format_id value + * \brief Get the codec identifier associated with a format + * + * \param format The media format + * + * \return codec identifier */ -enum ast_format_id ast_format_id_from_old_bitfield(uint64_t src); +unsigned int ast_format_get_codec_id(const struct ast_format *format); /*! - * \brief Retrieve the global format list in a read only array. - * \note ast_format_list_destroy must be called on every format - * list retrieved from this function. + * \brief Get the codec name associated with a format + * + * \param format The media format + * + * \return The codec name */ -const struct ast_format_list *ast_format_list_get(size_t *size); +const char *ast_format_get_codec_name(const struct ast_format *format); /*! - * \brief Destroy an ast_format_list gotten from ast_format_list_get() - */ -const struct ast_format_list *ast_format_list_destroy(const struct ast_format_list *list); - -/*! \brief Get the name of a format - * \param format id of format - * \return A static string containing the name of the format or "unknown" if unknown. - */ -const char* ast_getformatname(const struct ast_format *format); - -/*! \brief Returns a string containing all formats pertaining to an format id. - * \param buf a buffer for the output string - * \param size size of buf (bytes) - * \param id format id. - * \return The return value is buf. + * \brief Get whether or not the format can be smoothed + * + * \param format The media format + * + * \retval 0 the format cannot be smoothed + * \retval 1 the format can be smoothed */ -char* ast_getformatname_multiple_byid(char *buf, size_t size, enum ast_format_id id); +int ast_format_can_be_smoothed(const struct ast_format *format); /*! - * \brief Gets a format from a name. - * \param name string of format - * \param format structure to return the format in. - * \return This returns the format pointer given to it on success and NULL on failure + * \brief Get the media type of a format + * + * \param format The media format + * + * \return the media type */ -struct ast_format *ast_getformatbyname(const char *name, struct ast_format *format); +enum ast_media_type ast_format_get_type(const struct ast_format *format); /*! - * \brief Get a name from a format - * \param format to get name of - * \return This returns a static string identifying the format on success, 0 on error. + * \brief Get the default framing size (in milliseconds) for a format + * + * \param format The media format + * + * \return default framing size in milliseconds */ -const char *ast_codec2str(struct ast_format *format); +unsigned int ast_format_get_default_ms(const struct ast_format *format); /*! - * \brief Get the sample rate for a given format. + * \brief Get the minimum amount of media carried in this format + * + * \param format The media format + * + * \return minimum framing size in milliseconds */ -int ast_format_rate(const struct ast_format *format); +unsigned int ast_format_get_minimum_ms(const struct ast_format *format); /*! - * \brief register ast_format_attr_interface with core. + * \brief Get the maximum amount of media carried in this format * - * \retval 0 success - * \retval -1 failure + * \param format The media format + * + * \return maximum framing size in milliseconds */ -int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interface); +unsigned int ast_format_get_maximum_ms(const struct ast_format *format); /*! - * \brief unregister format_attr interface with core. + * \brief Get the minimum number of bytes expected in a frame for this format * - * \retval 0 success - * \retval -1 failure + * \param format The media format + * + * \return minimum expected bytes in a frame for this format */ -int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface); +unsigned int ast_format_get_minimum_bytes(const struct ast_format *format); /*! - * \brief Determine if a format is 16bit signed linear of any sample rate. + * \brief Get the sample rate of a media format + * + * \param format The media format + * + * \return sample rate */ -int ast_format_is_slinear(const struct ast_format *format); +unsigned int ast_format_get_sample_rate(const struct ast_format *format); /*! - * \brief Get the best slinear format id for a given sample rate + * \brief Get the length (in milliseconds) for the format with a given number of samples + * + * \param format The media format + * \param samples The number of samples + * + * \return length of media (in milliseconds) */ -enum ast_format_id ast_format_slin_by_rate(unsigned int rate); +unsigned int ast_format_determine_length(const struct ast_format *format, unsigned int samples); /*! * \since 12 @@ -494,4 +384,5 @@ struct stasis_message_type *ast_format_register_type(void); * \retval NULL on error */ struct stasis_message_type *ast_format_unregister_type(void); + #endif /* _AST_FORMAT_H */ diff --git a/include/asterisk/format_cache.h b/include/asterisk/format_cache.h new file mode 100644 index 000000000..e0744054e --- /dev/null +++ b/include/asterisk/format_cache.h @@ -0,0 +1,301 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Joshua Colp <jcolp@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Media Format Cache API + * + * \author Joshua Colp <jcolp@digium.com> + */ + +#ifndef _AST_FORMAT_CACHE_H_ +#define _AST_FORMAT_CACHE_H_ + +struct ast_format; + +/*! + * \brief Built-in cached signed linear 8kHz format. + */ +extern struct ast_format *ast_format_slin; + +/*! + * \brief Built-in cached signed linear 12kHz format. + */ +extern struct ast_format *ast_format_slin12; + +/*! + * \brief Built-in cached signed linear 16kHz format. + */ +extern struct ast_format *ast_format_slin16; + +/*! + * \brief Built-in cached signed linear 24kHz format. + */ +extern struct ast_format *ast_format_slin24; + +/*! + * \brief Built-in cached signed linear 32kHz format. + */ +extern struct ast_format *ast_format_slin32; + +/*! + * \brief Built-in cached signed linear 44kHz format. + */ +extern struct ast_format *ast_format_slin44; + +/*! + * \brief Built-in cached signed linear 48kHz format. + */ +extern struct ast_format *ast_format_slin48; + +/*! + * \brief Built-in cached signed linear 96kHz format. + */ +extern struct ast_format *ast_format_slin96; + +/*! + * \brief Built-in cached signed linear 192kHz format. + */ +extern struct ast_format *ast_format_slin192; + +/*! + * \brief Built-in cached ulaw format. + */ +extern struct ast_format *ast_format_ulaw; + +/*! + * \brief Built-in cached alaw format. + */ +extern struct ast_format *ast_format_alaw; + +/*! + * \brief Built-in cached testlaw format. + */ +extern struct ast_format *ast_format_testlaw; + +/*! + * \brief Built-in cached gsm format. + */ +extern struct ast_format *ast_format_gsm; + +/*! + * \brief Built-in cached adpcm format. + */ +extern struct ast_format *ast_format_adpcm; + +/*! + * \brief Built-in cached g722 format. + */ +extern struct ast_format *ast_format_g722; + +/*! + * \brief Built-in cached g726 format. + */ +extern struct ast_format *ast_format_g726; + +/*! + * \brief Built-in cached g726 aal2 format. + */ +extern struct ast_format *ast_format_g726_aal2; + +/*! + * \brief Built-in cached ilbc format. + */ +extern struct ast_format *ast_format_ilbc; + +/*! + * \brief Built-in cached ilbc format. + */ +extern struct ast_format *ast_format_lpc10; + +/*! + * \brief Built-in cached speex format. + */ +extern struct ast_format *ast_format_speex; + +/*! + * \brief Built-in cached speex at 16kHz format. + */ +extern struct ast_format *ast_format_speex16; + +/*! + * \brief Built-in cached speex at 32kHz format. + */ +extern struct ast_format *ast_format_speex32; + +/*! + * \brief Built-in cached g723.1 format. + */ +extern struct ast_format *ast_format_g723; + +/*! + * \brief Built-in cached g729 format. + */ +extern struct ast_format *ast_format_g729; + +/*! + * \brief Built-in cached g719 format. + */ +extern struct ast_format *ast_format_g719; + +/*! + * \brief Built-in cached h261 format. + */ +extern struct ast_format *ast_format_h261; + +/*! + * \brief Built-in cached h263 format. + */ +extern struct ast_format *ast_format_h263; + +/*! + * \brief Built-in cached h263 plus format. + */ +extern struct ast_format *ast_format_h263p; + +/*! + * \brief Built-in cached h264 format. + */ +extern struct ast_format *ast_format_h264; + +/*! + * \brief Built-in cached mp4 format. + */ +extern struct ast_format *ast_format_mp4; + +/*! + * \brief Built-in cached vp8 format. + */ +extern struct ast_format *ast_format_vp8; + +/*! + * \brief Built-in cached jpeg format. + */ +extern struct ast_format *ast_format_jpeg; + +/*! + * \brief Built-in cached png format. + */ +extern struct ast_format *ast_format_png; + +/*! + * \brief Built-in cached siren14 format. + */ +extern struct ast_format *ast_format_siren14; + +/*! + * \brief Built-in cached siren7 format. + */ +extern struct ast_format *ast_format_siren7; + +/*! + * \brief Built-in cached opus format. + */ +extern struct ast_format *ast_format_opus; + +/*! + * \brief Built-in cached t140 format. + */ +extern struct ast_format *ast_format_t140; + +/*! + * \brief Built-in cached t140 red format. + */ +extern struct ast_format *ast_format_t140_red; + +/*! + * \brief Built-in cached vp8 format. + */ +extern struct ast_format *ast_format_vp8; + +/*! + * \brief Built-in "null" format. + */ +extern struct ast_format *ast_format_none; + +/*! + * \brief Initialize format cache support within the core. + * + * \retval 0 success + * \retval -1 failure + */ +int ast_format_cache_init(void); + +/*! + * \brief Set a named format cache entry. + * + * \param format A pointer to the format to cache + * + * \retval 0 success + * \retval -1 failure + */ +int ast_format_cache_set(struct ast_format *format); + +/*! + * \brief Retrieve a named format from the cache. + * + * \param name Name of the cached format + * + * \retval non-NULL if found + * \retval NULL if not found + * + * \note The returned format has its reference count incremented. It must be + * dropped using ao2_ref or ao2_cleanup. + */ +struct ast_format *__ast_format_cache_get(const char *name); +struct ast_format *__ast_format_cache_get_debug(const char *name, const char *tag, const char *file, int line, const char *func); + +#ifdef REF_DEBUG +#define ast_format_cache_get(name) \ + __ast_format_cache_get_debug((name), "", __FILE__, __LINE__, __PRETTY_FUNCTION__) +#define ast_t_format_cache_get(name, tag) \ + __ast_format_cache_get_debug((name), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__) +#else +#define ast_format_cache_get(name) \ + __ast_format_cache_get((name)) +#define ast_t_format_cache_get(name, tag) \ + __ast_format_cache_get((name)) +#endif + + +/*! + * \brief Retrieve the best signed linear format given a sample rate. + * + * \param rate The sample rate + * + * \details + * This is a convenience function that returns one of the global + * ast_format_slinxxx formats. + * + * \return pointer to the signed linear format + * + * \note The returned format has NOT had its reference count incremented. + */ +struct ast_format *ast_format_cache_get_slin_by_rate(unsigned int rate); + +/*! + * \brief Determines if a format is one of the cached slin formats + * + * \param format The format to check + * + * \retval 0 if the format is not an SLIN format + * \retval 1 if the format is an SLIN format + */ +int ast_format_cache_is_slinear(struct ast_format *format); + +#endif /* _AST_FORMAT_CACHE_H */ diff --git a/include/asterisk/format_cap.h b/include/asterisk/format_cap.h index aa4eb3bfd..f7d33fccd 100644 --- a/include/asterisk/format_cap.h +++ b/include/asterisk/format_cap.h @@ -1,9 +1,9 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 2010, Digium, Inc. + * Copyright (C) 2014, Digium, Inc. * - * David Vossel <dvossel@digium.com> + * Joshua Colp <jcolp@digium.com> * * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact @@ -18,216 +18,289 @@ /*! * \file - * \brief Format Capability API + * \brief Format Capabilities API * - * \author David Vossel <dvossel@digium.com> + * \author Joshua Colp <jcolp@digium.com> */ -#ifndef _AST_FORMATCAP_H_ -#define _AST_FORMATCAP_H_ +#ifndef _AST_FORMAT_CAP_H_ +#define _AST_FORMAT_CAP_H_ -/*! Capabilities are represented by an opaque structure statically defined in format_capability.c */ +#include "asterisk/codec.h" + +/*! Capabilities are represented by an opaque structure statically defined in format_cap.c */ struct ast_format_cap; enum ast_format_cap_flags { /*! - * The ast_format_cap will be allocated with no lock. - * Useful if there is a separate lock used to protect the structure - */ - AST_FORMAT_CAP_FLAG_NOLOCK = (1 << 0), - /*! - * String representations of the formats are cached on the structure. - * Useful if string representation is frequently requested of the structure. + * Default format capabilities settings */ - AST_FORMAT_CAP_FLAG_CACHE_STRINGS = (1 << 1), + AST_FORMAT_CAP_FLAG_DEFAULT = 0, }; /*! * \brief Allocate a new ast_format_cap structure * * \param flags Modifiers of struct behavior. + * * \retval ast_format_cap object on success. * \retval NULL on failure. */ -struct ast_format_cap *ast_format_cap_alloc(enum ast_format_cap_flags flags); +struct ast_format_cap *__ast_format_cap_alloc(enum ast_format_cap_flags flags); +struct ast_format_cap *__ast_format_cap_alloc_debug(enum ast_format_cap_flags flags, const char *tag, const char *file, int line, const char *func); + +#ifdef REF_DEBUG +#define ast_format_cap_alloc(flags) \ + __ast_format_cap_alloc_debug((flags), "", __FILE__, __LINE__, __PRETTY_FUNCTION__) +#define ast_t_format_cap_alloc(flags, tag) \ + __ast_format_cap_alloc_debug((flags), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__) +#else +#define ast_format_cap_alloc(flags) \ + __ast_format_cap_alloc((flags)) +#define ast_t_format_cap_alloc(flags, tag) \ + __ast_format_cap_alloc((flags)) +#endif /*! - * \brief Destroy an ast_format_cap structure. + * \brief Set the global framing. + * + * \param cap The capabilities structure. + * \param framing The framing value (in milliseconds). * - * \return NULL + * \note This is used if a format does not provide a framing itself. Note that + * adding subsequent formats to the \c ast_format_cap structure may + * override this value, if the framing they require is less than the + * value set by this function. */ -void *ast_format_cap_destroy(struct ast_format_cap *cap); +void ast_format_cap_set_framing(struct ast_format_cap *cap, unsigned int framing); /*! - * \brief Add format capability to capabilities structure. + * \brief Get the global framing. * - * \note A copy of the input format is made and that copy is - * what is placed in the ast_format_cap structure. The actual - * input format ptr is not stored. + * \param cap The capabilities structure. + * + * \retval 0 if no formats are in the structure and no framing has been provided + * \retval The global framing value (in milliseconds) + * + * \note This will be the minimum framing allowed across all formats in the + * capabilities structure, or an overridden value */ -void ast_format_cap_add(struct ast_format_cap *cap, const struct ast_format *format); +unsigned int ast_format_cap_get_framing(const struct ast_format_cap *cap); /*! - * \brief Add all formats Asterisk knows about for a specific type to - * the capabilities structure. Formats with attributes are set, but their - * attributes are initilized to 0's. An attribute structure of 0's should - * indicate to the format attribute interface that the format has full - * capabilities. - * - * \note A copy of the input format is made and that copy is - * what is placed in the ast_format_cap structure. The actual - * input format ptr is not stored. + * \brief Add format capability to capabilities structure. + * + * \param cap The capabilities structure to add to. + * \param format The format to add. + * \param framing The framing for the format (in milliseconds). + * + * \retval 0 success + * \retval -1 failure + * + * \note A reference to the format is taken and used in the capabilities structure. + * + * \note The order in which add is called determines the format preference order. + * + * \note If framing is specified here it overrides any global framing that has been set. */ -void ast_format_cap_add_all_by_type(struct ast_format_cap *cap, enum ast_format_type type); +int __ast_format_cap_append(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing); +int __ast_format_cap_append_debug(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing, const char *tag, const char *file, int line, const char *func); + +#ifdef REF_DEBUG +#define ast_format_cap_append(cap, format, framing) \ + __ast_format_cap_append_debug((cap), (format), (framing), "", __FILE__, __LINE__, __PRETTY_FUNCTION__) +#define ast_t_format_cap_append(cap, format, framing, tag) \ + __ast_format_cap_append_debug((cap), (format), (framing), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__) +#else +#define ast_format_cap_append(cap, format, framing) \ + __ast_format_cap_append((cap), (format), (framing)) +#define ast_t_format_cap_append(cap, format, framing, tag) \ + __ast_format_cap_append((cap), (format), (framing)) +#endif /*! - * \brief Add all known formats to the capabilities structure using default format attribute. + * \brief Add all codecs Asterisk knows about for a specific type to + * the capabilities structure. + * + * \param cap The capabilities structure to add to. + * \param type The type of formats to add. + * + * \retval 0 success + * \retval -1 failure + * + * \note A generic format with no attributes is created using the codec. + * + * \note If AST_MEDIA_TYPE_UNKNOWN is passed as the type all known codecs will be added. */ -void ast_format_cap_add_all(struct ast_format_cap *cap); +int ast_format_cap_append_by_type(struct ast_format_cap *cap, enum ast_media_type type); /*! - * \brief Append the formats in src to dst + * \brief Append the formats of provided type in src to dst + * + * \param dst The destination capabilities structure + * \param src The source capabilities structure + * \param type The type of formats to append. + * + * \retval 0 success + * \retval -1 failure + * + * \note If AST_MEDIA_TYPE_UNKNOWN is passed as the type all known codecs will be added. */ -void ast_format_cap_append(struct ast_format_cap *dst, const struct ast_format_cap *src); +int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src, enum ast_media_type type); /*! - * \brief Copy all items in src to dst. - * \note any items in dst will be removed before copying + * \brief Replace the formats of provided type in dst with equivalent formats from src + * + * \param dst The destination capabilities structure + * \param src The source capabilities structure + * \param type The type of formats to replace. + * + * \note If AST_MEDIA_TYPE_UNKNOWN is passed as the type all known codecs will be replaced. + * \note Formats present in src but not dst will not be appended to dst. */ -void ast_format_cap_copy(struct ast_format_cap *dst, const struct ast_format_cap *src); +void ast_format_cap_replace_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src, enum ast_media_type type); /*! - * \brief create a deep copy of an ast_format_cap structure + * \brief Parse an "allow" or "deny" list and modify a format capabilities structure accordingly + * + * \param cap The capabilities structure to modify + * \param list The list containing formats to append or remove + * \param allowing If zero, start removing formats specified in the list. If non-zero, + * start appending formats specified in the list. * - * \retval cap on success - * \retval NULL on failure + * \retval 0 on success + * \retval -1 on failure */ -struct ast_format_cap *ast_format_cap_dup(const struct ast_format_cap *src); +int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const char *list, int allowing); /*! - * \brief determine if a capabilities structure is empty or not + * \brief Get the number of formats present within the capabilities structure * - * \retval 1, true is empty - * \retval 0, false, not empty + * \param cap The capabilities structure + * + * \return the number of formats */ -int ast_format_cap_is_empty(const struct ast_format_cap *cap); +size_t ast_format_cap_count(const struct ast_format_cap *cap); /*! - * \brief Remove format capability from capability structure. + * \brief Get the format at a specific index * - * \note format must match Exactly to format in ast_format_cap object in order - * to be removed. + * \param cap The capabilities structure + * \param position The position to get * - * \retval 0, remove was successful - * \retval -1, remove failed. Could not find format to remove + * \retval non-NULL success + * \retval NULL failure + * + * \note This is a zero based index. + * + * \note Formats are returned in order of preference. + * + * \note The reference count of the returned format is increased. It must be released using ao2_ref + * or ao2_cleanup. */ -int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format); +struct ast_format *ast_format_cap_get_format(const struct ast_format_cap *cap, int position); /*! - * \brief Remove all format capabilities from capability - * structure for a specific format id. + * \brief Get the most preferred format for a particular media type * - * \note This will remove _ALL_ formats matching the format id from the - * capabilities structure. + * \param cap The capabilities structure + * \param type The type of media to get * - * \retval 0, remove was successful - * \retval -1, remove failed. Could not find formats to remove + * \retval non-NULL the preferred format + * \retval NULL no media of \c type present + * + * \note The reference count of the returned format is increased. It must be released using ao2_ref + * or ao2_cleanup. */ -int ast_format_cap_remove_byid(struct ast_format_cap *cap, enum ast_format_id id); +struct ast_format *ast_format_cap_get_best_by_type(const struct ast_format_cap *cap, enum ast_media_type type); /*! - * \brief Remove all formats matching a specific format type. + * \brief Get the framing for a format + * + * \param cap The capabilities structure + * \param format The format to retrieve + * + * \return the framing (in milliseconds) */ -void ast_format_cap_remove_bytype(struct ast_format_cap *cap, enum ast_format_type type); +unsigned int ast_format_cap_get_format_framing(const struct ast_format_cap *cap, const struct ast_format *format); /*! - * \brief Remove all format capabilities from capability structure + * \brief Remove format capability from capability structure. + * + * \note format must be an exact pointer match to remove from capabilities structure. + * + * \retval 0, remove was successful + * \retval -1, remove failed. Could not find format to remove */ -void ast_format_cap_remove_all(struct ast_format_cap *cap); +int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format); /*! - * \brief Remove all previous formats and set a single new format. + * \brief Remove all formats matching a specific format type. + * + * \param cap The capabilities structure + * \param type The media type to remove formats of + * + * \note All formats can be removed by using the AST_MEDIA_TYPE_UNKNOWN type. */ -void ast_format_cap_set(struct ast_format_cap *cap, struct ast_format *format); +void ast_format_cap_remove_by_type(struct ast_format_cap *cap, enum ast_media_type type); /*! * \brief Find if input ast_format is within the capabilities of the ast_format_cap object * then return the compatible format from the capabilities structure in the result. * - * \retval 1 format is compatible with formats held in ast_format_cap object. - * \retval 0 format is not compatible with any formats in ast_format_cap object. + * \retval non-NULL if format is compatible + * \retval NULL if not compatible + * + * \note The reference count of the returned format is increased. It must be released using ao2_ref + * or ao2_cleanup. */ -int ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format, struct ast_format *result); +struct ast_format *ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format); /*! * \brief Find if ast_format is within the capabilities of the ast_format_cap object. * - * \retval 1 format is compatible with formats held in ast_format_cap object. - * \retval 0 format is not compatible with any formats in ast_format_cap object. +* \retval ast_format_cmp_res representing the result of the compatibility check between cap and format. */ -int ast_format_cap_iscompatible(const struct ast_format_cap *cap, const struct ast_format *format); +enum ast_format_cmp_res ast_format_cap_iscompatible_format(const struct ast_format_cap *cap, const struct ast_format *format); /*! - * \brief Finds the best quality audio format for a given format id and returns it in result. + * \brief Find the compatible formats between two capabilities structures * - * \retval 1 format found and set to result structure. - * \retval 0 no format found, result structure is cleared. - */ -int ast_format_cap_best_byid(const struct ast_format_cap *cap, enum ast_format_id, struct ast_format *result); - -/*! - * \brief is cap1 identical to cap2 + * \param cap1 The first capabilities structure + * \param cap2 The second capabilities structure + * \param[out] result The capabilities structure to place the results into * - * retval 1 true, identical - * retval 0 false, not identical - */ -int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2); - -/*! - * \brief Get joint capability structure. + * \retval 0 success + * \retval -1 failure * - * \note returns an ast_format_cap object containing the joint capabilities on success. This new - * capabilities structure is allocated with _NO_ locking enabled. If a joint structure requires - * locking, allocate it and use the ast_format_cap_joint_copy function to fill it with the joint - * capabilities. + * \note The preference order of cap1 is respected. * - * \retval !NULL success, joint capabilties structure with _NO_ locking enabled. - * \retval NULL failure + * \note If failure occurs the result format capabilities structure may contain a partial result. */ -struct ast_format_cap *ast_format_cap_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2); +int ast_format_cap_get_compatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, + struct ast_format_cap *result); /*! - * \brief Get joint capability structure, copy into result capabilities structure + * \brief Determine if any joint capabilities exist between two capabilities structures * - * \retval 1, joint capabilities exist - * \retval 0, joint capabilities do not exist - */ -int ast_format_cap_joint_copy(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result); - -/*! - * \brief Get joint capability structure, append into result capabilities structure + * \param cap1 The first capabilities structure + * \param cap2 The second capabilities structure * - * \retval 1, joint capabilities exist - * \retval 0, joint capabilities do not exist + * \retval 0 no joint capabilities exist + * \retval 1 joint capabilities exist */ -int ast_format_cap_joint_append(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result); +int ast_format_cap_iscompatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2); /*! - * \brief Find out if capability structures have any joint capabilities without - * returning those capabilities. + * \brief Determine if two capabilities structures are identical * - * \retval 1 true, has joint capabilities - * \retval 0 false, failure - */ -int ast_format_cap_has_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2); - -/*! - * \brief Get all capabilities for a specific media type + * \param cap1 The first capabilities structure + * \param cap2 The second capabilities structure * - * \retval !NULL success, new capabilities structure with _NO_ locking enabled on the new structure. - * \retval NULL failure + * \retval 0 capabilities are not identical + * \retval 1 capabilities are identical */ -struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap, enum ast_format_type ftype); +int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2); /*! * \brief Find out if the capabilities structure has any formats @@ -236,68 +309,16 @@ struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap, * \retval 1 true * \retval 0 false, no formats of specific type. */ -int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_type type); - -/*! \brief Start iterating formats */ -void ast_format_cap_iter_start(struct ast_format_cap *cap); - -/*! - * \brief Next format in interation - * - * \details - * Here is how to use the ast_format_cap iterator. - * - * 1. call ast_format_cap_iter_start - * 2. call ast_format_cap_iter_next in a loop until it returns -1 - * 3. call ast_format_cap_iter_end to terminate the iterator. - * - * example: - * - * ast_format_cap_iter_start(cap); - * while (!ast_format_cap_iter_next(cap, &format)) { - * } - * ast_format_cap_iter_end(Cap); - * - * \note Unless the container was alloced using no_lock, the container - * will be locked during the entire iteration until ast_format_cap_iter_end - * is called. XXX Remember this, and do not attempt to lock any containers - * within this iteration that will violate locking order. - * - * \retval 0 on success, new format is copied into input format struct - * \retval -1, no more formats are present. - */ -int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *format); - -/*! - * \brief Ends ast_format_cap iteration. - * \note this must be call after every ast_format_cap_iter_start - */ -void ast_format_cap_iter_end(struct ast_format_cap *cap); +int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_media_type type); /*! - * \brief ast_format_cap to old bitfield format represenatation + * \brief Get the names of codecs of a set of formats * - * \note This is only to be used for IAX2 compatibility + * \param cap The capabilities structure containing the formats + * \param buf A \c ast_str buffer to populate with the names of the formats * - * \retval old bitfield representation of ast_format_cap - * \retval 0, if no old bitfield capabilities are present in ast_format_cap - */ -uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap); - -/*! - * \brief convert old bitfield format to ast_format_cap represenatation - * \note This is only to be used for IAX2 compatibility - */ -void ast_format_cap_from_old_bitfield(struct ast_format_cap *dst, uint64_t src); - -/*! \brief Get the names of a set of formats - * \param buf a buffer for the output string - * \param size size of buf (bytes) - * \param cap format the format (combined IDs of codecs) - * Prints a list of readable codec names corresponding to "format". - * ex: for format=AST_FORMAT_GSM|AST_FORMAT_SPEEX|AST_FORMAT_ILBC it will return "0x602 (GSM|SPEEX|ILBC)" - * \return The return value is buf. + * \return The contents of the buffer in \c buf */ -char *ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap); +const char *ast_format_cap_get_names(struct ast_format_cap *cap, struct ast_str **buf); -#endif /* _AST_FORMATCAP_H */ +#endif /* _AST_FORMAT_CAP_H */ diff --git a/include/asterisk/format_compatibility.h b/include/asterisk/format_compatibility.h new file mode 100644 index 000000000..f14b7166c --- /dev/null +++ b/include/asterisk/format_compatibility.h @@ -0,0 +1,129 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Joshua Colp <jcolp@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Media Format Bitfield Compatibility API + * + * \author Joshua Colp <jcolp@digium.com> + */ + +#ifndef _AST_FORMAT_COMPATIBILITY_H_ +#define _AST_FORMAT_COMPATIBILITY_H_ + +struct ast_format; +struct ast_codec; + +/* + * Legacy bitfields for specific formats + */ + +/*! G.723.1 compression */ +#define AST_FORMAT_G723 (1ULL << 0) +/*! GSM compression */ +#define AST_FORMAT_GSM (1ULL << 1) +/*! Raw mu-law data (G.711) */ +#define AST_FORMAT_ULAW (1ULL << 2) +/*! Raw A-law data (G.711) */ +#define AST_FORMAT_ALAW (1ULL << 3) +/*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */ +#define AST_FORMAT_G726_AAL2 (1ULL << 4) +/*! ADPCM (IMA) */ +#define AST_FORMAT_ADPCM (1ULL << 5) +/*! Raw 16-bit Signed Linear (8000 Hz) PCM */ +#define AST_FORMAT_SLIN (1ULL << 6) +/*! LPC10, 180 samples/frame */ +#define AST_FORMAT_LPC10 (1ULL << 7) +/*! G.729A audio */ +#define AST_FORMAT_G729 (1ULL << 8) +/*! SpeeX Free Compression */ +#define AST_FORMAT_SPEEX (1ULL << 9) +/*! iLBC Free Compression */ +#define AST_FORMAT_ILBC (1ULL << 10) +/*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */ +#define AST_FORMAT_G726 (1ULL << 11) +/*! G.722 */ +#define AST_FORMAT_G722 (1ULL << 12) +/*! G.722.1 (also known as Siren7, 32kbps assumed) */ +#define AST_FORMAT_SIREN7 (1ULL << 13) +/*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */ +#define AST_FORMAT_SIREN14 (1ULL << 14) +/*! Raw 16-bit Signed Linear (16000 Hz) PCM */ +#define AST_FORMAT_SLIN16 (1ULL << 15) +/*! G.719 (64 kbps assumed) */ +#define AST_FORMAT_G719 (1ULL << 32) +/*! SpeeX Wideband (16kHz) Free Compression */ +#define AST_FORMAT_SPEEX16 (1ULL << 33) +/*! Opus audio (8kHz, 16kHz, 24kHz, 48Khz) */ +#define AST_FORMAT_OPUS (1ULL << 34) +/*! Raw testing-law data (G.711) */ +#define AST_FORMAT_TESTLAW (1ULL << 47) +/*! H.261 Video */ +#define AST_FORMAT_H261 (1ULL << 18) +/*! H.263 Video */ +#define AST_FORMAT_H263 (1ULL << 19) +/*! H.263+ Video */ +#define AST_FORMAT_H263P (1ULL << 20) +/*! H.264 Video */ +#define AST_FORMAT_H264 (1ULL << 21) +/*! MPEG4 Video */ +#define AST_FORMAT_MP4 (1ULL << 22) +/*! VP8 Video */ +#define AST_FORMAT_VP8 (1ULL << 23) +/*! JPEG Images */ +#define AST_FORMAT_JPEG (1ULL << 16) +/*! PNG Images */ +#define AST_FORMAT_PNG (1ULL << 17) +/*! T.140 RED Text format RFC 4103 */ +#define AST_FORMAT_T140_RED (1ULL << 26) +/*! T.140 Text format - ITU T.140, RFC 4103 */ +#define AST_FORMAT_T140 (1ULL << 27) + +/*! + * \brief Convert a format structure to its respective bitfield + * + * \param format The media format + * + * \retval non-zero success + * \retval zero format not supported + */ +uint64_t ast_format_compatibility_format2bitfield(const struct ast_format *format); + +/*! + * \brief Convert a codec structure to its respective bitfield + * + * \param codec The media codec + * + * \retval non-zero success + * \retval zero format not supported + */ +uint64_t ast_format_compatibility_codec2bitfield(const struct ast_codec *codec); + +/*! + * \brief Convert a bitfield to its respective format structure + * + * \param bitfield The bitfield for the media format + * + * \retval non-NULL success + * \retval NULL failure + * + * \note The reference count of the returned format is NOT incremented + */ +struct ast_format *ast_format_compatibility_bitfield2format(uint64_t bitfield); + +#endif /* _AST_FORMAT_COMPATIBILITY_H */ diff --git a/include/asterisk/format_pref.h b/include/asterisk/format_pref.h deleted file mode 100644 index f5c3c22a7..000000000 --- a/include/asterisk/format_pref.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2010, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! - * \file - * \brief Format Preference API - */ - -#ifndef _AST_FORMATPREF_H_ -#define _AST_FORMATPREF_H_ - -#include "asterisk/format.h" -#include "asterisk/format_cap.h" - -#define AST_CODEC_PREF_SIZE 64 -struct ast_codec_pref { - /*! This array represents the each format in the pref list */ - struct ast_format formats[AST_CODEC_PREF_SIZE]; - /*! This array represents the format id's index in the global format list. */ - char order[AST_CODEC_PREF_SIZE]; - /*! This array represents the format's framing size if present. */ - int framing[AST_CODEC_PREF_SIZE]; -}; - -/*! \page AudioCodecPref Audio Codec Preferences - - In order to negotiate audio codecs in the order they are configured - in \<channel\>.conf for a device, we set up codec preference lists - in addition to the codec capabilities setting. The capabilities - setting is a bitmask of audio and video codecs with no internal - order. This will reflect the offer given to the other side, where - the prefered codecs will be added to the top of the list in the - order indicated by the "allow" lines in the device configuration. - - Video codecs are not included in the preference lists since they - can't be transcoded and we just have to pick whatever is supported -*/ - -/*! - *\brief Initialize an audio codec preference to "no preference". - * \arg \ref AudioCodecPref -*/ -void ast_codec_pref_init(struct ast_codec_pref *pref); - -/*! - * \brief Codec located at a particular place in the preference index. - * \param pref preference structure to get the codec out of - * \param index to retrieve from - * \param result ast_format structure to store the index value in - * \return pointer to input ast_format on success, NULL on failure -*/ -struct ast_format *ast_codec_pref_index(struct ast_codec_pref *pref, int index, struct ast_format *result); - -/*! \brief Remove audio a codec from a preference list */ -void ast_codec_pref_remove(struct ast_codec_pref *pref, struct ast_format *format); - -/*! \brief Append all codecs to a preference list, without disturbing existing order */ -void ast_codec_pref_append_all(struct ast_codec_pref *pref); - -/*! \brief Append a audio codec to a preference list, removing it first if it was already there -*/ -int ast_codec_pref_append(struct ast_codec_pref *pref, struct ast_format *format); - -/*! \brief Prepend an audio codec to a preference list, removing it first if it was already there -*/ -void ast_codec_pref_prepend(struct ast_codec_pref *pref, struct ast_format *format, int only_if_existing); - -/*! \brief Select the best audio format according to preference list from supplied options. - * Best audio format is returned in the result format. - * - * \note If "find_best" is non-zero then if nothing is found, the "Best" format of - * the format list is selected and returned in the result structure, otherwise - * NULL is returned - * - * \retval ptr to result struture. - * \retval NULL, best codec was not found - */ -struct ast_format *ast_codec_choose(struct ast_codec_pref *pref, struct ast_format_cap *cap, int find_best, struct ast_format *result); - -/*! \brief Set packet size for codec -*/ -int ast_codec_pref_setsize(struct ast_codec_pref *pref, struct ast_format *format, int framems); - -/*! \brief Get packet size for codec -*/ -struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, struct ast_format *format); - -/*! \brief Dump audio codec preference list into a string */ -int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size); - -/*! \brief Shift an audio codec preference list up or down 65 bytes so that it becomes an ASCII string - * \note Due to a misunderstanding in how codec preferences are stored, this - * list starts at 'B', not 'A'. For backwards compatibility reasons, this - * cannot change. - * \param pref A codec preference list structure - * \param buf A string denoting codec preference, appropriate for use in line transmission - * \param size Size of \a buf - * \param right Boolean: if 0, convert from \a buf to \a pref; if 1, convert from \a pref to \a buf. - */ -void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right); - -#endif /* _AST_FORMATPREF_H */ diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 846832aff..a981c7e72 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -31,7 +31,6 @@ extern "C" { #include <sys/time.h> -#include "asterisk/format_pref.h" #include "asterisk/format.h" #include "asterisk/endian.h" #include "asterisk/linkedlists.h" @@ -136,9 +135,13 @@ enum { AST_FRFLAG_HAS_TIMING_INFO = (1 << 0), }; -union ast_frame_subclass { +struct ast_frame_subclass { + /*! A frame specific code */ int integer; - struct ast_format format; + /*! The asterisk media format */ + struct ast_format *format; + /*! For video formats, an indication that a frame ended */ + unsigned int frame_ending; }; /*! \brief Data structure associated with a single frame of data @@ -147,7 +150,7 @@ struct ast_frame { /*! Kind of frame */ enum ast_frame_type frametype; /*! Subclass, frame dependent */ - union ast_frame_subclass subclass; + struct ast_frame_subclass subclass; /*! Length of data */ int datalen; /*! Number of samples in this frame */ @@ -384,9 +387,6 @@ struct ast_control_pvt_cause_code { char code[1]; /*!< Tech-specific cause code information, beginning with the name of the tech */ }; -#define AST_SMOOTHER_FLAG_G729 (1 << 0) -#define AST_SMOOTHER_FLAG_BE (1 << 1) - /* Option identifiers and flags */ #define AST_OPTION_FLAG_REQUEST 0 #define AST_OPTION_FLAG_ACCEPT 1 @@ -565,77 +565,11 @@ void ast_swapcopy_samples(void *dst, const void *src, int samples); #define ast_frame_byteswap_be(fr) do { ; } while(0) #endif -/*! \brief Parse an "allow" or "deny" line in a channel or device configuration - and update the capabilities and pref if provided. - Video codecs are not added to codec preference lists, since we can not transcode - \return Returns number of errors encountered during parsing - */ -int ast_parse_allow_disallow(struct ast_codec_pref *pref, struct ast_format_cap *cap, const char *list, int allowing); - -/*! \name AST_Smoother -*/ -/*@{ */ -/*! \page ast_smooth The AST Frame Smoother -The ast_smoother interface was designed specifically -to take frames of variant sizes and produce frames of a single expected -size, precisely what you want to do. - -The basic interface is: - -- Initialize with ast_smoother_new() -- Queue input frames with ast_smoother_feed() -- Get output frames with ast_smoother_read() -- when you're done, free the structure with ast_smoother_free() -- Also see ast_smoother_test_flag(), ast_smoother_set_flags(), ast_smoother_get_flags(), ast_smoother_reset() -*/ -struct ast_smoother; - -struct ast_smoother *ast_smoother_new(int bytes); -void ast_smoother_set_flags(struct ast_smoother *smoother, int flags); -int ast_smoother_get_flags(struct ast_smoother *smoother); -int ast_smoother_test_flag(struct ast_smoother *s, int flag); -void ast_smoother_free(struct ast_smoother *s); -void ast_smoother_reset(struct ast_smoother *s, int bytes); - -/*! - * \brief Reconfigure an existing smoother to output a different number of bytes per frame - * \param s the smoother to reconfigure - * \param bytes the desired number of bytes per output frame - * \return nothing - * - */ -void ast_smoother_reconfigure(struct ast_smoother *s, int bytes); - -int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap); -struct ast_frame *ast_smoother_read(struct ast_smoother *s); -#define ast_smoother_feed(s,f) __ast_smoother_feed(s, f, 0) -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define ast_smoother_feed_be(s,f) __ast_smoother_feed(s, f, 1) -#define ast_smoother_feed_le(s,f) __ast_smoother_feed(s, f, 0) -#else -#define ast_smoother_feed_be(s,f) __ast_smoother_feed(s, f, 0) -#define ast_smoother_feed_le(s,f) __ast_smoother_feed(s, f, 1) -#endif -/*@} Doxygen marker */ - void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix); -/*! \brief Returns the number of samples contained in the frame */ -int ast_codec_get_samples(struct ast_frame *f); - -/*! \brief Returns the number of bytes for the number of samples of the given format */ -int ast_codec_get_len(struct ast_format *format, int samples); - /*! \brief Appends a frame to the end of a list of frames, truncating the maximum length of the list */ struct ast_frame *ast_frame_enqueue(struct ast_frame *head, struct ast_frame *f, int maxlen, int dupe); - -/*! \brief Gets duration in ms of interpolation frame for a format */ -static inline int ast_codec_interp_len(struct ast_format *format) -{ - return (format->id == AST_FORMAT_ILBC) ? 30 : 20; -} - /*! \brief Adjusts the volume of the audio samples contained in a frame. \param f The frame containing the samples (must be AST_FRAME_VOICE and AST_FORMAT_SLINEAR) diff --git a/include/asterisk/image.h b/include/asterisk/image.h index 302f09e85..9e358ad52 100644 --- a/include/asterisk/image.h +++ b/include/asterisk/image.h @@ -28,7 +28,7 @@ struct ast_imager { char *name; /*!< Name */ char *desc; /*!< Description */ char *exts; /*!< Extension(s) (separated by '|' ) */ - struct ast_format format; /*!< Image format */ + struct ast_format *format; /*!< Image format */ struct ast_frame *(*read_image)(int fd, int len); /*!< Read an image from a file descriptor */ int (*identify)(int fd); /*!< Identify if this is that type of file */ int (*write_image)(int fd, struct ast_frame *frame); /*!< Returns length written */ diff --git a/include/asterisk/mod_format.h b/include/asterisk/mod_format.h index ff3ab7bbf..7f17741fa 100644 --- a/include/asterisk/mod_format.h +++ b/include/asterisk/mod_format.h @@ -43,10 +43,10 @@ extern "C" { struct ast_format_def { char name[80]; /*!< Name of format */ char exts[80]; /*!< Extensions (separated by | if more than one) - this format can read. First is assumed for writing (e.g. .mp3) */ - struct ast_format format; /*!< Format of frames it uses/provides (one only) */ - /*! - * \brief Prepare an input stream for playback. + * this format can read. First is assumed for writing (e.g. .mp3) */ + struct ast_format *format; /*!< Format of frames it uses/provides (one only) */ + /*! + * \brief Prepare an input stream for playback. * \return 0 on success, -1 on error. * The FILE is already open (in s->f) so this function only needs to perform * any applicable validity checks on the file. If none is required, the @@ -110,7 +110,7 @@ struct ast_filestream { /*! Transparently translate from another format -- just once */ struct ast_trans_pvt *trans; struct ast_tranlator_pvt *tr; - struct ast_format lastwriteformat; + struct ast_format *lastwriteformat; int lasttimeout; struct ast_channel *owner; FILE *f; diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index d569710e0..45d9325ee 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -530,8 +530,6 @@ struct ast_sip_endpoint_media_configuration { struct ast_sip_direct_media_configuration direct_media; /*! T.38 (FoIP) options */ struct ast_sip_t38_configuration t38; - /*! Codec preferences */ - struct ast_codec_pref prefs; /*! Configured codecs */ struct ast_format_cap *codecs; /*! DSCP TOS bits for audio streams */ diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index 7340c6d71..51908f99b 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -126,8 +126,6 @@ struct ast_sip_session { struct ast_party_id id; /* Requested capabilities */ struct ast_format_cap *req_caps; - /* Codecs overriden by dialplan on an outgoing request */ - struct ast_codec_pref override_prefs; /* Optional DSP, used only for inband DTMF detection if configured */ struct ast_dsp *dsp; /* Whether the termination of the session should be deferred */ diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index 81e530e85..e5f38eecc 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -1,4 +1,4 @@ -/* + /* * Asterisk -- An open source telephony toolkit. * * Copyright (C) 1999 - 2009, Digium, Inc. @@ -71,10 +71,12 @@ extern "C" { #include "asterisk/astobj2.h" #include "asterisk/frame.h" +#include "asterisk/format_cap.h" #include "asterisk/netsock2.h" #include "asterisk/sched.h" #include "asterisk/res_srtp.h" #include "asterisk/stasis.h" +#include "asterisk/vector.h" /* Maximum number of payloads supported */ #if defined(LOW_MEMORY) @@ -245,7 +247,7 @@ struct ast_rtp_payload_type { int asterisk_format; /*! If asterisk_format is set, this is the internal * asterisk format represented by the payload */ - struct ast_format format; + struct ast_format *format; /*! Actual internal RTP specific value of the payload */ int rtp_code; /*! Actual payload number */ @@ -526,8 +528,6 @@ struct ast_rtp_engine { void (*prop_set)(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value); /*! Callback for setting a payload. If asterisk is to be used, asterisk_format will be set, otherwise value in code is used. */ void (*payload_set)(struct ast_rtp_instance *instance, int payload, int asterisk_format, struct ast_format *format, int code); - /*! Callback for setting packetization preferences */ - void (*packetization_set)(struct ast_rtp_instance *instance, struct ast_codec_pref *pref); /*! Callback for setting the remote address that RTP is to be sent to */ void (*remote_address_set)(struct ast_rtp_instance *instance, struct ast_sockaddr *sa); /*! Callback for changing DTMF mode */ @@ -575,11 +575,16 @@ struct ast_rtp_engine { /*! Structure that represents codec and packetization information */ struct ast_rtp_codecs { /*! Payloads present */ - struct ao2_container *payloads; - /*! Codec packetization preferences */ - struct ast_codec_pref pref; + AST_VECTOR(, struct ast_rtp_payload_type *) payloads; + /*! The framing for this media session */ + unsigned int framing; + /*! RW lock that protects elements in this structure */ + ast_rwlock_t codecs_lock; }; +#define AST_RTP_CODECS_NULL_INIT \ + { .payloads = { 0, }, .framing = 0, .codecs_lock = AST_RWLOCK_INIT_VALUE, } + /*! Structure that represents the glue that binds an RTP instance to a channel */ struct ast_rtp_glue { /*! Name of the channel driver that this glue is responsible for */ @@ -622,6 +627,18 @@ struct ast_rtp_glue { AST_RWLIST_ENTRY(ast_rtp_glue) entry; }; +/*! + * \brief Allocation routine for \ref ast_rtp_payload_type + * + * \retval NULL on error + * \retval An ao2 ref counted \c ast_rtp_payload_type on success. + * + * \note The \c ast_rtp_payload_type returned by this function is an + * ao2 ref counted object. + * + */ +struct ast_rtp_payload_type *ast_rtp_engine_alloc_payload_type(void); + #define ast_rtp_engine_register(engine) ast_rtp_engine_register2(engine, ast_module_info->self) /*! @@ -1117,25 +1134,6 @@ void ast_rtp_codecs_payloads_destroy(struct ast_rtp_codecs *codecs); void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance); /*! - * \brief Set payload information on an RTP instance to the default - * - * \param codecs The codecs structure to set defaults on - * \param instance Optionally the instance that the codecs structure belongs to - * - * Example usage: - * - * \code - * struct ast_rtp_codecs codecs; - * ast_rtp_codecs_payloads_default(&codecs, NULL); - * \endcode - * - * This sets the default payloads on the codecs structure. - * - * \since 1.8 - */ -void ast_rtp_codecs_payloads_default(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance); - -/*! * \brief Copy payload information from one RTP instance to another * * \param src The source codecs structure @@ -1249,20 +1247,36 @@ void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp * \param codecs Codecs structure to look in * \param payload Numerical payload to look up * - * \retval Payload information + * \retval Payload information. + * \retval NULL if payload does not exist. + * + * \note The payload returned by this function has its reference count increased. + * Callers are responsible for decrementing the reference count. * * Example usage: * * \code - * struct ast_rtp_payload_type payload_type; - * payload_type = ast_rtp_codecs_payload_lookup(&codecs, 0); + * struct ast_rtp_payload_type *payload_type; + * payload_type = ast_rtp_codecs_get_payload(&codecs, 0); * \endcode * * This looks up the information for payload '0' from the codecs structure. + */ +struct ast_rtp_payload_type *ast_rtp_codecs_get_payload(struct ast_rtp_codecs *codecs, int payload); + +/*! + * \brief Update the format associated with a payload in a codecs structure * - * \since 1.8 + * \param codecs Codecs structure to operate on + * \param payload Numerical payload to look up + * \param format The format to replace the existing one + * + * \retval 0 success + * \retval -1 failure + * + * \since 13 */ -struct ast_rtp_payload_type ast_rtp_codecs_payload_lookup(struct ast_rtp_codecs *codecs, int payload); +int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int payload, struct ast_format *format); /*! * \brief Retrieve the actual ast_format stored on the codecs structure for a specific payload @@ -1273,11 +1287,35 @@ struct ast_rtp_payload_type ast_rtp_codecs_payload_lookup(struct ast_rtp_codecs * \retval pointer to format structure on success * \retval NULL on failure * + * \note The format returned by this function has its reference count increased. + * Callers are responsible for decrementing the reference count. + * * \since 10.0 */ struct ast_format *ast_rtp_codecs_get_payload_format(struct ast_rtp_codecs *codecs, int payload); /*! + * \brief Set the framing used for a set of codecs + * + * \param codecs Codecs structure to set framing on + * \param framing The framing value to set on the codecs + * + * \since 13.0.0 + */ +void ast_rtp_codecs_set_framing(struct ast_rtp_codecs *codecs, unsigned int framing); + +/*! + * \brief Get the framing used for a set of codecs + * + * \param codecs Codecs structure to get the framing from + * + * \retval The framing to be used for the media stream associated with these codecs + * + * \since 13.0.0 + */ +unsigned int ast_rtp_codecs_get_framing(struct ast_rtp_codecs *codecs); + +/*! * \brief Get the sample rate associated with known RTP payload types * * \param asterisk_format True if the value in format is to be used. @@ -1393,8 +1431,8 @@ const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, struct ast_f * char buf[256] = ""; * struct ast_format tmp_fmt; * struct ast_format_cap *cap = ast_format_cap_alloc_nolock(); - * ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_ULAW, 0)); - * ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_GSM, 0)); + * ast_format_cap_append(cap, ast_format_set(&tmp_fmt, AST_FORMAT_ULAW, 0)); + * ast_format_cap_append(cap, ast_format_set(&tmp_fmt, AST_FORMAT_GSM, 0)); * char *mime = ast_rtp_lookup_mime_multiple2(&buf, sizeof(buf), cap, 0, 1, 0); * ast_format_cap_destroy(cap); * \endcode @@ -1406,25 +1444,6 @@ const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, struct ast_f char *ast_rtp_lookup_mime_multiple2(struct ast_str *buf, struct ast_format_cap *ast_format_capability, int rtp_capability, const int asterisk_format, enum ast_rtp_options options); /*! - * \brief Set codec packetization preferences - * - * \param codecs Codecs structure to muck with - * \param instance Optionally the instance that the codecs structure belongs to - * \param prefs Codec packetization preferences - * - * Example usage: - * - * \code - * ast_rtp_codecs_packetization_set(&codecs, NULL, &prefs); - * \endcode - * - * This sets the packetization preferences pointed to by prefs on the codecs structure pointed to by codecs. - * - * \since 1.8 - */ -void ast_rtp_codecs_packetization_set(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, struct ast_codec_pref *prefs); - -/*! * \brief Begin sending a DTMF digit * * \param instance The RTP instance to send the DTMF on @@ -2111,12 +2130,12 @@ struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance); /*! \brief Custom formats declared in codecs.conf at startup must be communicated to the rtp_engine * so their mime type can payload number can be initialized. */ -int ast_rtp_engine_load_format(const struct ast_format *format); +int ast_rtp_engine_load_format(struct ast_format *format); /*! \brief Formats requiring the use of a format attribute interface must have that * interface registered in order for the rtp engine to handle it correctly. If an * attribute interface is unloaded, this function must be called to notify the rtp_engine. */ -int ast_rtp_engine_unload_format(const struct ast_format *format); +int ast_rtp_engine_unload_format(struct ast_format *format); /*! * \brief Obtain a pointer to the ICE support present on an RTP instance diff --git a/include/asterisk/slin.h b/include/asterisk/slin.h index ab7d843ab..148ee09ab 100644 --- a/include/asterisk/slin.h +++ b/include/asterisk/slin.h @@ -70,7 +70,8 @@ static inline struct ast_frame *slin8_sample(void) .data.ptr = ex_slin8, }; - ast_format_set(&f.subclass.format, AST_FORMAT_SLINEAR, 0); + f.subclass.format = ast_format_slin; + return &f; } @@ -86,6 +87,7 @@ static inline struct ast_frame *slin16_sample(void) .data.ptr = ex_slin16, }; - ast_format_set(&f.subclass.format, AST_FORMAT_SLINEAR16, 0); + f.subclass.format = ast_format_slin16; + return &f; } diff --git a/include/asterisk/slinfactory.h b/include/asterisk/slinfactory.h index 324c0ae28..9a8ceae1e 100644 --- a/include/asterisk/slinfactory.h +++ b/include/asterisk/slinfactory.h @@ -39,8 +39,8 @@ struct ast_slinfactory { short *offset; /*!< Offset into the hold where audio begins */ size_t holdlen; /*!< Number of samples currently in the hold */ unsigned int size; /*!< Number of samples currently in the factory */ - struct ast_format format; /*!< Current format the translation path is converting from */ - struct ast_format output_format; /*!< The output format desired */ + struct ast_format *format; /*!< Current format the translation path is converting from */ + struct ast_format *output_format; /*!< The output format desired */ }; /*! @@ -60,7 +60,7 @@ void ast_slinfactory_init(struct ast_slinfactory *sf); * * \return 0 on success, non-zero on failure */ -int ast_slinfactory_init_with_format(struct ast_slinfactory *sf, const struct ast_format *slin_out); +int ast_slinfactory_init_with_format(struct ast_slinfactory *sf, struct ast_format *slin_out); /*! * \brief Destroy the contents of a slinfactory diff --git a/include/asterisk/smoother.h b/include/asterisk/smoother.h new file mode 100644 index 000000000..e63aa77bd --- /dev/null +++ b/include/asterisk/smoother.h @@ -0,0 +1,89 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2005, Digium, Inc. + * + * Mark Spencer <markster@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * \brief Asterisk internal frame definitions. + * \arg For an explanation of frames, see \ref Def_Frame + * \arg Frames are send of Asterisk channels, see \ref Def_Channel + */ + +#ifndef _ASTERISK_SMOOTHER_H +#define _ASTERISK_SMOOTHER_H + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include "asterisk/endian.h" + +#define AST_SMOOTHER_FLAG_G729 (1 << 0) +#define AST_SMOOTHER_FLAG_BE (1 << 1) + +/*! \name AST_Smoother +*/ +/*@{ */ +/*! \page ast_smooth The AST Frame Smoother +The ast_smoother interface was designed specifically +to take frames of variant sizes and produce frames of a single expected +size, precisely what you want to do. + +The basic interface is: + +- Initialize with ast_smoother_new() +- Queue input frames with ast_smoother_feed() +- Get output frames with ast_smoother_read() +- when you're done, free the structure with ast_smoother_free() +- Also see ast_smoother_test_flag(), ast_smoother_set_flags(), ast_smoother_get_flags(), ast_smoother_reset() +*/ +struct ast_smoother; + +struct ast_frame; + +struct ast_smoother *ast_smoother_new(int bytes); +void ast_smoother_set_flags(struct ast_smoother *smoother, int flags); +int ast_smoother_get_flags(struct ast_smoother *smoother); +int ast_smoother_test_flag(struct ast_smoother *s, int flag); +void ast_smoother_free(struct ast_smoother *s); +void ast_smoother_reset(struct ast_smoother *s, int bytes); + +/*! + * \brief Reconfigure an existing smoother to output a different number of bytes per frame + * \param s the smoother to reconfigure + * \param bytes the desired number of bytes per output frame + * \return nothing + * + */ +void ast_smoother_reconfigure(struct ast_smoother *s, int bytes); + +int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap); +struct ast_frame *ast_smoother_read(struct ast_smoother *s); +#define ast_smoother_feed(s,f) __ast_smoother_feed(s, f, 0) +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define ast_smoother_feed_be(s,f) __ast_smoother_feed(s, f, 1) +#define ast_smoother_feed_le(s,f) __ast_smoother_feed(s, f, 0) +#else +#define ast_smoother_feed_be(s,f) __ast_smoother_feed(s, f, 0) +#define ast_smoother_feed_le(s,f) __ast_smoother_feed(s, f, 1) +#endif +/*@} Doxygen marker */ + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* _ASTERISK_SMOOTHER_H */ diff --git a/include/asterisk/speech.h b/include/asterisk/speech.h index a914f4846..0da6f5cfc 100644 --- a/include/asterisk/speech.h +++ b/include/asterisk/speech.h @@ -58,7 +58,7 @@ struct ast_speech { /*! Current state of structure */ int state; /*! Expected write format */ - struct ast_format format; + struct ast_format *format; /*! Data for speech engine */ void *data; /*! Cached results */ diff --git a/include/asterisk/translate.h b/include/asterisk/translate.h index 602c3097c..e8e4c02d2 100644 --- a/include/asterisk/translate.h +++ b/include/asterisk/translate.h @@ -32,6 +32,8 @@ extern "C" { #include "asterisk/frame.h" #include "asterisk/plc.h" #include "asterisk/linkedlists.h" +#include "asterisk/format_cap.h" +#include "asterisk/format_cache.h" #endif struct ast_trans_pvt; /* declared below */ @@ -134,8 +136,11 @@ enum ast_trans_cost_table { */ struct ast_translator { char name[80]; /*!< Name of translator */ - struct ast_format src_format; /*!< Source format */ - struct ast_format dst_format; /*!< Destination format */ + struct ast_codec src_codec; /*!< Source codec */ + struct ast_codec dst_codec; /*!< Destination codec */ + struct ast_codec *core_src_codec; /*!< Core registered source codec */ + struct ast_codec *core_dst_codec; /*!< Core registered destination codec */ + const char *format; /*!< Optional name of a cached format this translator produces */ int table_cost; /*!< Cost value associated with this translator based * on translation cost table. */ @@ -204,12 +209,6 @@ struct ast_translator { struct ast_trans_pvt { struct ast_translator *t; struct ast_frame f; /*!< used in frameout */ - /*! If a translation path using a format with attributes requires the output - * to be a specific set of attributes, this variable will be set describing those - * attributes to the translator. Otherwise, the translator must choose a set - * of format attributes for the destination that preserves the quality of the - * audio in the best way possible. */ - struct ast_format explicit_dst; int samples; /*!< samples available in outbuf */ /*! \brief actual space used in outbuf */ int datalen; @@ -286,8 +285,8 @@ void ast_translator_deactivate(struct ast_translator *t); */ int ast_translator_best_choice(struct ast_format_cap *dst_cap, struct ast_format_cap *src_cap, - struct ast_format *dst_fmt_out, - struct ast_format *src_fmt_out); + struct ast_format **dst_fmt_out, + struct ast_format **src_fmt_out); /*! * \brief Builds a translator path diff --git a/include/asterisk/vector.h b/include/asterisk/vector.h index 0a2c6c965..0053d8a32 100644 --- a/include/asterisk/vector.h +++ b/include/asterisk/vector.h @@ -61,7 +61,7 @@ #define AST_VECTOR_INIT(vec, size) ({ \ size_t __size = (size); \ size_t alloc_size = __size * sizeof(*((vec)->elems)); \ - (vec)->elems = alloc_size ? ast_malloc(alloc_size) : NULL; \ + (vec)->elems = alloc_size ? ast_calloc(1, alloc_size) : NULL; \ (vec)->current = 0; \ if ((vec)->elems) { \ (vec)->max = __size; \ @@ -116,6 +116,48 @@ }) /*! + * \brief Insert an element at a specific position in a vector, growing the vector if needed. + * + * \param vec Vector to insert into. + * \param idx Position to insert at. + * \param elem Element to insert. + * + * \return 0 on success. + * \return Non-zero on failure. + * + * \warning This macro will overwrite anything already present at the position provided. + * + * \warning Use of this macro with the expectation that the element will remain at the provided + * index means you can not use the UNORDERED assortment of macros. These macros alter the ordering + * of the vector itself. + */ +#define AST_VECTOR_INSERT(vec, idx, elem) ({ \ + int res = 0; \ + do { \ + if (((idx) + 1) > (vec)->max) { \ + size_t new_max = ((idx) + 1) * 2; \ + typeof((vec)->elems) new_elems = ast_calloc(1, \ + new_max * sizeof(*new_elems)); \ + if (new_elems) { \ + memcpy(new_elems, (vec)->elems, \ + (vec)->current * sizeof(*new_elems)); \ + ast_free((vec)->elems); \ + (vec)->elems = new_elems; \ + (vec)->max = new_max; \ + } else { \ + res = -1; \ + break; \ + } \ + } \ + (vec)->elems[(idx)] = (elem); \ + if (((idx) + 1) > (vec)->current) { \ + (vec)->current = (idx) + 1; \ + } \ + } while(0); \ + res; \ +}) + +/*! * \brief Remove an element from a vector by index. * * Note that elements in the vector may be reordered, so that the remove can @@ -134,6 +176,25 @@ res; \ }) +/*! + * \brief Remove an element from a vector by index while maintaining order. + * + * \param vec Vector to remove from. + * \param idx Index of the element to remove. + * \return The element that was removed. + */ +#define AST_VECTOR_REMOVE_ORDERED(vec, idx) ({ \ + typeof((vec)->elems[0]) res; \ + size_t __idx = (idx); \ + size_t __move; \ + ast_assert(__idx < (vec)->current); \ + res = (vec)->elems[__idx]; \ + __move = ((vec)->current - (__idx) - 1) * sizeof(typeof((vec)->elems[0])); \ + memmove(&(vec)->elems[__idx], &(vec)->elems[__idx + 1], __move); \ + (vec)->current--; \ + res; \ +}) + /*! * \brief Remove an element from a vector that matches the given comparison @@ -162,6 +223,32 @@ }) /*! + * \brief Remove an element from a vector that matches the given comparison while maintaining order + * + * \param vec Vector to remove from. + * \param value Value to pass into comparator. + * \param cmp Comparator function/macros (called as \c cmp(elem, value)) + * \param cleanup How to cleanup a removed element macro/function. + * + * \return 0 if element was removed. + * \return Non-zero if element was not in the vector. + */ +#define AST_VECTOR_REMOVE_CMP_ORDERED(vec, value, cmp, cleanup) ({ \ + int res = -1; \ + size_t idx; \ + typeof(value) __value = (value); \ + for (idx = 0; idx < (vec)->current; ++idx) { \ + if (cmp((vec)->elems[idx], __value)) { \ + cleanup((vec)->elems[idx]); \ + AST_VECTOR_REMOVE_ORDERED((vec), idx); \ + res = 0; \ + break; \ + } \ + } \ + res; \ +}) + +/*! * \brief Default comparator for AST_VECTOR_REMOVE_ELEM_UNORDERED() * * \param elem Element to compare against @@ -197,6 +284,21 @@ }) /*! + * \brief Remove an element from a vector while maintaining order. + * + * \param vec Vector to remove from. + * \param elem Element to remove + * \param cleanup How to cleanup a removed element macro/function. + * + * \return 0 if element was removed. + * \return Non-zero if element was not in the vector. + */ +#define AST_VECTOR_REMOVE_ELEM_ORDERED(vec, elem, cleanup) ({ \ + AST_VECTOR_REMOVE_CMP_ORDERED((vec), (elem), \ + AST_VECTOR_ELEM_DEFAULT_CMP, cleanup); \ +}) + +/*! * \brief Get the number of elements in a vector. * * \param vec Vector to query. diff --git a/main/abstract_jb.c b/main/abstract_jb.c index 7841b6a4e..85c188e88 100644 --- a/main/abstract_jb.c +++ b/main/abstract_jb.c @@ -360,7 +360,7 @@ static void jb_get_and_deliver(struct ast_channel *chan) } while (now >= jb->next) { - interpolation_len = ast_codec_interp_len(&jb->last_format); + interpolation_len = ast_format_get_default_ms(jb->last_format); res = jbimpl->get(jbobj, &f, now, interpolation_len); @@ -371,13 +371,13 @@ static void jb_get_and_deliver(struct ast_channel *chan) case AST_JB_IMPL_DROP: jb_framelog("\tJB_GET {now=%ld}: %s frame with ts=%ld and len=%ld\n", now, jb_get_actions[res], f->ts, f->len); - ast_format_copy(&jb->last_format, &f->subclass.format); + ao2_replace(jb->last_format, f->subclass.format); ast_frfree(f); break; case AST_JB_IMPL_INTERP: /* interpolate a frame */ f = &finterp; - ast_format_copy(&f->subclass.format, &jb->last_format); + f->subclass.format = jb->last_format; f->samples = interpolation_len * 8; f->src = "JB interpolation"; f->delivery = ast_tvadd(jb->timebase, ast_samp2tv(jb->next, 1000)); @@ -437,7 +437,7 @@ static int create_jb(struct ast_channel *chan, struct ast_frame *frr) jb->next = jbimpl->next(jbobj); /* Init last format for a first time. */ - ast_format_copy(&jb->last_format, &frr->subclass.format); + jb->last_format = ao2_bump(frr->subclass.format); /* Create a frame log file */ if (ast_test_flag(jbconf, AST_JB_LOG)) { @@ -502,6 +502,8 @@ void ast_jb_destroy(struct ast_channel *chan) jb->logfile = NULL; } + ao2_cleanup(jb->last_format); + if (ast_test_flag(jb, JB_CREATED)) { /* Remove and free all frames still queued in jb */ while (jbimpl->remove(jbobj, &f) == AST_JB_IMPL_OK) { @@ -820,7 +822,7 @@ struct jb_framedata { const struct ast_jb_impl *jb_impl; struct ast_jb_conf jb_conf; struct timeval start_tv; - struct ast_format last_format; + struct ast_format *last_format; struct ast_timer *timer; int timer_interval; /* ms between deliveries */ int timer_fd; @@ -842,6 +844,7 @@ static void jb_framedata_destroy(struct jb_framedata *framedata) framedata->jb_impl->destroy(framedata->jb_obj); framedata->jb_obj = NULL; } + ao2_cleanup(framedata->last_format); ast_free(framedata); } @@ -909,7 +912,7 @@ static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_fram } jbframe = ast_frisolate(frame); - ast_format_copy(&framedata->last_format, &frame->subclass.format); + ao2_replace(framedata->last_format, frame->subclass.format); if (frame->len && (frame->len != framedata->timer_interval)) { framedata->timer_interval = frame->len; @@ -959,12 +962,12 @@ static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_fram frame = &ast_null_frame; break; case AST_JB_IMPL_INTERP: - if (framedata->last_format.id) { + if (framedata->last_format) { struct ast_frame tmp = { 0, }; tmp.frametype = AST_FRAME_VOICE; - ast_format_copy(&tmp.subclass.format, &framedata->last_format); + tmp.subclass.format = framedata->last_format; /* example: 8000hz / (1000 / 20ms) = 160 samples */ - tmp.samples = ast_format_rate(&framedata->last_format) / (1000 / framedata->timer_interval); + tmp.samples = ast_format_get_sample_rate(framedata->last_format) / (1000 / framedata->timer_interval); tmp.delivery = ast_tvadd(framedata->start_tv, ast_samp2tv(next, 1000)); tmp.offset = AST_FRIENDLY_OFFSET; tmp.src = "func_jitterbuffer interpolation"; diff --git a/main/app.c b/main/app.c index 822fe6c45..fa7c3ece1 100644 --- a/main/app.c +++ b/main/app.c @@ -70,6 +70,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/stasis.h" #include "asterisk/stasis_channels.h" #include "asterisk/json.h" +#include "asterisk/format_cache.h" #define MWI_TOPIC_BUCKETS 57 @@ -880,16 +881,18 @@ struct linear_state { int fd; int autoclose; int allowoverride; - struct ast_format origwfmt; + struct ast_format *origwfmt; }; static void linear_release(struct ast_channel *chan, void *params) { struct linear_state *ls = params; - if (ls->origwfmt.id && ast_set_write_format(chan, &ls->origwfmt)) { - ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%u'\n", ast_channel_name(chan), ls->origwfmt.id); + if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt)) { + ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%s'\n", + ast_channel_name(chan), ast_format_get_name(ls->origwfmt)); } + ao2_cleanup(ls->origwfmt); if (ls->autoclose) { close(ls->fd); @@ -909,7 +912,7 @@ static int linear_generator(struct ast_channel *chan, void *data, int len, int s }; int res; - ast_format_set(&f.subclass.format, AST_FORMAT_SLINEAR, 0); + f.subclass.format = ast_format_slin; len = samples * 2; if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { @@ -943,10 +946,11 @@ static void *linear_alloc(struct ast_channel *chan, void *params) ast_clear_flag(ast_channel_flags(chan), AST_FLAG_WRITE_INT); } - ast_format_copy(&ls->origwfmt, ast_channel_writeformat(chan)); + ls->origwfmt = ao2_bump(ast_channel_writeformat(chan)); - if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) { + if (ast_set_write_format(chan, ast_format_slin)) { ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", ast_channel_name(chan)); + ao2_cleanup(ls->origwfmt); ast_free(ls); ls = params = NULL; } @@ -1358,7 +1362,7 @@ static struct ast_frame *make_silence(const struct ast_frame *orig) return NULL; } - if (orig->subclass.format.id != AST_FORMAT_SLINEAR) { + if (ast_format_cmp(orig->subclass.format, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) { ast_log(LOG_WARNING, "Attempting to silence non-slin frame\n"); return NULL; } @@ -1385,7 +1389,7 @@ static struct ast_frame *make_silence(const struct ast_frame *orig) silence->samples = samples; silence->datalen = datalen; - ast_format_set(&silence->subclass.format, AST_FORMAT_SLINEAR, 0); + silence->subclass.format = ast_format_slin; return silence; } @@ -1400,13 +1404,13 @@ static struct ast_frame *make_silence(const struct ast_frame *orig) * \return 0 on success. * \return -1 on error. */ -static int set_read_to_slin(struct ast_channel *chan, struct ast_format *orig_format) +static int set_read_to_slin(struct ast_channel *chan, struct ast_format **orig_format) { if (!chan || !orig_format) { return -1; } - ast_format_copy(orig_format, ast_channel_readformat(chan)); - return ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR); + *orig_format = ao2_bump(ast_channel_readformat(chan)); + return ast_set_read_format(chan, ast_format_slin); } static int global_silence_threshold = 128; @@ -1448,7 +1452,7 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, int totalsilence = 0; int dspsilence = 0; int olddspsilence = 0; - struct ast_format rfmt; + struct ast_format *rfmt = NULL; struct ast_silence_generator *silgen = NULL; char prependfile[PATH_MAX]; int ioflags; /* IO flags for writing output file */ @@ -1467,7 +1471,6 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, break; } - ast_format_clear(&rfmt); if (silencethreshold < 0) { silencethreshold = global_silence_threshold; } @@ -1542,6 +1545,7 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); ast_dsp_free(sildet); + ao2_cleanup(rfmt); return -1; } } @@ -1692,7 +1696,7 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, * set the mode, if we haven't already * for sildet */ - if (muted && !rfmt.id) { + if (muted && !rfmt) { ast_verb(3, "Setting read format to linear mode\n"); res = set_read_to_slin(chan, &rfmt); if (res < 0) { @@ -1812,9 +1816,10 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, ast_filedelete(prependfile, sfmt[x]); } } - if (rfmt.id && ast_set_read_format(chan, &rfmt)) { - ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(&rfmt), ast_channel_name(chan)); + if (rfmt && ast_set_read_format(chan, rfmt)) { + ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_format_get_name(rfmt), ast_channel_name(chan)); } + ao2_cleanup(rfmt); if ((outmsg == 2) && (!skip_confirmation_sound)) { ast_stream_and_wait(chan, "auth-thankyou", ""); } diff --git a/main/asterisk.c b/main/asterisk.c index 55e06c385..1c6994280 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -248,6 +248,8 @@ int daemon(int, int); /* defined in libresolv of all places */ #include "asterisk/stasis_system.h" #include "asterisk/security_events.h" #include "asterisk/endpoints.h" +#include "asterisk/codec.h" +#include "asterisk/format_cache.h" #include "../defaults.h" @@ -4316,6 +4318,26 @@ int main(int argc, char *argv[]) exit(1); } + if (ast_codec_init()) { + printf("%s", term_quit()); + exit(1); + } + + if (ast_format_init()) { + printf("%s", term_quit()); + exit(1); + } + + if (ast_format_cache_init()) { + printf("%s", term_quit()); + exit(1); + } + + if (ast_codec_builtin_init()) { + printf("%s", term_quit()); + exit(1); + } + #ifdef AST_XML_DOCS /* Load XML documentation. */ ast_xmldoc_load_documentation(); @@ -4370,8 +4392,6 @@ int main(int argc, char *argv[]) threadstorage_init(); - ast_format_attr_init(); - ast_format_list_init(); if (ast_rtp_engine_init()) { printf("%s", term_quit()); exit(1); diff --git a/main/audiohook.c b/main/audiohook.c index 549ad31eb..33dad38f9 100644 --- a/main/audiohook.c +++ b/main/audiohook.c @@ -41,13 +41,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/slinfactory.h" #include "asterisk/frame.h" #include "asterisk/translate.h" +#include "asterisk/format_cache.h" #define AST_AUDIOHOOK_SYNC_TOLERANCE 100 /*!< Tolerance in milliseconds for audiohooks synchronization */ #define AST_AUDIOHOOK_SMALL_QUEUE_TOLERANCE 100 /*!< When small queue is enabled, this is the maximum amount of audio that can remain queued at a time. */ struct ast_audiohook_translate { struct ast_trans_pvt *trans_pvt; - struct ast_format format; + struct ast_format *format; }; struct ast_audiohook_list { @@ -67,7 +68,7 @@ struct ast_audiohook_list { static int audiohook_set_internal_rate(struct ast_audiohook *audiohook, int rate, int reset) { - struct ast_format slin; + struct ast_format *slin; if (audiohook->hook_internal_samp_rate == rate) { return 0; @@ -75,7 +76,8 @@ static int audiohook_set_internal_rate(struct ast_audiohook *audiohook, int rate audiohook->hook_internal_samp_rate = rate; - ast_format_set(&slin, ast_format_slin_by_rate(rate), 0); + slin = ast_format_cache_get_slin_by_rate(rate); + /* Setup the factories that are needed for this audiohook type */ switch (audiohook->type) { case AST_AUDIOHOOK_TYPE_SPY: @@ -84,12 +86,13 @@ static int audiohook_set_internal_rate(struct ast_audiohook *audiohook, int rate ast_slinfactory_destroy(&audiohook->read_factory); ast_slinfactory_destroy(&audiohook->write_factory); } - ast_slinfactory_init_with_format(&audiohook->read_factory, &slin); - ast_slinfactory_init_with_format(&audiohook->write_factory, &slin); + ast_slinfactory_init_with_format(&audiohook->read_factory, slin); + ast_slinfactory_init_with_format(&audiohook->write_factory, slin); break; default: break; } + return 0; } @@ -143,6 +146,8 @@ int ast_audiohook_destroy(struct ast_audiohook *audiohook) if (audiohook->trans_pvt) ast_translator_free_path(audiohook->trans_pvt); + ao2_cleanup(audiohook->format); + /* Lock and trigger be gone! */ ast_cond_destroy(&audiohook->trigger); ast_mutex_destroy(&audiohook->lock); @@ -220,11 +225,11 @@ static struct ast_frame *audiohook_read_frame_single(struct ast_audiohook *audio short buf[samples]; struct ast_frame frame = { .frametype = AST_FRAME_VOICE, + .subclass.format = ast_format_cache_get_slin_by_rate(audiohook->hook_internal_samp_rate), .data.ptr = buf, .datalen = sizeof(buf), .samples = samples, }; - ast_format_set(&frame.subclass.format, ast_format_slin_by_rate(audiohook->hook_internal_samp_rate), 0); /* Ensure the factory is able to give us the samples we want */ if (samples > ast_slinfactory_available(factory)) { @@ -254,7 +259,6 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho .datalen = sizeof(buf1), .samples = samples, }; - ast_format_set(&frame.subclass.format, ast_format_slin_by_rate(audiohook->hook_internal_samp_rate), 0); /* Make sure both factories have the required samples */ usable_read = (ast_slinfactory_available(&audiohook->read_factory) >= samples ? 1 : 0); @@ -346,6 +350,8 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho /* Make the final buffer part of the frame, so it gets duplicated fine */ frame.data.ptr = final_buf; + frame.subclass.format = ast_format_cache_get_slin_by_rate(audiohook->hook_internal_samp_rate); + /* Yahoo, a combined copy of the audio! */ return ast_frdup(&frame); } @@ -353,17 +359,17 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho static struct ast_frame *audiohook_read_frame_helper(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format, struct ast_frame **read_reference, struct ast_frame **write_reference) { struct ast_frame *read_frame = NULL, *final_frame = NULL; - struct ast_format tmp_fmt; + struct ast_format *slin; int samples_converted; /* the number of samples requested is based on the format they are requesting. Inorder * to process this correctly samples must be converted to our internal sample rate */ - if (audiohook->hook_internal_samp_rate == ast_format_rate(format)) { + if (audiohook->hook_internal_samp_rate == ast_format_get_sample_rate(format)) { samples_converted = samples; - } else if (audiohook->hook_internal_samp_rate > ast_format_rate(format)) { - samples_converted = samples * (audiohook->hook_internal_samp_rate / (float) ast_format_rate(format)); + } else if (audiohook->hook_internal_samp_rate > ast_format_get_sample_rate(format)) { + samples_converted = samples * (audiohook->hook_internal_samp_rate / (float) ast_format_get_sample_rate(format)); } else { - samples_converted = samples * (ast_format_rate(format) / (float) audiohook->hook_internal_samp_rate); + samples_converted = samples * (ast_format_get_sample_rate(format) / (float) audiohook->hook_internal_samp_rate); } if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ? @@ -372,21 +378,23 @@ static struct ast_frame *audiohook_read_frame_helper(struct ast_audiohook *audio return NULL; } + slin = ast_format_cache_get_slin_by_rate(audiohook->hook_internal_samp_rate); + /* If they don't want signed linear back out, we'll have to send it through the translation path */ - if (format->id != ast_format_slin_by_rate(audiohook->hook_internal_samp_rate)) { + if (ast_format_cmp(format, slin) != AST_FORMAT_CMP_EQUAL) { /* Rebuild translation path if different format then previously */ - if (ast_format_cmp(format, &audiohook->format) == AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_cmp(format, audiohook->format) == AST_FORMAT_CMP_NOT_EQUAL) { if (audiohook->trans_pvt) { ast_translator_free_path(audiohook->trans_pvt); audiohook->trans_pvt = NULL; } /* Setup new translation path for this format... if we fail we can't very well return signed linear so free the frame and return nothing */ - if (!(audiohook->trans_pvt = ast_translator_build_path(format, ast_format_set(&tmp_fmt, ast_format_slin_by_rate(audiohook->hook_internal_samp_rate), 0)))) { + if (!(audiohook->trans_pvt = ast_translator_build_path(format, slin))) { ast_frfree(read_frame); return NULL; } - ast_format_copy(&audiohook->format, format); + ao2_replace(audiohook->format, format); } /* Convert to requested format, and allow the read in frame to be freed */ final_frame = ast_translate(audiohook->trans_pvt, read_frame, 1); @@ -752,8 +760,7 @@ static struct ast_frame *audiohook_list_translate_to_slin(struct ast_audiohook_l struct ast_audiohook_translate *in_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->in_translate[0] : &audiohook_list->in_translate[1]); struct ast_frame *new_frame = frame; - struct ast_format tmp_fmt; - enum ast_format_id slin_id; + struct ast_format *slin; /* If we are capable of maintaining doing samplerates other that 8khz, update * the internal audiohook_list's rate and higher samplerate audio arrives. By @@ -761,24 +768,24 @@ static struct ast_frame *audiohook_list_translate_to_slin(struct ast_audiohook_l * as the are written and read from. */ if (audiohook_list->native_slin_compatible) { audiohook_list->list_internal_samp_rate = - MAX(ast_format_rate(&frame->subclass.format), audiohook_list->list_internal_samp_rate); + MAX(ast_format_get_sample_rate(frame->subclass.format), audiohook_list->list_internal_samp_rate); } - slin_id = ast_format_slin_by_rate(audiohook_list->list_internal_samp_rate); - - if (frame->subclass.format.id == slin_id) { + slin = ast_format_cache_get_slin_by_rate(audiohook_list->list_internal_samp_rate); + if (ast_format_cmp(frame->subclass.format, slin) == AST_FORMAT_CMP_EQUAL) { return new_frame; } - if (ast_format_cmp(&frame->subclass.format, &in_translate->format) == AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_cmp(frame->subclass.format, in_translate->format) == AST_FORMAT_CMP_NOT_EQUAL) { if (in_translate->trans_pvt) { ast_translator_free_path(in_translate->trans_pvt); } - if (!(in_translate->trans_pvt = ast_translator_build_path(ast_format_set(&tmp_fmt, slin_id, 0), &frame->subclass.format))) { + if (!(in_translate->trans_pvt = ast_translator_build_path(slin, frame->subclass.format))) { return NULL; } - ast_format_copy(&in_translate->format, &frame->subclass.format); + ao2_replace(in_translate->format, frame->subclass.format); } + if (!(new_frame = ast_translate(in_translate->trans_pvt, frame, 0))) { return NULL; } @@ -791,16 +798,16 @@ static struct ast_frame *audiohook_list_translate_to_native(struct ast_audiohook { struct ast_audiohook_translate *out_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->out_translate[0] : &audiohook_list->out_translate[1]); struct ast_frame *outframe = NULL; - if (ast_format_cmp(&slin_frame->subclass.format, outformat) == AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_cmp(slin_frame->subclass.format, outformat) == AST_FORMAT_CMP_NOT_EQUAL) { /* rebuild translators if necessary */ - if (ast_format_cmp(&out_translate->format, outformat) == AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_cmp(out_translate->format, outformat) == AST_FORMAT_CMP_NOT_EQUAL) { if (out_translate->trans_pvt) { ast_translator_free_path(out_translate->trans_pvt); } - if (!(out_translate->trans_pvt = ast_translator_build_path(outformat, &slin_frame->subclass.format))) { + if (!(out_translate->trans_pvt = ast_translator_build_path(outformat, slin_frame->subclass.format))) { return NULL; } - ast_format_copy(&out_translate->format, outformat); + ao2_replace(out_translate->format, outformat); } /* translate back to the format the frame came in as. */ if (!(outframe = ast_translate(out_translate->trans_pvt, slin_frame, 0))) { @@ -924,7 +931,7 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st /* ---Part_3: Decide what to do with the end_frame (whether to transcode or not) */ if (middle_frame_manipulated) { - if (!(end_frame = audiohook_list_translate_to_native(audiohook_list, direction, middle_frame, &start_frame->subclass.format))) { + if (!(end_frame = audiohook_list_translate_to_native(audiohook_list, direction, middle_frame, start_frame->subclass.format))) { /* translation failed, so just pass back the input frame */ end_frame = start_frame; } diff --git a/main/bridge.c b/main/bridge.c index 41053eb8a..d5fc1699a 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -934,61 +934,65 @@ int ast_bridge_destroy(struct ast_bridge *bridge, int cause) static int bridge_make_compatible(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) { - struct ast_format read_format; - struct ast_format write_format; - struct ast_format best_format; - char codec_buf[512]; + struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_format *read_format; + struct ast_format *write_format; + struct ast_format *best_format; - ast_format_copy(&read_format, ast_channel_readformat(bridge_channel->chan)); - ast_format_copy(&write_format, ast_channel_writeformat(bridge_channel->chan)); + read_format = ast_channel_readformat(bridge_channel->chan); + write_format = ast_channel_writeformat(bridge_channel->chan); /* Are the formats currently in use something this bridge can handle? */ - if (!ast_format_cap_iscompatible(bridge->technology->format_capabilities, ast_channel_readformat(bridge_channel->chan))) { - ast_best_codec(bridge->technology->format_capabilities, &best_format); + if (ast_format_cap_iscompatible_format(bridge->technology->format_capabilities, read_format) == AST_FORMAT_CMP_NOT_EQUAL) { + best_format = ast_format_cap_get_format(bridge->technology->format_capabilities, 0); /* Read format is a no go... */ ast_debug(1, "Bridge technology %s wants to read any of formats %s but channel has %s\n", bridge->technology->name, - ast_getformatname_multiple(codec_buf, sizeof(codec_buf), bridge->technology->format_capabilities), - ast_getformatname(&read_format)); + ast_format_cap_get_names(bridge->technology->format_capabilities, &codec_buf), + ast_format_get_name(read_format)); /* Switch read format to the best one chosen */ - if (ast_set_read_format(bridge_channel->chan, &best_format)) { + if (ast_set_read_format(bridge_channel->chan, best_format)) { ast_log(LOG_WARNING, "Failed to set channel %s to read format %s\n", - ast_channel_name(bridge_channel->chan), ast_getformatname(&best_format)); + ast_channel_name(bridge_channel->chan), ast_format_get_name(best_format)); + ao2_cleanup(best_format); return -1; } ast_debug(1, "Bridge %s put channel %s into read format %s\n", bridge->uniqueid, ast_channel_name(bridge_channel->chan), - ast_getformatname(&best_format)); + ast_format_get_name(best_format)); + ao2_cleanup(best_format); } else { ast_debug(1, "Bridge %s is happy that channel %s already has read format %s\n", bridge->uniqueid, ast_channel_name(bridge_channel->chan), - ast_getformatname(&read_format)); + ast_format_get_name(read_format)); } - if (!ast_format_cap_iscompatible(bridge->technology->format_capabilities, &write_format)) { - ast_best_codec(bridge->technology->format_capabilities, &best_format); + if (ast_format_cap_iscompatible_format(bridge->technology->format_capabilities, write_format) == AST_FORMAT_CMP_NOT_EQUAL) { + best_format = ast_format_cap_get_format(bridge->technology->format_capabilities, 0); /* Write format is a no go... */ ast_debug(1, "Bridge technology %s wants to write any of formats %s but channel has %s\n", bridge->technology->name, - ast_getformatname_multiple(codec_buf, sizeof(codec_buf), bridge->technology->format_capabilities), - ast_getformatname(&write_format)); + ast_format_cap_get_names(bridge->technology->format_capabilities, &codec_buf), + ast_format_get_name(write_format)); /* Switch write format to the best one chosen */ - if (ast_set_write_format(bridge_channel->chan, &best_format)) { + if (ast_set_write_format(bridge_channel->chan, best_format)) { ast_log(LOG_WARNING, "Failed to set channel %s to write format %s\n", - ast_channel_name(bridge_channel->chan), ast_getformatname(&best_format)); + ast_channel_name(bridge_channel->chan), ast_format_get_name(best_format)); + ao2_cleanup(best_format); return -1; } ast_debug(1, "Bridge %s put channel %s into write format %s\n", bridge->uniqueid, ast_channel_name(bridge_channel->chan), - ast_getformatname(&best_format)); + ast_format_get_name(best_format)); + ao2_cleanup(best_format); } else { ast_debug(1, "Bridge %s is happy that channel %s already has write format %s\n", bridge->uniqueid, ast_channel_name(bridge_channel->chan), - ast_getformatname(&write_format)); + ast_format_get_name(write_format)); } return 0; @@ -3525,7 +3529,7 @@ void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct a struct ast_bridge_video_talker_src_data *data; /* If the channel doesn't support video, we don't care about it */ - if (!ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_FORMAT_TYPE_VIDEO)) { + if (!ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_VIDEO)) { return; } diff --git a/main/bridge_basic.c b/main/bridge_basic.c index 60ce37a98..cb8c2f992 100644 --- a/main/bridge_basic.c +++ b/main/bridge_basic.c @@ -46,6 +46,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/dial.h" #include "asterisk/stasis_bridges.h" #include "asterisk/features.h" +#include "asterisk/format_cache.h" #define NORMAL_FLAGS (AST_BRIDGE_FLAG_DISSOLVE_HANGUP | AST_BRIDGE_FLAG_DISSOLVE_EMPTY \ | AST_BRIDGE_FLAG_SMART) @@ -2267,14 +2268,13 @@ static void recall_callback(struct ast_dial *dial) static int recalling_enter(struct attended_transfer_properties *props) { - RAII_VAR(struct ast_format_cap *, cap, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK), ast_format_cap_destroy); - struct ast_format fmt; + RAII_VAR(struct ast_format_cap *, cap, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup); if (!cap) { return -1; } - ast_format_cap_add(cap, ast_format_set(&fmt, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(cap, ast_format_slin, 0); /* When we dial the transfer target, since we are communicating * with a local channel, we can place the local channel in a bridge @@ -2395,8 +2395,7 @@ static int attach_framehook(struct attended_transfer_properties *props, struct a static int retransfer_enter(struct attended_transfer_properties *props) { - RAII_VAR(struct ast_format_cap *, cap, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK), ast_format_cap_destroy); - struct ast_format fmt; + RAII_VAR(struct ast_format_cap *, cap, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup); char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2]; int cause; @@ -2406,7 +2405,7 @@ static int retransfer_enter(struct attended_transfer_properties *props) snprintf(destination, sizeof(destination), "%s@%s", props->exten, props->context); - ast_format_cap_add(cap, ast_format_set(&fmt, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(cap, ast_format_slin, 0); /* Get a channel that is the destination we wish to call */ props->recall_target = ast_request("Local", cap, NULL, NULL, destination, &cause); diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 93cbed22d..ea9b3f868 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -320,25 +320,28 @@ struct ast_bridge_channel *ast_bridge_channel_peer(struct ast_bridge_channel *br void ast_bridge_channel_restore_formats(struct ast_bridge_channel *bridge_channel) { + ast_assert(bridge_channel->read_format != NULL); + ast_assert(bridge_channel->write_format != NULL); + /* Restore original formats of the channel as they came in */ - if (ast_format_cmp(ast_channel_readformat(bridge_channel->chan), &bridge_channel->read_format) == AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_cmp(ast_channel_readformat(bridge_channel->chan), bridge_channel->read_format) == AST_FORMAT_CMP_NOT_EQUAL) { ast_debug(1, "Bridge is returning %p(%s) to read format %s\n", bridge_channel, ast_channel_name(bridge_channel->chan), - ast_getformatname(&bridge_channel->read_format)); - if (ast_set_read_format(bridge_channel->chan, &bridge_channel->read_format)) { + ast_format_get_name(bridge_channel->read_format)); + if (ast_set_read_format(bridge_channel->chan, bridge_channel->read_format)) { ast_debug(1, "Bridge failed to return %p(%s) to read format %s\n", bridge_channel, ast_channel_name(bridge_channel->chan), - ast_getformatname(&bridge_channel->read_format)); + ast_format_get_name(bridge_channel->read_format)); } } - if (ast_format_cmp(ast_channel_writeformat(bridge_channel->chan), &bridge_channel->write_format) == AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_cmp(ast_channel_writeformat(bridge_channel->chan), bridge_channel->write_format) == AST_FORMAT_CMP_NOT_EQUAL) { ast_debug(1, "Bridge is returning %p(%s) to write format %s\n", bridge_channel, ast_channel_name(bridge_channel->chan), - ast_getformatname(&bridge_channel->write_format)); - if (ast_set_write_format(bridge_channel->chan, &bridge_channel->write_format)) { + ast_format_get_name(bridge_channel->write_format)); + if (ast_set_write_format(bridge_channel->chan, bridge_channel->write_format)) { ast_debug(1, "Bridge failed to return %p(%s) to write format %s\n", bridge_channel, ast_channel_name(bridge_channel->chan), - ast_getformatname(&bridge_channel->write_format)); + ast_format_get_name(bridge_channel->write_format)); } } } @@ -2342,8 +2345,8 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel) int res = 0; struct ast_bridge_features *channel_features; - ast_format_copy(&bridge_channel->read_format, ast_channel_readformat(bridge_channel->chan)); - ast_format_copy(&bridge_channel->write_format, ast_channel_writeformat(bridge_channel->chan)); + bridge_channel->read_format = ao2_bump(ast_channel_readformat(bridge_channel->chan)); + bridge_channel->write_format = ao2_bump(ast_channel_writeformat(bridge_channel->chan)); ast_debug(1, "Bridge %s: %p(%s) is joining\n", bridge_channel->bridge->uniqueid, @@ -2590,6 +2593,9 @@ static void bridge_channel_destroy(void *obj) pipe_close(bridge_channel->alert_pipe); ast_cond_destroy(&bridge_channel->cond); + + ao2_cleanup(bridge_channel->write_format); + ao2_cleanup(bridge_channel->read_format); } struct ast_bridge_channel *bridge_channel_internal_alloc(struct ast_bridge *bridge) diff --git a/main/callerid.c b/main/callerid.c index 5f53cb2ae..e3b2b139e 100644 --- a/main/callerid.c +++ b/main/callerid.c @@ -42,6 +42,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/callerid.h" #include "asterisk/fskmodem.h" #include "asterisk/utils.h" +#include "asterisk/format_cache.h" struct callerid_state { fsk_data fskd; diff --git a/main/ccss.c b/main/ccss.c index 09fa2d114..9fcabfefd 100644 --- a/main/ccss.c +++ b/main/ccss.c @@ -52,6 +52,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/manager.h" #include "asterisk/causes.h" #include "asterisk/stasis_system.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <application name="CallCompletionRequest" language="en_US"> @@ -2814,8 +2815,7 @@ static void *generic_recall(void *data) const char *callback_macro = ast_get_cc_callback_macro(agent->cc_params); const char *callback_sub = ast_get_cc_callback_sub(agent->cc_params); unsigned int recall_timer = ast_get_cc_recall_timer(agent->cc_params) * 1000; - struct ast_format tmp_fmt; - struct ast_format_cap *tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + struct ast_format_cap *tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!tmp_cap) { return NULL; @@ -2826,17 +2826,17 @@ static void *generic_recall(void *data) *target++ = '\0'; } - ast_format_cap_add(tmp_cap, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(tmp_cap, ast_format_slin, 0); if (!(chan = ast_request_and_dial(tech, tmp_cap, NULL, NULL, target, recall_timer, &reason, generic_pvt->cid_num, generic_pvt->cid_name))) { /* Hmm, no channel. Sucks for you, bud. */ ast_log_dynamic_level(cc_logger_level, "Core %u: Failed to call back %s for reason %d\n", agent->core_id, agent->device_name, reason); ast_cc_failed(agent->core_id, "Failed to call back device %s/%s", tech, target); - ast_format_cap_destroy(tmp_cap); + ao2_ref(tmp_cap, -1); return NULL; } - ast_format_cap_destroy(tmp_cap); + ao2_ref(tmp_cap, -1); /* We have a channel. It's time now to set up the datastore of recalled CC interfaces. * This will be a common task for all recall functions. If it were possible, I'd have diff --git a/main/channel.c b/main/channel.c index 15f2cbce0..b17dddeef 100644 --- a/main/channel.c +++ b/main/channel.c @@ -342,7 +342,7 @@ static char *complete_channeltypes(struct ast_cli_args *a) static char *handle_cli_core_show_channeltype(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct chanlist *cl = NULL; - char buf[512]; + struct ast_str *codec_buf = ast_str_alloca(64); switch (cmd) { case CLI_INIT: @@ -387,7 +387,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), + ast_format_cap_get_names(cl->tech->capabilities, &codec_buf), (cl->tech->send_digit_begin) ? "yes" : "no", (cl->tech->send_digit_end) ? "yes" : "no", (cl->tech->send_html) ? "yes" : "no", @@ -764,78 +764,6 @@ char *ast_transfercapability2str(int transfercapability) } } -/*! \brief Pick the best audio codec */ -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 */ - static const enum ast_format_id prefs[] = - { - /*! Okay, ulaw is used by all telephony equipment, so start with it */ - AST_FORMAT_ULAW, - /*! Unless of course, you're a silly European, so then prefer ALAW */ - AST_FORMAT_ALAW, - AST_FORMAT_G719, - AST_FORMAT_SIREN14, - AST_FORMAT_SIREN7, - AST_FORMAT_TESTLAW, - /*! G.722 is better then all below, but not as common as the above... so give ulaw and alaw priority */ - AST_FORMAT_G722, - /*! Okay, well, signed linear is easy to translate into other stuff */ - AST_FORMAT_SLINEAR192, - AST_FORMAT_SLINEAR96, - AST_FORMAT_SLINEAR48, - AST_FORMAT_SLINEAR44, - AST_FORMAT_SLINEAR32, - AST_FORMAT_SLINEAR24, - AST_FORMAT_SLINEAR16, - AST_FORMAT_SLINEAR12, - AST_FORMAT_SLINEAR, - /*! G.726 is standard ADPCM, in RFC3551 packing order */ - AST_FORMAT_G726, - /*! G.726 is standard ADPCM, in AAL2 packing order */ - AST_FORMAT_G726_AAL2, - /*! ADPCM has great sound quality and is still pretty easy to translate */ - AST_FORMAT_ADPCM, - /*! Okay, we're down to vocoders now, so pick GSM because it's small and easier to - translate and sounds pretty good */ - AST_FORMAT_GSM, - /*! iLBC is not too bad */ - AST_FORMAT_ILBC, - /*! Speex is free, but computationally more expensive than GSM */ - AST_FORMAT_SPEEX32, - AST_FORMAT_SPEEX16, - AST_FORMAT_SPEEX, - /*! Opus */ - AST_FORMAT_OPUS, - /*! SILK is pretty awesome. */ - AST_FORMAT_SILK, - /*! CELT supports crazy high sample rates */ - AST_FORMAT_CELT, - /*! Ick, LPC10 sounds terrible, but at least we have code for it, if you're tacky enough - to use it */ - AST_FORMAT_LPC10, - /*! G.729a is faster than 723 and slightly less expensive */ - AST_FORMAT_G729A, - /*! Down to G.723.1 which is proprietary but at least designed for voice */ - AST_FORMAT_G723_1, - }; - char buf[512]; - int x; - - /* Find the first preferred codec in the format given */ - for (x = 0; x < ARRAY_LEN(prefs); x++) { - if (ast_format_cap_best_byid(cap, prefs[x], result)) { - return result; - } - } - - ast_format_clear(result); - ast_log(LOG_WARNING, "Don't know any of %s formats\n", ast_getformatname_multiple(buf, sizeof(buf), cap)); - - return NULL; -} - /*! \brief Channel technology used to extract a channel from a running application. The * channel created with this technology will be immediately hung up - most external * applications won't ever want to see this. @@ -883,11 +811,18 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char ast_channel_stage_snapshot(tmp); - if (!(nativeformats = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_CACHE_STRINGS))) { + if (!(nativeformats = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { /* format capabilities structure allocation failure */ return ast_channel_unref(tmp); } + ast_format_cap_append(nativeformats, ast_format_none, 0); ast_channel_nativeformats_set(tmp, nativeformats); + ao2_ref(nativeformats, -1); + + ast_channel_set_rawwriteformat(tmp, ast_format_none); + ast_channel_set_rawreadformat(tmp, ast_format_none); + ast_channel_set_writeformat(tmp, ast_format_none); + ast_channel_set_readformat(tmp, ast_format_none); /* * Init file descriptors to unopened state so @@ -2317,6 +2252,13 @@ static void ast_channel_destructor(void *obj) if (ast_channel_pbx(chan)) ast_log_callid(LOG_WARNING, callid, "PBX may not have been terminated properly on '%s'\n", ast_channel_name(chan)); + /* Free formats */ + ast_channel_set_oldwriteformat(chan, NULL); + ast_channel_set_rawreadformat(chan, NULL); + ast_channel_set_rawwriteformat(chan, NULL); + ast_channel_set_readformat(chan, NULL); + ast_channel_set_writeformat(chan, NULL); + ast_party_dialed_free(ast_channel_dialed(chan)); ast_party_caller_free(ast_channel_caller(chan)); ast_party_connected_line_free(ast_channel_connected(chan)); @@ -2373,7 +2315,7 @@ static void ast_channel_destructor(void *obj) ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE) ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), device_name); } - ast_channel_nativeformats_set(chan, ast_format_cap_destroy(ast_channel_nativeformats(chan))); + ast_channel_nativeformats_set(chan, NULL); if (callid) { ast_callid_unref(callid); } @@ -2623,21 +2565,14 @@ int ast_softhangup(struct ast_channel *chan, int cause) static void free_translation(struct ast_channel *clonechan) { - if (ast_channel_writetrans(clonechan)) + if (ast_channel_writetrans(clonechan)) { ast_translator_free_path(ast_channel_writetrans(clonechan)); - if (ast_channel_readtrans(clonechan)) + } + if (ast_channel_readtrans(clonechan)) { ast_translator_free_path(ast_channel_readtrans(clonechan)); + } ast_channel_writetrans_set(clonechan, NULL); ast_channel_readtrans_set(clonechan, NULL); - if (ast_format_cap_is_empty(ast_channel_nativeformats(clonechan))) { - ast_format_clear(ast_channel_rawwriteformat(clonechan)); - ast_format_clear(ast_channel_rawreadformat(clonechan)); - } else { - struct ast_format tmpfmt; - ast_best_codec(ast_channel_nativeformats(clonechan), &tmpfmt); - ast_format_copy(ast_channel_rawwriteformat(clonechan), &tmpfmt); - ast_format_copy(ast_channel_rawreadformat(clonechan), &tmpfmt); - } } void ast_set_hangupsource(struct ast_channel *chan, const char *source, int force) @@ -2998,10 +2933,11 @@ static int generator_force(const void *data) generate = ast_channel_generator(chan)->generate; ast_channel_unlock(chan); - if (!tmp || !generate) + if (!tmp || !generate) { return 0; + } - res = generate(chan, tmp, 0, ast_format_rate(ast_channel_writeformat(chan)) / 50); + res = generate(chan, tmp, 0, ast_format_get_sample_rate(ast_channel_writeformat(chan)) / 50); ast_channel_lock(chan); if (ast_channel_generator(chan) && generate == ast_channel_generator(chan)->generate) { @@ -3677,11 +3613,9 @@ static void ast_read_generator_actions(struct ast_channel *chan, struct ast_fram * We must generate frames in phase locked mode since * we have no internal timer available. */ - - if (ast_format_cmp(&f->subclass.format, ast_channel_writeformat(chan)) == AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_cmp(f->subclass.format, ast_channel_writeformat(chan)) == AST_FORMAT_CMP_NOT_EQUAL) { float factor; - - factor = ((float) ast_format_rate(ast_channel_writeformat(chan))) / ((float) ast_format_rate(&f->subclass.format)); + factor = ((float) ast_format_get_sample_rate(ast_channel_writeformat(chan))) / ((float) ast_format_get_sample_rate(f->subclass.format)); samples = (int) (((float) f->samples) * factor); } else { samples = f->samples; @@ -4186,11 +4120,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) && !ast_format_cap_iscompatible(ast_channel_nativeformats(chan), &f->subclass.format)) { + } else if ((f->frametype == AST_FRAME_VOICE) && ast_format_cap_iscompatible_format(ast_channel_nativeformats(chan), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { /* This frame is not one of the current native formats -- drop it on the floor */ - char to[200]; + struct ast_str *codec_buf = ast_str_alloca(64); ast_log(LOG_NOTICE, "Dropping incompatible voice frame on %s of format %s since our native format has changed to %s\n", - ast_channel_name(chan), ast_getformatname(&f->subclass.format), ast_getformatname_multiple(to, sizeof(to), ast_channel_nativeformats(chan))); + ast_channel_name(chan), ast_format_get_name(f->subclass.format), ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf)); ast_frfree(f); f = &ast_null_frame; } else if ((f->frametype == AST_FRAME_VOICE)) { @@ -4206,7 +4140,9 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) #ifndef MONITOR_CONSTANT_DELAY int jump = ast_channel_outsmpl(chan) - ast_channel_insmpl(chan) - 4 * f->samples; if (jump >= 0) { - jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)), ast_format_rate(&f->subclass.format), ast_format_rate(&ast_channel_monitor(chan)->read_stream->fmt->format)); + jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)), + ast_format_get_sample_rate(f->subclass.format), + ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format)); if (ast_seekstream(ast_channel_monitor(chan)->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"); } @@ -4215,7 +4151,9 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) ast_channel_insmpl_set(chan, ast_channel_insmpl(chan) + f->samples); } #else - int jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)), ast_format_rate(f->subclass.codec), ast_format_rate(ast_channel_monitor(chan)->read_stream->fmt->format)); + int jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)), + ast_format_get_sample_rate(f->subclass.codec), + ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format)); if (jump - MONITOR_DELAY >= 0) { if (ast_seekstream(ast_channel_monitor(chan)->read_stream, jump - f->samples, SEEK_FORCECUR) == -1) ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n"); @@ -4748,7 +4686,7 @@ int ast_sendtext(struct ast_channel *chan, const char *text) } CHECK_BLOCKING(chan); - if (ast_channel_tech(chan)->write_text && (ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_FORMAT_TYPE_TEXT))) { + if (ast_channel_tech(chan)->write_text && (ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_TEXT))) { struct ast_frame f; f.frametype = AST_FRAME_TEXT; @@ -4759,7 +4697,7 @@ int ast_sendtext(struct ast_channel *chan, const char *text) f.offset = 0; f.seqno = 0; - ast_format_set(&f.subclass.format, AST_FORMAT_T140, 0); + f.subclass.format = ast_format_t140; res = ast_channel_tech(chan)->write_text(chan, &f); } else if (ast_channel_tech(chan)->send_text) { res = ast_channel_tech(chan)->send_text(chan, text); @@ -4856,7 +4794,7 @@ int ast_prod(struct ast_channel *chan) /* Send an empty audio frame to get things moving */ if (ast_channel_state(chan) != AST_STATE_UP) { ast_debug(1, "Prodding channel '%s'\n", ast_channel_name(chan)); - ast_format_copy(&a.subclass.format, ast_channel_rawwriteformat(chan)); + a.subclass.format = ast_channel_rawwriteformat(chan); a.data.ptr = nothing + AST_FRIENDLY_OFFSET; a.src = "ast_prod"; /* this better match check in ast_write */ if (ast_write(chan, &a)) @@ -5068,7 +5006,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) CHECK_BLOCKING(chan); break; case AST_FRAME_TEXT: - if (fr->subclass.integer == AST_FORMAT_T140) { + if (ast_format_cmp(fr->subclass.format, ast_format_t140) == AST_FORMAT_CMP_EQUAL) { res = (ast_channel_tech(chan)->write_text == NULL) ? 0 : ast_channel_tech(chan)->write_text(chan, fr); } else { @@ -5093,17 +5031,17 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) if (ast_channel_tech(chan)->write == NULL) break; /*! \todo XXX should return 0 maybe ? */ - if (ast_opt_generic_plc && fr->subclass.format.id == AST_FORMAT_SLINEAR) { + if (ast_opt_generic_plc && ast_format_cmp(fr->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) { 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 (ast_format_cmp(&fr->subclass.format, ast_channel_rawwriteformat(chan)) != AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_cmp(fr->subclass.format, ast_channel_rawwriteformat(chan)) != AST_FORMAT_CMP_NOT_EQUAL) { f = fr; } else { - if ((!ast_format_cap_iscompatible(ast_channel_nativeformats(chan), &fr->subclass.format)) && - (ast_format_cmp(ast_channel_writeformat(chan), &fr->subclass.format) != AST_FORMAT_CMP_EQUAL)) { - char nf[512]; + if ((ast_format_cap_iscompatible_format(ast_channel_nativeformats(chan), fr->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) && + (ast_format_cmp(ast_channel_writeformat(chan), fr->subclass.format) != AST_FORMAT_CMP_EQUAL)) { + struct ast_str *codec_buf = ast_str_alloca(64); /* * XXX Something is not right. We are not compatible with this @@ -5115,9 +5053,9 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) * areas. */ ast_log(LOG_WARNING, "Codec mismatch on channel %s setting write format to %s from %s native formats %s\n", - ast_channel_name(chan), ast_getformatname(&fr->subclass.format), ast_getformatname(ast_channel_writeformat(chan)), - ast_getformatname_multiple(nf, sizeof(nf), ast_channel_nativeformats(chan))); - ast_set_write_format_by_id(chan, fr->subclass.format.id); + ast_channel_name(chan), ast_format_get_name(fr->subclass.format), ast_format_get_name(ast_channel_writeformat(chan)), + ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf)); + ast_set_write_format(chan, fr->subclass.format); } f = (ast_channel_writetrans(chan)) ? ast_translate(ast_channel_writetrans(chan), fr, 0) : fr; @@ -5185,7 +5123,9 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) #ifndef MONITOR_CONSTANT_DELAY int jump = ast_channel_insmpl(chan) - ast_channel_outsmpl(chan) - 4 * cur->samples; if (jump >= 0) { - jump = calc_monitor_jump((ast_channel_insmpl(chan) - ast_channel_outsmpl(chan)), ast_format_rate(&f->subclass.format), ast_format_rate(&ast_channel_monitor(chan)->read_stream->fmt->format)); + jump = calc_monitor_jump((ast_channel_insmpl(chan) - ast_channel_outsmpl(chan)), + ast_format_get_sample_rate(f->subclass.format), + ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format)); if (ast_seekstream(ast_channel_monitor(chan)->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"); } @@ -5194,7 +5134,9 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) ast_channel_outsmpl_set(chan, ast_channel_outsmpl(chan) + cur->samples); } #else - int jump = calc_monitor_jump((ast_channel_insmpl(chan) - ast_channel_outsmpl(chan)), ast_format_rate(f->subclass.codec), ast_format_rate(ast_channel_monitor(chan)->read_stream->fmt->format)); + int jump = calc_monitor_jump((ast_channel_insmpl(chan) - ast_channel_outsmpl(chan)), + ast_format_get_sample_rate(f->subclass.codec), + ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format)); if (jump - MONITOR_DELAY >= 0) { if (ast_seekstream(ast_channel_monitor(chan)->write_stream, jump - cur->samples, SEEK_FORCECUR) == -1) { ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n"); @@ -5300,21 +5242,23 @@ static int set_format(struct ast_channel *chan, { struct ast_trans_pvt *trans_pvt; struct ast_format_cap *cap_native; - struct ast_format best_set_fmt; - struct ast_format best_native_fmt; + RAII_VAR(struct ast_format *, best_set_fmt, ast_format_cap_get_format(cap_set, 0), ao2_cleanup); + RAII_VAR(struct ast_format *, best_native_fmt, NULL, ao2_cleanup); int res; - ast_best_codec(cap_set, &best_set_fmt); + ast_assert(format != NULL); + ast_assert(rawformat != NULL); /* 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, &best_set_fmt, sizeof(best_set_fmt), 0)) { ast_debug(1, "Channel driver natively set channel %s to %s format %s\n", ast_channel_name(chan), - direction ? "write" : "read", ast_getformatname(&best_set_fmt)); + direction ? "write" : "read", ast_format_get_name(best_set_fmt)); ast_channel_lock(chan); - ast_format_copy(format, &best_set_fmt); - ast_format_copy(rawformat, &best_set_fmt); - ast_format_cap_set(ast_channel_nativeformats(chan), &best_set_fmt); + cap_native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + ast_format_cap_append(cap_native, best_set_fmt, 0); + ast_channel_nativeformats_set(chan, cap_native); + ao2_cleanup(cap_native); ast_channel_unlock(chan); trans_pvt = trans->get(chan); @@ -5344,31 +5288,27 @@ static int set_format(struct ast_channel *chan, res = ast_translator_best_choice(cap_native, cap_set, &best_native_fmt, &best_set_fmt); } if (res < 0) { - char from[200]; - char to[200]; + struct ast_str *codec_from = ast_str_alloca(64); + struct ast_str *codec_to = ast_str_alloca(64); - ast_getformatname_multiple(from, sizeof(from), cap_native); + ast_format_cap_get_names(cap_native, &codec_from); ast_channel_unlock(chan); - ast_getformatname_multiple(to, sizeof(to), cap_set); + ast_format_cap_get_names(cap_set, &codec_to); ast_log(LOG_WARNING, "Unable to find a codec translation path from %s to %s\n", - from, to); + ast_str_buffer(codec_from), ast_str_buffer(codec_to)); return -1; } /* Now we have a good choice for both. */ - 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) && + 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->get(chan))) { /* the channel is already in these formats, so nothing to do */ ast_channel_unlock(chan); return 0; } - ast_format_copy(rawformat, &best_native_fmt); - /* User perspective is fmt */ - ast_format_copy(format, &best_set_fmt); - /* Free any translation we have right now */ trans_pvt = trans->get(chan); if (trans_pvt) { @@ -5377,7 +5317,7 @@ static int set_format(struct ast_channel *chan, } /* Build a translation path from the raw format to the desired format */ - if (ast_format_cmp(format, rawformat) != AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_cmp(best_set_fmt, best_native_fmt) != 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 @@ -5387,20 +5327,33 @@ static int set_format(struct ast_channel *chan, } else { if (!direction) { /* reading */ - trans_pvt = ast_translator_build_path(format, rawformat); + trans_pvt = ast_translator_build_path(best_set_fmt, best_native_fmt); } else { /* writing */ - trans_pvt = ast_translator_build_path(rawformat, format); + trans_pvt = ast_translator_build_path(best_native_fmt, best_set_fmt); } trans->set(chan, trans_pvt); res = trans_pvt ? 0 : -1; } - ast_channel_unlock(chan); - ast_debug(1, "Set channel %s to %s format %s\n", - ast_channel_name(chan), - direction ? "write" : "read", - ast_getformatname(&best_set_fmt)); + if (!res) { + if (!direction) { + /* reading */ + ast_channel_set_readformat(chan, best_set_fmt); + ast_channel_set_rawreadformat(chan, best_native_fmt); + } else { + /* writing */ + ast_channel_set_writeformat(chan, best_set_fmt); + ast_channel_set_rawwriteformat(chan, best_native_fmt); + } + + ast_debug(1, "Set channel %s to %s format %s\n", + ast_channel_name(chan), + direction ? "write" : "read", + ast_format_get_name(best_set_fmt)); + } + + ast_channel_unlock(chan); /* If there is a generator on the channel, it needs to know about this * change if it is the write format. */ @@ -5413,35 +5366,15 @@ static int set_format(struct ast_channel *chan, int ast_set_read_format(struct ast_channel *chan, struct ast_format *format) { - struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); int res; - if (!cap) { - return -1; - } - ast_format_cap_add(cap, format); - - res = set_format(chan, - cap, - ast_channel_rawreadformat(chan), - ast_channel_readformat(chan), - &set_format_readtrans, - 0); - - ast_format_cap_destroy(cap); - return res; -} - -int ast_set_read_format_by_id(struct ast_channel *chan, enum ast_format_id id) -{ - struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - struct ast_format tmp_format; - int res; + ast_assert(format != NULL); if (!cap) { return -1; } - ast_format_cap_add(cap, ast_format_set(&tmp_format, id, 0)); + ast_format_cap_append(cap, format, 0); res = set_format(chan, cap, @@ -5450,7 +5383,7 @@ int ast_set_read_format_by_id(struct ast_channel *chan, enum ast_format_id id) &set_format_readtrans, 0); - ast_format_cap_destroy(cap); + ao2_cleanup(cap); return res; } @@ -5466,35 +5399,15 @@ int ast_set_read_format_from_cap(struct ast_channel *chan, struct ast_format_cap int ast_set_write_format(struct ast_channel *chan, struct ast_format *format) { - struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); int res; - if (!cap) { - return -1; - } - ast_format_cap_add(cap, format); - - res = set_format(chan, - cap, - ast_channel_rawwriteformat(chan), - ast_channel_writeformat(chan), - &set_format_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(AST_FORMAT_CAP_FLAG_NOLOCK); - struct ast_format tmp_format; - int res; + ast_assert(format != NULL); if (!cap) { return -1; } - ast_format_cap_add(cap, ast_format_set(&tmp_format, id, 0)); + ast_format_cap_append(cap, format, 0); res = set_format(chan, cap, @@ -5503,7 +5416,7 @@ int ast_set_write_format_by_id(struct ast_channel *chan, enum ast_format_id id) &set_format_writetrans, 1); - ast_format_cap_destroy(cap); + ao2_cleanup(cap); return res; } @@ -5912,26 +5825,29 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request AST_RWLIST_TRAVERSE(&backends, chan, list) { struct ast_format_cap *tmp_cap; - struct ast_format tmp_fmt; - struct ast_format best_audio_fmt; + RAII_VAR(struct ast_format *, tmp_fmt, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, best_audio_fmt, NULL, ao2_cleanup); struct ast_format_cap *joint_cap; if (strcasecmp(type, chan->tech->type)) continue; - 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))) { + tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (tmp_cap) { + ast_format_cap_append_from_cap(tmp_cap, request_cap, AST_MEDIA_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(tmp_cap, chan->tech->capabilities, &tmp_fmt, &best_audio_fmt); - ast_format_cap_destroy(tmp_cap); + ao2_ref(tmp_cap, -1); if (res < 0) { - char tmp1[256], tmp2[256]; + struct ast_str *tech_codecs = ast_str_alloca(64); + struct ast_str *request_codecs = ast_str_alloca(64); + 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), request_cap)); + ast_format_cap_get_names(chan->tech->capabilities, &tech_codecs), + ast_format_cap_get_names(request_cap, &request_codecs)); *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL; AST_RWLIST_UNLOCK(&backends); return NULL; @@ -5945,14 +5861,16 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request * 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))) { + joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!joint_cap) { return NULL; } - ast_format_cap_remove_bytype(joint_cap, AST_FORMAT_TYPE_AUDIO); - ast_format_cap_add(joint_cap, &best_audio_fmt); + ast_format_cap_append_from_cap(joint_cap, request_cap, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_remove_by_type(joint_cap, AST_MEDIA_TYPE_AUDIO); + ast_format_cap_append(joint_cap, best_audio_fmt, 0); if (!(c = chan->tech->requester(type, joint_cap, assignedids, requestor, addr, cause))) { - ast_format_cap_destroy(joint_cap); + ao2_ref(joint_cap, -1); return NULL; } @@ -5967,7 +5885,7 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request } } - joint_cap = ast_format_cap_destroy(joint_cap); + ao2_ref(joint_cap, -1); if (set_security_requirements(requestor, c)) { ast_log(LOG_WARNING, "Setting security requirements failed\n"); @@ -6164,8 +6082,8 @@ static int ast_channel_make_compatible_helper(struct ast_channel *from, struct a { struct ast_format_cap *src_cap; struct ast_format_cap *dst_cap; - struct ast_format best_src_fmt; - struct ast_format best_dst_fmt; + RAII_VAR(struct ast_format *, best_src_fmt, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, best_dst_fmt, NULL, ao2_cleanup); int no_path; ast_channel_lock_both(from, to); @@ -6182,8 +6100,8 @@ static int ast_channel_make_compatible_helper(struct ast_channel *from, struct a dst_cap = ast_channel_nativeformats(to); /* shallow copy, do not destroy */ /* If there's no audio in this call, don't bother with trying to find a translation path */ - if (!ast_format_cap_has_type(src_cap, AST_FORMAT_TYPE_AUDIO) - || !ast_format_cap_has_type(dst_cap, AST_FORMAT_TYPE_AUDIO)) { + if (!ast_format_cap_has_type(src_cap, AST_MEDIA_TYPE_AUDIO) + || !ast_format_cap_has_type(dst_cap, AST_MEDIA_TYPE_AUDIO)) { ast_channel_unlock(to); ast_channel_unlock(from); return 0; @@ -6206,28 +6124,29 @@ 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 */ - if (ast_format_cmp(&best_dst_fmt, &best_src_fmt) == AST_FORMAT_CMP_NOT_EQUAL + if (ast_format_cmp(best_dst_fmt, best_src_fmt) == AST_FORMAT_CMP_NOT_EQUAL && (ast_opt_generic_plc || ast_opt_transcode_via_slin)) { - int use_slin = (ast_format_is_slinear(&best_src_fmt) - || ast_format_is_slinear(&best_dst_fmt)) ? 1 : 0; + int use_slin = (ast_format_cache_is_slinear(best_src_fmt) + || ast_format_cache_is_slinear(best_dst_fmt)) ? 1 : 0; - if (use_slin || ast_translate_path_steps(&best_dst_fmt, &best_src_fmt) != 1) { - int best_sample_rate = (ast_format_rate(&best_src_fmt) > ast_format_rate(&best_dst_fmt)) ? - ast_format_rate(&best_src_fmt) : ast_format_rate(&best_dst_fmt); + if (use_slin || ast_translate_path_steps(best_dst_fmt, best_src_fmt) != 1) { + int best_sample_rate = (ast_format_get_sample_rate(best_src_fmt) > ast_format_get_sample_rate(best_dst_fmt)) ? + ast_format_get_sample_rate(best_src_fmt) : ast_format_get_sample_rate(best_dst_fmt); /* pick the best signed linear format based upon what preserves the sample rate the best. */ - ast_format_set(&best_src_fmt, ast_format_slin_by_rate(best_sample_rate), 0); + ao2_ref(best_src_fmt, -1); + best_src_fmt = ao2_bump(ast_format_cache_get_slin_by_rate(best_sample_rate)); } } - if (ast_set_read_format(from, &best_src_fmt)) { + if (ast_set_read_format(from, best_src_fmt)) { ast_log(LOG_WARNING, "Unable to set read format on channel %s to %s\n", - ast_channel_name(from), ast_getformatname(&best_src_fmt)); + ast_channel_name(from), ast_format_get_name(best_src_fmt)); return -1; } - if (ast_set_write_format(to, &best_src_fmt)) { + if (ast_set_write_format(to, best_src_fmt)) { ast_log(LOG_WARNING, "Unable to set write format on channel %s to %s\n", - ast_channel_name(to), ast_getformatname(&best_src_fmt)); + ast_channel_name(to), ast_format_get_name(best_src_fmt)); return -1; } return 0; @@ -6387,9 +6306,10 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann struct ast_party_redirecting redirecting; } exchange; struct ast_channel *bridged; - struct ast_format rformat; - struct ast_format wformat; - struct ast_format tmp_format; + struct ast_format *rformat; + struct ast_format *wformat; + struct ast_format *tmp_format; + struct ast_format_cap *tmp_cap; char tmp_name[AST_CHANNEL_NAME]; char clone_sending_dtmf_digit; struct timeval clone_sending_dtmf_tv; @@ -6446,8 +6366,8 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann * Remember the original read/write formats. We turn off any * translation on either one */ - ast_format_copy(&rformat, ast_channel_readformat(original)); - ast_format_copy(&wformat, ast_channel_writeformat(original)); + rformat = ao2_bump(ast_channel_readformat(original)); + wformat = ao2_bump(ast_channel_writeformat(original)); free_translation(clonechan); free_translation(original); @@ -6508,13 +6428,15 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann } /* Swap the raw formats */ - ast_format_copy(&tmp_format, ast_channel_rawreadformat(original)); - ast_format_copy(ast_channel_rawreadformat(original), ast_channel_rawreadformat(clonechan)); - ast_format_copy(ast_channel_rawreadformat(clonechan), &tmp_format); + tmp_format = ao2_bump(ast_channel_rawreadformat(original)); + ast_channel_set_rawreadformat(original, ast_channel_rawreadformat(clonechan)); + ast_channel_set_rawreadformat(clonechan, tmp_format); + ao2_cleanup(tmp_format); - ast_format_copy(&tmp_format, ast_channel_rawwriteformat(original)); - ast_format_copy(ast_channel_rawwriteformat(original), ast_channel_rawwriteformat(clonechan)); - ast_format_copy(ast_channel_rawwriteformat(clonechan), &tmp_format); + tmp_format = ao2_bump(ast_channel_rawwriteformat(original)); + ast_channel_set_rawwriteformat(original, ast_channel_rawwriteformat(clonechan)); + ast_channel_set_rawwriteformat(clonechan, tmp_format); + ao2_cleanup(tmp_format); ast_channel_softhangup_internal_flag_set(clonechan, AST_SOFTHANGUP_DEV); @@ -6642,16 +6564,21 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann ast_channel_set_fd(original, AST_TIMING_FD, ast_channel_timingfd(original)); /* Our native formats are different now */ - ast_format_cap_copy(ast_channel_nativeformats(original), ast_channel_nativeformats(clonechan)); + tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (tmp_cap) { + ast_format_cap_append_from_cap(tmp_cap, ast_channel_nativeformats(clonechan), AST_MEDIA_TYPE_UNKNOWN); + ast_channel_nativeformats_set(original, tmp_cap); + ao2_ref(tmp_cap, -1); + } /* 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_channel_musicclass_set(original, ast_channel_musicclass(clonechan)); @@ -6660,7 +6587,7 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann ast_channel_accountcode_set(original, S_OR(ast_channel_accountcode(clonechan), "")); ast_debug(1, "Putting channel %s in %s/%s formats\n", ast_channel_name(original), - ast_getformatname(&wformat), ast_getformatname(&rformat)); + ast_format_get_name(wformat), ast_format_get_name(rformat)); /* Fixup the original clonechan's physical side */ if (ast_channel_tech(original)->fixup && ast_channel_tech(original)->fixup(clonechan, original)) { @@ -6773,6 +6700,9 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann /* Release our held safety references. */ ast_channel_unref(original); ast_channel_unref(clonechan); + + ao2_cleanup(rformat); + ao2_cleanup(wformat); } void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani) @@ -6917,7 +6847,7 @@ struct tonepair_state { int v1_2; int v2_2; int v3_2; - struct ast_format origwfmt; + struct ast_format *origwfmt; int pos; int duration; int modulate; @@ -6930,8 +6860,10 @@ static void tonepair_release(struct ast_channel *chan, void *params) { struct tonepair_state *ts = params; - if (chan) - ast_set_write_format(chan, &ts->origwfmt); + if (chan) { + ast_set_write_format(chan, ts->origwfmt); + } + ao2_cleanup(ts->origwfmt); ast_free(ts); } @@ -6940,10 +6872,12 @@ static void *tonepair_alloc(struct ast_channel *chan, void *params) struct tonepair_state *ts; struct tonepair_def *td = params; - if (!(ts = ast_calloc(1, sizeof(*ts)))) + if (!(ts = ast_calloc(1, sizeof(*ts)))) { return NULL; - ast_format_copy(&ts->origwfmt, ast_channel_writeformat(chan)); - if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) { + } + + ts->origwfmt = ao2_bump(ast_channel_writeformat(chan)); + if (ast_set_write_format(chan, ast_format_slin)) { ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", ast_channel_name(chan)); tonepair_release(NULL, ts); ts = NULL; @@ -6997,7 +6931,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; - ast_format_set(&ts->f.subclass.format, AST_FORMAT_SLINEAR, 0); + ts->f.subclass.format = ast_format_slin; ts->f.datalen = len; ts->f.samples = samples; ts->f.offset = AST_FRIENDLY_OFFSET; @@ -7675,7 +7609,7 @@ static int silence_generator_generate(struct ast_channel *chan, void *data, int .samples = samples, .datalen = sizeof(buf), }; - ast_format_set(&frame.subclass.format, AST_FORMAT_SLINEAR, 0); + frame.subclass.format = ast_format_slin; memset(buf, 0, sizeof(buf)); @@ -7692,7 +7626,7 @@ static struct ast_generator silence_generator = { }; struct ast_silence_generator { - struct ast_format old_write_format; + struct ast_format *old_write_format; }; struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_channel *chan) @@ -7703,9 +7637,9 @@ struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_cha return NULL; } - ast_format_copy(&state->old_write_format, ast_channel_writeformat(chan)); + state->old_write_format = ao2_bump(ast_channel_writeformat(chan)); - if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) { + if (ast_set_write_format(chan, ast_format_slin) < 0) { ast_log(LOG_ERROR, "Could not set write format to SLINEAR\n"); ast_free(state); return NULL; @@ -7749,9 +7683,11 @@ void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_sil if (deactivate_silence_generator(chan)) { ast_debug(1, "Stopped silence generator on '%s'\n", ast_channel_name(chan)); - 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"); + } } + ao2_cleanup(state->old_write_format); ast_free(state); } @@ -10199,8 +10135,8 @@ struct ast_channel *ast_channel_yank(struct ast_channel *yankee) char *context; char *name; int amaflags; - struct ast_format readformat; - struct ast_format writeformat; + struct ast_format *readformat; + struct ast_format *writeformat; } my_vars = { 0, }; ast_channel_lock(yankee); @@ -10209,8 +10145,8 @@ struct ast_channel *ast_channel_yank(struct ast_channel *yankee) my_vars.context = ast_strdupa(ast_channel_context(yankee)); my_vars.name = ast_strdupa(ast_channel_name(yankee)); my_vars.amaflags = ast_channel_amaflags(yankee); - ast_format_copy(&my_vars.writeformat, ast_channel_writeformat(yankee)); - ast_format_copy(&my_vars.readformat, ast_channel_readformat(yankee)); + my_vars.writeformat = ao2_bump(ast_channel_writeformat(yankee)); + my_vars.readformat = ao2_bump(ast_channel_readformat(yankee)); ast_channel_unlock(yankee); /* Do not hold any channel locks while calling channel_alloc() since the function @@ -10218,12 +10154,16 @@ struct ast_channel *ast_channel_yank(struct ast_channel *yankee) if (!(yanked_chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, my_vars.accountcode, my_vars.exten, my_vars.context, NULL, yankee, my_vars.amaflags, "Surrogate/%s", my_vars.name))) { + ao2_cleanup(my_vars.writeformat); + ao2_cleanup(my_vars.readformat); return NULL; } /* Make formats okay */ - ast_format_copy(ast_channel_readformat(yanked_chan), &my_vars.readformat); - ast_format_copy(ast_channel_writeformat(yanked_chan), &my_vars.writeformat); + ast_channel_set_readformat(yanked_chan, my_vars.readformat); + ast_channel_set_writeformat(yanked_chan, my_vars.writeformat); + ao2_cleanup(my_vars.readformat); + ao2_cleanup(my_vars.writeformat); ast_channel_unlock(yanked_chan); diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index c2dc2d737..4ad0ef3a0 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -176,7 +176,7 @@ struct ast_channel { int fdno; /*!< Which fd had an event detected on */ int streamid; /*!< For streaming playback, the schedule ID */ int vstreamid; /*!< For streaming video playback, the schedule ID */ - struct ast_format oldwriteformat; /*!< Original writer format */ + struct ast_format *oldwriteformat; /*!< Original writer format */ int timingfd; /*!< Timing fd */ enum ast_channel_state state; /*!< State of line -- Don't write directly, use ast_setstate() */ int rings; /*!< Number of rings so far */ @@ -193,10 +193,10 @@ struct ast_channel { struct ast_flags flags; /*!< channel flags of AST_FLAG_ type */ int alertpipe[2]; struct ast_format_cap *nativeformats; /*!< Kinds of data this channel can natively handle */ - struct ast_format readformat; /*!< Requested read format (after translation) */ - struct ast_format writeformat; /*!< Requested write format (after translation) */ - struct ast_format rawreadformat; /*!< Raw read format (before translation) */ - struct ast_format rawwriteformat; /*!< Raw write format (before translation) */ + struct ast_format *readformat; /*!< Requested read format (after translation) */ + struct ast_format *writeformat; /*!< Requested write format (after translation) */ + struct ast_format *rawreadformat; /*!< Raw read format (before translation) */ + struct ast_format *rawwriteformat; /*!< Raw write format (before translation) */ unsigned int emulate_dtmf_duration; /*!< Number of ms left to emulate DTMF for */ #ifdef HAVE_EPOLL int epfd; @@ -826,7 +826,8 @@ struct ast_format_cap *ast_channel_nativeformats(const struct ast_channel *chan) } void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value) { - chan->nativeformats = value; + ao2_cleanup(chan->nativeformats); + chan->nativeformats = ao2_bump(value); } struct ast_framehook_list *ast_channel_framehooks(const struct ast_channel *chan) { @@ -949,25 +950,50 @@ void ast_channel_state_set(struct ast_channel *chan, enum ast_channel_state valu { chan->state = value; } +void ast_channel_set_oldwriteformat(struct ast_channel *chan, struct ast_format *format) +{ + ao2_cleanup(chan->oldwriteformat); + chan->oldwriteformat = ao2_bump(format); +} +void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format) +{ + ao2_cleanup(chan->rawreadformat); + chan->rawreadformat = ao2_bump(format); +} +void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format) +{ + ao2_cleanup(chan->rawwriteformat); + chan->rawwriteformat = ao2_bump(format); +} +void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format) +{ + ao2_cleanup(chan->readformat); + chan->readformat = ao2_bump(format); +} +void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format) +{ + ao2_cleanup(chan->writeformat); + chan->writeformat = ao2_bump(format); +} struct ast_format *ast_channel_oldwriteformat(struct ast_channel *chan) { - return &chan->oldwriteformat; + return chan->oldwriteformat; } struct ast_format *ast_channel_rawreadformat(struct ast_channel *chan) { - return &chan->rawreadformat; + return chan->rawreadformat; } struct ast_format *ast_channel_rawwriteformat(struct ast_channel *chan) { - return &chan->rawwriteformat; + return chan->rawwriteformat; } struct ast_format *ast_channel_readformat(struct ast_channel *chan) { - return &chan->readformat; + return chan->readformat; } struct ast_format *ast_channel_writeformat(struct ast_channel *chan) { - return &chan->writeformat; + return chan->writeformat; } struct ast_hangup_handler_list *ast_channel_hangup_handlers(struct ast_channel *chan) { diff --git a/main/cli.c b/main/cli.c index bff58695d..bb8e33e44 100644 --- a/main/cli.c +++ b/main/cli.c @@ -1521,9 +1521,9 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar long elapsed_seconds=0; int hour=0, min=0, sec=0; struct ast_var_t *var; - char nativeformats[256]; struct ast_str *write_transpath = ast_str_alloca(256); struct ast_str *read_transpath = ast_str_alloca(256); + struct ast_str *codec_buf = ast_str_alloca(64); struct ast_bridge *bridge; struct ast_callid *callid; char callid_buf[32]; @@ -1634,9 +1634,9 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar ast_channel_language(chan), ast_state2str(ast_channel_state(chan)), ast_channel_state(chan), - ast_getformatname_multiple(nativeformats, sizeof(nativeformats), ast_channel_nativeformats(chan)), - ast_getformatname(ast_channel_writeformat(chan)), - ast_getformatname(ast_channel_readformat(chan)), + ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf), + ast_format_get_name(ast_channel_writeformat(chan)), + ast_format_get_name(ast_channel_readformat(chan)), ast_str_strlen(write_transpath) ? "Yes" : "No", ast_str_buffer(write_transpath), ast_str_strlen(read_transpath) ? "Yes" : "No", diff --git a/main/codec.c b/main/codec.c new file mode 100644 index 000000000..e060efe3e --- /dev/null +++ b/main/codec.c @@ -0,0 +1,381 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Joshua Colp <jcolp@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Codecs API + * + * \author Joshua Colp <jcolp@digium.com> + */ + +/*** MODULEINFO + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/logger.h" +#include "asterisk/codec.h" +#include "asterisk/format.h" +#include "asterisk/frame.h" +#include "asterisk/astobj2.h" +#include "asterisk/strings.h" +#include "asterisk/module.h" +#include "asterisk/cli.h" + +/*! \brief Number of buckets to use for codecs (should be prime for performance reasons) */ +#define CODEC_BUCKETS 53 + +/*! \brief Current identifier value for newly registered codec */ +static int codec_id = 1; + +/*! \brief Registered codecs */ +static struct ao2_container *codecs; + +static int codec_hash(const void *obj, int flags) +{ + const struct ast_codec *codec; + const char *key; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_KEY: + key = obj; + return ast_str_hash(key); + case OBJ_SEARCH_OBJECT: + codec = obj; + return ast_str_hash(codec->name); + default: + /* Hash can only work on something with a full key. */ + ast_assert(0); + return 0; + } +} + +static int codec_cmp(void *obj, void *arg, int flags) +{ + const struct ast_codec *left = obj; + const struct ast_codec *right = arg; + const char *right_key = arg; + int cmp; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + right_key = right->name; + cmp = strcmp(left->name, right_key); + + if (right->type != AST_MEDIA_TYPE_UNKNOWN) { + cmp |= (right->type != left->type); + } + + /* BUGBUG: this will allow a match on a codec by name only. + * This is particularly useful when executed by the CLI; if + * that is not needed in translate.c, this can be removed. + */ + if (right->sample_rate) { + cmp |= (right->sample_rate != left->sample_rate); + } + break; + case OBJ_SEARCH_KEY: + cmp = strcmp(left->name, right_key); + break; + case OBJ_SEARCH_PARTIAL_KEY: + cmp = strncmp(left->name, right_key, strlen(right_key)); + break; + default: + ast_assert(0); + cmp = 0; + break; + } + if (cmp) { + return 0; + } + + return CMP_MATCH; +} + +static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + struct ao2_iterator i; + struct ast_codec *codec; + + switch (cmd) { + case CLI_INIT: + e->command = "core show codecs [audio|video|image|text]"; + e->usage = + "Usage: core show codecs [audio|video|image|text]\n" + " Displays codec mapping\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if ((a->argc < 3) || (a->argc > 4)) { + return CLI_SHOWUSAGE; + } + + if (!ast_opt_dont_warn) { + ast_cli(a->fd, "Disclaimer: this command is for informational purposes only.\n" + "\tIt does not indicate anything about your configuration.\n"); + } + + ast_cli(a->fd, "%8s %5s %8s %s\n","ID","TYPE","NAME","DESCRIPTION"); + ast_cli(a->fd, "-----------------------------------------------------------------------------------\n"); + + ao2_rdlock(codecs); + i = ao2_iterator_init(codecs, AO2_ITERATOR_DONTLOCK); + + for (; (codec = ao2_iterator_next(&i)); ao2_ref(codec, -1)) { + if (a->argc == 4) { + if (!strcasecmp(a->argv[3], "audio")) { + if (codec->type != AST_MEDIA_TYPE_AUDIO) { + continue; + } + } else if (!strcasecmp(a->argv[3], "video")) { + if (codec->type != AST_MEDIA_TYPE_VIDEO) { + continue; + } + } else if (!strcasecmp(a->argv[3], "image")) { + if (codec->type != AST_MEDIA_TYPE_IMAGE) { + continue; + } + } else if (!strcasecmp(a->argv[3], "text")) { + if (codec->type != AST_MEDIA_TYPE_TEXT) { + continue; + } + } else { + continue; + } + } + + ast_cli(a->fd, "%8u %5s %8s (%s)\n", + codec->id, + ast_codec_media_type2str(codec->type), + codec->name, + codec->description); + } + + ao2_iterator_destroy(&i); + ao2_unlock(codecs); + + return CLI_SUCCESS; +} + +/*! \brief Callback function for getting a codec based on unique identifier */ +static int codec_id_cmp(void *obj, void *arg, int flags) +{ + struct ast_codec *codec = obj; + int *id = arg; + + return (codec->id == *id) ? CMP_MATCH | CMP_STOP : 0; +} + +static char *show_codec(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + int type_punned_codec; + struct ast_codec *codec; + + switch (cmd) { + case CLI_INIT: + e->command = "core show codec"; + e->usage = + "Usage: core show codec <number>\n" + " Displays codec mapping\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if (a->argc != 4) { + return CLI_SHOWUSAGE; + } + + if (sscanf(a->argv[3], "%30d", &type_punned_codec) != 1) { + return CLI_SHOWUSAGE; + } + + codec = ao2_callback(codecs, 0, codec_id_cmp, &type_punned_codec); + if (!codec) { + ast_cli(a->fd, "Codec %d not found\n", type_punned_codec); + return CLI_SUCCESS; + } + + ast_cli(a->fd, "%11u %s\n", (unsigned int) codec->id, codec->description); + + ao2_ref(codec, -1); + + return CLI_SUCCESS; +} + +/* Builtin Asterisk CLI-commands for debugging */ +static struct ast_cli_entry codec_cli[] = { + AST_CLI_DEFINE(show_codecs, "Displays a list of registered codecs"), + AST_CLI_DEFINE(show_codec, "Shows a specific codec"), +}; + +/*! \brief Function called when the process is shutting down */ +static void codec_shutdown(void) +{ + ast_cli_unregister_multiple(codec_cli, ARRAY_LEN(codec_cli)); + ao2_cleanup(codecs); + codecs = NULL; +} + +int ast_codec_init(void) +{ + codecs = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, CODEC_BUCKETS, codec_hash, codec_cmp); + if (!codecs) { + return -1; + } + + ast_cli_register_multiple(codec_cli, ARRAY_LEN(codec_cli)); + ast_register_atexit(codec_shutdown); + + return 0; +} + +static void codec_dtor(void *obj) +{ + struct ast_codec *codec; + + codec = obj; + + ast_module_unref(codec->mod); +} + +int __ast_codec_register(struct ast_codec *codec, struct ast_module *mod) +{ + SCOPED_AO2WRLOCK(lock, codecs); + struct ast_codec *codec_new; + + /* Some types have specific requirements */ + if (codec->type == AST_MEDIA_TYPE_UNKNOWN) { + ast_log(LOG_ERROR, "A media type must be specified for codec '%s'\n", codec->name); + return -1; + } else if (codec->type == AST_MEDIA_TYPE_AUDIO) { + if (!codec->sample_rate) { + ast_log(LOG_ERROR, "A sample rate must be specified for codec '%s' of type '%s'\n", + codec->name, ast_codec_media_type2str(codec->type)); + return -1; + } + } + + codec_new = ao2_find(codecs, codec, OBJ_SEARCH_OBJECT | OBJ_NOLOCK); + if (codec_new) { + ast_log(LOG_ERROR, "A codec with name '%s' of type '%s' and sample rate '%u' is already registered\n", + codec->name, ast_codec_media_type2str(codec->type), codec->sample_rate); + ao2_ref(codec_new, -1); + return -1; + } + + codec_new = ao2_t_alloc_options(sizeof(*codec_new), codec_dtor, + AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(codec->description, "")); + if (!codec_new) { + ast_log(LOG_ERROR, "Could not allocate a codec with name '%s' of type '%s' and sample rate '%u'\n", + codec->name, ast_codec_media_type2str(codec->type), codec->sample_rate); + return -1; + } + *codec_new = *codec; + codec_new->id = codec_id++; + + ao2_link_flags(codecs, codec_new, OBJ_NOLOCK); + + /* Once registered a codec can not be unregistered, and the module must persist */ + ast_module_ref(mod); + + ast_verb(2, "Registered '%s' codec '%s' at sample rate '%u' with id '%u'\n", + ast_codec_media_type2str(codec->type), codec->name, codec->sample_rate, codec_new->id); + + ao2_ref(codec_new, -1); + + return 0; +} + +struct ast_codec *ast_codec_get(const char *name, enum ast_media_type type, unsigned int sample_rate) +{ + struct ast_codec codec = { + .name = name, + .type = type, + .sample_rate = sample_rate, + }; + + return ao2_find(codecs, &codec, OBJ_SEARCH_OBJECT); +} + +struct ast_codec *ast_codec_get_by_id(int id) +{ + return ao2_callback(codecs, 0, codec_id_cmp, &id); +} + +int ast_codec_get_max(void) +{ + return codec_id; +} + +const char *ast_codec_media_type2str(enum ast_media_type type) +{ + switch (type) { + case AST_MEDIA_TYPE_AUDIO: + return "audio"; + case AST_MEDIA_TYPE_VIDEO: + return "video"; + case AST_MEDIA_TYPE_IMAGE: + return "image"; + case AST_MEDIA_TYPE_TEXT: + return "text"; + default: + return "<unknown>"; + } +} + +unsigned int ast_codec_samples_count(struct ast_frame *frame) +{ + struct ast_codec *codec; + unsigned int samples = 0; + + if ((frame->frametype != AST_FRAME_VOICE) && + (frame->frametype != AST_FRAME_VIDEO) && + (frame->frametype != AST_FRAME_IMAGE)) { + return 0; + } + + /* BUGBUG - why not just get the codec pointer off the format? + This is a bit roundabout + */ + codec = ast_codec_get_by_id(ast_format_get_codec_id(frame->subclass.format)); + + if (codec->samples_count) { + samples = codec->samples_count(frame); + } else { + ast_log(LOG_WARNING, "Unable to calculate samples for codec %s\n", + ast_format_get_name(frame->subclass.format)); + } + + ao2_ref(codec, -1); + return samples; +} + +unsigned int ast_codec_determine_length(const struct ast_codec *codec, unsigned int samples) +{ + if (!codec->get_length) { + return 0; + } + + return codec->get_length(samples); +} diff --git a/main/codec_builtin.c b/main/codec_builtin.c new file mode 100644 index 000000000..594074aa4 --- /dev/null +++ b/main/codec_builtin.c @@ -0,0 +1,845 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Joshua Colp <jcolp@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Built-in supported codecs + * + * \author Joshua Colp <jcolp@digium.com> + */ + +/*** MODULEINFO + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/logger.h" +#include "asterisk/astobj2.h" +#include "asterisk/codec.h" +#include "asterisk/format.h" +#include "asterisk/format_cache.h" +#include "asterisk/frame.h" + +enum frame_type { + TYPE_HIGH, /* 0x0 */ + TYPE_LOW, /* 0x1 */ + TYPE_SILENCE, /* 0x2 */ + TYPE_DONTSEND /* 0x3 */ +}; + +#define TYPE_MASK 0x3 + +static int g723_len(unsigned char buf) +{ + enum frame_type type = buf & TYPE_MASK; + + switch(type) { + case TYPE_DONTSEND: + return 0; + break; + case TYPE_SILENCE: + return 4; + break; + case TYPE_HIGH: + return 24; + break; + case TYPE_LOW: + return 20; + break; + default: + ast_log(LOG_WARNING, "Badly encoded frame (%u)\n", type); + } + return -1; +} + +static int g723_samples(struct ast_frame *frame) +{ + unsigned char *buf = frame->data.ptr; + int pos = 0, samples = 0, res; + + while(pos < frame->datalen) { + res = g723_len(buf[pos]); + if (res <= 0) + break; + samples += 240; + pos += res; + } + + return samples; +} + +static int g723_length(unsigned int samples) +{ + return (samples / 240) * 20; +} + +static struct ast_codec g723 = { + .name = "g723", + .description = "G.723.1", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 30, + .maximum_ms = 300, + .default_ms = 30, + .minimum_bytes = 20, + .samples_count = g723_samples, + .get_length = g723_length, +}; + +static int none_samples(struct ast_frame *frame) +{ + return frame->datalen; +} + +static int none_length(unsigned int samples) { + return samples; +} + +static struct ast_codec none = { + .name = "none", + .description = "<Null> codec", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, /* This must have some sample rate to prevent divide by 0 */ + .minimum_ms = 10, + .maximum_ms = 150, + .default_ms = 20, + .minimum_bytes = 20, + .samples_count = none_samples, + .get_length = none_length, +}; + +static int ulaw_samples(struct ast_frame *frame) +{ + return frame->datalen; +} + +static int ulaw_length(unsigned int samples) +{ + return samples; +} + +static struct ast_codec ulaw = { + .name = "ulaw", + .description = "G.711 u-law", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 150, + .default_ms = 20, + .minimum_bytes = 80, + .samples_count = ulaw_samples, + .get_length = ulaw_length, + .smooth = 1, +}; + +static struct ast_codec alaw = { + .name = "alaw", + .description = "G.711 a-law", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 150, + .default_ms = 20, + .minimum_bytes = 80, + .samples_count = ulaw_samples, + .get_length = ulaw_length, + .smooth = 1, +}; + +static int gsm_samples(struct ast_frame *frame) +{ + return 160 * (frame->datalen / 33); +} + +static int gsm_length(unsigned int samples) +{ + return (samples / 160) * 33; +} + +static struct ast_codec gsm = { + .name = "gsm", + .description = "GSM", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 20, + .maximum_ms = 300, + .default_ms = 20, + .minimum_bytes = 33, + .samples_count = gsm_samples, + .get_length = gsm_length, + .smooth = 1, +}; + +static int g726_samples(struct ast_frame *frame) +{ + return frame->datalen * 2; +} + +static int g726_length(unsigned int samples) +{ + return samples / 2; +} + +static struct ast_codec g726rfc3551 = { + .name = "g726", + .description = "G.726 RFC3551", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 300, + .default_ms = 20, + .minimum_bytes = 40, + .samples_count = g726_samples, + .get_length = g726_length, + .smooth = 1, +}; + +static struct ast_codec g726aal2 = { + .name = "g726aal2", + .description = "G.726 AAL2", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 300, + .default_ms = 20, + .minimum_bytes = 40, + .samples_count = g726_samples, + .get_length = g726_length, + .smooth = 1, +}; + +static struct ast_codec adpcm = { + .name = "adpcm", + .description = "Dialogic ADPCM", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 300, + .default_ms = 20, + .minimum_bytes = 40, + .samples_count = g726_samples, + .get_length = g726_length, + .smooth = 1, +}; + +static int slin_samples(struct ast_frame *frame) +{ + return frame->datalen / 2; +} + +static int slin_length(unsigned int samples) +{ + return samples * 2; +} + +static struct ast_codec slin8 = { + .name = "slin", + .description = "16 bit Signed Linear PCM", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 70, + .default_ms = 20, + .minimum_bytes = 160, + .samples_count = slin_samples, + .get_length = slin_length, + .smooth = 1, +}; + +static struct ast_codec slin12 = { + .name = "slin", + .description = "16 bit Signed Linear PCM (12kHz)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 12000, + .minimum_ms = 10, + .maximum_ms = 70, + .default_ms = 20, + .minimum_bytes = 240, + .samples_count = slin_samples, + .get_length = slin_length, + .smooth = 1, +}; + +static struct ast_codec slin16 = { + .name = "slin", + .description = "16 bit Signed Linear PCM (16kHz)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + .minimum_ms = 10, + .maximum_ms = 70, + .default_ms = 20, + .minimum_bytes = 320, + .samples_count = slin_samples, + .get_length = slin_length, + .smooth = 1, +}; + +static struct ast_codec slin24 = { + .name = "slin", + .description = "16 bit Signed Linear PCM (24kHz)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 24000, + .minimum_ms = 10, + .maximum_ms = 70, + .default_ms = 20, + .minimum_bytes = 480, + .samples_count = slin_samples, + .get_length = slin_length, + .smooth = 1, +}; + +static struct ast_codec slin32 = { + .name = "slin", + .description = "16 bit Signed Linear PCM (32kHz)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 32000, + .minimum_ms = 10, + .maximum_ms = 70, + .default_ms = 20, + .minimum_bytes = 640, + .samples_count = slin_samples, + .get_length = slin_length, + .smooth = 1, +}; + +static struct ast_codec slin44 = { + .name = "slin", + .description = "16 bit Signed Linear PCM (44kHz)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 44100, + .minimum_ms = 10, + .maximum_ms = 70, + .default_ms = 20, + .minimum_bytes = 882, + .samples_count = slin_samples, + .get_length = slin_length, + .smooth = 1, +}; + +static struct ast_codec slin48 = { + .name = "slin", + .description = "16 bit Signed Linear PCM (48kHz)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 48000, + .minimum_ms = 10, + .maximum_ms = 70, + .default_ms = 20, + .minimum_bytes = 960, + .samples_count = slin_samples, + .get_length = slin_length, + .smooth = 1, +}; + +static struct ast_codec slin96 = { + .name = "slin", + .description = "16 bit Signed Linear PCM (96kHz)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 96000, + .minimum_ms = 10, + .maximum_ms = 70, + .default_ms = 20, + .minimum_bytes = 1920, + .samples_count = slin_samples, + .get_length = slin_length, + .smooth = 1, +}; + +static struct ast_codec slin192 = { + .name = "slin", + .description = "16 bit Signed Linear PCM (192kHz)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 192000, + .minimum_ms = 10, + .maximum_ms = 70, + .default_ms = 20, + .minimum_bytes = 3840, + .samples_count = slin_samples, + .get_length = slin_length, + .smooth = 1, +}; + +static int lpc10_samples(struct ast_frame *frame) +{ + int samples = 22 * 8; + + /* assumes that the RTP packet contains one LPC10 frame */ + samples += (((char *)(frame->data.ptr))[7] & 0x1) * 8; + + return samples; +} + +static struct ast_codec lpc10 = { + .name = "lpc10", + .description = "LPC10", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 20, + .maximum_ms = 20, + .default_ms = 20, + .minimum_bytes = 7, + .samples_count = lpc10_samples, + .smooth = 1, +}; + +static int g729_samples(struct ast_frame *frame) +{ + return frame->datalen * 8; +} + +static int g729_length(unsigned int samples) +{ + return samples / 8; +} + +static struct ast_codec g729a = { + .name = "g729", + .description = "G.729A", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 230, + .default_ms = 20, + .minimum_bytes = 10, + .samples_count = g729_samples, + .get_length = g729_length, + .smooth = 1, +}; + +static unsigned char get_n_bits_at(unsigned char *data, int n, int bit) +{ + int byte = bit / 8; /* byte containing first bit */ + int rem = 8 - (bit % 8); /* remaining bits in first byte */ + unsigned char ret = 0; + + if (n <= 0 || n > 8) + return 0; + + if (rem < n) { + ret = (data[byte] << (n - rem)); + ret |= (data[byte + 1] >> (8 - n + rem)); + } else { + ret = (data[byte] >> (rem - n)); + } + + return (ret & (0xff >> (8 - n))); +} + +static int speex_get_wb_sz_at(unsigned char *data, int len, int bit) +{ + static const int SpeexWBSubModeSz[] = { + 4, 36, 112, 192, + 352, 0, 0, 0 }; + int off = bit; + unsigned char c; + + /* skip up to two wideband frames */ + if (((len * 8 - off) >= 5) && + get_n_bits_at(data, 1, off)) { + c = get_n_bits_at(data, 3, off + 1); + off += SpeexWBSubModeSz[c]; + + if (((len * 8 - off) >= 5) && + get_n_bits_at(data, 1, off)) { + c = get_n_bits_at(data, 3, off + 1); + off += SpeexWBSubModeSz[c]; + + if (((len * 8 - off) >= 5) && + get_n_bits_at(data, 1, off)) { + ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n"); + return -1; + } + } + + } + return off - bit; +} + +static int speex_samples(unsigned char *data, int len) +{ + static const int SpeexSubModeSz[] = { + 5, 43, 119, 160, + 220, 300, 364, 492, + 79, 0, 0, 0, + 0, 0, 0, 0 }; + static const int SpeexInBandSz[] = { + 1, 1, 4, 4, + 4, 4, 4, 4, + 8, 8, 16, 16, + 32, 32, 64, 64 }; + int bit = 0; + int cnt = 0; + int off; + unsigned char c; + + while ((len * 8 - bit) >= 5) { + /* skip wideband frames */ + off = speex_get_wb_sz_at(data, len, bit); + if (off < 0) { + ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n"); + break; + } + bit += off; + + if ((len * 8 - bit) < 5) + break; + + /* get control bits */ + c = get_n_bits_at(data, 5, bit); + bit += 5; + + if (c == 15) { + /* terminator */ + break; + } else if (c == 14) { + /* in-band signal; next 4 bits contain signal id */ + c = get_n_bits_at(data, 4, bit); + bit += 4; + bit += SpeexInBandSz[c]; + } else if (c == 13) { + /* user in-band; next 4 bits contain msg len */ + c = get_n_bits_at(data, 4, bit); + bit += 4; + /* after which it's 5-bit signal id + c bytes of data */ + bit += 5 + c * 8; + } else if (c > 8) { + /* unknown */ + ast_log(LOG_WARNING, "Unknown speex control frame %d\n", c); + break; + } else { + /* skip number bits for submode (less the 5 control bits) */ + bit += SpeexSubModeSz[c] - 5; + cnt += 160; /* new frame */ + } + } + return cnt; +} + +static int speex8_samples(struct ast_frame *frame) +{ + return speex_samples(frame->data.ptr, frame->datalen); +} + +static struct ast_codec speex8 = { + .name = "speex", + .description = "SpeeX", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 60, + .default_ms = 20, + .minimum_bytes = 10, + .samples_count = speex8_samples, +}; + +static int speex16_samples(struct ast_frame *frame) +{ + return 2 * speex_samples(frame->data.ptr, frame->datalen); +} + +static struct ast_codec speex16 = { + .name = "speex", + .description = "SpeeX 16khz", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + .minimum_ms = 10, + .maximum_ms = 60, + .default_ms = 20, + .minimum_bytes = 10, + .samples_count = speex16_samples, +}; + +static int speex32_samples(struct ast_frame *frame) +{ + return 4 * speex_samples(frame->data.ptr, frame->datalen); +} + +static struct ast_codec speex32 = { + .name = "speex", + .description = "SpeeX 32khz", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 32000, + .minimum_ms = 10, + .maximum_ms = 60, + .default_ms = 20, + .minimum_bytes = 10, + .samples_count = speex32_samples, +}; + +static int ilbc_samples(struct ast_frame *frame) +{ + return 240 * (frame->datalen / 50); +} + +static struct ast_codec ilbc = { + .name = "ilbc", + .description = "iLBC", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 30, + .maximum_ms = 30, + .default_ms = 30, + .minimum_bytes = 50, + .samples_count = ilbc_samples, + .smooth = 1, +}; + +static struct ast_codec g722 = { + .name = "g722", + .description = "G722", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + .minimum_ms = 10, + .maximum_ms = 150, + .default_ms = 20, + .minimum_bytes = 80, + .samples_count = g726_samples, + .get_length = g726_length, + .smooth = 1, +}; + +static int siren7_samples(struct ast_frame *frame) +{ + return frame->datalen * (16000 / 4000); +} + +static int siren7_length(unsigned int samples) +{ + return samples / (16000 / 4000); +} + +static struct ast_codec siren7 = { + .name = "siren7", + .description = "ITU G.722.1 (Siren7, licensed from Polycom)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + .minimum_ms = 20, + .maximum_ms = 80, + .default_ms = 20, + .minimum_bytes = 80, + .samples_count = siren7_samples, + .get_length = siren7_length, +}; + +static int siren14_samples(struct ast_frame *frame) +{ + return (int) frame->datalen * ((float) 32000 / 6000); +} + +static int siren14_length(unsigned int samples) +{ + return (int) samples / ((float) 32000 / 6000);; +} + +static struct ast_codec siren14 = { + .name = "siren14", + .description = "ITU G.722.1 Annex C, (Siren14, licensed from Polycom)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 32000, + .minimum_ms = 20, + .maximum_ms = 80, + .default_ms = 20, + .minimum_bytes = 120, + .samples_count = siren14_samples, + .get_length = siren14_length, +}; + +static struct ast_codec testlaw = { + .name = "testlaw", + .description = "G.711 test-law", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 150, + .default_ms = 20, + .minimum_bytes = 80, + .samples_count = ulaw_samples, + .get_length = ulaw_length, + .smooth = 1, +}; + +static int g719_samples(struct ast_frame *frame) +{ + return (int) frame->datalen * ((float) 48000 / 8000); +} + +static int g719_length(unsigned int samples) +{ + return (int) samples / ((float) 48000 / 8000); +} + +static struct ast_codec g719 = { + .name = "g719", + .description = "ITU G.719", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 48000, + .minimum_ms = 20, + .maximum_ms = 80, + .default_ms = 20, + .minimum_bytes = 160, + .samples_count = g719_samples, + .get_length = g719_length, +}; + +static struct ast_codec opus = { + .name = "opus", + .description = "Opus Codec", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 48000, + .minimum_ms = 20, + .maximum_ms = 60, + .default_ms = 20, + .minimum_bytes = 10, +}; + +static struct ast_codec jpeg = { + .name = "jpeg", + .description = "JPEG image", + .type = AST_MEDIA_TYPE_IMAGE, +}; + +static struct ast_codec png = { + .name = "png", + .description = "PNG Image", + .type = AST_MEDIA_TYPE_IMAGE, +}; + +static struct ast_codec h261 = { + .name = "h261", + .description = "H.261 video", + .type = AST_MEDIA_TYPE_VIDEO, +}; + +static struct ast_codec h263 = { + .name = "h263", + .description = "H.263 video", + .type = AST_MEDIA_TYPE_VIDEO, +}; + +static struct ast_codec h263p = { + .name = "h263p", + .description = "H.263+ video", + .type = AST_MEDIA_TYPE_VIDEO, +}; + +static struct ast_codec h264 = { + .name = "h264", + .description = "H.264 video", + .type = AST_MEDIA_TYPE_VIDEO, +}; + +static struct ast_codec mpeg4 = { + .name = "mpeg4", + .description = "MPEG4 video", + .type = AST_MEDIA_TYPE_VIDEO, +}; + +static struct ast_codec vp8 = { + .name = "vp8", + .description = "VP8 video", + .type = AST_MEDIA_TYPE_VIDEO, +}; + +static struct ast_codec t140red = { + .name = "red", + .description = "T.140 Realtime Text with redundancy", + .type = AST_MEDIA_TYPE_TEXT, +}; + +static struct ast_codec t140 = { + .name = "t140", + .description = "Passthrough T.140 Realtime Text", + .type = AST_MEDIA_TYPE_TEXT, +}; + +#define CODEC_REGISTER_AND_CACHE(codec) \ + ({ \ + int __res_ ## __LINE__ = 0; \ + struct ast_format *__fmt_ ## __LINE__; \ + struct ast_codec *__codec_ ## __LINE__; \ + res |= __ast_codec_register(&(codec), NULL); \ + __codec_ ## __LINE__ = ast_codec_get((codec).name, (codec).type, (codec).sample_rate); \ + __fmt_ ## __LINE__ = ast_format_create(__codec_ ## __LINE__); \ + res |= ast_format_cache_set(__fmt_ ## __LINE__); \ + ao2_ref(__fmt_ ## __LINE__, -1); \ + ao2_ref(__codec_ ## __LINE__, -1); \ + __res_ ## __LINE__; \ + }) + +#define CODEC_REGISTER_AND_CACHE_NAMED(format_name, codec) \ + ({ \ + int __res_ ## __LINE__ = 0; \ + struct ast_format *__fmt_ ## __LINE__; \ + struct ast_codec *__codec_ ## __LINE__; \ + res |= __ast_codec_register(&(codec), NULL); \ + __codec_ ## __LINE__ = ast_codec_get((codec).name, (codec).type, (codec).sample_rate); \ + __fmt_ ## __LINE__ = ast_format_create_named((format_name), __codec_ ## __LINE__); \ + res |= ast_format_cache_set(__fmt_ ## __LINE__); \ + ao2_ref(__fmt_ ## __LINE__, -1); \ + ao2_ref(__codec_ ## __LINE__, -1); \ + __res_ ## __LINE__; \ + }) + +int ast_codec_builtin_init(void) +{ + int res = 0; + + res |= CODEC_REGISTER_AND_CACHE(g723); + res |= CODEC_REGISTER_AND_CACHE(ulaw); + res |= CODEC_REGISTER_AND_CACHE(alaw); + res |= CODEC_REGISTER_AND_CACHE(gsm); + res |= CODEC_REGISTER_AND_CACHE(g726rfc3551); + res |= CODEC_REGISTER_AND_CACHE(g726aal2); + res |= CODEC_REGISTER_AND_CACHE(adpcm); + res |= CODEC_REGISTER_AND_CACHE(slin8); + res |= CODEC_REGISTER_AND_CACHE_NAMED("slin12", slin12); + res |= CODEC_REGISTER_AND_CACHE_NAMED("slin16", slin16); + res |= CODEC_REGISTER_AND_CACHE_NAMED("slin24", slin24); + res |= CODEC_REGISTER_AND_CACHE_NAMED("slin32", slin32); + res |= CODEC_REGISTER_AND_CACHE_NAMED("slin44", slin44); + res |= CODEC_REGISTER_AND_CACHE_NAMED("slin48", slin48); + res |= CODEC_REGISTER_AND_CACHE_NAMED("slin96", slin96); + res |= CODEC_REGISTER_AND_CACHE_NAMED("slin192", slin192); + res |= CODEC_REGISTER_AND_CACHE(lpc10); + res |= CODEC_REGISTER_AND_CACHE(g729a); + res |= CODEC_REGISTER_AND_CACHE(speex8); + res |= CODEC_REGISTER_AND_CACHE_NAMED("speex16", speex16); + res |= CODEC_REGISTER_AND_CACHE_NAMED("speex32", speex32); + res |= CODEC_REGISTER_AND_CACHE(ilbc); + res |= CODEC_REGISTER_AND_CACHE(g722); + res |= CODEC_REGISTER_AND_CACHE(siren7); + res |= CODEC_REGISTER_AND_CACHE(siren14); + res |= CODEC_REGISTER_AND_CACHE(testlaw); + res |= CODEC_REGISTER_AND_CACHE(g719); + res |= CODEC_REGISTER_AND_CACHE(opus); + res |= CODEC_REGISTER_AND_CACHE(jpeg); + res |= CODEC_REGISTER_AND_CACHE(png); + res |= CODEC_REGISTER_AND_CACHE(h261); + res |= CODEC_REGISTER_AND_CACHE(h263); + res |= CODEC_REGISTER_AND_CACHE(h263p); + res |= CODEC_REGISTER_AND_CACHE(h264); + res |= CODEC_REGISTER_AND_CACHE(mpeg4); + res |= CODEC_REGISTER_AND_CACHE(vp8); + res |= CODEC_REGISTER_AND_CACHE(t140red); + res |= CODEC_REGISTER_AND_CACHE(t140); + res |= CODEC_REGISTER_AND_CACHE(none); + + return res; +} diff --git a/main/config_options.c b/main/config_options.c index ae40c6289..c86db0247 100644 --- a/main/config_options.c +++ b/main/config_options.c @@ -40,6 +40,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/xmldoc.h" #include "asterisk/cli.h" #include "asterisk/term.h" +#include "asterisk/format_cap.h" #ifdef LOW_MEMORY #define CONFIG_OPT_BUCKETS 5 @@ -1377,9 +1378,8 @@ static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var * enum aco_option_type in config_options.h */ static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) { - struct ast_codec_pref *pref = (struct ast_codec_pref *)(obj + opt->args[0]); - struct ast_format_cap **cap = (struct ast_format_cap **)(obj + opt->args[1]); - return ast_parse_allow_disallow(pref, *cap, var->value, opt->flags); + struct ast_format_cap **cap = (struct ast_format_cap **)(obj + opt->args[0]); + return ast_format_cap_update_by_allow_disallow(*cap, var->value, opt->flags); } /*! \brief Default option handler for stringfields diff --git a/main/core_local.c b/main/core_local.c index e803f29ec..e1b66d0a7 100644 --- a/main/core_local.c +++ b/main/core_local.c @@ -1008,7 +1008,8 @@ static void local_shutdown(void) ao2_ref(locals, -1); locals = NULL; - ast_format_cap_destroy(local_tech.capabilities); + ao2_cleanup(local_tech.capabilities); + local_tech.capabilities = NULL; STASIS_MESSAGE_TYPE_CLEANUP(ast_local_optimization_begin_type); STASIS_MESSAGE_TYPE_CLEANUP(ast_local_optimization_end_type); @@ -1030,14 +1031,15 @@ int ast_local_init(void) return -1; } - if (!(local_tech.capabilities = ast_format_cap_alloc(0))) { + if (!(local_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return -1; } - ast_format_cap_add_all(local_tech.capabilities); + ast_format_cap_append_by_type(local_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN); locals = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, locals_cmp_cb); if (!locals) { - ast_format_cap_destroy(local_tech.capabilities); + ao2_cleanup(local_tech.capabilities); + local_tech.capabilities = NULL; return -1; } @@ -1045,7 +1047,8 @@ int ast_local_init(void) if (ast_channel_register(&local_tech)) { ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); ao2_ref(locals, -1); - ast_format_cap_destroy(local_tech.capabilities); + ao2_cleanup(local_tech.capabilities); + local_tech.capabilities = NULL; return -1; } ast_cli_register_multiple(cli_local, ARRAY_LEN(cli_local)); diff --git a/main/core_unreal.c b/main/core_unreal.c index c9afa5194..a1ae897b9 100644 --- a/main/core_unreal.c +++ b/main/core_unreal.c @@ -859,7 +859,8 @@ void ast_unreal_destructor(void *vdoomed) { struct ast_unreal_pvt *doomed = vdoomed; - doomed->reqcap = ast_format_cap_destroy(doomed->reqcap); + ao2_cleanup(doomed->reqcap); + doomed->reqcap = NULL; } struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap) @@ -878,11 +879,13 @@ struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructo if (!unreal) { return NULL; } - unreal->reqcap = ast_format_cap_dup(cap); + + unreal->reqcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!unreal->reqcap) { ao2_ref(unreal, -1); return NULL; } + ast_format_cap_append_from_cap(unreal->reqcap, cap, AST_MEDIA_TYPE_UNKNOWN); memcpy(&unreal->jb_conf, &jb_conf, sizeof(unreal->jb_conf)); @@ -896,7 +899,7 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p, { struct ast_channel *owner; struct ast_channel *chan; - struct ast_format fmt; + RAII_VAR(struct ast_format *, fmt, NULL, ao2_cleanup); struct ast_assigned_ids id1 = {NULL, NULL}; struct ast_assigned_ids id2 = {NULL, NULL}; int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1); @@ -940,14 +943,22 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p, ao2_ref(p, +1); ast_channel_tech_pvt_set(owner, p); - ast_format_cap_copy(ast_channel_nativeformats(owner), p->reqcap); + ast_channel_nativeformats_set(owner, p->reqcap); /* Determine our read/write format and set it on each channel */ - ast_best_codec(p->reqcap, &fmt); - ast_format_copy(ast_channel_writeformat(owner), &fmt); - ast_format_copy(ast_channel_rawwriteformat(owner), &fmt); - ast_format_copy(ast_channel_readformat(owner), &fmt); - ast_format_copy(ast_channel_rawreadformat(owner), &fmt); + fmt = ast_format_cap_get_format(p->reqcap, 0); + if (!fmt) { + ast_channel_tech_pvt_set(owner, NULL); + ao2_ref(p, -1); + ast_channel_unlock(owner); + ast_channel_release(owner); + return NULL; + } + + ast_channel_set_writeformat(owner, fmt); + ast_channel_set_rawwriteformat(owner, fmt); + ast_channel_set_readformat(owner, fmt); + ast_channel_set_rawreadformat(owner, fmt); ast_set_flag(ast_channel_flags(owner), AST_FLAG_DISABLE_DEVSTATE_CACHE); @@ -955,6 +966,7 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p, if (ast_channel_cc_params_init(owner, requestor ? ast_channel_get_cc_config_params((struct ast_channel *) requestor) : NULL)) { + ast_channel_tech_pvt_set(owner, NULL); ao2_ref(p, -1); ast_channel_tech_pvt_set(owner, NULL); ast_channel_unlock(owner); @@ -970,6 +982,7 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p, "%s/%s-%08x;2", tech->type, p->name, (unsigned)generated_seqno); if (!chan) { ast_log(LOG_WARNING, "Unable to allocate chan channel structure\n"); + ast_channel_tech_pvt_set(owner, NULL); ao2_ref(p, -1); ast_channel_tech_pvt_set(owner, NULL); ast_channel_release(owner); @@ -984,13 +997,13 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p, ao2_ref(p, +1); ast_channel_tech_pvt_set(chan, p); - ast_format_cap_copy(ast_channel_nativeformats(chan), p->reqcap); + ast_channel_nativeformats_set(chan, p->reqcap); /* Format was already determined when setting up owner */ - ast_format_copy(ast_channel_writeformat(chan), &fmt); - ast_format_copy(ast_channel_rawwriteformat(chan), &fmt); - ast_format_copy(ast_channel_readformat(chan), &fmt); - ast_format_copy(ast_channel_rawreadformat(chan), &fmt); + ast_channel_set_writeformat(chan, fmt); + ast_channel_set_rawwriteformat(chan, fmt); + ast_channel_set_readformat(chan, fmt); + ast_channel_set_rawreadformat(chan, fmt); ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE); diff --git a/main/data.c b/main/data.c index 092d7aad5..746c52dfd 100644 --- a/main/data.c +++ b/main/data.c @@ -45,6 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/manager.h" #include "asterisk/test.h" #include "asterisk/frame.h" +#include "asterisk/codec.h" /*** DOCUMENTATION <manager name="DataGet" language="en_US"> @@ -3097,62 +3098,69 @@ static int manager_data_get(struct mansession *s, const struct message *m) return RESULT_SUCCESS; } +static int data_add_codec(struct ast_data *codecs, struct ast_format *format) { + struct ast_data *codec; + struct ast_codec *tmp; + + tmp = ast_codec_get_by_id(ast_format_get_codec_id(format)); + if (!tmp) { + return -1; + } + + codec = ast_data_add_node(codecs, "codec"); + if (!codec) { + ao2_ref(tmp, -1); + return -1; + } + + ast_data_add_str(codec, "name", tmp->name); + ast_data_add_int(codec, "samplespersecond", tmp->sample_rate); + ast_data_add_str(codec, "description", tmp->description); + ast_data_add_int(codec, "frame_length", tmp->minimum_bytes); + ao2_ref(tmp, -1); + + return 0; +} + int ast_data_add_codec(struct ast_data *root, const char *node_name, struct ast_format *format) { - struct ast_data *codecs, *codec; - size_t fmlist_size; - const struct ast_format_list *fmlist; - int x; + struct ast_data *codecs; codecs = ast_data_add_node(root, node_name); if (!codecs) { return -1; } - fmlist = ast_format_list_get(&fmlist_size); - for (x = 0; x < fmlist_size; x++) { - if (ast_format_cmp(&fmlist[x].format, format) == AST_FORMAT_CMP_EQUAL) { - codec = ast_data_add_node(codecs, "codec"); - if (!codec) { - ast_format_list_destroy(fmlist); - return -1; - } - ast_data_add_str(codec, "name", fmlist[x].name); - ast_data_add_int(codec, "samplespersecond", fmlist[x].samplespersecond); - ast_data_add_str(codec, "description", fmlist[x].desc); - ast_data_add_int(codec, "frame_length", fmlist[x].fr_len); - } - } - ast_format_list_destroy(fmlist); - return 0; + return data_add_codec(codecs, format); } int ast_data_add_codecs(struct ast_data *root, const char *node_name, struct ast_format_cap *cap) { - struct ast_data *codecs, *codec; - size_t fmlist_size; - const struct ast_format_list *fmlist; - int x; + struct ast_data *codecs; + size_t i; + size_t count; codecs = ast_data_add_node(root, node_name); if (!codecs) { return -1; } - fmlist = ast_format_list_get(&fmlist_size); - for (x = 0; x < fmlist_size; x++) { - if (ast_format_cap_iscompatible(cap, &fmlist[x].format)) { - codec = ast_data_add_node(codecs, "codec"); - if (!codec) { - ast_format_list_destroy(fmlist); - return -1; - } - ast_data_add_str(codec, "name", fmlist[x].name); - ast_data_add_int(codec, "samplespersecond", fmlist[x].samplespersecond); - ast_data_add_str(codec, "description", fmlist[x].desc); - ast_data_add_int(codec, "frame_length", fmlist[x].fr_len); + + count = ast_format_cap_count(cap); + for (i = 1; i <= count; ++i) { + struct ast_format *fmt; + + fmt = ast_format_cap_get_format(cap, i); + if (!fmt) { + return -1; } + + if (data_add_codec(codecs, fmt)) { + ao2_ref(fmt, -1); + return -1; + } + + ao2_ref(fmt, -1); } - ast_format_list_destroy(fmlist); return 0; } diff --git a/main/dial.c b/main/dial.c index f03d43d25..0955aad04 100644 --- a/main/dial.c +++ b/main/dial.c @@ -300,23 +300,23 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe /* Copy device string over */ ast_copy_string(numsubst, channel->device, sizeof(numsubst)); - if (!ast_format_cap_is_empty(cap)) { + if (ast_format_cap_count(cap)) { cap_request = cap; } else if (chan) { cap_request = ast_channel_nativeformats(chan); } else { - cap_all_audio = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - ast_format_cap_add_all_by_type(cap_all_audio, AST_FORMAT_TYPE_AUDIO); + cap_all_audio = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + ast_format_cap_append_by_type(cap_all_audio, AST_MEDIA_TYPE_AUDIO); cap_request = cap_all_audio; } /* If we fail to create our owner channel bail out */ if (!(channel->owner = ast_request(channel->tech, cap_request, &assignedids, chan, numsubst, &channel->cause))) { - cap_all_audio = ast_format_cap_destroy(cap_all_audio); + ao2_cleanup(cap_all_audio); return -1; } cap_request = NULL; - cap_all_audio = ast_format_cap_destroy(cap_all_audio); + ao2_cleanup(cap_all_audio); ast_channel_lock(channel->owner); ast_channel_stage_snapshot(channel->owner); diff --git a/main/dsp.c b/main/dsp.c index 747ff28e5..3a5d1221a 100644 --- a/main/dsp.c +++ b/main/dsp.c @@ -60,6 +60,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include <math.h> #include "asterisk/frame.h" +#include "asterisk/format_cache.h" #include "asterisk/channel.h" #include "asterisk/dsp.h" #include "asterisk/ulaw.h" @@ -1183,7 +1184,7 @@ int ast_dsp_call_progress(struct ast_dsp *dsp, struct ast_frame *inf) ast_log(LOG_WARNING, "Can't check call progress of non-voice frames\n"); return 0; } - if (!ast_format_is_slinear(&inf->subclass.format)) { + if (!ast_format_cache_is_slinear(inf->subclass.format)) { ast_log(LOG_WARNING, "Can only check call progress in signed-linear frames\n"); return 0; } @@ -1408,30 +1409,29 @@ static int ast_dsp_silence_noise_with_energy(struct ast_dsp *dsp, struct ast_fra ast_log(LOG_WARNING, "Can't calculate silence on a non-voice frame\n"); return 0; } - if (!ast_format_is_slinear(&f->subclass.format)) { + + if (ast_format_cache_is_slinear(f->subclass.format)) { + s = f->data.ptr; + len = f->datalen/2; + } else { odata = f->data.ptr; len = f->datalen; - switch (f->subclass.format.id) { - case AST_FORMAT_ULAW: - s = ast_alloca(len * 2); - for (x = 0; x < len; x++) { - s[x] = AST_MULAW(odata[x]); - } - break; - case AST_FORMAT_ALAW: - s = ast_alloca(len * 2); - for (x = 0; x < len; x++) { - s[x] = AST_ALAW(odata[x]); - } - break; - default: - ast_log(LOG_WARNING, "Can only calculate silence on signed-linear, alaw or ulaw frames :(\n"); + if (ast_format_cmp(f->subclass.format, ast_format_ulaw)) { + s = ast_alloca(len * 2); + for (x = 0; x < len; x++) { + s[x] = AST_MULAW(odata[x]); + } + } else if (ast_format_cmp(f->subclass.format, ast_format_alaw)) { + s = ast_alloca(len * 2); + for (x = 0; x < len; x++) { + s[x] = AST_ALAW(odata[x]); + } + } else { + ast_log(LOG_WARNING, "Can only calculate silence on signed-linear, alaw or ulaw frames :(\n"); return 0; } - } else { - s = f->data.ptr; - len = f->datalen/2; } + if (noise) { return __ast_dsp_silence_noise(dsp, s, len, NULL, total, frames_energy); } else { @@ -1476,31 +1476,26 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, odata = af->data.ptr; len = af->datalen; /* Make sure we have short data */ - if (ast_format_is_slinear(&af->subclass.format)) { + if (ast_format_cache_is_slinear(af->subclass.format)) { shortdata = af->data.ptr; len = af->datalen / 2; + } else if (ast_format_cmp(af->subclass.format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) { + shortdata = ast_alloca(af->datalen * 2); + for (x = 0; x < len; x++) { + shortdata[x] = AST_MULAW(odata[x]); + } + } else if (ast_format_cmp(af->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) { + shortdata = ast_alloca(af->datalen * 2); + for (x = 0; x < len; x++) { + shortdata[x] = AST_ALAW(odata[x]); + } } else { - switch (af->subclass.format.id) { - case AST_FORMAT_ULAW: - case AST_FORMAT_TESTLAW: - shortdata = ast_alloca(af->datalen * 2); - for (x = 0; x < len; x++) { - shortdata[x] = AST_MULAW(odata[x]); - } - break; - case AST_FORMAT_ALAW: - shortdata = ast_alloca(af->datalen * 2); - for (x = 0; x < len; x++) { - shortdata[x] = AST_ALAW(odata[x]); - } - break; - default: - /*Display warning only once. Otherwise you would get hundreds of warnings every second */ - if (dsp->display_inband_dtmf_warning) - ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(&af->subclass.format)); - dsp->display_inband_dtmf_warning = 0; - return af; + /*Display warning only once. Otherwise you would get hundreds of warnings every second */ + if (dsp->display_inband_dtmf_warning) { + ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_format_get_name(af->subclass.format)); } + dsp->display_inband_dtmf_warning = 0; + return af; } /* Initially we do not want to mute anything */ @@ -1629,19 +1624,14 @@ done: memset(shortdata + dsp->mute_data[x].start, 0, sizeof(int16_t) * (dsp->mute_data[x].end - dsp->mute_data[x].start)); } - switch (af->subclass.format.id) { - case AST_FORMAT_ULAW: + if (ast_format_cmp(af->subclass.format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) { for (x = 0; x < len; x++) { odata[x] = AST_LIN2MU((unsigned short) shortdata[x]); } - break; - case AST_FORMAT_ALAW: + } else if (ast_format_cmp(af->subclass.format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) { for (x = 0; x < len; x++) { odata[x] = AST_LIN2A((unsigned short) shortdata[x]); } - /* fall through */ - default: - break; } if (outf) { diff --git a/main/file.c b/main/file.c index df67fbf43..fa4c63bd9 100644 --- a/main/file.c +++ b/main/file.c @@ -189,8 +189,8 @@ int ast_stopstream(struct ast_channel *tmp) if (ast_channel_stream(tmp)) { ast_closestream(ast_channel_stream(tmp)); ast_channel_stream_set(tmp, NULL); - if (ast_channel_oldwriteformat(tmp)->id && ast_set_write_format(tmp, ast_channel_oldwriteformat(tmp))) - ast_log(LOG_WARNING, "Unable to restore format back to %s\n", ast_getformatname(ast_channel_oldwriteformat(tmp))); + if (ast_channel_oldwriteformat(tmp) && ast_set_write_format(tmp, ast_channel_oldwriteformat(tmp))) + ast_log(LOG_WARNING, "Unable to restore format back to %s\n", ast_format_get_name(ast_channel_oldwriteformat(tmp))); } /* Stop the video stream too */ if (ast_channel_vstream(tmp) != NULL) { @@ -207,10 +207,10 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f) { int res = -1; if (f->frametype == AST_FRAME_VIDEO) { - if (AST_FORMAT_GET_TYPE(fs->fmt->format.id) == AST_FORMAT_TYPE_AUDIO) { + if (ast_format_get_type(fs->fmt->format) == AST_MEDIA_TYPE_AUDIO) { /* This is the audio portion. Call the video one... */ if (!fs->vfs && fs->filename) { - const char *type = ast_getformatname(&f->subclass.format); + const char *type = ast_format_get_name(f->subclass.format); fs->vfs = ast_writefile(fs->filename, type, NULL, fs->flags, 0, fs->mode); ast_debug(1, "Opened video output file\n"); } @@ -223,7 +223,7 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f) ast_log(LOG_WARNING, "Tried to write non-voice frame\n"); return -1; } - if (ast_format_cmp(&f->subclass.format, &fs->fmt->format) != AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_cmp(f->subclass.format, fs->fmt->format) != AST_FORMAT_CMP_NOT_EQUAL) { res = fs->fmt->write(fs, f); if (res < 0) ast_log(LOG_WARNING, "Natural write failed\n"); @@ -232,18 +232,19 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f) } else { /* XXX If they try to send us a type of frame that isn't the normal frame, and isn't the one we've setup a translator for, we do the "wrong thing" XXX */ - if (fs->trans && (ast_format_cmp(&f->subclass.format, &fs->lastwriteformat) != AST_FORMAT_CMP_EQUAL)) { + if (fs->trans && (ast_format_cmp(f->subclass.format, fs->lastwriteformat) != AST_FORMAT_CMP_EQUAL)) { ast_translator_free_path(fs->trans); fs->trans = NULL; } - if (!fs->trans) - fs->trans = ast_translator_build_path(&fs->fmt->format, &f->subclass.format); - if (!fs->trans) + if (!fs->trans) { + fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass.format); + } + if (!fs->trans) { ast_log(LOG_WARNING, "Unable to translate to format %s, source format %s\n", - fs->fmt->name, ast_getformatname(&f->subclass.format)); - else { + fs->fmt->name, ast_format_get_name(f->subclass.format)); + } else { struct ast_frame *trf; - ast_format_copy(&fs->lastwriteformat, &f->subclass.format); + ao2_replace(fs->lastwriteformat, f->subclass.format); /* Get the translated frame but don't consume the original in case they're using it on another stream */ if ((trf = ast_translate(fs->trans, f, 0))) { struct ast_frame *cur; @@ -349,7 +350,7 @@ static int exts_compare(const char *exts, const char *type) */ static void filestream_close(struct ast_filestream *f) { - enum ast_format_type format_type = AST_FORMAT_GET_TYPE(f->fmt->format.id); + enum ast_media_type format_type = ast_format_get_type(f->fmt->format); if (!f->owner) { return; @@ -358,12 +359,12 @@ static void filestream_close(struct ast_filestream *f) /* Stop a running stream if there is one */ switch (format_type) { - case AST_FORMAT_TYPE_AUDIO: + case AST_MEDIA_TYPE_AUDIO: ast_channel_stream_set(f->owner, NULL); AST_SCHED_DEL_ACCESSOR(ast_channel_sched(f->owner), f->owner, ast_channel_streamid, ast_channel_streamid_set); ast_settimeout(f->owner, 0, NULL, NULL); break; - case AST_FORMAT_TYPE_VIDEO: + case AST_MEDIA_TYPE_VIDEO: ast_channel_vstream_set(f->owner, NULL); AST_SCHED_DEL_ACCESSOR(ast_channel_sched(f->owner), f->owner, ast_channel_vstreamid, ast_channel_vstreamid_set); break; @@ -418,6 +419,8 @@ static void filestream_destructor(void *arg) } if (f->orig_chan_name) free((void *) f->orig_chan_name); + ao2_cleanup(f->lastwriteformat); + ao2_cleanup(f->fr.subclass.format); ast_module_unref(f->fmt->module); } @@ -436,6 +439,15 @@ static struct ast_filestream *get_filestream(struct ast_format_def *fmt, FILE *b if (fmt->buf_size) s->buf = (char *)(s + 1); s->fr.src = fmt->name; + + if (ast_format_get_type(fmt->format) == AST_MEDIA_TYPE_AUDIO) { + s->fr.frametype = AST_FRAME_VOICE; + } else if (ast_format_get_type(fmt->format) == AST_MEDIA_TYPE_VIDEO) { + s->fr.frametype = AST_FRAME_VIDEO; + } + s->fr.mallocd = 0; + s->fr.subclass.format = ao2_bump(fmt->format); + return s; } @@ -529,9 +541,9 @@ static int filehelper(const char *filename, const void *arg2, const char *fmt, c FILE *bfile; struct ast_filestream *s; - if ((ast_format_cmp(ast_channel_writeformat(chan), &f->format) == AST_FORMAT_CMP_NOT_EQUAL) && - !(((AST_FORMAT_GET_TYPE(f->format.id) == AST_FORMAT_TYPE_AUDIO) && fmt) || - ((AST_FORMAT_GET_TYPE(f->format.id) == AST_FORMAT_TYPE_VIDEO) && fmt))) { + if ((ast_format_cmp(ast_channel_writeformat(chan), f->format) == AST_FORMAT_CMP_NOT_EQUAL) && + !(((ast_format_get_type(f->format) == AST_MEDIA_TYPE_AUDIO) && fmt) || + ((ast_format_get_type(f->format) == AST_MEDIA_TYPE_VIDEO) && fmt))) { ast_free(fn); continue; /* not a supported format */ } @@ -559,7 +571,7 @@ static int filehelper(const char *filename, const void *arg2, const char *fmt, c s->fmt = f; s->trans = NULL; s->filename = NULL; - if (AST_FORMAT_GET_TYPE(s->fmt->format.id) == AST_FORMAT_TYPE_AUDIO) { + if (ast_format_get_type(s->fmt->format) == AST_MEDIA_TYPE_AUDIO) { if (ast_channel_stream(chan)) ast_closestream(ast_channel_stream(chan)); ast_channel_stream_set(chan, s); @@ -579,7 +591,7 @@ static int filehelper(const char *filename, const void *arg2, const char *fmt, c /* if arg2 is present, it is a format capabilities structure. * Add this format to the set of formats this file can be played in */ if (arg2) { - ast_format_cap_add((struct ast_format_cap *) arg2, &f->format); + ast_format_cap_append((struct ast_format_cap *) arg2, f->format, 0); } res = 1; /* file does exist and format it exists in is returned in arg2 */ break; @@ -749,23 +761,23 @@ struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char buflen = strlen(preflang) + strlen(filename) + 4; buf = ast_alloca(buflen); - if (!(file_fmt_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) { + if (!(file_fmt_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return NULL; } if (!fileexists_core(filename, NULL, preflang, buf, buflen, file_fmt_cap) || - !ast_format_cap_has_type(file_fmt_cap, AST_FORMAT_TYPE_AUDIO)) { + !ast_format_cap_has_type(file_fmt_cap, AST_MEDIA_TYPE_AUDIO)) { ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename); - file_fmt_cap = ast_format_cap_destroy(file_fmt_cap); + ao2_ref(file_fmt_cap, -1); return NULL; } /* Set the channel to a format we can work with and save off the previous format. */ - ast_format_copy(ast_channel_oldwriteformat(chan), ast_channel_writeformat(chan)); + ast_channel_set_oldwriteformat(chan, ast_channel_writeformat(chan)); /* Set the channel to the best format that exists for the file. */ res = ast_set_write_format_from_cap(chan, file_fmt_cap); /* don't need this anymore now that the channel's write format is set. */ - file_fmt_cap = ast_format_cap_destroy(file_fmt_cap); + ao2_ref(file_fmt_cap, -1); if (res == -1) { /* No format available that works with this channel */ return NULL; @@ -781,50 +793,50 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil /* As above, but for video. But here we don't have translators * so we must enforce a format. */ - struct ast_format tmp_fmt; struct ast_format_cap *tmp_cap; char *buf; int buflen; - const char *fmt; - int fd; + int i, fd; - if (preflang == NULL) + if (preflang == NULL) { preflang = ""; + } buflen = strlen(preflang) + strlen(filename) + 4; buf = ast_alloca(buflen); /* is the channel capable of video without translation ?*/ - if (!ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_FORMAT_TYPE_VIDEO)) { + if (!ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_VIDEO)) { return NULL; } - if (!(tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) { + if (!(tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return NULL; } /* Video is supported, so see what video formats exist for this file */ if (!fileexists_core(filename, NULL, preflang, buf, buflen, tmp_cap)) { - tmp_cap = ast_format_cap_destroy(tmp_cap); + ao2_ref(tmp_cap, -1); return NULL; } /* iterate over file formats and pick the first one compatible with the channel's native formats */ - ast_format_cap_iter_start(tmp_cap); - while (!ast_format_cap_iter_next(tmp_cap, &tmp_fmt)) { - fmt = ast_getformatname(&tmp_fmt); - if ((AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_VIDEO) || - !ast_format_cap_iscompatible(ast_channel_nativeformats(chan), &tmp_fmt)) { + for (i = 0; i < ast_format_cap_count(tmp_cap); ++i) { + struct ast_format *format = ast_format_cap_get_format(tmp_cap, i); + + if ((ast_format_get_type(format) != AST_MEDIA_TYPE_VIDEO) || + !ast_format_cap_iscompatible(ast_channel_nativeformats(chan), tmp_cap)) { + ao2_ref(format, -1); continue; } - fd = filehelper(buf, chan, fmt, ACTION_OPEN); + fd = filehelper(buf, chan, ast_format_get_name(format), ACTION_OPEN); if (fd >= 0) { - ast_format_cap_iter_end(tmp_cap); - tmp_cap = ast_format_cap_destroy(tmp_cap); + ao2_ref(format, -1); + ao2_ref(tmp_cap, -1); return ast_channel_vstream(chan); } ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename); + ao2_ref(format, -1); } - ast_format_cap_iter_end(tmp_cap); - tmp_cap = ast_format_cap_destroy(tmp_cap); + ao2_ref(tmp_cap, -1); return NULL; } @@ -897,14 +909,14 @@ static enum fsread_res ast_readaudio_callback(struct ast_filestream *s) if (whennext != s->lasttimeout) { if (ast_channel_timingfd(s->owner) > -1) { - float samp_rate = (float) ast_format_rate(&s->fmt->format); + float samp_rate = (float) ast_format_get_sample_rate(s->fmt->format); unsigned int rate; rate = (unsigned int) roundf(samp_rate / ((float) whennext)); ast_settimeout_full(s->owner, rate, ast_fsread_audio, s, 1); } else { - ast_channel_streamid_set(s->owner, ast_sched_add(ast_channel_sched(s->owner), whennext / (ast_format_rate(&s->fmt->format) / 1000), ast_fsread_audio, s)); + ast_channel_streamid_set(s->owner, ast_sched_add(ast_channel_sched(s->owner), whennext / (ast_format_get_sample_rate(s->fmt->format) / 1000), ast_fsread_audio, s)); } s->lasttimeout = whennext; return FSREAD_SUCCESS_NOSCHED; @@ -954,7 +966,7 @@ static enum fsread_res ast_readvideo_callback(struct ast_filestream *s) } if (whennext != s->lasttimeout) { - ast_channel_vstreamid_set(s->owner, ast_sched_add(ast_channel_sched(s->owner), whennext / (ast_format_rate(&s->fmt->format) / 1000), ast_fsread_video, s)); + ast_channel_vstreamid_set(s->owner, ast_sched_add(ast_channel_sched(s->owner), whennext / (ast_format_get_sample_rate(s->fmt->format) / 1000), ast_fsread_video, s)); s->lasttimeout = whennext; return FSREAD_SUCCESS_NOSCHED; } @@ -985,7 +997,7 @@ int ast_playstream(struct ast_filestream *s) { enum fsread_res res; - if (AST_FORMAT_GET_TYPE(s->fmt->format.id) == AST_FORMAT_TYPE_AUDIO) + if (ast_format_get_type(s->fmt->format) == AST_MEDIA_TYPE_AUDIO) res = ast_readaudio_callback(s); else res = ast_readvideo_callback(s); @@ -1067,14 +1079,15 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p { struct ast_filestream *fs; struct ast_filestream *vfs=NULL; - char fmt[256]; off_t pos; int seekattempt; int res; fs = ast_openstream(chan, filename, preflang); if (!fs) { - ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname_multiple(fmt, sizeof(fmt), ast_channel_nativeformats(chan)), strerror(errno)); + struct ast_str *codec_buf = ast_str_alloca(64); + ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", + filename, ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf), strerror(errno)); return -1; } @@ -1096,7 +1109,7 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p vfs = ast_openvstream(chan, filename, preflang); if (vfs) { - ast_debug(1, "Ooh, found a video stream, too, format %s\n", ast_getformatname(&vfs->fmt->format)); + ast_debug(1, "Ooh, found a video stream, too, format %s\n", ast_format_get_name(vfs->fmt->format)); } if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_MASQ_NOSTREAM)) @@ -1108,7 +1121,7 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p res = ast_playstream(fs); if (!res && vfs) res = ast_playstream(vfs); - ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", ast_channel_name(chan), filename, ast_getformatname(ast_channel_writeformat(chan)), preflang ? preflang : "default"); + ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", ast_channel_name(chan), filename, ast_format_get_name(ast_channel_writeformat(chan)), preflang ? preflang : "default"); return res; } @@ -1330,7 +1343,7 @@ static void waitstream_control(struct ast_channel *c, } if (cb) { - long ms_len = ast_tellstream(ast_channel_stream(c)) / (ast_format_rate(&ast_channel_stream(c)->fmt->format) / 1000); + long ms_len = ast_tellstream(ast_channel_stream(c)) / (ast_format_get_sample_rate(ast_channel_stream(c)->fmt->format) / 1000); cb(c, ms_len, type); } @@ -1373,7 +1386,7 @@ static int waitstream_core(struct ast_channel *c, orig_chan_name = ast_strdupa(ast_channel_name(c)); if (ast_channel_stream(c) && cb) { - long ms_len = ast_tellstream(ast_channel_stream(c)) / (ast_format_rate(&ast_channel_stream(c)->fmt->format) / 1000); + long ms_len = ast_tellstream(ast_channel_stream(c)) / (ast_format_get_sample_rate(ast_channel_stream(c)->fmt->format) / 1000); cb(c, ms_len, AST_WAITSTREAM_CB_START); } @@ -1722,7 +1735,7 @@ static char *handle_cli_core_show_file_formats(struct ast_cli_entry *e, int cmd, AST_RWLIST_RDLOCK(&formats); AST_RWLIST_TRAVERSE(&formats, f, list) { - ast_cli(a->fd, FORMAT2, ast_getformatname(&f->format), f->name, f->exts); + ast_cli(a->fd, FORMAT2, ast_format_get_name(f->format), f->name, f->exts); count_fmt++; } AST_RWLIST_UNLOCK(&formats); @@ -1732,13 +1745,13 @@ static char *handle_cli_core_show_file_formats(struct ast_cli_entry *e, int cmd, #undef FORMAT2 } -const struct ast_format *ast_get_format_for_file_ext(const char *file_ext) +struct ast_format *ast_get_format_for_file_ext(const char *file_ext) { struct ast_format_def *f; SCOPED_RDLOCK(lock, &formats.lock); AST_RWLIST_TRAVERSE(&formats, f, list) { if (exts_compare(f->exts, file_ext)) { - return &f->format; + return f->format; } } diff --git a/main/format.c b/main/format.c index c4ad45b7f..83206f28c 100644 --- a/main/format.c +++ b/main/format.c @@ -1,10 +1,9 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 2010, Digium, Inc. + * Copyright (C) 2014, Digium, Inc. * - * David Vossel <dvossel@digium.com> - * Mark Spencer <markster@digium.com> + * Joshua Colp <jcolp@digium.com> * * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact @@ -17,12 +16,11 @@ * at the top of the source tree. */ -/*! - * \file - * \brief Format API +/*! \file * - * \author David Vossel <dvossel@digium.com> - * \author Mark Spencer <markster@digium.com> + * \brief Media Format API + * + * \author Joshua Colp <jcolp@digium.com> */ /*** MODULEINFO @@ -31,1420 +29,351 @@ #include "asterisk.h" -ASTERISK_FILE_VERSION(__FILE__, "$Revision$"); +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") -#include "asterisk/_private.h" +#include "asterisk/logger.h" +#include "asterisk/codec.h" #include "asterisk/format.h" #include "asterisk/astobj2.h" -#include "asterisk/lock.h" -#include "asterisk/frame.h" -#include "asterisk/utils.h" -#include "asterisk/cli.h" -#include "asterisk/rtp_engine.h" -#include "asterisk/config.h" - -#define FORMAT_CONFIG "codecs.conf" - -/*! - * \brief Container for all the format attribute interfaces. - * \note This container uses RWLOCKs instead of MUTEX locks. . - * \note An ao2 container was chosen for fast lookup. - */ -static struct ao2_container *interfaces; - -/*! a wrapper is used put interfaces into the ao2 container. */ -struct interface_ao2_wrapper { - enum ast_format_id id; - const struct ast_format_attr_interface *interface; +#include "asterisk/strings.h" + +/*! \brief Number of buckets to use for format interfaces (should be prime for performance reasons) */ +#define FORMAT_INTERFACE_BUCKETS 53 + +/*! \brief Definition of a media format */ +struct ast_format { + /*! Name of the format */ + const char *name; + /*! \brief Pointer to the codec in use for this format */ + struct ast_codec *codec; + /*! \brief Attribute specific data, implementation specific */ + void *attribute_data; + /*! \brief Pointer to the optional format interface */ + const struct ast_format_interface *interface; }; -/*! \brief Format List container, This container is never directly accessed outside - * of this file, and It only exists for building the format_list_array. */ -static struct ao2_container *format_list; -/*! \brief Format List array is a read only array protected by a read write lock. - * This array may be used outside this file with the use of reference counting to - * guarantee safety for access by multiple threads. */ -static struct ast_format_list *format_list_array; -static size_t format_list_array_len = 0; -/*! \brief Locks the format list array so a reference can be taken safely. */ -static ast_rwlock_t format_list_array_lock; - -static int interface_cmp_cb(void *obj, void *arg, int flags) -{ - struct interface_ao2_wrapper *wrapper1 = obj; - struct interface_ao2_wrapper *wrapper2 = arg; - - return (wrapper2->id == wrapper1->id) ? CMP_MATCH | CMP_STOP : 0; -} - -static int interface_hash_cb(const void *obj, const int flags) -{ - const struct interface_ao2_wrapper *wrapper = obj; - return wrapper->id; -} - -void ast_format_copy(struct ast_format *dst, const struct ast_format *src) -{ - *dst = *src; -} - -void ast_format_set_video_mark(struct ast_format *format) -{ - format->fattr.rtp_marker_bit = 1; -} - -int ast_format_get_video_mark(const struct ast_format *format) -{ - return format->fattr.rtp_marker_bit; -} - -static struct interface_ao2_wrapper *find_interface(const struct ast_format *format) -{ - struct interface_ao2_wrapper tmp_wrapper = { - .id = format->id, - }; +/*! \brief Structure used when registering a format interface */ +struct format_interface { + /*! \brief Pointer to the format interface itself */ + const struct ast_format_interface *interface; + /*! \brief Name of the codec the interface is for */ + char codec[0]; +}; - return ao2_find(interfaces, &tmp_wrapper, OBJ_POINTER); -} +/*! \brief Container for registered format interfaces */ +static struct ao2_container *interfaces; -static int has_interface(const struct ast_format *format) +static int format_interface_hash(const void *obj, int flags) { - struct interface_ao2_wrapper *wrapper; + const struct format_interface *format_interface; + const char *key; - wrapper = find_interface(format); - if (!wrapper) { + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_KEY: + key = obj; + return ast_str_hash(key); + case OBJ_SEARCH_OBJECT: + format_interface = obj; + return ast_str_hash(format_interface->codec); + default: + /* Hash can only work on something with a full key. */ + ast_assert(0); return 0; } - ao2_ref(wrapper, -1); - return 1; } -int ast_format_sdp_parse(struct ast_format *format, const char *attributes) +static int format_interface_cmp(void *obj, void *arg, int flags) { - struct interface_ao2_wrapper *wrapper; - int res; + const struct format_interface *left = obj; + const struct format_interface *right = arg; + const char *right_key = arg; + int cmp; - if (!(wrapper = find_interface(format))) { - return 0; + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + cmp = strcmp(left->codec, right->codec); + break; + case OBJ_SEARCH_KEY: + cmp = strcmp(left->codec, right_key); + break; + case OBJ_SEARCH_PARTIAL_KEY: + cmp = strncmp(left->codec, right_key, strlen(right_key)); + break; + default: + ast_assert(0); + cmp = 0; + break; } - - ao2_rdlock(wrapper); - if (!wrapper->interface || !wrapper->interface->format_attr_sdp_parse) { - ao2_unlock(wrapper); - ao2_ref(wrapper, -1); + if (cmp) { return 0; } - res = wrapper->interface->format_attr_sdp_parse(&format->fattr, attributes); - - ao2_unlock(wrapper); - ao2_ref(wrapper, -1); - - return res; + return CMP_MATCH; } -void ast_format_sdp_generate(const struct ast_format *format, unsigned int payload, struct ast_str **str) +/*! \brief Function called when the process is shutting down */ +static void format_shutdown(void) { - struct interface_ao2_wrapper *wrapper; - - if (!(wrapper = find_interface(format))) { - return; - } - - ao2_rdlock(wrapper); - if (!wrapper->interface || !wrapper->interface->format_attr_sdp_generate) { - ao2_unlock(wrapper); - ao2_ref(wrapper, -1); - return; - } - - wrapper->interface->format_attr_sdp_generate(&format->fattr, payload, str); - - ao2_unlock(wrapper); - ao2_ref(wrapper, -1); + ao2_cleanup(interfaces); + interfaces = NULL; } -/*! \internal - * \brief set format attributes using an interface - */ -static int format_set_helper(struct ast_format *format, va_list ap) +int ast_format_init(void) { - struct interface_ao2_wrapper *wrapper; - - if (!(wrapper = find_interface(format))) { - ast_log(LOG_WARNING, "Could not find format interface to set.\n"); - return -1; - } - - ao2_rdlock(wrapper); - if (!wrapper->interface || !wrapper->interface->format_attr_set) { - ao2_unlock(wrapper); - ao2_ref(wrapper, -1); + interfaces = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, FORMAT_INTERFACE_BUCKETS, format_interface_hash, + format_interface_cmp); + if (!interfaces) { return -1; } - wrapper->interface->format_attr_set(&format->fattr, ap); - - ao2_unlock(wrapper); - ao2_ref(wrapper, -1); + ast_register_atexit(format_shutdown); return 0; } -struct ast_format *ast_format_append(struct ast_format *format, ... ) -{ - va_list ap; - va_start(ap, format); - format_set_helper(format, ap); - va_end(ap); - - return format; -} - -struct ast_format *ast_format_set(struct ast_format *format, enum ast_format_id id, int set_attributes, ... ) +int __ast_format_interface_register(const char *codec, const struct ast_format_interface *interface, struct ast_module *mod) { - /* initialize the structure before setting it. */ - ast_format_clear(format); - - format->id = id; + SCOPED_AO2WRLOCK(lock, interfaces); + struct format_interface *format_interface; - if (set_attributes) { - va_list ap; - va_start(ap, set_attributes); - format_set_helper(format, ap); - va_end(ap); + if (!interface->format_clone || !interface->format_destroy) { + ast_log(LOG_ERROR, "Format interface for codec '%s' does not implement required callbacks\n", codec); + return -1; } - return format; -} - -void ast_format_clear(struct ast_format *format) -{ - format->id = 0; - memset(&format->fattr, 0, sizeof(format->fattr)); -} - -/*! \internal - * \brief determine if a list of attribute key value pairs are set on a format - */ -static int format_isset_helper(const struct ast_format *format, va_list ap) -{ - int res; - struct interface_ao2_wrapper *wrapper; - struct ast_format tmp = { - .id = format->id, - .fattr = { { 0, }, }, - }; - - if (!(wrapper = find_interface(format))) { + format_interface = ao2_find(interfaces, codec, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (format_interface) { + ast_log(LOG_ERROR, "A format interface is already present for codec '%s'\n", codec); + ao2_ref(format_interface, -1); return -1; } - ao2_rdlock(wrapper); - if (!wrapper->interface || - !wrapper->interface->format_attr_set || - !wrapper->interface->format_attr_cmp) { - - ao2_unlock(wrapper); - ao2_ref(wrapper, -1); + format_interface = ao2_alloc_options(sizeof(*format_interface) + strlen(codec) + 1, + NULL, AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!format_interface) { return -1; } + format_interface->interface = interface; + strcpy(format_interface->codec, codec); /* Safe */ - /* if isset is present, use that function, else just build a new - * format and use the cmp function */ - if (wrapper->interface->format_attr_isset) { - res = wrapper->interface->format_attr_isset(&format->fattr, ap); - } else { - wrapper->interface->format_attr_set(&tmp.fattr, ap); - /* use our tmp structure to tell if the attributes are set or not */ - res = wrapper->interface->format_attr_cmp(&tmp.fattr, &format->fattr); - res = (res == AST_FORMAT_CMP_NOT_EQUAL) ? -1 : 0; - } + ao2_link_flags(interfaces, format_interface, OBJ_NOLOCK); + ao2_ref(format_interface, -1); - ao2_unlock(wrapper); - ao2_ref(wrapper, -1); + ast_verb(2, "Registered format interface for codec '%s'\n", codec); - return res; + return 0; } -int ast_format_isset(const struct ast_format *format, ... ) +void *ast_format_get_attribute_data(const struct ast_format *format) { - va_list ap; - int res; - - va_start(ap, format); - res = format_isset_helper(format, ap); - va_end(ap); - return res; + return format->attribute_data; } -int ast_format_get_value(const struct ast_format *format, int key, void *value) +void ast_format_set_attribute_data(struct ast_format *format, void *attribute_data) { - int res = 0; - struct interface_ao2_wrapper *wrapper; - - if (!(wrapper = find_interface(format))) { - return -1; - } - ao2_rdlock(wrapper); - if (!wrapper->interface || - !wrapper->interface->format_attr_get_val) { - - ao2_unlock(wrapper); - ao2_ref(wrapper, -1); - return -1; - } - - res = wrapper->interface->format_attr_get_val(&format->fattr, key, value); - - ao2_unlock(wrapper); - ao2_ref(wrapper, -1); - - return res; + format->attribute_data = attribute_data; } -/*! \internal - * \brief cmp format attributes using an interface - */ -static enum ast_format_cmp_res format_cmp_helper(const struct ast_format *format1, const struct ast_format *format2) +/*! \brief Destructor for media formats */ +static void format_destroy(void *obj) { - enum ast_format_cmp_res res = AST_FORMAT_CMP_EQUAL; - struct interface_ao2_wrapper *wrapper; + struct ast_format *format = obj; - if (!(wrapper = find_interface(format1))) { - return res; + if (format->interface) { + format->interface->format_destroy(format); } - ao2_rdlock(wrapper); - if (!wrapper->interface || !wrapper->interface->format_attr_cmp) { - ao2_unlock(wrapper); - ao2_ref(wrapper, -1); - return res; - } - - res = wrapper->interface->format_attr_cmp(&format1->fattr, &format2->fattr); - - ao2_unlock(wrapper); - ao2_ref(wrapper, -1); - - return res; + ao2_cleanup(format->codec); } -enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2) +struct ast_format *ast_format_create_named(const char *format_name, struct ast_codec *codec) { - if (format1->id != format2->id) { - return AST_FORMAT_CMP_NOT_EQUAL; - } - - return format_cmp_helper(format1, format2); -} + struct ast_format *format; + struct format_interface *format_interface; -/*! \internal - * \brief get joint format attributes using an interface - */ -static int format_joint_helper(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result) -{ - int res = 0; - struct interface_ao2_wrapper *wrapper; - - if (!(wrapper = find_interface(format1))) { - /* if no interface is present, we assume formats are joint by id alone */ - return res; + format = ao2_t_alloc_options(sizeof(*format), format_destroy, + AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(codec->description, "")); + if (!format) { + return NULL; } + format->name = format_name; + format->codec = ao2_bump(codec); - ao2_rdlock(wrapper); - if (wrapper->interface && wrapper->interface->format_attr_get_joint) { - res = wrapper->interface->format_attr_get_joint(&format1->fattr, &format2->fattr, &result->fattr); + format_interface = ao2_find(interfaces, codec->name, OBJ_SEARCH_KEY); + if (format_interface) { + format->interface = format_interface->interface; + ao2_ref(format_interface, -1); } - ao2_unlock(wrapper); - - ao2_ref(wrapper, -1); - return res; + return format; } -int ast_format_joint(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result) +struct ast_format *ast_format_clone(const struct ast_format *format) { - if (format1->id != format2->id) { - return -1; - } - result->id = format1->id; - return format_joint_helper(format1, format2, result); -} + struct ast_format *cloned = ast_format_create_named(format->name, format->codec); - -uint64_t ast_format_id_to_old_bitfield(enum ast_format_id id) -{ - switch (id) { - /*! G.723.1 compression */ - case AST_FORMAT_G723_1: - return (1ULL << 0); - /*! GSM compression */ - case AST_FORMAT_GSM: - return (1ULL << 1); - /*! Raw mu-law data (G.711) */ - case AST_FORMAT_ULAW: - return (1ULL << 2); - /*! Raw A-law data (G.711) */ - case AST_FORMAT_ALAW: - return (1ULL << 3); - /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */ - case AST_FORMAT_G726_AAL2: - return (1ULL << 4); - /*! ADPCM (IMA) */ - case AST_FORMAT_ADPCM: - return (1ULL << 5); - /*! Raw 16-bit Signed Linear (8000 Hz) PCM */ - case AST_FORMAT_SLINEAR: - return (1ULL << 6); - /*! LPC10, 180 samples/frame */ - case AST_FORMAT_LPC10: - return (1ULL << 7); - /*! G.729A audio */ - case AST_FORMAT_G729A: - return (1ULL << 8); - /*! SpeeX Free Compression */ - case AST_FORMAT_SPEEX: - return (1ULL << 9); - /*! iLBC Free Compression */ - case AST_FORMAT_ILBC: - return (1ULL << 10); - /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */ - case AST_FORMAT_G726: - return (1ULL << 11); - /*! G.722 */ - case AST_FORMAT_G722: - return (1ULL << 12); - /*! G.722.1 (also known as Siren7, 32kbps assumed) */ - case AST_FORMAT_SIREN7: - return (1ULL << 13); - /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */ - case AST_FORMAT_SIREN14: - return (1ULL << 14); - /*! Raw 16-bit Signed Linear (16000 Hz) PCM */ - case AST_FORMAT_SLINEAR16: - return (1ULL << 15); - /*! G.719 (64 kbps assumed) */ - case AST_FORMAT_G719: - return (1ULL << 32); - /*! SpeeX Wideband (16kHz) Free Compression */ - case AST_FORMAT_SPEEX16: - return (1ULL << 33); - /*! Opus audio (8kHz, 16kHz, 24kHz, 48Khz) */ - case AST_FORMAT_OPUS: - return (1ULL << 34); - /*! Raw mu-law data (G.711) */ - case AST_FORMAT_TESTLAW: - return (1ULL << 47); - - /*! H.261 Video */ - case AST_FORMAT_H261: - return (1ULL << 18); - /*! H.263 Video */ - case AST_FORMAT_H263: - return (1ULL << 19); - /*! H.263+ Video */ - case AST_FORMAT_H263_PLUS: - return (1ULL << 20); - /*! H.264 Video */ - case AST_FORMAT_H264: - return (1ULL << 21); - /*! MPEG4 Video */ - case AST_FORMAT_MP4_VIDEO: - return (1ULL << 22); - /*! VP8 Video */ - case AST_FORMAT_VP8: - return (1ULL << 23); - - /*! JPEG Images */ - case AST_FORMAT_JPEG: - return (1ULL << 16); - /*! PNG Images */ - case AST_FORMAT_PNG: - return (1ULL << 17); - - /*! T.140 RED Text format RFC 4103 */ - case AST_FORMAT_T140RED: - return (1ULL << 26); - /*! T.140 Text format - ITU T.140, RFC 4103 */ - case AST_FORMAT_T140: - return (1ULL << 27); - default: - return 0; /* not supported by old bitfield. */ + if (!cloned) { + return NULL; } - return 0; - -} -uint64_t ast_format_to_old_bitfield(const struct ast_format *format) -{ - return ast_format_id_to_old_bitfield(format->id); -} - -struct ast_format *ast_format_from_old_bitfield(struct ast_format *dst, uint64_t src) -{ - switch (src) { - /*! G.723.1 compression */ - case (1ULL << 0): - return ast_format_set(dst, AST_FORMAT_G723_1, 0); - /*! GSM compression */ - case (1ULL << 1): - return ast_format_set(dst, AST_FORMAT_GSM, 0); - /*! Raw mu-law data (G.711) */ - case (1ULL << 2): - return ast_format_set(dst, AST_FORMAT_ULAW, 0); - /*! Raw A-law data (G.711) */ - case (1ULL << 3): - return ast_format_set(dst, AST_FORMAT_ALAW, 0); - /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */ - case (1ULL << 4): - return ast_format_set(dst, AST_FORMAT_G726_AAL2, 0); - /*! ADPCM (IMA) */ - case (1ULL << 5): - return ast_format_set(dst, AST_FORMAT_ADPCM, 0); - /*! Raw 16-bit Signed Linear (8000 Hz) PCM */ - case (1ULL << 6): - return ast_format_set(dst, AST_FORMAT_SLINEAR, 0); - /*! LPC10, 180 samples/frame */ - case (1ULL << 7): - return ast_format_set(dst, AST_FORMAT_LPC10, 0); - /*! G.729A audio */ - case (1ULL << 8): - return ast_format_set(dst, AST_FORMAT_G729A, 0); - /*! SpeeX Free Compression */ - case (1ULL << 9): - return ast_format_set(dst, AST_FORMAT_SPEEX, 0); - /*! iLBC Free Compression */ - case (1ULL << 10): - return ast_format_set(dst, AST_FORMAT_ILBC, 0); - /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */ - case (1ULL << 11): - return ast_format_set(dst, AST_FORMAT_G726, 0); - /*! G.722 */ - case (1ULL << 12): - return ast_format_set(dst, AST_FORMAT_G722, 0); - /*! G.722.1 (also known as Siren7, 32kbps assumed) */ - case (1ULL << 13): - return ast_format_set(dst, AST_FORMAT_SIREN7, 0); - /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */ - case (1ULL << 14): - return ast_format_set(dst, AST_FORMAT_SIREN14, 0); - /*! Raw 16-bit Signed Linear (16000 Hz) PCM */ - case (1ULL << 15): - return ast_format_set(dst, AST_FORMAT_SLINEAR16, 0); - /*! G.719 (64 kbps assumed) */ - case (1ULL << 32): - return ast_format_set(dst, AST_FORMAT_G719, 0); - /*! SpeeX Wideband (16kHz) Free Compression */ - case (1ULL << 33): - return ast_format_set(dst, AST_FORMAT_SPEEX16, 0); - /*! Opus audio (8kHz, 16kHz, 24kHz, 48Khz) */ - case (1ULL << 34): - return ast_format_set(dst, AST_FORMAT_OPUS, 0); - /*! Raw mu-law data (G.711) */ - case (1ULL << 47): - return ast_format_set(dst, AST_FORMAT_TESTLAW, 0); - - /*! H.261 Video */ - case (1ULL << 18): - return ast_format_set(dst, AST_FORMAT_H261, 0); - /*! H.263 Video */ - case (1ULL << 19): - return ast_format_set(dst, AST_FORMAT_H263, 0); - /*! H.263+ Video */ - case (1ULL << 20): - return ast_format_set(dst, AST_FORMAT_H263_PLUS, 0); - /*! H.264 Video */ - case (1ULL << 21): - return ast_format_set(dst, AST_FORMAT_H264, 0); - /*! MPEG4 Video */ - case (1ULL << 22): - return ast_format_set(dst, AST_FORMAT_MP4_VIDEO, 0); - /*! VP8 Video */ - case (1ULL << 23): - return ast_format_set(dst, AST_FORMAT_VP8, 0); - - /*! JPEG Images */ - case (1ULL << 16): - return ast_format_set(dst, AST_FORMAT_JPEG, 0); - /*! PNG Images */ - case (1ULL << 17): - return ast_format_set(dst, AST_FORMAT_PNG, 0); - - /*! T.140 RED Text format RFC 4103 */ - case (1ULL << 26): - return ast_format_set(dst, AST_FORMAT_T140RED, 0); - /*! T.140 Text format - ITU T.140, RFC 4103 */ - case (1ULL << 27): - return ast_format_set(dst, AST_FORMAT_T140, 0); + if (cloned->interface && cloned->interface->format_clone(format, cloned)) { + ao2_ref(cloned, -1); + return NULL; } - ast_format_clear(dst); - return NULL; -} -enum ast_format_id ast_format_id_from_old_bitfield(uint64_t src) -{ - struct ast_format dst; - if (ast_format_from_old_bitfield(&dst, src)) { - return dst.id; - } - return 0; + return cloned; } -int ast_format_is_slinear(const struct ast_format *format) +struct ast_format *ast_format_create(struct ast_codec *codec) { - if (format->id == AST_FORMAT_SLINEAR || - format->id == AST_FORMAT_SLINEAR12 || - format->id == AST_FORMAT_SLINEAR16 || - format->id == AST_FORMAT_SLINEAR24 || - format->id == AST_FORMAT_SLINEAR32 || - format->id == AST_FORMAT_SLINEAR44 || - format->id == AST_FORMAT_SLINEAR48 || - format->id == AST_FORMAT_SLINEAR96 || - format->id == AST_FORMAT_SLINEAR192) { - return 1; - } - return 0; + return ast_format_create_named(codec->name, codec); } -enum ast_format_id ast_format_slin_by_rate(unsigned int rate) +enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2) { - if (rate >= 192000) { - return AST_FORMAT_SLINEAR192; - } else if (rate >= 96000) { - return AST_FORMAT_SLINEAR96; - } else if (rate >= 48000) { - return AST_FORMAT_SLINEAR48; - } else if (rate >= 44100) { - return AST_FORMAT_SLINEAR44; - } else if (rate >= 32000) { - return AST_FORMAT_SLINEAR32; - } else if (rate >= 24000) { - return AST_FORMAT_SLINEAR24; - } else if (rate >= 16000) { - return AST_FORMAT_SLINEAR16; - } else if (rate >= 12000) { - return AST_FORMAT_SLINEAR12; - } - return AST_FORMAT_SLINEAR; -} + const struct ast_format_interface *interface; -const char* ast_getformatname(const struct ast_format *format) -{ - int x; - const char *ret = "unknown"; - size_t f_len; - const struct ast_format_list *f_list = ast_format_list_get(&f_len); - for (x = 0; x < f_len; x++) { - if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) { - ret = f_list[x].name; - break; - } + if (format1 == NULL || format2 == NULL) { + return AST_FORMAT_CMP_NOT_EQUAL; } - f_list = ast_format_list_destroy(f_list); - return ret; -} - -char *ast_getformatname_multiple_byid(char *buf, size_t size, enum ast_format_id id) -{ - int x; - unsigned len; - char *start, *end = buf; - size_t f_len; - const struct ast_format_list *f_list = ast_format_list_get(&f_len); - - if (!size) { - f_list = ast_format_list_destroy(f_list); - return buf; - } - snprintf(end, size, "("); - len = strlen(end); - end += len; - size -= len; - start = end; - for (x = 0; x < f_len; x++) { - if (f_list[x].format.id == id) { - snprintf(end, size, "%s|", f_list[x].name); - len = strlen(end); - end += len; - size -= len; - } - } - if (start == end) { - ast_copy_string(start, "nothing)", size); - } else if (size > 1) { - *(end - 1) = ')'; + if (format1 == format2) { + return AST_FORMAT_CMP_EQUAL; } - f_list = ast_format_list_destroy(f_list); - return buf; -} - -static struct ast_codec_alias_table { - const char *alias; - const char *realname; -} ast_codec_alias_table[] = { - { "slinear", "slin"}, - { "slinear16", "slin16"}, - { "g723.1", "g723"}, - { "g722.1", "siren7"}, - { "g722.1c", "siren14"}, -}; -static const char *ast_expand_codec_alias(const char *in) -{ - int x; - - for (x = 0; x < ARRAY_LEN(ast_codec_alias_table); x++) { - if (!strcmp(in,ast_codec_alias_table[x].alias)) - return ast_codec_alias_table[x].realname; + if (format1->codec != format2->codec) { + return AST_FORMAT_CMP_NOT_EQUAL; } - return in; -} - -struct ast_format *ast_getformatbyname(const char *name, struct ast_format *result) -{ - int x; - size_t f_len; - const struct ast_format_list *f_list = ast_format_list_get(&f_len); - for (x = 0; x < f_len; x++) { - if (!strcasecmp(f_list[x].name, name) || - !strcasecmp(f_list[x].name, ast_expand_codec_alias(name))) { + interface = format1->interface ? format1->interface : format2->interface; - ast_format_copy(result, &f_list[x].format); - f_list = ast_format_list_destroy(f_list); - return result; - } + if (interface) { + return interface->format_cmp(format1, format2); } - f_list = ast_format_list_destroy(f_list); - - return NULL; -} -const char *ast_codec2str(struct ast_format *format) -{ - int x; - const char *ret = "unknown"; - size_t f_len; - const struct ast_format_list *f_list = ast_format_list_get(&f_len); - - for (x = 0; x < f_len; x++) { - if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) { - ret = f_list[x].desc; - break; - } - } - f_list = ast_format_list_destroy(f_list); - return ret; + return AST_FORMAT_CMP_EQUAL; } -int ast_format_rate(const struct ast_format *format) +struct ast_format *ast_format_joint(const struct ast_format *format1, const struct ast_format *format2) { - switch (format->id) { - case AST_FORMAT_SLINEAR12: - return 12000; - case AST_FORMAT_SLINEAR24: - return 24000; - case AST_FORMAT_SLINEAR32: - return 32000; - case AST_FORMAT_SLINEAR44: - return 44100; - case AST_FORMAT_SLINEAR48: - return 48000; - case AST_FORMAT_SLINEAR96: - return 96000; - case AST_FORMAT_SLINEAR192: - return 192000; - case AST_FORMAT_G722: - case AST_FORMAT_SLINEAR16: - case AST_FORMAT_SIREN7: - case AST_FORMAT_SPEEX16: - return 16000; - case AST_FORMAT_SIREN14: - case AST_FORMAT_SPEEX32: - return 32000; - case AST_FORMAT_G719: - return 48000; - case AST_FORMAT_SILK: - if (!(ast_format_isset(format, - SILK_ATTR_KEY_SAMP_RATE, - SILK_ATTR_VAL_SAMP_24KHZ, - AST_FORMAT_ATTR_END))) { - return 24000; - } else if (!(ast_format_isset(format, - SILK_ATTR_KEY_SAMP_RATE, - SILK_ATTR_VAL_SAMP_16KHZ, - AST_FORMAT_ATTR_END))) { - return 16000; - } else if (!(ast_format_isset(format, - SILK_ATTR_KEY_SAMP_RATE, - SILK_ATTR_VAL_SAMP_12KHZ, - AST_FORMAT_ATTR_END))) { - return 12000; - } else { - return 8000; - } - case AST_FORMAT_CELT: - { - int samplerate; - if (!(ast_format_get_value(format, - CELT_ATTR_KEY_SAMP_RATE, - &samplerate))) { - return samplerate; - } - } - /* Opus */ - case AST_FORMAT_OPUS: - return 48000; - default: - return 8000; - } -} + const struct ast_format_interface *interface; -static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - int x, found=0; - size_t f_len; - const struct ast_format_list *f_list; - - switch (cmd) { - case CLI_INIT: - e->command = "core show codecs [audio|video|image|text]"; - e->usage = - "Usage: core show codecs [audio|video|image|text]\n" - " Displays codec mapping\n"; - return NULL; - case CLI_GENERATE: + if (format1->codec != format2->codec) { return NULL; } - if ((a->argc < 3) || (a->argc > 4)) { - return CLI_SHOWUSAGE; + /* If the two formats are the same structure OR if the codec is the same and no attributes + * exist we can immediately return a format with reference count bumped up, since they are + * the same. + */ + if ((ast_format_cmp(format1, format2) == AST_FORMAT_CMP_EQUAL && !format1->attribute_data && !format2->attribute_data)) { + return ao2_bump((struct ast_format*)format1); } - f_list = ast_format_list_get(&f_len); - if (!ast_opt_dont_warn) { - ast_cli(a->fd, "Disclaimer: this command is for informational purposes only.\n" - "\tIt does not indicate anything about your configuration.\n"); - } + interface = format1->interface ? format1->interface : format2->interface; - ast_cli(a->fd, "%8s %5s %8s %s\n","ID","TYPE","NAME","DESCRIPTION"); - ast_cli(a->fd, "-----------------------------------------------------------------------------------\n"); - - for (x = 0; x < f_len; x++) { - if (a->argc == 4) { - if (!strcasecmp(a->argv[3], "audio")) { - if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_AUDIO) { - continue; - } - } else if (!strcasecmp(a->argv[3], "video")) { - if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_VIDEO) { - continue; - } - } else if (!strcasecmp(a->argv[3], "image")) { - if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_IMAGE) { - continue; - } - } else if (!strcasecmp(a->argv[3], "text")) { - if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_TEXT) { - continue; - } - } else { - continue; - } - } - - ast_cli(a->fd, "%8u %5s %8s (%s)\n", - f_list[x].format.id, - (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_AUDIO) ? "audio" : - (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_IMAGE) ? "image" : - (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_VIDEO) ? "video" : - (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_TEXT) ? "text" : - "(unk)", - f_list[x].name, - f_list[x].desc); - found = 1; - } - - f_list = ast_format_list_destroy(f_list); - if (!found) { - return CLI_SHOWUSAGE; - } else { - return CLI_SUCCESS; - } + /* If there is attribute data on either there has to be an interface */ + return interface->format_get_joint(format1, format2); } -static char *show_codec_n(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +struct ast_format *ast_format_attribute_set(const struct ast_format *format, const char *name, const char *value) { - enum ast_format_id format_id; - int x, found = 0; - int type_punned_codec; - size_t f_len; - const struct ast_format_list *f_list; - - switch (cmd) { - case CLI_INIT: - e->command = "core show codec"; - e->usage = - "Usage: core show codec <number>\n" - " Displays codec mapping\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - - if (a->argc != 4) { - return CLI_SHOWUSAGE; - } + const struct ast_format_interface *interface = format->interface; - if (sscanf(a->argv[3], "%30d", &type_punned_codec) != 1) { - return CLI_SHOWUSAGE; - } - format_id = type_punned_codec; - - f_list = ast_format_list_get(&f_len); - for (x = 0; x < f_len; x++) { - if (f_list[x].format.id == format_id) { - found = 1; - ast_cli(a->fd, "%11u %s\n", (unsigned int) format_id, f_list[x].desc); + if (!interface) { + struct format_interface *format_interface = ao2_find(interfaces, format->codec->name, OBJ_SEARCH_KEY); + if (format_interface) { + interface = format_interface->interface; + ao2_ref(format_interface, -1); } } - if (!found) { - ast_cli(a->fd, "Codec %u not found\n", format_id); + if (!interface || !interface->format_attribute_set) { + return ao2_bump((struct ast_format*)format); } - f_list = ast_format_list_destroy(f_list); - return CLI_SUCCESS; + return interface->format_attribute_set(format, name, value); } -/* Builtin Asterisk CLI-commands for debugging */ -static struct ast_cli_entry my_clis[] = { - AST_CLI_DEFINE(show_codecs, "Displays a list of codecs"), - AST_CLI_DEFINE(show_codec_n, "Shows a specific codec"), -}; - -static int format_list_add_custom(struct ast_format_list *new) +struct ast_format *ast_format_parse_sdp_fmtp(const struct ast_format *format, const char *attributes) { - RAII_VAR(struct ast_format_list *, entry, NULL, ao2_cleanup); - if (!(entry = ao2_alloc(sizeof(*entry), NULL))) { - return -1; - } - memcpy(entry, new, sizeof(struct ast_format_list)); - entry->custom_entry = 1; - ao2_link(format_list, entry); - return 0; -} -static int format_list_add_static( - const struct ast_format *format, - const char *name, - int samplespersecond, - const char *description, - int fr_len, - int min_ms, - int max_ms, - int inc_ms, - int def_ms, - unsigned int flags, - int cur_ms) -{ - struct ast_format_list *entry; - if (!(entry = ao2_alloc(sizeof(*entry), NULL))) { - return -1; - } - ast_format_copy(&entry->format, format); - ast_copy_string(entry->name, name, sizeof(entry->name)); - ast_copy_string(entry->desc, description, sizeof(entry->desc)); - entry->samplespersecond = samplespersecond; - entry->fr_len = fr_len; - entry->min_ms = min_ms; - entry->max_ms = max_ms; - entry->inc_ms = inc_ms; - entry->def_ms = def_ms; - entry->flags = flags; - entry->cur_ms = cur_ms; - entry->custom_entry = 0; - - ao2_link(format_list, entry); - ao2_ref(entry, -1); - return 0; -} + const struct ast_format_interface *interface = format->interface; -static int list_all_custom(void *obj, void *arg, int flag) -{ - struct ast_format_list *entry = obj; - return entry->custom_entry ? CMP_MATCH : 0; -} - -static int list_cmp_cb(void *obj, void *arg, int flags) -{ - struct ast_format_list *entry1 = obj; - struct ast_format_list *entry2 = arg; - - return (ast_format_cmp(&entry1->format, &entry2->format) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH | CMP_STOP : 0; -} - -const struct ast_format_list *ast_format_list_get(size_t *size) -{ - struct ast_format_list *list; - ast_rwlock_rdlock(&format_list_array_lock); - ao2_ref(format_list_array, 1); - list = format_list_array; - *size = format_list_array_len; - ast_rwlock_unlock(&format_list_array_lock); - return list; -} -const struct ast_format_list *ast_format_list_destroy(const struct ast_format_list *list) -{ - ao2_ref((void *) list, -1); - return NULL; -} - -static int build_format_list_array(void) -{ - struct ast_format_list *tmp; - size_t arraysize = sizeof(struct ast_format_list) * ao2_container_count(format_list); - int i = 0; - struct ao2_iterator it; - - ast_rwlock_wrlock(&format_list_array_lock); - tmp = format_list_array; - if (!(format_list_array = ao2_alloc(arraysize, NULL))) { - format_list_array = tmp; - ast_rwlock_unlock(&format_list_array_lock); - return -1; - } - format_list_array_len = ao2_container_count(format_list); - if (tmp) { - ao2_ref(tmp, -1); + if (!interface) { + struct format_interface *format_interface = ao2_find(interfaces, format->codec->name, OBJ_SEARCH_KEY); + if (format_interface) { + interface = format_interface->interface; + ao2_ref(format_interface, -1); + } } - /* walk through the container adding elements to the static array */ - it = ao2_iterator_init(format_list, 0); - while ((tmp = ao2_iterator_next(&it)) && (i < format_list_array_len)) { - memcpy(&format_list_array[i], tmp, sizeof(struct ast_format_list)); - ao2_ref(tmp, -1); - i++; + if (!interface || !interface->format_parse_sdp_fmtp) { + return ao2_bump((struct ast_format*)format); } - ao2_iterator_destroy(&it); - ast_rwlock_unlock(&format_list_array_lock); - return 0; + return interface->format_parse_sdp_fmtp(format, attributes); } -static int format_list_init(void) +void ast_format_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str) { - struct ast_format tmpfmt; - if (!(format_list = ao2_container_alloc(1, NULL, list_cmp_cb))) { - return -1; + if (!format->interface || !format->interface->format_generate_sdp_fmtp) { + return; } - /* initiate static entries XXX DO NOT CHANGE THIS ORDER! */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0), "g723", 8000, "G.723.1", 20, 30, 300, 30, 30, 0, 0); /*!< G723.1 */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0), "gsm", 8000, "GSM", 33, 20, 300, 20, 20, 0, 0); /*!< codec_gsm.c */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0), "ulaw", 8000, "G.711 u-law", 80, 10, 150, 10, 20, 0, 0); /*!< codec_ulaw.c */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0), "alaw", 8000, "G.711 A-law", 80, 10, 150, 10, 20, 0, 0); /*!< codec_alaw.c */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G726, 0), "g726", 8000, "G.726 RFC3551", 40, 10, 300, 10, 20, 0, 0); /*!< codec_g726.c */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), "adpcm" , 8000, "Dialogic ADPCM", 40, 10, 300, 10, 20, 0, 0); /*!< codec_adpcm.c */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0), "slin", 8000, "16 bit Signed Linear PCM", 160, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0); /*!< Signed linear */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_LPC10, 0), "lpc10", 8000, "LPC10", 7, 20, 20, 20, 20, 0, 0); /*!< codec_lpc10.c */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0), "g729", 8000, "G.729A", 10, 10, 230, 10, 20, AST_SMOOTHER_FLAG_G729, 0); /*!< Binary commercial distribution */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX, 0), "speex", 8000, "SpeeX", 10, 10, 60, 10, 20, 0, 0); /*!< codec_speex.c */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX16, 0), "speex16", 16000, "SpeeX 16khz", 10, 10, 60, 10, 20, 0, 0); /*!< codec_speex.c */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ILBC, 0), "ilbc", 8000, "iLBC", 50, 30, 30, 30, 30, 0, 0); /*!< codec_ilbc.c */ /* inc=30ms - workaround */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G726_AAL2, 0), "g726aal2", 8000, "G.726 AAL2", 40, 10, 300, 10, 20, 0, 0); /*!< codec_g726.c */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G722, 0), "g722", 16000, "G722", 80, 10, 150, 10, 20, 0, 0); /*!< codec_g722.c */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR16, 0), "slin16", 16000, "16 bit Signed Linear PCM (16kHz)", 320, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (16kHz) */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_JPEG, 0), "jpeg", 0, "JPEG image", 0, 0, 0, 0 ,0 ,0 ,0); /*!< See format_jpeg.c */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_PNG, 0), "png", 0, "PNG image", 0, 0, 0, 0 ,0 ,0 ,0); /*!< PNG Image format */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H261, 0), "h261", 0, "H.261 Video", 0, 0, 0, 0 ,0 ,0 ,0); /*!< H.261 Video Passthrough */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H263, 0), "h263", 0, "H.263 Video", 0, 0, 0, 0 ,0 ,0 ,0); /*!< H.263 Passthrough support, see format_h263.c */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H263_PLUS, 0), "h263p", 0, "H.263+ Video", 0, 0, 0,0 ,0 ,0, 0); /*!< H.263plus passthrough support See format_h263.c */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H264, 0), "h264", 0, "H.264 Video", 0, 0, 0, 0 ,0 ,0, 0); /*!< Passthrough support, see format_h263.c */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_MP4_VIDEO, 0), "mpeg4", 0, "MPEG4 Video", 0, 0, 0, 0, 0 ,0, 0); /*!< Passthrough support for MPEG4 */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_T140RED, 0), "red", 1, "T.140 Realtime Text with redundancy", 0, 0, 0,0 ,0 ,0, 0); /*!< Redundant T.140 Realtime Text */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_T140, 0), "t140", 0, "Passthrough T.140 Realtime Text", 0, 0, 0, 0 ,0 ,0, 0); /*!< Passthrough support for T.140 Realtime Text */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SIREN7, 0), "siren7", 16000, "ITU G.722.1 (Siren7, licensed from Polycom)", 80, 20, 80, 20, 20, 0, 0); /*!< Binary commercial distribution */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SIREN14, 0), "siren14", 32000, "ITU G.722.1 Annex C, (Siren14, licensed from Polycom)", 120, 20, 80, 20, 20, 0, 0); /*!< Binary commercial distribution */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_TESTLAW, 0), "testlaw", 8000, "G.711 test-law", 80, 10, 150, 10, 20, 0, 0); /*!< codec_ulaw.c */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), "g719", 48000, "ITU G.719", 160, 20, 80, 20, 20, 0, 0); - - /* ORDER MAY CHANGE AFTER THIS POINT IN THE LIST */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX32, 0), "speex32", 32000, "SpeeX 32khz", 10, 10, 60, 10, 20, 0, 0); /*!< codec_speex.c */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR12, 0), "slin12", 12000, "16 bit Signed Linear PCM (12kHz)", 240, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (12kHz) */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR24, 0), "slin24", 24000, "16 bit Signed Linear PCM (24kHz)", 480, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (24kHz) */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR32, 0), "slin32", 32000, "16 bit Signed Linear PCM (32kHz)", 640, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (32kHz) */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR44, 0), "slin44", 44100, "16 bit Signed Linear PCM (44kHz)", 882, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (44.1kHz) */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR48, 0), "slin48", 48000, "16 bit Signed Linear PCM (48kHz)", 960, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (48kHz) */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR96, 0), "slin96", 96000, "16 bit Signed Linear PCM (96kHz)", 1920, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (96kHz) */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR192, 0), "slin192", 192000, "16 bit Signed Linear PCM (192kHz)", 3840, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (192kHz) */ - /* Opus (FIXME: real min is 3/5/10, real max is 120...) */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_OPUS, 0), "opus", 48000, "Opus Codec", 10, 20, 60, 20, 20, 0, 0); /*!< codec_opus.c */ - /* VP8 (passthrough) */ - format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_VP8, 0), "vp8", 0, "VP8 Video", 0, 0, 0, 0 ,0 ,0, 0); /*!< Passthrough support, see format_h263.c */ - return 0; + format->interface->format_generate_sdp_fmtp(format, payload, str); } -/*! - * \internal - * \brief Clean up resources on Asterisk shutdown - */ -static void format_list_shutdown(void) +unsigned int ast_format_get_codec_id(const struct ast_format *format) { - ast_rwlock_destroy(&format_list_array_lock); - if (format_list) { - ao2_t_ref(format_list, -1, "Unref format_list container in shutdown"); - format_list = NULL; - } - if (format_list_array) { - ao2_t_ref(format_list_array, -1, "Unref format_list_array in shutdown"); - format_list_array = NULL; - } + return format->codec->id; } -int ast_format_list_init(void) +const char *ast_format_get_name(const struct ast_format *format) { - if (ast_rwlock_init(&format_list_array_lock)) { - return -1; - } - if (format_list_init()) { - goto init_list_cleanup; - } - if (build_format_list_array()) { - goto init_list_cleanup; - } - - ast_register_atexit(format_list_shutdown); - return 0; -init_list_cleanup: - - format_list_shutdown(); - return -1; + return format->name; } -/*! - * \internal - * \brief Clean up resources on Asterisk shutdown - */ -static void format_attr_shutdown(void) +const char *ast_format_get_codec_name(const struct ast_format *format) { - ast_cli_unregister_multiple(my_clis, ARRAY_LEN(my_clis)); - if (interfaces) { - ao2_ref(interfaces, -1); - interfaces = NULL; - } + return format->codec->name; } -int ast_format_attr_init(void) +int ast_format_can_be_smoothed(const struct ast_format *format) { - interfaces = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, - 283, interface_hash_cb, interface_cmp_cb); - if (!interfaces) { - return -1; - } - - ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis)); - ast_register_cleanup(format_attr_shutdown); - return 0; + return format->codec->smooth; } -static int custom_celt_format(struct ast_format_list *entry, unsigned int maxbitrate, unsigned int framesize) +enum ast_media_type ast_format_get_type(const struct ast_format *format) { - if (!entry->samplespersecond) { - ast_log(LOG_WARNING, "Custom CELT format definition '%s' requires sample rate to be defined.\n", entry->name); - } - ast_format_set(&entry->format, AST_FORMAT_CELT, 0); - if (!has_interface(&entry->format)) { - return -1; - } - - snprintf(entry->desc, sizeof(entry->desc), "CELT Custom Format %ukhz", entry->samplespersecond/1000); - - ast_format_append(&entry->format, - CELT_ATTR_KEY_SAMP_RATE, entry->samplespersecond, - CELT_ATTR_KEY_MAX_BITRATE, maxbitrate, - CELT_ATTR_KEY_FRAME_SIZE, framesize, - AST_FORMAT_ATTR_END); - - entry->fr_len = 80; - entry->min_ms = 20; - entry->max_ms = 20; - entry->inc_ms = 20; - entry->def_ms = 20; - return 0; + return format->codec->type; } -static int custom_silk_format(struct ast_format_list *entry, unsigned int maxbitrate, int usedtx, int usefec, int packetloss_percentage) +unsigned int ast_format_get_default_ms(const struct ast_format *format) { - if (!entry->samplespersecond) { - ast_log(LOG_WARNING, "Custom SILK format definition '%s' requires sample rate to be defined.\n", entry->name); - } - ast_format_set(&entry->format, AST_FORMAT_SILK, 0); - - if (!has_interface(&entry->format)) { - return -1; - } - - switch (entry->samplespersecond) { - case 8000: - ast_copy_string(entry->desc, "SILK Custom Format 8khz", sizeof(entry->desc)); - ast_format_append(&entry->format, - SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_8KHZ, - AST_FORMAT_ATTR_END); - break; - case 12000: - ast_copy_string(entry->desc, "SILK Custom Format 12khz", sizeof(entry->desc)); - ast_format_append(&entry->format, - SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_12KHZ, - AST_FORMAT_ATTR_END); - break; - case 16000: - ast_copy_string(entry->desc, "SILK Custom Format 16khz", sizeof(entry->desc)); - ast_format_append(&entry->format, - SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_16KHZ, - AST_FORMAT_ATTR_END); - break; - case 24000: - ast_copy_string(entry->desc, "SILK Custom Format 24khz", sizeof(entry->desc)); - ast_format_append(&entry->format, - SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_24KHZ, - AST_FORMAT_ATTR_END); - break; - default: - ast_log(LOG_WARNING, "Custom SILK format definition '%s' can not support sample rate %u\n", entry->name, entry->samplespersecond); - return -1; - } - ast_format_append(&entry->format, - SILK_ATTR_KEY_MAX_BITRATE, maxbitrate, - SILK_ATTR_KEY_DTX, usedtx ? 1 : 0, - SILK_ATTR_KEY_FEC, usefec ? 1 : 0, - SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE, packetloss_percentage, - AST_FORMAT_ATTR_END); - - entry->fr_len = 80; - entry->min_ms = 20; - entry->max_ms = 20; - entry->inc_ms = 20; - entry->def_ms = 20; - return 0; + return format->codec->default_ms; } -static int conf_process_format_name(const char *name, enum ast_format_id *id) +unsigned int ast_format_get_minimum_ms(const struct ast_format *format) { - if (!strcasecmp(name, "silk")) { - *id = AST_FORMAT_SILK; - } else if (!strcasecmp(name, "celt")) { - *id = AST_FORMAT_CELT; - } else { - *id = 0; - return -1; - } - return 0; + return format->codec->minimum_ms; } -static int conf_process_sample_rate(const char *rate, unsigned int *result) +unsigned int ast_format_get_maximum_ms(const struct ast_format *format) { - if (!strcasecmp(rate, "8000")) { - *result = 8000; - } else if (!strcasecmp(rate, "12000")) { - *result = 12000; - } else if (!strcasecmp(rate, "16000")) { - *result = 16000; - } else if (!strcasecmp(rate, "24000")) { - *result = 24000; - } else if (!strcasecmp(rate, "32000")) { - *result = 32000; - } else if (!strcasecmp(rate, "44100")) { - *result = 44100; - } else if (!strcasecmp(rate, "48000")) { - *result = 48000; - } else if (!strcasecmp(rate, "96000")) { - *result = 96000; - } else if (!strcasecmp(rate, "192000")) { - *result = 192000; - } else { - *result = 0; - return -1; - } - - return 0; + return format->codec->maximum_ms; } -static int load_format_config(void) -{ - struct ast_flags config_flags = { 0, }; - struct ast_config *cfg = ast_config_load(FORMAT_CONFIG, config_flags); - struct ast_format_list entry; - struct ast_variable *var; - char *cat = NULL; - int add_it = 0; - - struct { - enum ast_format_id id; - unsigned int maxbitrate; - unsigned int framesize; - unsigned int packetloss_percentage; - int usefec; - int usedtx; - } settings; - - if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) { - return 0; - } - - /* remove all custom formats from the AO2 Container. Note, this has no affect on the - * global format list until the list is rebuild. That is why this is okay to do while - * reloading the config. */ - ao2_callback(format_list, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, list_all_custom, NULL); - while ((cat = ast_category_browse(cfg, cat))) { - memset(&entry, 0, sizeof(entry)); - memset(&settings, 0, sizeof(settings)); - add_it = 0; - - if (!(ast_variable_retrieve(cfg, cat, "type"))) { - continue; - } - ast_copy_string(entry.name, cat, sizeof(entry.name)); - var = ast_variable_browse(cfg, cat); - for (var = ast_variable_browse(cfg, cat); var; var = var->next) { - if (!strcasecmp(var->name, "type") && conf_process_format_name(var->value, &settings.id)) { - ast_log(LOG_WARNING, "Can not make custom format type for '%s' at line %d of %s\n", - var->value, var->lineno, FORMAT_CONFIG); - continue; - } else if (!strcasecmp(var->name, "samprate") && conf_process_sample_rate(var->value, &entry.samplespersecond)) { - ast_log(LOG_WARNING, "Sample rate '%s' at line %d of %s is not supported.\n", - var->value, var->lineno, FORMAT_CONFIG); - } else if (!strcasecmp(var->name, "maxbitrate")) { - if (sscanf(var->value, "%30u", &settings.maxbitrate) != 1) { - ast_log(LOG_WARNING, "maxbitrate '%s' at line %d of %s is not supported.\n", - var->value, var->lineno, FORMAT_CONFIG); - } - } else if (!strcasecmp(var->name, "framesize")) { - if (sscanf(var->value, "%30u", &settings.framesize) != 1) { - ast_log(LOG_WARNING, "framesize '%s' at line %d of %s is not supported.\n", - var->value, var->lineno, FORMAT_CONFIG); - } - } else if (!strcasecmp(var->name, "dtx")) { - settings.usedtx = ast_true(var->value) ? 1 : 0; - } else if (!strcasecmp(var->name, "fec")) { - settings.usefec = ast_true(var->value) ? 1 : 0; - } else if (!strcasecmp(var->name, "packetloss_percentage")) { - if ((sscanf(var->value, "%30u", &settings.packetloss_percentage) != 1) || (settings.packetloss_percentage > 100)) { - ast_log(LOG_WARNING, "packetloss_percentage '%s' at line %d of %s is not supported.\n", - var->value, var->lineno, FORMAT_CONFIG); - } - } - } - - switch (settings.id) { - case AST_FORMAT_SILK: - if (!(custom_silk_format(&entry, settings.maxbitrate, settings.usedtx, settings.usefec, settings.packetloss_percentage))) { - add_it = 1; - } - break; - case AST_FORMAT_CELT: - if (!(custom_celt_format(&entry, settings.maxbitrate, settings.framesize))) { - add_it = 1; - } - break; - default: - ast_log(LOG_WARNING, "Can not create custom format %s\n", entry.name); - } - - if (add_it) { - format_list_add_custom(&entry); - } - } - ast_config_destroy(cfg); - build_format_list_array(); - return 0; +unsigned int ast_format_get_minimum_bytes(const struct ast_format *format) +{ + return format->codec->minimum_bytes; } -int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interface) +unsigned int ast_format_get_sample_rate(const struct ast_format *format) { - int x; - size_t f_len; - const struct ast_format_list *f_list; - struct interface_ao2_wrapper *wrapper; - struct interface_ao2_wrapper tmp_wrapper = { - .id = interface->id, - }; - - /* - * Grab the write lock before checking for duplicates in - * anticipation of adding a new interface and to prevent a - * duplicate from sneaking in between the check and add. - */ - ao2_wrlock(interfaces); - - /* check for duplicates first*/ - if ((wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) { - ao2_unlock(interfaces); - ast_log(LOG_WARNING, "Can not register attribute interface for format id %u, interface already exists.\n", interface->id); - ao2_ref(wrapper, -1); - return -1; - } - - wrapper = ao2_alloc_options(sizeof(*wrapper), NULL, AO2_ALLOC_OPT_LOCK_RWLOCK); - if (!wrapper) { - ao2_unlock(interfaces); - return -1; - } - - wrapper->interface = interface; - wrapper->id = interface->id; - - /* The write lock is already held. */ - ao2_link_flags(interfaces, wrapper, OBJ_NOLOCK); - ao2_unlock(interfaces); - - ao2_ref(wrapper, -1); - - /* This will find all custom formats in codecs.conf for this new registered interface */ - load_format_config(); - - /* update the RTP engine to all custom formats created for this interface */ - f_list = ast_format_list_get(&f_len); - for (x = 0; x < f_len; x++) { - if (f_list[x].format.id == tmp_wrapper.id) { - ast_rtp_engine_load_format(&f_list[x].format); - } - } - f_list = ast_format_list_destroy(f_list); - return 0; + return format->codec->sample_rate; } -int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface) +unsigned int ast_format_determine_length(const struct ast_format *format, unsigned int samples) { - int x; - size_t f_len; - const struct ast_format_list *f_list; - struct interface_ao2_wrapper *wrapper; - struct interface_ao2_wrapper tmp_wrapper = { - .id = interface->id, - }; - - if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_UNLINK)))) { - return -1; - } - - ao2_wrlock(wrapper); - wrapper->interface = NULL; - ao2_unlock(wrapper); - - ao2_ref(wrapper, -1); - - /* update the RTP engine to remove all custom formats created for this interface */ - f_list = ast_format_list_get(&f_len); - for (x = 0; x < f_len; x++) { - if (f_list[x].format.id == tmp_wrapper.id) { - ast_rtp_engine_unload_format(&f_list[x].format); - } - } - - /* This will remove all custom formats previously created for this interface */ - load_format_config(); - f_list = ast_format_list_destroy(f_list); - return 0; + return ast_codec_determine_length(format->codec, samples); } diff --git a/main/format_cache.c b/main/format_cache.c new file mode 100644 index 000000000..c170a76f9 --- /dev/null +++ b/main/format_cache.c @@ -0,0 +1,519 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Joshua Colp <jcolp@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Media Format Cache API + * + * \author Joshua Colp <jcolp@digium.com> + */ + +/*** MODULEINFO + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/logger.h" +#include "asterisk/format.h" +#include "asterisk/format_cache.h" +#include "asterisk/astobj2.h" +#include "asterisk/strings.h" + +/*! + * \brief Built-in cached signed linear 8kHz format. + */ +struct ast_format *ast_format_slin; + +/*! + * \brief Built-in cached signed linear 12kHz format. + */ +struct ast_format *ast_format_slin12; + +/*! + * \brief Built-in cached signed linear 16kHz format. + */ +struct ast_format *ast_format_slin16; + +/*! + * \brief Built-in cached signed linear 24kHz format. + */ +struct ast_format *ast_format_slin24; + +/*! + * \brief Built-in cached signed linear 32kHz format. + */ +struct ast_format *ast_format_slin32; + +/*! + * \brief Built-in cached signed linear 44kHz format. + */ +struct ast_format *ast_format_slin44; + +/*! + * \brief Built-in cached signed linear 48kHz format. + */ +struct ast_format *ast_format_slin48; + +/*! + * \brief Built-in cached signed linear 96kHz format. + */ +struct ast_format *ast_format_slin96; + +/*! + * \brief Built-in cached signed linear 192kHz format. + */ +struct ast_format *ast_format_slin192; + +/*! + * \brief Built-in cached ulaw format. + */ +struct ast_format *ast_format_ulaw; + +/*! + * \brief Built-in cached alaw format. + */ +struct ast_format *ast_format_alaw; + +/*! + * \brief Built-in cached testlaw format. + */ +struct ast_format *ast_format_testlaw; + +/*! + * \brief Built-in cached gsm format. + */ +struct ast_format *ast_format_gsm; + +/*! + * \brief Built-in cached adpcm format. + */ +struct ast_format *ast_format_adpcm; + +/*! + * \brief Built-in cached g722 format. + */ +struct ast_format *ast_format_g722; + +/*! + * \brief Built-in cached g726 format. + */ +struct ast_format *ast_format_g726; + +/*! + * \brief Built-in cached g726-aal2 format. + */ +struct ast_format *ast_format_g726_aal2; + +/*! + * \brief Built-in cached ilbc format. + */ +struct ast_format *ast_format_ilbc; + +/*! + * \brief Built-in cached ilbc format. + */ +struct ast_format *ast_format_lpc10; + +/*! + * \brief Built-in cached speex format. + */ +struct ast_format *ast_format_speex; + +/*! + * \brief Built-in cached speex at 16kHz format. + */ +struct ast_format *ast_format_speex16; + +/*! + * \brief Built-in cached speex at 32kHz format. + */ +struct ast_format *ast_format_speex32; + +/*! + * \brief Built-in cached g723.1 format. + */ +struct ast_format *ast_format_g723; + +/*! + * \brief Built-in cached g729 format. + */ +struct ast_format *ast_format_g729; + +/*! + * \brief Built-in cached g719 format. + */ +struct ast_format *ast_format_g719; + +/*! + * \brief Built-in cached h261 format. + */ +struct ast_format *ast_format_h261; + +/*! + * \brief Built-in cached h263 format. + */ +struct ast_format *ast_format_h263; + +/*! + * \brief Built-in cached h263 plus format. + */ +struct ast_format *ast_format_h263p; + +/*! + * \brief Built-in cached h264 format. + */ +struct ast_format *ast_format_h264; + +/*! + * \brief Built-in cached mp4 format. + */ +struct ast_format *ast_format_mp4; + +/*! + * \brief Built-in cached vp8 format. + */ +struct ast_format *ast_format_vp8; + +/*! + * \brief Built-in cached jpeg format. + */ +struct ast_format *ast_format_jpeg; + +/*! + * \brief Built-in cached png format. + */ +struct ast_format *ast_format_png; + +/*! + * \brief Built-in cached siren14 format. + */ +struct ast_format *ast_format_siren14; + +/*! + * \brief Built-in cached siren7 format. + */ +struct ast_format *ast_format_siren7; + +/*! + * \brief Built-in cached opus format. + */ +struct ast_format *ast_format_opus; + +/*! + * \brief Built-in cached t140 format. + */ +struct ast_format *ast_format_t140; + +/*! + * \brief Built-in cached t140 red format. + */ +struct ast_format *ast_format_t140_red; + +/*! + * \brief Built-in cached vp8 format. + */ +struct ast_format *ast_format_vp8; + +/*! + * \brief Built-in "null" format. + */ +struct ast_format *ast_format_none; + +/*! \brief Number of buckets to use for the media format cache (should be prime for performance reasons) */ +#define CACHE_BUCKETS 53 + +/*! \brief Cached formats */ +static struct ao2_container *formats; + +static int format_hash_cb(const void *obj, int flags) +{ + const struct ast_format *format; + const char *key; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_KEY: + key = obj; + return ast_str_case_hash(key); + case OBJ_SEARCH_OBJECT: + format = obj; + return ast_str_case_hash(ast_format_get_name(format)); + default: + /* Hash can only work on something with a full key. */ + ast_assert(0); + return 0; + } +} + +static int format_cmp_cb(void *obj, void *arg, int flags) +{ + const struct ast_format *left = obj; + const struct ast_format *right = arg; + const char *right_key = arg; + int cmp; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + right_key = ast_format_get_name(right); + /* Fall through */ + case OBJ_SEARCH_KEY: + cmp = strcasecmp(ast_format_get_name(left), right_key); + break; + case OBJ_SEARCH_PARTIAL_KEY: + cmp = strncasecmp(ast_format_get_name(left), right_key, strlen(right_key)); + break; + default: + ast_assert(0); + cmp = 0; + break; + } + if (cmp) { + return 0; + } + + return CMP_MATCH; +} + +/*! \brief Function called when the process is shutting down */ +static void format_cache_shutdown(void) +{ + ao2_cleanup(formats); + formats = NULL; + + ao2_replace(ast_format_g723, NULL); + ao2_replace(ast_format_ulaw, NULL); + ao2_replace(ast_format_alaw, NULL); + ao2_replace(ast_format_gsm, NULL); + ao2_replace(ast_format_g726, NULL); + ao2_replace(ast_format_g726_aal2, NULL); + ao2_replace(ast_format_adpcm, NULL); + ao2_replace(ast_format_slin, NULL); + ao2_replace(ast_format_slin12, NULL); + ao2_replace(ast_format_slin16, NULL); + ao2_replace(ast_format_slin24, NULL); + ao2_replace(ast_format_slin32, NULL); + ao2_replace(ast_format_slin44, NULL); + ao2_replace(ast_format_slin48, NULL); + ao2_replace(ast_format_slin96, NULL); + ao2_replace(ast_format_slin192, NULL); + ao2_replace(ast_format_lpc10, NULL); + ao2_replace(ast_format_g729, NULL); + ao2_replace(ast_format_speex, NULL); + ao2_replace(ast_format_speex16, NULL); + ao2_replace(ast_format_speex32, NULL); + ao2_replace(ast_format_ilbc, NULL); + ao2_replace(ast_format_g722, NULL); + ao2_replace(ast_format_siren7, NULL); + ao2_replace(ast_format_siren14, NULL); + ao2_replace(ast_format_testlaw, NULL); + ao2_replace(ast_format_g719, NULL); + ao2_replace(ast_format_opus, NULL); + ao2_replace(ast_format_jpeg, NULL); + ao2_replace(ast_format_png, NULL); + ao2_replace(ast_format_h261, NULL); + ao2_replace(ast_format_h263, NULL); + ao2_replace(ast_format_h263p, NULL); + ao2_replace(ast_format_h264, NULL); + ao2_replace(ast_format_mp4, NULL); + ao2_replace(ast_format_vp8, NULL); + ao2_replace(ast_format_t140_red, NULL); + ao2_replace(ast_format_t140, NULL); + ao2_replace(ast_format_none, NULL); +} + +int ast_format_cache_init(void) +{ + formats = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, CACHE_BUCKETS, + format_hash_cb, format_cmp_cb); + if (!formats) { + return -1; + } + + ast_register_atexit(format_cache_shutdown); + + return 0; +} + +static void set_cached_format(const char *name, struct ast_format *format) +{ + if (!strcmp(name, "g723")) { + ao2_replace(ast_format_g723, format); + } else if (!strcmp(name, "ulaw")) { + ao2_replace(ast_format_ulaw, format); + } else if (!strcmp(name, "alaw")) { + ao2_replace(ast_format_alaw, format); + } else if (!strcmp(name, "gsm")) { + ao2_replace(ast_format_gsm, format); + } else if (!strcmp(name, "g726")) { + ao2_replace(ast_format_g726, format); + } else if (!strcmp(name, "g726aal2")) { + ao2_replace(ast_format_g726_aal2, format); + } else if (!strcmp(name, "adpcm")) { + ao2_replace(ast_format_adpcm, format); + } else if (!strcmp(name, "slin")) { + ao2_replace(ast_format_slin, format); + } else if (!strcmp(name, "slin12")) { + ao2_replace(ast_format_slin12, format); + } else if (!strcmp(name, "slin16")) { + ao2_replace(ast_format_slin16, format); + } else if (!strcmp(name, "slin24")) { + ao2_replace(ast_format_slin24, format); + } else if (!strcmp(name, "slin32")) { + ao2_replace(ast_format_slin32, format); + } else if (!strcmp(name, "slin44")) { + ao2_replace(ast_format_slin44, format); + } else if (!strcmp(name, "slin48")) { + ao2_replace(ast_format_slin48, format); + } else if (!strcmp(name, "slin96")) { + ao2_replace(ast_format_slin96, format); + } else if (!strcmp(name, "slin192")) { + ao2_replace(ast_format_slin192, format); + } else if (!strcmp(name, "lpc10")) { + ao2_replace(ast_format_lpc10, format); + } else if (!strcmp(name, "g729")) { + ao2_replace(ast_format_g729, format); + } else if (!strcmp(name, "speex")) { + ao2_replace(ast_format_speex, format); + } else if (!strcmp(name, "speex16")) { + ao2_replace(ast_format_speex16, format); + } else if (!strcmp(name, "speex32")) { + ao2_replace(ast_format_speex32, format); + } else if (!strcmp(name, "ilbc")) { + ao2_replace(ast_format_ilbc, format); + } else if (!strcmp(name, "g722")) { + ao2_replace(ast_format_g722, format); + } else if (!strcmp(name, "siren7")) { + ao2_replace(ast_format_siren7, format); + } else if (!strcmp(name, "siren14")) { + ao2_replace(ast_format_siren14, format); + } else if (!strcmp(name, "testlaw")) { + ao2_replace(ast_format_testlaw, format); + } else if (!strcmp(name, "g719")) { + ao2_replace(ast_format_g719, format); + } else if (!strcmp(name, "opus")) { + ao2_replace(ast_format_opus, format); + } else if (!strcmp(name, "jpeg")) { + ao2_replace(ast_format_jpeg, format); + } else if (!strcmp(name, "png")) { + ao2_replace(ast_format_png, format); + } else if (!strcmp(name, "h261")) { + ao2_replace(ast_format_h261, format); + } else if (!strcmp(name, "h263")) { + ao2_replace(ast_format_h263, format); + } else if (!strcmp(name, "h263p")) { + ao2_replace(ast_format_h263p, format); + } else if (!strcmp(name, "h264")) { + ao2_replace(ast_format_h264, format); + } else if (!strcmp(name, "mpeg4")) { + ao2_replace(ast_format_mp4, format); + } else if (!strcmp(name, "vp8")) { + ao2_replace(ast_format_vp8, format); + } else if (!strcmp(name, "red")) { + ao2_replace(ast_format_t140_red, format); + } else if (!strcmp(name, "t140")) { + ao2_replace(ast_format_t140, format); + } else if (!strcmp(name, "none")) { + ao2_replace(ast_format_none, format); + } +} + +int ast_format_cache_set(struct ast_format *format) +{ + SCOPED_AO2WRLOCK(lock, formats); + struct ast_format *old_format; + + ast_assert(format != NULL); + + if (ast_strlen_zero(ast_format_get_name(format))) { + return -1; + } + + old_format = ao2_find(formats, ast_format_get_name(format), OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (old_format) { + ao2_unlink_flags(formats, old_format, OBJ_NOLOCK); + } + ao2_link_flags(formats, format, OBJ_NOLOCK); + + set_cached_format(ast_format_get_name(format), format); + + ast_verb(2, "%s cached format with name '%s'\n", + old_format ? "Updated" : "Created", + ast_format_get_name(format)); + + ao2_cleanup(old_format); + + return 0; +} + +struct ast_format *__ast_format_cache_get(const char *name) +{ + if (ast_strlen_zero(name)) { + return NULL; + } + + return ao2_find(formats, name, OBJ_SEARCH_KEY); +} + +struct ast_format *__ast_format_cache_get_debug(const char *name, const char *tag, const char *file, int line, const char *func) +{ + if (ast_strlen_zero(name)) { + return NULL; + } + + return __ao2_find_debug(formats, name, OBJ_SEARCH_KEY, S_OR(tag, "ast_format_cache_get"), file, line, func); +} + +struct ast_format *ast_format_cache_get_slin_by_rate(unsigned int rate) +{ + if (rate >= 192000) { + return ast_format_slin192; + } else if (rate >= 96000) { + return ast_format_slin96; + } else if (rate >= 48000) { + return ast_format_slin48; + } else if (rate >= 44100) { + return ast_format_slin44; + } else if (rate >= 32000) { + return ast_format_slin32; + } else if (rate >= 24000) { + return ast_format_slin24; + } else if (rate >= 16000) { + return ast_format_slin16; + } else if (rate >= 12000) { + return ast_format_slin12; + } + return ast_format_slin; +} + +int ast_format_cache_is_slinear(struct ast_format *format) +{ + if ((ast_format_cmp(format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) + || (ast_format_cmp(format, ast_format_slin16) == AST_FORMAT_CMP_EQUAL) + || (ast_format_cmp(format, ast_format_slin24) == AST_FORMAT_CMP_EQUAL) + || (ast_format_cmp(format, ast_format_slin32) == AST_FORMAT_CMP_EQUAL) + || (ast_format_cmp(format, ast_format_slin44) == AST_FORMAT_CMP_EQUAL) + || (ast_format_cmp(format, ast_format_slin48) == AST_FORMAT_CMP_EQUAL) + || (ast_format_cmp(format, ast_format_slin96) == AST_FORMAT_CMP_EQUAL) + || (ast_format_cmp(format, ast_format_slin192) == AST_FORMAT_CMP_EQUAL)) { + return 1; + } + + return 0; +}
\ No newline at end of file diff --git a/main/format_cap.c b/main/format_cap.c index 96c2fa3aa..65e469fc1 100644 --- a/main/format_cap.c +++ b/main/format_cap.c @@ -1,9 +1,9 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 2010, Digium, Inc. + * Copyright (C) 2014, Digium, Inc. * - * David Vossel <dvossel@digium.com> + * Joshua Colp <jcolp@digium.com> * * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact @@ -16,11 +16,11 @@ * at the top of the source tree. */ -/*! - * \file - * \brief Format Capability API +/*! \file + * + * \brief Format Capabilities API * - * \author David Vossel <dvossel@digium.com> + * \author Joshua Colp <jcolp@digium.com> */ /*** MODULEINFO @@ -29,653 +29,674 @@ #include "asterisk.h" -ASTERISK_FILE_VERSION(__FILE__, "$Revision$"); +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") -#include "asterisk/_private.h" +#include "asterisk/logger.h" #include "asterisk/format.h" #include "asterisk/format_cap.h" -#include "asterisk/frame.h" +#include "asterisk/format_cache.h" +#include "asterisk/codec.h" #include "asterisk/astobj2.h" +#include "asterisk/strings.h" +#include "asterisk/vector.h" +#include "asterisk/linkedlists.h" #include "asterisk/utils.h" -#define FORMAT_STR_BUFSIZE 256 +/*! \brief Structure used for capability formats, adds framing */ +struct format_cap_framed { + /*! \brief A pointer to the format */ + struct ast_format *format; + /*! \brief The format framing size */ + unsigned int framing; + /*! \brief Linked list information */ + AST_LIST_ENTRY(format_cap_framed) entry; +}; +/*! \brief Format capabilities structure, holds formats + preference order + etc */ struct ast_format_cap { - /* The capabilities structure is just an ao2 container of ast_formats */ - struct ao2_container *formats; - struct ao2_iterator it; - /*! TRUE if the formats container created without a lock. */ - struct ast_flags flags; - unsigned int string_cache_valid; - char format_strs[0]; + /*! \brief Vector of formats, indexed using the codec identifier */ + AST_VECTOR(, struct format_cap_framed_list) formats; + /*! \brief Vector of formats, added in preference order */ + AST_VECTOR(, struct format_cap_framed *) preference_order; + /*! \brief Global framing size, applies to all formats if no framing present on format */ + unsigned int framing; }; -/*! format exists within capabilities structure if it is identical to - * another format, or if the format is a proper subset of another format. */ -static int cmp_cb(void *obj, void *arg, int flags) +/*! \brief Linked list for formats */ +AST_LIST_HEAD_NOLOCK(format_cap_framed_list, format_cap_framed); + +/*! \brief Dummy empty list for when we are inserting a new list */ +static const struct format_cap_framed_list format_cap_framed_list_empty = AST_LIST_HEAD_NOLOCK_INIT_VALUE; + +/*! \brief Destructor for format capabilities structure */ +static void format_cap_destroy(void *obj) { - struct ast_format *format1 = arg; - struct ast_format *format2 = obj; - enum ast_format_cmp_res res = ast_format_cmp(format1, format2); - - return ((res == AST_FORMAT_CMP_EQUAL) || - (res == AST_FORMAT_CMP_SUBSET)) ? - CMP_MATCH | CMP_STOP : - 0; + struct ast_format_cap *cap = obj; + int idx; + + for (idx = 0; idx < AST_VECTOR_SIZE(&cap->formats); idx++) { + struct format_cap_framed_list *list = AST_VECTOR_GET_ADDR(&cap->formats, idx); + struct format_cap_framed *framed; + + while ((framed = AST_LIST_REMOVE_HEAD(list, entry))) { + ao2_ref(framed, -1); + } + } + AST_VECTOR_FREE(&cap->formats); + + for (idx = 0; idx < AST_VECTOR_SIZE(&cap->preference_order); idx++) { + struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, idx); + + /* This will always be non-null, unlike formats */ + ao2_ref(framed, -1); + } + AST_VECTOR_FREE(&cap->preference_order); } -static int hash_cb(const void *obj, const int flags) +static inline void format_cap_init(struct ast_format_cap *cap, enum ast_format_cap_flags flags) { - const struct ast_format *format = obj; - return format->id; + AST_VECTOR_INIT(&cap->formats, 0); + + /* TODO: Look at common usage of this and determine a good starting point */ + AST_VECTOR_INIT(&cap->preference_order, 5); + + cap->framing = UINT_MAX; } -struct ast_format_cap *ast_format_cap_alloc(enum ast_format_cap_flags flags) +struct ast_format_cap *__ast_format_cap_alloc(enum ast_format_cap_flags flags) { struct ast_format_cap *cap; - unsigned int alloc_size; - - alloc_size = sizeof(*cap); - if (flags & AST_FORMAT_CAP_FLAG_CACHE_STRINGS) { - alloc_size += FORMAT_STR_BUFSIZE; - } - cap = ast_calloc(1, alloc_size); + cap = ao2_alloc_options(sizeof(*cap), format_cap_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!cap) { return NULL; } - ast_set_flag(&cap->flags, flags); - cap->formats = ao2_container_alloc_options( - (flags & AST_FORMAT_CAP_FLAG_NOLOCK) ? - AO2_ALLOC_OPT_LOCK_NOLOCK : - AO2_ALLOC_OPT_LOCK_MUTEX, - 11, hash_cb, cmp_cb); - if (!cap->formats) { - ast_free(cap); - return NULL; - } + format_cap_init(cap, flags); return cap; } -void *ast_format_cap_destroy(struct ast_format_cap *cap) +struct ast_format_cap *__ast_format_cap_alloc_debug(enum ast_format_cap_flags flags, const char *tag, const char *file, int line, const char *func) { + struct ast_format_cap *cap; + + cap = __ao2_alloc_debug(sizeof(*cap), format_cap_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(tag, "ast_format_cap_alloc"), file, line, func, 1); if (!cap) { return NULL; } - ao2_ref(cap->formats, -1); - ast_free(cap); - return NULL; -} -static void format_cap_add(struct ast_format_cap *cap, const struct ast_format *format) -{ - struct ast_format *fnew; - - if (!format || !format->id) { - return; - } - if (!(fnew = ao2_alloc(sizeof(struct ast_format), NULL))) { - return; - } - ast_format_copy(fnew, format); - ao2_link(cap->formats, fnew); + format_cap_init(cap, flags); - ao2_ref(fnew, -1); + return cap; } -void ast_format_cap_add(struct ast_format_cap *cap, const struct ast_format *format) +void ast_format_cap_set_framing(struct ast_format_cap *cap, unsigned int framing) { - format_cap_add(cap, format); - cap->string_cache_valid = 0; + cap->framing = framing; } -void ast_format_cap_add_all_by_type(struct ast_format_cap *cap, enum ast_format_type type) +/*! \brief Destructor for format capabilities framed structure */ +static void format_cap_framed_destroy(void *obj) { - int x; - size_t f_len = 0; - const struct ast_format_list *f_list = ast_format_list_get(&f_len); + struct format_cap_framed *framed = obj; - for (x = 0; x < f_len; x++) { - if (AST_FORMAT_GET_TYPE(f_list[x].format.id) == type) { - format_cap_add(cap, &f_list[x].format); - } - } - cap->string_cache_valid = 0; - ast_format_list_destroy(f_list); + ao2_cleanup(framed->format); } -void ast_format_cap_add_all(struct ast_format_cap *cap) +static inline int format_cap_framed_init(struct format_cap_framed *framed, struct ast_format_cap *cap, struct ast_format *format, unsigned int framing) { - int x; - size_t f_len = 0; - const struct ast_format_list *f_list = ast_format_list_get(&f_len); + struct format_cap_framed_list *list; - for (x = 0; x < f_len; x++) { - format_cap_add(cap, &f_list[x].format); + framed->framing = framing; + + if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) { + if (AST_VECTOR_INSERT(&cap->formats, ast_format_get_codec_id(format), format_cap_framed_list_empty)) { + ao2_ref(framed, -1); + return -1; + } } - cap->string_cache_valid = 0; - ast_format_list_destroy(f_list); -} + list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format)); -static int append_cb(void *obj, void *arg, int flag) -{ - struct ast_format_cap *result = (struct ast_format_cap *) arg; - struct ast_format *format = (struct ast_format *) obj; + /* Order doesn't matter for formats, so insert at the head for performance reasons */ + ao2_ref(framed, +1); + AST_LIST_INSERT_HEAD(list, framed, entry); - if (!ast_format_cap_iscompatible(result, format)) { - format_cap_add(result, format); - } + /* This takes the allocation reference */ + AST_VECTOR_APPEND(&cap->preference_order, framed); + + cap->framing = MIN(cap->framing, framing ? framing : ast_format_get_default_ms(format)); return 0; } -void ast_format_cap_append(struct ast_format_cap *dst, const struct ast_format_cap *src) +/*! \internal \brief Determine if \c format is in \c cap */ +static int format_in_format_cap(struct ast_format_cap *cap, struct ast_format *format) { - ao2_callback(src->formats, OBJ_NODATA, append_cb, dst); - dst->string_cache_valid = 0; -} + struct format_cap_framed *framed; + int i; -static int copy_cb(void *obj, void *arg, int flag) -{ - struct ast_format_cap *result = (struct ast_format_cap *) arg; - struct ast_format *format = (struct ast_format *) obj; + for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) { + framed = AST_VECTOR_GET(&cap->preference_order, i); + + if (ast_format_get_codec_id(format) == ast_format_get_codec_id(framed->format)) { + return 1; + } + } - format_cap_add(result, format); return 0; } -static void format_cap_remove_all(struct ast_format_cap *cap) +int __ast_format_cap_append(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing) { - ao2_callback(cap->formats, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, NULL, NULL); -} + struct format_cap_framed *framed; -void ast_format_cap_copy(struct ast_format_cap *dst, const struct ast_format_cap *src) -{ - format_cap_remove_all(dst); - ao2_callback(src->formats, OBJ_NODATA, copy_cb, dst); - dst->string_cache_valid = 0; -} + ast_assert(format != NULL); -struct ast_format_cap *ast_format_cap_dup(const struct ast_format_cap *cap) -{ - struct ast_format_cap *dst; + if (format_in_format_cap(cap, format)) { + return 0; + } - dst = ast_format_cap_alloc(ast_test_flag(&cap->flags, AST_FLAGS_ALL)); - if (!dst) { - return NULL; + framed = ao2_alloc_options(sizeof(*framed), format_cap_framed_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!framed) { + return -1; } - ao2_callback(cap->formats, OBJ_NODATA, copy_cb, dst); - dst->string_cache_valid = 0; - return dst; + framed->format = ao2_bump(format); + + return format_cap_framed_init(framed, cap, format, framing); } -int ast_format_cap_is_empty(const struct ast_format_cap *cap) +int __ast_format_cap_append_debug(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing, const char *tag, const char *file, int line, const char *func) { - if (!cap) { - return 1; + struct format_cap_framed *framed; + + ast_assert(format != NULL); + + if (format_in_format_cap(cap, format)) { + return 0; } - return ao2_container_count(cap->formats) == 0 ? 1 : 0; -} -static int find_exact_cb(void *obj, void *arg, int flag) -{ - struct ast_format *format1 = (struct ast_format *) arg; - struct ast_format *format2 = (struct ast_format *) obj; + framed = ao2_alloc_options(sizeof(*framed), format_cap_framed_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!framed) { + return -1; + } - return (ast_format_cmp(format1, format2) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH : 0; + __ao2_ref_debug(format, +1, S_OR(tag, "ast_format_cap_append"), file, line, func); + framed->format = format; + + return format_cap_framed_init(framed, cap, format, framing); } -int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format) +int ast_format_cap_append_by_type(struct ast_format_cap *cap, enum ast_media_type type) { - struct ast_format *fremove; + int id; - fremove = ao2_callback(cap->formats, OBJ_POINTER | OBJ_UNLINK, find_exact_cb, format); - if (fremove) { - ao2_ref(fremove, -1); - cap->string_cache_valid = 0; - return 0; + for (id = 1; id < ast_codec_get_max(); ++id) { + struct ast_codec *codec = ast_codec_get_by_id(id); + struct ast_format *format; + int res; + + if (!codec) { + continue; + } + + if ((type != AST_MEDIA_TYPE_UNKNOWN) && codec->type != type) { + ao2_ref(codec, -1); + continue; + } + + format = ast_format_create(codec); + ao2_ref(codec, -1); + + if (!format) { + return -1; + } + + /* Use the global framing or default framing of the codec */ + res = ast_format_cap_append(cap, format, 0); + ao2_ref(format, -1); + + if (res) { + return -1; + } } - return -1; + return 0; } -struct multiple_by_id_data { - struct ast_format *format; - int match_found; -}; - -static int multiple_by_id_cb(void *obj, void *arg, int flag) +int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src, + enum ast_media_type type) { - struct multiple_by_id_data *data = arg; - struct ast_format *format = obj; - int res; + int idx, res = 0; + + for (idx = 0; (idx < AST_VECTOR_SIZE(&src->preference_order)) && !res; ++idx) { + struct format_cap_framed *framed = AST_VECTOR_GET(&src->preference_order, idx); - res = (format->id == data->format->id) ? CMP_MATCH : 0; - if (res) { - data->match_found = 1; + if (type == AST_MEDIA_TYPE_UNKNOWN || ast_format_get_type(framed->format) == type) { + res = ast_format_cap_append(dst, framed->format, framed->framing); + } } return res; } -int ast_format_cap_remove_byid(struct ast_format_cap *cap, enum ast_format_id id) +static int format_cap_replace(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing) { - struct ast_format format = { - .id = id, - }; - struct multiple_by_id_data data = { - .format = &format, - .match_found = 0, - }; - - ao2_callback(cap->formats, - OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, - multiple_by_id_cb, - &data); - - /* match_found will be set if at least one item was removed */ - if (data.match_found) { - cap->string_cache_valid = 0; - return 0; + struct format_cap_framed *framed; + int i; + + ast_assert(format != NULL); + + for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) { + framed = AST_VECTOR_GET(&cap->preference_order, i); + + if (ast_format_get_codec_id(format) == ast_format_get_codec_id(framed->format)) { + ao2_t_replace(framed->format, format, "replacing with new format"); + framed->framing = framing; + return 0; + } } return -1; } -static int multiple_by_type_cb(void *obj, void *arg, int flag) +void ast_format_cap_replace_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src, + enum ast_media_type type) { - int *type = arg; - struct ast_format *format = obj; - return ((AST_FORMAT_GET_TYPE(format->id)) == *type) ? CMP_MATCH : 0; -} + int idx; -void ast_format_cap_remove_bytype(struct ast_format_cap *cap, enum ast_format_type type) -{ - ao2_callback(cap->formats, - OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, - multiple_by_type_cb, - &type); - cap->string_cache_valid = 0; + for (idx = 0; (idx < AST_VECTOR_SIZE(&src->preference_order)); ++idx) { + struct format_cap_framed *framed = AST_VECTOR_GET(&src->preference_order, idx); + + if (type == AST_MEDIA_TYPE_UNKNOWN || ast_format_get_type(framed->format) == type) { + format_cap_replace(dst, framed->format, framed->framing); + } + } } -void ast_format_cap_remove_all(struct ast_format_cap *cap) +int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const char *list, int allowing) { - format_cap_remove_all(cap); - cap->string_cache_valid = 0; + int res = 0, all = 0, iter_allowing; + char *parse = NULL, *this = NULL, *psize = NULL; + + parse = ast_strdupa(list); + while ((this = strsep(&parse, ","))) { + int framems = 0; + struct ast_format *format = NULL; + + iter_allowing = allowing; + if (*this == '!') { + this++; + iter_allowing = !allowing; + } + if ((psize = strrchr(this, ':'))) { + *psize++ = '\0'; + ast_debug(1, "Packetization for codec: %s is %s\n", this, psize); + if (!sscanf(psize, "%30d", &framems) || (framems < 0)) { + framems = 0; + res = -1; + ast_log(LOG_WARNING, "Bad packetization value for codec %s\n", this); + continue; + } + } + all = strcasecmp(this, "all") ? 0 : 1; + + if (!all && !(format = ast_format_cache_get(this))) { + ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", iter_allowing ? "allow" : "disallow", this); + res = -1; + continue; + } + + if (cap) { + if (iter_allowing) { + if (all) { + ast_format_cap_append_by_type(cap, AST_MEDIA_TYPE_UNKNOWN); + } else { + ast_format_cap_append(cap, format, framems); + } + } else { + if (all) { + ast_format_cap_remove_by_type(cap, AST_MEDIA_TYPE_UNKNOWN); + } else { + ast_format_cap_remove(cap, format); + } + } + } + + ao2_cleanup(format); + } + return res; } -void ast_format_cap_set(struct ast_format_cap *cap, struct ast_format *format) +size_t ast_format_cap_count(const struct ast_format_cap *cap) { - format_cap_remove_all(cap); - format_cap_add(cap, format); - cap->string_cache_valid = 0; + return AST_VECTOR_SIZE(&cap->preference_order); } -int ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format, struct ast_format *result) +struct ast_format *ast_format_cap_get_format(const struct ast_format_cap *cap, int position) { - struct ast_format *f; - struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap; + struct format_cap_framed *framed; + + ast_assert(position < AST_VECTOR_SIZE(&cap->preference_order)); - f = ao2_find(tmp_cap->formats, format, OBJ_POINTER); - if (f) { - ast_format_copy(result, f); - ao2_ref(f, -1); - return 1; + if (position >= AST_VECTOR_SIZE(&cap->preference_order)) { + return NULL; } - ast_format_clear(result); - return 0; + + framed = AST_VECTOR_GET(&cap->preference_order, position); + + ast_assert(framed->format != ast_format_none); + ao2_ref(framed->format, +1); + return framed->format; } -int ast_format_cap_iscompatible(const struct ast_format_cap *cap, const struct ast_format *format) +struct ast_format *ast_format_cap_get_best_by_type(const struct ast_format_cap *cap, enum ast_media_type type) { - struct ast_format *f; - struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap; + int i; - if (!tmp_cap) { - return 0; + if (type == AST_MEDIA_TYPE_UNKNOWN) { + return ast_format_cap_get_format(cap, 0); } - f = ao2_find(tmp_cap->formats, format, OBJ_POINTER); - if (f) { - ao2_ref(f, -1); - return 1; + for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) { + struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, i); + + if (ast_format_get_type(framed->format) == type) { + ao2_ref(framed->format, +1); + ast_assert(framed->format != ast_format_none); + return framed->format; + } } - return 0; + return NULL; } -struct byid_data { - struct ast_format *result; - enum ast_format_id id; -}; -static int find_best_byid_cb(void *obj, void *arg, int flag) +unsigned int ast_format_cap_get_framing(const struct ast_format_cap *cap) { - struct ast_format *format = obj; - struct byid_data *data = arg; + return (cap->framing != UINT_MAX) ? cap->framing : 0; +} - if (data->id != format->id) { +unsigned int ast_format_cap_get_format_framing(const struct ast_format_cap *cap, const struct ast_format *format) +{ + unsigned int framing; + struct format_cap_framed_list *list; + struct format_cap_framed *framed, *result = NULL; + + if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) { return 0; } - if (!data->result->id || (ast_format_rate(data->result) < ast_format_rate(format))) { - ast_format_copy(data->result, format); + + framing = cap->framing != UINT_MAX ? cap->framing : ast_format_get_default_ms(format); + list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format)); + + AST_LIST_TRAVERSE(list, framed, entry) { + enum ast_format_cmp_res res = ast_format_cmp(format, framed->format); + + if (res == AST_FORMAT_CMP_NOT_EQUAL) { + continue; + } + + result = framed; + + if (res == AST_FORMAT_CMP_EQUAL) { + break; + } } - return 0; -} -int ast_format_cap_best_byid(const struct ast_format_cap *cap, enum ast_format_id id, struct ast_format *result) -{ - struct byid_data data; - data.result = result; - data.id = id; - - ast_format_clear(result); - ao2_callback(cap->formats, - OBJ_MULTIPLE | OBJ_NODATA, - find_best_byid_cb, - &data); - return result->id ? 1 : 0; + if (result && result->framing) { + framing = result->framing; + } + + return framing; } -/*! \internal - * \brief this struct is just used for the ast_format_cap_joint function so we can provide - * both a format and a result ast_format_cap structure as arguments to the find_joint_cb - * ao2 callback function. +/*! + * \brief format_cap_framed comparator for AST_VECTOR_REMOVE_CMP_ORDERED() + * + * \param elem Element to compare against + * \param value Value to compare with the vector element. + * + * \return 0 if element does not match. + * \return Non-zero if element matches. */ -struct find_joint_data { - /*! format to compare to for joint capabilities */ - struct ast_format *format; - /*! if joint formmat exists with above format, add it to the result container */ - struct ast_format_cap *joint_cap; - int joint_found; -}; +#define FORMAT_CAP_FRAMED_ELEM_CMP(elem, value) ((elem)->format == (value)) -static int find_joint_cb(void *obj, void *arg, int flag) +/*! + * \brief format_cap_framed vector element cleanup. + * + * \param elem Element to cleanup + * + * \return Nothing + */ +#define FORMAT_CAP_FRAMED_ELEM_CLEANUP(elem) ao2_cleanup((elem)) + +int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format) { - struct ast_format *format = obj; - struct find_joint_data *data = arg; + struct format_cap_framed_list *list; + struct format_cap_framed *framed; - struct ast_format tmp = { 0, }; - if (!ast_format_joint(format, data->format, &tmp)) { - if (data->joint_cap) { - ast_format_cap_add(data->joint_cap, &tmp); - } - data->joint_found++; + ast_assert(format != NULL); + + if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) { + return -1; } - return 0; -} + list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format)); -int ast_format_cap_has_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2) -{ - struct ao2_iterator it; - struct ast_format *tmp; - struct find_joint_data data = { - .joint_found = 0, - .joint_cap = NULL, - }; - - it = ao2_iterator_init(cap1->formats, 0); - while ((tmp = ao2_iterator_next(&it))) { - data.format = tmp; - ao2_callback(cap2->formats, - OBJ_MULTIPLE | OBJ_NODATA, - find_joint_cb, - &data); - ao2_ref(tmp, -1); + AST_LIST_TRAVERSE_SAFE_BEGIN(list, framed, entry) { + if (!FORMAT_CAP_FRAMED_ELEM_CMP(framed, format)) { + continue; + } + + AST_LIST_REMOVE_CURRENT(entry); + FORMAT_CAP_FRAMED_ELEM_CLEANUP(framed); + break; } - ao2_iterator_destroy(&it); + AST_LIST_TRAVERSE_SAFE_END; - return data.joint_found ? 1 : 0; + return AST_VECTOR_REMOVE_CMP_ORDERED(&cap->preference_order, format, + FORMAT_CAP_FRAMED_ELEM_CMP, FORMAT_CAP_FRAMED_ELEM_CLEANUP); } -int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2) +void ast_format_cap_remove_by_type(struct ast_format_cap *cap, enum ast_media_type type) { - struct ao2_iterator it; - struct ast_format *tmp; + int idx; - if (ao2_container_count(cap1->formats) != ao2_container_count(cap2->formats)) { - return 0; /* if they are not the same size, they are not identical */ - } + for (idx = 0; idx < AST_VECTOR_SIZE(&cap->formats); ++idx) { + struct format_cap_framed_list *list = AST_VECTOR_GET_ADDR(&cap->formats, idx); + struct format_cap_framed *framed; - it = ao2_iterator_init(cap1->formats, 0); - while ((tmp = ao2_iterator_next(&it))) { - if (!ast_format_cap_iscompatible(cap2, tmp)) { - ao2_ref(tmp, -1); - ao2_iterator_destroy(&it); - return 0; + AST_LIST_TRAVERSE_SAFE_BEGIN(list, framed, entry) { + if ((type != AST_MEDIA_TYPE_UNKNOWN) && + ast_format_get_type(framed->format) != type) { + continue; + } + + AST_LIST_REMOVE_CURRENT(entry); + AST_VECTOR_REMOVE_CMP_ORDERED(&cap->preference_order, framed->format, + FORMAT_CAP_FRAMED_ELEM_CMP, FORMAT_CAP_FRAMED_ELEM_CLEANUP); + ao2_ref(framed, -1); } - ao2_ref(tmp, -1); + AST_LIST_TRAVERSE_SAFE_END; } - ao2_iterator_destroy(&it); - - return 1; } -struct ast_format_cap *ast_format_cap_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2) +struct ast_format *ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format) { - struct ao2_iterator it; - struct ast_format_cap *result = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - struct ast_format *tmp; - struct find_joint_data data = { - .joint_found = 0, - .joint_cap = result, - }; - if (!result) { + struct format_cap_framed_list *list; + struct format_cap_framed *framed; + struct ast_format *result = NULL; + + ast_assert(format != NULL); + + if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) { return NULL; } - it = ao2_iterator_init(cap1->formats, 0); - while ((tmp = ao2_iterator_next(&it))) { - data.format = tmp; - ao2_callback(cap2->formats, - OBJ_MULTIPLE | OBJ_NODATA, - find_joint_cb, - &data); - ao2_ref(tmp, -1); - } - ao2_iterator_destroy(&it); + list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format)); - if (ao2_container_count(result->formats)) { - return result; - } + AST_LIST_TRAVERSE(list, framed, entry) { + enum ast_format_cmp_res res = ast_format_cmp(format, framed->format); - result = ast_format_cap_destroy(result); - return NULL; -} + if (res == AST_FORMAT_CMP_NOT_EQUAL) { + continue; + } -static int joint_copy_helper(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result, int append) -{ - struct ao2_iterator it; - struct ast_format *tmp; - struct find_joint_data data = { - .joint_cap = result, - .joint_found = 0, - }; - if (!append) { - format_cap_remove_all(result); - } - it = ao2_iterator_init(cap1->formats, 0); - while ((tmp = ao2_iterator_next(&it))) { - data.format = tmp; - ao2_callback(cap2->formats, - OBJ_MULTIPLE | OBJ_NODATA, - find_joint_cb, - &data); - ao2_ref(tmp, -1); - } - ao2_iterator_destroy(&it); + /* Replace any current result, this one will also be a subset OR an exact match */ + ao2_cleanup(result); - result->string_cache_valid = 0; + result = ast_format_joint(format, framed->format); - return ao2_container_count(result->formats) ? 1 : 0; -} + /* If it's a match we can do no better so return asap */ + if (res == AST_FORMAT_CMP_EQUAL) { + break; + } + } -int ast_format_cap_joint_append(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result) -{ - return joint_copy_helper(cap1, cap2, result, 1); + return result; } -int ast_format_cap_joint_copy(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result) +enum ast_format_cmp_res ast_format_cap_iscompatible_format(const struct ast_format_cap *cap, + const struct ast_format *format) { - return joint_copy_helper(cap1, cap2, result, 0); -} + enum ast_format_cmp_res res = AST_FORMAT_CMP_NOT_EQUAL; + struct format_cap_framed_list *list; + struct format_cap_framed *framed; -struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap, enum ast_format_type ftype) -{ - struct ao2_iterator it; - struct ast_format_cap *result = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - struct ast_format *tmp; + ast_assert(format != NULL); - if (!result) { - return NULL; + if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) { + return AST_FORMAT_CMP_NOT_EQUAL; } - /* for each format in cap1, see if that format is - * compatible with cap2. If so copy it to the result */ - it = ao2_iterator_init(cap->formats, 0); - while ((tmp = ao2_iterator_next(&it))) { - if (AST_FORMAT_GET_TYPE(tmp->id) == ftype) { - /* copy format */ - ast_format_cap_add(result, tmp); + list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format)); + + AST_LIST_TRAVERSE(list, framed, entry) { + enum ast_format_cmp_res cmp = ast_format_cmp(format, framed->format); + + if (cmp == AST_FORMAT_CMP_NOT_EQUAL) { + continue; } - ao2_ref(tmp, -1); - } - ao2_iterator_destroy(&it); - if (ao2_container_count(result->formats)) { - return result; + res = cmp; + + if (res == AST_FORMAT_CMP_EQUAL) { + break; + } } - result = ast_format_cap_destroy(result); - return NULL; + return res; } - -int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_type type) +int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_media_type type) { - struct ao2_iterator it; - struct ast_format *tmp; + int idx; - it = ao2_iterator_init(cap->formats, 0); - while ((tmp = ao2_iterator_next(&it))) { - if (AST_FORMAT_GET_TYPE(tmp->id) == type) { - ao2_ref(tmp, -1); - ao2_iterator_destroy(&it); + for (idx = 0; idx < AST_VECTOR_SIZE(&cap->preference_order); ++idx) { + struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, idx); + + if (ast_format_get_type(framed->format) == type) { return 1; } - ao2_ref(tmp, -1); } - ao2_iterator_destroy(&it); return 0; } -void ast_format_cap_iter_start(struct ast_format_cap *cap) +int ast_format_cap_get_compatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, + struct ast_format_cap *result) { - /* We can unconditionally lock even if the container has no lock. */ - ao2_lock(cap->formats); - cap->it = ao2_iterator_init(cap->formats, AO2_ITERATOR_DONTLOCK); -} + int idx, res = 0; -void ast_format_cap_iter_end(struct ast_format_cap *cap) -{ - ao2_iterator_destroy(&cap->it); - /* We can unconditionally unlock even if the container has no lock. */ - ao2_unlock(cap->formats); -} + for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) { + struct format_cap_framed *framed = AST_VECTOR_GET(&cap1->preference_order, idx); + struct ast_format *format; -int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *format) -{ - struct ast_format *tmp = ao2_iterator_next(&cap->it); + format = ast_format_cap_get_compatible_format(cap2, framed->format); + if (!format) { + continue; + } - if (!tmp) { - return -1; + res = ast_format_cap_append(result, format, framed->framing); + ao2_ref(format, -1); + + if (res) { + break; + } } - ast_format_copy(format, tmp); - ao2_ref(tmp, -1); - return 0; + return res; } -static char *getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap) +int ast_format_cap_iscompatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2) { - int x; - unsigned len; - char *start, *end = buf; - struct ast_format tmp_fmt; - size_t f_len; - const struct ast_format_list *f_list = ast_format_list_get(&f_len); - - if (!size) { - f_list = ast_format_list_destroy(f_list); - return buf; - } - snprintf(end, size, "("); - len = strlen(end); - end += len; - size -= len; - start = end; - for (x = 0; x < f_len; x++) { - ast_format_copy(&tmp_fmt, &f_list[x].format); - if (ast_format_cap_iscompatible(cap, &tmp_fmt)) { - snprintf(end, size, "%s|", f_list[x].name); - len = strlen(end); - end += len; - size -= len; + int idx; + + for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) { + struct format_cap_framed *framed = AST_VECTOR_GET(&cap1->preference_order, idx); + + if (ast_format_cap_iscompatible_format(cap2, framed->format) != AST_FORMAT_CMP_NOT_EQUAL) { + return 1; } } - if (start == end) { - ast_copy_string(start, "nothing)", size); - } else if (size > 1) { - *(end - 1) = ')'; - } - f_list = ast_format_list_destroy(f_list); - return buf; + + return 0; } -char *ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap) +static int internal_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2) { - if (ast_test_flag(&cap->flags, AST_FORMAT_CAP_FLAG_CACHE_STRINGS)) { - if (!cap->string_cache_valid) { - getformatname_multiple(cap->format_strs, FORMAT_STR_BUFSIZE, cap); - cap->string_cache_valid = 1; + int idx; + struct ast_format *tmp; + + for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) { + tmp = ast_format_cap_get_format(cap1, idx); + + if (ast_format_cap_iscompatible_format(cap2, tmp) != AST_FORMAT_CMP_EQUAL) { + ao2_ref(tmp, -1); + return 0; } - ast_copy_string(buf, cap->format_strs, size); - return buf; + + ao2_ref(tmp, -1); } - return getformatname_multiple(buf, size, cap); + return 1; } -uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap) +int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2) { - uint64_t res = 0; - struct ao2_iterator it; - struct ast_format *tmp; + if (AST_VECTOR_SIZE(&cap1->preference_order) != AST_VECTOR_SIZE(&cap2->preference_order)) { + return 0; /* if they are not the same size, they are not identical */ + } - it = ao2_iterator_init(cap->formats, 0); - while ((tmp = ao2_iterator_next(&it))) { - res |= ast_format_to_old_bitfield(tmp); - ao2_ref(tmp, -1); + if (!internal_format_cap_identical(cap1, cap2)) { + return 0; } - ao2_iterator_destroy(&it); - return res; + + return internal_format_cap_identical(cap2, cap1); } -void ast_format_cap_from_old_bitfield(struct ast_format_cap *dst, uint64_t src) +const char *ast_format_cap_get_names(struct ast_format_cap *cap, struct ast_str **buf) { - uint64_t tmp = 0; - int x; - struct ast_format tmp_format = { 0, }; - - format_cap_remove_all(dst); - for (x = 0; x < 64; x++) { - tmp = (1ULL << x); - if (tmp & src) { - format_cap_add(dst, ast_format_from_old_bitfield(&tmp_format, tmp)); + int i; + + ast_str_set(buf, 0, "("); + + if (!AST_VECTOR_SIZE(&cap->preference_order)) { + ast_str_append(buf, 0, "nothing)"); + return ast_str_buffer(*buf); + } + + for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); ++i) { + int res; + struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, i); + + res = ast_str_append(buf, 0, "%s%s", ast_format_get_name(framed->format), + i < AST_VECTOR_SIZE(&cap->preference_order) - 1 ? "|" : ""); + if (res < 0) { + break; } } - dst->string_cache_valid = 0; + ast_str_append(buf, 0, ")"); + + return ast_str_buffer(*buf); } diff --git a/main/format_compatibility.c b/main/format_compatibility.c new file mode 100644 index 000000000..df82bacd5 --- /dev/null +++ b/main/format_compatibility.c @@ -0,0 +1,274 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Joshua Colp <jcolp@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Media Format Bitfield Compatibility API + * + * \author Joshua Colp <jcolp@digium.com> + */ + +/*** MODULEINFO + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/logger.h" +#include "asterisk/astobj2.h" +#include "asterisk/codec.h" +#include "asterisk/format.h" +#include "asterisk/format_compatibility.h" +#include "asterisk/format_cache.h" + +uint64_t ast_format_compatibility_format2bitfield(const struct ast_format *format) +{ + if (ast_format_cmp(format, ast_format_g723) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_G723; + } else if (ast_format_cmp(format, ast_format_gsm) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_GSM; + } else if (ast_format_cmp(format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_ULAW; + } else if (ast_format_cmp(format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_ALAW; + } else if (ast_format_cmp(format, ast_format_g726_aal2) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_G726_AAL2; + } else if (ast_format_cmp(format, ast_format_adpcm) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_ADPCM; + } else if (ast_format_cmp(format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_SLIN; + } else if (ast_format_cmp(format, ast_format_lpc10) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_LPC10; + } else if (ast_format_cmp(format, ast_format_g729) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_G729; + } else if (ast_format_cmp(format, ast_format_speex) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_SPEEX; + } else if (ast_format_cmp(format, ast_format_ilbc) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_ILBC; + } else if (ast_format_cmp(format, ast_format_g726) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_G726; + } else if (ast_format_cmp(format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_G722; + } else if (ast_format_cmp(format, ast_format_siren7) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_SIREN7; + } else if (ast_format_cmp(format, ast_format_siren14) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_SIREN14; + } else if (ast_format_cmp(format, ast_format_slin16) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_SLIN16; + } else if (ast_format_cmp(format, ast_format_g719) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_G719; + } else if (ast_format_cmp(format, ast_format_speex16) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_SPEEX16; + } else if (ast_format_cmp(format, ast_format_opus) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_OPUS; + } else if (ast_format_cmp(format, ast_format_testlaw) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_TESTLAW; + } else if (ast_format_cmp(format, ast_format_h261) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_H261; + } else if (ast_format_cmp(format, ast_format_h263) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_H263; + } else if (ast_format_cmp(format, ast_format_h263p) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_H263P; + } else if (ast_format_cmp(format, ast_format_h264) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_H264; + } else if (ast_format_cmp(format, ast_format_mp4) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_MP4; + } else if (ast_format_cmp(format, ast_format_vp8) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_VP8; + } else if (ast_format_cmp(format, ast_format_jpeg) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_JPEG; + } else if (ast_format_cmp(format, ast_format_png) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_PNG; + } else if (ast_format_cmp(format, ast_format_t140_red) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_T140_RED; + } else if (ast_format_cmp(format, ast_format_t140) == AST_FORMAT_CMP_EQUAL) { + return AST_FORMAT_T140; + } + + return 0; +} + +uint64_t ast_format_compatibility_codec2bitfield(const struct ast_codec *codec) +{ + if (codec->id == ast_format_get_codec_id(ast_format_g723)) { + return AST_FORMAT_G723; + } else if (codec->id == ast_format_get_codec_id(ast_format_gsm)) { + return AST_FORMAT_GSM; + } else if (codec->id == ast_format_get_codec_id(ast_format_ulaw)) { + return AST_FORMAT_ULAW; + } else if (codec->id == ast_format_get_codec_id(ast_format_alaw)) { + return AST_FORMAT_ALAW; + } else if (codec->id == ast_format_get_codec_id(ast_format_g726_aal2)) { + return AST_FORMAT_G726_AAL2; + } else if (codec->id == ast_format_get_codec_id(ast_format_adpcm)) { + return AST_FORMAT_ADPCM; + } else if (codec->id == ast_format_get_codec_id(ast_format_slin)) { + return AST_FORMAT_SLIN; + } else if (codec->id == ast_format_get_codec_id(ast_format_lpc10)) { + return AST_FORMAT_LPC10; + } else if (codec->id == ast_format_get_codec_id(ast_format_g729)) { + return AST_FORMAT_G729; + } else if (codec->id == ast_format_get_codec_id(ast_format_speex)) { + return AST_FORMAT_SPEEX; + } else if (codec->id == ast_format_get_codec_id(ast_format_ilbc)) { + return AST_FORMAT_ILBC; + } else if (codec->id == ast_format_get_codec_id(ast_format_g726)) { + return AST_FORMAT_G726; + } else if (codec->id == ast_format_get_codec_id(ast_format_g722)) { + return AST_FORMAT_G722; + } else if (codec->id == ast_format_get_codec_id(ast_format_siren7)) { + return AST_FORMAT_SIREN7; + } else if (codec->id == ast_format_get_codec_id(ast_format_siren14)) { + return AST_FORMAT_SIREN14; + } else if (codec->id == ast_format_get_codec_id(ast_format_slin16)) { + return AST_FORMAT_SLIN16; + } else if (codec->id == ast_format_get_codec_id(ast_format_g719)) { + return AST_FORMAT_G719; + } else if (codec->id == ast_format_get_codec_id(ast_format_speex16)) { + return AST_FORMAT_SPEEX16; + } else if (codec->id == ast_format_get_codec_id(ast_format_opus)) { + return AST_FORMAT_OPUS; + } else if (codec->id == ast_format_get_codec_id(ast_format_testlaw)) { + return AST_FORMAT_TESTLAW; + } else if (codec->id == ast_format_get_codec_id(ast_format_h261)) { + return AST_FORMAT_H261; + } else if (codec->id == ast_format_get_codec_id(ast_format_h263)) { + return AST_FORMAT_H263; + } else if (codec->id == ast_format_get_codec_id(ast_format_h263p)) { + return AST_FORMAT_H263P; + } else if (codec->id == ast_format_get_codec_id(ast_format_h264)) { + return AST_FORMAT_H264; + } else if (codec->id == ast_format_get_codec_id(ast_format_mp4)) { + return AST_FORMAT_MP4; + } else if (codec->id == ast_format_get_codec_id(ast_format_vp8)) { + return AST_FORMAT_VP8; + } else if (codec->id == ast_format_get_codec_id(ast_format_jpeg)) { + return AST_FORMAT_JPEG; + } else if (codec->id == ast_format_get_codec_id(ast_format_png)) { + return AST_FORMAT_PNG; + } else if (codec->id == ast_format_get_codec_id(ast_format_t140_red)) { + return AST_FORMAT_T140_RED; + } else if (codec->id == ast_format_get_codec_id(ast_format_t140)) { + return AST_FORMAT_T140; + } + + return 0; +} + +struct ast_format *ast_format_compatibility_bitfield2format(uint64_t bitfield) +{ + switch (bitfield) { + /*! G.723.1 compression */ + case AST_FORMAT_G723: + return ast_format_g723; + /*! GSM compression */ + case AST_FORMAT_GSM: + return ast_format_gsm; + /*! Raw mu-law data (G.711) */ + case AST_FORMAT_ULAW: + return ast_format_ulaw; + /*! Raw A-law data (G.711) */ + case AST_FORMAT_ALAW: + return ast_format_alaw; + /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */ + case AST_FORMAT_G726_AAL2: + return ast_format_g726_aal2; + /*! ADPCM (IMA) */ + case AST_FORMAT_ADPCM: + return ast_format_adpcm; + /*! Raw 16-bit Signed Linear (8000 Hz) PCM */ + case AST_FORMAT_SLIN: + return ast_format_slin; + /*! LPC10, 180 samples/frame */ + case AST_FORMAT_LPC10: + return ast_format_lpc10; + /*! G.729A audio */ + case AST_FORMAT_G729: + return ast_format_g729; + /*! SpeeX Free Compression */ + case AST_FORMAT_SPEEX: + return ast_format_speex; + /*! iLBC Free Compression */ + case AST_FORMAT_ILBC: + return ast_format_ilbc; + /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */ + case AST_FORMAT_G726: + return ast_format_g726; + /*! G.722 */ + case AST_FORMAT_G722: + return ast_format_g722; + /*! G.722.1 (also known as Siren7, 32kbps assumed) */ + case AST_FORMAT_SIREN7: + return ast_format_siren7; + /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */ + case AST_FORMAT_SIREN14: + return ast_format_siren14; + /*! Raw 16-bit Signed Linear (16000 Hz) PCM */ + case AST_FORMAT_SLIN16: + return ast_format_slin16; + /*! G.719 (64 kbps assumed) */ + case AST_FORMAT_G719: + return ast_format_g719; + /*! SpeeX Wideband (16kHz) Free Compression */ + case AST_FORMAT_SPEEX16: + return ast_format_speex16; + /*! Opus audio (8kHz, 16kHz, 24kHz, 48Khz) */ + case AST_FORMAT_OPUS: + return ast_format_opus; + /*! Raw mu-law data (G.711) */ + case AST_FORMAT_TESTLAW: + return ast_format_testlaw; + + /*! H.261 Video */ + case AST_FORMAT_H261: + return ast_format_h261; + /*! H.263 Video */ + case AST_FORMAT_H263: + return ast_format_h263; + /*! H.263+ Video */ + case AST_FORMAT_H263P: + return ast_format_h263p; + /*! H.264 Video */ + case AST_FORMAT_H264: + return ast_format_h264; + /*! MPEG4 Video */ + case AST_FORMAT_MP4: + return ast_format_mp4; + /*! VP8 Video */ + case AST_FORMAT_VP8: + return ast_format_vp8; + + /*! JPEG Images */ + case AST_FORMAT_JPEG: + return ast_format_jpeg; + /*! PNG Images */ + case AST_FORMAT_PNG: + return ast_format_png; + + /*! T.140 RED Text format RFC 4103 */ + case AST_FORMAT_T140_RED: + return ast_format_t140; + /*! T.140 Text format - ITU T.140, RFC 4103 */ + case AST_FORMAT_T140: + return ast_format_t140_red; + } + return 0; +} + diff --git a/main/format_pref.c b/main/format_pref.c deleted file mode 100644 index b96184a08..000000000 --- a/main/format_pref.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2010, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! - * \file - * \brief Format Preference API - */ - -/*** MODULEINFO - <support_level>core</support_level> - ***/ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$"); - -#include "asterisk/_private.h" -#include "asterisk/frame.h" -#include "asterisk/channel.h" -#include "asterisk/utils.h" - -void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right) -{ - size_t f_len; - const struct ast_format_list *f_list = ast_format_list_get(&f_len); - int x, differential = (int) 'A', mem; - char *from, *to; - - /* TODO re-evaluate this function. It is using the order of the formats specified - * in the global format list in a way that may not be safe. */ - if (right) { - from = pref->order; - to = buf; - mem = size; - } else { - to = pref->order; - from = buf; - mem = AST_CODEC_PREF_SIZE; - } - - memset(to, 0, mem); - for (x = 0; x < AST_CODEC_PREF_SIZE; x++) { - if (!from[x]) { - break; - } - to[x] = right ? (from[x] + differential) : (from[x] - differential); - if (!right && to[x] && (to[x] < f_len)) { - ast_format_copy(&pref->formats[x], &f_list[to[x]-1].format); - } - } - ast_format_list_destroy(f_list); -} - -int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size) -{ - int x; - struct ast_format format; - size_t total_len, slen; - const char *formatname; - - memset(buf, 0, size); - total_len = size; - buf[0] = '('; - total_len--; - for (x = 0; x < AST_CODEC_PREF_SIZE; x++) { - if (total_len <= 0) - break; - if (!(ast_codec_pref_index(pref, x, &format))) - break; - if ((formatname = ast_getformatname(&format))) { - slen = strlen(formatname); - if (slen > total_len) - break; - strncat(buf, formatname, total_len - 1); /* safe */ - total_len -= slen; - } - if (total_len && x < AST_CODEC_PREF_SIZE - 1 && ast_codec_pref_index(pref, x + 1, &format)) { - strncat(buf, "|", total_len - 1); /* safe */ - total_len--; - } - } - if (total_len) { - strncat(buf, ")", total_len - 1); /* safe */ - total_len--; - } - - return size - total_len; -} - -struct ast_format *ast_codec_pref_index(struct ast_codec_pref *pref, int idx, struct ast_format *result) -{ - if ((idx >= 0) && (idx < sizeof(pref->order)) && pref->formats[idx].id) { - ast_format_copy(result, &pref->formats[idx]); - } else { - ast_format_clear(result); - return NULL; - } - - return result; -} - -/*! \brief Remove codec from pref list */ -void ast_codec_pref_remove(struct ast_codec_pref *pref, struct ast_format *format) -{ - struct ast_codec_pref oldorder; - int x, y = 0; - size_t f_len = 0; - const struct ast_format_list *f_list; - - if (!pref->order[0]) { - return; - } - - f_list = ast_format_list_get(&f_len); - memcpy(&oldorder, pref, sizeof(oldorder)); - memset(pref, 0, sizeof(*pref)); - - for (x = 0; x < f_len; x++) { - if (!oldorder.order[x]) { - break; - } - if (ast_format_cmp(&f_list[oldorder.order[x]-1].format, format) == AST_FORMAT_CMP_NOT_EQUAL) { - pref->order[y] = oldorder.order[x]; - ast_format_copy(&pref->formats[y], &oldorder.formats[x]); - pref->framing[y++] = oldorder.framing[x]; - } - } - ast_format_list_destroy(f_list); -} - -/*! \brief Append all codecs to a preference list, without distrubing existing order */ -void ast_codec_pref_append_all(struct ast_codec_pref *pref) -{ - int x, y, found; - size_t f_len = 0; - const struct ast_format_list *f_list = ast_format_list_get(&f_len); - - /* leave any existing entries, and don't create duplicates (e.g. allow=ulaw,all) */ - for (x = 0; x < f_len; x++) { - /* x = codec to add */ - found = 0; - for (y = 0; y < f_len; y++) { - /* y = scan of existing preferences */ - if (!pref->order[y]) { - break; - } - if (x + 1 == pref->order[y]) { - found = 1; - break; - } - } - if (found) { - continue; - } - for (; y < f_len; y++) { - /* add x to the end of y */ - if (!pref->order[y]) - { - pref->order[y] = x + 1; - ast_format_copy(&pref->formats[y], &f_list[x].format); - break; - } - } - } -} - -/*! \brief Append codec to list */ -int ast_codec_pref_append(struct ast_codec_pref *pref, struct ast_format *format) -{ - int x, newindex = 0; - size_t f_len = 0; - const struct ast_format_list *f_list = ast_format_list_get(&f_len); - - ast_codec_pref_remove(pref, format); - - for (x = 0; x < f_len; x++) { - if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) { - newindex = x + 1; - break; - } - } - - if (newindex) { - for (x = 0; x < f_len; x++) { - if (!pref->order[x]) { - pref->order[x] = newindex; - ast_format_copy(&pref->formats[x], format); - break; - } - } - } - - ast_format_list_destroy(f_list); - return x; -} - -/*! \brief Prepend codec to list */ -void ast_codec_pref_prepend(struct ast_codec_pref *pref, struct ast_format *format, int only_if_existing) -{ - int x, newindex = 0; - size_t f_len = 0; - const struct ast_format_list *f_list = ast_format_list_get(&f_len); - - /* First step is to get the codecs "index number" */ - for (x = 0; x < f_len; x++) { - if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) { - newindex = x + 1; - break; - } - } - /* Done if its unknown */ - if (!newindex) { - ast_format_list_destroy(f_list); - return; - } - - /* Now find any existing occurrence, or the end */ - for (x = 0; x < AST_CODEC_PREF_SIZE; x++) { - if (!pref->order[x] || pref->order[x] == newindex) - break; - } - - /* If we failed to find any occurrence, set to the end */ - if (x == AST_CODEC_PREF_SIZE) { - --x; - } - - if (only_if_existing && !pref->order[x]) { - ast_format_list_destroy(f_list); - return; - } - - /* Move down to make space to insert - either all the way to the end, - or as far as the existing location (which will be overwritten) */ - for (; x > 0; x--) { - pref->order[x] = pref->order[x - 1]; - pref->framing[x] = pref->framing[x - 1]; - ast_format_copy(&pref->formats[x], &pref->formats[x - 1]); - } - - /* And insert the new entry */ - pref->order[0] = newindex; - pref->framing[0] = 0; /* ? */ - ast_format_copy(&pref->formats[0], format); - ast_format_list_destroy(f_list); -} - -/*! \brief Set packet size for codec */ -int ast_codec_pref_setsize(struct ast_codec_pref *pref, struct ast_format *format, int framems) -{ - int x, idx = -1; - size_t f_len = 0; - const struct ast_format_list *f_list = ast_format_list_get(&f_len); - - for (x = 0; x < f_len; x++) { - if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) { - idx = x; - break; - } - } - - if (idx < 0) { - ast_format_list_destroy(f_list); - return -1; - } - - /* size validation */ - if (!framems) - framems = f_list[idx].def_ms; - - if (f_list[idx].inc_ms && framems % f_list[idx].inc_ms) /* avoid division by zero */ - framems -= framems % f_list[idx].inc_ms; - - if (framems < f_list[idx].min_ms) - framems = f_list[idx].min_ms; - - if (framems > f_list[idx].max_ms) - framems = f_list[idx].max_ms; - - for (x = 0; x < f_len; x++) { - if (pref->order[x] == (idx + 1)) { - pref->framing[x] = framems; - break; - } - } - - ast_format_list_destroy(f_list); - return x; -} - -/*! \brief Get packet size for codec */ -struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, struct ast_format *format) -{ - int x, idx = -1, framems = 0; - struct ast_format_list fmt = { { 0, }, }; - size_t f_len = 0; - const struct ast_format_list *f_list = ast_format_list_get(&f_len); - - for (x = 0; x < f_len; x++) { - if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) { - fmt = f_list[x]; - idx = x; - break; - } - } - - if (idx < 0) { - ast_log(AST_LOG_WARNING, "Format %s unknown; unable to get preferred codec packet size\n", ast_getformatname(format)); - ast_format_list_destroy(f_list); - return fmt; - } - - for (x = 0; x < f_len; x++) { - if (pref->order[x] == (idx + 1)) { - framems = pref->framing[x]; - break; - } - } - - /* size validation */ - if (!framems) - framems = f_list[idx].def_ms; - - if (f_list[idx].inc_ms && framems % f_list[idx].inc_ms) /* avoid division by zero */ - framems -= framems % f_list[idx].inc_ms; - - if (framems < f_list[idx].min_ms) - framems = f_list[idx].min_ms; - - if (framems > f_list[idx].max_ms) - framems = f_list[idx].max_ms; - - fmt.cur_ms = framems; - ast_format_list_destroy(f_list); - return fmt; -} - -/*! \brief Pick a codec */ -struct ast_format *ast_codec_choose(struct ast_codec_pref *pref, struct ast_format_cap *cap, int find_best, struct ast_format *result) -{ - int x, slot, found = 0; - size_t f_len = 0; - const struct ast_format_list *f_list = ast_format_list_get(&f_len); - - for (x = 0; x < f_len; x++) { - slot = pref->order[x]; - - if (!slot) - break; - if (ast_format_cap_get_compatible_format(cap, &f_list[slot-1].format, result)) { - found = 1; /*format is found and stored in result */ - break; - } - } - ast_format_list_destroy(f_list); - if (found && (AST_FORMAT_GET_TYPE(result->id) == AST_FORMAT_TYPE_AUDIO)) { - return result; - } - ast_format_clear(result); - ast_debug(4, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec"); - - return find_best ? ast_best_codec(cap, result) : NULL; -} - - diff --git a/main/frame.c b/main/frame.c index 76ea3f66c..64af88237 100644 --- a/main/frame.c +++ b/main/frame.c @@ -34,6 +34,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/_private.h" #include "asterisk/lock.h" #include "asterisk/frame.h" +#include "asterisk/format_cache.h" #include "asterisk/channel.h" #include "asterisk/cli.h" #include "asterisk/term.h" @@ -71,199 +72,8 @@ struct ast_frame_cache { }; #endif -#define SMOOTHER_SIZE 8000 - -enum frame_type { - TYPE_HIGH, /* 0x0 */ - TYPE_LOW, /* 0x1 */ - TYPE_SILENCE, /* 0x2 */ - TYPE_DONTSEND /* 0x3 */ -}; - -#define TYPE_MASK 0x3 - -struct ast_smoother { - int size; - struct ast_format format; - int flags; - float samplesperbyte; - unsigned int opt_needs_swap:1; - struct ast_frame f; - struct timeval delivery; - char data[SMOOTHER_SIZE]; - char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET]; - struct ast_frame *opt; - int len; -}; - struct ast_frame ast_null_frame = { AST_FRAME_NULL, }; -static int smoother_frame_feed(struct ast_smoother *s, struct ast_frame *f, int swap) -{ - if (s->flags & AST_SMOOTHER_FLAG_G729) { - if (s->len % 10) { - ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n"); - return 0; - } - } - if (swap) { - ast_swapcopy_samples(s->data + s->len, f->data.ptr, f->samples); - } else { - memcpy(s->data + s->len, f->data.ptr, f->datalen); - } - /* If either side is empty, reset the delivery time */ - if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery)) { /* XXX really ? */ - s->delivery = f->delivery; - } - s->len += f->datalen; - - return 0; -} - -void ast_smoother_reset(struct ast_smoother *s, int bytes) -{ - memset(s, 0, sizeof(*s)); - s->size = bytes; -} - -void ast_smoother_reconfigure(struct ast_smoother *s, int bytes) -{ - /* if there is no change, then nothing to do */ - if (s->size == bytes) { - return; - } - /* set the new desired output size */ - s->size = bytes; - /* if there is no 'optimized' frame in the smoother, - * then there is nothing left to do - */ - if (!s->opt) { - return; - } - /* there is an 'optimized' frame here at the old size, - * but it must now be put into the buffer so the data - * can be extracted at the new size - */ - smoother_frame_feed(s, s->opt, s->opt_needs_swap); - s->opt = NULL; -} - -struct ast_smoother *ast_smoother_new(int size) -{ - struct ast_smoother *s; - if (size < 1) - return NULL; - if ((s = ast_malloc(sizeof(*s)))) - ast_smoother_reset(s, size); - return s; -} - -int ast_smoother_get_flags(struct ast_smoother *s) -{ - return s->flags; -} - -void ast_smoother_set_flags(struct ast_smoother *s, int flags) -{ - s->flags = flags; -} - -int ast_smoother_test_flag(struct ast_smoother *s, int flag) -{ - return (s->flags & flag); -} - -int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap) -{ - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Huh? Can't smooth a non-voice frame!\n"); - return -1; - } - if (!s->format.id) { - ast_format_copy(&s->format, &f->subclass.format); - s->samplesperbyte = (float)f->samples / (float)f->datalen; - } else if (ast_format_cmp(&s->format, &f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { - ast_log(LOG_WARNING, "Smoother was working on %s format frames, now trying to feed %s?\n", - ast_getformatname(&s->format), ast_getformatname(&f->subclass.format)); - return -1; - } - if (s->len + f->datalen > SMOOTHER_SIZE) { - ast_log(LOG_WARNING, "Out of smoother space\n"); - return -1; - } - if (((f->datalen == s->size) || - ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729))) && - !s->opt && - !s->len && - (f->offset >= AST_MIN_OFFSET)) { - /* Optimize by sending the frame we just got - on the next read, thus eliminating the douple - copy */ - if (swap) - ast_swapcopy_samples(f->data.ptr, f->data.ptr, f->samples); - s->opt = f; - s->opt_needs_swap = swap ? 1 : 0; - return 0; - } - - return smoother_frame_feed(s, f, swap); -} - -struct ast_frame *ast_smoother_read(struct ast_smoother *s) -{ - struct ast_frame *opt; - int len; - - /* IF we have an optimization frame, send it */ - if (s->opt) { - if (s->opt->offset < AST_FRIENDLY_OFFSET) - ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).\n", - s->opt->offset); - opt = s->opt; - s->opt = NULL; - return opt; - } - - /* Make sure we have enough data */ - if (s->len < s->size) { - /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */ - if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->len % 10))) - return NULL; - } - len = s->size; - if (len > s->len) - len = s->len; - /* Make frame */ - s->f.frametype = AST_FRAME_VOICE; - ast_format_copy(&s->f.subclass.format, &s->format); - s->f.data.ptr = s->framedata + AST_FRIENDLY_OFFSET; - s->f.offset = AST_FRIENDLY_OFFSET; - s->f.datalen = len; - /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */ - s->f.samples = len * s->samplesperbyte; /* XXX rounding */ - s->f.delivery = s->delivery; - /* Fill Data */ - memcpy(s->f.data.ptr, s->data, len); - s->len -= len; - /* Move remaining data to the front if applicable */ - if (s->len) { - /* In principle this should all be fine because if we are sending - G.729 VAD, the next timestamp will take over anyawy */ - memmove(s->data, s->data + len, s->len); - if (!ast_tvzero(s->delivery)) { - /* If we have delivery time, increment it, otherwise, leave it at 0 */ - s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, ast_format_rate(&s->format))); - } - } - /* Return frame */ - return &s->f; -} - -void ast_smoother_free(struct ast_smoother *s) -{ - ast_free(s); -} - static struct ast_frame *ast_frame_header_new(void) { struct ast_frame *f; @@ -316,9 +126,13 @@ static void __frame_free(struct ast_frame *fr, int cache) /* Cool, only the header is malloc'd, let's just cache those for now * to keep things simple... */ struct ast_frame_cache *frames; - if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames))) && (frames->size < FRAME_CACHE_MAX_SIZE)) { + if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) || + (fr->frametype == AST_FRAME_IMAGE)) { + ao2_cleanup(fr->subclass.format); + } + AST_LIST_INSERT_HEAD(&frames->list, fr, frame_list); frames->size++; return; @@ -335,7 +149,14 @@ static void __frame_free(struct ast_frame *fr, int cache) ast_free((void *) fr->src); } if (fr->mallocd & AST_MALLOCD_HDR) { + if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) || + (fr->frametype == AST_FRAME_IMAGE)) { + ao2_cleanup(fr->subclass.format); + } + ast_free(fr); + } else { + fr->mallocd = 0; } } @@ -387,7 +208,12 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr) return NULL; } out->frametype = fr->frametype; - ast_format_copy(&out->subclass.format, &fr->subclass.format); + if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) || + (fr->frametype == AST_FRAME_IMAGE)) { + out->subclass.format = ao2_bump(fr->subclass.format); + } else { + memcpy(&out->subclass, &fr->subclass, sizeof(out->subclass)); + } out->datalen = fr->datalen; out->samples = fr->samples; out->offset = fr->offset; @@ -494,7 +320,12 @@ struct ast_frame *ast_frdup(const struct ast_frame *f) } out->frametype = f->frametype; - ast_format_copy(&out->subclass.format, &f->subclass.format); + if ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_VIDEO) || + (f->frametype == AST_FRAME_IMAGE)) { + out->subclass.format = ao2_bump(f->subclass.format); + } else { + memcpy(&out->subclass, &f->subclass, sizeof(out->subclass)); + } out->datalen = f->datalen; out->samples = f->samples; out->delivery = f->delivery; @@ -650,7 +481,7 @@ void ast_frame_subclass2str(struct ast_frame *f, char *subclass, size_t slen, ch } break; case AST_FRAME_IMAGE: - snprintf(subclass, slen, "Image format %s\n", ast_getformatname(&f->subclass.format)); + snprintf(subclass, slen, "Image format %s\n", ast_format_get_name(f->subclass.format)); break; case AST_FRAME_HTML: switch (f->subclass.integer) { @@ -816,369 +647,13 @@ void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix) term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn))); } -int ast_parse_allow_disallow(struct ast_codec_pref *pref, struct ast_format_cap *cap, const char *list, int allowing) -{ - int errors = 0, framems = 0, all = 0, iter_allowing; - char *parse = NULL, *this = NULL, *psize = NULL; - struct ast_format format; - - parse = ast_strdupa(list); - while ((this = strsep(&parse, ","))) { - iter_allowing = allowing; - framems = 0; - if (*this == '!') { - this++; - iter_allowing = !allowing; - } - if ((psize = strrchr(this, ':'))) { - *psize++ = '\0'; - ast_debug(1, "Packetization for codec: %s is %s\n", this, psize); - framems = atoi(psize); - if (framems < 0) { - framems = 0; - errors++; - ast_log(LOG_WARNING, "Bad packetization value for codec %s\n", this); - } - } - all = strcasecmp(this, "all") ? 0 : 1; - - if (!all && !ast_getformatbyname(this, &format)) { - ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", iter_allowing ? "allow" : "disallow", this); - errors++; - continue; - } - - if (cap) { - if (iter_allowing) { - if (all) { - ast_format_cap_add_all(cap); - } else { - ast_format_cap_add(cap, &format); - } - } else { - if (all) { - ast_format_cap_remove_all(cap); - } else { - ast_format_cap_remove(cap, &format); - } - } - } - - if (pref) { - if (!all) { - if (iter_allowing) { - ast_codec_pref_append(pref, &format); - ast_codec_pref_setsize(pref, &format, framems); - } else { - ast_codec_pref_remove(pref, &format); - } - } else if (!iter_allowing) { - memset(pref, 0, sizeof(*pref)); - } else { - ast_codec_pref_append_all(pref); - } - } - } - return errors; -} - -static int g723_len(unsigned char buf) -{ - enum frame_type type = buf & TYPE_MASK; - - switch(type) { - case TYPE_DONTSEND: - return 0; - break; - case TYPE_SILENCE: - return 4; - break; - case TYPE_HIGH: - return 24; - break; - case TYPE_LOW: - return 20; - break; - default: - ast_log(LOG_WARNING, "Badly encoded frame (%u)\n", type); - } - return -1; -} - -static int g723_samples(unsigned char *buf, int maxlen) -{ - int pos = 0; - int samples = 0; - int res; - while(pos < maxlen) { - res = g723_len(buf[pos]); - if (res <= 0) - break; - samples += 240; - pos += res; - } - return samples; -} - -static unsigned char get_n_bits_at(unsigned char *data, int n, int bit) -{ - int byte = bit / 8; /* byte containing first bit */ - int rem = 8 - (bit % 8); /* remaining bits in first byte */ - unsigned char ret = 0; - - if (n <= 0 || n > 8) - return 0; - - if (rem < n) { - ret = (data[byte] << (n - rem)); - ret |= (data[byte + 1] >> (8 - n + rem)); - } else { - ret = (data[byte] >> (rem - n)); - } - - return (ret & (0xff >> (8 - n))); -} - -static int speex_get_wb_sz_at(unsigned char *data, int len, int bit) -{ - static const int SpeexWBSubModeSz[] = { - 4, 36, 112, 192, - 352, 0, 0, 0 }; - int off = bit; - unsigned char c; - - /* skip up to two wideband frames */ - if (((len * 8 - off) >= 5) && - get_n_bits_at(data, 1, off)) { - c = get_n_bits_at(data, 3, off + 1); - off += SpeexWBSubModeSz[c]; - - if (((len * 8 - off) >= 5) && - get_n_bits_at(data, 1, off)) { - c = get_n_bits_at(data, 3, off + 1); - off += SpeexWBSubModeSz[c]; - - if (((len * 8 - off) >= 5) && - get_n_bits_at(data, 1, off)) { - ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n"); - return -1; - } - } - - } - return off - bit; -} - -static int speex_samples(unsigned char *data, int len) -{ - static const int SpeexSubModeSz[] = { - 5, 43, 119, 160, - 220, 300, 364, 492, - 79, 0, 0, 0, - 0, 0, 0, 0 }; - static const int SpeexInBandSz[] = { - 1, 1, 4, 4, - 4, 4, 4, 4, - 8, 8, 16, 16, - 32, 32, 64, 64 }; - int bit = 0; - int cnt = 0; - int off; - unsigned char c; - - while ((len * 8 - bit) >= 5) { - /* skip wideband frames */ - off = speex_get_wb_sz_at(data, len, bit); - if (off < 0) { - ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n"); - break; - } - bit += off; - - if ((len * 8 - bit) < 5) - break; - - /* get control bits */ - c = get_n_bits_at(data, 5, bit); - bit += 5; - - if (c == 15) { - /* terminator */ - break; - } else if (c == 14) { - /* in-band signal; next 4 bits contain signal id */ - c = get_n_bits_at(data, 4, bit); - bit += 4; - bit += SpeexInBandSz[c]; - } else if (c == 13) { - /* user in-band; next 4 bits contain msg len */ - c = get_n_bits_at(data, 4, bit); - bit += 4; - /* after which it's 5-bit signal id + c bytes of data */ - bit += 5 + c * 8; - } else if (c > 8) { - /* unknown */ - ast_log(LOG_WARNING, "Unknown speex control frame %d\n", c); - break; - } else { - /* skip number bits for submode (less the 5 control bits) */ - bit += SpeexSubModeSz[c] - 5; - cnt += 160; /* new frame */ - } - } - return cnt; -} - -int ast_codec_get_samples(struct ast_frame *f) -{ - int samples = 0; - - switch (f->subclass.format.id) { - case AST_FORMAT_SPEEX: - samples = speex_samples(f->data.ptr, f->datalen); - break; - case AST_FORMAT_SPEEX16: - samples = 2 * speex_samples(f->data.ptr, f->datalen); - break; - case AST_FORMAT_SPEEX32: - samples = 4 * speex_samples(f->data.ptr, f->datalen); - break; - case AST_FORMAT_G723_1: - samples = g723_samples(f->data.ptr, f->datalen); - break; - case AST_FORMAT_ILBC: - samples = 240 * (f->datalen / 50); - break; - case AST_FORMAT_GSM: - samples = 160 * (f->datalen / 33); - break; - case AST_FORMAT_G729A: - samples = f->datalen * 8; - break; - case AST_FORMAT_SLINEAR: - case AST_FORMAT_SLINEAR16: - samples = f->datalen / 2; - break; - case AST_FORMAT_LPC10: - /* assumes that the RTP packet contains one LPC10 frame */ - samples = 22 * 8; - samples += (((char *)(f->data.ptr))[7] & 0x1) * 8; - break; - case AST_FORMAT_ULAW: - case AST_FORMAT_ALAW: - case AST_FORMAT_TESTLAW: - samples = f->datalen; - break; - case AST_FORMAT_G722: - case AST_FORMAT_ADPCM: - case AST_FORMAT_G726: - case AST_FORMAT_G726_AAL2: - samples = f->datalen * 2; - break; - case AST_FORMAT_SIREN7: - /* 16,000 samples per second at 32kbps is 4,000 bytes per second */ - samples = f->datalen * (16000 / 4000); - break; - case AST_FORMAT_SIREN14: - /* 32,000 samples per second at 48kbps is 6,000 bytes per second */ - samples = (int) f->datalen * ((float) 32000 / 6000); - break; - case AST_FORMAT_G719: - /* 48,000 samples per second at 64kbps is 8,000 bytes per second */ - samples = (int) f->datalen * ((float) 48000 / 8000); - break; - case AST_FORMAT_SILK: - if (!(ast_format_isset(&f->subclass.format, - SILK_ATTR_KEY_SAMP_RATE, - SILK_ATTR_VAL_SAMP_24KHZ, - AST_FORMAT_ATTR_END))) { - return 480; - } else if (!(ast_format_isset(&f->subclass.format, - SILK_ATTR_KEY_SAMP_RATE, - SILK_ATTR_VAL_SAMP_16KHZ, - AST_FORMAT_ATTR_END))) { - return 320; - } else if (!(ast_format_isset(&f->subclass.format, - SILK_ATTR_KEY_SAMP_RATE, - SILK_ATTR_VAL_SAMP_12KHZ, - AST_FORMAT_ATTR_END))) { - return 240; - } else { - return 160; - } - case AST_FORMAT_CELT: - /* TODO This assumes 20ms delivery right now, which is incorrect */ - samples = ast_format_rate(&f->subclass.format) / 50; - break; - case AST_FORMAT_OPUS: - /* TODO This assumes 20ms delivery right now, which is incorrect */ - samples = 960; - break; - default: - ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(&f->subclass.format)); - } - return samples; -} - -int ast_codec_get_len(struct ast_format *format, int samples) -{ - int len = 0; - - /* XXX Still need speex, and lpc10 XXX */ - switch(format->id) { - case AST_FORMAT_G723_1: - len = (samples / 240) * 20; - break; - case AST_FORMAT_ILBC: - len = (samples / 240) * 50; - break; - case AST_FORMAT_GSM: - len = (samples / 160) * 33; - break; - case AST_FORMAT_G729A: - len = samples / 8; - break; - case AST_FORMAT_SLINEAR: - case AST_FORMAT_SLINEAR16: - len = samples * 2; - break; - case AST_FORMAT_ULAW: - case AST_FORMAT_ALAW: - case AST_FORMAT_TESTLAW: - len = samples; - break; - case AST_FORMAT_G722: - case AST_FORMAT_ADPCM: - case AST_FORMAT_G726: - case AST_FORMAT_G726_AAL2: - len = samples / 2; - break; - case AST_FORMAT_SIREN7: - /* 16,000 samples per second at 32kbps is 4,000 bytes per second */ - len = samples / (16000 / 4000); - break; - case AST_FORMAT_SIREN14: - /* 32,000 samples per second at 48kbps is 6,000 bytes per second */ - len = (int) samples / ((float) 32000 / 6000); - break; - case AST_FORMAT_G719: - /* 48,000 samples per second at 64kbps is 8,000 bytes per second */ - len = (int) samples / ((float) 48000 / 8000); - break; - default: - ast_log(LOG_WARNING, "Unable to calculate sample length for format %s\n", ast_getformatname(format)); - } - - return len; -} - int ast_frame_adjust_volume(struct ast_frame *f, int adjustment) { int count; short *fdata = f->data.ptr; short adjust_value = abs(adjustment); - if ((f->frametype != AST_FRAME_VOICE) || !(ast_format_is_slinear(&f->subclass.format))) { + if ((f->frametype != AST_FRAME_VOICE) || !(ast_format_cache_is_slinear(f->subclass.format))) { return -1; } @@ -1202,10 +677,10 @@ int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2) int count; short *data1, *data2; - if ((f1->frametype != AST_FRAME_VOICE) || (f1->subclass.format.id != AST_FORMAT_SLINEAR)) + if ((f1->frametype != AST_FRAME_VOICE) || (ast_format_cmp(f1->subclass.format, ast_format_slin) != AST_FORMAT_CMP_NOT_EQUAL)) return -1; - if ((f2->frametype != AST_FRAME_VOICE) || (f2->subclass.format.id != AST_FORMAT_SLINEAR)) + if ((f2->frametype != AST_FRAME_VOICE) || (ast_format_cmp(f2->subclass.format, ast_format_slin) != AST_FORMAT_CMP_NOT_EQUAL)) return -1; if (f1->samples != f2->samples) diff --git a/main/image.c b/main/image.c index 08620d734..53638f30c 100644 --- a/main/image.c +++ b/main/image.c @@ -114,7 +114,7 @@ struct ast_frame *ast_read_image(const char *filename, const char *preflang, str AST_RWLIST_RDLOCK(&imagers); AST_RWLIST_TRAVERSE(&imagers, i, list) { /* if NULL image format, just pick the first one, otherwise match it. */ - if (!format || (ast_format_cmp(&i->format, format) == AST_FORMAT_CMP_EQUAL)) { + if (!format || (ast_format_cmp(i->format, format) == AST_FORMAT_CMP_EQUAL)) { char *stringp=NULL; ast_copy_string(tmp, i->exts, sizeof(tmp)); stringp = tmp; @@ -194,7 +194,7 @@ static char *handle_core_show_image_formats(struct ast_cli_entry *e, int cmd, st ast_cli(a->fd, FORMAT, "----", "----------", "-----------", "------"); AST_RWLIST_RDLOCK(&imagers); AST_RWLIST_TRAVERSE(&imagers, i, list) { - ast_cli(a->fd, FORMAT2, i->name, i->exts, i->desc, ast_getformatname(&i->format)); + ast_cli(a->fd, FORMAT2, i->name, i->exts, i->desc, ast_format_get_name(i->format)); count_fmt++; } AST_RWLIST_UNLOCK(&imagers); diff --git a/main/indications.c b/main/indications.c index 2f2bdce62..27d2b5356 100644 --- a/main/indications.c +++ b/main/indications.c @@ -37,6 +37,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/linkedlists.h" #include "asterisk/indications.h" #include "asterisk/frame.h" +#include "asterisk/format_cache.h" #include "asterisk/channel.h" #include "asterisk/utils.h" #include "asterisk/cli.h" @@ -120,7 +121,7 @@ struct playtones_state { int npos; int oldnpos; int pos; - struct ast_format origwfmt; + struct ast_format *origwfmt; struct ast_frame f; unsigned char offset[AST_FRIENDLY_OFFSET]; short data[4000]; @@ -131,13 +132,11 @@ static void playtones_release(struct ast_channel *chan, void *params) struct playtones_state *ps = params; if (chan) { - ast_set_write_format(chan, &ps->origwfmt); + ast_set_write_format(chan, ps->origwfmt); } - if (ps->items) { - ast_free(ps->items); - ps->items = NULL; - } + ao2_cleanup(ps->origwfmt); + ast_free(ps->items); ast_free(ps); } @@ -151,9 +150,9 @@ static void *playtones_alloc(struct ast_channel *chan, void *params) return NULL; } - ast_format_copy(&ps->origwfmt, ast_channel_writeformat(chan)); + ps->origwfmt = ao2_bump(ast_channel_writeformat(chan)); - if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) { + if (ast_set_write_format(chan, ast_format_slin)) { ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", ast_channel_name(chan)); playtones_release(NULL, ps); ps = NULL; @@ -227,7 +226,7 @@ static int playtones_generator(struct ast_channel *chan, void *data, int len, in } ps->f.frametype = AST_FRAME_VOICE; - ast_format_set(&ps->f.subclass.format, AST_FORMAT_SLINEAR, 0); + ps->f.subclass.format = ast_format_slin; ps->f.datalen = len; ps->f.samples = samples; ps->f.offset = AST_FRIENDLY_OFFSET; diff --git a/main/manager.c b/main/manager.c index 75811886f..35ba5d46c 100644 --- a/main/manager.c +++ b/main/manager.c @@ -99,6 +99,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/bridge.h" #include "asterisk/features_config.h" #include "asterisk/rtp_engine.h" +#include "asterisk/format_cache.h" #include "asterisk/translate.h" /*** DOCUMENTATION @@ -3869,7 +3870,7 @@ static int action_status(struct mansession *s, const struct message *m) struct ast_str *write_transpath = ast_str_alloca(256); struct ast_str *read_transpath = ast_str_alloca(256); struct ast_channel *chan; - char nativeformats[256]; + struct ast_str *codec_buf = ast_str_alloca(64); int channels = 0; int all = ast_strlen_zero(name); /* set if we want all channels */ char id_text[256]; @@ -4007,10 +4008,10 @@ static int action_status(struct mansession *s, const struct message *m) ast_channel_linkedid(chan), ast_channel_appl(chan), ast_channel_data(chan), - ast_getformatname_multiple(nativeformats, sizeof(nativeformats), ast_channel_nativeformats(chan)), - ast_getformatname(ast_channel_readformat(chan)), + ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf), + ast_format_get_name(ast_channel_readformat(chan)), ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath), - ast_getformatname(ast_channel_writeformat(chan)), + ast_format_get_name(ast_channel_writeformat(chan)), ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath), ast_channel_callgroup(chan), ast_channel_pickupgroup(chan), @@ -4458,7 +4459,7 @@ struct fast_originate_helper { */ static void destroy_fast_originate_helper(struct fast_originate_helper *doomed) { - ast_format_cap_destroy(doomed->cap); + ao2_cleanup(doomed->cap); ast_variables_destroy(doomed->vars); ast_string_field_free_memory(doomed); ast_free(doomed); @@ -4781,8 +4782,7 @@ static int action_originate(struct mansession *s, const struct message *m) int reason = 0; char tmp[256]; char tmp2[256]; - struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - struct ast_format tmp_fmt; + struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); pthread_t th; int bridge_early = 0; @@ -4790,7 +4790,7 @@ static int action_originate(struct mansession *s, const struct message *m) astman_send_error(s, m, "Internal Error. Memory allocation failure."); return 0; } - ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(cap, ast_format_slin, 0); if ((assignedids.uniqueid && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid)) || (assignedids.uniqueid2 && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid2))) { @@ -4840,8 +4840,8 @@ static int action_originate(struct mansession *s, const struct message *m) } } if (!ast_strlen_zero(codecs)) { - ast_format_cap_remove_all(cap); - ast_parse_allow_disallow(NULL, cap, codecs, 1); + ast_format_cap_remove_by_type(cap, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_update_by_allow_disallow(cap, codecs, 1); } if (!ast_strlen_zero(app) && s->session) { @@ -4957,7 +4957,7 @@ static int action_originate(struct mansession *s, const struct message *m) } fast_orig_cleanup: - ast_format_cap_destroy(cap); + ao2_cleanup(cap); return 0; } diff --git a/main/media_index.c b/main/media_index.c index a643c237f..3e3824580 100644 --- a/main/media_index.c +++ b/main/media_index.c @@ -56,7 +56,7 @@ static void media_variant_destroy(void *obj) struct media_variant *variant = obj; ast_string_field_free_memory(variant); - variant->formats = ast_format_cap_destroy(variant->formats); + ao2_cleanup(variant->formats); } static struct media_variant *media_variant_alloc(const char *variant_str) @@ -67,7 +67,7 @@ static struct media_variant *media_variant_alloc(const char *variant_str) return NULL; } - variant->formats = ast_format_cap_alloc(0); + variant->formats = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!variant->formats) { return NULL; } @@ -239,6 +239,7 @@ const char *ast_media_get_description(struct ast_media_index *index, const char struct ast_format_cap *ast_media_get_format_cap(struct ast_media_index *index, const char *filename, const char *variant_str) { + struct ast_format_cap *dupcap; RAII_VAR(struct media_variant *, variant, NULL, ao2_cleanup); if (ast_strlen_zero(filename) || ast_strlen_zero(variant_str)) { return NULL; @@ -249,7 +250,11 @@ struct ast_format_cap *ast_media_get_format_cap(struct ast_media_index *index, c return NULL; } - return ast_format_cap_dup(variant->formats); + dupcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (dupcap) { + ast_format_cap_append_from_cap(dupcap, variant->formats, AST_MEDIA_TYPE_UNKNOWN); + } + return dupcap; } /*! \brief Add the variant to the list of variants requested */ @@ -317,7 +322,7 @@ struct ao2_container *ast_media_get_media(struct ast_media_index *index) } /*! \brief Update an index with new format/variant information */ -static int update_file_format_info(struct ast_media_index *index, const char *filename, const char *variant_str, const struct ast_format *file_format) +static int update_file_format_info(struct ast_media_index *index, const char *filename, const char *variant_str, struct ast_format *file_format) { RAII_VAR(struct media_variant *, variant, find_variant(index, filename, variant_str), ao2_cleanup); if (!variant) { @@ -327,14 +332,14 @@ static int update_file_format_info(struct ast_media_index *index, const char *fi } } - ast_format_cap_add(variant->formats, file_format); + ast_format_cap_append(variant->formats, file_format, 0); return 0; } /*! \brief Process a media file into the index */ static int process_media_file(struct ast_media_index *index, const char *variant, const char *subdir, const char *filename_stripped, const char *ext) { - const struct ast_format *file_format; + struct ast_format *file_format; const char *file_identifier = filename_stripped; RAII_VAR(struct ast_str *, file_id_str, NULL, ast_free); diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 9e3d7d108..07ef1f697 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -196,12 +196,18 @@ static AST_RWLIST_HEAD_STATIC(engines, ast_rtp_engine); /*! List of RTP glues */ static AST_RWLIST_HEAD_STATIC(glues, ast_rtp_glue); +#define MAX_RTP_MIME_TYPES 128 + /*! The following array defines the MIME Media type (and subtype) for each of our codecs, or RTP-specific data type. */ static struct ast_rtp_mime_type { + /*! \brief A mapping object between the Asterisk codec and this RTP payload */ struct ast_rtp_payload_type payload_type; - char *type; - char *subtype; + /*! \brief The media type */ + char type[16]; + /*! \brief The format type */ + char subtype[64]; + /*! \brief Expected sample rate of the /c subtype */ unsigned int sample_rate; } ast_rtp_mime_types[128]; /* This will Likely not need to grow any time soon. */ static ast_rwlock_t mime_types_lock; @@ -223,6 +229,24 @@ static ast_rwlock_t static_RTP_PT_lock; /*! \brief \ref stasis topic for RTP related messages */ static struct stasis_topic *rtp_topic; + +/*! \internal \brief Destructor for \c ast_rtp_payload_type */ +static void rtp_payload_type_dtor(void *obj) +{ + struct ast_rtp_payload_type *payload = obj; + + ao2_cleanup(payload->format); +} + +struct ast_rtp_payload_type *ast_rtp_engine_alloc_payload_type(void) +{ + struct ast_rtp_payload_type *payload; + + payload = ao2_alloc(sizeof(*payload), rtp_payload_type_dtor); + + return payload; +} + int ast_rtp_engine_register2(struct ast_rtp_engine *engine, struct ast_module *module) { struct ast_rtp_engine *current_engine; @@ -526,34 +550,30 @@ struct ast_rtp_codecs *ast_rtp_instance_get_codecs(struct ast_rtp_instance *inst return &instance->codecs; } -static int rtp_payload_type_hash(const void *obj, const int flags) +int ast_rtp_codecs_payloads_initialize(struct ast_rtp_codecs *codecs) { - const struct ast_rtp_payload_type *type = obj; - const int *payload = obj; + int res; + + codecs->framing = 0; + ast_rwlock_init(&codecs->codecs_lock); + res = AST_VECTOR_INIT(&codecs->payloads, AST_RTP_MAX_PT); - return (flags & OBJ_KEY) ? *payload : type->payload; + return res; } -static int rtp_payload_type_cmp(void *obj, void *arg, int flags) +void ast_rtp_codecs_payloads_destroy(struct ast_rtp_codecs *codecs) { - struct ast_rtp_payload_type *type1 = obj, *type2 = arg; - const int *payload = arg; + int i; - return (type1->payload == (OBJ_KEY ? *payload : type2->payload)) ? CMP_MATCH | CMP_STOP : 0; -} + for (i = 0; i < AST_VECTOR_SIZE(&codecs->payloads); i++) { + struct ast_rtp_payload_type *type; -int ast_rtp_codecs_payloads_initialize(struct ast_rtp_codecs *codecs) -{ - if (!(codecs->payloads = ao2_container_alloc(AST_RTP_MAX_PT, rtp_payload_type_hash, rtp_payload_type_cmp))) { - return -1; + type = AST_VECTOR_GET(&codecs->payloads, i); + ao2_t_cleanup(type, "destroying ast_rtp_codec"); } + AST_VECTOR_FREE(&codecs->payloads); - return 0; -} - -void ast_rtp_codecs_payloads_destroy(struct ast_rtp_codecs *codecs) -{ - ao2_cleanup(codecs->payloads); + ast_rwlock_destroy(&codecs->codecs_lock); } void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance) @@ -570,106 +590,69 @@ void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp ast_rtp_codecs_payloads_initialize(codecs); } -void ast_rtp_codecs_payloads_default(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance) -{ - int i; - - ast_rwlock_rdlock(&static_RTP_PT_lock); - for (i = 0; i < AST_RTP_MAX_PT; i++) { - if (static_RTP_PT[i].rtp_code || static_RTP_PT[i].asterisk_format) { - struct ast_rtp_payload_type *type; - - if (!(type = ao2_alloc(sizeof(*type), NULL))) { - /* Unfortunately if this occurs the payloads container will not contain all possible default payloads - * but we err on the side of doing what we can in the hopes that the extreme memory conditions which - * caused this to occur will go away. - */ - continue; - } - - type->payload = i; - type->asterisk_format = static_RTP_PT[i].asterisk_format; - type->rtp_code = static_RTP_PT[i].rtp_code; - ast_format_copy(&type->format, &static_RTP_PT[i].format); - - ao2_link_flags(codecs->payloads, type, OBJ_NOLOCK); - - if (instance && instance->engine && instance->engine->payload_set) { - instance->engine->payload_set(instance, i, type->asterisk_format, &type->format, type->rtp_code); - } - - ao2_ref(type, -1); - } - } - ast_rwlock_unlock(&static_RTP_PT_lock); -} - void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance) { int i; - struct ast_rtp_payload_type *type; - for (i = 0; i < AST_RTP_MAX_PT; i++) { - struct ast_rtp_payload_type *new_type; + ast_rwlock_rdlock(&src->codecs_lock); + ast_rwlock_wrlock(&dest->codecs_lock); - if (!(type = ao2_find(src->payloads, &i, OBJ_KEY | OBJ_NOLOCK))) { - continue; - } + for (i = 0; i < AST_VECTOR_SIZE(&src->payloads); i++) { + struct ast_rtp_payload_type *type; - if (!(new_type = ao2_alloc(sizeof(*new_type), NULL))) { + type = AST_VECTOR_GET(&src->payloads, i); + if (!type) { continue; } - - ast_debug(2, "Copying payload %d from %p to %p\n", i, src, dest); - - new_type->payload = i; - *new_type = *type; - - ao2_link_flags(dest->payloads, new_type, OBJ_NOLOCK); - - ao2_ref(new_type, -1); + if (i < AST_VECTOR_SIZE(&dest->payloads)) { + ao2_t_cleanup(AST_VECTOR_GET(&dest->payloads, i), "cleaning up vector element about to be replaced"); + } + ast_debug(2, "Copying payload %d (%p) from %p to %p\n", i, type, src, dest); + ao2_bump(type); + AST_VECTOR_INSERT(&dest->payloads, i, type); if (instance && instance->engine && instance->engine->payload_set) { - instance->engine->payload_set(instance, i, type->asterisk_format, &type->format, type->rtp_code); + instance->engine->payload_set(instance, i, type->asterisk_format, type->format, type->rtp_code); } - - ao2_ref(type, -1); } + dest->framing = src->framing; + ast_rwlock_unlock(&dest->codecs_lock); + ast_rwlock_unlock(&src->codecs_lock); } void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload) { - struct ast_rtp_payload_type *type; + struct ast_rtp_payload_type *new_type; - ast_rwlock_rdlock(&static_RTP_PT_lock); + new_type = ast_rtp_engine_alloc_payload_type(); + if (!new_type) { + return; + } + ast_rwlock_rdlock(&static_RTP_PT_lock); if (payload < 0 || payload >= AST_RTP_MAX_PT) { ast_rwlock_unlock(&static_RTP_PT_lock); return; } - if (!(type = ao2_find(codecs->payloads, &payload, OBJ_KEY | OBJ_NOLOCK))) { - if (!(type = ao2_alloc(sizeof(*type), NULL))) { - ast_rwlock_unlock(&static_RTP_PT_lock); - return; - } - type->payload = payload; - ao2_link_flags(codecs->payloads, type, OBJ_NOLOCK); + ast_rwlock_wrlock(&codecs->codecs_lock); + if (payload < AST_VECTOR_SIZE(&codecs->payloads)) { + ao2_t_cleanup(AST_VECTOR_GET(&codecs->payloads, payload), "cleaning up replaced payload type"); } - type->asterisk_format = static_RTP_PT[payload].asterisk_format; - type->rtp_code = static_RTP_PT[payload].rtp_code; - type->payload = payload; - ast_format_copy(&type->format, &static_RTP_PT[payload].format); + new_type->asterisk_format = static_RTP_PT[payload].asterisk_format; + new_type->rtp_code = static_RTP_PT[payload].rtp_code; + new_type->payload = payload; + new_type->format = ao2_bump(static_RTP_PT[payload].format); - ast_debug(1, "Setting payload %d based on m type on %p\n", payload, codecs); + ast_debug(1, "Setting payload %d (%p) based on m type on %p\n", payload, new_type, codecs); + AST_VECTOR_INSERT(&codecs->payloads, payload, new_type); if (instance && instance->engine && instance->engine->payload_set) { - instance->engine->payload_set(instance, payload, type->asterisk_format, &type->format, type->rtp_code); + instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code); } - ao2_ref(type, -1); - + ast_rwlock_unlock(&codecs->codecs_lock); ast_rwlock_unlock(&static_RTP_PT_lock); } @@ -681,13 +664,16 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, unsigned int i; int found = 0; - if (pt < 0 || pt >= AST_RTP_MAX_PT) + ast_rwlock_rdlock(&mime_types_lock); + if (pt < 0 || pt >= AST_RTP_MAX_PT) { + ast_rwlock_unlock(&mime_types_lock); return -1; /* bogus payload type */ + } - ast_rwlock_rdlock(&mime_types_lock); + ast_rwlock_wrlock(&codecs->codecs_lock); for (i = 0; i < mime_types_len; ++i) { const struct ast_rtp_mime_type *t = &ast_rtp_mime_types[i]; - struct ast_rtp_payload_type *type; + struct ast_rtp_payload_type *new_type; if (strcasecmp(mimesubtype, t->subtype)) { continue; @@ -707,29 +693,33 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, found = 1; - if (!(type = ao2_find(codecs->payloads, &pt, OBJ_KEY | OBJ_NOLOCK))) { - if (!(type = ao2_alloc(sizeof(*type), NULL))) { - continue; - } - type->payload = pt; - ao2_link_flags(codecs->payloads, type, OBJ_NOLOCK); + new_type = ast_rtp_engine_alloc_payload_type(); + if (!new_type) { + continue; } - *type = t->payload_type; - type->payload = pt; + if (pt < AST_VECTOR_SIZE(&codecs->payloads)) { + ao2_t_cleanup(AST_VECTOR_GET(&codecs->payloads, pt), "cleaning up replaced payload type"); + } - if ((t->payload_type.format.id == AST_FORMAT_G726) && t->payload_type.asterisk_format && (options & AST_RTP_OPT_G726_NONSTANDARD)) { - ast_format_set(&type->format, AST_FORMAT_G726_AAL2, 0); + new_type->payload = pt; + new_type->asterisk_format = t->payload_type.asterisk_format; + new_type->rtp_code = t->payload_type.rtp_code; + if ((ast_format_cmp(t->payload_type.format, ast_format_g726) == AST_FORMAT_CMP_EQUAL) && + t->payload_type.asterisk_format && (options & AST_RTP_OPT_G726_NONSTANDARD)) { + new_type->format = ao2_bump(ast_format_g726_aal2); + } else { + new_type->format = ao2_bump(t->payload_type.format); } + AST_VECTOR_INSERT(&codecs->payloads, pt, new_type); if (instance && instance->engine && instance->engine->payload_set) { - instance->engine->payload_set(instance, pt, type->asterisk_format, &type->format, type->rtp_code); + instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code); } - ao2_ref(type, -1); - break; } + ast_rwlock_unlock(&codecs->codecs_lock); ast_rwlock_unlock(&mime_types_lock); return (found ? 0 : -2); @@ -742,157 +732,209 @@ int ast_rtp_codecs_payloads_set_rtpmap_type(struct ast_rtp_codecs *codecs, struc void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload) { + struct ast_rtp_payload_type *type; + if (payload < 0 || payload >= AST_RTP_MAX_PT) { return; } ast_debug(2, "Unsetting payload %d on %p\n", payload, codecs); - ao2_find(codecs->payloads, &payload, OBJ_KEY | OBJ_NOLOCK | OBJ_NODATA | OBJ_UNLINK); + ast_rwlock_wrlock(&codecs->codecs_lock); + if (payload < AST_VECTOR_SIZE(&codecs->payloads)) { + type = AST_VECTOR_GET(&codecs->payloads, payload); + ao2_cleanup(type); + AST_VECTOR_INSERT(&codecs->payloads, payload, NULL); + } if (instance && instance->engine && instance->engine->payload_set) { instance->engine->payload_set(instance, payload, 0, NULL, 0); } + + ast_rwlock_unlock(&codecs->codecs_lock); } -struct ast_rtp_payload_type ast_rtp_codecs_payload_lookup(struct ast_rtp_codecs *codecs, int payload) +struct ast_rtp_payload_type *ast_rtp_codecs_get_payload(struct ast_rtp_codecs *codecs, int payload) { - struct ast_rtp_payload_type result = { .asterisk_format = 0, }, *type; + struct ast_rtp_payload_type *type = NULL; if (payload < 0 || payload >= AST_RTP_MAX_PT) { - return result; + return NULL; } - if ((type = ao2_find(codecs->payloads, &payload, OBJ_KEY | OBJ_NOLOCK))) { - result = *type; - ao2_ref(type, -1); + ast_rwlock_rdlock(&codecs->codecs_lock); + if (payload < AST_VECTOR_SIZE(&codecs->payloads)) { + type = AST_VECTOR_GET(&codecs->payloads, payload); + ao2_bump(type); } + ast_rwlock_unlock(&codecs->codecs_lock); - if (!result.rtp_code && !result.asterisk_format) { + if (!type) { + type = ast_rtp_engine_alloc_payload_type(); + if (!type) { + return NULL; + } ast_rwlock_rdlock(&static_RTP_PT_lock); - result = static_RTP_PT[payload]; + type->asterisk_format = static_RTP_PT[payload].asterisk_format; + type->rtp_code = static_RTP_PT[payload].rtp_code; + type->payload = payload; + type->format = ao2_bump(static_RTP_PT[payload].format); ast_rwlock_unlock(&static_RTP_PT_lock); } - return result; + return type; } +int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int payload, struct ast_format *format) +{ + struct ast_rtp_payload_type *type; + + if (payload < 0 || payload >= AST_RTP_MAX_PT) { + return -1; + } + + ast_rwlock_wrlock(&codecs->codecs_lock); + if (payload < AST_VECTOR_SIZE(&codecs->payloads)) { + type = AST_VECTOR_GET(&codecs->payloads, payload); + if (type && type->asterisk_format) { + ao2_replace(type->format, format); + } + } + ast_rwlock_unlock(&codecs->codecs_lock); + + return 0; +} struct ast_format *ast_rtp_codecs_get_payload_format(struct ast_rtp_codecs *codecs, int payload) { struct ast_rtp_payload_type *type; - struct ast_format *format; + struct ast_format *format = NULL; if (payload < 0 || payload >= AST_RTP_MAX_PT) { return NULL; } - if (!(type = ao2_find(codecs->payloads, &payload, OBJ_KEY | OBJ_NOLOCK))) { - return NULL; + ast_rwlock_rdlock(&codecs->codecs_lock); + if (payload < AST_VECTOR_SIZE(&codecs->payloads)) { + type = AST_VECTOR_GET(&codecs->payloads, payload); + if (type && type->asterisk_format) { + format = ao2_bump(type->format); + } } - - format = type->asterisk_format ? &type->format : NULL; - - ao2_ref(type, -1); + ast_rwlock_unlock(&codecs->codecs_lock); return format; } -static int rtp_payload_type_add_ast(void *obj, void *arg, int flags) +void ast_rtp_codecs_set_framing(struct ast_rtp_codecs *codecs, unsigned int framing) { - struct ast_rtp_payload_type *type = obj; - struct ast_format_cap *astformats = arg; - - if (type->asterisk_format) { - ast_format_cap_add(astformats, &type->format); + if (!framing) { + return; } - return 0; + ast_rwlock_wrlock(&codecs->codecs_lock); + codecs->framing = framing; + ast_rwlock_unlock(&codecs->codecs_lock); } -static int rtp_payload_type_add_nonast(void *obj, void *arg, int flags) +unsigned int ast_rtp_codecs_get_framing(struct ast_rtp_codecs *codecs) { - struct ast_rtp_payload_type *type = obj; - int *nonastformats = arg; + unsigned int framing; - if (!type->asterisk_format) { - *nonastformats |= type->rtp_code; - } + ast_rwlock_rdlock(&codecs->codecs_lock); + framing = codecs->framing; + ast_rwlock_unlock(&codecs->codecs_lock); - return 0; + return framing; } void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_format_cap *astformats, int *nonastformats) { - ast_format_cap_remove_all(astformats); + int i; + + ast_format_cap_remove_by_type(astformats, AST_MEDIA_TYPE_UNKNOWN); *nonastformats = 0; - ao2_callback(codecs->payloads, OBJ_NODATA | OBJ_MULTIPLE | OBJ_NOLOCK, rtp_payload_type_add_ast, astformats); - ao2_callback(codecs->payloads, OBJ_NODATA | OBJ_MULTIPLE | OBJ_NOLOCK, rtp_payload_type_add_nonast, nonastformats); -} + ast_rwlock_rdlock(&codecs->codecs_lock); + for (i = 0; i < AST_VECTOR_SIZE(&codecs->payloads); i++) { + struct ast_rtp_payload_type *type; -static int rtp_payload_type_find_format(void *obj, void *arg, int flags) -{ - struct ast_rtp_payload_type *type = obj; - struct ast_format *format = arg; + type = AST_VECTOR_GET(&codecs->payloads, i); + if (!type) { + continue; + } - return (type->asterisk_format && (ast_format_cmp(&type->format, format) != AST_FORMAT_CMP_NOT_EQUAL)) ? CMP_MATCH | CMP_STOP : 0; -} + if (type->asterisk_format) { + ast_format_cap_append(astformats, type->format, 0); + } else { + *nonastformats |= type->rtp_code; + } + } -static int rtp_payload_type_find_nonast_format(void *obj, void *arg, int flags) -{ - struct ast_rtp_payload_type *type = obj; - int *rtp_code = arg; + if (codecs->framing) { + ast_format_cap_set_framing(astformats, codecs->framing); + } - return ((!type->asterisk_format && (type->rtp_code == *rtp_code)) ? CMP_MATCH | CMP_STOP : 0); + ast_rwlock_unlock(&codecs->codecs_lock); } int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code) { struct ast_rtp_payload_type *type; - int i, res = -1; + int i; + int payload = -1; - if (asterisk_format && format && (type = ao2_callback(codecs->payloads, OBJ_NOLOCK, rtp_payload_type_find_format, (void*)format))) { - res = type->payload; - ao2_ref(type, -1); - return res; - } else if (!asterisk_format && (type = ao2_callback(codecs->payloads, OBJ_NOLOCK, rtp_payload_type_find_nonast_format, (void*)&code))) { - res = type->payload; - ao2_ref(type, -1); - return res; - } + ast_rwlock_rdlock(&codecs->codecs_lock); + for (i = 0; i < AST_VECTOR_SIZE(&codecs->payloads); i++) { + type = AST_VECTOR_GET(&codecs->payloads, i); + if (!type) { + continue; + } - ast_rwlock_rdlock(&static_RTP_PT_lock); - for (i = 0; i < AST_RTP_MAX_PT; i++) { - if (static_RTP_PT[i].asterisk_format && asterisk_format && format && - (ast_format_cmp(format, &static_RTP_PT[i].format) != AST_FORMAT_CMP_NOT_EQUAL)) { - res = i; - break; - } else if (!static_RTP_PT[i].asterisk_format && !asterisk_format && - (static_RTP_PT[i].rtp_code == code)) { - res = i; + if ((asterisk_format && format && ast_format_cmp(format, type->format) == AST_FORMAT_CMP_EQUAL) + || (!asterisk_format && type->rtp_code == code)) { + payload = i; break; } } - ast_rwlock_unlock(&static_RTP_PT_lock); + ast_rwlock_unlock(&codecs->codecs_lock); - return res; + if (payload < 0) { + ast_rwlock_rdlock(&static_RTP_PT_lock); + for (i = 0; i < AST_RTP_MAX_PT; i++) { + if (static_RTP_PT[i].asterisk_format && asterisk_format && format && + (ast_format_cmp(format, static_RTP_PT[i].format) != AST_FORMAT_CMP_NOT_EQUAL)) { + payload = i; + break; + } else if (!static_RTP_PT[i].asterisk_format && !asterisk_format && + (static_RTP_PT[i].rtp_code == code)) { + payload = i; + break; + } + } + ast_rwlock_unlock(&static_RTP_PT_lock); + } + + return payload; } + int ast_rtp_codecs_find_payload_code(struct ast_rtp_codecs *codecs, int code) { struct ast_rtp_payload_type *type; int res = -1; - /* Search the payload type in the codecs passed */ - if ((type = ao2_find(codecs->payloads, &code, OBJ_NOLOCK | OBJ_KEY))) - { - res = type->payload; - ao2_ref(type, -1); - return res; + ast_rwlock_rdlock(&codecs->codecs_lock); + if (code < AST_VECTOR_SIZE(&codecs->payloads)) { + type = AST_VECTOR_GET(&codecs->payloads, code); + if (type) { + res = type->payload; + } } + ast_rwlock_unlock(&codecs->codecs_lock); return res; } + const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, struct ast_format *format, int code, enum ast_rtp_options options) { int i; @@ -901,8 +943,9 @@ const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, struct ast_f ast_rwlock_rdlock(&mime_types_lock); for (i = 0; i < mime_types_len; i++) { if (ast_rtp_mime_types[i].payload_type.asterisk_format && asterisk_format && format && - (ast_format_cmp(format, &ast_rtp_mime_types[i].payload_type.format) != AST_FORMAT_CMP_NOT_EQUAL)) { - if ((format->id == AST_FORMAT_G726_AAL2) && (options & AST_RTP_OPT_G726_NONSTANDARD)) { + (ast_format_cmp(format, ast_rtp_mime_types[i].payload_type.format) != AST_FORMAT_CMP_NOT_EQUAL)) { + if ((ast_format_cmp(format, ast_format_g726_aal2) == AST_FORMAT_CMP_EQUAL) && + (options & AST_RTP_OPT_G726_NONSTANDARD)) { res = "G726-32"; break; } else { @@ -929,7 +972,7 @@ unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, struct ast_format ast_rwlock_rdlock(&mime_types_lock); for (i = 0; i < mime_types_len; ++i) { if (ast_rtp_mime_types[i].payload_type.asterisk_format && asterisk_format && format && - (ast_format_cmp(format, &ast_rtp_mime_types[i].payload_type.format) != AST_FORMAT_CMP_NOT_EQUAL)) { + (ast_format_cmp(format, ast_rtp_mime_types[i].payload_type.format) != AST_FORMAT_CMP_NOT_EQUAL)) { res = ast_rtp_mime_types[i].sample_rate; break; } else if (!ast_rtp_mime_types[i].payload_type.asterisk_format && !asterisk_format && @@ -953,15 +996,15 @@ char *ast_rtp_lookup_mime_multiple2(struct ast_str *buf, struct ast_format_cap * if (asterisk_format) { - struct ast_format tmp_fmt; - ast_format_cap_iter_start(ast_format_capability); - while (!ast_format_cap_iter_next(ast_format_capability, &tmp_fmt)) { - name = ast_rtp_lookup_mime_subtype2(asterisk_format, &tmp_fmt, 0, options); + int x; + struct ast_format *tmp_fmt; + for (x = 0; x < ast_format_cap_count(ast_format_capability); x++) { + tmp_fmt = ast_format_cap_get_format(ast_format_capability, x); + name = ast_rtp_lookup_mime_subtype2(asterisk_format, tmp_fmt, 0, options); + ao2_ref(tmp_fmt, -1); ast_str_append(&buf, 0, "%s|", name); found = 1; } - ast_format_cap_iter_end(ast_format_capability); - } else { int x; ast_str_append(&buf, 0, "0x%x (", (unsigned int) rtp_capability); @@ -979,15 +1022,6 @@ char *ast_rtp_lookup_mime_multiple2(struct ast_str *buf, struct ast_format_cap * return ast_str_buffer(buf); } -void ast_rtp_codecs_packetization_set(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, struct ast_codec_pref *prefs) -{ - codecs->pref = *prefs; - - if (instance && instance->engine->packetization_set) { - instance->engine->packetization_set(instance, &instance->codecs.pref); - } -} - int ast_rtp_instance_dtmf_begin(struct ast_rtp_instance *instance, char digit) { return instance->engine->dtmf_begin ? instance->engine->dtmf_begin(instance, digit) : -1; @@ -1089,8 +1123,8 @@ void ast_rtp_instance_early_bridge_make_compatible(struct ast_channel *c_dst, st struct ast_rtp_glue *glue_dst, *glue_src; enum ast_rtp_glue_result audio_glue_dst_res = AST_RTP_GLUE_RESULT_FORBID, video_glue_dst_res = AST_RTP_GLUE_RESULT_FORBID; enum ast_rtp_glue_result audio_glue_src_res = AST_RTP_GLUE_RESULT_FORBID, video_glue_src_res = AST_RTP_GLUE_RESULT_FORBID; - struct ast_format_cap *cap_dst = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - struct ast_format_cap *cap_src = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + struct ast_format_cap *cap_dst = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + struct ast_format_cap *cap_src = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); /* Lock both channels so we can look for the glue that binds them together */ ast_channel_lock_both(c_dst, c_src); @@ -1131,7 +1165,7 @@ void ast_rtp_instance_early_bridge_make_compatible(struct ast_channel *c_dst, st } /* Make sure we have matching codecs */ - if (!ast_format_cap_has_joint(cap_dst, cap_src)) { + if (!ast_format_cap_iscompatible(cap_dst, cap_src)) { goto done; } @@ -1156,8 +1190,8 @@ done: ast_channel_unlock(c_dst); ast_channel_unlock(c_src); - ast_format_cap_destroy(cap_dst); - ast_format_cap_destroy(cap_src); + ao2_cleanup(cap_dst); + ao2_cleanup(cap_src); unref_instance_cond(&instance_dst); unref_instance_cond(&instance_src); @@ -1175,13 +1209,13 @@ int ast_rtp_instance_early_bridge(struct ast_channel *c0, struct ast_channel *c1 struct ast_rtp_glue *glue0, *glue1; enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID, video_glue0_res = AST_RTP_GLUE_RESULT_FORBID; enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID, video_glue1_res = AST_RTP_GLUE_RESULT_FORBID; - struct ast_format_cap *cap0 = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - struct ast_format_cap *cap1 = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + struct ast_format_cap *cap0 = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + struct ast_format_cap *cap1 = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); /* If there is no second channel just immediately bail out, we are of no use in that scenario */ if (!c1 || !cap1 || !cap0) { - ast_format_cap_destroy(cap0); - ast_format_cap_destroy(cap1); + ao2_cleanup(cap0); + ao2_cleanup(cap1); return -1; } @@ -1220,7 +1254,7 @@ int ast_rtp_instance_early_bridge(struct ast_channel *c0, struct ast_channel *c1 } /* Make sure we have matching codecs */ - if (!ast_format_cap_has_joint(cap0, cap1)) { + if (!ast_format_cap_iscompatible(cap0, cap1)) { goto done; } @@ -1233,8 +1267,8 @@ done: ast_channel_unlock(c0); ast_channel_unlock(c1); - ast_format_cap_destroy(cap0); - ast_format_cap_destroy(cap1); + ao2_cleanup(cap0); + ao2_cleanup(cap1); unref_instance_cond(&instance0); unref_instance_cond(&instance1); @@ -1419,7 +1453,7 @@ void ast_rtp_instance_available_formats(struct ast_rtp_instance *instance, struc { if (instance->engine->available_formats) { instance->engine->available_formats(instance, to_endpoint, to_asterisk, result); - if (!ast_format_cap_is_empty(result)) { + if (ast_format_cap_count(result)) { return; } } @@ -1631,7 +1665,27 @@ void ast_rtp_dtls_cfg_free(struct ast_rtp_dtls_cfg *dtls_cfg) ast_free(dtls_cfg->capath); } -static void set_next_mime_type(const struct ast_format *format, int rtp_code, char *type, char *subtype, unsigned int sample_rate) +/*! \internal + * \brief Small helper routine that cleans up entry i in + * \c static_RTP_PT. + */ +static void rtp_engine_static_RTP_PT_cleanup(int i) +{ + ao2_cleanup(static_RTP_PT[i].format); + memset(&static_RTP_PT[i], 0, sizeof(struct ast_rtp_payload_type)); +} + +/*! \internal + * \brief Small helper routine that cleans up entry i in + * \c ast_rtp_mime_types. + */ +static void rtp_engine_mime_type_cleanup(int i) +{ + ao2_cleanup(ast_rtp_mime_types[i].payload_type.format); + memset(&ast_rtp_mime_types[i], 0, sizeof(struct ast_rtp_mime_type)); +} + +static void set_next_mime_type(struct ast_format *format, int rtp_code, const char *type, const char *subtype, unsigned int sample_rate) { int x = mime_types_len; if (ARRAY_LEN(ast_rtp_mime_types) == mime_types_len) { @@ -1639,20 +1693,22 @@ static void set_next_mime_type(const struct ast_format *format, int rtp_code, ch } ast_rwlock_wrlock(&mime_types_lock); + /* Make sure any previous value in ast_rtp_mime_types is cleaned up */ + memset(&ast_rtp_mime_types[x], 0, sizeof(struct ast_rtp_mime_type)); if (format) { ast_rtp_mime_types[x].payload_type.asterisk_format = 1; - ast_format_copy(&ast_rtp_mime_types[x].payload_type.format, format); + ast_rtp_mime_types[x].payload_type.format = ao2_bump(format); } else { ast_rtp_mime_types[x].payload_type.rtp_code = rtp_code; } - ast_rtp_mime_types[x].type = type; - ast_rtp_mime_types[x].subtype = subtype; + ast_copy_string(ast_rtp_mime_types[x].type, type, sizeof(ast_rtp_mime_types[x].type)); + ast_copy_string(ast_rtp_mime_types[x].subtype, subtype, sizeof(ast_rtp_mime_types[x].subtype)); ast_rtp_mime_types[x].sample_rate = sample_rate; mime_types_len++; ast_rwlock_unlock(&mime_types_lock); } -static void add_static_payload(int map, const struct ast_format *format, int rtp_code) +static void add_static_payload(int map, struct ast_format *format, int rtp_code) { int x; ast_rwlock_wrlock(&static_RTP_PT_lock); @@ -1667,39 +1723,38 @@ static void add_static_payload(int map, const struct ast_format *format, int rtp } if (map < 0) { - ast_log(LOG_WARNING, "No Dynamic RTP mapping available for format %s\n" ,ast_getformatname(format)); + ast_log(LOG_WARNING, "No Dynamic RTP mapping available for format %s\n", + ast_format_get_name(format)); ast_rwlock_unlock(&static_RTP_PT_lock); return; } if (format) { static_RTP_PT[map].asterisk_format = 1; - ast_format_copy(&static_RTP_PT[map].format, format); + static_RTP_PT[map].format = ao2_bump(format); } else { static_RTP_PT[map].rtp_code = rtp_code; } ast_rwlock_unlock(&static_RTP_PT_lock); } -int ast_rtp_engine_load_format(const struct ast_format *format) +int ast_rtp_engine_load_format(struct ast_format *format) { - switch (format->id) { - case AST_FORMAT_SILK: - set_next_mime_type(format, 0, "audio", "SILK", ast_format_rate(format)); - add_static_payload(-1, format, 0); - break; - case AST_FORMAT_CELT: - set_next_mime_type(format, 0, "audio", "CELT", ast_format_rate(format)); - add_static_payload(-1, format, 0); - break; - default: - break; - } + char *codec_name = ast_strdupa(ast_format_get_name(format)); + + codec_name = ast_str_to_upper(codec_name); + + set_next_mime_type(format, + 0, + ast_codec_media_type2str(ast_format_get_type(format)), + codec_name, + ast_format_get_sample_rate(format)); + add_static_payload(-1, format, 0); return 0; } -int ast_rtp_engine_unload_format(const struct ast_format *format) +int ast_rtp_engine_unload_format(struct ast_format *format) { int x; int y = 0; @@ -1707,17 +1762,17 @@ int ast_rtp_engine_unload_format(const struct ast_format *format) ast_rwlock_wrlock(&static_RTP_PT_lock); /* remove everything pertaining to this format id from the lists */ for (x = 0; x < AST_RTP_MAX_PT; x++) { - if (ast_format_cmp(&static_RTP_PT[x].format, format) == AST_FORMAT_CMP_EQUAL) { - memset(&static_RTP_PT[x], 0, sizeof(struct ast_rtp_payload_type)); + if (ast_format_cmp(static_RTP_PT[x].format, format) == AST_FORMAT_CMP_EQUAL) { + rtp_engine_static_RTP_PT_cleanup(x); } } ast_rwlock_unlock(&static_RTP_PT_lock); - ast_rwlock_wrlock(&mime_types_lock); /* rebuild the list skipping the items matching this id */ for (x = 0; x < mime_types_len; x++) { - if (ast_format_cmp(&ast_rtp_mime_types[x].payload_type.format, format) == AST_FORMAT_CMP_EQUAL) { + if (ast_format_cmp(ast_rtp_mime_types[x].payload_type.format, format) == AST_FORMAT_CMP_EQUAL) { + rtp_engine_mime_type_cleanup(x); continue; } ast_rtp_mime_types[y] = ast_rtp_mime_types[x]; @@ -1976,16 +2031,32 @@ struct stasis_topic *ast_rtp_topic(void) static void rtp_engine_shutdown(void) { + int x; + ao2_cleanup(rtp_topic); rtp_topic = NULL; STASIS_MESSAGE_TYPE_CLEANUP(ast_rtp_rtcp_received_type); STASIS_MESSAGE_TYPE_CLEANUP(ast_rtp_rtcp_sent_type); + + ast_rwlock_wrlock(&static_RTP_PT_lock); + for (x = 0; x < AST_RTP_MAX_PT; x++) { + if (static_RTP_PT[x].format) { + rtp_engine_static_RTP_PT_cleanup(x); + } + } + ast_rwlock_unlock(&static_RTP_PT_lock); + + ast_rwlock_wrlock(&mime_types_lock); + for (x = 0; x < mime_types_len; x++) { + if (ast_rtp_mime_types[x].payload_type.format) { + rtp_engine_mime_type_cleanup(x); + } + } + ast_rwlock_unlock(&mime_types_lock); } int ast_rtp_engine_init() { - struct ast_format tmpfmt; - ast_rwlock_init(&mime_types_lock); ast_rwlock_init(&static_RTP_PT_lock); @@ -1998,90 +2069,90 @@ int ast_rtp_engine_init() ast_register_atexit(rtp_engine_shutdown); /* Define all the RTP mime types available */ - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0), 0, "audio", "G723", 8000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0), 0, "audio", "GSM", 8000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0), 0, "audio", "PCMU", 8000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0), 0, "audio", "G711U", 8000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0), 0, "audio", "PCMA", 8000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0), 0, "audio", "G711A", 8000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G726, 0), 0, "audio", "G726-32", 8000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), 0, "audio", "DVI4", 8000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0), 0, "audio", "L16", 8000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR16, 0), 0, "audio", "L16", 16000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR16, 0), 0, "audio", "L16-256", 16000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_LPC10, 0), 0, "audio", "LPC", 8000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0), 0, "audio", "G729", 8000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0), 0, "audio", "G729A", 8000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0), 0, "audio", "G.729", 8000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX, 0), 0, "audio", "speex", 8000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX16, 0), 0, "audio", "speex", 16000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX32, 0), 0, "audio", "speex", 32000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_ILBC, 0), 0, "audio", "iLBC", 8000); + set_next_mime_type(ast_format_g723, 0, "audio", "G723", 8000); + set_next_mime_type(ast_format_gsm, 0, "audio", "GSM", 8000); + set_next_mime_type(ast_format_ulaw, 0, "audio", "PCMU", 8000); + set_next_mime_type(ast_format_ulaw, 0, "audio", "G711U", 8000); + set_next_mime_type(ast_format_alaw, 0, "audio", "PCMA", 8000); + set_next_mime_type(ast_format_alaw, 0, "audio", "G711A", 8000); + set_next_mime_type(ast_format_g726, 0, "audio", "G726-32", 8000); + set_next_mime_type(ast_format_adpcm, 0, "audio", "DVI4", 8000); + set_next_mime_type(ast_format_slin, 0, "audio", "L16", 8000); + set_next_mime_type(ast_format_slin16, 0, "audio", "L16", 16000); + set_next_mime_type(ast_format_slin16, 0, "audio", "L16-256", 16000); + set_next_mime_type(ast_format_lpc10, 0, "audio", "LPC", 8000); + set_next_mime_type(ast_format_g729, 0, "audio", "G729", 8000); + set_next_mime_type(ast_format_g729, 0, "audio", "G729A", 8000); + set_next_mime_type(ast_format_g729, 0, "audio", "G.729", 8000); + set_next_mime_type(ast_format_speex, 0, "audio", "speex", 8000); + set_next_mime_type(ast_format_speex16, 0, "audio", "speex", 16000); + set_next_mime_type(ast_format_speex32, 0, "audio", "speex", 32000); + set_next_mime_type(ast_format_ilbc, 0, "audio", "iLBC", 8000); /* this is the sample rate listed in the RTP profile for the G.722 codec, *NOT* the actual sample rate of the media stream */ - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G722, 0), 0, "audio", "G722", 8000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G726_AAL2, 0), 0, "audio", "AAL2-G726-32", 8000); + set_next_mime_type(ast_format_g722, 0, "audio", "G722", 8000); + set_next_mime_type(ast_format_g726_aal2, 0, "audio", "AAL2-G726-32", 8000); set_next_mime_type(NULL, AST_RTP_DTMF, "audio", "telephone-event", 8000); set_next_mime_type(NULL, AST_RTP_CISCO_DTMF, "audio", "cisco-telephone-event", 8000); set_next_mime_type(NULL, AST_RTP_CN, "audio", "CN", 8000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_JPEG, 0), 0, "video", "JPEG", 90000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_PNG, 0), 0, "video", "PNG", 90000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_H261, 0), 0, "video", "H261", 90000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_H263, 0), 0, "video", "H263", 90000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_H263_PLUS, 0), 0, "video", "H263-1998", 90000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_H264, 0), 0, "video", "H264", 90000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_MP4_VIDEO, 0), 0, "video", "MP4V-ES", 90000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_T140RED, 0), 0, "text", "RED", 1000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_T140, 0), 0, "text", "T140", 1000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SIREN7, 0), 0, "audio", "G7221", 16000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_SIREN14, 0), 0, "audio", "G7221", 32000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), 0, "audio", "G719", 48000); + set_next_mime_type(ast_format_jpeg, 0, "video", "JPEG", 90000); + set_next_mime_type(ast_format_png, 0, "video", "PNG", 90000); + set_next_mime_type(ast_format_h261, 0, "video", "H261", 90000); + set_next_mime_type(ast_format_h263, 0, "video", "H263", 90000); + set_next_mime_type(ast_format_h263p, 0, "video", "h263-1998", 90000); + set_next_mime_type(ast_format_h264, 0, "video", "H264", 90000); + set_next_mime_type(ast_format_mp4, 0, "video", "MP4V-ES", 90000); + set_next_mime_type(ast_format_t140_red, 0, "text", "RED", 1000); + set_next_mime_type(ast_format_t140, 0, "text", "T140", 1000); + set_next_mime_type(ast_format_siren7, 0, "audio", "G7221", 16000); + set_next_mime_type(ast_format_siren14, 0, "audio", "G7221", 32000); + set_next_mime_type(ast_format_g719, 0, "audio", "G719", 48000); /* Opus and VP8 */ - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_OPUS, 0), 0, "audio", "opus", 48000); - set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_VP8, 0), 0, "video", "VP8", 90000); + set_next_mime_type(ast_format_opus, 0, "audio", "opus", 48000); + set_next_mime_type(ast_format_vp8, 0, "video", "VP8", 90000); /* Define the static rtp payload mappings */ - add_static_payload(0, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0), 0); + add_static_payload(0, ast_format_ulaw, 0); #ifdef USE_DEPRECATED_G726 - add_static_payload(2, ast_format_set(&tmpfmt, AST_FORMAT_G726, 0), 0);/* Technically this is G.721, but if Cisco can do it, so can we... */ + add_static_payload(2, ast_format_g726, 0);/* Technically this is G.721, but if Cisco can do it, so can we... */ #endif - add_static_payload(3, ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0), 0); - add_static_payload(4, ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0), 0); - add_static_payload(5, ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), 0);/* 8 kHz */ - add_static_payload(6, ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), 0); /* 16 kHz */ - add_static_payload(7, ast_format_set(&tmpfmt, AST_FORMAT_LPC10, 0), 0); - add_static_payload(8, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0), 0); - add_static_payload(9, ast_format_set(&tmpfmt, AST_FORMAT_G722, 0), 0); - add_static_payload(10, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0), 0); /* 2 channels */ - add_static_payload(11, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0), 0); /* 1 channel */ + add_static_payload(3, ast_format_gsm, 0); + add_static_payload(4, ast_format_g723, 0); + add_static_payload(5, ast_format_adpcm, 0);/* 8 kHz */ + add_static_payload(6, ast_format_adpcm, 0); /* 16 kHz */ + add_static_payload(7, ast_format_lpc10, 0); + add_static_payload(8, ast_format_alaw, 0); + add_static_payload(9, ast_format_g722, 0); + add_static_payload(10, ast_format_slin, 0); /* 2 channels */ + add_static_payload(11, ast_format_slin, 0); /* 1 channel */ add_static_payload(13, NULL, AST_RTP_CN); - add_static_payload(16, ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), 0); /* 11.025 kHz */ - add_static_payload(17, ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), 0); /* 22.050 kHz */ - add_static_payload(18, ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0), 0); + add_static_payload(16, ast_format_adpcm, 0); /* 11.025 kHz */ + add_static_payload(17, ast_format_adpcm, 0); /* 22.050 kHz */ + add_static_payload(18, ast_format_g729, 0); add_static_payload(19, NULL, AST_RTP_CN); /* Also used for CN */ - add_static_payload(26, ast_format_set(&tmpfmt, AST_FORMAT_JPEG, 0), 0); - add_static_payload(31, ast_format_set(&tmpfmt, AST_FORMAT_H261, 0), 0); - add_static_payload(34, ast_format_set(&tmpfmt, AST_FORMAT_H263, 0), 0); - add_static_payload(97, ast_format_set(&tmpfmt, AST_FORMAT_ILBC, 0), 0); - add_static_payload(98, ast_format_set(&tmpfmt, AST_FORMAT_H263_PLUS, 0), 0); - add_static_payload(99, ast_format_set(&tmpfmt, AST_FORMAT_H264, 0), 0); + add_static_payload(26, ast_format_jpeg, 0); + add_static_payload(31, ast_format_h261, 0); + add_static_payload(34, ast_format_h263, 0); + add_static_payload(97, ast_format_ilbc, 0); + add_static_payload(98, ast_format_h263p, 0); + add_static_payload(99, ast_format_h264, 0); add_static_payload(101, NULL, AST_RTP_DTMF); - add_static_payload(102, ast_format_set(&tmpfmt, AST_FORMAT_SIREN7, 0), 0); - add_static_payload(103, ast_format_set(&tmpfmt, AST_FORMAT_H263_PLUS, 0), 0); - add_static_payload(104, ast_format_set(&tmpfmt, AST_FORMAT_MP4_VIDEO, 0), 0); - add_static_payload(105, ast_format_set(&tmpfmt, AST_FORMAT_T140RED, 0), 0); /* Real time text chat (with redundancy encoding) */ - add_static_payload(106, ast_format_set(&tmpfmt, AST_FORMAT_T140, 0), 0); /* Real time text chat */ - add_static_payload(110, ast_format_set(&tmpfmt, AST_FORMAT_SPEEX, 0), 0); - add_static_payload(111, ast_format_set(&tmpfmt, AST_FORMAT_G726, 0), 0); - add_static_payload(112, ast_format_set(&tmpfmt, AST_FORMAT_G726_AAL2, 0), 0); - add_static_payload(115, ast_format_set(&tmpfmt, AST_FORMAT_SIREN14, 0), 0); - add_static_payload(116, ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), 0); - add_static_payload(117, ast_format_set(&tmpfmt, AST_FORMAT_SPEEX16, 0), 0); - add_static_payload(118, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR16, 0), 0); /* 16 Khz signed linear */ - add_static_payload(119, ast_format_set(&tmpfmt, AST_FORMAT_SPEEX32, 0), 0); + add_static_payload(102, ast_format_siren7, 0); + add_static_payload(103, ast_format_h263p, 0); + add_static_payload(104, ast_format_mp4, 0); + add_static_payload(105, ast_format_t140_red, 0); /* Real time text chat (with redundancy encoding) */ + add_static_payload(106, ast_format_t140, 0); /* Real time text chat */ + add_static_payload(110, ast_format_speex, 0); + add_static_payload(111, ast_format_g726, 0); + add_static_payload(112, ast_format_g726_aal2, 0); + add_static_payload(115, ast_format_siren14, 0); + add_static_payload(116, ast_format_g719, 0); + add_static_payload(117, ast_format_speex16, 0); + add_static_payload(118, ast_format_slin16, 0); /* 16 Khz signed linear */ + add_static_payload(119, ast_format_speex32, 0); add_static_payload(121, NULL, AST_RTP_CISCO_DTMF); /* Must be type 121 */ /* Opus and VP8 */ - add_static_payload(100, ast_format_set(&tmpfmt, AST_FORMAT_VP8, 0), 0); - add_static_payload(107, ast_format_set(&tmpfmt, AST_FORMAT_OPUS, 0), 0); + add_static_payload(100, ast_format_vp8, 0); + add_static_payload(107, ast_format_opus, 0); return 0; } diff --git a/main/slinfactory.c b/main/slinfactory.c index 44efc420f..8c117d652 100644 --- a/main/slinfactory.c +++ b/main/slinfactory.c @@ -33,24 +33,26 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/frame.h" +#include "asterisk/format_cache.h" #include "asterisk/slinfactory.h" #include "asterisk/translate.h" +#include "asterisk/astobj2.h" void ast_slinfactory_init(struct ast_slinfactory *sf) { memset(sf, 0, sizeof(*sf)); sf->offset = sf->hold; - ast_format_set(&sf->output_format, AST_FORMAT_SLINEAR, 0); + sf->output_format = ao2_bump(ast_format_slin); } -int ast_slinfactory_init_with_format(struct ast_slinfactory *sf, const struct ast_format *slin_out) +int ast_slinfactory_init_with_format(struct ast_slinfactory *sf, struct ast_format *slin_out) { memset(sf, 0, sizeof(*sf)); sf->offset = sf->hold; - if (!ast_format_is_slinear(slin_out)) { + if (!ast_format_cache_is_slinear(slin_out)) { return -1; } - ast_format_copy(&sf->output_format, slin_out); + sf->output_format = ao2_bump(slin_out); return 0; } @@ -64,8 +66,14 @@ void ast_slinfactory_destroy(struct ast_slinfactory *sf) sf->trans = NULL; } - while ((f = AST_LIST_REMOVE_HEAD(&sf->queue, frame_list))) + while ((f = AST_LIST_REMOVE_HEAD(&sf->queue, frame_list))) { ast_frfree(f); + } + + ao2_cleanup(sf->output_format); + sf->output_format = NULL; + ao2_cleanup(sf->format); + sf->format = NULL; } int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f) @@ -83,22 +91,22 @@ int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f) return 0; } - if (ast_format_cmp(&f->subclass.format, &sf->output_format) == AST_FORMAT_CMP_NOT_EQUAL) { - if (sf->trans && (ast_format_cmp(&f->subclass.format, &sf->format) == AST_FORMAT_CMP_NOT_EQUAL)) { + if (ast_format_cmp(f->subclass.format, sf->output_format) == AST_FORMAT_CMP_NOT_EQUAL) { + if (sf->trans && (ast_format_cmp(f->subclass.format, sf->format) == AST_FORMAT_CMP_NOT_EQUAL)) { ast_translator_free_path(sf->trans); sf->trans = NULL; } if (!sf->trans) { - if (!(sf->trans = ast_translator_build_path(&sf->output_format, &f->subclass.format))) { + if (!(sf->trans = ast_translator_build_path(sf->output_format, f->subclass.format))) { ast_log(LOG_WARNING, "Cannot build a path from %s (%u)to %s (%u)\n", - ast_getformatname(&f->subclass.format), - f->subclass.format.id, - ast_getformatname(&sf->output_format), - sf->output_format.id); + ast_format_get_name(f->subclass.format), + ast_format_get_codec_id(f->subclass.format), + ast_format_get_name(sf->output_format), + ast_format_get_codec_id(sf->output_format)); return 0; } - ast_format_copy(&sf->format, &f->subclass.format); + ao2_replace(sf->format, f->subclass.format); } if (!(begin_frame = ast_translate(sf->trans, f, 0))) { diff --git a/main/smoother.c b/main/smoother.c new file mode 100644 index 000000000..720ad8549 --- /dev/null +++ b/main/smoother.c @@ -0,0 +1,227 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2005, Digium, Inc. + * + * Mark Spencer <markster@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Frame smoother manipulation routines + * + * \author Mark Spencer <markster@digium.com> + */ + +/*** MODULEINFO + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/_private.h" +#include "asterisk/frame.h" +#include "asterisk/astobj2.h" +#include "asterisk/time.h" +#include "asterisk/utils.h" +#include "asterisk/format.h" +#include "asterisk/codec.h" +#include "asterisk/smoother.h" + +#define SMOOTHER_SIZE 8000 + +struct ast_smoother { + int size; + struct ast_format *format; + int flags; + float samplesperbyte; + unsigned int opt_needs_swap:1; + struct ast_frame f; + struct timeval delivery; + char data[SMOOTHER_SIZE]; + char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET]; + struct ast_frame *opt; + int len; +}; + +static int smoother_frame_feed(struct ast_smoother *s, struct ast_frame *f, int swap) +{ + if (s->flags & AST_SMOOTHER_FLAG_G729) { + if (s->len % 10) { + ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n"); + return 0; + } + } + if (swap) { + ast_swapcopy_samples(s->data + s->len, f->data.ptr, f->samples); + } else { + memcpy(s->data + s->len, f->data.ptr, f->datalen); + } + /* If either side is empty, reset the delivery time */ + if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery)) { /* XXX really ? */ + s->delivery = f->delivery; + } + s->len += f->datalen; + + return 0; +} + +void ast_smoother_reset(struct ast_smoother *s, int bytes) +{ + ao2_cleanup(s->format); + memset(s, 0, sizeof(*s)); + s->size = bytes; +} + +void ast_smoother_reconfigure(struct ast_smoother *s, int bytes) +{ + /* if there is no change, then nothing to do */ + if (s->size == bytes) { + return; + } + /* set the new desired output size */ + s->size = bytes; + /* if there is no 'optimized' frame in the smoother, + * then there is nothing left to do + */ + if (!s->opt) { + return; + } + /* there is an 'optimized' frame here at the old size, + * but it must now be put into the buffer so the data + * can be extracted at the new size + */ + smoother_frame_feed(s, s->opt, s->opt_needs_swap); + s->opt = NULL; +} + +struct ast_smoother *ast_smoother_new(int size) +{ + struct ast_smoother *s; + if (size < 1) + return NULL; + if ((s = ast_calloc(1, sizeof(*s)))) + ast_smoother_reset(s, size); + return s; +} + +int ast_smoother_get_flags(struct ast_smoother *s) +{ + return s->flags; +} + +void ast_smoother_set_flags(struct ast_smoother *s, int flags) +{ + s->flags = flags; +} + +int ast_smoother_test_flag(struct ast_smoother *s, int flag) +{ + return (s->flags & flag); +} + +int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap) +{ + if (f->frametype != AST_FRAME_VOICE) { + ast_log(LOG_WARNING, "Huh? Can't smooth a non-voice frame!\n"); + return -1; + } + if (!s->format) { + s->format = ao2_bump(f->subclass.format); + s->samplesperbyte = (float)f->samples / (float)f->datalen; + } else if (ast_format_cmp(s->format, f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + ast_log(LOG_WARNING, "Smoother was working on %s format frames, now trying to feed %s?\n", + ast_format_get_name(s->format), ast_format_get_name(f->subclass.format)); + return -1; + } + if (s->len + f->datalen > SMOOTHER_SIZE) { + ast_log(LOG_WARNING, "Out of smoother space\n"); + return -1; + } + if (((f->datalen == s->size) || + ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729))) && + !s->opt && + !s->len && + (f->offset >= AST_MIN_OFFSET)) { + /* Optimize by sending the frame we just got + on the next read, thus eliminating the douple + copy */ + if (swap) + ast_swapcopy_samples(f->data.ptr, f->data.ptr, f->samples); + s->opt = f; + s->opt_needs_swap = swap ? 1 : 0; + return 0; + } + + return smoother_frame_feed(s, f, swap); +} + +struct ast_frame *ast_smoother_read(struct ast_smoother *s) +{ + struct ast_frame *opt; + int len; + + /* IF we have an optimization frame, send it */ + if (s->opt) { + if (s->opt->offset < AST_FRIENDLY_OFFSET) + ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).\n", + s->opt->offset); + opt = s->opt; + s->opt = NULL; + return opt; + } + + /* Make sure we have enough data */ + if (s->len < s->size) { + /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */ + if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->len % 10))) + return NULL; + } + len = s->size; + if (len > s->len) + len = s->len; + /* Make frame */ + s->f.frametype = AST_FRAME_VOICE; + s->f.subclass.format = s->format; + s->f.data.ptr = s->framedata + AST_FRIENDLY_OFFSET; + s->f.offset = AST_FRIENDLY_OFFSET; + s->f.datalen = len; + /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */ + s->f.samples = len * s->samplesperbyte; /* XXX rounding */ + s->f.delivery = s->delivery; + /* Fill Data */ + memcpy(s->f.data.ptr, s->data, len); + s->len -= len; + /* Move remaining data to the front if applicable */ + if (s->len) { + /* In principle this should all be fine because if we are sending + G.729 VAD, the next timestamp will take over anyawy */ + memmove(s->data, s->data + len, s->len); + if (!ast_tvzero(s->delivery)) { + /* If we have delivery time, increment it, otherwise, leave it at 0 */ + s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, + ast_format_get_sample_rate(s->format))); + } + } + /* Return frame */ + return &s->f; +} + +void ast_smoother_free(struct ast_smoother *s) +{ + ao2_cleanup(s->format); + ast_free(s); +} + diff --git a/main/sorcery.c b/main/sorcery.c index 9488dee4b..85a699bcb 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -43,7 +43,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/taskprocessor.h" #include "asterisk/threadpool.h" #include "asterisk/json.h" -#include "asterisk/format_pref.h" /* To prevent DEBUG_FD_LEAKS from interfering with things we undef open and close */ #undef open @@ -233,10 +232,9 @@ static int chararray_handler_fn(const void *obj, const intptr_t *args, char **bu static int codec_handler_fn(const void *obj, const intptr_t *args, char **buf) { - char tmp_buf[256]; - struct ast_codec_pref *pref = (struct ast_codec_pref *)(obj + args[0]); - ast_codec_pref_string(pref, tmp_buf, sizeof(tmp_buf)); - return !(*buf = ast_strdup(tmp_buf)); + struct ast_str *codec_buf = ast_str_alloca(64); + struct ast_format_cap **cap = (struct ast_format_cap **)(obj + args[0]); + return !(*buf = ast_strdup(ast_format_cap_get_names(*cap, &codec_buf))); } static sorcery_field_handler sorcery_field_default_handler(enum aco_option_type type) diff --git a/main/sounds_index.c b/main/sounds_index.c index 41430fa45..bc5263908 100644 --- a/main/sounds_index.c +++ b/main/sounds_index.c @@ -158,10 +158,10 @@ static int show_sound_info_cb(void *obj, void *arg, int flags) { char *language = obj; struct ast_cli_args *a = arg; - struct ast_format format; + struct ast_format *format; int formats_shown = 0; RAII_VAR(struct ast_media_index *, local_index, ast_sounds_get_index(), ao2_cleanup); - RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy); + struct ast_format_cap *cap; const char *description = ast_media_get_description(local_index, a->argv[3], language); ast_cli(a->fd, " Language %s:\n", language); @@ -171,12 +171,14 @@ static int show_sound_info_cb(void *obj, void *arg, int flags) cap = ast_media_get_format_cap(local_index, a->argv[3], language); if (cap) { - ast_format_cap_iter_start(cap); - while (!ast_format_cap_iter_next(cap, &format)) { - ast_cli(a->fd, " Format: %s\n", ast_getformatname(&format)); + int x; + for (x = 0; x < ast_format_cap_count(cap); x++) { + format = ast_format_cap_get_format(cap, x); + ast_cli(a->fd, " Format: %s\n", ast_format_get_name(format)); + ao2_ref(format, -1); formats_shown = 1; - } - ast_format_cap_iter_end(cap); + } + ao2_ref(cap, -1); } if (!formats_shown) { diff --git a/main/translate.c b/main/translate.c index c24700b45..0696f5d83 100644 --- a/main/translate.c +++ b/main/translate.c @@ -43,6 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/sched.h" #include "asterisk/cli.h" #include "asterisk/term.h" +#include "asterisk/format.h" /*! \todo * TODO: sample frames for each supported input format. @@ -76,11 +77,11 @@ struct translator_path { static struct translator_path **__matrix; /*! - * \brief table for converting index to format id values. + * \brief table for converting index to format values. * * \note this table is protected by the table_lock. */ -static int *__indextable; +static unsigned int *__indextable; /*! protects the __indextable for resizing */ static ast_rwlock_t tablelock; @@ -99,9 +100,9 @@ static void matrix_rebuild(int samples); /*! * \internal - * \brief converts format id to index value. + * \brief converts codec id to index value. */ -static int format2index(enum ast_format_id id) +static int codec_to_index(unsigned int id) { int x; @@ -119,16 +120,34 @@ static int format2index(enum ast_format_id id) /*! * \internal - * \brief add a new format to the matrix and index table structures. + * \brief converts codec to index value. + */ +static int codec2index(struct ast_codec *codec) +{ + return codec_to_index(codec->id); +} + +/*! + * \internal + * \brief converts format to codec index value. + */ +static int format2index(struct ast_format *format) +{ + return codec_to_index(ast_format_get_codec_id(format)); +} + +/*! + * \internal + * \brief add a new codec to the matrix and index table structures. * - * \note it is perfectly safe to call this on formats already indexed. + * \note it is perfectly safe to call this on codecs already indexed. * * \retval 0, success * \retval -1, matrix and index table need to be resized */ -static int add_format2index(enum ast_format_id id) +static int add_codec2index(struct ast_codec *codec) { - if (format2index(id) >= 0) { + if (codec2index(codec) != -1) { /* format is already already indexed */ return 0; } @@ -138,7 +157,7 @@ static int add_format2index(enum ast_format_id id) ast_rwlock_unlock(&tablelock); return -1; /* hit max length */ } - __indextable[cur_max_index] = id; + __indextable[cur_max_index] = codec->id; cur_max_index++; ast_rwlock_unlock(&tablelock); @@ -147,20 +166,20 @@ static int add_format2index(enum ast_format_id id) /*! * \internal - * \brief converts index value back to format id + * \brief converts index value back to codec */ -static enum ast_format_id index2format(int index) +static struct ast_codec *index2codec(int index) { - enum ast_format_id format_id; + struct ast_codec *codec; if (index >= cur_max_index) { return 0; } ast_rwlock_rdlock(&tablelock); - format_id = __indextable[index]; + codec = ast_codec_get_by_id(__indextable[index]); ast_rwlock_unlock(&tablelock); - return format_id; + return codec; } /*! @@ -176,7 +195,7 @@ static enum ast_format_id index2format(int index) static int matrix_resize(int init) { struct translator_path **tmp_matrix = NULL; - int *tmp_table = NULL; + unsigned int *tmp_table = NULL; int old_index; int x; @@ -202,7 +221,7 @@ static int matrix_resize(int init) } /* make new index table */ - if (!(tmp_table = ast_calloc(1, sizeof(int) * index_size))) { + if (!(tmp_table = ast_calloc(1, sizeof(unsigned int) * index_size))) { goto resize_cleanup; } @@ -213,7 +232,7 @@ static int matrix_resize(int init) } ast_free(__matrix); - memcpy(tmp_table, __indextable, sizeof(int) * old_index); + memcpy(tmp_table, __indextable, sizeof(unsigned int) * old_index); ast_free(__indextable); } @@ -270,11 +289,23 @@ static struct translator_path *matrix_get(unsigned int x, unsigned int y) * wrappers around the translator routines. */ +static void destroy(struct ast_trans_pvt *pvt) +{ + struct ast_translator *t = pvt->t; + + if (t->destroy) { + t->destroy(pvt); + } + ao2_cleanup(pvt->f.subclass.format); + ast_free(pvt); + ast_module_unref(t->module); +} + /*! * \brief Allocate the descriptor, required outbuf space, * and possibly desc. */ -static void *newpvt(struct ast_translator *t, const struct ast_format *explicit_dst) +static struct ast_trans_pvt *newpvt(struct ast_translator *t) { struct ast_trans_pvt *pvt; int len; @@ -300,28 +331,49 @@ static void *newpvt(struct ast_translator *t, const struct ast_format *explicit_ if (t->buf_size) {/* finally buffer and header */ pvt->outbuf.c = ofs + AST_FRIENDLY_OFFSET; } - /* if a explicit destination format is provided, set that on the pvt so the - * translator will process it. */ - if (explicit_dst) { - ast_format_copy(&pvt->explicit_dst, explicit_dst); - } + + ast_module_ref(t->module); + /* call local init routine, if present */ if (t->newpvt && t->newpvt(pvt)) { ast_free(pvt); + ast_module_unref(t->module); return NULL; } - ast_module_ref(t->module); - return pvt; -} -static void destroy(struct ast_trans_pvt *pvt) -{ - struct ast_translator *t = pvt->t; + /* Setup normal static translation frame. */ + pvt->f.frametype = AST_FRAME_VOICE; + pvt->f.mallocd = 0; + pvt->f.offset = AST_FRIENDLY_OFFSET; + pvt->f.src = pvt->t->name; + pvt->f.data.ptr = pvt->outbuf.c; - if (t->destroy) - t->destroy(pvt); - ast_free(pvt); - ast_module_unref(t->module); + /* if the translator has not provided a format find one in the cache or create one */ + if (!pvt->f.subclass.format) { + if (!ast_strlen_zero(pvt->t->format)) { + pvt->f.subclass.format = ast_format_cache_get(pvt->t->format); + } + + if (!pvt->f.subclass.format) { + struct ast_codec *codec = ast_codec_get(t->dst_codec.name, + t->dst_codec.type, t->dst_codec.sample_rate); + if (!codec) { + ast_log(LOG_ERROR, "Unable to get destination codec\n"); + destroy(pvt); + return NULL; + } + pvt->f.subclass.format = ast_format_create(codec); + ao2_ref(codec, -1); + } + + if (!pvt->f.subclass.format) { + ast_log(LOG_ERROR, "Unable to create format\n"); + destroy(pvt); + return NULL; + } + } + + return pvt; } /*! \brief framein wrapper, deals with bound checks. */ @@ -374,8 +426,9 @@ struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt, if (samples) { f->samples = samples; } else { - if (pvt->samples == 0) + if (pvt->samples == 0) { return NULL; + } f->samples = pvt->samples; pvt->samples = 0; } @@ -386,13 +439,6 @@ struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt, pvt->datalen = 0; } - f->frametype = AST_FRAME_VOICE; - ast_format_copy(&f->subclass.format, &pvt->t->dst_format); - f->mallocd = 0; - f->offset = AST_FRIENDLY_OFFSET; - f->src = pvt->t->name; - f->data.ptr = pvt->outbuf.c; - return ast_frisolate(f); } @@ -417,11 +463,9 @@ struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct a { struct ast_trans_pvt *head = NULL, *tail = NULL; int src_index, dst_index; - struct ast_format tmp_fmt1; - struct ast_format tmp_fmt2; - src_index = format2index(src->id); - dst_index = format2index(dst->id); + src_index = format2index(src); + dst_index = format2index(dst); if (src_index < 0 || dst_index < 0) { ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src_index < 0 ? "starting" : "ending"); @@ -432,26 +476,16 @@ struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct a while (src_index != dst_index) { struct ast_trans_pvt *cur; - struct ast_format *explicit_dst = NULL; struct ast_translator *t = matrix_get(src_index, dst_index)->step; if (!t) { - int src_id = index2format(src_index); - int dst_id = index2format(dst_index); ast_log(LOG_WARNING, "No translator path from %s to %s\n", - ast_getformatname(ast_format_set(&tmp_fmt1, src_id, 0)), - ast_getformatname(ast_format_set(&tmp_fmt2, dst_id, 0))); + ast_format_get_name(src), ast_format_get_name(dst)); AST_RWLIST_UNLOCK(&translators); return NULL; } - if (dst_index == t->dst_fmt_index) { - explicit_dst = dst; - } - if (!(cur = newpvt(t, explicit_dst))) { - int src_id = index2format(src_index); - int dst_id = index2format(dst_index); + if (!(cur = newpvt(t))) { ast_log(LOG_WARNING, "Failed to build translator step from %s to %s\n", - ast_getformatname(ast_format_set(&tmp_fmt1, src_id, 0)), - ast_getformatname(ast_format_set(&tmp_fmt2, dst_id, 0))); + ast_format_get_name(src), ast_format_get_name(dst)); if (head) { ast_translator_free_path(head); } @@ -508,7 +542,8 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, path->nextout = f->delivery; } /* Predict next incoming sample */ - path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, ast_format_rate(&f->subclass.format))); + path->nextin = ast_tvadd(path->nextin, ast_samp2tv( + f->samples, ast_format_get_sample_rate(f->subclass.format))); } delivery = f->delivery; for (out = f; out && p ; p = p->next) { @@ -531,7 +566,8 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, /* Predict next outgoing timestamp from samples in this frame. */ - path->nextout = ast_tvadd(path->nextout, ast_samp2tv(out->samples, ast_format_rate(&out->subclass.format))); + path->nextout = ast_tvadd(path->nextout, ast_samp2tv( + out->samples, ast_format_get_sample_rate(out->subclass.format))); if (f->samples != out->samples && ast_test_flag(out, AST_FRFLAG_HAS_TIMING_INFO)) { ast_debug(4, "Sample size different %d vs %d\n", f->samples, out->samples); ast_clear_flag(out, AST_FRFLAG_HAS_TIMING_INFO); @@ -572,7 +608,7 @@ static void generate_computational_cost(struct ast_translator *t, int seconds) struct rusage start; struct rusage end; int cost; - int out_rate = ast_format_rate(&t->dst_format); + int out_rate = t->dst_codec.sample_rate; if (!seconds) { seconds = 1; @@ -585,7 +621,7 @@ static void generate_computational_cost(struct ast_translator *t, int seconds) return; } - pvt = newpvt(t, NULL); + pvt = newpvt(t); if (!pvt) { ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name); t->comp_cost = 999999; @@ -643,21 +679,23 @@ static void generate_computational_cost(struct ast_translator *t, int seconds) * \retval Table Cost value greater than 0. * \retval 0 on error. */ -static int generate_table_cost(struct ast_format *src, struct ast_format *dst) +static int generate_table_cost(struct ast_codec *src, struct ast_codec *dst) { - int src_rate = ast_format_rate(src); + int src_rate = src->sample_rate; int src_ll = 0; - int dst_rate = ast_format_rate(dst); + int dst_rate = dst->sample_rate; int dst_ll = 0; - if ((AST_FORMAT_GET_TYPE(src->id) != AST_FORMAT_TYPE_AUDIO) || (AST_FORMAT_GET_TYPE(dst->id) != AST_FORMAT_TYPE_AUDIO)) { + if ((src->type != AST_MEDIA_TYPE_AUDIO) || + (dst->type != AST_MEDIA_TYPE_AUDIO)) { /* This method of generating table cost is limited to audio. * Translators for media other than audio must manually set their * table cost. */ return 0; } - src_ll = ast_format_is_slinear(src); - dst_ll = ast_format_is_slinear(dst); + + src_ll = !strcmp(src->name, "slin"); + dst_ll = !strcmp(dst->name, "slin"); if (src_ll) { if (dst_ll && (src_rate == dst_rate)) { return AST_TRANS_COST_LL_LL_ORIGSAMP; @@ -763,18 +801,25 @@ static void matrix_rebuild(int samples) /* if no step already exists between x and z OR the new cost of using the intermediate * step is cheaper, use this step. */ if (!matrix_get(x, z)->step || (newtablecost < matrix_get(x, z)->table_cost)) { - struct ast_format tmpx; - struct ast_format tmpy; - struct ast_format tmpz; matrix_get(x, z)->step = matrix_get(x, y)->step; matrix_get(x, z)->table_cost = newtablecost; matrix_get(x, z)->multistep = 1; changed++; - ast_debug(10, "Discovered %u cost path from %s to %s, via %s\n", - matrix_get(x, z)->table_cost, - ast_getformatname(ast_format_set(&tmpx, index2format(x), 0)), - ast_getformatname(ast_format_set(&tmpy, index2format(z), 0)), - ast_getformatname(ast_format_set(&tmpz, index2format(y), 0))); + + if (DEBUG_ATLEAST(10)) { + struct ast_codec *x_codec = index2codec(x); + struct ast_codec *y_codec = index2codec(y); + struct ast_codec *z_codec = index2codec(z); + + ast_log(LOG_DEBUG, + "Discovered %u cost path from %s to %s, via %s\n", + matrix_get(x, z)->table_cost, x_codec->name, + y_codec->name, z_codec->name); + + ao2_ref(x_codec, -1); + ao2_ref(y_codec, -1); + ao2_ref(z_codec, -1); + } } } } @@ -785,20 +830,26 @@ static void matrix_rebuild(int samples) } } -const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **str) +static void codec_append_name(const struct ast_codec *codec, struct ast_str **buf) { - struct ast_trans_pvt *pn = p; - char tmp[256]; + if (codec) { + ast_str_append(buf, 0, "(%s@%u)", codec->name, codec->sample_rate); + } else { + ast_str_append(buf, 0, "(nothing)"); + } +} +const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **str) +{ if (!p || !p->t) { return ""; } - ast_str_set(str, 0, "%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), p->t->src_format.id)); - - while ( (p = pn) ) { - pn = p->next; - ast_str_append(str, 0, "->%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), p->t->dst_format.id)); + codec_append_name(&p->t->src_codec, str); + while (p) { + ast_str_append(str, 0, "->"); + codec_append_name(&p->t->dst_codec, str); + p = p->next; } return ast_str_buffer(*str); @@ -806,24 +857,24 @@ const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str ** static char *complete_trans_path_choice(const char *line, const char *word, int pos, int state) { - int which = 0; + int i = 1, which = 0; int wordlen = strlen(word); - int i; - char *ret = NULL; - size_t len = 0; - const struct ast_format_list *format_list = ast_format_list_get(&len); + struct ast_codec *codec; - for (i = 0; i < len; i++) { - if (AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) { + while ((codec = ast_codec_get_by_id(i))) { + ++i; + if (codec->type != AST_MEDIA_TYPE_AUDIO) { + ao2_ref(codec, -1); continue; } - if (!strncasecmp(word, format_list[i].name, wordlen) && ++which > state) { - ret = ast_strdup(format_list[i].name); - break; + if (!strncasecmp(word, codec->name, wordlen) && ++which > state) { + char *res = ast_strdup(codec->name); + ao2_ref(codec, -1); + return res; } + ao2_ref(codec, -1); } - ast_format_list_destroy(format_list); - return ret; + return NULL; } static void handle_cli_recalc(struct ast_cli_args *a) @@ -847,63 +898,61 @@ static void handle_cli_recalc(struct ast_cli_args *a) static char *handle_show_translation_table(struct ast_cli_args *a) { - int x; - int y; - int i; - int k; - int curlen = 0; - int longest = 0; - int f_len; - size_t f_size = 0; - const struct ast_format_list *f_list = ast_format_list_get(&f_size); + int x, y, i, k; + int longest = 0, num_codecs = 0, curlen = 0; struct ast_str *out = ast_str_create(1024); + struct ast_codec *codec; - f_len = f_size; - AST_RWLIST_RDLOCK(&translators); - ast_cli(a->fd, " Translation times between formats (in microseconds) for one second of data\n"); - ast_cli(a->fd, " Source Format (Rows) Destination Format (Columns)\n\n"); - - /* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */ - for (i = 0; i < f_len; i++) { - /* translation only applies to audio right now. */ - if (AST_FORMAT_GET_TYPE(f_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) + /* Get the length of the longest (usable?) codec name, + so we know how wide the left side should be */ + for (i = 1; (codec = ast_codec_get_by_id(i)); ao2_ref(codec, -1), ++i) { + ++num_codecs; + if (codec->type != AST_MEDIA_TYPE_AUDIO) { continue; - curlen = strlen(ast_getformatname(&f_list[i].format)); + } + curlen = strlen(codec->name); if (curlen > longest) { longest = curlen; } } - for (i = -1; i < f_len; i++) { + AST_RWLIST_RDLOCK(&translators); + ast_cli(a->fd, " Translation times between formats (in microseconds) for one second of data\n"); + ast_cli(a->fd, " Source Format (Rows) Destination Format (Columns)\n\n"); + + for (i = 0; i < num_codecs; i++) { + struct ast_codec *row = i ? ast_codec_get_by_id(i) : NULL; + x = -1; - if ((i >= 0) && ((x = format2index(f_list[i].format.id)) < 0)) { - continue; - } - /* translation only applies to audio right now. */ - if (i >= 0 && (AST_FORMAT_GET_TYPE(f_list[i].format.id) != AST_FORMAT_TYPE_AUDIO)) { + if ((i > 0) && (row->type != AST_MEDIA_TYPE_AUDIO)) { + ao2_ref(row, -1); continue; } - /*Go ahead and move to next iteration if dealing with an unknown codec*/ - if (i >= 0 && !strcmp(ast_getformatname(&f_list[i].format), "unknown")) { + + if ((i > 0) && (x = codec2index(row)) == -1) { + ao2_ref(row, -1); continue; } + ast_str_set(&out, 0, " "); - for (k = -1; k < f_len; k++) { + for (k = 0; k < num_codecs; k++) { + struct ast_codec *col = k ? ast_codec_get_by_id(k) : NULL; + y = -1; - if ((k >= 0) && ((y = format2index(f_list[k].format.id)) < 0)) { + if ((k > 0) && (col->type != AST_MEDIA_TYPE_AUDIO)) { + ao2_ref(col, -1); continue; } - /* translation only applies to audio right now. */ - if (k >= 0 && (AST_FORMAT_GET_TYPE(f_list[k].format.id) != AST_FORMAT_TYPE_AUDIO)) { - continue; - } - /*Go ahead and move to next iteration if dealing with an unknown codec*/ - if (k >= 0 && !strcmp(ast_getformatname(&f_list[k].format), "unknown")) { + + if ((k > 0) && (y = codec2index(col)) == -1) { + ao2_ref(col, -1); continue; } - if (k >= 0) { - curlen = strlen(ast_getformatname(&f_list[k].format)); + + if (k > 0) { + curlen = strlen(col->name); } + if (curlen < 5) { curlen = 5; } @@ -911,12 +960,12 @@ static char *handle_show_translation_table(struct ast_cli_args *a) if (x >= 0 && y >= 0 && matrix_get(x, y)->step) { /* Actual codec output */ ast_str_append(&out, 0, "%*u", curlen + 1, (matrix_get(x, y)->table_cost/100)); - } else if (i == -1 && k >= 0) { + } else if (i == 0 && k > 0) { /* Top row - use a dynamic size */ - ast_str_append(&out, 0, "%*s", curlen + 1, ast_getformatname(&f_list[k].format)); - } else if (k == -1 && i >= 0) { + ast_str_append(&out, 0, "%*s", curlen + 1, col->name); + } else if (k == 0 && i > 0) { /* Left column - use a static size. */ - ast_str_append(&out, 0, "%*s", longest, ast_getformatname(&f_list[i].format)); + ast_str_append(&out, 0, "%*s", longest, row->name); } else if (x >= 0 && y >= 0) { /* Codec not supported */ ast_str_append(&out, 0, "%*s", curlen + 1, "-"); @@ -924,74 +973,79 @@ static char *handle_show_translation_table(struct ast_cli_args *a) /* Upper left hand corner */ ast_str_append(&out, 0, "%*s", longest, ""); } + ao2_cleanup(col); } ast_str_append(&out, 0, "\n"); ast_cli(a->fd, "%s", ast_str_buffer(out)); + ao2_cleanup(row); } ast_free(out); AST_RWLIST_UNLOCK(&translators); - ast_format_list_destroy(f_list); return CLI_SUCCESS; } -static char *handle_show_translation_path(struct ast_cli_args *a) +static char *handle_show_translation_path(struct ast_cli_args *a, const char *codec_name, unsigned int sample_rate) { - struct ast_format input_src_format; - size_t len = 0; - int i; - const struct ast_format_list *format_list = ast_format_list_get(&len); + int i = 1; struct ast_str *str = ast_str_alloca(1024); struct ast_translator *step; - char tmp[256]; + struct ast_codec *dst_codec; + struct ast_codec *src_codec = ast_codec_get(codec_name, AST_MEDIA_TYPE_AUDIO, sample_rate); - ast_format_clear(&input_src_format); - for (i = 0; i < len; i++) { - if (AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) { - continue; - } - if (!strncasecmp(format_list[i].name, a->argv[4], strlen(format_list[i].name))) { - ast_format_copy(&input_src_format, &format_list[i].format); - } - } - - if (!input_src_format.id) { - ast_cli(a->fd, "Source codec \"%s\" is not found.\n", a->argv[4]); - ast_format_list_destroy(format_list); + if (!src_codec) { + ast_cli(a->fd, "Source codec \"%s\" is not found.\n", codec_name); return CLI_FAILURE; } AST_RWLIST_RDLOCK(&translators); - ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %d ---\n", a->argv[4], ast_format_rate(&input_src_format)); - for (i = 0; i < len; i++) { - int src; - int dst; - if ((AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) || (format_list[i].format.id == input_src_format.id)) { + ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %u ---\n", + codec_name, src_codec->sample_rate); + + while ((dst_codec = ast_codec_get_by_id(i))) { + int src, dst; + char src_buffer[64]; + char dst_buffer[64]; + + ++i; + if (src_codec == dst_codec || + dst_codec->type != AST_MEDIA_TYPE_AUDIO) { + ao2_ref(dst_codec, -1); continue; } - dst = format2index(format_list[i].format.id); - src = format2index(input_src_format.id); - ast_str_reset(str); - if ((len >= cur_max_index) && (src >= 0) && (dst >= 0) && matrix_get(src, dst)->step) { - ast_str_append(&str, 0, "%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), matrix_get(src, dst)->step->src_format.id)); - while (src != dst) { - step = matrix_get(src, dst)->step; - if (!step) { - ast_str_reset(str); - break; + + dst = codec2index(dst_codec); + src = codec2index(src_codec); + + if (src < 0 || dst < 0) { + ast_str_set(&str, 0, "No Translation Path"); + } else { + step = matrix_get(src, dst)->step; + + if (step) { + codec_append_name(&step->src_codec, &str); + while (src != dst) { + src = step->dst_fmt_index; + step = matrix_get(src, dst)->step; + if (!step) { + ast_str_append(&str, 0, "->"); + codec_append_name(dst_codec, &str); + break; + } + ast_str_append(&str, 0, "->"); + codec_append_name(&step->src_codec, &str); } - ast_str_append(&str, 0, "->%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), step->dst_format.id)); - src = step->dst_fmt_index; } } - if (ast_strlen_zero(ast_str_buffer(str))) { - ast_str_set(&str, 0, "No Translation Path"); - } - ast_cli(a->fd, "\t%-10.10s To %-10.10s: %-60.60s\n", a->argv[4], format_list[i].name, ast_str_buffer(str)); + snprintf(src_buffer, sizeof(src_buffer), "%s:%u", src_codec->name, src_codec->sample_rate); + snprintf(dst_buffer, sizeof(dst_buffer), "%s:%u", dst_codec->name, dst_codec->sample_rate); + ast_cli(a->fd, "\t%-16.16s To %-16.16s: %-60.60s\n", + src_buffer, dst_buffer, ast_str_buffer(str)); + ast_str_reset(str); + ao2_ref(dst_codec, -1); } AST_RWLIST_UNLOCK(&translators); - - ast_format_list_destroy(format_list); + ao2_ref(src_codec, -1); return CLI_SUCCESS; } @@ -1009,8 +1063,10 @@ static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd, " with each conversion. If the argument 'recalc' is supplied along\n" " with optional number of seconds to test a new test will be performed\n" " as the chart is being displayed.\n" - " 2. 'core show translation paths [codec]'\n" - " This will display all the translation paths associated with a codec\n"; + " 2. 'core show translation paths [codec [sample_rate]]'\n" + " This will display all the translation paths associated with a codec.\n" + " If a codec has multiple sample rates, the sample rate must be\n" + " provided as well.\n"; return NULL; case CLI_GENERATE: if (a->pos == 3) { @@ -1019,14 +1075,22 @@ static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd, if (a->pos == 4 && !strcasecmp(a->argv[3], option[1])) { return complete_trans_path_choice(a->line, a->word, a->pos, a->n); } + /* BUGBUG - add tab completion for sample rates */ return NULL; } - if (a->argc > 5) + if (a->argc > 6) return CLI_SHOWUSAGE; if (a->argv[3] && !strcasecmp(a->argv[3], option[1]) && a->argc == 5) { /* show paths */ - return handle_show_translation_path(a); + return handle_show_translation_path(a, a->argv[4], 0); + } else if (a->argv[3] && !strcasecmp(a->argv[3], option[1]) && a->argc == 6) { + unsigned int sample_rate; + if (sscanf(a->argv[5], "%30u", &sample_rate) != 1) { + ast_cli(a->fd, "Invalid sample rate: %s.\n", a->argv[5]); + return CLI_FAILURE; + } + return handle_show_translation_path(a, a->argv[4], sample_rate); } else if (a->argv[3] && !strcasecmp(a->argv[3], option[0])) { /* recalc and then fall through to show table */ handle_cli_recalc(a); } else if (a->argc > 3) { /* wrong input */ @@ -1045,14 +1109,29 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod) { struct ast_translator *u; char tmp[80]; + RAII_VAR(struct ast_codec *, src_codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, dst_codec, NULL, ao2_cleanup); - if (add_format2index(t->src_format.id) || add_format2index(t->dst_format.id)) { + src_codec = ast_codec_get(t->src_codec.name, t->src_codec.type, t->src_codec.sample_rate); + if (!src_codec) { + ast_assert(0); + ast_log(LOG_WARNING, "Failed to register translator: unknown source codec %s\n", t->src_codec.name); + return -1; + } + + dst_codec = ast_codec_get(t->dst_codec.name, t->dst_codec.type, t->dst_codec.sample_rate); + if (!dst_codec) { + ast_log(LOG_WARNING, "Failed to register translator: unknown destination codec %s\n", t->dst_codec.name); + return -1; + } + + if (add_codec2index(src_codec) || add_codec2index(dst_codec)) { if (matrix_resize(0)) { ast_log(LOG_WARNING, "Translator matrix can not represent any more translators. Out of resources.\n"); return -1; } - add_format2index(t->src_format.id); - add_format2index(t->dst_format.id); + add_codec2index(src_codec); + add_codec2index(dst_codec); } if (!mod) { @@ -1064,15 +1143,15 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod) ast_log(LOG_WARNING, "empty buf size, you need to supply one\n"); return -1; } - if (!t->table_cost && !(t->table_cost = generate_table_cost(&t->src_format, &t->dst_format))) { + if (!t->table_cost && !(t->table_cost = generate_table_cost(src_codec, dst_codec))) { ast_log(LOG_WARNING, "Table cost could not be generated for %s, " "Please set table_cost variable on translator.\n", t->name); return -1; } t->module = mod; - t->src_fmt_index = format2index(t->src_format.id); - t->dst_fmt_index = format2index(t->dst_format.id); + t->src_fmt_index = codec2index(src_codec); + t->dst_fmt_index = codec2index(dst_codec); t->active = 1; if (t->src_fmt_index < 0 || t->dst_fmt_index < 0) { @@ -1080,12 +1159,12 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod) return -1; } if (t->src_fmt_index >= cur_max_index) { - ast_log(LOG_WARNING, "Source format %s is larger than cur_max_index\n", ast_getformatname(&t->src_format)); + ast_log(LOG_WARNING, "Source codec %s is larger than cur_max_index\n", t->src_codec.name); return -1; } if (t->dst_fmt_index >= cur_max_index) { - ast_log(LOG_WARNING, "Destination format %s is larger than cur_max_index\n", ast_getformatname(&t->dst_format)); + ast_log(LOG_WARNING, "Destination codec %s is larger than cur_max_index\n", t->dst_codec.name); return -1; } @@ -1106,9 +1185,9 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod) generate_computational_cost(t, 1); - ast_verb(2, "Registered translator '%s' from format %s to %s, table cost, %d, computational cost %d\n", - term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), - ast_getformatname(&t->src_format), ast_getformatname(&t->dst_format), t->table_cost, t->comp_cost); + ast_verb(2, "Registered translator '%s' from codec %s to %s, table cost, %d, computational cost %d\n", + term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), + t->src_codec.name, t->dst_codec.name, t->table_cost, t->comp_cost); AST_RWLIST_WRLOCK(&translators); @@ -1125,7 +1204,7 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod) } AST_RWLIST_TRAVERSE_SAFE_END; - /* if no existing translator was found for this format combination, + /* if no existing translator was found for this codec combination, add it to the beginning of the list */ if (t) { AST_RWLIST_INSERT_HEAD(&translators, t, list); @@ -1149,10 +1228,9 @@ int ast_unregister_translator(struct ast_translator *t) AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) { if (u == t) { AST_RWLIST_REMOVE_CURRENT(list); - ast_verb(2, "Unregistered translator '%s' from format %s to %s\n", + ast_verb(2, "Unregistered translator '%s' from codec %s to %s\n", term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), - ast_getformatname(&t->src_format), - ast_getformatname(&t->dst_format)); + t->src_codec.name, t->dst_codec.name); found = 1; break; } @@ -1187,91 +1265,105 @@ void ast_translator_deactivate(struct ast_translator *t) /*! \brief Calculate our best translator source format, given costs, and a desired destination */ int ast_translator_best_choice(struct ast_format_cap *dst_cap, struct ast_format_cap *src_cap, - struct ast_format *dst_fmt_out, - struct ast_format *src_fmt_out) + struct ast_format **dst_fmt_out, + struct ast_format **src_fmt_out) { - struct ast_format best; - struct ast_format_cap *joint_cap = ast_format_cap_joint(dst_cap, src_cap); + unsigned int besttablecost = INT_MAX; + unsigned int beststeps = INT_MAX; + RAII_VAR(struct ast_format *, best, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, bestdst, NULL, ao2_cleanup); + RAII_VAR(struct ast_format_cap *, joint_cap, NULL, ao2_cleanup); + int i; + int j; - ast_format_clear(&best); + if (!(joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { + return -1; + } + ast_format_cap_get_compatible(dst_cap, src_cap, joint_cap); - if (joint_cap) { /* yes, pick one and return */ - struct ast_format tmp_fmt; + for (i = 0; i < ast_format_cap_count(joint_cap); ++i) { + struct ast_format *fmt = + ast_format_cap_get_format(joint_cap, i); - ast_format_cap_iter_start(joint_cap); - while (!ast_format_cap_iter_next(joint_cap, &tmp_fmt)) { - /* We are guaranteed to find one common format. */ - if (!best.id) { - ast_format_copy(&best, &tmp_fmt); - continue; - } - /* If there are multiple common formats, pick the one with the highest sample rate */ - if (ast_format_rate(&best) < ast_format_rate(&tmp_fmt)) { - ast_format_copy(&best, &tmp_fmt); - continue; - } + if (!fmt) { + continue; + } + + if (!best) { + /* No ao2_ref operations needed, we're done with fmt */ + best = fmt; + continue; } - ast_format_cap_iter_end(joint_cap); - /* We are done, this is a common format to both. */ - ast_format_copy(dst_fmt_out, &best); - ast_format_copy(src_fmt_out, &best); - ast_format_cap_destroy(joint_cap); + if (ast_format_get_sample_rate(best) < + ast_format_get_sample_rate(fmt)) { + ao2_replace(best, fmt); + } + ao2_ref(fmt, -1); + } + + if (best) { + ao2_replace(*dst_fmt_out, best); + ao2_replace(*src_fmt_out, best); return 0; - } else { /* No, we will need to translate */ - unsigned int besttablecost = INT_MAX; - unsigned int beststeps = INT_MAX; - struct ast_format cur_dst; - struct ast_format cur_src; - struct ast_format bestdst; + } + /* need to translate */ + AST_RWLIST_RDLOCK(&translators); - ast_format_clear(&bestdst); + for (i = 0; i < ast_format_cap_count(dst_cap); ++i) { + struct ast_format *dst = + ast_format_cap_get_format(dst_cap, i); - AST_RWLIST_RDLOCK(&translators); - ast_format_cap_iter_start(dst_cap); - while (!ast_format_cap_iter_next(dst_cap, &cur_dst)) { - ast_format_cap_iter_start(src_cap); - while (!ast_format_cap_iter_next(src_cap, &cur_src)) { - int x = format2index(cur_src.id); - int y = format2index(cur_dst.id); - struct translator_path *trans; - - if (x < 0 || y < 0) { - continue; - } - trans = matrix_get(x, y); - if (!trans || !trans->step) { - continue; - } - if (trans->table_cost < besttablecost || trans->multistep < beststeps) { - /* better than what we have so far */ - ast_format_copy(&best, &cur_src); - ast_format_copy(&bestdst, &cur_dst); - besttablecost = trans->table_cost; - beststeps = trans->multistep; - } - } - ast_format_cap_iter_end(src_cap); + if (!dst) { + continue; } - ast_format_cap_iter_end(dst_cap); - AST_RWLIST_UNLOCK(&translators); - if (best.id) { - ast_format_copy(dst_fmt_out, &bestdst); - ast_format_copy(src_fmt_out, &best); - return 0; + for (j = 0; j < ast_format_cap_count(src_cap); ++j) { + struct ast_format *src = + ast_format_cap_get_format(src_cap, j); + int x, y; + + if (!src) { + continue; + } + + x = format2index(src); + y = format2index(dst); + if (x < 0 || y < 0) { + ao2_ref(src, -1); + continue; + } + if (!matrix_get(x, y) || !(matrix_get(x, y)->step)) { + ao2_ref(src, -1); + continue; + } + if (((matrix_get(x, y)->table_cost < besttablecost) || + (matrix_get(x, y)->multistep < beststeps))) { + /* better than what we have so far */ + ao2_replace(best, src); + ao2_replace(bestdst, dst); + besttablecost = matrix_get(x, y)->table_cost; + beststeps = matrix_get(x, y)->multistep; + } + ao2_ref(src, -1); } + ao2_ref(dst, -1); + } + AST_RWLIST_UNLOCK(&translators); + if (!best) { return -1; } + ao2_replace(*dst_fmt_out, bestdst); + ao2_replace(*src_fmt_out, best); + return 0; } unsigned int ast_translate_path_steps(struct ast_format *dst_format, struct ast_format *src_format) { unsigned int res = -1; - int src, dest; /* convert bitwise format numbers into array indices */ - src = format2index(src_format->id); - dest = format2index(dst_format->id); + int src = format2index(src_format); + int dest = format2index(dst_format); if (src < 0 || dest < 0) { ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src < 0 ? "starting" : "ending"); @@ -1288,25 +1380,72 @@ unsigned int ast_translate_path_steps(struct ast_format *dst_format, struct ast_ return res; } +static void check_translation_path( + struct ast_format_cap *dest, struct ast_format_cap *src, + struct ast_format_cap *result, struct ast_format *src_fmt, + enum ast_media_type type) +{ + int index, src_index = format2index(src_fmt); + /* For a given source format, traverse the list of + known formats to determine whether there exists + a translation path from the source format to the + destination format. */ + for (index = 0; (src_index >= 0) && index < cur_max_index; index++) { + struct ast_codec *codec = index2codec(index); + RAII_VAR(struct ast_format *, fmt, ast_format_create(codec), ao2_cleanup); + + ao2_ref(codec, -1); + + if (ast_format_get_type(fmt) != type) { + continue; + } + + /* if this is not a desired format, nothing to do */ + if (ast_format_cap_iscompatible_format(dest, fmt) == AST_FORMAT_CMP_NOT_EQUAL) { + continue; + } + + /* if the source is supplying this format, then + we can leave it in the result */ + if (ast_format_cap_iscompatible_format(src, fmt) == AST_FORMAT_CMP_EQUAL) { + continue; + } + + /* if we don't have a translation path from the src + to this format, remove it from the result */ + if (!matrix_get(src_index, index)->step) { + ast_format_cap_remove(result, fmt); + continue; + } + + /* now check the opposite direction */ + if (!matrix_get(index, src_index)->step) { + ast_format_cap_remove(result, fmt); + } + } + +} + void ast_translate_available_formats(struct ast_format_cap *dest, struct ast_format_cap *src, struct ast_format_cap *result) { - struct ast_format tmp_fmt; - struct ast_format cur_dest, cur_src; - int src_audio = 0; - int src_video = 0; + struct ast_format *cur_dest, *cur_src; int index; - ast_format_cap_iter_start(dest); - while (!ast_format_cap_iter_next(dest, &cur_dest)) { + for (index = 0; index < ast_format_cap_count(dest); ++index) { + if (!(cur_dest = ast_format_cap_get_format(dest, index))) { + continue; + } + /* We give preference to a joint format structure if possible */ - if (ast_format_cap_get_compatible_format(src, &cur_dest, &tmp_fmt)) { - ast_format_cap_add(result, &tmp_fmt); + if ((cur_src = ast_format_cap_get_compatible_format(src, cur_dest))) { + ast_format_cap_append(result, cur_src, 0); + ao2_ref(cur_src, -1); } else { /* Otherwise we just use the destination format */ - ast_format_cap_add(result, &cur_dest); + ast_format_cap_append(result, cur_dest, 0); } + ao2_ref(cur_dest, -1); } - ast_format_cap_iter_end(dest); /* if we don't have a source format, we just have to try all possible destination formats */ @@ -1314,91 +1453,19 @@ void ast_translate_available_formats(struct ast_format_cap *dest, struct ast_for return; } - ast_format_cap_iter_start(src); - while (!ast_format_cap_iter_next(src, &cur_src)) { - /* If we have a source audio format, get its format index */ - if (AST_FORMAT_GET_TYPE(cur_src.id) == AST_FORMAT_TYPE_AUDIO) { - src_audio = format2index(cur_src.id); - } - - /* If we have a source video format, get its format index */ - if (AST_FORMAT_GET_TYPE(cur_src.id) == AST_FORMAT_TYPE_VIDEO) { - src_video = format2index(cur_src.id); + for (index = 0; index < ast_format_cap_count(src); ++index) { + if (!(cur_src = ast_format_cap_get_format(src, index))) { + continue; } AST_RWLIST_RDLOCK(&translators); - - /* For a given source audio format, traverse the list of - known audio formats to determine whether there exists - a translation path from the source format to the - destination format. */ - for (index = 0; (src_audio >= 0) && index < cur_max_index; index++) { - ast_format_set(&tmp_fmt, index2format(index), 0); - - if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_AUDIO) { - continue; - } - - /* if this is not a desired format, nothing to do */ - if (!ast_format_cap_iscompatible(dest, &tmp_fmt)) { - continue; - } - - /* if the source is supplying this format, then - we can leave it in the result */ - if (ast_format_cap_iscompatible(src, &tmp_fmt)) { - continue; - } - - /* if we don't have a translation path from the src - to this format, remove it from the result */ - if (!matrix_get(src_audio, index)->step) { - ast_format_cap_remove_byid(result, tmp_fmt.id); - continue; - } - - /* now check the opposite direction */ - if (!matrix_get(index, src_audio)->step) { - ast_format_cap_remove_byid(result, tmp_fmt.id); - } - } - - /* For a given source video format, traverse the list of - known video formats to determine whether there exists - a translation path from the source format to the - destination format. */ - for (index = 0; (src_video >= 0) && index < cur_max_index; index++) { - ast_format_set(&tmp_fmt, index2format(index), 0); - if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_VIDEO) { - continue; - } - - /* if this is not a desired format, nothing to do */ - if (!ast_format_cap_iscompatible(dest, &tmp_fmt)) { - continue; - } - - /* if the source is supplying this format, then - we can leave it in the result */ - if (ast_format_cap_iscompatible(src, &tmp_fmt)) { - continue; - } - - /* if we don't have a translation path from the src - to this format, remove it from the result */ - if (!matrix_get(src_video, index)->step) { - ast_format_cap_remove_byid(result, tmp_fmt.id); - continue; - } - - /* now check the opposite direction */ - if (!matrix_get(index, src_video)->step) { - ast_format_cap_remove_byid(result, tmp_fmt.id); - } - } + check_translation_path(dest, src, result, + cur_src, AST_MEDIA_TYPE_AUDIO); + check_translation_path(dest, src, result, + cur_src, AST_MEDIA_TYPE_VIDEO); AST_RWLIST_UNLOCK(&translators); + ao2_ref(cur_src, -1); } - ast_format_cap_iter_end(src); } static void translate_shutdown(void) diff --git a/main/utils.c b/main/utils.c index 0097487a3..a916e79c8 100644 --- a/main/utils.c +++ b/main/utils.c @@ -1054,10 +1054,10 @@ struct ast_str *ast_dump_locks(void) if (!header_printed) { if (lock_info->lwp != -1) { ast_str_append(&str, 0, "=== Thread ID: 0x%lx LWP:%d (%s)\n", - (long) lock_info->thread_id, lock_info->lwp, lock_info->thread_name); + (long unsigned) lock_info->thread_id, lock_info->lwp, lock_info->thread_name); } else { ast_str_append(&str, 0, "=== Thread ID: 0x%lx (%s)\n", - (long) lock_info->thread_id, lock_info->thread_name); + (long unsigned) lock_info->thread_id, lock_info->thread_name); } header_printed = 1; } diff --git a/pbx/pbx_spool.c b/pbx/pbx_spool.c index 4461d7fc7..adec3b26a 100644 --- a/pbx/pbx_spool.c +++ b/pbx/pbx_spool.c @@ -53,6 +53,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/utils.h" #include "asterisk/options.h" +#include "asterisk/format.h" +#include "asterisk/format_cache.h" /* * pbx_spool is similar in spirit to qcall, but with substantially enhanced functionality... @@ -108,7 +110,7 @@ static void free_outgoing(struct outgoing *o) if (o->vars) { ast_variables_destroy(o->vars); } - o->capabilities = ast_format_cap_destroy(o->capabilities); + ao2_cleanup(o->capabilities); ast_string_field_free_memory(o); ast_free(o); } @@ -116,7 +118,6 @@ static void free_outgoing(struct outgoing *o) static struct outgoing *new_outgoing(const char *fn) { struct outgoing *o; - struct ast_format tmpfmt; o = ast_calloc(1, sizeof(*o)); if (!o) { @@ -144,12 +145,12 @@ static struct outgoing *new_outgoing(const char *fn) return NULL; } - o->capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + o->capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!o->capabilities) { free_outgoing(o); return NULL; } - ast_format_cap_add(o->capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(o->capabilities, ast_format_slin, 0); return o; } @@ -226,7 +227,7 @@ static int apply_outgoing(struct outgoing *o, FILE *f) o->maxretries = 0; } } else if (!strcasecmp(buf, "codecs")) { - ast_parse_allow_disallow(NULL, o->capabilities, c, 1); + ast_format_cap_update_by_allow_disallow(o->capabilities, c, 1); } else if (!strcasecmp(buf, "context")) { ast_string_field_set(o, context, c); } else if (!strcasecmp(buf, "extension")) { diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c index eeb4237d0..93ecd14b7 100644 --- a/res/ari/resource_bridges.c +++ b/res/ari/resource_bridges.c @@ -44,6 +44,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/format_cap.h" #include "asterisk/file.h" #include "asterisk/musiconhold.h" +#include "asterisk/format_cache.h" /*! * \brief Finds a bridge, filling the response with an error, if appropriate. @@ -303,19 +304,14 @@ static void *bridge_channel_control_thread(void *data) static struct ast_channel *prepare_bridge_media_channel(const char *type) { - RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy); - struct ast_format format; + RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup); - cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!cap) { return NULL; } - ast_format_cap_add(cap, ast_format_set(&format, AST_FORMAT_SLINEAR, 0)); - - if (!cap) { - return NULL; - } + ast_format_cap_append(cap, ast_format_slin, 0); return ast_request(type, cap, NULL, NULL, "ARI", NULL); } diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c index 393609298..cef1e7130 100644 --- a/res/ari/resource_channels.c +++ b/res/ari/resource_channels.c @@ -42,6 +42,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/stasis_app_snoop.h" #include "asterisk/stasis_channels.h" #include "asterisk/causes.h" +#include "asterisk/format_cache.h" #include "asterisk/core_local.h" #include "resource_channels.h" @@ -772,8 +773,7 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint, char *cid_name = NULL; int timeout = 30000; RAII_VAR(struct ast_format_cap *, cap, - ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK), ast_format_cap_destroy); - struct ast_format tmp_fmt; + ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup); char *stuff; struct ast_channel *chan; struct ast_channel *local_peer; @@ -787,7 +787,7 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint, ast_ari_response_alloc_failed(response); return; } - ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(cap, ast_format_slin, 0); if ((assignedids.uniqueid && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid)) || (assignedids.uniqueid2 && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid2))) { diff --git a/res/ari/resource_sounds.c b/res/ari/resource_sounds.c index 5be4bf9a8..5a523d387 100644 --- a/res/ari/resource_sounds.c +++ b/res/ari/resource_sounds.c @@ -46,8 +46,8 @@ static int add_format_information_cb(void *obj, void *arg, int flags) { char *language = obj; struct lang_format_info *args = arg; - struct ast_format format; - RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy); + int idx; + RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup); RAII_VAR(struct ast_media_index *, sounds_index, ast_sounds_get_index(), ao2_cleanup); if (!sounds_index) { @@ -59,27 +59,28 @@ static int add_format_information_cb(void *obj, void *arg, int flags) return CMP_STOP; } - ast_format_cap_iter_start(cap); - while (!ast_format_cap_iter_next(cap, &format)) { + for (idx = 0; idx < ast_format_cap_count(cap); idx++) { + struct ast_format *format = ast_format_cap_get_format(cap, idx); struct ast_json *lang_format_pair; - const char *format_name = ast_getformatname(&format); if (!ast_strlen_zero(args->format_filter) - && strcmp(args->format_filter, format_name)) { + && strcmp(args->format_filter, ast_format_get_name(format))) { + ao2_ref(format, -1); continue; } lang_format_pair = ast_json_pack("{s: s, s: s}", "language", language, - "format", format_name); + "format", ast_format_get_name(format)); if (!lang_format_pair) { - ast_format_cap_iter_end(cap); + ao2_ref(format, -1); return CMP_STOP; } ast_json_array_append(args->format_list, lang_format_pair); + ao2_ref(format, -1); } - ast_format_cap_iter_end(cap); + return 0; } diff --git a/res/parking/parking_applications.c b/res/parking/parking_applications.c index 51d6aff8f..8bb57b62b 100644 --- a/res/parking/parking_applications.c +++ b/res/parking/parking_applications.c @@ -37,6 +37,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/say.h" #include "asterisk/bridge_basic.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <application name="Park" language="en_US"> @@ -688,11 +689,10 @@ static void announce_to_dial(char *dial_string, char *announce_string, int parki struct ast_channel *dchan; struct outgoing_helper oh = { 0, }; int outstate; - struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); char buf[13]; char *dial_tech; char *cur_announce; - struct ast_format tmpfmt; dial_tech = strsep(&dial_string, "/"); ast_verb(3, "Dial Tech,String: (%s,%s)\n", dial_tech, dial_string); @@ -701,7 +701,7 @@ static void announce_to_dial(char *dial_string, char *announce_string, int parki ast_log(LOG_WARNING, "PARK: Failed to announce park.\n"); goto announce_cleanup; } - ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(cap_slin, ast_format_slin, 0); snprintf(buf, sizeof(buf), "%d", parkingspace); oh.vars = ast_variable_new("_PARKEDAT", buf, ""); @@ -737,7 +737,7 @@ static void announce_to_dial(char *dial_string, char *announce_string, int parki ast_hangup(dchan); announce_cleanup: - cap_slin = ast_format_cap_destroy(cap_slin); + ao2_cleanup(cap_slin); } static void park_announce_update_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) diff --git a/res/res_adsi.c b/res/res_adsi.c index 92987f072..e11432e29 100644 --- a/res/res_adsi.c +++ b/res/res_adsi.c @@ -50,6 +50,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/config.h" #include "asterisk/file.h" #include "asterisk/adsi.h" +#include "asterisk/format_cache.h" #define DEFAULT_ADSI_MAX_RETRIES 3 @@ -154,12 +155,14 @@ static int adsi_careful_send(struct ast_channel *chan, unsigned char *buf, int l { /* Sends carefully on a full duplex channel by using reading for timing */ - struct ast_frame *inf, outf; + struct ast_frame *inf; + struct ast_frame outf = { + .frametype = AST_FRAME_VOICE, + .subclass.format = ast_format_ulaw, + .data.ptr = buf, + }; int amt; - /* Zero out our outgoing frame */ - memset(&outf, 0, sizeof(outf)); - if (remain && *remain) { amt = len; @@ -169,9 +172,7 @@ static int adsi_careful_send(struct ast_channel *chan, unsigned char *buf, int l } else { *remain = *remain - amt; } - outf.frametype = AST_FRAME_VOICE; - ast_format_set(&outf.subclass.format, AST_FORMAT_ULAW, 0); - outf.data.ptr = buf; + outf.datalen = amt; outf.samples = amt; if (ast_write(chan, &outf)) { @@ -201,7 +202,7 @@ static int adsi_careful_send(struct ast_channel *chan, unsigned char *buf, int l continue; } - if (inf->subclass.format.id != AST_FORMAT_ULAW) { + if (ast_format_cmp(inf->subclass.format, ast_format_ulaw) != AST_FORMAT_CMP_EQUAL) { ast_log(LOG_WARNING, "Channel not in ulaw?\n"); ast_frfree(inf); return -1; @@ -212,9 +213,6 @@ static int adsi_careful_send(struct ast_channel *chan, unsigned char *buf, int l } else if (remain) { *remain = inf->datalen - amt; } - outf.frametype = AST_FRAME_VOICE; - ast_format_set(&outf.subclass.format, AST_FORMAT_ULAW, 0); - outf.data.ptr = buf; outf.datalen = amt; outf.samples = amt; if (ast_write(chan, &outf)) { @@ -245,11 +243,9 @@ static int __adsi_transmit_messages(struct ast_channel *chan, unsigned char **ms } while (retries < maxretries) { - struct ast_format tmpfmt; if (!(ast_channel_adsicpe(chan) & ADSI_FLAG_DATAMODE)) { /* Generate CAS (no SAS) */ - ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0); - ast_gen_cas(buf, 0, 680, &tmpfmt); + ast_gen_cas(buf, 0, 680, ast_format_ulaw); /* Send CAS */ if (adsi_careful_send(chan, buf, 680, NULL)) { @@ -308,7 +304,7 @@ static int __adsi_transmit_messages(struct ast_channel *chan, unsigned char **ms def= ast_channel_defer_dtmf(chan); #endif while ((x < 6) && msg[x]) { - if ((res = adsi_generate(buf + pos, msgtype[x], msg[x], msglen[x], x+1 - start, (x == 5) || !msg[x+1], ast_format_set(&tmpfmt, AST_FORMAT_ULAW,0))) < 0) { + if ((res = adsi_generate(buf + pos, msgtype[x], msg[x], msglen[x], x+1 - start, (x == 5) || !msg[x+1], ast_format_ulaw)) < 0) { ast_log(LOG_WARNING, "Failed to generate ADSI message %d on channel %s\n", x + 1, ast_channel_name(chan)); return -1; } @@ -395,11 +391,8 @@ static int adsi_transmit_message_full(struct ast_channel *chan, unsigned char *m { unsigned char *msgs[5] = { NULL, NULL, NULL, NULL, NULL }; int msglens[5], msgtypes[5], newdatamode = (ast_channel_adsicpe(chan) & ADSI_FLAG_DATAMODE), res, x, waitforswitch = 0; - struct ast_format writeformat; - struct ast_format readformat; - - ast_format_copy(&writeformat, ast_channel_writeformat(chan)); - ast_format_copy(&readformat, ast_channel_readformat(chan)); + RAII_VAR(struct ast_format *, writeformat, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, readformat, NULL, ao2_cleanup); for (x = 0; x < msglen; x += (msg[x+1]+2)) { if (msg[x] == ADSI_SWITCH_TO_DATA) { @@ -426,16 +419,19 @@ static int adsi_transmit_message_full(struct ast_channel *chan, unsigned char *m ast_stopstream(chan); - if (ast_set_write_format_by_id(chan, AST_FORMAT_ULAW)) { + writeformat = ao2_bump(ast_channel_writeformat(chan)); + readformat = ao2_bump(ast_channel_readformat(chan)); + + if (ast_set_write_format(chan, ast_format_ulaw)) { ast_log(LOG_WARNING, "Unable to set write format to ULAW\n"); return -1; } - if (ast_set_read_format_by_id(chan, AST_FORMAT_ULAW)) { + if (ast_set_read_format(chan, ast_format_ulaw)) { ast_log(LOG_WARNING, "Unable to set read format to ULAW\n"); - if (writeformat.id) { - if (ast_set_write_format(chan, &writeformat)) { - ast_log(LOG_WARNING, "Unable to restore write format to %s\n", ast_getformatname(&writeformat)); + if (writeformat) { + if (ast_set_write_format(chan, writeformat)) { + ast_log(LOG_WARNING, "Unable to restore write format to %s\n", ast_format_get_name(writeformat)); } } return -1; @@ -454,11 +450,11 @@ static int adsi_transmit_message_full(struct ast_channel *chan, unsigned char *m ast_channel_adsicpe_set(chan, (ast_channel_adsicpe(chan) & ~ADSI_FLAG_DATAMODE) | newdatamode); } - if (writeformat.id) { - ast_set_write_format(chan, &writeformat); + if (writeformat) { + ast_set_write_format(chan, writeformat); } - if (readformat.id) { - ast_set_read_format(chan, &readformat); + if (readformat) { + ast_set_read_format(chan, readformat); } if (!res) { diff --git a/res/res_agi.c b/res/res_agi.c index 67a213f8d..b612f7d72 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -68,6 +68,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/netsock2.h" #include "asterisk/stasis_channels.h" #include "asterisk/stasis_message_router.h" +#include "asterisk/format_cache.h" #define AST_API_MODULE #include "asterisk/agi.h" @@ -2538,8 +2539,7 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const int silence = 0; /* amount of silence to allow */ int gotsilence = 0; /* did we timeout for silence? */ char *silencestr = NULL; - struct ast_format rfmt; - ast_format_clear(&rfmt); + RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup); /* XXX EAGI FIXME XXX */ @@ -2569,8 +2569,8 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const } if (silence > 0) { - ast_format_copy(&rfmt, ast_channel_readformat(chan)); - res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR); + rfmt = ao2_bump(ast_channel_readformat(chan)); + res = ast_set_read_format(chan, ast_format_slin); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); ast_agi_send(agi->fd, chan, "200 result=%d\n", res); @@ -2694,7 +2694,7 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const } if (silence > 0) { - res = ast_set_read_format(chan, &rfmt); + res = ast_set_read_format(chan, rfmt); if (res) ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(chan)); ast_dsp_free(sildet); @@ -3032,7 +3032,6 @@ static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, const c static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[]) { struct ast_format_cap *cap; - struct ast_format tmpfmt; /* If a structure already exists, return an error */ if (agi->speech) { @@ -3040,16 +3039,16 @@ static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, con return RESULT_SUCCESS; } - if (!(cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) { + if (!(cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return RESULT_FAILURE; } - ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(cap, ast_format_slin, 0); if ((agi->speech = ast_speech_new(argv[2], cap))) { ast_agi_send(agi->fd, chan, "200 result=1\n"); } else { ast_agi_send(agi->fd, chan, "200 result=0\n"); } - cap = ast_format_cap_destroy(cap); + ao2_ref(cap, -1); return RESULT_SUCCESS; } @@ -3182,7 +3181,6 @@ static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, const char *prompt; char dtmf = 0, tmp[4096] = "", *buf = tmp; int timeout = 0, offset = 0, res = 0, i = 0; - struct ast_format old_read_format; long current_offset = 0; const char *reason = NULL; struct ast_frame *fr = NULL; @@ -3206,8 +3204,7 @@ static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, offset = atoi(argv[4]); /* We want frames coming in signed linear */ - ast_format_copy(&old_read_format, ast_channel_readformat(chan)); - if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) { + if (ast_set_read_format(chan, ast_format_slin)) { ast_agi_send(agi->fd, chan, "200 result=0\n"); return RESULT_SUCCESS; } @@ -4195,23 +4192,26 @@ static int agi_exec(struct ast_channel *chan, const char *data) static int eagi_exec(struct ast_channel *chan, const char *data) { int res; - struct ast_format readformat; + struct ast_format *readformat; if (ast_check_hangup(chan)) { ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n"); return 0; } - ast_format_copy(&readformat, ast_channel_readformat(chan)); - if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) { + readformat = ao2_bump(ast_channel_readformat(chan)); + if (ast_set_read_format(chan, ast_format_slin)) { ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", ast_channel_name(chan)); + ao2_ref(readformat, -1); return -1; } res = agi_exec_full(chan, data, 1, 0); if (!res) { - if (ast_set_read_format(chan, &readformat)) { - ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", ast_channel_name(chan), ast_getformatname(&readformat)); + if (ast_set_read_format(chan, readformat)) { + ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", ast_channel_name(chan), + ast_format_get_name(readformat)); } } + ao2_ref(readformat, -1); return res; } diff --git a/res/res_calendar.c b/res/res_calendar.c index ae52cbfce..77f8ef662 100644 --- a/res/res_calendar.c +++ b/res/res_calendar.c @@ -55,6 +55,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/cli.h" #include "asterisk/pbx.h" #include "asterisk/app.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <function name="CALENDAR_BUSY" language="en_US"> @@ -730,6 +731,7 @@ static void *do_notify(void *data) struct ast_variable *itervar; char *tech, *dest; char buf[8]; + struct ast_format_cap *caps; tech = ast_strdupa(event->owner->notify_channel); @@ -760,12 +762,19 @@ static void *do_notify(void *data) } ast_channel_tech_set(chan, &null_tech); - ast_format_set(ast_channel_writeformat(chan), AST_FORMAT_SLINEAR, 0); - ast_format_set(ast_channel_readformat(chan), AST_FORMAT_SLINEAR, 0); - ast_format_set(ast_channel_rawwriteformat(chan), AST_FORMAT_SLINEAR, 0); - ast_format_set(ast_channel_rawreadformat(chan), AST_FORMAT_SLINEAR, 0); - /* clear native formats and set to slinear. write format is signlear so just use that to set it */ - ast_format_cap_set(ast_channel_nativeformats(chan), ast_channel_writeformat(chan)); + ast_channel_set_writeformat(chan, ast_format_slin); + ast_channel_set_readformat(chan, ast_format_slin); + ast_channel_set_rawwriteformat(chan, ast_format_slin); + ast_channel_set_rawreadformat(chan, ast_format_slin); + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_log(LOG_ERROR, "Could not allocate capabilities, notification not being sent!\n"); + goto notify_cleanup; + } + ast_format_cap_append(caps, ast_format_slin, 0); + ast_channel_nativeformats_set(chan, caps); + ao2_ref(caps, -1); ast_channel_unlock(chan); diff --git a/res/res_clioriginate.c b/res/res_clioriginate.c index cd8b5dde1..3903b6c3b 100644 --- a/res/res_clioriginate.c +++ b/res/res_clioriginate.c @@ -38,6 +38,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$"); #include "asterisk/cli.h" #include "asterisk/utils.h" #include "asterisk/frame.h" +#include "asterisk/format_cache.h" /*! The timeout for originated calls, in seconds */ #define TIMEOUT 30 @@ -57,7 +58,6 @@ static char *orig_app(int fd, const char *chan, const char *app, const char *app char *chandata; int reason = 0; struct ast_format_cap *cap; - struct ast_format tmpfmt; if (ast_strlen_zero(app)) return CLI_SHOWUSAGE; @@ -70,12 +70,12 @@ static char *orig_app(int fd, const char *chan, const char *app, const char *app return CLI_SHOWUSAGE; } - if (!(cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) { + if (!(cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return CLI_FAILURE; } - ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(cap, ast_format_slin, 0); ast_pbx_outgoing_app(chantech, cap, chandata, TIMEOUT * 1000, app, appdata, &reason, 0, NULL, NULL, NULL, NULL, NULL, NULL); - cap = ast_format_cap_destroy(cap); + ao2_ref(cap, -1); return CLI_SUCCESS; } @@ -96,7 +96,6 @@ static char *orig_exten(int fd, const char *chan, const char *data) char *context = NULL; int reason = 0; struct ast_format_cap *cap; - struct ast_format tmpfmt; chandata = ast_strdupa(chan); @@ -115,12 +114,12 @@ static char *orig_exten(int fd, const char *chan, const char *data) exten = "s"; if (ast_strlen_zero(context)) context = "default"; - if (!(cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) { + if (!(cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { return CLI_FAILURE; } - ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(cap, ast_format_slin, 0); ast_pbx_outgoing_exten(chantech, cap, chandata, TIMEOUT * 1000, context, exten, 1, &reason, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL); - cap = ast_format_cap_destroy(cap); + ao2_ref(cap, -1); return CLI_SUCCESS; } diff --git a/res/res_fax.c b/res/res_fax.c index 758309822..d59ab09e6 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -89,6 +89,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/translate.h" #include "asterisk/stasis.h" #include "asterisk/stasis_channels.h" +#include "asterisk/smoother.h" +#include "asterisk/format_cache.h" /*** DOCUMENTATION <application name="ReceiveFAX" language="en_US" module="res_fax"> @@ -453,10 +455,10 @@ struct fax_gateway { /*! \brief a flag to track the state of our negotiation */ enum ast_t38_state t38_state; /*! \brief original audio formats */ - struct ast_format chan_read_format; - struct ast_format chan_write_format; - struct ast_format peer_read_format; - struct ast_format peer_write_format; + struct ast_format *chan_read_format; + struct ast_format *chan_write_format; + struct ast_format *peer_read_format; + struct ast_format *peer_write_format; }; /*! \brief used for fax detect framehook */ @@ -468,7 +470,7 @@ struct fax_detect { /*! \brief DSP Processor */ struct ast_dsp *dsp; /*! \brief original audio formats */ - struct ast_format orig_format; + struct ast_format *orig_format; /*! \brief fax session details */ struct ast_fax_session_details *details; /*! \brief mode */ @@ -1570,20 +1572,18 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det int timeout = RES_FAX_TIMEOUT; int chancount; unsigned int expected_frametype = -1; - union ast_frame_subclass expected_framesubclass = { .integer = -1 }; + struct ast_frame_subclass expected_framesubclass = { .integer = 0, }; unsigned int t38negotiated = (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED); struct ast_control_t38_parameters t38_parameters; const char *tempvar; struct ast_fax_session *fax = NULL; struct ast_frame *frame = NULL; struct ast_channel *c = chan; - struct ast_format orig_write_format; - struct ast_format orig_read_format; + RAII_VAR(struct ast_format *, orig_write_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, orig_read_format, NULL, ao2_cleanup); int remaining_time; struct timeval start; - ast_format_clear(&orig_write_format); - ast_format_clear(&orig_read_format); chancount = 1; /* create the FAX session */ @@ -1607,10 +1607,10 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det report_fax_status(chan, details, "Allocating Resources"); if (details->caps & AST_FAX_TECH_AUDIO) { - expected_frametype = AST_FRAME_VOICE;; - ast_format_set(&expected_framesubclass.format, AST_FORMAT_SLINEAR, 0); - ast_format_copy(&orig_write_format, ast_channel_writeformat(chan)); - if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) { + expected_frametype = AST_FRAME_VOICE; + expected_framesubclass.format = ast_format_slin; + orig_write_format = ao2_bump(ast_channel_writeformat(chan)); + if (ast_set_write_format(chan, ast_format_slin) < 0) { ast_log(LOG_ERROR, "channel '%s' failed to set write format to signed linear'.\n", ast_channel_name(chan)); ao2_lock(faxregistry.container); ao2_unlink(faxregistry.container, fax); @@ -1619,8 +1619,8 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det ast_channel_unlock(chan); return -1; } - ast_format_copy(&orig_read_format, ast_channel_readformat(chan)); - if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) { + orig_read_format = ao2_bump(ast_channel_readformat(chan)); + if (ast_set_read_format(chan, ast_format_slin) < 0) { ast_log(LOG_ERROR, "channel '%s' failed to set read format to signed linear.\n", ast_channel_name(chan)); ao2_lock(faxregistry.container); ao2_unlink(faxregistry.container, fax); @@ -1724,8 +1724,10 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det ast_verb(3, "Channel '%s' switched to T.38 FAX session '%u'.\n", ast_channel_name(chan), fax->id); } - } else if ((frame->frametype == expected_frametype) && - (!memcmp(&frame->subclass, &expected_framesubclass, sizeof(frame->subclass)))) { + } else if ((frame->frametype == expected_frametype) && (expected_framesubclass.integer == frame->subclass.integer) && + ((!frame->subclass.format && !expected_framesubclass.format) || + (frame->subclass.format && expected_framesubclass.format && + (ast_format_cmp(frame->subclass.format, expected_framesubclass.format) != AST_FORMAT_CMP_NOT_EQUAL)))) { struct ast_frame *f; if (fax->smoother) { @@ -1809,11 +1811,11 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det * restore them now */ if (chancount) { - if (orig_read_format.id) { - ast_set_read_format(chan, &orig_read_format); + if (orig_read_format) { + ast_set_read_format(chan, orig_read_format); } - if (orig_write_format.id) { - ast_set_write_format(chan, &orig_write_format); + if (orig_write_format) { + ast_set_write_format(chan, orig_write_format); } } @@ -2823,6 +2825,11 @@ static void destroy_gateway(void *data) ao2_ref(gateway->s, -1); gateway->s = NULL; } + + ao2_cleanup(gateway->chan_read_format); + ao2_cleanup(gateway->chan_write_format); + ao2_cleanup(gateway->peer_read_format); + ao2_cleanup(gateway->peer_write_format); } /*! \brief Create a new fax gateway object. @@ -3274,14 +3281,14 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct set_channel_variables(chan, details); if (gateway->bridged) { - ast_set_read_format(chan, &gateway->chan_read_format); - ast_set_read_format(chan, &gateway->chan_write_format); + ast_set_read_format(chan, gateway->chan_read_format); + ast_set_read_format(chan, gateway->chan_write_format); ast_channel_unlock(chan); peer = ast_channel_bridge_peer(chan); if (peer) { - ast_set_read_format(peer, &gateway->peer_read_format); - ast_set_read_format(peer, &gateway->peer_write_format); + ast_set_read_format(peer, gateway->peer_read_format); + ast_set_read_format(peer, gateway->peer_write_format); ast_channel_make_compatible(chan, peer); } ast_channel_lock(chan); @@ -3326,18 +3333,18 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct /* we are bridged, change r/w formats to SLIN for v21 preamble * detection and T.30 */ - ast_format_copy(&gateway->chan_read_format, ast_channel_readformat(chan)); - ast_format_copy(&gateway->chan_write_format, ast_channel_readformat(chan)); + ao2_replace(gateway->chan_read_format, ast_channel_readformat(chan)); + ao2_replace(gateway->chan_write_format, ast_channel_readformat(chan)); - ast_format_copy(&gateway->peer_read_format, ast_channel_readformat(peer)); - ast_format_copy(&gateway->peer_write_format, ast_channel_readformat(peer)); + ao2_replace(gateway->peer_read_format, ast_channel_readformat(peer)); + ao2_replace(gateway->peer_write_format, ast_channel_readformat(peer)); - ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR); - ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR); + ast_set_read_format(chan, ast_format_slin); + ast_set_write_format(chan, ast_format_slin); ast_channel_unlock(chan); - ast_set_read_format_by_id(peer, AST_FORMAT_SLINEAR); - ast_set_write_format_by_id(peer, AST_FORMAT_SLINEAR); + ast_set_read_format(peer, ast_format_slin); + ast_set_write_format(peer, ast_format_slin); ast_channel_make_compatible(chan, peer); ast_channel_lock(chan); @@ -3361,12 +3368,9 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct /* only handle VOICE, MODEM, and CONTROL frames*/ switch (f->frametype) { case AST_FRAME_VOICE: - switch (f->subclass.format.id) { - case AST_FORMAT_SLINEAR: - case AST_FORMAT_ALAW: - case AST_FORMAT_ULAW: - break; - default: + if ((ast_format_cmp(f->subclass.format, ast_format_slin) != AST_FORMAT_CMP_EQUAL) && + (ast_format_cmp(f->subclass.format, ast_format_alaw) != AST_FORMAT_CMP_EQUAL) && + (ast_format_cmp(f->subclass.format, ast_format_ulaw) != AST_FORMAT_CMP_EQUAL)) { return f; } break; @@ -3412,7 +3416,7 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct if (gateway->t38_state == T38_STATE_NEGOTIATED) { /* framehooks are called in __ast_read() before frame format * translation is done, so we need to translate here */ - if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id != AST_FORMAT_SLINEAR)) { + if ((f->frametype == AST_FRAME_VOICE) && (ast_format_cmp(f->subclass.format, ast_format_slin) != AST_FORMAT_CMP_EQUAL)) { if (ast_channel_readtrans(active) && (f = ast_translate(ast_channel_readtrans(active), f, 1)) == NULL) { f = &ast_null_frame; return f; @@ -3424,7 +3428,8 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct * write would fail, or even if a failure would be fatal so for * now we'll just ignore the return value. */ gateway->s->tech->write(gateway->s, f); - if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id != AST_FORMAT_SLINEAR) && ast_channel_readtrans(active)) { + if ((f->frametype == AST_FRAME_VOICE) && (ast_format_cmp(f->subclass.format, ast_format_slin) != AST_FORMAT_CMP_EQUAL) && + ast_channel_readtrans(active)) { /* Only free the frame if we translated / duplicated it - otherwise, * let whatever is outside the frame hook do it */ ast_frfree(f); @@ -3435,15 +3440,16 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct /* force silence on the line if T.38 negotiation might be taking place */ if (gateway->t38_state != T38_STATE_UNAVAILABLE && gateway->t38_state != T38_STATE_REJECTED) { - if (f->frametype == AST_FRAME_VOICE && f->subclass.format.id == AST_FORMAT_SLINEAR) { + if (f->frametype == AST_FRAME_VOICE && + (ast_format_cmp(f->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) { short silence_buf[f->samples]; struct ast_frame silence_frame = { .frametype = AST_FRAME_VOICE, + .subclass.format = ast_format_slin, .data.ptr = silence_buf, .samples = f->samples, .datalen = sizeof(silence_buf), }; - ast_format_set(&silence_frame.subclass.format, AST_FORMAT_SLINEAR, 0); memset(silence_buf, 0, sizeof(silence_buf)); return ast_frisolate(&silence_frame); } else { @@ -3513,6 +3519,7 @@ static void destroy_faxdetect(void *data) faxdetect->dsp = NULL; } ao2_ref(faxdetect->details, -1); + ao2_cleanup(faxdetect->orig_format); } /*! \brief Create a new fax detect object. @@ -3587,23 +3594,22 @@ static struct ast_frame *fax_detect_framehook(struct ast_channel *chan, struct a switch (event) { case AST_FRAMEHOOK_EVENT_ATTACHED: /* Setup format for DSP on ATTACH*/ - ast_format_copy(&faxdetect->orig_format, ast_channel_readformat(chan)); - switch (ast_channel_readformat(chan)->id) { - case AST_FORMAT_SLINEAR: - case AST_FORMAT_ALAW: - case AST_FORMAT_ULAW: - break; - default: - if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) { - ast_framehook_detach(chan, details->faxdetect_id); - details->faxdetect_id = -1; - return f; - } + ao2_replace(faxdetect->orig_format, ast_channel_readformat(chan)); + + if ((ast_format_cmp(ast_channel_readformat(chan), ast_format_slin) != AST_FORMAT_CMP_EQUAL) && + (ast_format_cmp(ast_channel_readformat(chan), ast_format_alaw) != AST_FORMAT_CMP_EQUAL) && + (ast_format_cmp(ast_channel_readformat(chan), ast_format_ulaw) != AST_FORMAT_CMP_EQUAL)) { + if (ast_set_read_format(chan, ast_format_slin)) { + ast_framehook_detach(chan, details->faxdetect_id); + details->faxdetect_id = -1; + return f; + } } + return NULL; case AST_FRAMEHOOK_EVENT_DETACHED: /* restore audio formats when we are detached */ - ast_set_read_format(chan, &faxdetect->orig_format); + ast_set_read_format(chan, faxdetect->orig_format); ast_channel_unlock(chan); peer = ast_channel_bridge_peer(chan); if (peer) { @@ -3638,13 +3644,10 @@ static struct ast_frame *fax_detect_framehook(struct ast_channel *chan, struct a return f; } /* We can only process some formats*/ - switch (f->subclass.format.id) { - case AST_FORMAT_SLINEAR: - case AST_FORMAT_ALAW: - case AST_FORMAT_ULAW: - break; - default: - return f; + if ((ast_format_cmp(f->subclass.format, ast_format_slin) != AST_FORMAT_CMP_EQUAL) && + (ast_format_cmp(f->subclass.format, ast_format_alaw) != AST_FORMAT_CMP_EQUAL) && + (ast_format_cmp(f->subclass.format, ast_format_ulaw) != AST_FORMAT_CMP_EQUAL)) { + return f; } break; case AST_FRAME_CONTROL: diff --git a/res/res_fax_spandsp.c b/res/res_fax_spandsp.c index 75018e864..63be1b3cb 100644 --- a/res/res_fax_spandsp.c +++ b/res/res_fax_spandsp.c @@ -65,6 +65,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/astobj2.h" #include "asterisk/res_fax.h" #include "asterisk/channel.h" +#include "asterisk/format_cache.h" #define SPANDSP_FAX_SAMPLES 160 #define SPANDSP_FAX_TIMER_RATE 8000 / SPANDSP_FAX_SAMPLES /* 50 ticks per second, 20ms, 160 samples per second */ @@ -609,9 +610,9 @@ static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s) struct ast_frame fax_frame = { .frametype = AST_FRAME_VOICE, .src = "res_fax_spandsp_g711", + .subclass.format = ast_format_slin, }; struct ast_frame *f = &fax_frame; - ast_format_set(&fax_frame.subclass.format, AST_FORMAT_SLINEAR, 0); if (ast_timer_ack(p->timer, 1) < 0) { ast_log(LOG_ERROR, "Failed to acknowledge timer for FAX session '%u'\n", s->id); @@ -664,20 +665,21 @@ static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame return -1; } - ast_debug(5, "frame={ datalen=%d, samples=%d, mallocd=%d, src=%s, flags=%u, ts=%ld, len=%ld, seqno=%d, data.ptr=%p, subclass.format.id=%u }\n", f->datalen, f->samples, f->mallocd, f->src, f->flags, f->ts, f->len, f->seqno, f->data.ptr, f->subclass.format.id); + ast_debug(5, "frame={ datalen=%d, samples=%d, mallocd=%d, src=%s, flags=%u, ts=%ld, len=%ld, seqno=%d, data.ptr=%p, subclass.format=%s }\n", f->datalen, f->samples, f->mallocd, f->src, f->flags, f->ts, f->len, f->seqno, f->data.ptr, ast_format_get_name(f->subclass.format)); /* slinear frame can be passed to spandsp */ - if (f->subclass.format.id == AST_FORMAT_SLINEAR) { + if (ast_format_cmp(f->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) { modem_connect_tones_rx(p->tone_state, f->data.ptr, f->samples); /* alaw/ulaw frame must be converted to slinear before passing to spandsp */ - } else if (f->subclass.format.id == AST_FORMAT_ALAW || f->subclass.format.id == AST_FORMAT_ULAW) { + } else if (ast_format_cmp(f->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL || + ast_format_cmp(f->subclass.format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) { if (!(slndata = ast_malloc(sizeof(*slndata) * f->samples))) { return -1; } - decoder = g711_init(NULL, (f->subclass.format.id == AST_FORMAT_ALAW ? G711_ALAW : G711_ULAW)); + decoder = g711_init(NULL, (ast_format_cmp(f->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL ? G711_ALAW : G711_ULAW)); g711_decode(decoder, slndata, f->data.ptr, f->samples); - ast_debug(5, "spandsp transcoding frame from %s to slinear for v21 detection\n", (f->subclass.format.id == AST_FORMAT_ALAW ? "G711_ALAW" : "G711_ULAW")); + ast_debug(5, "spandsp transcoding frame from %s to slinear for v21 detection\n", ast_format_get_name(f->subclass.format)); modem_connect_tones_rx(p->tone_state, slndata, f->samples); g711_release(decoder); #if SPANDSP_RELEASE_DATE >= 20090220 @@ -687,7 +689,7 @@ static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame /* frame in other formats cannot be passed to spandsp, it could cause segfault */ } else { - ast_log(LOG_WARNING, "Unknown frame format %u, v.21 detection skipped\n", f->subclass.format.id); + ast_log(LOG_WARNING, "Frame format %s not supported, v.21 detection skipped\n", ast_format_get_name(f->subclass.format)); return -1; } @@ -749,6 +751,7 @@ static int spandsp_fax_gw_t30_gen(struct ast_channel *chan, void *data, int len, struct ast_frame *f; struct ast_frame t30_frame = { .frametype = AST_FRAME_VOICE, + .subclass.format = ast_format_slin, .src = "res_fax_spandsp_g711", .samples = samples, .flags = AST_FAX_FRFLAG_GATEWAY, @@ -756,7 +759,6 @@ static int spandsp_fax_gw_t30_gen(struct ast_channel *chan, void *data, int len, AST_FRAME_SET_BUFFER(&t30_frame, buffer, AST_FRIENDLY_OFFSET, t30_frame.samples * sizeof(int16_t)); - ast_format_set(&t30_frame.subclass.format, AST_FORMAT_SLINEAR, 0); if (!(f = ast_frisolate(&t30_frame))) { return p->isdone ? -1 : res; } @@ -878,7 +880,8 @@ static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct a /* Process a IFP packet */ if ((f->frametype == AST_FRAME_MODEM) && (f->subclass.integer == AST_MODEM_T38)) { return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno); - } else if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id == AST_FORMAT_SLINEAR)) { + } else if ((f->frametype == AST_FRAME_VOICE) && + (ast_format_cmp(f->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) { return t38_gateway_rx(&p->t38_gw_state, f->data.ptr, f->samples); } diff --git a/res/res_format_attr_celt.c b/res/res_format_attr_celt.c index 1249f0472..7d7c0f844 100644 --- a/res/res_format_attr_celt.c +++ b/res/res_format_attr_celt.c @@ -45,152 +45,148 @@ struct celt_attr { unsigned int framesize; }; -static int celt_sdp_parse(struct ast_format_attr *format_attr, const char *attributes) +static void celt_destroy(struct ast_format *format) { - struct celt_attr *attr = (struct celt_attr *) format_attr; + struct celt_attr *attr = ast_format_get_attribute_data(format); + + ast_free(attr); +} + +static int celt_clone(const struct ast_format *src, struct ast_format *dst) +{ + struct celt_attr *original = ast_format_get_attribute_data(src); + struct celt_attr *attr = ast_calloc(1, sizeof(*attr)); + + if (!attr) { + return -1; + } + + if (original) { + *attr = *original; + } + + ast_format_set_attribute_data(dst, attr); + + return 0; +} + +static struct ast_format *celt_parse_sdp_fmtp(const struct ast_format *format, const char *attributes) +{ + struct ast_format *cloned; + struct celt_attr *attr; unsigned int val; + cloned = ast_format_clone(format); + if (!cloned) { + return NULL; + } + attr = ast_format_get_attribute_data(cloned); + if (sscanf(attributes, "framesize=%30u", &val) == 1) { attr->framesize = val; } - return 0; + return cloned; } -static void celt_sdp_generate(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str) +static void celt_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str) { - struct celt_attr *attr = (struct celt_attr *) format_attr; + struct celt_attr *attr = ast_format_get_attribute_data(format); - if (!attr->framesize) { + if (!attr || !attr->framesize) { return; } ast_str_append(str, 0, "a=fmtp:%u framesize=%u\r\n", payload, attr->framesize); } -static enum ast_format_cmp_res celt_cmp(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2) +static enum ast_format_cmp_res celt_cmp(const struct ast_format *format1, const struct ast_format *format2) { - struct celt_attr *attr1 = (struct celt_attr *) fattr1; - struct celt_attr *attr2 = (struct celt_attr *) fattr2; + struct celt_attr *attr1 = ast_format_get_attribute_data(format1); + struct celt_attr *attr2 = ast_format_get_attribute_data(format2); - if (attr1->samplerate == attr2->samplerate) { + if (((!attr1 || !attr1->samplerate) && (!attr2 || !attr2->samplerate)) || + (attr1->samplerate == attr2->samplerate)) { return AST_FORMAT_CMP_EQUAL; } + return AST_FORMAT_CMP_NOT_EQUAL; } -static int celt_get_val(const struct ast_format_attr *fattr, int key, void *result) +static struct ast_format *celt_getjoint(const struct ast_format *format1, const struct ast_format *format2) { - const struct celt_attr *attr = (struct celt_attr *) fattr; - int *val = result; - - switch (key) { - case CELT_ATTR_KEY_SAMP_RATE: - *val = attr->samplerate; - break; - case CELT_ATTR_KEY_MAX_BITRATE: - *val = attr->maxbitrate; - break; - case CELT_ATTR_KEY_FRAME_SIZE: - *val = attr->framesize; - break; - default: - ast_log(LOG_WARNING, "unknown attribute type %d\n", key); - return -1; - } - return 0; -} + struct celt_attr *attr1 = ast_format_get_attribute_data(format1); + struct celt_attr *attr2 = ast_format_get_attribute_data(format2); + struct ast_format *jointformat; + struct celt_attr *jointattr; -static int celt_isset(const struct ast_format_attr *fattr, va_list ap) -{ - enum celt_attr_keys key; - const struct celt_attr *attr = (struct celt_attr *) fattr; - - for (key = va_arg(ap, int); - key != AST_FORMAT_ATTR_END; - key = va_arg(ap, int)) - { - switch (key) { - case CELT_ATTR_KEY_SAMP_RATE: - if (attr->samplerate != (va_arg(ap, int))) { - return -1; - } - break; - case CELT_ATTR_KEY_MAX_BITRATE: - if (attr->maxbitrate != (va_arg(ap, int))) { - return -1; - } - break; - case CELT_ATTR_KEY_FRAME_SIZE: - if (attr->framesize != (va_arg(ap, int))) { - return -1; - } - break; - default: - ast_log(LOG_WARNING, "unknown attribute type %u\n", key); - return -1; - } + if (attr1 && attr2 && (attr1->samplerate != attr2->samplerate)) { + return NULL; } - return 0; -} -static int celt_getjoint(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result) -{ - struct celt_attr *attr1 = (struct celt_attr *) fattr1; - struct celt_attr *attr2 = (struct celt_attr *) fattr2; - struct celt_attr *attr_res = (struct celt_attr *) result; - /* sample rate is the only attribute that has any bearing on if joint capabilities exist or not */ - if (attr1->samplerate != attr2->samplerate) { - return -1; + jointformat = ast_format_clone(format1); + if (!jointformat) { + return NULL; } + jointattr = ast_format_get_attribute_data(jointformat); + /* either would work, they are guaranteed the same at this point. */ - attr_res->samplerate = attr1->samplerate; + jointattr->samplerate = attr1->samplerate; /* Take the lowest max bitrate */ - attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate); + jointattr->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate); - attr_res->framesize = attr2->framesize; /* TODO figure out what joint framesize means */ - return 0; + jointattr->framesize = attr2->framesize; /* TODO figure out what joint framesize means */ + + return jointformat; } -static void celt_set(struct ast_format_attr *fattr, va_list ap) +static struct ast_format *celt_set(const struct ast_format *format, const char *name, const char *value) { - enum celt_attr_keys key; - struct celt_attr *attr = (struct celt_attr *) fattr; - - for (key = va_arg(ap, int); - key != AST_FORMAT_ATTR_END; - key = va_arg(ap, int)) - { - switch (key) { - case CELT_ATTR_KEY_SAMP_RATE: - attr->samplerate = (va_arg(ap, int)); - break; - case CELT_ATTR_KEY_MAX_BITRATE: - attr->maxbitrate = (va_arg(ap, int)); - break; - case CELT_ATTR_KEY_FRAME_SIZE: - attr->framesize = (va_arg(ap, int)); - break; - default: - ast_log(LOG_WARNING, "unknown attribute type %u\n", key); - } + struct ast_format *cloned; + struct celt_attr *attr; + unsigned int val; + + cloned = ast_format_clone(format); + if (!cloned) { + return NULL; + } + attr = ast_format_get_attribute_data(cloned); + + if (sscanf(value, "%30u", &val) != 1) { + ast_log(LOG_WARNING, "Unknown value '%s' for attribute type '%s'\n", + value, name); + ao2_ref(cloned, -1); + return NULL; } + + if (!strcasecmp(name, "sample_rate")) { + attr->samplerate = val; + } else if (!strcasecmp(name, "max_bitrate")) { + attr->maxbitrate = val; + } else if (!strcasecmp(name, "frame_size")) { + attr->framesize = val; + } else { + ast_log(LOG_WARNING, "Unknown attribute type '%s'\n", name); + ao2_ref(cloned, -1); + return NULL; + } + + return cloned; } -static struct ast_format_attr_interface celt_interface = { - .id = AST_FORMAT_CELT, - .format_attr_cmp = celt_cmp, - .format_attr_get_joint = celt_getjoint, - .format_attr_set = celt_set, - .format_attr_isset = celt_isset, - .format_attr_get_val = celt_get_val, - .format_attr_sdp_parse = celt_sdp_parse, - .format_attr_sdp_generate = celt_sdp_generate, +static struct ast_format_interface celt_interface = { + .format_destroy = celt_destroy, + .format_clone = celt_clone, + .format_cmp = celt_cmp, + .format_get_joint = celt_getjoint, + .format_attribute_set = celt_set, + .format_parse_sdp_fmtp = celt_parse_sdp_fmtp, + .format_generate_sdp_fmtp = celt_generate_sdp_fmtp, }; static int load_module(void) { - if (ast_format_attr_reg_interface(&celt_interface)) { + if (ast_format_interface_register("celt", &celt_interface)) { return AST_MODULE_LOAD_DECLINE; } @@ -199,7 +195,6 @@ static int load_module(void) static int unload_module(void) { - ast_format_attr_unreg_interface(&celt_interface); return 0; } diff --git a/res/res_format_attr_h263.c b/res/res_format_attr_h263.c index 8ec28aac9..121beb1bc 100644 --- a/res/res_format_attr_h263.c +++ b/res/res_format_attr_h263.c @@ -38,250 +38,231 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/format.h" -enum h263_attr_keys { - H263_ATTR_KEY_SQCIF, /*!< Minimum picture interval for SQCIF resolution */ - H263_ATTR_KEY_QCIF, /*!< Minimum picture interval for QCIF resolution */ - H263_ATTR_KEY_CIF, /*!< Minimum picture interval for CIF resolution */ - H263_ATTR_KEY_CIF4, /*!< Minimum picture interval for CIF4 resolution */ - H263_ATTR_KEY_CIF16, /*!< Minimum picture interval for CIF16 resolution */ - H263_ATTR_KEY_VGA, /*!< Minimum picture interval for VGA resolution */ - H263_ATTR_KEY_CUSTOM_XMAX, /*!< Custom resolution (Xmax) */ - H263_ATTR_KEY_CUSTOM_YMAX, /*!< Custom resolution (Ymax) */ - H263_ATTR_KEY_CUSTOM_MPI, /*!< Custom resolution (MPI) */ - H263_ATTR_KEY_F, /*!< F annex support */ - H263_ATTR_KEY_I, /*!< I annex support */ - H263_ATTR_KEY_J, /*!< J annex support */ - H263_ATTR_KEY_T, /*!< T annex support */ - H263_ATTR_KEY_K, /*!< K annex support */ - H263_ATTR_KEY_N, /*!< N annex support */ - H263_ATTR_KEY_P_SUB1, /*!< Reference picture resampling (sub mode 1) */ - H263_ATTR_KEY_P_SUB2, /*!< Reference picture resampling (sub mode 2) */ - H263_ATTR_KEY_P_SUB3, /*!< Reference picture resampling (sub mode 3) */ - H263_ATTR_KEY_P_SUB4, /*!< Reference picture resampling (sub mode 4) */ - H263_ATTR_KEY_PAR_WIDTH, /*!< Pixel aspect ratio (width) */ - H263_ATTR_KEY_PAR_HEIGHT, /*!< Pixel aspect ratio (height) */ - H263_ATTR_KEY_BPP, /*!< Bits per picture maximum */ - H263_ATTR_KEY_HRD, /*!< Hypothetical reference decoder status */ - H263_ATTR_KEY_END, /*!< End terminator for list */ +struct h263_attr { + unsigned int SQCIF; /*!< Minimum picture interval for SQCIF resolution */ + unsigned int QCIF; /*!< Minimum picture interval for QCIF resolution */ + unsigned int CIF; /*!< Minimum picture interval for CIF resolution */ + unsigned int CIF4; /*!< Minimum picture interval for CIF4 resolution */ + unsigned int CIF16; /*!< Minimum picture interval for CIF16 resolution */ + unsigned int VGA; /*!< Minimum picture interval for VGA resolution */ + unsigned int CUSTOM_XMAX; /*!< Custom resolution (Xmax) */ + unsigned int CUSTOM_YMAX; /*!< Custom resolution (Ymax) */ + unsigned int CUSTOM_MPI; /*!< Custom resolution (MPI) */ + unsigned int F; /*!< F annex support */ + unsigned int I; /*!< I annex support */ + unsigned int J; /*!< J annex support */ + unsigned int T; /*!< T annex support */ + unsigned int K; /*!< K annex support */ + unsigned int N; /*!< N annex support */ + unsigned int P_SUB1; /*!< Reference picture resampling (sub mode 1) */ + unsigned int P_SUB2; /*!< Reference picture resampling (sub mode 2) */ + unsigned int P_SUB3; /*!< Reference picture resampling (sub mode 3) */ + unsigned int P_SUB4; /*!< Reference picture resampling (sub mode 4) */ + unsigned int PAR_WIDTH; /*!< Pixel aspect ratio (width) */ + unsigned int PAR_HEIGHT; /*!< Pixel aspect ratio (height) */ + unsigned int BPP; /*!< Bits per picture maximum */ + unsigned int HRD; /*!< Hypothetical reference decoder status */ }; -static int h263_format_attr_get_joint(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result) +static void h263_destroy(struct ast_format *format) { - int i; + struct h263_attr *attr = ast_format_get_attribute_data(format); - /* These are all receiver options so we just copy over what they sent */ - for (i = H263_ATTR_KEY_SQCIF; i < H263_ATTR_KEY_END; i++) { - result->format_attr[i] = fattr1->format_attr[i] ? fattr1->format_attr[i] : fattr2->format_attr[i]; + ast_free(attr); +} + +static int h263_clone(const struct ast_format *src, struct ast_format *dst) +{ + struct h263_attr *original = ast_format_get_attribute_data(src); + struct h263_attr *attr = ast_calloc(1, sizeof(*attr)); + + if (!attr) { + return -1; + } + + if (original) { + *attr = *original; } + ast_format_set_attribute_data(dst, attr); + return 0; } -static int h263_format_attr_sdp_parse(struct ast_format_attr *format_attr, const char *attributes) +static enum ast_format_cmp_res h263_cmp(const struct ast_format *format1, const struct ast_format *format2) +{ + struct h263_attr *attr1 = ast_format_get_attribute_data(format1); + struct h263_attr *attr2 = ast_format_get_attribute_data(format2); + + if (!attr1 || !attr2 || (attr1 && attr2 && !memcmp(attr1, attr2, sizeof(*attr1)))) { + return AST_FORMAT_CMP_EQUAL; + } + return AST_FORMAT_CMP_NOT_EQUAL; +} + +#define DETERMINE_JOINT(joint, attr1, attr2, field) (joint->field = (attr1 && attr1->field) ? attr1->field : (attr2 && attr2->field) ? attr2->field : 0) + +static struct ast_format *h263_getjoint(const struct ast_format *format1, const struct ast_format *format2) +{ + struct ast_format *cloned; + struct h263_attr *attr, *attr1, *attr2; + + cloned = ast_format_clone(format1); + if (!cloned) { + return NULL; + } + attr = ast_format_get_attribute_data(cloned); + + attr1 = ast_format_get_attribute_data(format1); + attr2 = ast_format_get_attribute_data(format2); + + DETERMINE_JOINT(attr, attr1, attr2, SQCIF); + DETERMINE_JOINT(attr, attr1, attr2, QCIF); + DETERMINE_JOINT(attr, attr1, attr2, CIF); + DETERMINE_JOINT(attr, attr1, attr2, CIF4); + DETERMINE_JOINT(attr, attr1, attr2, CIF16); + DETERMINE_JOINT(attr, attr1, attr2, VGA); + DETERMINE_JOINT(attr, attr1, attr2, CUSTOM_XMAX); + DETERMINE_JOINT(attr, attr1, attr2, CUSTOM_YMAX); + DETERMINE_JOINT(attr, attr1, attr2, CUSTOM_MPI); + DETERMINE_JOINT(attr, attr1, attr2, F); + DETERMINE_JOINT(attr, attr1, attr2, I); + DETERMINE_JOINT(attr, attr1, attr2, J); + DETERMINE_JOINT(attr, attr1, attr2, T); + DETERMINE_JOINT(attr, attr1, attr2, K); + DETERMINE_JOINT(attr, attr1, attr2, N); + DETERMINE_JOINT(attr, attr1, attr2, P_SUB1); + DETERMINE_JOINT(attr, attr1, attr2, P_SUB2); + DETERMINE_JOINT(attr, attr1, attr2, P_SUB3); + DETERMINE_JOINT(attr, attr1, attr2, P_SUB4); + DETERMINE_JOINT(attr, attr1, attr2, PAR_WIDTH); + DETERMINE_JOINT(attr, attr1, attr2, PAR_HEIGHT); + DETERMINE_JOINT(attr, attr1, attr2, BPP); + DETERMINE_JOINT(attr, attr1, attr2, HRD); + + return cloned; +} + +static struct ast_format *h263_parse_sdp_fmtp(const struct ast_format *format, const char *attributes) { char *attribs = ast_strdupa(attributes), *attrib; + struct ast_format *cloned; + struct h263_attr *attr; + + cloned = ast_format_clone(format); + if (!cloned) { + return NULL; + } + attr = ast_format_get_attribute_data(cloned); while ((attrib = strsep(&attribs, ";"))) { unsigned int val, val2 = 0, val3 = 0, val4 = 0; if (sscanf(attrib, "SQCIF=%30u", &val) == 1) { - format_attr->format_attr[H263_ATTR_KEY_SQCIF] = val; + attr->SQCIF = val; } else if (sscanf(attrib, "QCIF=%30u", &val) == 1) { - format_attr->format_attr[H263_ATTR_KEY_QCIF] = val; + attr->QCIF = val; } else if (sscanf(attrib, "CIF=%30u", &val) == 1) { - format_attr->format_attr[H263_ATTR_KEY_CIF] = val; + attr->CIF = val; } else if (sscanf(attrib, "CIF4=%30u", &val) == 1) { - format_attr->format_attr[H263_ATTR_KEY_CIF4] = val; + attr->CIF4 = val; } else if (sscanf(attrib, "CIF16=%30u", &val) == 1) { - format_attr->format_attr[H263_ATTR_KEY_CIF16] = val; + attr->CIF16 = val; } else if (sscanf(attrib, "VGA=%30u", &val) == 1) { - format_attr->format_attr[H263_ATTR_KEY_VGA] = val; + attr->VGA = val; } else if (sscanf(attrib, "CUSTOM=%30u,%30u,%30u", &val, &val2, &val3) == 3) { - format_attr->format_attr[H263_ATTR_KEY_CUSTOM_XMAX] = val; - format_attr->format_attr[H263_ATTR_KEY_CUSTOM_YMAX] = val2; - format_attr->format_attr[H263_ATTR_KEY_CUSTOM_MPI] = val3; + attr->CUSTOM_XMAX = val; + attr->CUSTOM_YMAX = val2; + attr->CUSTOM_MPI = val3; } else if (sscanf(attrib, "F=%30u", &val) == 1) { - format_attr->format_attr[H263_ATTR_KEY_F] = val; + attr->F = val; } else if (sscanf(attrib, "I=%30u", &val) == 1) { - format_attr->format_attr[H263_ATTR_KEY_I] = val; + attr->I = val; } else if (sscanf(attrib, "J=%30u", &val) == 1) { - format_attr->format_attr[H263_ATTR_KEY_J] = val; + attr->J = val; } else if (sscanf(attrib, "T=%30u", &val) == 1) { - format_attr->format_attr[H263_ATTR_KEY_T] = val; + attr->T = val; } else if (sscanf(attrib, "K=%30u", &val) == 1) { - format_attr->format_attr[H263_ATTR_KEY_K] = val; + attr->K = val; } else if (sscanf(attrib, "N=%30u", &val) == 1) { - format_attr->format_attr[H263_ATTR_KEY_N] = val; + attr->N = val; } else if (sscanf(attrib, "PAR=%30u:%30u", &val, &val2) == 2) { - format_attr->format_attr[H263_ATTR_KEY_PAR_WIDTH] = val; - format_attr->format_attr[H263_ATTR_KEY_PAR_HEIGHT] = val2; + attr->PAR_WIDTH = val; + attr->PAR_HEIGHT = val2; } else if (sscanf(attrib, "BPP=%30u", &val) == 1) { - format_attr->format_attr[H263_ATTR_KEY_BPP] = val; + attr->BPP = val; } else if (sscanf(attrib, "HRD=%30u", &val) == 1) { - format_attr->format_attr[H263_ATTR_KEY_HRD] = val; + attr->HRD = val; } else if (sscanf(attrib, "P=%30u,%30u,%30u,%30u", &val, &val2, &val3, &val4) > 0) { - format_attr->format_attr[H263_ATTR_KEY_P_SUB1] = val; - format_attr->format_attr[H263_ATTR_KEY_P_SUB2] = val2; - format_attr->format_attr[H263_ATTR_KEY_P_SUB3] = val3; - format_attr->format_attr[H263_ATTR_KEY_P_SUB4] = val4; + attr->P_SUB1 = val; + attr->P_SUB2 = val2; + attr->P_SUB3 = val3; + attr->P_SUB4 = val4; } } - return 0; + return cloned; } -/*! \brief Helper function which converts a key enum into a string value for SDP */ -static const char *h263_attr_key_to_str(enum h263_attr_keys key, const struct ast_format_attr *format_attr) +static void h263_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str) { - switch (key) { - case H263_ATTR_KEY_SQCIF: - return format_attr->format_attr[key] ? "SQCIF" : NULL; - case H263_ATTR_KEY_QCIF: - return format_attr->format_attr[key] ? "QCIF" : NULL; - case H263_ATTR_KEY_CIF: - return format_attr->format_attr[key] ? "CIF" : NULL; - case H263_ATTR_KEY_CIF4: - return format_attr->format_attr[key] ? "CIF4" : NULL; - case H263_ATTR_KEY_CIF16: - return format_attr->format_attr[key] ? "CIF16" : NULL; - case H263_ATTR_KEY_VGA: - return format_attr->format_attr[key] ? "VGA" : NULL; - case H263_ATTR_KEY_F: - return "F"; - case H263_ATTR_KEY_I: - return "I"; - case H263_ATTR_KEY_J: - return "J"; - case H263_ATTR_KEY_T: - return "T"; - case H263_ATTR_KEY_K: - return "K"; - case H263_ATTR_KEY_N: - return "N"; - case H263_ATTR_KEY_BPP: - return "BPP"; - case H263_ATTR_KEY_HRD: - return "HRD"; - case H263_ATTR_KEY_CUSTOM_XMAX: - case H263_ATTR_KEY_CUSTOM_YMAX: - case H263_ATTR_KEY_CUSTOM_MPI: - case H263_ATTR_KEY_P_SUB1: - case H263_ATTR_KEY_P_SUB2: - case H263_ATTR_KEY_P_SUB3: - case H263_ATTR_KEY_P_SUB4: - case H263_ATTR_KEY_PAR_WIDTH: - case H263_ATTR_KEY_PAR_HEIGHT: - case H263_ATTR_KEY_END: - default: - return NULL; + struct h263_attr *attr = ast_format_get_attribute_data(format); + + if (!attr) { + return; } - return NULL; -} + ast_str_append(str, 0, "a=fmtp:%u SQCIF=%u;QCIF=%u;CIF=%u;CIF4=%u;CIF16=%u;VGA=%u;F=%u;I=%u;J=%u;T=%u;K=%u;N=%u;BPP=%u;HRD=%u", + payload, attr->SQCIF, attr->QCIF, attr->CIF, attr->CIF4, attr->CIF16, attr->VGA, attr->F, attr->I, attr->J, + attr->T, attr->K, attr->N, attr->BPP, attr->HRD); -static void h263_format_attr_sdp_generate(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str) -{ - int i, added = 0; - - for (i = H263_ATTR_KEY_SQCIF; i < H263_ATTR_KEY_END; i++) { - const char *name; - - if (i == H263_ATTR_KEY_CUSTOM_XMAX) { - if (!format_attr->format_attr[H263_ATTR_KEY_CUSTOM_XMAX] || !format_attr->format_attr[H263_ATTR_KEY_CUSTOM_YMAX] || - !format_attr->format_attr[H263_ATTR_KEY_CUSTOM_MPI]) { - continue; - } - - if (!added) { - ast_str_append(str, 0, "a=fmtp:%u CUSTOM=%u,%u,%u", payload, format_attr->format_attr[H263_ATTR_KEY_CUSTOM_XMAX], - format_attr->format_attr[H263_ATTR_KEY_CUSTOM_YMAX], format_attr->format_attr[H263_ATTR_KEY_CUSTOM_MPI]); - added = 1; - } else { - ast_str_append(str, 0, ";CUSTOM=%u,%u,%u", format_attr->format_attr[H263_ATTR_KEY_CUSTOM_XMAX], - format_attr->format_attr[H263_ATTR_KEY_CUSTOM_YMAX], format_attr->format_attr[H263_ATTR_KEY_CUSTOM_MPI]); - } - } else if (i == H263_ATTR_KEY_PAR_WIDTH) { - if (!format_attr->format_attr[H263_ATTR_KEY_PAR_WIDTH] || !format_attr->format_attr[H263_ATTR_KEY_PAR_HEIGHT]) { - continue; - } - - if (!added) { - ast_str_append(str, 0, "a=fmtp:%u PAR=%u:%u", payload, format_attr->format_attr[H263_ATTR_KEY_PAR_WIDTH], - format_attr->format_attr[H263_ATTR_KEY_PAR_HEIGHT]); - added = 1; - } else { - ast_str_append(str, 0, ";PAR=%u:%u", format_attr->format_attr[H263_ATTR_KEY_PAR_WIDTH], - format_attr->format_attr[H263_ATTR_KEY_PAR_HEIGHT]); - } - } else if (i == H263_ATTR_KEY_P_SUB1) { - if (!format_attr->format_attr[H263_ATTR_KEY_P_SUB1]) { - continue; - } - - if (!added) { - ast_str_append(str, 0, "a=fmtp:%u P=%u", payload, format_attr->format_attr[H263_ATTR_KEY_P_SUB1]); - added = 1; - } else { - ast_str_append(str, 0, ";P=%u", format_attr->format_attr[H263_ATTR_KEY_P_SUB1]); - } - - if (format_attr->format_attr[H263_ATTR_KEY_P_SUB2]) { - ast_str_append(str, 0, ",%u", format_attr->format_attr[H263_ATTR_KEY_P_SUB2]); - } - if (format_attr->format_attr[H263_ATTR_KEY_P_SUB3]) { - ast_str_append(str, 0, ",%u", format_attr->format_attr[H263_ATTR_KEY_P_SUB3]); - } - if (format_attr->format_attr[H263_ATTR_KEY_P_SUB4]) { - ast_str_append(str, 0, ",%u", format_attr->format_attr[H263_ATTR_KEY_P_SUB4]); - } - - } else if ((name = h263_attr_key_to_str(i, format_attr))) { - if (!added) { - ast_str_append(str, 0, "a=fmtp:%u %s=%u", payload, name, format_attr->format_attr[i]); - added = 1; - } else { - ast_str_append(str, 0, ";%s=%u", name, format_attr->format_attr[i]); - } - } + if (attr->CUSTOM_XMAX && attr->CUSTOM_YMAX && attr->CUSTOM_MPI) { + ast_str_append(str, 0, ";CUSTOM=%u,%u,%u", attr->CUSTOM_XMAX, attr->CUSTOM_YMAX, attr->CUSTOM_MPI); } - if (added) { - ast_str_append(str, 0, "\r\n"); + if (attr->PAR_WIDTH && attr->PAR_HEIGHT) { + ast_str_append(str, 0, ";PAR=%u:%u", attr->PAR_WIDTH, attr->PAR_HEIGHT); } + if (attr->P_SUB1) { + ast_str_append(str, 0, ";P=%u", attr->P_SUB1); + if (attr->P_SUB2) { + ast_str_append(str, 0, ",%u", attr->P_SUB2); + } + if (attr->P_SUB3) { + ast_str_append(str, 0, ",%u", attr->P_SUB3); + } + if (attr->P_SUB4) { + ast_str_append(str, 0, ",%u", attr->P_SUB4); + } + } + + ast_str_append(str, 0, "\r\n"); + return; } -static struct ast_format_attr_interface h263_format_attr_interface = { - .id = AST_FORMAT_H263, - .format_attr_get_joint = h263_format_attr_get_joint, - .format_attr_sdp_parse = h263_format_attr_sdp_parse, - .format_attr_sdp_generate = h263_format_attr_sdp_generate, -}; - -static struct ast_format_attr_interface h263p_format_attr_interface = { - .id = AST_FORMAT_H263_PLUS, - .format_attr_get_joint = h263_format_attr_get_joint, - .format_attr_sdp_parse = h263_format_attr_sdp_parse, - .format_attr_sdp_generate = h263_format_attr_sdp_generate, +static struct ast_format_interface h263_interface = { + .format_destroy = h263_destroy, + .format_clone = h263_clone, + .format_cmp = h263_cmp, + .format_get_joint = h263_getjoint, + .format_parse_sdp_fmtp = h263_parse_sdp_fmtp, + .format_generate_sdp_fmtp = h263_generate_sdp_fmtp, }; static int unload_module(void) { - ast_format_attr_unreg_interface(&h263_format_attr_interface); - ast_format_attr_unreg_interface(&h263p_format_attr_interface); - return 0; } static int load_module(void) { - if (ast_format_attr_reg_interface(&h263_format_attr_interface)) { + if (ast_format_interface_register("h263", &h263_interface)) { return AST_MODULE_LOAD_DECLINE; } - if (ast_format_attr_reg_interface(&h263p_format_attr_interface)) { - ast_format_attr_unreg_interface(&h263_format_attr_interface); + if (ast_format_interface_register("h263p", &h263_interface)) { return AST_MODULE_LOAD_DECLINE; } diff --git a/res/res_format_attr_h264.c b/res/res_format_attr_h264.c index 2bd47e025..81784bb48 100644 --- a/res/res_format_attr_h264.c +++ b/res/res_format_attr_h264.c @@ -50,266 +50,284 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") * H264_MAX_SPS_PPS_SIZE */ #define H264_MAX_SPS_PPS_SIZE_SCAN_LIMIT "15" -enum h264_attr_keys { - H264_ATTR_KEY_PROFILE_IDC, - H264_ATTR_KEY_PROFILE_IOP, - H264_ATTR_KEY_LEVEL, - H264_ATTR_KEY_MAX_MBPS, - H264_ATTR_KEY_MAX_FS, - H264_ATTR_KEY_MAX_CPB, - H264_ATTR_KEY_MAX_DPB, - H264_ATTR_KEY_MAX_BR, - H264_ATTR_KEY_MAX_SMBPS, - H264_ATTR_KEY_MAX_FPS, - H264_ATTR_KEY_REDUNDANT_PIC_CAP, - H264_ATTR_KEY_PARAMETER_ADD, - H264_ATTR_KEY_PACKETIZATION_MODE, - H264_ATTR_KEY_SPROP_INTERLEAVING_DEPTH, - H264_ATTR_KEY_SPROP_DEINT_BUF_REQ, - H264_ATTR_KEY_DEINT_BUF_CAP, - H264_ATTR_KEY_SPROP_INIT_BUF_TIME, - H264_ATTR_KEY_SPROP_MAX_DON_DIFF, - H264_ATTR_KEY_MAX_RCMD_NALU_SIZE, - H264_ATTR_KEY_LEVEL_ASYMMETRY_ALLOWED, - H264_ATTR_KEY_SPS_LEN, - H264_ATTR_KEY_PPS_LEN, - H264_ATTR_KEY_SPS, - H264_ATTR_KEY_PPS = H264_ATTR_KEY_SPS + H264_MAX_SPS_PPS_SIZE, - H264_ATTR_KEY_END = H264_ATTR_KEY_PPS + H264_MAX_SPS_PPS_SIZE, +struct h264_attr { + unsigned int PROFILE_IDC; + unsigned int PROFILE_IOP; + unsigned int LEVEL; + unsigned int MAX_MBPS; + unsigned int MAX_FS; + unsigned int MAX_CPB; + unsigned int MAX_DPB; + unsigned int MAX_BR; + unsigned int MAX_SMBPS; + unsigned int MAX_FPS; + unsigned int REDUNDANT_PIC_CAP; + unsigned int PARAMETER_ADD; + unsigned int PACKETIZATION_MODE; + unsigned int SPROP_INTERLEAVING_DEPTH; + unsigned int SPROP_DEINT_BUF_REQ; + unsigned int DEINT_BUF_CAP; + unsigned int SPROP_INIT_BUF_TIME; + unsigned int SPROP_MAX_DON_DIFF; + unsigned int MAX_RCMD_NALU_SIZE; + unsigned int LEVEL_ASYMMETRY_ALLOWED; + char SPS[H264_MAX_SPS_PPS_SIZE]; + char PPS[H264_MAX_SPS_PPS_SIZE]; }; -static enum ast_format_cmp_res h264_format_attr_cmp(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2) +static void h264_destroy(struct ast_format *format) { - if (!fattr1->format_attr[H264_ATTR_KEY_PROFILE_IDC] || !fattr2->format_attr[H264_ATTR_KEY_PROFILE_IDC] || - (fattr1->format_attr[H264_ATTR_KEY_PROFILE_IDC] == fattr2->format_attr[H264_ATTR_KEY_PROFILE_IDC])) { + struct h264_attr *attr = ast_format_get_attribute_data(format); + + ast_free(attr); +} + +static int h264_clone(const struct ast_format *src, struct ast_format *dst) +{ + struct h264_attr *original = ast_format_get_attribute_data(src); + struct h264_attr *attr = ast_calloc(1, sizeof(*attr)); + + if (!attr) { + return -1; + } + + if (original) { + *attr = *original; + } + + ast_format_set_attribute_data(dst, attr); + + return 0; +} + +static enum ast_format_cmp_res h264_cmp(const struct ast_format *format1, const struct ast_format *format2) +{ + struct h264_attr *attr1 = ast_format_get_attribute_data(format1); + struct h264_attr *attr2 = ast_format_get_attribute_data(format2); + + if (!attr1 || !attr1->PROFILE_IDC || !attr2 || !attr2->PROFILE_IDC || + (attr1->PROFILE_IDC == attr2->PROFILE_IDC)) { return AST_FORMAT_CMP_EQUAL; } return AST_FORMAT_CMP_NOT_EQUAL; } -static int h264_format_attr_get_joint(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result) +#define DETERMINE_JOINT(joint, attr1, attr2, field) (joint->field = (attr1 && attr1->field) ? attr1->field : (attr2 && attr2->field) ? attr2->field : 0) + +static struct ast_format *h264_getjoint(const struct ast_format *format1, const struct ast_format *format2) { - int i; + struct ast_format *cloned; + struct h264_attr *attr, *attr1, *attr2; + + cloned = ast_format_clone(format1); + if (!cloned) { + return NULL; + } + attr = ast_format_get_attribute_data(cloned); + + attr1 = ast_format_get_attribute_data(format1); + attr2 = ast_format_get_attribute_data(format2); + + DETERMINE_JOINT(attr, attr1, attr2, PROFILE_IDC); + DETERMINE_JOINT(attr, attr1, attr2, PROFILE_IOP); + DETERMINE_JOINT(attr, attr1, attr2, LEVEL); + DETERMINE_JOINT(attr, attr1, attr2, MAX_MBPS); + DETERMINE_JOINT(attr, attr1, attr2, MAX_FS); + DETERMINE_JOINT(attr, attr1, attr2, MAX_CPB); + DETERMINE_JOINT(attr, attr1, attr2, MAX_DPB); + DETERMINE_JOINT(attr, attr1, attr2, MAX_BR); + DETERMINE_JOINT(attr, attr1, attr2, MAX_SMBPS); + DETERMINE_JOINT(attr, attr1, attr2, MAX_FPS); + DETERMINE_JOINT(attr, attr1, attr2, REDUNDANT_PIC_CAP); + DETERMINE_JOINT(attr, attr1, attr2, PARAMETER_ADD); + DETERMINE_JOINT(attr, attr1, attr2, SPROP_INTERLEAVING_DEPTH); + DETERMINE_JOINT(attr, attr1, attr2, SPROP_DEINT_BUF_REQ); + DETERMINE_JOINT(attr, attr1, attr2, DEINT_BUF_CAP); + DETERMINE_JOINT(attr, attr1, attr2, SPROP_INIT_BUF_TIME); + DETERMINE_JOINT(attr, attr1, attr2, SPROP_MAX_DON_DIFF); + DETERMINE_JOINT(attr, attr1, attr2, MAX_RCMD_NALU_SIZE); + DETERMINE_JOINT(attr, attr1, attr2, LEVEL_ASYMMETRY_ALLOWED); + DETERMINE_JOINT(attr, attr1, attr2, PACKETIZATION_MODE); + + if (attr1 && !ast_strlen_zero(attr1->SPS)) { + ast_copy_string(attr->SPS, attr1->SPS, sizeof(attr->SPS)); + } else if (attr2 && !ast_strlen_zero(attr2->SPS)) { + ast_copy_string(attr->SPS, attr1->SPS, sizeof(attr->SPS)); + } - for (i = H264_ATTR_KEY_PROFILE_IDC; i < H264_ATTR_KEY_END; i++) { - result->format_attr[i] = fattr1->format_attr[i] ? fattr1->format_attr[i] : fattr2->format_attr[i]; + if (attr1 && !ast_strlen_zero(attr1->PPS)) { + ast_copy_string(attr->PPS, attr1->PPS, sizeof(attr->PPS)); + } else if (attr2 && !ast_strlen_zero(attr2->PPS)) { + ast_copy_string(attr->PPS, attr1->PPS, sizeof(attr->PPS)); } - return 0; + return cloned; } -static int h264_format_attr_sdp_parse(struct ast_format_attr *format_attr, const char *attributes) +static struct ast_format *h264_parse_sdp_fmtp(const struct ast_format *format, const char *attributes) { char *attribs = ast_strdupa(attributes), *attrib; + struct ast_format *cloned; + struct h264_attr *attr; - format_attr->format_attr[H264_ATTR_KEY_REDUNDANT_PIC_CAP] = H264_ATTR_KEY_UNSET; - format_attr->format_attr[H264_ATTR_KEY_PARAMETER_ADD] = H264_ATTR_KEY_UNSET; - format_attr->format_attr[H264_ATTR_KEY_PACKETIZATION_MODE] = H264_ATTR_KEY_UNSET; - format_attr->format_attr[H264_ATTR_KEY_LEVEL_ASYMMETRY_ALLOWED] = H264_ATTR_KEY_UNSET; + cloned = ast_format_clone(format); + if (!cloned) { + return NULL; + } + attr = ast_format_get_attribute_data(cloned); + + attr->REDUNDANT_PIC_CAP = H264_ATTR_KEY_UNSET; + attr->PARAMETER_ADD = H264_ATTR_KEY_UNSET; + attr->PACKETIZATION_MODE = H264_ATTR_KEY_UNSET; + attr->LEVEL_ASYMMETRY_ALLOWED = H264_ATTR_KEY_UNSET; while ((attrib = strsep(&attribs, ";"))) { unsigned int val; unsigned long int val2; - char sps[H264_MAX_SPS_PPS_SIZE], pps[H264_MAX_SPS_PPS_SIZE]; if (sscanf(attrib, "profile-level-id=%lx", &val2) == 1) { - format_attr->format_attr[H264_ATTR_KEY_PROFILE_IDC] = ((val2 >> 16) & 0xFF); - format_attr->format_attr[H264_ATTR_KEY_PROFILE_IOP] = ((val2 >> 8) & 0xFF); - format_attr->format_attr[H264_ATTR_KEY_LEVEL] = (val2 & 0xFF); - } else if (sscanf(attrib, "sprop-parameter-sets=%" H264_MAX_SPS_PPS_SIZE_SCAN_LIMIT "[^','],%" H264_MAX_SPS_PPS_SIZE_SCAN_LIMIT "s", sps, pps) == 2) { + attr->PROFILE_IDC = ((val2 >> 16) & 0xFF); + attr->PROFILE_IOP = ((val2 >> 8) & 0xFF); + attr->LEVEL = (val2 & 0xFF); + } else if (sscanf(attrib, "sprop-parameter-sets=%" H264_MAX_SPS_PPS_SIZE_SCAN_LIMIT "[^','],%" H264_MAX_SPS_PPS_SIZE_SCAN_LIMIT "s", attr->SPS, attr->PPS) == 2) { /* XXX sprop-parameter-sets can actually be of unlimited length. This may need to be addressed later. */ - unsigned char spsdecoded[H264_MAX_SPS_PPS_SIZE] = { 0, }, ppsdecoded[H264_MAX_SPS_PPS_SIZE] = { 0, }; - int i; - - ast_base64decode(spsdecoded, sps, sizeof(spsdecoded)); - ast_base64decode(ppsdecoded, pps, sizeof(ppsdecoded)); - - format_attr->format_attr[H264_ATTR_KEY_SPS_LEN] = 0; - format_attr->format_attr[H264_ATTR_KEY_PPS_LEN] = 0; - - for (i = 0; i < H264_MAX_SPS_PPS_SIZE; i++) { - if (spsdecoded[i]) { - format_attr->format_attr[H264_ATTR_KEY_SPS + i] = spsdecoded[i]; - format_attr->format_attr[H264_ATTR_KEY_SPS_LEN]++; - } - if (ppsdecoded[i]) { - format_attr->format_attr[H264_ATTR_KEY_PPS + i] = ppsdecoded[i]; - format_attr->format_attr[H264_ATTR_KEY_PPS_LEN]++; - } - } } else if (sscanf(attrib, "max-mbps=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_MAX_MBPS] = val; + attr->MAX_MBPS = val; } else if (sscanf(attrib, "max-fs=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_MAX_FS] = val; + attr->MAX_FS = val; } else if (sscanf(attrib, "max-cpb=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_MAX_CPB] = val; + attr->MAX_CPB = val; } else if (sscanf(attrib, "max-dpb=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_MAX_DPB] = val; + attr->MAX_DPB = val; } else if (sscanf(attrib, "max-br=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_MAX_BR] = val; + attr->MAX_BR = val; } else if (sscanf(attrib, "max-smbps=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_MAX_SMBPS] = val; + attr->MAX_SMBPS = val; } else if (sscanf(attrib, "max-fps=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_MAX_FPS] = val; + attr->MAX_FPS = val; } else if (sscanf(attrib, "redundant-pic-cap=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_REDUNDANT_PIC_CAP] = val; + attr->REDUNDANT_PIC_CAP = val; } else if (sscanf(attrib, "parameter-add=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_PARAMETER_ADD] = val; + attr->PARAMETER_ADD = val; } else if (sscanf(attrib, "packetization-mode=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_PACKETIZATION_MODE] = val; + attr->PACKETIZATION_MODE = val; } else if (sscanf(attrib, "sprop-interleaving-depth=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_SPROP_INTERLEAVING_DEPTH] = val; + attr->SPROP_INTERLEAVING_DEPTH = val; } else if (sscanf(attrib, "sprop-deint-buf-req=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_SPROP_DEINT_BUF_REQ] = val; + attr->SPROP_DEINT_BUF_REQ = val; } else if (sscanf(attrib, "deint-buf-cap=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_DEINT_BUF_CAP] = val; + attr->DEINT_BUF_CAP = val; } else if (sscanf(attrib, "sprop-init-buf-time=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_SPROP_INIT_BUF_TIME] = val; + attr->SPROP_INIT_BUF_TIME = val; } else if (sscanf(attrib, "sprop-max-don-diff=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_SPROP_MAX_DON_DIFF] = val; + attr->SPROP_MAX_DON_DIFF = val; } else if (sscanf(attrib, "max-rcmd-nalu-size=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_MAX_RCMD_NALU_SIZE] = val; + attr->MAX_RCMD_NALU_SIZE = val; } else if (sscanf(attrib, "level-asymmetry-allowed=%30u", &val) == 1) { - format_attr->format_attr[H264_ATTR_KEY_LEVEL_ASYMMETRY_ALLOWED] = val; + attr->LEVEL_ASYMMETRY_ALLOWED = val; } } - return 0; + return cloned; } -/*! \brief Helper function which converts a key enum into a string value for SDP */ -static const char *h264_attr_key_to_str(enum h264_attr_keys key) +#define APPEND_IF_NOT_H264_UNSET(field, str, name) do { \ + if (field != H264_ATTR_KEY_UNSET) { \ + if (added) { \ + ast_str_append(str, 0, ";"); \ + } else { \ + added = 1; \ + } \ + ast_str_append(str, 0, "%s=%u", name, field); \ + } \ +} while (0) + +#define APPEND_IF_NONZERO(field, str, name) do { \ + if (field) { \ + if (added) { \ + ast_str_append(str, 0, ";"); \ + } else { \ + added = 1; \ + } \ + ast_str_append(str, 0, "%s=%u", name, field); \ + } \ +} while (0) + +static void h264_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str) { - switch (key) { - case H264_ATTR_KEY_MAX_MBPS: - return "max-mbps"; - case H264_ATTR_KEY_MAX_FS: - return "max-fs"; - case H264_ATTR_KEY_MAX_CPB: - return "max-cpb"; - case H264_ATTR_KEY_MAX_DPB: - return "max-dpb"; - case H264_ATTR_KEY_MAX_BR: - return "max-br"; - case H264_ATTR_KEY_MAX_SMBPS: - return "max-smbps"; - case H264_ATTR_KEY_MAX_FPS: - return "max-fps"; - case H264_ATTR_KEY_REDUNDANT_PIC_CAP: - return "redundant-pic-cap"; - case H264_ATTR_KEY_PARAMETER_ADD: - return "parameter-add"; - case H264_ATTR_KEY_PACKETIZATION_MODE: - return "packetization-mode"; - case H264_ATTR_KEY_SPROP_INTERLEAVING_DEPTH: - return "sprop-interleaving-depth"; - case H264_ATTR_KEY_SPROP_DEINT_BUF_REQ: - return "sprop-deint-buf-req"; - case H264_ATTR_KEY_DEINT_BUF_CAP: - return "deint-buf-cap"; - case H264_ATTR_KEY_SPROP_INIT_BUF_TIME: - return "sprop-init-buf-time"; - case H264_ATTR_KEY_SPROP_MAX_DON_DIFF: - return "sprop-max-don-diff"; - case H264_ATTR_KEY_MAX_RCMD_NALU_SIZE: - return "max-rcmd-nalu-size"; - case H264_ATTR_KEY_LEVEL_ASYMMETRY_ALLOWED: - return "level-asymmetry-allowed"; - default: - return NULL; - } + struct h264_attr *attr = ast_format_get_attribute_data(format); + int added = 0; - return NULL; -} - -/*! \brief Helper function which determines if the value of an attribute can be placed into the SDP */ -static int h264_attr_key_addable(const struct ast_format_attr *format_attr, enum h264_attr_keys key) -{ - switch (key) { - case H264_ATTR_KEY_REDUNDANT_PIC_CAP: - case H264_ATTR_KEY_PARAMETER_ADD: - case H264_ATTR_KEY_PACKETIZATION_MODE: - case H264_ATTR_KEY_LEVEL_ASYMMETRY_ALLOWED: - return (format_attr->format_attr[key] != H264_ATTR_KEY_UNSET) ? 1 : 0; - default: - return format_attr->format_attr[key] ? 1 : 0; + if (!attr) { + return; } - return 1; -} + ast_str_append(str, 0, "a=fmtp:%u ", payload); + + APPEND_IF_NONZERO(attr->MAX_MBPS, str, "max-mbps"); + APPEND_IF_NONZERO(attr->MAX_FS, str, "max-fs"); + APPEND_IF_NONZERO(attr->MAX_CPB, str, "max-cpb"); + APPEND_IF_NONZERO(attr->MAX_DPB, str, "max-dpb"); + APPEND_IF_NONZERO(attr->MAX_BR, str, "max-br"); + APPEND_IF_NONZERO(attr->MAX_SMBPS, str, "max-smbps"); + APPEND_IF_NONZERO(attr->MAX_FPS, str, "max-fps"); + APPEND_IF_NONZERO(attr->SPROP_INTERLEAVING_DEPTH, str, "sprop-interleaving-depth"); + APPEND_IF_NONZERO(attr->SPROP_DEINT_BUF_REQ, str, "sprop-deint-buf-req"); + APPEND_IF_NONZERO(attr->DEINT_BUF_CAP, str, "deint-buf-cap"); + APPEND_IF_NONZERO(attr->SPROP_INIT_BUF_TIME, str, "sprop-init-buf-time"); + APPEND_IF_NONZERO(attr->SPROP_MAX_DON_DIFF, str, "sprop-max-don-diff"); + APPEND_IF_NONZERO(attr->MAX_RCMD_NALU_SIZE, str, "max-rcmd-nalu-size"); + + APPEND_IF_NOT_H264_UNSET(attr->REDUNDANT_PIC_CAP, str, "redundant-pic-cap"); + APPEND_IF_NOT_H264_UNSET(attr->PARAMETER_ADD, str, "parameter-add"); + APPEND_IF_NOT_H264_UNSET(attr->PACKETIZATION_MODE, str, "packetization-mode"); + APPEND_IF_NOT_H264_UNSET(attr->LEVEL_ASYMMETRY_ALLOWED, str, "level-asymmetry-allowed"); + + if (attr->PROFILE_IDC && attr->PROFILE_IOP && attr->LEVEL) { + if (added) { + ast_str_append(str, 0, ";"); + } else { + added = 1; + } + ast_str_append(str, 0, "profile-level-id=%02X%02X%02X", attr->PROFILE_IDC, attr->PROFILE_IOP, attr->LEVEL); + } -static void h264_format_attr_sdp_generate(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str) -{ - int i, added = 0; - - for (i = H264_ATTR_KEY_PROFILE_IDC; i < H264_ATTR_KEY_END; i++) { - const char *name; - - if (i == H264_ATTR_KEY_SPS && format_attr->format_attr[H264_ATTR_KEY_SPS] && format_attr->format_attr[H264_ATTR_KEY_PPS]) { - unsigned char spsdecoded[H264_MAX_SPS_PPS_SIZE] = { 0, }, ppsdecoded[H264_MAX_SPS_PPS_SIZE] = { 0, }; - int pos; - char sps[H264_MAX_SPS_PPS_SIZE], pps[H264_MAX_SPS_PPS_SIZE]; - - for (pos = 0; pos < H264_MAX_SPS_PPS_SIZE; pos++) { - spsdecoded[pos] = format_attr->format_attr[H264_ATTR_KEY_SPS + pos]; - ppsdecoded[pos] = format_attr->format_attr[H264_ATTR_KEY_PPS + pos]; - } - - ast_base64encode(sps, spsdecoded, format_attr->format_attr[H264_ATTR_KEY_SPS_LEN], H264_MAX_SPS_PPS_SIZE); - ast_base64encode(pps, ppsdecoded, format_attr->format_attr[H264_ATTR_KEY_PPS_LEN], H264_MAX_SPS_PPS_SIZE); - - if (!added) { - ast_str_append(str, 0, "a=fmtp:%u sprop-parameter-sets=%s,%s", payload, sps, pps); - added = 1; - } else { - ast_str_append(str, 0, ";sprop-parameter-sets=%s,%s", sps, pps); - } - } else if (i == H264_ATTR_KEY_PROFILE_IDC && format_attr->format_attr[H264_ATTR_KEY_PROFILE_IDC] && - format_attr->format_attr[H264_ATTR_KEY_PROFILE_IOP] && format_attr->format_attr[H264_ATTR_KEY_LEVEL]) { - if (!added) { - ast_str_append(str, 0, "a=fmtp:%u profile-level-id=%02X%02X%02X", payload, format_attr->format_attr[H264_ATTR_KEY_PROFILE_IDC], - format_attr->format_attr[H264_ATTR_KEY_PROFILE_IOP], format_attr->format_attr[H264_ATTR_KEY_LEVEL]); - added = 1; - } else { - ast_str_append(str, 0, ";profile-level-id=%02X%02X%02X", format_attr->format_attr[H264_ATTR_KEY_PROFILE_IDC], - format_attr->format_attr[H264_ATTR_KEY_PROFILE_IOP], format_attr->format_attr[H264_ATTR_KEY_LEVEL]); - } - } else if ((name = h264_attr_key_to_str(i)) && h264_attr_key_addable(format_attr, i)) { - if (!added) { - ast_str_append(str, 0, "a=fmtp:%u %s=%u", payload, name, format_attr->format_attr[i]); - added = 1; - } else { - ast_str_append(str, 0, ";%s=%u", name, format_attr->format_attr[i]); - } + if (!ast_strlen_zero(attr->SPS) && !ast_strlen_zero(attr->PPS)) { + if (added) { + ast_str_append(str, 0, ";"); + } else { + added = 1; } + ast_str_append(str, 0, ";sprop-parameter-sets=%s,%s", attr->SPS, attr->PPS); } - - if (added) { + + if (!added) { + ast_str_reset(*str); + } else { ast_str_append(str, 0, "\r\n"); } return; } -static struct ast_format_attr_interface h264_format_attr_interface = { - .id = AST_FORMAT_H264, - .format_attr_cmp = h264_format_attr_cmp, - .format_attr_get_joint = h264_format_attr_get_joint, - .format_attr_sdp_parse = h264_format_attr_sdp_parse, - .format_attr_sdp_generate = h264_format_attr_sdp_generate, +static struct ast_format_interface h264_interface = { + .format_destroy = h264_destroy, + .format_clone = h264_clone, + .format_cmp = h264_cmp, + .format_get_joint = h264_getjoint, + .format_parse_sdp_fmtp = h264_parse_sdp_fmtp, + .format_generate_sdp_fmtp = h264_generate_sdp_fmtp, }; static int unload_module(void) { - ast_format_attr_unreg_interface(&h264_format_attr_interface); - return 0; } static int load_module(void) { - if (ast_format_attr_reg_interface(&h264_format_attr_interface)) { + if (ast_format_interface_register("h264", &h264_interface)) { return AST_MODULE_LOAD_DECLINE; } diff --git a/res/res_format_attr_opus.c b/res/res_format_attr_opus.c index 3fa7dcef3..9e84982fb 100644 --- a/res/res_format_attr_opus.c +++ b/res/res_format_attr_opus.c @@ -51,12 +51,44 @@ struct opus_attr { unsigned int spropstereo; /* Default 0 */ }; -static int opus_sdp_parse(struct ast_format_attr *format_attr, const char *attributes) +static void opus_destroy(struct ast_format *format) { - struct opus_attr *attr = (struct opus_attr *) format_attr; + struct opus_attr *attr = ast_format_get_attribute_data(format); + + ast_free(attr); +} + +static int opus_clone(const struct ast_format *src, struct ast_format *dst) +{ + struct opus_attr *original = ast_format_get_attribute_data(src); + struct opus_attr *attr = ast_calloc(1, sizeof(*attr)); + + if (!attr) { + return -1; + } + + if (original) { + *attr = *original; + } + + ast_format_set_attribute_data(dst, attr); + + return 0; +} + +static struct ast_format *opus_parse_sdp_fmtp(const struct ast_format *format, const char *attributes) +{ + struct ast_format *cloned; + struct opus_attr *attr; const char *kvp; unsigned int val; + cloned = ast_format_clone(format); + if (!cloned) { + return NULL; + } + attr = ast_format_get_attribute_data(cloned); + if ((kvp = strstr(attributes, "maxplaybackrate")) && sscanf(kvp, "maxplaybackrate=%30u", &val) == 1) { attr->maxplayrate = val; } @@ -91,9 +123,13 @@ static int opus_sdp_parse(struct ast_format_attr *format_attr, const char *attri return 0; } -static void opus_sdp_generate(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str) +static void opus_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str) { - struct opus_attr *attr = (struct opus_attr *) format_attr; + struct opus_attr *attr = ast_format_get_attribute_data(format); + + if (!attr) { + return; + } /* FIXME should we only generate attributes that were explicitly set? */ ast_str_append(str, 0, @@ -120,114 +156,18 @@ static void opus_sdp_generate(const struct ast_format_attr *format_attr, unsigne ); } -static int opus_get_val(const struct ast_format_attr *fattr, int key, void *result) +static struct ast_format *opus_getjoint(const struct ast_format *format1, const struct ast_format *format2) { - const struct opus_attr *attr = (struct opus_attr *) fattr; - int *val = result; - - switch (key) { - case OPUS_ATTR_KEY_MAX_BITRATE: - *val = attr->maxbitrate; - break; - case OPUS_ATTR_KEY_MAX_PLAYRATE: - *val = attr->maxplayrate; - break; - case OPUS_ATTR_KEY_MINPTIME: - *val = attr->minptime; - break; - case OPUS_ATTR_KEY_STEREO: - *val = attr->stereo; - break; - case OPUS_ATTR_KEY_CBR: - *val = attr->cbr; - break; - case OPUS_ATTR_KEY_FEC: - *val = attr->fec; - break; - case OPUS_ATTR_KEY_DTX: - *val = attr->dtx; - break; - case OPUS_ATTR_KEY_SPROP_CAPTURE_RATE: - *val = attr->spropmaxcapturerate; - break; - case OPUS_ATTR_KEY_SPROP_STEREO: - *val = attr->spropstereo; - break; - default: - ast_log(LOG_WARNING, "unknown attribute type %d\n", key); - return -1; - } - return 0; -} + struct opus_attr *attr1 = ast_format_get_attribute_data(format1); + struct opus_attr *attr2 = ast_format_get_attribute_data(format2); + struct ast_format *jointformat; + struct opus_attr *attr_res; -static int opus_isset(const struct ast_format_attr *fattr, va_list ap) -{ - enum opus_attr_keys key; - const struct opus_attr *attr = (struct opus_attr *) fattr; - - for (key = va_arg(ap, int); - key != AST_FORMAT_ATTR_END; - key = va_arg(ap, int)) - { - switch (key) { - case OPUS_ATTR_KEY_MAX_BITRATE: - if (attr->maxbitrate != (va_arg(ap, int))) { - return -1; - } - break; - case OPUS_ATTR_KEY_MAX_PLAYRATE: - if (attr->maxplayrate != (va_arg(ap, int))) { - return -1; - } - break; - case OPUS_ATTR_KEY_MINPTIME: - if (attr->minptime != (va_arg(ap, int))) { - return -1; - } - break; - case OPUS_ATTR_KEY_STEREO: - if (attr->stereo != (va_arg(ap, int))) { - return -1; - } - break; - case OPUS_ATTR_KEY_CBR: - if (attr->cbr != (va_arg(ap, int))) { - return -1; - } - break; - case OPUS_ATTR_KEY_FEC: - if (attr->fec != (va_arg(ap, int))) { - return -1; - } - break; - case OPUS_ATTR_KEY_DTX: - if (attr->dtx != (va_arg(ap, int))) { - return -1; - } - break; - case OPUS_ATTR_KEY_SPROP_CAPTURE_RATE: - if (attr->spropmaxcapturerate != (va_arg(ap, int))) { - return -1; - } - break; - case OPUS_ATTR_KEY_SPROP_STEREO: - if (attr->spropstereo != (va_arg(ap, int))) { - return -1; - } - break; - default: - ast_log(LOG_WARNING, "unknown attribute type %u\n", key); - return -1; - } + jointformat = ast_format_clone(format1); + if (!jointformat) { + return NULL; } - return 0; -} -static int opus_getjoint(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result) -{ - struct opus_attr *attr1 = (struct opus_attr *) fattr1; - struct opus_attr *attr2 = (struct opus_attr *) fattr2; - struct opus_attr *attr_res = (struct opus_attr *) result; - int joint = 0; + attr_res = ast_format_get_attribute_data(jointformat); /* Only do dtx if both sides want it. DTX is a trade off between * computational complexity and bandwidth. */ @@ -243,65 +183,64 @@ static int opus_getjoint(const struct ast_format_attr *fattr1, const struct ast_ /* FIXME: do we need to join other attributes as well, e.g., minptime, cbr, etc.? */ - return joint; + return jointformat; } -static void opus_set(struct ast_format_attr *fattr, va_list ap) +static struct ast_format *opus_set(const struct ast_format *format, const char *name, const char *value) { - enum opus_attr_keys key; - struct opus_attr *attr = (struct opus_attr *) fattr; - - for (key = va_arg(ap, int); - key != AST_FORMAT_ATTR_END; - key = va_arg(ap, int)) - { - switch (key) { - case OPUS_ATTR_KEY_MAX_BITRATE: - attr->maxbitrate = (va_arg(ap, int)); - break; - case OPUS_ATTR_KEY_MAX_PLAYRATE: - attr->maxplayrate = (va_arg(ap, int)); - break; - case OPUS_ATTR_KEY_MINPTIME: - attr->minptime = (va_arg(ap, int)); - break; - case OPUS_ATTR_KEY_STEREO: - attr->stereo = (va_arg(ap, int)); - break; - case OPUS_ATTR_KEY_CBR: - attr->cbr = (va_arg(ap, int)); - break; - case OPUS_ATTR_KEY_FEC: - attr->fec = (va_arg(ap, int)); - break; - case OPUS_ATTR_KEY_DTX: - attr->dtx = (va_arg(ap, int)); - break; - case OPUS_ATTR_KEY_SPROP_CAPTURE_RATE: - attr->spropmaxcapturerate = (va_arg(ap, int)); - break; - case OPUS_ATTR_KEY_SPROP_STEREO: - attr->spropstereo = (va_arg(ap, int)); - break; - default: - ast_log(LOG_WARNING, "unknown attribute type %u\n", key); - } + struct ast_format *cloned; + struct opus_attr *attr; + unsigned int val; + + if (sscanf(value, "%30u", &val) != 1) { + ast_log(LOG_WARNING, "Unknown value '%s' for attribute type '%s'\n", + value, name); + return NULL; + } + + cloned = ast_format_clone(format); + if (!cloned) { + return NULL; } + attr = ast_format_get_attribute_data(cloned); + + if (!strcasecmp(name, "max_bitrate")) { + attr->maxbitrate = val; + } else if (!strcasecmp(name, "max_playrate")) { + attr->maxplayrate = val; + } else if (!strcasecmp(name, "minptime")) { + attr->minptime = val; + } else if (!strcasecmp(name, "stereo")) { + attr->stereo = val; + } else if (!strcasecmp(name, "cbr")) { + attr->cbr = val; + } else if (!strcasecmp(name, "fec")) { + attr->fec = val; + } else if (!strcasecmp(name, "dtx")) { + attr->dtx = val; + } else if (!strcasecmp(name, "sprop_capture_rate")) { + attr->spropmaxcapturerate = val; + } else if (!strcasecmp(name, "sprop_stereo")) { + attr->spropstereo = val; + } else { + ast_log(LOG_WARNING, "unknown attribute type %s\n", name); + } + + return cloned; } -static struct ast_format_attr_interface opus_interface = { - .id = AST_FORMAT_OPUS, - .format_attr_get_joint = opus_getjoint, - .format_attr_set = opus_set, - .format_attr_isset = opus_isset, - .format_attr_get_val = opus_get_val, - .format_attr_sdp_parse = opus_sdp_parse, - .format_attr_sdp_generate = opus_sdp_generate, +static struct ast_format_interface opus_interface = { + .format_destroy = opus_destroy, + .format_clone = opus_clone, + .format_get_joint = opus_getjoint, + .format_attribute_set = opus_set, + .format_parse_sdp_fmtp = opus_parse_sdp_fmtp, + .format_generate_sdp_fmtp = opus_generate_sdp_fmtp, }; static int load_module(void) { - if (ast_format_attr_reg_interface(&opus_interface)) { + if (ast_format_interface_register("opus", &opus_interface)) { return AST_MODULE_LOAD_DECLINE; } @@ -310,7 +249,6 @@ static int load_module(void) static int unload_module(void) { - ast_format_attr_unreg_interface(&opus_interface); return 0; } diff --git a/res/res_format_attr_silk.c b/res/res_format_attr_silk.c index 075570fb5..a46c62099 100644 --- a/res/res_format_attr_silk.c +++ b/res/res_format_attr_silk.c @@ -47,11 +47,43 @@ struct silk_attr { unsigned int packetloss_percentage; }; -static int silk_sdp_parse(struct ast_format_attr *format_attr, const char *attributes) +static void silk_destroy(struct ast_format *format) { - struct silk_attr *attr = (struct silk_attr *) format_attr; + struct silk_attr *attr = ast_format_get_attribute_data(format); + + ast_free(attr); +} + +static int silk_clone(const struct ast_format *src, struct ast_format *dst) +{ + struct silk_attr *original = ast_format_get_attribute_data(src); + struct silk_attr *attr = ast_calloc(1, sizeof(*attr)); + + if (!attr) { + return -1; + } + + if (original) { + *attr = *original; + } + + ast_format_set_attribute_data(dst, attr); + + return 0; +} + +static struct ast_format *silk_parse_sdp_fmtp(const struct ast_format *format, const char *attributes) +{ + struct ast_format *cloned; + struct silk_attr *attr; unsigned int val; + cloned = ast_format_clone(format); + if (!cloned) { + return NULL; + } + attr = ast_format_get_attribute_data(cloned); + if (sscanf(attributes, "maxaveragebitrate=%30u", &val) == 1) { attr->maxbitrate = val; } @@ -65,9 +97,13 @@ static int silk_sdp_parse(struct ast_format_attr *format_attr, const char *attri return 0; } -static void silk_sdp_generate(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str) +static void silk_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str) { - struct silk_attr *attr = (struct silk_attr *) format_attr; + struct silk_attr *attr = ast_format_get_attribute_data(format); + + if (!attr) { + return; + } if ((attr->maxbitrate > 5000) && (attr->maxbitrate < 40000)) { ast_str_append(str, 0, "a=fmtp:%u maxaveragebitrate=%u\r\n", payload, attr->maxbitrate); @@ -77,99 +113,40 @@ static void silk_sdp_generate(const struct ast_format_attr *format_attr, unsigne ast_str_append(str, 0, "a=fmtp:%u useinbandfec=%u\r\n", payload, attr->fec); } -static enum ast_format_cmp_res silk_cmp(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2) +static enum ast_format_cmp_res silk_cmp(const struct ast_format *format1, const struct ast_format *format2) { - struct silk_attr *attr1 = (struct silk_attr *) fattr1; - struct silk_attr *attr2 = (struct silk_attr *) fattr2; + struct silk_attr *attr1 = ast_format_get_attribute_data(format1); + struct silk_attr *attr2 = ast_format_get_attribute_data(format2); - if (attr1->samplerate == attr2->samplerate) { + if (((!attr1 || !attr1->samplerate) && (!attr2 || !attr2->samplerate)) || + (attr1->samplerate == attr2->samplerate)) { return AST_FORMAT_CMP_EQUAL; } + return AST_FORMAT_CMP_NOT_EQUAL; } -static int silk_get_val(const struct ast_format_attr *fattr, int key, void *result) +static struct ast_format *silk_getjoint(const struct ast_format *format1, const struct ast_format *format2) { - const struct silk_attr *attr = (struct silk_attr *) fattr; - int *val = result; - - switch (key) { - case SILK_ATTR_KEY_SAMP_RATE: - *val = attr->samplerate; - break; - case SILK_ATTR_KEY_MAX_BITRATE: - *val = attr->maxbitrate; - break; - case SILK_ATTR_KEY_DTX: - *val = attr->dtx; - break; - case SILK_ATTR_KEY_FEC: - *val = attr->fec; - break; - case SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE: - *val = attr->packetloss_percentage; - break; - default: - ast_log(LOG_WARNING, "unknown attribute type %d\n", key); - return -1; - } - return 0; -} + struct silk_attr *attr1 = ast_format_get_attribute_data(format1); + struct silk_attr *attr2 = ast_format_get_attribute_data(format2); + unsigned int samplerate; + struct ast_format *jointformat; + struct silk_attr *attr_res; -static int silk_isset(const struct ast_format_attr *fattr, va_list ap) -{ - enum silk_attr_keys key; - const struct silk_attr *attr = (struct silk_attr *) fattr; - - for (key = va_arg(ap, int); - key != AST_FORMAT_ATTR_END; - key = va_arg(ap, int)) - { - switch (key) { - case SILK_ATTR_KEY_SAMP_RATE: - if (attr->samplerate != (va_arg(ap, int))) { - return -1; - } - break; - case SILK_ATTR_KEY_MAX_BITRATE: - if (attr->maxbitrate != (va_arg(ap, int))) { - return -1; - } - break; - case SILK_ATTR_KEY_DTX: - if (attr->dtx != (va_arg(ap, int))) { - return -1; - } - break; - case SILK_ATTR_KEY_FEC: - if (attr->fec != (va_arg(ap, int))) { - return -1; - } - break; - case SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE: - if (attr->packetloss_percentage != (va_arg(ap, int))) { - return -1; - } - break; - default: - ast_log(LOG_WARNING, "unknown attribute type %u\n", key); - return -1; - } + samplerate = attr1->samplerate & attr2->samplerate; + /* sample rate is the only attribute that has any bearing on if joint capabilities exist or not */ + if (samplerate) { + return NULL; } - return 0; -} -static int silk_getjoint(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result) -{ - struct silk_attr *attr1 = (struct silk_attr *) fattr1; - struct silk_attr *attr2 = (struct silk_attr *) fattr2; - struct silk_attr *attr_res = (struct silk_attr *) result; - int joint = -1; - attr_res->samplerate = attr1->samplerate & attr2->samplerate; - /* sample rate is the only attribute that has any bearing on if joint capabilities exist or not */ - if (attr_res->samplerate) { - joint = 0; + jointformat = ast_format_clone(format1); + if (!jointformat) { + return NULL; } + attr_res = ast_format_get_attribute_data(jointformat); + attr_res->samplerate = samplerate; + /* Take the lowest max bitrate */ attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate); @@ -184,54 +161,58 @@ static int silk_getjoint(const struct ast_format_attr *fattr1, const struct ast_ /* Use the maximum packetloss percentage between the two attributes. This affects how * much redundancy is used in the FEC. */ attr_res->packetloss_percentage = MAX(attr1->packetloss_percentage, attr2->packetloss_percentage); - return joint; + + return jointformat; } -static void silk_set(struct ast_format_attr *fattr, va_list ap) +static struct ast_format *silk_set(const struct ast_format *format, const char *name, const char *value) { - enum silk_attr_keys key; - struct silk_attr *attr = (struct silk_attr *) fattr; - - for (key = va_arg(ap, int); - key != AST_FORMAT_ATTR_END; - key = va_arg(ap, int)) - { - switch (key) { - case SILK_ATTR_KEY_SAMP_RATE: - attr->samplerate = (va_arg(ap, int)); - break; - case SILK_ATTR_KEY_MAX_BITRATE: - attr->maxbitrate = (va_arg(ap, int)); - break; - case SILK_ATTR_KEY_DTX: - attr->dtx = (va_arg(ap, int)); - break; - case SILK_ATTR_KEY_FEC: - attr->fec = (va_arg(ap, int)); - break; - case SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE: - attr->packetloss_percentage = (va_arg(ap, int)); - break; - default: - ast_log(LOG_WARNING, "unknown attribute type %u\n", key); - } + struct ast_format *cloned; + struct silk_attr *attr; + unsigned int val; + + if (sscanf(value, "%30u", &val) != 1) { + ast_log(LOG_WARNING, "Unknown value '%s' for attribute type '%s'\n", + value, name); + return NULL; + } + + cloned = ast_format_clone(format); + if (!cloned) { + return NULL; + } + attr = ast_format_get_attribute_data(cloned); + + if (!strcasecmp(name, "sample_rate")) { + attr->samplerate = val; + } else if (!strcasecmp(name, "max_bitrate")) { + attr->maxbitrate = val; + } else if (!strcasecmp(name, "dtx")) { + attr->dtx = val; + } else if (!strcasecmp(name, "fec")) { + attr->fec = val; + } else if (!strcasecmp(name, "packetloss_percentage")) { + attr->packetloss_percentage = val; + } else { + ast_log(LOG_WARNING, "unknown attribute type %s\n", name); } + + return cloned; } -static struct ast_format_attr_interface silk_interface = { - .id = AST_FORMAT_SILK, - .format_attr_cmp = silk_cmp, - .format_attr_get_joint = silk_getjoint, - .format_attr_set = silk_set, - .format_attr_isset = silk_isset, - .format_attr_get_val = silk_get_val, - .format_attr_sdp_parse = silk_sdp_parse, - .format_attr_sdp_generate = silk_sdp_generate, +static struct ast_format_interface silk_interface = { + .format_destroy = silk_destroy, + .format_clone = silk_clone, + .format_cmp = silk_cmp, + .format_get_joint = silk_getjoint, + .format_attribute_set = silk_set, + .format_parse_sdp_fmtp = silk_parse_sdp_fmtp, + .format_generate_sdp_fmtp = silk_generate_sdp_fmtp, }; static int load_module(void) { - if (ast_format_attr_reg_interface(&silk_interface)) { + if (ast_format_interface_register("silk", &silk_interface)) { return AST_MODULE_LOAD_DECLINE; } @@ -240,7 +221,6 @@ static int load_module(void) static int unload_module(void) { - ast_format_attr_unreg_interface(&silk_interface); return 0; } diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index 1d05f0daa..093c846ee 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -131,8 +131,8 @@ static int respawn_time = 20; struct moh_files_state { /*! Holds a reference to the MOH class. */ struct mohclass *class; - struct ast_format origwfmt; - struct ast_format mohwfmt; + struct ast_format *origwfmt; + struct ast_format *mohwfmt; int announcement; int samples; int sample_queue; @@ -170,7 +170,7 @@ struct mohclass { int total_files; unsigned int flags; /*! The format from the MOH source, not applicable to "files" mode */ - struct ast_format format; + struct ast_format *format; /*! The pid of the external application delivering MOH */ int pid; time_t start; @@ -188,7 +188,7 @@ struct mohclass { struct mohdata { int pipe[2]; - struct ast_format origwfmt; + struct ast_format *origwfmt; struct mohclass *parent; struct ast_frame f; AST_LIST_ENTRY(mohdata) list; @@ -289,10 +289,14 @@ static void moh_files_release(struct ast_channel *chan, void *data) moh_post_stop(chan); - ast_format_clear(&state->mohwfmt); /* make sure to clear this format before restoring the original format. */ - if (state->origwfmt.id && ast_set_write_format(chan, &state->origwfmt)) { - ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%s'\n", ast_channel_name(chan), ast_getformatname(&state->origwfmt)); + ao2_ref(state->mohwfmt, -1); + state->mohwfmt = NULL; /* make sure to clear this format before restoring the original format */ + if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) { + ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%s'\n", ast_channel_name(chan), + ast_format_get_name(state->origwfmt)); } + ao2_cleanup(state->origwfmt); + state->origwfmt = NULL; state->save_pos = state->pos; state->announcement = 0; @@ -405,15 +409,15 @@ static void moh_files_write_format_change(struct ast_channel *chan, void *data) /* In order to prevent a recursive call to this function as a result * of setting the moh write format back on the channel. Clear * the moh write format before setting the write format on the channel.*/ - if (&state->origwfmt.id) { - struct ast_format tmp; + if (state->origwfmt) { + struct ast_format *tmp; - ast_format_copy(&tmp, ast_channel_writeformat(chan)); - if (state->mohwfmt.id) { - ast_format_clear(&state->origwfmt); - ast_set_write_format(chan, &state->mohwfmt); + tmp = ao2_bump(ast_channel_writeformat(chan)); + ao2_replace(state->origwfmt, NULL); + if (state->mohwfmt) { + ast_set_write_format(chan, state->mohwfmt); } - ast_format_copy(&state->origwfmt, &tmp); + state->origwfmt = tmp; } } @@ -442,8 +446,8 @@ static int moh_files_generator(struct ast_channel *chan, void *data, int len, in state->samples += f->samples; state->sample_queue -= f->samples; - if (ast_format_cmp(&f->subclass.format, &state->mohwfmt) == AST_FORMAT_CMP_NOT_EQUAL) { - ast_format_copy(&state->mohwfmt, &f->subclass.format); + if (ast_format_cmp(f->subclass.format, state->mohwfmt) == AST_FORMAT_CMP_NOT_EQUAL) { + ao2_replace(state->mohwfmt, f->subclass.format); } res = ast_write(chan, f); ast_frfree(f); @@ -486,8 +490,9 @@ static void *moh_files_alloc(struct ast_channel *chan, void *params) } state->class = mohclass_ref(class, "Reffing music class for channel"); - ast_format_copy(&state->origwfmt, ast_channel_writeformat(chan)); - ast_format_copy(&state->mohwfmt, ast_channel_writeformat(chan)); + /* it's possible state is not a new allocation, don't leak old refs */ + ao2_replace(state->origwfmt, ast_channel_writeformat(chan)); + ao2_replace(state->mohwfmt, ast_channel_writeformat(chan)); moh_post_start(chan, class->name); @@ -733,12 +738,12 @@ static void *monmp3thread(void *data) res = 8 * MOH_MS_INTERVAL; /* 800/100 = 8 samples/ms */ } /* For non-8000Hz formats, we need to alter the resolution */ - res = res * ast_format_rate(&class->format) / 8000; + res = res * ast_format_get_sample_rate(class->format) / 8000; if ((strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir")) && AST_LIST_EMPTY(&class->members)) continue; /* Read mp3 audio */ - len = ast_codec_get_len(&class->format, res); + len = ast_format_determine_length(class->format, res); if ((res2 = read(class->srcfd, sbuf, len)) != len) { if (!res2) { @@ -902,7 +907,7 @@ static struct mohdata *mohalloc(struct mohclass *cl) fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK); moh->f.frametype = AST_FRAME_VOICE; - ast_format_copy(&moh->f.subclass.format, &cl->format); + moh->f.subclass.format = cl->format; moh->f.offset = AST_FRIENDLY_OFFSET; moh->parent = mohclass_ref(cl, "Reffing music class for mohdata parent"); @@ -918,7 +923,7 @@ static void moh_release(struct ast_channel *chan, void *data) { struct mohdata *moh = data; struct mohclass *class = moh->parent; - struct ast_format oldwfmt; + struct ast_format *oldwfmt; ao2_lock(class); AST_LIST_REMOVE(&moh->parent->members, moh, list); @@ -927,7 +932,7 @@ static void moh_release(struct ast_channel *chan, void *data) close(moh->pipe[0]); close(moh->pipe[1]); - ast_format_copy(&oldwfmt, &moh->origwfmt); + oldwfmt = moh->origwfmt; moh->parent = class = mohclass_unref(class, "unreffing moh->parent upon deactivation of generator"); @@ -940,13 +945,15 @@ static void moh_release(struct ast_channel *chan, void *data) if (state && state->class) { state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator"); } - if (oldwfmt.id && ast_set_write_format(chan, &oldwfmt)) { + if (oldwfmt && ast_set_write_format(chan, oldwfmt)) { ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", - ast_channel_name(chan), ast_getformatname(&oldwfmt)); + ast_channel_name(chan), ast_format_get_name(oldwfmt)); } moh_post_stop(chan); } + + ao2_cleanup(oldwfmt); } static void *moh_alloc(struct ast_channel *chan, void *params) @@ -972,9 +979,10 @@ static void *moh_alloc(struct ast_channel *chan, void *params) } if ((res = mohalloc(class))) { - ast_format_copy(&res->origwfmt, ast_channel_writeformat(chan)); - if (ast_set_write_format(chan, &class->format)) { - ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", ast_channel_name(chan), ast_codec2str(&class->format)); + res->origwfmt = ao2_bump(ast_channel_writeformat(chan)); + if (ast_set_write_format(chan, class->format)) { + ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", ast_channel_name(chan), + ast_format_get_name(class->format)); moh_release(NULL, res); res = NULL; } else { @@ -991,7 +999,7 @@ static int moh_generate(struct ast_channel *chan, void *data, int len, int sampl short buf[1280 + AST_FRIENDLY_OFFSET / 2]; int res; - len = ast_codec_get_len(&moh->parent->format, samples); + len = ast_format_determine_length(moh->parent->format, samples); if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, ast_channel_name(chan)); @@ -1003,7 +1011,7 @@ static int moh_generate(struct ast_channel *chan, void *data, int len, int sampl moh->f.datalen = res; moh->f.data.ptr = buf + AST_FRIENDLY_OFFSET / 2; - moh->f.samples = ast_codec_get_samples(&moh->f); + moh->f.samples = ast_codec_samples_count(&moh->f); if (ast_write(chan, &moh->f) < 0) { ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno)); @@ -1303,6 +1311,8 @@ static void local_ast_moh_cleanup(struct ast_channel *chan) mohclass_unref(state->class, "Uh Oh. Cleaning up MOH with an active class"); ast_log(LOG_WARNING, "Uh Oh. Cleaning up MOH with an active class\n"); } + ao2_cleanup(state->origwfmt); + ao2_cleanup(state->mohwfmt); ast_free(ast_channel_music_state(chan)); ast_channel_music_state_set(chan, NULL); /* Only held a module reference if we had a music state */ @@ -1329,7 +1339,7 @@ static struct mohclass *_moh_class_malloc(const char *file, int line, const char ao2_alloc(sizeof(*class), moh_class_destructor) #endif )) { - ast_format_set(&class->format, AST_FORMAT_SLINEAR, 0); + class->format = ao2_bump(ast_format_slin); class->srcfd = -1; } @@ -1407,10 +1417,10 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha")) ast_set_flag(mohclass, MOH_SORTALPHA); else if (!strcasecmp(tmp->name, "format")) { - ast_getformatbyname(tmp->value, &mohclass->format); - if (!mohclass->format.id) { + mohclass->format = ast_format_cache_get(tmp->value); + if (!mohclass->format) { ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value); - ast_format_set(&mohclass->format, AST_FORMAT_SLINEAR, 0); + mohclass->format = ao2_bump(ast_format_slin); } } } @@ -1643,6 +1653,8 @@ static void moh_class_destructor(void *obj) class->timer = NULL; } + ao2_cleanup(class->format); + /* Finally, collect the exit status of the monitor thread */ if (tid > 0) { pthread_join(tid, NULL); @@ -1737,10 +1749,10 @@ static int load_moh_classes(int reload) } else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) { ast_set_flag(class, MOH_SORTALPHA); } else if (!strcasecmp(var->name, "format")) { - ast_getformatbyname(var->value, &class->format); - if (!class->format.id) { + class->format = ast_format_cache_get(var->value); + if (!class->format) { ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value); - ast_format_set(&class->format, AST_FORMAT_SLINEAR, 0); + class->format = ao2_bump(ast_format_slin); } } } @@ -1877,7 +1889,7 @@ static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struc ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>")); } if (strcasecmp(class->mode, "files")) { - ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(&class->format)); + ast_cli(a->fd, "\tFormat: %s\n", ast_format_get_name(class->format)); } } ao2_iterator_destroy(&i); diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 59db4eb1e..548372879 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1648,8 +1648,8 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod ast_sorcery_object_field_register(sip_sorcery, "endpoint", "type", "", OPT_NOOP_T, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "context", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, context)); - ast_sorcery_object_field_register_alias(sip_sorcery, "endpoint", "disallow", "", OPT_CODEC_T, 0, FLDSET(struct ast_sip_endpoint, media.prefs, media.codecs)); - ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow", "", OPT_CODEC_T, 1, FLDSET(struct ast_sip_endpoint, media.prefs, media.codecs)); + ast_sorcery_object_field_register_alias(sip_sorcery, "endpoint", "disallow", "", OPT_CODEC_T, 0, FLDSET(struct ast_sip_endpoint, media.codecs)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow", "", OPT_CODEC_T, 1, FLDSET(struct ast_sip_endpoint, media.codecs)); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtmf_mode", "rfc4733", dtmf_handler, dtmf_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.ipv6)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_symmetric", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.symmetric)); @@ -1851,9 +1851,7 @@ static void endpoint_destructor(void* obj) ast_string_field_free_memory(endpoint); - if (endpoint->media.codecs) { - ast_format_cap_destroy(endpoint->media.codecs); - } + ao2_ref(endpoint->media.codecs, -1); subscription_configuration_destroy(&endpoint->subscription); info_configuration_destroy(&endpoint->info); media_configuration_destroy(&endpoint->media); @@ -1891,7 +1889,7 @@ void *ast_sip_endpoint_alloc(const char *name) ao2_cleanup(endpoint); return NULL; } - if (!(endpoint->media.codecs = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) { + if (!(endpoint->media.codecs = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { ao2_cleanup(endpoint); return NULL; } diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index b7e1eef3d..90a2cec46 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -41,6 +41,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" +#include "asterisk/format.h" +#include "asterisk/format_cap.h" #include "asterisk/rtp_engine.h" #include "asterisk/netsock2.h" #include "asterisk/channel.h" @@ -68,38 +70,39 @@ static const char STR_VIDEO[] = "video"; static const int FD_VIDEO = 2; /*! \brief Retrieves an ast_format_type based on the given stream_type */ -static enum ast_format_type stream_to_media_type(const char *stream_type) +static enum ast_media_type stream_to_media_type(const char *stream_type) { if (!strcasecmp(stream_type, STR_AUDIO)) { - return AST_FORMAT_TYPE_AUDIO; + return AST_MEDIA_TYPE_AUDIO; } else if (!strcasecmp(stream_type, STR_VIDEO)) { - return AST_FORMAT_TYPE_VIDEO; + return AST_MEDIA_TYPE_VIDEO; } return 0; } /*! \brief Get the starting descriptor for a media type */ -static int media_type_to_fdno(enum ast_format_type media_type) +static int media_type_to_fdno(enum ast_media_type media_type) { switch (media_type) { - case AST_FORMAT_TYPE_AUDIO: return FD_AUDIO; - case AST_FORMAT_TYPE_VIDEO: return FD_VIDEO; - case AST_FORMAT_TYPE_TEXT: - case AST_FORMAT_TYPE_IMAGE: break; + case AST_MEDIA_TYPE_AUDIO: return FD_AUDIO; + case AST_MEDIA_TYPE_VIDEO: return FD_VIDEO; + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_IMAGE: break; } return -1; } /*! \brief Remove all other cap types but the one given */ -static void format_cap_only_type(struct ast_format_cap *caps, enum ast_format_type media_type) +static void format_cap_only_type(struct ast_format_cap *caps, enum ast_media_type media_type) { - int i = AST_FORMAT_INC; - while (i <= AST_FORMAT_TYPE_TEXT) { - if (i != media_type) { - ast_format_cap_remove_bytype(caps, i); + int i = 0; + while (i <= AST_MEDIA_TYPE_TEXT) { + if (i != media_type && i != AST_MEDIA_TYPE_UNKNOWN) { + ast_format_cap_remove_by_type(caps, i); } - i += AST_FORMAT_INC; + i += 1; } } @@ -116,9 +119,6 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RTCP, 1); ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_NAT, session->endpoint->media.rtp.symmetric); - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session_media->rtp), - session_media->rtp, &session->endpoint->media.prefs); - if (session->endpoint->dtmf == AST_SIP_DTMF_INBAND) { ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_INBAND); } @@ -185,74 +185,97 @@ static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp if ((pjmedia_sdp_attr_get_fmtp(attr, &fmtp)) == PJ_SUCCESS) { sscanf(pj_strbuf(&fmtp.fmt), "%d", &num); if ((format = ast_rtp_codecs_get_payload_format(codecs, num))) { + struct ast_format *format_parsed; + ast_copy_pj_str(fmt_param, &fmtp.fmt_param, sizeof(fmt_param)); - ast_format_sdp_parse(format, fmt_param); + + format_parsed = ast_format_parse_sdp_fmtp(format, fmt_param); + if (format_parsed) { + ast_rtp_codecs_payload_replace_format(codecs, num, format_parsed); + ao2_ref(format_parsed, -1); + } + + ao2_ref(format, -1); } } } + + /* Get the packetization, if it exists */ + if ((attr = pjmedia_sdp_media_find_attr2(stream, "ptime", NULL))) { + unsigned long framing = pj_strtoul(pj_strltrim(&attr->value)); + if (framing && session->endpoint->media.rtp.use_ptime) { + ast_rtp_codecs_set_framing(codecs, framing); + } + } } static int set_caps(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *stream) { - RAII_VAR(struct ast_format_cap *, caps, NULL, ast_format_cap_destroy); - RAII_VAR(struct ast_format_cap *, peer, NULL, ast_format_cap_destroy); - RAII_VAR(struct ast_format_cap *, joint, NULL, ast_format_cap_destroy); - enum ast_format_type media_type = stream_to_media_type(session_media->stream_type); - struct ast_rtp_codecs codecs; - struct ast_format fmt; + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_format_cap *, peer, NULL, ao2_cleanup); + RAII_VAR(struct ast_format_cap *, joint, NULL, ao2_cleanup); + enum ast_media_type media_type = stream_to_media_type(session_media->stream_type); + struct ast_rtp_codecs codecs = AST_RTP_CODECS_NULL_INIT; int fmts = 0; int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) && - !ast_format_cap_is_empty(session->direct_media_cap); + ast_format_cap_count(session->direct_media_cap); - if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK)) || - !(peer = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) { + if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) || + !(peer = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) || + !(joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", session_media->stream_type); return -1; } /* get the endpoint capabilities */ if (direct_media_enabled) { - ast_format_cap_joint_copy(session->endpoint->media.codecs, session->direct_media_cap, caps); + ast_format_cap_get_compatible(session->endpoint->media.codecs, session->direct_media_cap, caps); + format_cap_only_type(caps, media_type); } else { - ast_format_cap_copy(caps, session->endpoint->media.codecs); + ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, media_type); } - format_cap_only_type(caps, media_type); /* get the capabilities on the peer */ get_codecs(session, stream, &codecs); ast_rtp_codecs_payload_formats(&codecs, peer, &fmts); /* get the joint capabilities between peer and endpoint */ - if (!(joint = ast_format_cap_joint(caps, peer))) { - char usbuf[64], thembuf[64]; + ast_format_cap_get_compatible(caps, peer, joint); + if (!ast_format_cap_count(joint)) { + struct ast_str *usbuf = ast_str_alloca(64); + struct ast_str *thembuf = ast_str_alloca(64); ast_rtp_codecs_payloads_destroy(&codecs); - - ast_getformatname_multiple(usbuf, sizeof(usbuf), caps); - ast_getformatname_multiple(thembuf, sizeof(thembuf), peer); - ast_log(LOG_WARNING, "No joint capabilities between our configuration(%s) and incoming SDP(%s)\n", usbuf, thembuf); + ast_log(LOG_WARNING, "No joint capabilities between our configuration(%s) and incoming SDP(%s)\n", + ast_format_cap_get_names(peer, &usbuf), + ast_format_cap_get_names(caps, &thembuf)); return -1; } ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(session_media->rtp), session_media->rtp); - ast_format_cap_copy(caps, session->req_caps); - ast_format_cap_remove_bytype(caps, media_type); - ast_format_cap_append(caps, joint); - ast_format_cap_append(session->req_caps, caps); + ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_from_cap(caps, session->req_caps, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_remove_by_type(caps, media_type); + ast_format_cap_append_from_cap(caps, joint, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_from_cap(session->req_caps, caps, AST_MEDIA_TYPE_UNKNOWN); if (session->channel) { - ast_format_cap_copy(caps, ast_channel_nativeformats(session->channel)); - ast_format_cap_remove_bytype(caps, media_type); - ast_codec_choose(&session->endpoint->media.prefs, joint, 1, &fmt); - ast_format_cap_add(caps, &fmt); + struct ast_format *fmt; + + ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(session->channel), AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_remove_by_type(caps, media_type); + fmt = ast_format_cap_get_format(joint, 0); + ast_format_cap_append(caps, fmt, 0); /* Apply the new formats to the channel, potentially changing read/write formats while doing so */ - ast_format_cap_copy(ast_channel_nativeformats(session->channel), caps); - ast_set_read_format(session->channel, ast_channel_readformat(session->channel)); - ast_set_write_format(session->channel, ast_channel_writeformat(session->channel)); + ast_channel_nativeformats_set(session->channel, caps); + ast_channel_set_rawwriteformat(session->channel, fmt); + ast_channel_set_rawreadformat(session->channel, fmt); + + ao2_ref(fmt, -1); } ast_rtp_codecs_payloads_destroy(&codecs); @@ -286,7 +309,7 @@ static pjmedia_sdp_attr* generate_fmtp_attr(pj_pool_t *pool, struct ast_format * pjmedia_sdp_attr *attr = NULL; char *tmp; - ast_format_sdp_generate(format, rtp_code, &fmtp0); + ast_format_generate_sdp_fmtp(format, rtp_code, &fmtp0); if (ast_str_strlen(fmtp0)) { tmp = ast_str_buffer(fmtp0) + ast_str_strlen(fmtp0) - 1; /* remove any carriage return line feeds */ @@ -304,18 +327,6 @@ static pjmedia_sdp_attr* generate_fmtp_attr(pj_pool_t *pool, struct ast_format * return attr; } -static int codec_pref_has_type(struct ast_codec_pref *prefs, enum ast_format_type media_type) -{ - int i; - struct ast_format fmt; - for (i = 0; ast_codec_pref_index(prefs, i, &fmt); ++i) { - if (AST_FORMAT_GET_TYPE(fmt.id) == media_type) { - return 1; - } - } - return 0; -} - /*! \brief Function which adds ICE attributes to a media stream */ static void add_ice_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media) { @@ -469,38 +480,6 @@ static void process_ice_attributes(struct ast_sip_session *session, struct ast_s ice->start(session_media->rtp); } -static void apply_packetization(struct ast_sip_session *session, struct ast_sip_session_media *session_media, - const struct pjmedia_sdp_media *remote_stream) -{ - pjmedia_sdp_attr *attr; - pj_str_t value; - unsigned long framing; - int codec; - struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(session_media->rtp)->pref; - - /* Apply packetization if available and configured to do so */ - if (!session->endpoint->media.rtp.use_ptime || !(attr = pjmedia_sdp_media_find_attr2(remote_stream, "ptime", NULL))) { - return; - } - - value = attr->value; - framing = pj_strtoul(pj_strltrim(&value)); - - for (codec = 0; codec < AST_RTP_MAX_PT; codec++) { - struct ast_rtp_payload_type format = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs( - session_media->rtp), codec); - - if (!format.asterisk_format) { - continue; - } - - ast_codec_pref_setsize(pref, &format.format, framing); - } - - ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session_media->rtp), - session_media->rtp, pref); -} - /*! \brief figure out media transport encryption type from the media transport string */ static enum ast_sip_session_media_encryption get_media_encryption_type(pj_str_t transport) { @@ -722,7 +701,7 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct { char host[NI_MAXHOST]; RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr); - enum ast_format_type media_type = stream_to_media_type(session_media->stream_type); + enum ast_media_type media_type = stream_to_media_type(session_media->stream_type); /* If no type formats have been configured reject this stream */ if (!ast_format_cap_has_type(session->endpoint->media.codecs, media_type)) { @@ -759,11 +738,6 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct if (set_caps(session, session_media, stream)) { return -1; } - - if (media_type == AST_FORMAT_TYPE_AUDIO) { - apply_packetization(session, session_media, stream); - } - return 1; } @@ -892,18 +866,14 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as int noncodec = (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733) ? AST_RTP_DTMF : 0; int min_packet_size = 0, max_packet_size = 0; int rtp_code; - struct ast_format format; - RAII_VAR(struct ast_format_cap *, caps, NULL, ast_format_cap_destroy); - enum ast_format_type media_type = stream_to_media_type(session_media->stream_type); + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + enum ast_media_type media_type = stream_to_media_type(session_media->stream_type); + int use_override_prefs = ast_format_cap_count(session->req_caps); int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) && - !ast_format_cap_is_empty(session->direct_media_cap); + ast_format_cap_count(session->direct_media_cap); - int use_override_prefs = session->override_prefs.formats[0].id; - struct ast_codec_pref *prefs = use_override_prefs ? - &session->override_prefs : &session->endpoint->media.prefs; - - if ((use_override_prefs && !codec_pref_has_type(&session->override_prefs, media_type)) || + if ((use_override_prefs && !ast_format_cap_has_type(session->req_caps, media_type)) || (!use_override_prefs && !ast_format_cap_has_type(session->endpoint->media.codecs, media_type))) { /* If no type formats are configured don't add a stream */ return 0; @@ -954,59 +924,53 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as /* Add ICE attributes and candidates */ add_ice_to_stream(session, session_media, pool, media); - if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) { + if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", session_media->stream_type); return -1; } if (direct_media_enabled) { - ast_format_cap_joint_copy(session->endpoint->media.codecs, session->direct_media_cap, caps); - } else if (ast_format_cap_is_empty(session->req_caps) || !ast_format_cap_has_joint(session->req_caps, session->endpoint->media.codecs)) { - ast_format_cap_copy(caps, session->endpoint->media.codecs); + ast_format_cap_get_compatible(session->endpoint->media.codecs, session->direct_media_cap, caps); + } else if (!ast_format_cap_count(session->req_caps) || + !ast_format_cap_iscompatible(session->req_caps, session->endpoint->media.codecs)) { + ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, media_type); } else { - ast_format_cap_copy(caps, session->req_caps); + ast_format_cap_append_from_cap(caps, session->req_caps, media_type); } - for (index = 0; ast_codec_pref_index(prefs, index, &format); ++index) { - struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(session_media->rtp)->pref; - - if (AST_FORMAT_GET_TYPE(format.id) != media_type) { - continue; - } + for (index = 0; index < ast_format_cap_count(caps); ++index) { + struct ast_format *format = ast_format_cap_get_format(caps, index); - if (!use_override_prefs && !ast_format_cap_get_compatible_format(caps, &format, &format)) { + if (ast_format_get_type(format) != media_type) { + ao2_ref(format, -1); continue; } - if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp), 1, &format, 0)) == -1) { - ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n",ast_getformatname(&format)); + if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp), 1, format, 0)) == -1) { + ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", ast_format_get_name(format)); + ao2_ref(format, -1); continue; } - if (!(attr = generate_rtpmap_attr(media, pool, rtp_code, 1, &format, 0))) { + if (!(attr = generate_rtpmap_attr(media, pool, rtp_code, 1, format, 0))) { + ao2_ref(format, -1); continue; } - media->attr[media->attr_count++] = attr; - if ((attr = generate_fmtp_attr(pool, &format, rtp_code))) { + if ((attr = generate_fmtp_attr(pool, format, rtp_code))) { media->attr[media->attr_count++] = attr; } - if (pref && media_type != AST_FORMAT_TYPE_VIDEO) { - struct ast_format_list fmt = ast_codec_pref_getsize(pref, &format); - if (fmt.cur_ms && ((fmt.cur_ms < min_packet_size) || !min_packet_size)) { - min_packet_size = fmt.cur_ms; - } - - if (fmt.max_ms && ((fmt.max_ms < max_packet_size) || !max_packet_size)) { - max_packet_size = fmt.max_ms; - } + if (ast_format_get_maximum_ms(format) && + ((ast_format_get_maximum_ms(format) < max_packet_size) || !max_packet_size)) { + max_packet_size = ast_format_get_maximum_ms(format); } + ao2_ref(format, -1); } /* Add non-codec formats */ - if (media_type != AST_FORMAT_TYPE_VIDEO) { + if (media_type != AST_MEDIA_TYPE_VIDEO) { for (index = 1LL; index <= AST_RTP_MAX; index <<= 1) { if (!(noncodec & index) || (rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp), 0, NULL, index)) == -1) { @@ -1033,6 +997,10 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as } /* If ptime is set add it as an attribute */ + min_packet_size = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(session_media->rtp)); + if (!min_packet_size) { + min_packet_size = ast_format_cap_get_framing(caps); + } if (min_packet_size) { snprintf(tmp, sizeof(tmp), "%d", min_packet_size); attr = pjmedia_sdp_attr_create(pool, "ptime", pj_cstr(&stmp, tmp)); @@ -1061,7 +1029,7 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream) { RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr); - enum ast_format_type media_type = stream_to_media_type(session_media->stream_type); + enum ast_media_type media_type = stream_to_media_type(session_media->stream_type); char host[NI_MAXHOST]; int fdno; @@ -1095,15 +1063,10 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a /* Apply connection information to the RTP instance */ ast_sockaddr_set_port(addrs, remote_stream->desc.port); ast_rtp_instance_set_remote_address(session_media->rtp, addrs); - if (set_caps(session, session_media, local_stream)) { return -1; } - if (media_type == AST_FORMAT_TYPE_AUDIO) { - apply_packetization(session, session_media, remote_stream); - } - if ((fdno = media_type_to_fdno(media_type)) < 0) { return -1; } @@ -1117,7 +1080,7 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a ast_rtp_instance_activate(session_media->rtp); /* audio stream handles music on hold */ - if (media_type != AST_FORMAT_TYPE_AUDIO) { + if (media_type != AST_MEDIA_TYPE_AUDIO) { return 1; } diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 336122040..96faa64bb 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1069,8 +1069,8 @@ static void session_destructor(void *obj) ast_party_id_free(&session->id); ao2_cleanup(session->endpoint); ao2_cleanup(session->contact); - ast_format_cap_destroy(session->req_caps); - ast_format_cap_destroy(session->direct_media_cap); + ao2_cleanup(session->req_caps); + ao2_cleanup(session->direct_media_cap); if (session->dsp) { ast_dsp_free(session->dsp); @@ -1169,7 +1169,7 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, session->endpoint = ao2_bump(endpoint); session->contact = ao2_bump(contact); session->inv_session = inv_session; - session->req_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + session->req_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (endpoint->dtmf == AST_SIP_DTMF_INBAND) { dsp_features |= DSP_FEATURE_DIGIT_DETECT; @@ -1197,7 +1197,7 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, iter->session_begin(session); } } - session->direct_media_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + session->direct_media_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); AST_LIST_HEAD_INIT_NOLOCK(&session->delayed_requests); ast_party_id_init(&session->id); ao2_ref(session, +1); @@ -1273,9 +1273,19 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint return NULL; } - if (!ast_format_cap_is_empty(req_caps)) { - ast_format_cap_copy(session->req_caps, session->endpoint->media.codecs); - ast_format_cap_append(session->req_caps, req_caps); + if (ast_format_cap_count(req_caps)) { + /* get joint caps between req_caps and endpoint caps */ + struct ast_format_cap *joint_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + ast_format_cap_get_compatible(req_caps, session->endpoint->media.codecs, joint_caps); + + /* if joint caps */ + if (ast_format_cap_count(joint_caps)) { + /* copy endpoint caps into session->req_caps */ + ast_format_cap_append_from_cap(session->req_caps, session->endpoint->media.codecs, AST_MEDIA_TYPE_UNKNOWN); + /* replace instances of joint caps equivalents in session->req_caps */ + ast_format_cap_replace_from_cap(session->req_caps, joint_caps, AST_MEDIA_TYPE_UNKNOWN); + } + ao2_cleanup(joint_caps); } if ((pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS)) { diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 7251e8f80..bd930295b 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -56,6 +56,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/stun.h" #include "asterisk/pbx.h" #include "asterisk/frame.h" +#include "asterisk/format_cache.h" #include "asterisk/channel.h" #include "asterisk/acl.h" #include "asterisk/config.h" @@ -66,6 +67,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/unaligned.h" #include "asterisk/module.h" #include "asterisk/rtp_engine.h" +#include "asterisk/smoother.h" #include "asterisk/test.h" #define MAX_TIMESTAMP_SKEW 640 @@ -216,8 +218,8 @@ struct ast_rtp { unsigned int cycles; /*!< Shifted count of sequence number cycles */ double rxjitter; /*!< Interarrival jitter at the moment in seconds */ double rxtransit; /*!< Relative transit time for previous packet */ - struct ast_format lasttxformat; - struct ast_format lastrxformat; + struct ast_format *lasttxformat; + struct ast_format *lastrxformat; int rtptimeout; /*!< RTP timeout time (negative or zero means disabled, negative value means temporarily disabled) */ int rtpholdtimeout; /*!< RTP timeout when on hold (negative or zero means disabled, negative value means temporarily disabled). */ @@ -1833,7 +1835,11 @@ static int rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, static int rtp_get_rate(struct ast_format *format) { - return (format->id == AST_FORMAT_G722) ? 8000 : ast_format_rate(format); + /* For those wondering: due to a fluke in RFC publication, G.722 is advertised + * as having a sample rate of 8kHz, while implementations must know that its + * real rate is 16kHz. Seriously. + */ + return (ast_format_cmp(format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) ? 8000 : (int)ast_format_get_sample_rate(format); } static unsigned int ast_rtcp_calc_interval(struct ast_rtp *rtp) @@ -2184,6 +2190,10 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, rtp->dtlstimerid = -1; #endif + rtp->f.subclass.format = ao2_bump(ast_format_none); + rtp->lastrxformat = ao2_bump(ast_format_none); + rtp->lasttxformat = ao2_bump(ast_format_none); + return 0; } @@ -2265,6 +2275,10 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance) } #endif + ao2_cleanup(rtp->lasttxformat); + ao2_cleanup(rtp->lastrxformat); + ao2_cleanup(rtp->f.subclass.format); + /* Destroy synchronization items */ ast_mutex_destroy(&rtp->lock); ast_cond_destroy(&rtp->cond); @@ -2444,7 +2458,7 @@ static int ast_rtp_dtmf_end_with_duration(struct ast_rtp_instance *instance, cha rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000)); - if (duration > 0 && (measured_samples = duration * rtp_get_rate(&rtp->f.subclass.format) / 1000) > rtp->send_duration) { + if (duration > 0 && (measured_samples = duration * rtp_get_rate(rtp->f.subclass.format) / 1000) > rtp->send_duration) { ast_debug(2, "Adjusting final end duration from %d to %u\n", rtp->send_duration, measured_samples); rtp->send_duration = measured_samples; } @@ -2620,7 +2634,7 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) int fraction_lost; struct timeval dlsr = { 0, }; char bdata[512]; - int rate = rtp_get_rate(&rtp->f.subclass.format); + int rate = rtp_get_rate(rtp->f.subclass.format); int ice; int header_offset = 0; struct ast_sockaddr remote_address = { {0,} }; @@ -2791,9 +2805,9 @@ static int ast_rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame int pred, mark = 0; unsigned int ms = calc_txstamp(rtp, &frame->delivery); struct ast_sockaddr remote_address = { {0,} }; - int rate = rtp_get_rate(&frame->subclass.format) / 1000; + int rate = rtp_get_rate(frame->subclass.format) / 1000; - if (frame->subclass.format.id == AST_FORMAT_G722) { + if (ast_format_cmp(frame->subclass.format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) { frame->samples /= 2; } @@ -2817,7 +2831,7 @@ static int ast_rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame } } } else if (frame->frametype == AST_FRAME_VIDEO) { - mark = ast_format_get_video_mark(&frame->subclass.format); + mark = frame->subclass.frame_ending; pred = rtp->lastovidtimestamp + frame->samples; /* Re-calculate last TS */ rtp->lastts = rtp->lastts + ms * 90; @@ -2959,7 +2973,7 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); struct ast_sockaddr remote_address = { {0,} }; - struct ast_format subclass; + struct ast_format *format; int codec; ast_rtp_instance_get_remote_address(instance, &remote_address); @@ -3029,17 +3043,28 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr } /* Grab the subclass and look up the payload we are going to use */ - ast_format_copy(&subclass, &frame->subclass.format); - if ((codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 1, &subclass, 0)) < 0) { - ast_log(LOG_WARNING, "Don't know how to send format %s packets with RTP\n", ast_getformatname(&frame->subclass.format)); + codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), + 1, + frame->subclass.format, + 0); + if (codec < 0) { + ast_log(LOG_WARNING, "Don't know how to send format %s packets with RTP\n", + ast_format_get_name(frame->subclass.format)); return -1; } - /* Oh dear, if the format changed we will have to set up a new smoother */ - if (ast_format_cmp(&rtp->lasttxformat, &subclass) == AST_FORMAT_CMP_NOT_EQUAL) { - ast_debug(1, "Ooh, format changed from %s to %s\n", ast_getformatname(&rtp->lasttxformat), ast_getformatname(&subclass)); - rtp->lasttxformat = subclass; - ast_format_copy(&rtp->lasttxformat, &subclass); + /* Note that we do not increase the ref count here as this pointer + * will not be held by any thing explicitly. The format variable is + * merely a convenience reference to frame->subclass.format */ + format = frame->subclass.format; + if (ast_format_cmp(rtp->lasttxformat, format) == AST_FORMAT_CMP_NOT_EQUAL) { + /* Oh dear, if the format changed we will have to set up a new smoother */ + if (option_debug > 0) { + ast_debug(1, "Ooh, format changed from %s to %s\n", + ast_format_get_name(rtp->lasttxformat), + ast_format_get_name(frame->subclass.format)); + } + ao2_replace(rtp->lasttxformat, format); if (rtp->smoother) { ast_smoother_free(rtp->smoother); rtp->smoother = NULL; @@ -3047,34 +3072,15 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr } /* If no smoother is present see if we have to set one up */ - if (!rtp->smoother) { - struct ast_format_list fmt = ast_codec_pref_getsize(&ast_rtp_instance_get_codecs(instance)->pref, &subclass); - - switch (subclass.id) { - case AST_FORMAT_SPEEX: - case AST_FORMAT_SPEEX16: - case AST_FORMAT_SPEEX32: - case AST_FORMAT_SILK: - case AST_FORMAT_CELT: - case AST_FORMAT_G723_1: - case AST_FORMAT_SIREN7: - case AST_FORMAT_SIREN14: - case AST_FORMAT_G719: - /* Opus */ - case AST_FORMAT_OPUS: - /* these are all frame-based codecs and cannot be safely run through - a smoother */ - break; - default: - if (fmt.inc_ms) { - if (!(rtp->smoother = ast_smoother_new((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms))) { - ast_log(LOG_WARNING, "Unable to create smoother: format %s ms: %d len: %d\n", ast_getformatname(&subclass), fmt.cur_ms, ((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms)); - return -1; - } - if (fmt.flags) { - ast_smoother_set_flags(rtp->smoother, fmt.flags); - } - ast_debug(1, "Created smoother: format: %s ms: %d len: %d\n", ast_getformatname(&subclass), fmt.cur_ms, ((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms)); + if (!rtp->smoother && ast_format_can_be_smoothed(format)) { + unsigned int framing_ms = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(instance)); + + if (framing_ms) { + rtp->smoother = ast_smoother_new((framing_ms * ast_format_get_minimum_bytes(format)) / ast_format_get_minimum_ms(format)); + if (!rtp->smoother) { + ast_log(LOG_WARNING, "Unable to create smoother: format %s ms: %u len: %u\n", + ast_format_get_name(format), framing_ms, ast_format_get_minimum_bytes(format)); + return -1; } } } @@ -3122,7 +3128,7 @@ static void calc_rxstamp(struct timeval *tv, struct ast_rtp *rtp, unsigned int t double d; double dtv; double prog; - int rate = rtp_get_rate(&rtp->f.subclass.format); + int rate = rtp_get_rate(rtp->f.subclass.format); double normdev_rxjitter_current; if ((!rtp->rxcore.tv_sec && !rtp->rxcore.tv_usec) || mark) { @@ -3277,7 +3283,7 @@ static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned cha rtp->dtmf_duration = new_duration; rtp->resp = resp; f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0)); - f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(&f->subclass.format)), ast_tv(0, 0)); + f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.format)), ast_tv(0, 0)); rtp->resp = 0; rtp->dtmf_duration = rtp->dtmf_timeout = 0; AST_LIST_INSERT_TAIL(frames, f, frame_list); @@ -3308,7 +3314,7 @@ static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned cha if (rtp->resp && rtp->resp != resp) { /* Another digit already began. End it */ f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0)); - f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(&f->subclass.format)), ast_tv(0, 0)); + f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.format)), ast_tv(0, 0)); rtp->resp = 0; rtp->dtmf_duration = rtp->dtmf_timeout = 0; AST_LIST_INSERT_TAIL(frames, f, frame_list); @@ -3405,10 +3411,10 @@ static struct ast_frame *process_dtmf_cisco(struct ast_rtp_instance *instance, u } } else if ((rtp->resp == resp) && !power) { f = create_dtmf_frame(instance, AST_FRAME_DTMF_END, ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE)); - f->samples = rtp->dtmfsamples * (rtp->lastrxformat.id ? (rtp_get_rate(&rtp->lastrxformat) / 1000) : 8); + f->samples = rtp->dtmfsamples * (rtp_get_rate(rtp->lastrxformat) / 1000); rtp->resp = 0; } else if (rtp->resp == resp) { - rtp->dtmfsamples += 20 * (rtp->lastrxformat.id ? (rtp_get_rate(&rtp->lastrxformat) / 1000) : 8); + rtp->dtmfsamples += 20 * (rtp_get_rate(rtp->lastrxformat) / 1000); } rtp->dtmf_timeout = 0; @@ -3424,7 +3430,8 @@ static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, u totally help us out becuase we don't have an engine to keep it going and we are not guaranteed to have it every 20ms or anything */ if (rtpdebug) { - ast_debug(0, "- RTP 3389 Comfort noise event: Level %d (len = %d)\n", (int) rtp->lastrxformat.id, len); + ast_debug(0, "- RTP 3389 Comfort noise event: Format %s (len = %d)\n", + ast_format_get_name(rtp->lastrxformat), len); } if (ast_test_flag(rtp, FLAG_3389_WARNING)) { @@ -3796,7 +3803,7 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int struct ast_rtp_instance *instance1 = ast_rtp_instance_get_bridged(instance); struct ast_rtp *rtp = ast_rtp_instance_get_data(instance), *bridged = ast_rtp_instance_get_data(instance1); int res = 0, payload = 0, bridged_payload = 0, mark; - struct ast_rtp_payload_type payload_type; + RAII_VAR(struct ast_rtp_payload_type *, payload_type, NULL, ao2_cleanup); int reconstruct = ntohl(rtpheader[0]); struct ast_sockaddr remote_address = { {0,} }; int ice; @@ -3806,10 +3813,13 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int mark = (((reconstruct & 0x800000) >> 23) != 0); /* Check what the payload value should be */ - payload_type = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(instance), payload); + payload_type = ast_rtp_codecs_get_payload(ast_rtp_instance_get_codecs(instance), payload); + if (!payload_type) { + return -1; + } /* Otherwise adjust bridged payload to match */ - bridged_payload = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance1), payload_type.asterisk_format, &payload_type.format, payload_type.rtp_code); + bridged_payload = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance1), payload_type->asterisk_format, payload_type->format, payload_type->rtp_code); /* If no codec could be matched between instance and instance1, then somehow things were made incompatible while we were still bridged. Bail. */ if (bridged_payload < 0) { @@ -3880,7 +3890,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc struct ast_sockaddr addr; int res, hdrlen = 12, version, payloadtype, padding, mark, ext, cc, prev_seqno; unsigned int *rtpheader = (unsigned int*)(rtp->rawdata + AST_FRIENDLY_OFFSET), seqno, ssrc, timestamp; - struct ast_rtp_payload_type payload; + RAII_VAR(struct ast_rtp_payload_type *, payload, NULL, ao2_cleanup); struct ast_sockaddr remote_address = { {0,} }; struct frame_list frames; @@ -4120,20 +4130,20 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc payloadtype, seqno, timestamp,res - hdrlen); } - payload = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(instance), payloadtype); + payload = ast_rtp_codecs_get_payload(ast_rtp_instance_get_codecs(instance), payloadtype); /* If the payload is not actually an Asterisk one but a special one pass it off to the respective handler */ - if (!payload.asterisk_format) { + if (!payload->asterisk_format) { struct ast_frame *f = NULL; - if (payload.rtp_code == AST_RTP_DTMF) { + if (payload->rtp_code == AST_RTP_DTMF) { /* process_dtmf_rfc2833 may need to return multiple frames. We do this * by passing the pointer to the frame list to it so that the method * can append frames to the list as needed. */ process_dtmf_rfc2833(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark, &frames); - } else if (payload.rtp_code == AST_RTP_CISCO_DTMF) { + } else if (payload->rtp_code == AST_RTP_CISCO_DTMF) { f = process_dtmf_cisco(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark); - } else if (payload.rtp_code == AST_RTP_CN) { + } else if (payload->rtp_code == AST_RTP_CN) { f = process_cn_rfc3389(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark); } else { ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n", @@ -4153,10 +4163,25 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc return &ast_null_frame; } - ast_format_copy(&rtp->lastrxformat, &payload.format); - ast_format_copy(&rtp->f.subclass.format, &payload.format); - rtp->f.frametype = (AST_FORMAT_GET_TYPE(rtp->f.subclass.format.id) == AST_FORMAT_TYPE_AUDIO) ? AST_FRAME_VOICE : (AST_FORMAT_GET_TYPE(rtp->f.subclass.format.id) == AST_FORMAT_TYPE_VIDEO) ? AST_FRAME_VIDEO : AST_FRAME_TEXT; - + ao2_replace(rtp->lastrxformat, payload->format); + ao2_replace(rtp->f.subclass.format, payload->format); + switch (ast_format_get_type(rtp->f.subclass.format)) { + case AST_MEDIA_TYPE_AUDIO: + rtp->f.frametype = AST_FRAME_VOICE; + break; + case AST_MEDIA_TYPE_VIDEO: + rtp->f.frametype = AST_FRAME_VIDEO; + break; + case AST_MEDIA_TYPE_TEXT: + rtp->f.frametype = AST_FRAME_TEXT; + break; + case AST_MEDIA_TYPE_IMAGE: + /* Fall through */ + default: + ast_log(LOG_WARNING, "Unknown or unsupported media type: %s\n", + ast_codec_media_type2str(ast_format_get_type(rtp->f.subclass.format))); + return &ast_null_frame; + } rtp->rxseqno = seqno; if (rtp->dtmf_timeout && rtp->dtmf_timeout < timestamp) { @@ -4165,7 +4190,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc if (rtp->resp) { struct ast_frame *f; f = create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0); - f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(&f->subclass.format)), ast_tv(0, 0)); + f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.format)), ast_tv(0, 0)); rtp->resp = 0; rtp->dtmf_timeout = rtp->dtmf_duration = 0; AST_LIST_INSERT_TAIL(&frames, f, frame_list); @@ -4182,7 +4207,9 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET; rtp->f.seqno = seqno; - if (rtp->f.subclass.format.id == AST_FORMAT_T140 && (int)seqno - (prev_seqno+1) > 0 && (int)seqno - (prev_seqno+1) < 10) { + if ((ast_format_cmp(rtp->f.subclass.format, ast_format_t140) == AST_FORMAT_CMP_EQUAL) + && ((int)seqno - (prev_seqno + 1) > 0) + && ((int)seqno - (prev_seqno + 1) < 10)) { unsigned char *data = rtp->f.data.ptr; memmove(rtp->f.data.ptr+3, rtp->f.data.ptr, rtp->f.datalen); @@ -4192,7 +4219,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc *data = 0xBD; } - if (rtp->f.subclass.format.id == AST_FORMAT_T140RED) { + if (ast_format_cmp(rtp->f.subclass.format, ast_format_t140_red) == AST_FORMAT_CMP_EQUAL) { unsigned char *data = rtp->f.data.ptr; unsigned char *header_end; int num_generations; @@ -4201,7 +4228,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc int diff =(int)seqno - (prev_seqno+1); /* if diff = 0, no drop*/ int x; - ast_format_set(&rtp->f.subclass.format, AST_FORMAT_T140, 0); + ao2_replace(rtp->f.subclass.format, ast_format_t140); header_end = memchr(data, ((*data) & 0x7f), rtp->f.datalen); if (header_end == NULL) { return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame; @@ -4239,17 +4266,17 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc } } - if (AST_FORMAT_GET_TYPE(rtp->f.subclass.format.id) == AST_FORMAT_TYPE_AUDIO) { - rtp->f.samples = ast_codec_get_samples(&rtp->f); - if (ast_format_is_slinear(&rtp->f.subclass.format)) { + if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_AUDIO) { + rtp->f.samples = ast_codec_samples_count(&rtp->f); + if (ast_format_cache_is_slinear(rtp->f.subclass.format)) { ast_frame_byteswap_be(&rtp->f); } calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark); /* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */ ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO); - rtp->f.ts = timestamp / (rtp_get_rate(&rtp->f.subclass.format) / 1000); - rtp->f.len = rtp->f.samples / ((ast_format_rate(&rtp->f.subclass.format) / 1000)); - } else if (AST_FORMAT_GET_TYPE(rtp->f.subclass.format.id) == AST_FORMAT_TYPE_VIDEO) { + rtp->f.ts = timestamp / (rtp_get_rate(rtp->f.subclass.format) / 1000); + rtp->f.len = rtp->f.samples / ((ast_format_get_sample_rate(rtp->f.subclass.format) / 1000)); + } else if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_VIDEO) { /* Video -- samples is # of samples vs. 90000 */ if (!rtp->lastividtimestamp) rtp->lastividtimestamp = timestamp; @@ -4258,10 +4285,8 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc rtp->f.delivery.tv_sec = 0; rtp->f.delivery.tv_usec = 0; /* Pass the RTP marker bit as bit */ - if (mark) { - ast_format_set_video_mark(&rtp->f.subclass.format); - } - } else { + rtp->f.subclass.frame_ending = mark; + } else if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_TEXT) { /* TEXT -- samples is # of samples vs. 1000 */ if (!rtp->lastitexttimestamp) rtp->lastitexttimestamp = timestamp; @@ -4269,6 +4294,10 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc rtp->lastitexttimestamp = timestamp; rtp->f.delivery.tv_sec = 0; rtp->f.delivery.tv_usec = 0; + } else { + ast_log(LOG_WARNING, "Unknown or unsupported media type: %s\n", + ast_codec_media_type2str(ast_format_get_type(rtp->f.subclass.format))); + return &ast_null_frame;; } AST_LIST_INSERT_TAIL(&frames, &rtp->f, frame_list); @@ -4413,7 +4442,7 @@ static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int } rtp->red->t140.frametype = AST_FRAME_TEXT; - ast_format_set(&rtp->red->t140.subclass.format, AST_FORMAT_T140RED, 0); + ao2_replace(rtp->red->t140.subclass.format, ast_format_t140_red); rtp->red->t140.data.ptr = &rtp->red->buf_data; rtp->red->t140.ts = 0; diff --git a/res/res_rtp_multicast.c b/res/res_rtp_multicast.c index c13e9ad1e..7e8b24214 100644 --- a/res/res_rtp_multicast.c +++ b/res/res_rtp_multicast.c @@ -53,6 +53,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/unaligned.h" #include "asterisk/module.h" #include "asterisk/rtp_engine.h" +#include "asterisk/format_cache.h" /*! Command value used for Linksys paging to indicate we are starting */ #define LINKSYS_MCAST_STARTCMD 6 @@ -144,7 +145,8 @@ static int multicast_rtp_new(struct ast_rtp_instance *instance, struct ast_sched static int rtp_get_rate(struct ast_format *format) { - return (format->id == AST_FORMAT_G722) ? 8000 : ast_format_rate(format); + return ast_format_cmp(format, ast_format_g722) == AST_FORMAT_CMP_EQUAL ? + 8000 : ast_format_get_sample_rate(format); } static unsigned int calc_txstamp(struct multicast_rtp *rtp, struct timeval *delivery) @@ -237,7 +239,7 @@ static int multicast_rtp_write(struct ast_rtp_instance *instance, struct ast_fra int hdrlen = 12, res = 0, codec; unsigned char *rtpheader; unsigned int ms = calc_txstamp(multicast, &frame->delivery); - int rate = rtp_get_rate(&frame->subclass.format) / 1000; + int rate = rtp_get_rate(frame->subclass.format) / 1000; /* We only accept audio, nothing else */ if (frame->frametype != AST_FRAME_VOICE) { @@ -245,7 +247,7 @@ static int multicast_rtp_write(struct ast_rtp_instance *instance, struct ast_fra } /* Grab the actual payload number for when we create the RTP packet */ - if ((codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 1, &frame->subclass.format, 0)) < 0) { + if ((codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 1, frame->subclass.format, 0)) < 0) { return -1; } diff --git a/res/res_speech.c b/res/res_speech.c index 71c283f40..0e4352da4 100644 --- a/res/res_speech.c +++ b/res/res_speech.c @@ -38,7 +38,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$"); #include "asterisk/cli.h" #include "asterisk/term.h" #include "asterisk/speech.h" - +#include "asterisk/format_cache.h" static AST_RWLIST_HEAD_STATIC(engines, ast_speech_engine); static struct ast_speech_engine *default_engine = NULL; @@ -183,26 +183,34 @@ struct ast_speech *ast_speech_new(const char *engine_name, const struct ast_form { struct ast_speech_engine *engine = NULL; struct ast_speech *new_speech = NULL; - struct ast_format_cap *joint = NULL; - struct ast_format best; - - ast_format_set(&best, AST_FORMAT_SLINEAR, 0); + struct ast_format_cap *joint; + RAII_VAR(struct ast_format *, best, NULL, ao2_cleanup); /* Try to find the speech recognition engine that was requested */ if (!(engine = find_engine(engine_name))) return NULL; - /* Before even allocating the memory below do some codec negotiation, we choose the best codec possible and fall back to signed linear if possible */ - if ((joint = ast_format_cap_joint(engine->formats, cap))) { - ast_best_codec(joint, &best); - joint = ast_format_cap_destroy(joint); - } else if (!ast_format_cap_iscompatible(engine->formats, &best)) { + joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!joint) { return NULL; } + ast_format_cap_get_compatible(engine->formats, cap, joint); + best = ast_format_cap_get_format(joint, 0); + ao2_ref(joint, -1); + + if (!best) { + if (ast_format_cap_iscompatible_format(engine->formats, ast_format_slin) != AST_FORMAT_CMP_NOT_EQUAL) { + best = ao2_bump(ast_format_slin); + } else { + return NULL; + } + } + /* Allocate our own speech structure, and try to allocate a structure from the engine too */ - if (!(new_speech = ast_calloc(1, sizeof(*new_speech)))) + if (!(new_speech = ast_calloc(1, sizeof(*new_speech)))) { return NULL; + } /* Initialize the lock */ ast_mutex_init(&new_speech->lock); @@ -214,13 +222,13 @@ struct ast_speech *ast_speech_new(const char *engine_name, const struct ast_form new_speech->engine = engine; /* Can't forget the format audio is going to be in */ - ast_format_copy(&new_speech->format, &best); + new_speech->format = best; /* We are not ready to accept audio yet */ ast_speech_change_state(new_speech, AST_SPEECH_STATE_NOT_READY); /* Pass ourselves to the engine so they can set us up some more and if they error out then do not create a structure */ - if (engine->create(new_speech, &best)) { + if (engine->create(new_speech, best)) { ast_mutex_destroy(&new_speech->lock); ast_free(new_speech); new_speech = NULL; @@ -248,6 +256,8 @@ int ast_speech_destroy(struct ast_speech *speech) if (speech->processing_sound) ast_free(speech->processing_sound); + ao2_ref(speech->format, -1); + /* Aloha we are done */ ast_free(speech); diff --git a/res/res_stasis.c b/res/res_stasis.c index d915914d5..cda0d80eb 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -72,6 +72,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/causes.h" #include "asterisk/stringfields.h" #include "asterisk/bridge_after.h" +#include "asterisk/format_cache.h" /*! Time to wait for a frame in the application */ #define MAX_WAIT_MS 200 @@ -435,15 +436,14 @@ static void moh_after_bridge_cb(struct ast_channel *chan, void *data) /*! Request a bridge MOH channel */ static struct ast_channel *prepare_bridge_moh_channel(void) { - RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy); - struct ast_format format; + RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup); - cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); + cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!cap) { return NULL; } - ast_format_cap_add(cap, ast_format_set(&format, AST_FORMAT_SLINEAR, 0)); + ast_format_cap_append(cap, ast_format_slin, 0); return ast_request("Announcer", cap, NULL, NULL, "ARI_MOH", NULL); } diff --git a/res/res_stasis_snoop.c b/res/res_stasis_snoop.c index e4a309d47..c39c8fae2 100644 --- a/res/res_stasis_snoop.c +++ b/res/res_stasis_snoop.c @@ -40,6 +40,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/timing.h" #include "asterisk/stasis_channels.h" #include "asterisk/json.h" +#include "asterisk/format_cache.h" /*! \brief The interval (in milliseconds) that the Snoop timer is triggered, also controls length of audio within frames */ #define SNOOP_INTERVAL 20 @@ -58,7 +59,7 @@ struct stasis_app_snoop { /*! \brief Number of samples to be read in when spying */ unsigned int spy_samples; /*! \brief Format in use by the spy audiohook */ - struct ast_format spy_format; + struct ast_format *spy_format; /*! \brief Audiohook used to whisper on the channel */ struct ast_audiohook whisper; /*! \brief Direction for whispering */ @@ -179,7 +180,7 @@ static struct ast_frame *snoop_read(struct ast_channel *chan) /* Only get audio from the spy audiohook if it is active */ if (snoop->spy_active) { ast_audiohook_lock(&snoop->spy); - frame = ast_audiohook_read_frame(&snoop->spy, snoop->spy_samples, snoop->spy_direction, &snoop->spy_format); + frame = ast_audiohook_read_frame(&snoop->spy, snoop->spy_samples, snoop->spy_direction, snoop->spy_format); ast_audiohook_unlock(&snoop->spy); } @@ -278,10 +279,10 @@ static int snoop_setup_audiohook(struct ast_channel *chan, enum ast_audiohook_ty static void snoop_determine_format(struct ast_channel *chan, struct stasis_app_snoop *snoop) { SCOPED_CHANNELLOCK(lock, chan); - unsigned int rate = MAX(ast_format_rate(ast_channel_rawwriteformat(chan)), - ast_format_rate(ast_channel_rawreadformat(chan))); + unsigned int rate = MAX(ast_format_get_sample_rate(ast_channel_rawwriteformat(chan)), + ast_format_get_sample_rate(ast_channel_rawreadformat(chan))); - ast_format_set(&snoop->spy_format, ast_format_slin_by_rate(rate), 0); + snoop->spy_format = ast_format_cache_get_slin_by_rate(rate); } struct ast_channel *stasis_app_control_snoop(struct ast_channel *chan, @@ -289,6 +290,7 @@ struct ast_channel *stasis_app_control_snoop(struct ast_channel *chan, const char *app, const char *app_args, const char *snoop_id) { RAII_VAR(struct stasis_app_snoop *, snoop, NULL, ao2_cleanup); + struct ast_format_cap *caps; pthread_t thread; struct ast_assigned_ids assignedids = { .uniqueid = snoop_id, @@ -343,11 +345,18 @@ struct ast_channel *stasis_app_control_snoop(struct ast_channel *chan, ast_channel_set_fd(snoop->chan, 0, ast_timer_fd(snoop->timer)); /* The format on the Snoop channel will be this signed linear format, and it will never change */ - ast_format_cap_set(ast_channel_nativeformats(snoop->chan), &snoop->spy_format); - ast_format_copy(ast_channel_writeformat(snoop->chan), &snoop->spy_format); - ast_format_copy(ast_channel_rawwriteformat(snoop->chan), &snoop->spy_format); - ast_format_copy(ast_channel_readformat(snoop->chan), &snoop->spy_format); - ast_format_copy(ast_channel_rawreadformat(snoop->chan), &snoop->spy_format); + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + return NULL; + } + ast_format_cap_append(caps, snoop->spy_format, 0); + ast_channel_nativeformats_set(snoop->chan, caps); + ao2_ref(caps, -1); + + ast_channel_set_writeformat(snoop->chan, snoop->spy_format); + ast_channel_set_rawwriteformat(snoop->chan, snoop->spy_format); + ast_channel_set_readformat(snoop->chan, snoop->spy_format); + ast_channel_set_rawreadformat(snoop->chan, snoop->spy_format); ast_channel_unlock(snoop->chan); @@ -357,7 +366,7 @@ struct ast_channel *stasis_app_control_snoop(struct ast_channel *chan, return NULL; } - snoop->spy_samples = ast_format_rate(&snoop->spy_format) / (1000 / SNOOP_INTERVAL); + snoop->spy_samples = ast_format_get_sample_rate(snoop->spy_format) / (1000 / SNOOP_INTERVAL); snoop->spy_active = 1; } diff --git a/tests/test_abstract_jb.c b/tests/test_abstract_jb.c index f48307a3a..f0c0315bf 100644 --- a/tests/test_abstract_jb.c +++ b/tests/test_abstract_jb.c @@ -43,6 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/test.h" #include "asterisk/abstract_jb.h" #include "asterisk/frame.h" +#include "asterisk/format_cache.h" #define DEFAULT_FRAME_MS 160 #define DEFAULT_CONFIG_FLAGS 0 @@ -85,7 +86,7 @@ static struct ast_frame *create_test_frame(long timestamp, { struct ast_frame f = {0}; - f.subclass.format.id = AST_FORMAT_SLINEAR; + f.subclass.format = ast_format_slin; f.frametype = AST_FRAME_VOICE; f.src = "TEST"; f.ts = timestamp; diff --git a/tests/test_cel.c b/tests/test_cel.c index ff0aaca24..010f19987 100644 --- a/tests/test_cel.c +++ b/tests/test_cel.c @@ -38,6 +38,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/test.h" #include "asterisk/cel.h" #include "asterisk/channel.h" +#include "asterisk/format_cache.h" #include "asterisk/linkedlists.h" #include "asterisk/chanvars.h" #include "asterisk/utils.h" @@ -1317,7 +1318,10 @@ AST_TEST_DEFINE(test_cel_attended_transfer_bridges_swap) do_sleep(); /* Perform attended transfer */ - ast_bridge_transfer_attended(chan_alice, chan_david); + if (ast_bridge_transfer_attended(chan_alice, chan_david)) { + ast_test_status_update(test, "Attended transfer failed!\n"); + return AST_TEST_FAIL; + } do_sleep(); BRIDGE_ENTER_EVENT_PEER(chan_bob, bridge2, "CELTestChannel/David,CELTestChannel/Charlie"); @@ -1397,7 +1401,10 @@ AST_TEST_DEFINE(test_cel_attended_transfer_bridges_merge) BRIDGE_ENTER(chan_david, bridge2); /* Perform attended transfer */ - ast_bridge_transfer_attended(chan_alice, chan_david); + if (ast_bridge_transfer_attended(chan_alice, chan_david)) { + ast_test_status_update(test, "Attended transfer failed!\n"); + return AST_TEST_FAIL; + } do_sleep(); BRIDGE_EXIT_EVENT_PEER(chan_charlie, bridge2, "CELTestChannel/David"); BRIDGE_ENTER_EVENT_PEER(chan_charlie, bridge1, "CELTestChannel/Bob,CELTestChannel/Alice"); diff --git a/tests/test_config.c b/tests/test_config.c index f9e9a6f48..a8a83b2b0 100644 --- a/tests/test_config.c +++ b/tests/test_config.c @@ -45,6 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$"); #include "asterisk/frame.h" #include "asterisk/utils.h" #include "asterisk/logger.h" +#include "asterisk/format_cap.h" #define CONFIG_FILE "test_config.conf" @@ -627,7 +628,6 @@ struct test_item { struct ast_sockaddr sockaddropt; int boolopt; struct ast_ha *aclopt; - struct ast_codec_pref codecprefopt; struct ast_format_cap *codeccapopt; unsigned int customopt:1; }; @@ -653,9 +653,7 @@ static void test_item_destructor(void *obj) { struct test_item *item = obj; ast_string_field_free_memory(item); - if (item->codeccapopt) { - ast_format_cap_destroy(item->codeccapopt); - } + ao2_cleanup(item->codeccapopt); if (item->aclopt) { ast_free_ha(item->aclopt); } @@ -671,7 +669,7 @@ static void *test_item_alloc(const char *cat) ao2_ref(item, -1); return NULL; } - if (!(item->codeccapopt = ast_format_cap_alloc(0))) { + if (!(item->codeccapopt = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { ao2_ref(item, -1); return NULL; } @@ -821,7 +819,7 @@ AST_TEST_DEFINE(config_options_test) aco_option_register(&cfg_info, "boolflag3", ACO_EXACT, config_test_conf.types, BOOLFLAG3_DEFAULT, OPT_BOOLFLAG_T, 1, FLDSET(struct test_item, flags), BOOLFLAG3); aco_option_register(&cfg_info, "aclpermitopt", ACO_EXACT, config_test_conf.types, ACL_DEFAULT, OPT_ACL_T, 1, FLDSET(struct test_item, aclopt)); aco_option_register(&cfg_info, "acldenyopt", ACO_EXACT, config_test_conf.types, ACL_DEFAULT, OPT_ACL_T, 0, FLDSET(struct test_item, aclopt)); - aco_option_register(&cfg_info, "codecopt", ACO_EXACT, config_test_conf.types, CODEC_DEFAULT, OPT_CODEC_T, 1, FLDSET(struct test_item, codecprefopt, codeccapopt)); + aco_option_register(&cfg_info, "codecopt", ACO_EXACT, config_test_conf.types, CODEC_DEFAULT, OPT_CODEC_T, 1, FLDSET(struct test_item, codeccapopt)); aco_option_register(&cfg_info, "stropt", ACO_EXACT, config_test_conf.types, STR_DEFAULT, OPT_STRINGFIELD_T, 0, STRFLDSET(struct test_item, stropt)); aco_option_register_custom(&cfg_info, "customopt", ACO_EXACT, config_test_conf.types, CUSTOM_DEFAULT, customopt_handler, 0); aco_option_register_deprecated(&cfg_info, "permit", config_test_conf.types, "aclpermitopt"); @@ -855,11 +853,11 @@ AST_TEST_DEFINE(config_options_test) ast_sockaddr_parse(&acl_allow, "1.2.3.4", PARSE_PORT_FORBID); ast_sockaddr_parse(&acl_fail, "1.1.1.1", PARSE_PORT_FORBID); - defaults.codeccapopt = ast_format_cap_alloc(0); - ast_parse_allow_disallow(&defaults.codecprefopt, defaults.codeccapopt, CODEC_DEFAULT, 1); + defaults.codeccapopt = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + ast_format_cap_update_by_allow_disallow(defaults.codeccapopt, CODEC_DEFAULT, 1); - configs.codeccapopt = ast_format_cap_alloc(0); - ast_parse_allow_disallow(&configs.codecprefopt, configs.codeccapopt, CODEC_CONFIG, 1); + configs.codeccapopt = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + ast_format_cap_update_by_allow_disallow(configs.codeccapopt, CODEC_CONFIG, 1); ast_string_field_init(&defaults, 128); ast_string_field_init(&configs, 128); @@ -907,10 +905,13 @@ AST_TEST_DEFINE(config_options_test) res = AST_TEST_FAIL; } if (!ast_format_cap_identical(arr[x]->codeccapopt, control->codeccapopt)) { - char buf1[128], buf2[128]; - ast_getformatname_multiple(buf1, sizeof(buf1), arr[x]->codeccapopt); - ast_getformatname_multiple(buf2, sizeof(buf2), control->codeccapopt); - ast_test_status_update(test, "format did not match: '%s' vs '%s' on loop %d\n", buf1, buf2, x); + struct ast_str *codec_buf1 = ast_str_alloca(64); + struct ast_str *codec_buf2 = ast_str_alloca(64); + + ast_test_status_update(test, "format did not match: '%s' vs '%s' on loop %d\n", + ast_format_cap_get_names(arr[x]->codeccapopt, &codec_buf1), + ast_format_cap_get_names(control->codeccapopt, &codec_buf2), + x); res = AST_TEST_FAIL; } if (strcasecmp(arr[x]->stropt, control->stropt)) { @@ -925,8 +926,10 @@ AST_TEST_DEFINE(config_options_test) } ast_free_ha(configs.aclopt); - ast_format_cap_destroy(defaults.codeccapopt); - ast_format_cap_destroy(configs.codeccapopt); + ao2_cleanup(defaults.codeccapopt); + defaults.codeccapopt = NULL; + ao2_cleanup(configs.codeccapopt); + configs.codeccapopt = NULL; ast_string_field_free_memory(&defaults); ast_string_field_free_memory(&configs); return res; diff --git a/tests/test_core_codec.c b/tests/test_core_codec.c new file mode 100644 index 000000000..499e633df --- /dev/null +++ b/tests/test_core_codec.c @@ -0,0 +1,369 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Joshua Colp <jcolp@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Core Codec API Unit Tests + * + * \author Joshua Colp <jcolp@digium.com> + * + */ + +/*** MODULEINFO + <depend>TEST_FRAMEWORK</depend> + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/test.h" +#include "asterisk/module.h" +#include "asterisk/codec.h" + +static struct ast_codec known_unknown = { + .name = "unit_test", + .description = "Unit test codec", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 150, + .default_ms = 20, +}; + +static struct ast_codec doubly = { + .name = "unit_test_double", + .description = "Unit test codec", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 150, + .default_ms = 20, +}; + +static struct ast_codec unknown = { + .name = "unit_test_unknown", + .description = "Unit test codec", + .type = AST_MEDIA_TYPE_UNKNOWN, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 150, + .default_ms = 20, +}; + +static struct ast_codec audio_without_rate = { + .name = "unit_test_audio_without_rate", + .description = "Unit test codec", + .type = AST_MEDIA_TYPE_AUDIO, + .minimum_ms = 10, + .maximum_ms = 150, + .default_ms = 20, +}; + +static struct ast_codec audio_get = { + .name = "unit_test_audio_get", + .description = "Unit test codec", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 150, + .default_ms = 20, +}; + +static struct ast_codec audio_get_unknown = { + .name = "unit_test_audio_get_unknown", + .description = "Unit test codec", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 150, + .default_ms = 20, +}; + +static struct ast_codec audio_get_id = { + .name = "unit_test_audio_get_id", + .description = "Unit test codec", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 150, + .default_ms = 20, +}; + +AST_TEST_DEFINE(codec_register) +{ + switch (cmd) { + case TEST_INIT: + info->name = "codec_register"; + info->category = "/main/core_codec/"; + info->summary = "codec registration unit test"; + info->description = + "Test registration of a core codec that is known to be unknown"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + if (ast_codec_register(&known_unknown)) { + ast_test_status_update(test, "Unsuccessfully registered a codec that is known to be unknown\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(codec_register_twice) +{ + switch (cmd) { + case TEST_INIT: + info->name = "codec_register_twice"; + info->category = "/main/core_codec/"; + info->summary = "codec registration unit test"; + info->description = + "Test double registration of a core codec to confirm it fails"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + if (ast_codec_register(&doubly)) { + ast_test_status_update(test, "Unsuccessfully registered a codec that is known to be unknown\n"); + return AST_TEST_FAIL; + } + + if (!ast_codec_register(&doubly)) { + ast_test_status_update(test, "Successfully registered a codec twice\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(codec_register_unknown) +{ + switch (cmd) { + case TEST_INIT: + info->name = "codec_register_unknown"; + info->category = "/main/core_codec/"; + info->summary = "codec registration unit test"; + info->description = + "Test that registration of an unknown codec type fails"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + if (!ast_codec_register(&unknown)) { + ast_test_status_update(test, "Successfully registered a codec with an unknown media type\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(codec_register_audio_no_sample_rate) +{ + switch (cmd) { + case TEST_INIT: + info->name = "codec_register_audio_no_sample_rate"; + info->category = "/main/core_codec/"; + info->summary = "codec registration unit test"; + info->description = + "Test that registration of an audio codec without sample rate fails"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + if (!ast_codec_register(&audio_without_rate)) { + ast_test_status_update(test, "Successfully registered an audio codec without a sample rate\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(codec_get) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "codec_get"; + info->category = "/main/core_codec/"; + info->summary = "codec get unit test"; + info->description = + "Test that getting of a known codec succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + if (ast_codec_register(&audio_get)) { + ast_test_status_update(test, "Unsucessfully registered a codec for getting\n"); + return AST_TEST_FAIL; + } + + codec = ast_codec_get("unit_test_audio_get", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Unsuccessfully retrieved a codec we just registered\n"); + return AST_TEST_FAIL; + } else if (strcmp(codec->name, audio_get.name)) { + ast_test_status_update(test, "Name of retrieved codec does not match registered codec\n"); + return AST_TEST_FAIL; + } else if (codec->type != audio_get.type) { + ast_test_status_update(test, "Type of retrieved codec does not match registered codec\n"); + return AST_TEST_FAIL; + } else if (codec->sample_rate != audio_get.sample_rate) { + ast_test_status_update(test, "Sample rate of retrieved codec does not match registered codec\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(codec_get_unregistered) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "codec_get_unregistered"; + info->category = "/main/core_codec/"; + info->summary = "codec get unit test"; + info->description = + "Test that getting of a codec that is not registered fails"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("goats", AST_MEDIA_TYPE_AUDIO, 8000); + if (codec) { + ast_test_status_update(test, "Successfully got a codec named '%s' when getting a codec named 'goats'\n", + codec->name); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(codec_get_unknown) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "codec_get_unknown"; + info->category = "/main/core_codec/"; + info->summary = "codec get unit test"; + info->description = + "Test that getting of a known codec using name and unknown type succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + if (ast_codec_register(&audio_get_unknown)) { + ast_test_status_update(test, "Unsucessfully registered a codec for getting\n"); + return AST_TEST_FAIL; + } + + codec = ast_codec_get("unit_test_audio_get_unknown", AST_MEDIA_TYPE_UNKNOWN, 8000); + if (!codec) { + ast_test_status_update(test, "Unsuccessfully retrieved a codec we just registered\n"); + return AST_TEST_FAIL; + } else if (strcmp(codec->name, audio_get_unknown.name)) { + ast_test_status_update(test, "Name of retrieved codec does not match registered codec\n"); + return AST_TEST_FAIL; + } else if (codec->type != audio_get_unknown.type) { + ast_test_status_update(test, "Type of retrieved codec does not match registered codec\n"); + return AST_TEST_FAIL; + } else if (codec->sample_rate != audio_get_unknown.sample_rate) { + ast_test_status_update(test, "Sample rate of retrieved codec does not match registered codec\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(codec_get_id) +{ + RAII_VAR(struct ast_codec *, named, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "codec_get_unknown"; + info->category = "/main/core_codec/"; + info->summary = "codec get unit test"; + info->description = + "Test that getting of a known codec using name and unknown type succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + if (ast_codec_register(&audio_get_id)) { + ast_test_status_update(test, "Unsucessfully registered a codec for getting\n"); + return AST_TEST_FAIL; + } + + named = ast_codec_get("unit_test_audio_get_id", AST_MEDIA_TYPE_AUDIO, 8000); + if (!named) { + ast_test_status_update(test, "Unsuccessfully retrieved a codec we just registered\n"); + return AST_TEST_FAIL; + } + + codec = ast_codec_get_by_id(named->id); + if (!codec) { + ast_test_status_update(test, "Unsuccessfully retrieved a codec using id of a named codec we just got\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(codec_register); + AST_TEST_UNREGISTER(codec_register_twice); + AST_TEST_UNREGISTER(codec_register_unknown); + AST_TEST_UNREGISTER(codec_register_audio_no_sample_rate); + AST_TEST_UNREGISTER(codec_get); + AST_TEST_UNREGISTER(codec_get_unregistered); + AST_TEST_UNREGISTER(codec_get_unknown); + AST_TEST_UNREGISTER(codec_get_id); + return 0; +} + +static int load_module(void) +{ + AST_TEST_REGISTER(codec_register); + AST_TEST_REGISTER(codec_register_twice); + AST_TEST_REGISTER(codec_register_unknown); + AST_TEST_REGISTER(codec_register_audio_no_sample_rate); + AST_TEST_REGISTER(codec_get); + AST_TEST_REGISTER(codec_get_unregistered); + AST_TEST_REGISTER(codec_get_unknown); + AST_TEST_REGISTER(codec_get_id); + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Core codec API test module"); diff --git a/tests/test_core_format.c b/tests/test_core_format.c new file mode 100644 index 000000000..2ae944bb3 --- /dev/null +++ b/tests/test_core_format.c @@ -0,0 +1,975 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Joshua Colp <jcolp@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Core Format API Unit Tests + * + * \author Joshua Colp <jcolp@digium.com> + * + */ + +/*** MODULEINFO + <depend>TEST_FRAMEWORK</depend> + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/test.h" +#include "asterisk/module.h" +#include "asterisk/codec.h" +#include "asterisk/format.h" + +#define TEST_CATEGORY "/main/core_format/" + +static void test_core_format_destroy(struct ast_format *format); +static int test_core_format_clone(const struct ast_format *src, struct ast_format *dst); +static enum ast_format_cmp_res test_core_format_cmp(const struct ast_format *format1, const struct ast_format *format2); +static struct ast_format *test_core_format_get_joint(const struct ast_format *format1, const struct ast_format *format2); +static struct ast_format *test_core_format_attribute_set(const struct ast_format *format, const char *name, const char *value); +static struct ast_format *test_core_format_parse_sdp_fmtp(const struct ast_format *format, const char *attributes); +static void test_core_format_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str); + +/*! \brief A format attribute 'module' used by the unit tests */ +static struct ast_format_interface test_core_format_attr = { + .format_destroy = &test_core_format_destroy, + .format_clone = &test_core_format_clone, + .format_cmp = &test_core_format_cmp, + .format_get_joint = &test_core_format_get_joint, + .format_attribute_set = &test_core_format_attribute_set, + .format_parse_sdp_fmtp = &test_core_format_parse_sdp_fmtp, + .format_generate_sdp_fmtp = &test_core_format_generate_sdp_fmtp, +}; + +/*! \brief A test piece of data to associate with \ref test_core_format_attr */ +struct test_core_format_pvt { + /*! Some data field */ + int field_one; + /*! Another arbitrary data field */ + int field_two; +}; + +/*! \brief A test codec for these unit tests. Should be used with \c test_core_format */ +static struct ast_codec test_core_format_codec = { + .name = "test_core_format_codec", + .description = "Unit test codec used by test_core_format", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 150, + .default_ms = 20, +}; + +/*! \brief Tracking object used to verify format attribute callbacks */ +struct callbacks_called { + /*! Number of times \ref test_core_format_destroy was called */ + int format_destroy; + /*! Number of times \ref test_core_format_clone was called */ + int format_clone; + /*! Number of times \ref test_core_format_cmp was called */ + int format_cmp; + /*! Number of times \ref test_core_format_get_joint was called */ + int format_get_joint; + /*! Number of times \ref test_core_format_attribute_set was called */ + int format_attribute_set; + /*! Number of times \ref test_core_format_parse_sdp_fmtp was called */ + int format_parse_sdp_fmtp; + /*! Number of times \ref test_core_format_generate_sdp_fmtp was called */ + int format_generate_sdp_fmtp; +}; + +/*! \brief A global tracking object. Cleared out by the test init cb */ +static struct callbacks_called test_callbacks_called; + +/*! \brief Format attribute callback for when format attributes are to be destroyed */ +static void test_core_format_destroy(struct ast_format *format) +{ + struct test_core_format_pvt *pvt = ast_format_get_attribute_data(format); + + ast_free(pvt); + ++test_callbacks_called.format_destroy; +} + +/*! \brief Format attribute callback called during format cloning */ +static int test_core_format_clone(const struct ast_format *src, struct ast_format *dst) +{ + struct test_core_format_pvt *pvt = ast_format_get_attribute_data(src); + struct test_core_format_pvt *new_pvt; + + new_pvt = ast_calloc(1, sizeof(*new_pvt)); + if (!new_pvt) { + return -1; + } + + if (pvt) { + *new_pvt = *pvt; + } + ast_format_set_attribute_data(dst, new_pvt); + + ++test_callbacks_called.format_clone; + + return 0; +} + +/*! \brief Format attribute callback called during format comparison */ +static enum ast_format_cmp_res test_core_format_cmp(const struct ast_format *format1, const struct ast_format *format2) +{ + struct test_core_format_pvt *pvt1 = ast_format_get_attribute_data(format1); + struct test_core_format_pvt *pvt2 = ast_format_get_attribute_data(format2); + + ++test_callbacks_called.format_cmp; + if (pvt1 == pvt2) { + return AST_FORMAT_CMP_EQUAL; + } + + if ((!pvt1 && pvt2 && (pvt2->field_one != 0 || pvt2->field_two != 0)) + || (pvt1 && !pvt2 && (pvt1->field_one != 0 || pvt1->field_two != 0))) { + return AST_FORMAT_CMP_NOT_EQUAL; + } + + if (pvt1 && pvt2) { + if (!memcmp(pvt1, pvt2, sizeof(*pvt1))) { + return AST_FORMAT_CMP_EQUAL; + } else { + return AST_FORMAT_CMP_NOT_EQUAL; + } + } + + return AST_FORMAT_CMP_EQUAL; +} + +/*! + * \brief Format attribute callback called during joint format capability + * \note Our test will assume the max of attributes \c field_one and \c field_two + */ +static struct ast_format *test_core_format_get_joint(const struct ast_format *format1, const struct ast_format *format2) +{ + struct test_core_format_pvt *pvt1 = ast_format_get_attribute_data(format1); + struct test_core_format_pvt *pvt2 = ast_format_get_attribute_data(format2); + struct ast_format *joint; + struct test_core_format_pvt *joint_pvt; + + joint = ast_format_clone(format1); + if (!joint) { + return NULL; + } + joint_pvt = ast_format_get_attribute_data(joint); + + joint_pvt->field_one = MAX(pvt1 ? pvt1->field_one : 0, pvt2 ? pvt2->field_one : 0); + joint_pvt->field_two = MAX(pvt2 ? pvt2->field_two : 0, pvt2 ? pvt2->field_two : 0); + + ++test_callbacks_called.format_get_joint; + + return joint; +} + +/*! \brief Format attribute callback for setting an attribute on a format */ +static struct ast_format *test_core_format_attribute_set(const struct ast_format *format, const char *name, const char *value) +{ + struct ast_format *clone = ast_format_clone(format); + struct test_core_format_pvt *clone_pvt; + + if (!clone) { + return NULL; + } + clone_pvt = ast_format_get_attribute_data(clone); + + if (!strcmp(name, "one")) { + clone_pvt->field_one = atoi(value); + } else if (!strcmp(name, "two")) { + clone_pvt->field_two = atoi(value); + } + ++test_callbacks_called.format_attribute_set; + + return clone; +} + +/*! \brief Format attribute callback to construct a format from an SDP fmtp line */ +static struct ast_format *test_core_format_parse_sdp_fmtp(const struct ast_format *format, const char *attributes) +{ + struct ast_format *clone = ast_format_clone(format); + struct test_core_format_pvt *pvt; + + if (!clone) { + return NULL; + } + + pvt = ast_format_get_attribute_data(clone); + + if (sscanf(attributes, "one=%d;two=%d", &pvt->field_one, &pvt->field_two) != 2) { + ao2_ref(clone, -1); + return NULL; + } + + ++test_callbacks_called.format_parse_sdp_fmtp; + return clone; +} + +/*! \brief Format attribute callback to generate an SDP fmtp line from a format */ +static void test_core_format_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str) +{ + struct test_core_format_pvt *pvt = ast_format_get_attribute_data(format); + + if (!pvt) { + return; + } + + ast_str_append(str, 0, "a=fmtp:%d one=%d;two=%d\r\n", payload, pvt->field_one, pvt->field_two); + + ++test_callbacks_called.format_generate_sdp_fmtp; +} + +AST_TEST_DEFINE(format_create) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = TEST_CATEGORY; + info->summary = "Format creation unit test"; + info->description = + "Test creation of a format"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + format = ast_format_create(codec); + if (!format) { + ast_test_status_update(test, "Could not create format using built-in codec\n"); + return AST_TEST_FAIL; + } else if (ast_format_get_codec_id(format) != codec->id) { + ast_test_status_update(test, "Created format does not contain provided codec\n"); + return AST_TEST_FAIL; + } + + ao2_ref(format, -1); + format = ast_format_create_named("super_ulaw", codec); + if (!format) { + ast_test_status_update(test, "Could not create format using built-in codec\n"); + return AST_TEST_FAIL; + } else if (ast_format_get_codec_id(format) != codec->id) { + ast_test_status_update(test, "Created format does not contain provided codec\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_create_attr) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format_w_attr, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = TEST_CATEGORY; + info->summary = "Format creation w/ attributes unit test"; + info->description = + "Test creation of a format with attributes"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("test_core_format_codec", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve test_core_format_codec codec\n"); + return AST_TEST_FAIL; + } + + format = ast_format_create(codec); + if (!format) { + ast_test_status_update(test, "Could not create format using test_core_format_codec codec\n"); + return AST_TEST_FAIL; + } else if (ast_format_get_codec_id(format) != codec->id) { + ast_test_status_update(test, "Created format does not contain provided codec\n"); + return AST_TEST_FAIL; + } + + format_w_attr = ast_format_attribute_set(format, "one", "1"); + if (!format_w_attr) { + ast_test_status_update(test, "Could not create format with attributes using test_core_format_codec codec\n"); + return AST_TEST_FAIL; + } else if (ast_format_get_codec_id(format_w_attr) != codec->id) { + ast_test_status_update(test, "Created format does not contain provided codec\n"); + return AST_TEST_FAIL; + } else if (ast_format_cmp(format, format_w_attr) == AST_FORMAT_CMP_EQUAL) { + ast_test_status_update(test, "Format with attributes should not be equal to format without attributes\n"); + return AST_TEST_FAIL; + } + + ast_test_validate(test, test_callbacks_called.format_attribute_set == 1); + ast_test_validate(test, test_callbacks_called.format_cmp == 1); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_clone) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format_w_attr, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, clone, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = TEST_CATEGORY; + info->summary = "Format cloning unit test"; + info->description = + "Test cloning of a format"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("test_core_format_codec", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve test_core_format_codec codec\n"); + return AST_TEST_FAIL; + } + + format = ast_format_create(codec); + if (!format) { + ast_test_status_update(test, "Could not create format using test_core_format_codec codec\n"); + return AST_TEST_FAIL; + } else if (ast_format_get_codec_id(format) != codec->id) { + ast_test_status_update(test, "Created format does not contain provided codec\n"); + return AST_TEST_FAIL; + } + + format_w_attr = ast_format_attribute_set(format, "one", "1"); + if (!format_w_attr) { + ast_test_status_update(test, "Could not create format with attributes using test_core_format_codec codec\n"); + return AST_TEST_FAIL; + } else if (ast_format_get_codec_id(format_w_attr) != codec->id) { + ast_test_status_update(test, "Created format does not contain provided codec\n"); + return AST_TEST_FAIL; + } + + /* Test cloning a format without attributes */ + clone = ast_format_clone(format); + if (!clone) { + ast_test_status_update(test, "Could not create cloned format\n"); + return AST_TEST_FAIL; + } else if (ast_format_get_codec_id(clone) != codec->id) { + ast_test_status_update(test, "Cloned format does not contain provided codec\n"); + return AST_TEST_FAIL; + } else if (clone == format) { + ast_test_status_update(test, "Cloned format pointer is the same as original format pointer\n"); + return AST_TEST_FAIL; + } else if (ast_format_cmp(clone, format) != AST_FORMAT_CMP_EQUAL) { + ast_test_status_update(test, "Cloned format is not the same as its original format\n"); + return AST_TEST_FAIL; + } + ao2_ref(clone, -1); + + /* Test cloning a format with attributes */ + clone = ast_format_clone(format_w_attr); + if (!clone) { + ast_test_status_update(test, "Could not create cloned format\n"); + return AST_TEST_FAIL; + } else if (ast_format_get_codec_id(clone) != codec->id) { + ast_test_status_update(test, "Cloned format does not contain provided codec\n"); + return AST_TEST_FAIL; + } else if (clone == format_w_attr) { + ast_test_status_update(test, "Cloned format pointer is the same as original format pointer\n"); + return AST_TEST_FAIL; + } else if (ast_format_cmp(clone, format_w_attr) != AST_FORMAT_CMP_EQUAL) { + ast_test_status_update(test, "Cloned format is not the same as its original format\n"); + return AST_TEST_FAIL; + } + ast_test_validate(test, test_callbacks_called.format_attribute_set == 1); + ast_test_validate(test, test_callbacks_called.format_clone == 3); + ast_test_validate(test, test_callbacks_called.format_cmp == 2); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cmp_same_codec) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, named, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = TEST_CATEGORY; + info->summary = "Format comparison unit test"; + info->description = + "Test comparison of two different formats with same codec"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + first = ast_format_create(codec); + if (!first) { + ast_test_status_update(test, "Could not create first format using built-in codec\n"); + return AST_TEST_FAIL; + } + + second = ast_format_create(codec); + if (!second) { + ast_test_status_update(test, "Could not create second format using built-in codec\n"); + return AST_TEST_FAIL; + } + + named = ast_format_create_named("super_ulaw", codec); + if (!named) { + ast_test_status_update(test, "Could not create named format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cmp(first, second) != AST_FORMAT_CMP_EQUAL) { + ast_test_status_update(test, "Two formats that are the same compared as not being equal\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cmp(first, named) != AST_FORMAT_CMP_EQUAL) { + ast_test_status_update(test, "Two formats that are the same compared as not being equal\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cmp_different_codec) +{ + RAII_VAR(struct ast_codec *, first_codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, second_codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = TEST_CATEGORY; + info->summary = "Format comparison unit test"; + info->description = + "Test comparison of two different formats with different codec"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + first_codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!first_codec) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + first = ast_format_create(first_codec); + if (!first) { + ast_test_status_update(test, "Could not create first format using built-in codec\n"); + return AST_TEST_FAIL; + } + + second_codec = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!second_codec) { + ast_test_status_update(test, "Could not retrieve built-in alaw codec\n"); + return AST_TEST_FAIL; + } + + second = ast_format_create(second_codec); + if (!second) { + ast_test_status_update(test, "Could not create second format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cmp(first, second) != AST_FORMAT_CMP_NOT_EQUAL) { + ast_test_status_update(test, "Two formats that have different codecs did not compare as being not equal\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_attr_cmp_same_codec) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, original, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = TEST_CATEGORY; + info->summary = "Format with attributes comparison unit test"; + info->description = + "Test comparison of two different formats with attributes with same codec"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("test_core_format_codec", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve test_core_format_codec codec\n"); + return AST_TEST_FAIL; + } + + original = ast_format_create(codec); + if (!original) { + ast_test_status_update(test, "Could not create format using test_core_format_codec codec\n"); + return AST_TEST_FAIL; + } + + first = ast_format_attribute_set(original, "one", "1"); + if (!first) { + ast_test_status_update(test, "Could not create first format with attributes\n"); + return AST_TEST_FAIL; + } + + second = ast_format_attribute_set(original, "two", "1"); + if (!second) { + ast_test_status_update(test, "Could not create second format with attributes\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cmp(first, second) == AST_FORMAT_CMP_EQUAL) { + ast_test_status_update(test, "Formats with different attributes were compared to be equal when they should not\n"); + return AST_TEST_FAIL; + } + + ao2_ref(second, -1); + second = ast_format_attribute_set(original, "one", "1"); + + if (ast_format_cmp(first, second) != AST_FORMAT_CMP_EQUAL) { + ast_test_status_update(test, "Formats with the same attributes should be equal\n"); + return AST_TEST_FAIL; + } + + ast_test_validate(test, test_callbacks_called.format_attribute_set == 3); + ast_test_validate(test, test_callbacks_called.format_cmp == 2); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_joint_same_codec) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, joint, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = TEST_CATEGORY; + info->summary = "Joint format unit test"; + info->description = + "Test joint format creation using two different formats with same codec"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + first = ast_format_create(codec); + if (!first) { + ast_test_status_update(test, "Could not create first format using built-in codec\n"); + return AST_TEST_FAIL; + } + + second = ast_format_create(codec); + if (!second) { + ast_test_status_update(test, "Could not create second format using built-in codec\n"); + return AST_TEST_FAIL; + } + + joint = ast_format_joint(first, second); + if (!joint) { + ast_test_status_update(test, "Failed to create a joint format using two formats of same codec\n"); + return AST_TEST_FAIL; + } else if (ast_format_get_codec_id(joint) != codec->id) { + ast_test_status_update(test, "Returned joint format does not contain expected codec\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_attr_joint_same_codec) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, original, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, joint, NULL, ao2_cleanup); + struct ast_str *fmtp = ast_str_alloca(64); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = TEST_CATEGORY; + info->summary = "Joint format attribute unit test"; + info->description = + "Test joint format creation using two different formats with attributes and with same codec"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("test_core_format_codec", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve test_core_format_codec codec\n"); + return AST_TEST_FAIL; + } + + original = ast_format_create(codec); + if (!original) { + ast_test_status_update(test, "Could not create format from test_core_format_codec codec\n"); + return AST_TEST_FAIL; + } + + first = ast_format_attribute_set(original, "one", "2"); + if (!first) { + ast_test_status_update(test, "Could not create first format using test_core_format_codec codec\n"); + return AST_TEST_FAIL; + } + + second = ast_format_attribute_set(original, "one", "5"); + if (!second) { + ast_test_status_update(test, "Could not create second format using test_core_format_codec codec\n"); + return AST_TEST_FAIL; + } + + joint = ast_format_joint(first, second); + if (!joint) { + ast_test_status_update(test, "Failed to create a joint format using two formats of same codec\n"); + return AST_TEST_FAIL; + } else if (ast_format_get_codec_id(joint) != codec->id) { + ast_test_status_update(test, "Returned joint format does not contain expected codec\n"); + return AST_TEST_FAIL; + } + + ast_format_generate_sdp_fmtp(joint, 100, &fmtp); + ast_test_validate(test, strcmp("a=fmtp:100 one=5;two=0\r\n", ast_str_buffer(fmtp)) == 0); + + ast_test_validate(test, test_callbacks_called.format_attribute_set == 2); + ast_test_validate(test, test_callbacks_called.format_get_joint == 1); + ast_test_validate(test, test_callbacks_called.format_generate_sdp_fmtp == 1); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_joint_different_codec) +{ + RAII_VAR(struct ast_codec *, first_codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, second_codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, joint, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = TEST_CATEGORY; + info->summary = "Joint format unit test"; + info->description = + "Test that there is no joint format between two different formats with different codec"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + first_codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!first_codec) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + first = ast_format_create(first_codec); + if (!first) { + ast_test_status_update(test, "Could not create first format using built-in codec\n"); + return AST_TEST_FAIL; + } + + second_codec = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!second_codec) { + ast_test_status_update(test, "Could not retrieve built-in alaw codec\n"); + return AST_TEST_FAIL; + } + + second = ast_format_create(second_codec); + if (!second) { + ast_test_status_update(test, "Could not create second format using built-in codec\n"); + return AST_TEST_FAIL; + } + + joint = ast_format_joint(first, second); + if (joint) { + ast_test_status_update(test, "Got a joint format between two formats with different codecs\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_copy) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, copy, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = TEST_CATEGORY; + info->summary = "Format copying unit test"; + info->description = + "Test copying of a format"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + format = ast_format_create(codec); + if (!format) { + ast_test_status_update(test, "Could not create format using built-in codec\n"); + return AST_TEST_FAIL; + } + + copy = ao2_bump(format); + if (!copy) { + ast_test_status_update(test, "Copying of a just created format failed\n"); + return AST_TEST_FAIL; + } else if (copy != format) { + ast_test_status_update(test, "Copying of a format returned a new format instead of the same one\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_attribute_set_without_interface) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = TEST_CATEGORY; + info->summary = "Format attribute setting unit test"; + info->description = + "Test that attribute setting on a format without an interface fails"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + format = ast_format_create(codec); + if (!format) { + ast_test_status_update(test, "Could not create format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (!ast_format_attribute_set(format, "bees", "cool")) { + ast_test_status_update(test, "Successfully set an attribute on a format without an interface\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_parse_sdp_fmtp_without_interface) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, generated, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = TEST_CATEGORY; + info->summary = "Format sdp parse unit test"; + info->description = + "Test that sdp parsing on a format without an interface fails"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + format = ast_format_create(codec); + if (!format) { + ast_test_status_update(test, "Could not create format using built-in codec\n"); + return AST_TEST_FAIL; + } + + generated = ast_format_parse_sdp_fmtp(format, "tacos"); + if (generated != format) { + ast_test_status_update(test, "Successfully parsed SDP on a format without an interface\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_parse_and_generate_sdp_fmtp) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, generated, NULL, ao2_cleanup); + struct ast_str *fmtp = ast_str_alloca(64); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = TEST_CATEGORY; + info->summary = "Format sdp parse/generate unit test"; + info->description = + "Test that sdp parsing and generation on a format with an interface succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("test_core_format_codec", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve test_core_format_codec codec\n"); + return AST_TEST_FAIL; + } + + format = ast_format_create(codec); + if (!format) { + ast_test_status_update(test, "Could not create format using test_core_format_codec codec\n"); + return AST_TEST_FAIL; + } + + generated = ast_format_parse_sdp_fmtp(format, "one=1000;two=256"); + if (format == generated) { + ast_test_status_update(test, "Failed to parse SDP on a format without an interface\n"); + return AST_TEST_FAIL; + } + + ast_format_generate_sdp_fmtp(generated, 8, &fmtp); + + ast_test_validate(test, strcmp("a=fmtp:8 one=1000;two=256\r\n", ast_str_buffer(fmtp)) == 0); + ast_test_validate(test, test_callbacks_called.format_parse_sdp_fmtp == 1); + ast_test_validate(test, test_callbacks_called.format_generate_sdp_fmtp == 1); + + return AST_TEST_PASS; +} + +static int test_core_format_init(struct ast_test_info *info, struct ast_test *test) +{ + memset(&test_callbacks_called, 0, sizeof(test_callbacks_called)); + + return 0; +} + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(format_create); + AST_TEST_UNREGISTER(format_create_attr); + AST_TEST_UNREGISTER(format_clone); + AST_TEST_UNREGISTER(format_cmp_same_codec); + AST_TEST_UNREGISTER(format_attr_cmp_same_codec); + AST_TEST_UNREGISTER(format_cmp_different_codec); + AST_TEST_UNREGISTER(format_joint_same_codec); + AST_TEST_UNREGISTER(format_attr_joint_same_codec); + AST_TEST_UNREGISTER(format_joint_different_codec); + AST_TEST_UNREGISTER(format_copy); + AST_TEST_UNREGISTER(format_attribute_set_without_interface); + AST_TEST_UNREGISTER(format_parse_sdp_fmtp_without_interface); + AST_TEST_UNREGISTER(format_parse_and_generate_sdp_fmtp); + + return 0; +} + +static int load_module(void) +{ + /* Test codec/format interface used by this module */ + if (ast_codec_register(&test_core_format_codec)) { + ast_log(AST_LOG_ERROR, "Failed to register test_core_format_codec\n"); + return AST_MODULE_LOAD_DECLINE; + } + + if (ast_format_interface_register("test_core_format_codec", &test_core_format_attr)) { + ast_log(AST_LOG_ERROR, "Failed to register format interface for test_core_format_codec\n"); + return AST_MODULE_LOAD_DECLINE; + } + + AST_TEST_REGISTER(format_create); + AST_TEST_REGISTER(format_create_attr); + AST_TEST_REGISTER(format_clone); + AST_TEST_REGISTER(format_cmp_same_codec); + AST_TEST_REGISTER(format_attr_cmp_same_codec); + AST_TEST_REGISTER(format_cmp_different_codec); + AST_TEST_REGISTER(format_joint_same_codec); + AST_TEST_REGISTER(format_attr_joint_same_codec); + AST_TEST_REGISTER(format_joint_different_codec); + AST_TEST_REGISTER(format_copy); + AST_TEST_REGISTER(format_attribute_set_without_interface); + AST_TEST_REGISTER(format_parse_sdp_fmtp_without_interface); + AST_TEST_REGISTER(format_parse_and_generate_sdp_fmtp); + + ast_test_register_init(TEST_CATEGORY, &test_core_format_init); + + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Core format API test module"); diff --git a/tests/test_format_api.c b/tests/test_format_api.c deleted file mode 100644 index 6cc349570..000000000 --- a/tests/test_format_api.c +++ /dev/null @@ -1,859 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2010, Digium, Inc. - * - * David Vossel <dvossel@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! - * \file - * \brief Tests for the ast_event API - * - * \author David Vossel <dvossel@digium.com> - * - * \ingroup tests - * - */ - -/*** MODULEINFO - <depend>TEST_FRAMEWORK</depend> - <support_level>core</support_level> - ***/ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/module.h" -#include "asterisk/test.h" -#include "asterisk/format.h" -#include "asterisk/format_cap.h" -#include "asterisk/strings.h" - -/*! These are the keys for accessing attributes */ -enum test_attr_keys { - TEST_ATTR_KEY_SAMP_RATE, - TEST_ATTR_KEY_STRING, -}; - -/*! These are the values for the TEST_ATTR_KEY_SAMP_RATE key */ -enum test_attr_vals_samp { - TEST_ATTR_VAL_SAMP_8KHZ = (1 << 0), - TEST_ATTR_VAL_SAMP_12KHZ = (1 << 1), - TEST_ATTR_VAL_SAMP_16KHZ = (1 << 2), - TEST_ATTR_VAL_SAMP_32KHZ = (1 << 3), - TEST_ATTR_VAL_SAMP_48KHZ = (1 << 4), -}; - -/*! This is the attribute structure used for our test interface. */ -struct test_attr { - enum test_attr_vals_samp samp_flags; - char string[32]; -}; - -static enum ast_format_cmp_res test_cmp(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2) -{ - struct test_attr *attr1 = (struct test_attr *) fattr1; - struct test_attr *attr2 = (struct test_attr *) fattr2; - - if ((attr1->samp_flags == attr2->samp_flags) && - !(strcmp(attr1->string, attr2->string))) { - return AST_FORMAT_CMP_EQUAL; - } - if ((attr1->samp_flags != (attr1->samp_flags & attr2->samp_flags)) || - (!ast_strlen_zero(attr1->string) && strcmp(attr1->string, attr2->string))) { - return AST_FORMAT_CMP_NOT_EQUAL; - } - return AST_FORMAT_CMP_SUBSET; -} - -static int test_getjoint(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result) -{ - struct test_attr *attr1 = (struct test_attr *) fattr1; - struct test_attr *attr2 = (struct test_attr *) fattr2; - struct test_attr *attr_res = (struct test_attr *) result; - int joint = -1; - - attr_res->samp_flags = (attr1->samp_flags & attr2->samp_flags); - - if (attr_res->samp_flags) { - joint = 0; - } - - if (!strcmp(attr1->string, attr2->string)) { - ast_copy_string(attr_res->string, attr1->string, sizeof(attr_res->string)); - joint = 0; - } - - return joint; -} - -static void test_set(struct ast_format_attr *fattr, va_list ap) -{ - enum test_attr_keys key; - struct test_attr *attr = (struct test_attr *) fattr; - char *string; - - for (key = va_arg(ap, int); - key != AST_FORMAT_ATTR_END; - key = va_arg(ap, int)) - { - switch (key) { - case TEST_ATTR_KEY_SAMP_RATE: - attr->samp_flags = (va_arg(ap, int) | attr->samp_flags); - break; - case TEST_ATTR_KEY_STRING: - string = va_arg(ap, char *); - if (!ast_strlen_zero(string)) { - ast_copy_string(attr->string, string, sizeof(attr->string)); - } - break; - default: - ast_log(LOG_WARNING, "unknown attribute type %d\n", key); - } - } -} - -/*! uLaw does not actually have any attributes associated with it. - * This is just for the purpose of testing. We are guaranteed there - * will never exist a interface for uLaw already. */ -static struct ast_format_attr_interface test_interface = { - .id = AST_FORMAT_TESTLAW, - .format_attr_cmp = test_cmp, - .format_attr_get_joint = test_getjoint, - .format_attr_set = test_set -}; - -/*! - * \internal - */ -AST_TEST_DEFINE(format_test1) -{ - struct ast_format format1 = { 0, }; - struct ast_format format2 = { 0, }; - struct ast_format joint = { 0, }; - - switch (cmd) { - case TEST_INIT: - info->name = "ast_format_test1"; - info->category = "/main/format/"; - info->summary = "Test ast_format with attributes."; - info->description = - "This test exercises the Ast Format API by creating and registering " - "a custom ast_format_attr_interface and performing various function " - "calls on ast_formats using the interface. "; - return AST_TEST_NOT_RUN; - case TEST_EXECUTE: - break; - } - - if (ast_format_attr_reg_interface(&test_interface)) { - ast_test_status_update(test, "test_interface failed to register.\n"); - return AST_TEST_FAIL; - } - - /* set a format with a single attribute. */ - ast_format_set(&format1, AST_FORMAT_TESTLAW, 1, - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, - AST_FORMAT_ATTR_END); - if (ast_format_isset(&format1, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, AST_FORMAT_ATTR_END)) { - ast_test_status_update(test, "format1 did not set number attribute correctly.\n"); - return AST_TEST_FAIL; - } - if (!ast_format_isset(&format1, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_12KHZ, AST_FORMAT_ATTR_END)) { - ast_test_status_update(test, "format1 did not determine isset on number correctly. \n"); - return AST_TEST_FAIL; - } - - /* append the string attribute to a format with previous attributes already set */ - ast_format_append(&format1, - TEST_ATTR_KEY_STRING,"String", - AST_FORMAT_ATTR_END); - if (ast_format_isset(&format1, TEST_ATTR_KEY_STRING, "String", AST_FORMAT_ATTR_END)) { - ast_test_status_update(test, "format1 did not set string attribute correctly.\n"); - return AST_TEST_FAIL; - } - if (!ast_format_isset(&format1, TEST_ATTR_KEY_STRING, "Not a string", AST_FORMAT_ATTR_END)) { - ast_test_status_update(test, "format1 did not determine isset on string correctly. \n"); - return AST_TEST_FAIL; - } - - /* set format2 with both STRING and NUMBER at the same time */ - ast_format_set(&format2, AST_FORMAT_TESTLAW, 1, - TEST_ATTR_KEY_STRING, "MOOOoo", - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ, - AST_FORMAT_ATTR_END); - /* perform isset with multiple key value pairs. */ - - if (ast_format_isset(&format2, - TEST_ATTR_KEY_STRING, "MOOOoo", - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ, - AST_FORMAT_ATTR_END)) { - - ast_test_status_update(test, "format2 did not set attributes correctly.\n"); - return AST_TEST_FAIL; - } - if (!ast_format_isset(&format2, - TEST_ATTR_KEY_STRING, "WRONG", - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ, - AST_FORMAT_ATTR_END)) { - - ast_test_status_update(test, "format2 did not deterine isset correctly.\n"); - return AST_TEST_FAIL; - } - - /* get joint attributes between format1 and format2. */ - if (ast_format_joint(&format1, &format2, &joint)) { - ast_test_status_update(test, "failed to get joint attributes.\n"); - return AST_TEST_FAIL; - } - if (ast_format_isset(&joint, TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, AST_FORMAT_ATTR_END)) { - ast_test_status_update(test, "joint attribute was not what we expected.\n"); - return AST_TEST_FAIL; - } - - /* exercise compare functions */ - if (ast_format_cmp(&format1, &format2) != AST_FORMAT_CMP_NOT_EQUAL) { - ast_test_status_update(test, "cmp 1 failed.\n"); - return AST_TEST_FAIL; - } - if (ast_format_cmp(&format1, &format1) != AST_FORMAT_CMP_EQUAL) { - ast_test_status_update(test, "cmp 2 failed.\n"); - return AST_TEST_FAIL; - } - if (ast_format_cmp(&joint, &format1) != AST_FORMAT_CMP_SUBSET) { - ast_test_status_update(test, "cmp 3 failed.\n"); - return AST_TEST_FAIL; - } - - /* unregister interface */ - if (ast_format_attr_unreg_interface(&test_interface)) { - ast_test_status_update(test, "test_interface failed to unregister.\n"); - return AST_TEST_FAIL; - } - - return AST_TEST_PASS; -} - -/*! - * \internal - */ -AST_TEST_DEFINE(format_test2) -{ - struct ast_format format = { 0, }; - - switch (cmd) { - case TEST_INIT: - info->name = "ast_format_test2"; - info->category = "/main/format/"; - info->summary = "Test ast_format unique id and category system"; - info->description = - "This test exercises the Ast Format unique id and category " - "system by creating formats of various types and verifying " - "their category matches what we expect."; - return AST_TEST_NOT_RUN; - case TEST_EXECUTE: - break; - } - - ast_format_set(&format, AST_FORMAT_ULAW, 0); - if (AST_FORMAT_GET_TYPE(format.id) != AST_FORMAT_TYPE_AUDIO) { - ast_test_status_update(test, "audio type failed\n"); - return AST_TEST_FAIL; - } - - ast_format_set(&format, AST_FORMAT_H264, 0); - if (AST_FORMAT_GET_TYPE(format.id) != AST_FORMAT_TYPE_VIDEO) { - ast_test_status_update(test, "video type failed\n"); - return AST_TEST_FAIL; - } - - ast_format_set(&format, AST_FORMAT_JPEG, 0); - if (AST_FORMAT_GET_TYPE(format.id) != AST_FORMAT_TYPE_IMAGE) { - ast_test_status_update(test, "image type failed\n"); - return AST_TEST_FAIL; - } - - ast_format_set(&format, AST_FORMAT_T140, 0); - if (AST_FORMAT_GET_TYPE(format.id) != AST_FORMAT_TYPE_TEXT) { - ast_test_status_update(test, "text type failed\n"); - return AST_TEST_FAIL; - } - - return AST_TEST_PASS; -} - -static int container_test1_helper(struct ast_format_cap *cap1, struct ast_format_cap *cap2, struct ast_test *test) -{ - - int res = AST_TEST_PASS; - struct ast_format_cap *cap_joint = NULL; - struct ast_format tmpformat; - - if (ast_format_attr_reg_interface(&test_interface)) { - ast_test_status_update(test, "test_interface failed to register.\n"); - ast_format_cap_destroy(cap1); - ast_format_cap_destroy(cap2); - return AST_TEST_FAIL; - } - - ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)); - ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)); - ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_G722, 0)); - ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_ALAW, 0)); - ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_H264, 0)); - ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_H263, 0)); - ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_T140, 0)); - ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_JPEG, 0)); - ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1, - TEST_ATTR_KEY_STRING, "testing caps hooray", - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ, - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_32KHZ, - AST_FORMAT_ATTR_END)); - - /* Test is compatible */ - if (!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_ALAW, 0)) || - !ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)) || - !ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)) || - !ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_H264, 0)) || - !ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_JPEG, 0)) || - !ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_T140, 0))) { - ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 1.\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - - /* Test things that are not compatible */ - if (ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_SPEEX, 0)) || - ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_SPEEX16, 0)) || - ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_H261, 0))) { - ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 2.\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - - /* Test compatiblity with format with attributes. */ - if (!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1, - TEST_ATTR_KEY_STRING, "testing caps hooray", - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ, - AST_FORMAT_ATTR_END))) { - - ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 3.\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - if (!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1, - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, - AST_FORMAT_ATTR_END))) { - - ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 4.\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - if (ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1, - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_48KHZ, /* 48khz was not compatible, so this should fail iscompatible check */ - AST_FORMAT_ATTR_END))) { - - ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 5.\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - - /* Lets start testing the functions that compare ast_format_cap objects. - * Genreate the cap2 object to contain some similar formats as cap1 - * and some different formats as well. */ - ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)); - ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)); - ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_SIREN7, 0)); - ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_H261, 0)); - ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_T140, 0)); - ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1, - TEST_ATTR_KEY_STRING, "testing caps hooray", - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_12KHZ, - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ, - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_32KHZ, - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_48KHZ, - AST_FORMAT_ATTR_END)); - - - /* find joint formats between cap1 and cap2 */ - cap_joint = ast_format_cap_joint(cap1, cap2); - - if (!cap_joint) { - ast_test_status_update(test, "failed to create joint capabilities correctly.\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - /* determine if cap_joint is what we think it should be */ - if (!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)) || - !ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)) || - !ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_T140, 0)) || - !ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1, - TEST_ATTR_KEY_STRING, "testing caps hooray", - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ, - AST_FORMAT_ATTR_END))) { - - ast_test_status_update(test, "ast cap_joint failed to properly detect compatibility test 1.\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - /* make sure joint cap does not have formats that should not be there */ - if (ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_SIREN7, 0)) || - ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1, - TEST_ATTR_KEY_STRING, "testing caps hooray", - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ, - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ, - TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_48KHZ, - AST_FORMAT_ATTR_END))) { - - ast_test_status_update(test, "ast cap_joint failed to properly detect compatibility test 1.\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - - /* Lets test removing a capability */ - if (ast_format_cap_remove(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_T140, 0))) { - ast_test_status_update(test, "ast_format_cap_remove failed. \n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - /* Lets make sure what we just removed does not still exist */ - if (ast_format_cap_iscompatible(cap_joint, &tmpformat)) { - ast_test_status_update(test, "ast_format_cap_remove failed 2. \n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - /* Lets test removing a capability by id.*/ - if (ast_format_cap_remove_byid(cap_joint, AST_FORMAT_GSM)) { - ast_test_status_update(test, "ast_format_cap_remove failed 3. \n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - /* Lets make sure what we just removed does not still exist */ - if (ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0))) { - ast_test_status_update(test, "ast_format_cap_remove failed 4. \n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - - /* lets test getting joint formats by type */ - ast_format_cap_destroy(cap_joint); - if (!(cap_joint = ast_format_cap_get_type(cap1, AST_FORMAT_TYPE_VIDEO))) { - ast_test_status_update(test, "ast_format_cap_get_type failed.\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - /* lets make sure our joint capability structure has what we expect */ - if (!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_H264, 0)) || - !ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_H263, 0))) { - ast_test_status_update(test, "get_type failed 2.\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - /* now make sure joint does not have anything but video */ - if (ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_ALAW, 0)) || - ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)) || - ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)) || - ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_JPEG, 0)) || - ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_T140, 0))) { - ast_test_status_update(test, "get_type failed 3.\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - - /* now lets remove everythign from cap_joint */ - ast_format_cap_remove_all(cap_joint); - if (!ast_format_cap_is_empty(cap_joint)) { - ast_test_status_update(test, "failed to remove all\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - - /* now lets add all by type */ - ast_format_cap_add_all_by_type(cap_joint, AST_FORMAT_TYPE_AUDIO); - if (ast_format_cap_is_empty(cap_joint)) { - ast_test_status_update(test, "failed to add all by type AUDIO\n"); - res = AST_TEST_FAIL; - } - ast_format_cap_iter_start(cap_joint); - while (!(ast_format_cap_iter_next(cap_joint, &tmpformat))) { - if (AST_FORMAT_GET_TYPE(tmpformat.id) != AST_FORMAT_TYPE_AUDIO) { - ast_test_status_update(test, "failed to add all by type AUDIO\n"); - res = AST_TEST_FAIL; - ast_format_cap_iter_end(cap_joint); - goto test3_cleanup; - } - } - ast_format_cap_iter_end(cap_joint); - - /* test append */ - ast_format_cap_append(cap_joint, cap1); - ast_format_cap_iter_start(cap1); - while (!(ast_format_cap_iter_next(cap1, &tmpformat))) { - if (!ast_format_cap_iscompatible(cap_joint, &tmpformat)) { - ast_test_status_update(test, "failed to append format capabilities.\n"); - res = AST_TEST_FAIL; - ast_format_cap_iter_end(cap1); - goto test3_cleanup; - } - } - ast_format_cap_iter_end(cap1); - - /* test copy */ - cap1 = ast_format_cap_destroy(cap1); - cap1 = ast_format_cap_dup(cap_joint); - if (!ast_format_cap_identical(cap_joint, cap1)) { - ast_test_status_update(test, "failed to copy capabilities\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - - /* test remove by type */ - ast_format_cap_remove_bytype(cap_joint, AST_FORMAT_TYPE_AUDIO); - if (ast_format_cap_has_type(cap_joint, AST_FORMAT_TYPE_AUDIO)) { - ast_test_status_update(test, "failed to remove all by type audio\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - if (!ast_format_cap_has_type(cap_joint, AST_FORMAT_TYPE_TEXT)) { /* it should still have text */ - ast_test_status_update(test, "failed to remove all by type audio\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - ast_format_cap_iter_start(cap_joint); - while (!(ast_format_cap_iter_next(cap_joint, &tmpformat))) { - if (AST_FORMAT_GET_TYPE(tmpformat.id) == AST_FORMAT_TYPE_AUDIO) { - ast_test_status_update(test, "failed to remove all by type audio\n"); - res = AST_TEST_FAIL; - ast_format_cap_iter_end(cap_joint); - goto test3_cleanup; - } - } - ast_format_cap_iter_end(cap_joint); - - /* test add all */ - ast_format_cap_remove_all(cap_joint); - ast_format_cap_add_all(cap_joint); - { - int video = 0, audio = 0, text = 0, image = 0; - ast_format_cap_iter_start(cap_joint); - while (!(ast_format_cap_iter_next(cap_joint, &tmpformat))) { - switch (AST_FORMAT_GET_TYPE(tmpformat.id)) { - case AST_FORMAT_TYPE_AUDIO: - audio++; - break; - case AST_FORMAT_TYPE_VIDEO: - video++; - break; - case AST_FORMAT_TYPE_TEXT: - text++; - break; - case AST_FORMAT_TYPE_IMAGE: - image++; - break; - } - } - ast_format_cap_iter_end(cap_joint); - if (!video || !audio || !text || !image) { - ast_test_status_update(test, "failed to add all\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - } - - /* test copy2 */ - ast_format_cap_copy(cap2, cap_joint); - if (!ast_format_cap_identical(cap2, cap_joint)) { - ast_test_status_update(test, "ast_format_cap_copy failed\n"); - res = AST_TEST_FAIL; - goto test3_cleanup; - } - -test3_cleanup: - ast_format_cap_destroy(cap1); - ast_format_cap_destroy(cap2); - ast_format_cap_destroy(cap_joint); - - /* unregister interface */ - if (ast_format_attr_unreg_interface(&test_interface)) { - ast_test_status_update(test, "test_interface failed to unregister.\n"); - res = AST_TEST_FAIL; - } - - return res; -} - -/*! - * \internal - */ -AST_TEST_DEFINE(container_test1_nolock) -{ - struct ast_format_cap *cap1; - struct ast_format_cap *cap2; - - switch (cmd) { - case TEST_INIT: - info->name = "container_test_1_no_locking"; - info->category = "/main/format/"; - info->summary = "Test ast_format and ast_format_cap structures, no locking"; - info->description = - "This test exercises the Ast Format Capability API by creating " - "capability structures and performing various API calls on them."; - return AST_TEST_NOT_RUN; - case TEST_EXECUTE: - break; - } - - cap1 = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - cap2 = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - - if (!cap1 || !cap2) { - ast_test_status_update(test, "cap alloc failed.\n"); - return AST_TEST_FAIL; - } - return container_test1_helper(cap1, cap2, test); -} - - -/*! - * \internal - */ -AST_TEST_DEFINE(container_test1_withlock) -{ - struct ast_format_cap *cap1; - struct ast_format_cap *cap2; - - switch (cmd) { - case TEST_INIT: - info->name = "container_test1_with_locking"; - info->category = "/main/format/"; - info->summary = "Test ast_format and ast_format_cap structures, with locking"; - info->description = - "This test exercises the Ast Format Capability API by creating " - "capability structures and performing various API calls on them."; - return AST_TEST_NOT_RUN; - case TEST_EXECUTE: - break; - } - - cap1 = ast_format_cap_alloc(0); - cap2 = ast_format_cap_alloc(0); - - if (!cap1 || !cap2) { - ast_test_status_update(test, "cap alloc failed.\n"); - return AST_TEST_FAIL; - } - return container_test1_helper(cap1, cap2, test); -} - -static int container_test2_no_locking_helper(struct ast_format_cap *cap, struct ast_test *test) -{ - int num = 0; - struct ast_format tmpformat = { 0, }; - - ast_format_cap_add(cap, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)); - ast_format_cap_add(cap, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)); - ast_format_cap_add(cap, ast_format_set(&tmpformat, AST_FORMAT_G722, 0)); - - ast_format_cap_iter_start(cap); - while (!ast_format_cap_iter_next(cap, &tmpformat)) { - num++; - } - ast_format_cap_iter_end(cap); - - ast_format_cap_iter_start(cap); - while (!ast_format_cap_iter_next(cap, &tmpformat)) { - num++; - } - ast_format_cap_iter_end(cap); - - ast_format_cap_destroy(cap); - ast_test_status_update(test, "%d items iterated over\n", num); - return (num == 6) ? AST_TEST_PASS : AST_TEST_FAIL; - -} - -/*! - * \internal - */ -AST_TEST_DEFINE(container_test2_no_locking) -{ - struct ast_format_cap *cap; - - switch (cmd) { - case TEST_INIT: - info->name = "container_test2_no_locking"; - info->category = "/main/format/"; - info->summary = "Test ast_format_cap iterator, no locking"; - info->description = - "This test exercises the Ast Capability API iterators."; - return AST_TEST_NOT_RUN; - case TEST_EXECUTE: - break; - } - - cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - if (!cap) { - ast_test_status_update(test, "alloc failed\n"); - return AST_TEST_FAIL; - } - return container_test2_no_locking_helper(cap, test); -} - -/*! - * \internal - */ -AST_TEST_DEFINE(container_test2_with_locking) -{ - struct ast_format_cap *cap; - - switch (cmd) { - case TEST_INIT: - info->name = "container_test2_with_locking"; - info->category = "/main/format/"; - info->summary = "Test ast_format_cap iterator, with locking"; - info->description = - "This test exercises the Ast Capability API iterators."; - return AST_TEST_NOT_RUN; - case TEST_EXECUTE: - break; - } - - cap = ast_format_cap_alloc(0); - if (!cap) { - ast_test_status_update(test, "alloc failed\n"); - return AST_TEST_FAIL; - } - return container_test2_no_locking_helper(cap, test); -} - - -static int container_test3_helper(int nolocking, struct ast_test *test) -{ - int x; - int res = AST_TEST_PASS; - struct ast_format_cap *cap1; - struct ast_format_cap *cap2; - struct ast_format_cap *joint; - - for (x = 0; x < 2000; x++) { - if (nolocking) { - cap1 = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - cap2 = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK); - } else { - cap1 = ast_format_cap_alloc(0); - cap2 = ast_format_cap_alloc(0); - joint = ast_format_cap_alloc(0); - } - if (!cap1 || !cap2 || !joint) { - ast_test_status_update(test, "cap alloc fail\n"); - return AST_TEST_FAIL; - } - ast_format_cap_add_all(cap1); - ast_format_cap_add_all_by_type(cap2, AST_FORMAT_TYPE_AUDIO); - ast_format_cap_joint_copy(cap1, cap2, joint); - if (!(ast_format_cap_identical(cap2, joint))) { - ast_test_status_update(test, "failed identical test\n"); - res = AST_TEST_FAIL; - cap1 = ast_format_cap_destroy(cap1); - cap2 = ast_format_cap_destroy(cap2); - joint = ast_format_cap_destroy(joint); - break; - } - cap1 = ast_format_cap_destroy(cap1); - cap2 = ast_format_cap_destroy(cap2); - joint = ast_format_cap_destroy(joint); - } - return res; -} - -/*! - * \internal - */ -AST_TEST_DEFINE(container_test3_nolock) -{ - switch (cmd) { - case TEST_INIT: - info->name = "container_test3_no_locking"; - info->category = "/main/format/"; - info->summary = "Load Test ast_format_cap no locking."; - info->description = - "This test exercises the Ast Capability API and its iterators for the purpose " - "of measuring performance."; - return AST_TEST_NOT_RUN; - case TEST_EXECUTE: - break; - } - - return container_test3_helper(1, test); -} - -/*! - * \internal - */ -AST_TEST_DEFINE(container_test3_withlock) -{ - switch (cmd) { - case TEST_INIT: - info->name = "container_test3_with_locking"; - info->category = "/main/format/"; - info->summary = "Load Test ast_format_cap with locking."; - info->description = - "This test exercises the Ast Capability API and its iterators for the purpose " - "of measuring performance."; - return AST_TEST_NOT_RUN; - case TEST_EXECUTE: - break; - } - - return container_test3_helper(0, test); -} - -static int unload_module(void) -{ - AST_TEST_UNREGISTER(format_test1); - AST_TEST_UNREGISTER(format_test2); - AST_TEST_UNREGISTER(container_test1_nolock); - AST_TEST_UNREGISTER(container_test1_withlock); - AST_TEST_UNREGISTER(container_test2_no_locking); - AST_TEST_UNREGISTER(container_test2_with_locking); - AST_TEST_UNREGISTER(container_test3_nolock); - AST_TEST_UNREGISTER(container_test3_withlock); - - return 0; -} - -static int load_module(void) -{ - AST_TEST_REGISTER(format_test1); - AST_TEST_REGISTER(format_test2); - AST_TEST_REGISTER(container_test1_nolock); - AST_TEST_REGISTER(container_test1_withlock); - AST_TEST_REGISTER(container_test2_no_locking); - AST_TEST_REGISTER(container_test2_with_locking); - AST_TEST_REGISTER(container_test3_nolock); - AST_TEST_REGISTER(container_test3_withlock); - - return AST_MODULE_LOAD_SUCCESS; -} - -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ast_format API Tests"); diff --git a/tests/test_format_cache.c b/tests/test_format_cache.c new file mode 100644 index 000000000..cc1696b70 --- /dev/null +++ b/tests/test_format_cache.c @@ -0,0 +1,281 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Joshua Colp <jcolp@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Format Cache API Unit Tests + * + * \author Joshua Colp <jcolp@digium.com> + * + */ + +/*** MODULEINFO + <depend>TEST_FRAMEWORK</depend> + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/test.h" +#include "asterisk/module.h" +#include "asterisk/codec.h" +#include "asterisk/format.h" +#include "asterisk/format_cache.h" + +AST_TEST_DEFINE(format_cache_set) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "format_cache_set"; + info->category = "/main/format_cache/"; + info->summary = "format cache add unit test"; + info->description = + "Test that adding of a cached format succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + format = ast_format_create_named("ulaw@20_1", codec); + if (!format) { + ast_test_status_update(test, "Could not create format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cache_set(format)) { + ast_test_status_update(test, "Could not add just created format to cache\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cache_set_duplicate) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "format_cache_set_duplicate"; + info->category = "/main/format_cache/"; + info->summary = "format cache add unit test"; + info->description = + "Test that adding of a cached format multiple times succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + format = ast_format_create_named("ulaw@20_2", codec); + if (!format) { + ast_test_status_update(test, "Could not create format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cache_set(format)) { + ast_test_status_update(test, "Could not add just created format to cache\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cache_set(format)) { + ast_test_status_update(test, "Failed to update cached format\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cache_set_null) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "format_cache_set_null"; + info->category = "/main/format_cache/"; + info->summary = "format cache add unit test"; + info->description = + "Test that adding a NULL or empty format to the cache does not succeed"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + format = ast_format_create_named("", codec); + if (!format) { + ast_test_status_update(test, "Could not create format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (!ast_format_cache_set(format)) { + ast_test_status_update(test, "Successfully cached a format with an empty name\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cache_get) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, cached, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "format_cache_get"; + info->category = "/main/format_cache/"; + info->summary = "format cache get unit test"; + info->description = + "Test that getting of a cached format succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + format = ast_format_create_named("ulaw@20", codec); + if (!format) { + ast_test_status_update(test, "Could not create format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cache_set(format)) { + ast_test_status_update(test, "Could not add just created format to cache\n"); + return AST_TEST_FAIL; + } + + cached = ast_format_cache_get("ulaw@20"); + if (!cached) { + ast_test_status_update(test, "Failed to retrieve a format we just cached\n"); + return AST_TEST_FAIL; + } else if (cached != format) { + ast_test_status_update(test, "Returned cached format does not match format we just added\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cache_get_nonexistent) +{ + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, cached, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "format_cache_get_nonxistent"; + info->category = "/main/format_cache/"; + info->summary = "format cache get unit test"; + info->description = + "Test that getting of a non-existent cached format does not succeed"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + format = ast_format_create_named("ulaw@40", codec); + if (!format) { + ast_test_status_update(test, "Could not create format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cache_set(format)) { + ast_test_status_update(test, "Could not add just created format to cache\n"); + return AST_TEST_FAIL; + } + + cached = ast_format_cache_get("ulaw@60"); + if (cached) { + ast_test_status_update(test, "Retrieved a cached format when one should not have existed\n"); + return AST_TEST_FAIL; + } + + cached = ast_format_cache_get(""); + if (cached) { + ast_test_status_update(test, "Retrieved a cached format when we provided an empty name\n"); + return AST_TEST_FAIL; + } + + cached = ast_format_cache_get(NULL); + if (cached) { + ast_test_status_update(test, "Retrieved a cached format when we provided a NULL name\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(format_cache_set); + AST_TEST_UNREGISTER(format_cache_set_duplicate); + AST_TEST_UNREGISTER(format_cache_set_null); + AST_TEST_UNREGISTER(format_cache_get); + AST_TEST_UNREGISTER(format_cache_get_nonexistent); + return 0; +} + +static int load_module(void) +{ + AST_TEST_REGISTER(format_cache_set); + AST_TEST_REGISTER(format_cache_set_duplicate); + AST_TEST_REGISTER(format_cache_set_null); + AST_TEST_REGISTER(format_cache_get); + AST_TEST_REGISTER(format_cache_get_nonexistent); + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Format cache API test module"); diff --git a/tests/test_format_cap.c b/tests/test_format_cap.c new file mode 100644 index 000000000..38320e635 --- /dev/null +++ b/tests/test_format_cap.c @@ -0,0 +1,1479 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Joshua Colp <jcolp@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Format Capabilities API Unit Tests + * + * \author Joshua Colp <jcolp@digium.com> + * + */ + +/*** MODULEINFO + <depend>TEST_FRAMEWORK</depend> + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/test.h" +#include "asterisk/module.h" +#include "asterisk/codec.h" +#include "asterisk/frame.h" +#include "asterisk/format.h" +#include "asterisk/format_cap.h" + +AST_TEST_DEFINE(format_cap_alloc) +{ + struct ast_format_cap *caps; + + switch (cmd) { + case TEST_INIT: + info->name = "format_cap_alloc"; + info->category = "/main/format_cap/"; + info->summary = "format capabilities allocation unit test"; + info->description = + "Test that allocation of a format capabilities structure succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + ao2_ref(caps, -1); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_append_single) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, retrieved, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = "/main/format_cap/"; + info->summary = "format capabilities adding unit test"; + info->description = + "Test that adding a single format to a format capabilities structure succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + format = ast_format_create(codec); + if (!format) { + ast_test_status_update(test, "Could not create format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, format, 42)) { + ast_test_status_update(test, "Could not add newly created format to capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_count(caps) != 1) { + ast_test_status_update(test, "Number of formats in capabilities structure should be 1 but is %zu\n", + ast_format_cap_count(caps)); + return AST_TEST_FAIL; + } + + retrieved = ast_format_cap_get_format(caps, 0); + if (!retrieved) { + ast_test_status_update(test, "Attempted to get single format from capabilities structure but got nothing\n"); + return AST_TEST_FAIL; + } else if (retrieved != format) { + ast_test_status_update(test, "Retrieved format is not the same as the one we added\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_get_format_framing(caps, retrieved) != 42) { + ast_test_status_update(test, "Framing for format in capabilities structure does not match what we provided\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_append_multiple) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, retrieved, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = "/main/format_cap/"; + info->summary = "format capabilities adding unit test"; + info->description = + "Test that adding multiple formats to a format capabilities structure succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!ulaw) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + ulaw_format = ast_format_create(ulaw); + if (!ulaw_format) { + ast_test_status_update(test, "Could not create ulaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!alaw) { + ast_test_status_update(test, "Could not retrieve built-in alaw codec\n"); + return AST_TEST_FAIL; + } + + alaw_format = ast_format_create(alaw); + if (!alaw_format) { + ast_test_status_update(test, "Could not create alaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ulaw_format, 42)) { + ast_test_status_update(test, "Could not add newly created ulaw format to capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append(caps, alaw_format, 84)) { + ast_test_status_update(test, "Could not add newly created alaw format to capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_count(caps) != 2) { + ast_test_status_update(test, "Number of formats in capabilities structure should be 2 but is %zu\n", + ast_format_cap_count(caps)); + return AST_TEST_FAIL; + } + + retrieved = ast_format_cap_get_format(caps, 0); + if (!retrieved) { + ast_test_status_update(test, "Attempted to get first format from capabilities structure but got nothing\n"); + return AST_TEST_FAIL; + } else if (retrieved != ulaw_format) { + ast_test_status_update(test, "First retrieved format is not the ulaw one we added\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_get_format_framing(caps, retrieved) != 42) { + ast_test_status_update(test, "Framing for ulaw format in capabilities structure does not match what we provided\n"); + } + ao2_ref(retrieved, -1); + + retrieved = ast_format_cap_get_format(caps, 1); + if (!retrieved) { + ast_test_status_update(test, "Attempted to get second format from capabilities structure but got nothing\n"); + return AST_TEST_FAIL; + } else if (retrieved != alaw_format) { + ast_test_status_update(test, "First retrieved format is not the alaw one we added\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_get_format_framing(caps, retrieved) != 84) { + ast_test_status_update(test, "Framing for alaw format in capabilities structure does not match what we provided\n"); + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_append_all_unknown) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = "/main/format_cap/"; + info->summary = "format capabilities adding unit test"; + info->description = + "Test that adding of all formats to a format capabilities structure succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append_by_type(caps, AST_MEDIA_TYPE_UNKNOWN)) { + ast_test_status_update(test, "Failed to add all media formats of all types to capabilities structure\n"); + return AST_TEST_FAIL; + } else if (!ast_format_cap_has_type(caps, AST_MEDIA_TYPE_AUDIO)) { + ast_test_status_update(test, "Added all media formats but no audio formats exist when they should\n"); + return AST_TEST_FAIL; + } else if (!ast_format_cap_has_type(caps, AST_MEDIA_TYPE_VIDEO)) { + ast_test_status_update(test, "Added all media formats but no video formats exist when they should\n"); + return AST_TEST_FAIL; + } else if ((ast_format_cap_count(caps) + 1) != ast_codec_get_max()) { + ast_test_status_update(test, "The number of formats in the capabilities structure does not match known number\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_append_all_audio) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = "/main/format_cap/"; + info->summary = "format capabilities adding unit test"; + info->description = + "Test that adding of all audio formats to a format capabilities structure succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append_by_type(caps, AST_MEDIA_TYPE_AUDIO)) { + ast_test_status_update(test, "Failed to add all audio media formats to capabilities structure\n"); + return AST_TEST_FAIL; + } else if (!ast_format_cap_has_type(caps, AST_MEDIA_TYPE_AUDIO)) { + ast_test_status_update(test, "Added audio media formats but no audio formats exist when they should\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_has_type(caps, AST_MEDIA_TYPE_VIDEO)) { + ast_test_status_update(test, "Added only audio media formats but video formats exist when they should not\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_has_type(caps, AST_MEDIA_TYPE_TEXT)) { + ast_test_status_update(test, "Added only audio media formats but text formats exist when they should not\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_has_type(caps, AST_MEDIA_TYPE_IMAGE)) { + ast_test_status_update(test, "Added only audio media formats but image formats exist when they should not\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_append_duplicate) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format_named, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, retrieved, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = "/main/format_cap/"; + info->summary = "format capabilities duplication unit test"; + info->description = + "Test that adding a single format multiple times to a capabilities structure results in only a single format"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + format = ast_format_create(codec); + if (!format) { + ast_test_status_update(test, "Could not create format using built-in codec\n"); + return AST_TEST_FAIL; + } + + format_named = ast_format_create_named("ulaw@20", codec); + if (!format_named) { + ast_test_status_update(test, "Could not create named format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, format, 42)) { + ast_test_status_update(test, "Could not add newly created format to capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_count(caps) != 1) { + ast_test_status_update(test, "Number of formats in capabilities structure should be 1 but is %zu\n", + ast_format_cap_count(caps)); + return AST_TEST_FAIL; + } + + /* Note: regardless of it being a duplicate, ast_format_cap_append should return success */ + if (ast_format_cap_append(caps, format, 0)) { + ast_test_status_update(test, "Adding of duplicate format to capabilities structure failed\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_count(caps) != 1) { + ast_test_status_update(test, "Number of formats in capabilities structure should be 1 but is %zu\n", + ast_format_cap_count(caps)); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, format_named, 0)) { + ast_test_status_update(test, "Adding of duplicate named format to capabilities structure failed\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_count(caps) != 1) { + ast_test_status_update(test, "Number of formats in capabilities structure should be 1 but is %zu\n", + ast_format_cap_count(caps)); + return AST_TEST_FAIL; + } + + retrieved = ast_format_cap_get_format(caps, 0); + if (!retrieved) { + ast_test_status_update(test, "Attempted to get single format from capabilities structure but got nothing\n"); + return AST_TEST_FAIL; + } else if (retrieved != format) { + ast_test_status_update(test, "Retrieved format is not the same as the one we added\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_get_format_framing(caps, retrieved) != 42) { + ast_test_status_update(test, "Framing for format in capabilities structure does not match what we provided\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_append_from_cap) +{ + RAII_VAR(struct ast_format_cap *, dst_caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_format_cap *, src_caps, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = "/main/format_cap/"; + info->summary = "format capabilities append unit test"; + info->description = + "Test that appending video formats from one capabilities structure to another succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + dst_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!dst_caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append_by_type(dst_caps, AST_MEDIA_TYPE_AUDIO)) { + ast_test_status_update(test, "Failed to add all audio media formats to capabilities structure\n"); + return AST_TEST_FAIL; + } + + src_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!src_caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append_by_type(src_caps, AST_MEDIA_TYPE_VIDEO)) { + ast_test_status_update(test, "Failed to add all video media formats to capabilities structure\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append_from_cap(dst_caps, src_caps, AST_MEDIA_TYPE_UNKNOWN)) { + ast_test_status_update(test, "Failed to append formats to capabilities structure\n"); + return AST_TEST_FAIL; + } else if (!ast_format_cap_has_type(dst_caps, AST_MEDIA_TYPE_AUDIO)) { + ast_test_status_update(test, "Successfully appended video formats to destination capabilities but it no longer contains audio formats\n"); + return AST_TEST_FAIL; + } else if (!ast_format_cap_has_type(dst_caps, AST_MEDIA_TYPE_VIDEO)) { + ast_test_status_update(test, "Successfully appended formats but video formats do not exist in destination capabilities\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_append_from_cap_duplicate) +{ + RAII_VAR(struct ast_format_cap *, dst_caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_format_cap *, src_caps, NULL, ao2_cleanup); + unsigned int count; + unsigned int total_count; + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = "/main/format_cap/"; + info->summary = "format capabilities append duplicate unit test"; + info->description = + "Test that appending capabilities structures multiple times does not result in duplicate formats"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + dst_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!dst_caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append_by_type(dst_caps, AST_MEDIA_TYPE_AUDIO)) { + ast_test_status_update(test, "Failed to add all audio media formats to capabilities structure\n"); + return AST_TEST_FAIL; + } + + src_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!src_caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append_by_type(src_caps, AST_MEDIA_TYPE_VIDEO)) { + ast_test_status_update(test, "Failed to add all video media formats to capabilities structure\n"); + return AST_TEST_FAIL; + } + + total_count = ast_format_cap_count(src_caps) + ast_format_cap_count(dst_caps); + + if (ast_format_cap_append_from_cap(dst_caps, src_caps, AST_MEDIA_TYPE_UNKNOWN)) { + ast_test_status_update(test, "Failed to append formats to capabilities structure\n"); + return AST_TEST_FAIL; + } else if (!ast_format_cap_has_type(dst_caps, AST_MEDIA_TYPE_AUDIO)) { + ast_test_status_update(test, "Successfully appended video formats to destination capabilities but it no longer contains audio formats\n"); + return AST_TEST_FAIL; + } else if (!ast_format_cap_has_type(dst_caps, AST_MEDIA_TYPE_VIDEO)) { + ast_test_status_update(test, "Successfully appended formats but video formats do not exist in destination capabilities\n"); + return AST_TEST_FAIL; + } + + count = ast_format_cap_count(dst_caps); + + if (ast_format_cap_append_from_cap(dst_caps, src_caps, AST_MEDIA_TYPE_UNKNOWN)) { + ast_test_status_update(test, "Failed to append duplicate formats to capabilities structure\n"); + return AST_TEST_FAIL; + } + + ast_test_validate(test, count == ast_format_cap_count(dst_caps)); + ast_test_validate(test, count == total_count); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_set_framing) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "format_cap_set_framing"; + info->category = "/main/format_cap/"; + info->summary = "format capabilities framing unit test"; + info->description = + "Test that global framing on a format capabilities structure is used when it should be"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + ast_format_cap_set_framing(caps, 160); + + ast_test_validate(test, ast_format_cap_get_framing(caps) == 160); + + ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!ulaw) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + ulaw_format = ast_format_create(ulaw); + if (!ulaw_format) { + ast_test_status_update(test, "Could not create ulaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!alaw) { + ast_test_status_update(test, "Could not retrieve built-in alaw codec\n"); + return AST_TEST_FAIL; + } + + alaw_format = ast_format_create(alaw); + if (!alaw_format) { + ast_test_status_update(test, "Could not create alaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ulaw_format, 42)) { + ast_test_status_update(test, "Could not add newly created ulaw format to capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append(caps, alaw_format, 0)) { + ast_test_status_update(test, "Could not add newly created alaw format to capabilities structure\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_get_format_framing(caps, ulaw_format) != 42) { + ast_test_status_update(test, "Added ulaw format to capabilities structure with explicit framing but did not get it back\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_get_format_framing(caps, alaw_format) != ast_format_get_default_ms(alaw_format)) { + ast_test_status_update(test, "Added alaw format to capabilities structure with no explicit framing but did not get global back\n"); + return AST_TEST_FAIL; + } + ast_test_validate(test, ast_format_cap_get_framing(caps) == ast_format_get_default_ms(alaw_format)); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_remove_single) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "format_cap_remove_single"; + info->category = "/main/format_cap/"; + info->summary = "format capabilities removal unit test"; + info->description = + "Test that removing a single format from a format capabilities structure succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!codec) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + format = ast_format_create(codec); + if (!format) { + ast_test_status_update(test, "Could not create format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, format, 42)) { + ast_test_status_update(test, "Could not add newly created format to capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_remove(caps, format)) { + ast_test_status_update(test, "Could not remove format that was just added to capabilities structure\n"); + return AST_TEST_FAIL; + } else if (!ast_format_cap_remove(caps, format)) { + ast_test_status_update(test, "Successfully removed a format twice from the capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_count(caps)) { + ast_test_status_update(test, "Capabilities structure should be empty but instead it contains '%zu' formats\n", + ast_format_cap_count(caps)); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_remove_multiple) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, retrieved, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "format_cap_remove_multiple"; + info->category = "/main/format_cap/"; + info->summary = "format capabilities removal unit test"; + info->description = + "Test that removing a format from a format capabilities structure containing multiple formats succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!ulaw) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + ulaw_format = ast_format_create(ulaw); + if (!ulaw_format) { + ast_test_status_update(test, "Could not create ulaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!alaw) { + ast_test_status_update(test, "Could not retrieve built-in alaw codec\n"); + return AST_TEST_FAIL; + } + + alaw_format = ast_format_create(alaw); + if (!alaw_format) { + ast_test_status_update(test, "Could not create alaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ulaw_format, 42)) { + ast_test_status_update(test, "Could not add newly created ulaw format to capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append(caps, alaw_format, 84)) { + ast_test_status_update(test, "Could not add newly created alaw format to capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_remove(caps, ulaw_format)) { + ast_test_status_update(test, "Could not remove the ulaw format we just added to capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_count(caps) != 1) { + ast_test_status_update(test, "Capabilities structure should contain 1 format but it contains '%zu'\n", + ast_format_cap_count(caps)); + return AST_TEST_FAIL; + } + + retrieved = ast_format_cap_get_format(caps, 0); + if (!retrieved) { + ast_test_status_update(test, "Attempted to get first format from capabilities structure but got nothing\n"); + return AST_TEST_FAIL; + } else if (retrieved != alaw_format) { + ast_test_status_update(test, "First retrieved format is not the alaw one we added\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_remove_bytype) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "format_cap_remove_bytype"; + info->category = "/main/format_cap/"; + info->summary = "format capabilities removal unit test"; + info->description = + "Test that removal of a specific type of format from a format capabilities structure succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append_by_type(caps, AST_MEDIA_TYPE_UNKNOWN)) { + ast_test_status_update(test, "Failed to add all media formats of all types to capabilities structure\n"); + return AST_TEST_FAIL; + } + + ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_AUDIO); + if (ast_format_cap_has_type(caps, AST_MEDIA_TYPE_AUDIO)) { + ast_test_status_update(test, "Removed all audio type formats from capabilities structure but some remain\n"); + return AST_TEST_FAIL; + } else if (!ast_format_cap_has_type(caps, AST_MEDIA_TYPE_VIDEO)) { + ast_test_status_update(test, "Removed audio type formats from capabilities structure but video are gone as well\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_remove_all) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "format_cap_remove_all"; + info->category = "/main/format_cap/"; + info->summary = "format capabilities removal unit test"; + info->description = + "Test that removal of all formats from a format capabilities structure succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append_by_type(caps, AST_MEDIA_TYPE_UNKNOWN)) { + ast_test_status_update(test, "Failed to add all media formats of all types to capabilities structure\n"); + return AST_TEST_FAIL; + } + + ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_UNKNOWN); + + if (ast_format_cap_count(caps)) { + ast_test_status_update(test, "Removed all formats from capabilities structure but some remain\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_get_compatible_format) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, compatible, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "format_cap_get_compatible_format"; + info->category = "/main/format_cap/"; + info->summary = "format capabilities negotiation unit test"; + info->description = + "Test that getting a compatible format from a capabilities structure succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!ulaw) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + ulaw_format = ast_format_create(ulaw); + if (!ulaw_format) { + ast_test_status_update(test, "Could not create ulaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!alaw) { + ast_test_status_update(test, "Could not retrieve built-in alaw codec\n"); + return AST_TEST_FAIL; + } + + alaw_format = ast_format_create(alaw); + if (!alaw_format) { + ast_test_status_update(test, "Could not create alaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ulaw_format, 42)) { + ast_test_status_update(test, "Could not add newly created ulaw format to capabilities structure\n"); + return AST_TEST_FAIL; + } + + compatible = ast_format_cap_get_compatible_format(caps, alaw_format); + if (compatible) { + ast_test_status_update(test, "Retrieved a compatible format from capabilities structure when none should exist\n"); + return AST_TEST_FAIL; + } + + compatible = ast_format_cap_get_compatible_format(caps, ulaw_format); + if (!compatible) { + ast_test_status_update(test, "Did not retrieve a compatible format from capabilities structure when there should be one\n"); + return AST_TEST_FAIL; + } else if (compatible != ulaw_format) { + ast_test_status_update(test, "Compatible format is not the format we added to the capabilities structure\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_iscompatible_format) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "format_cap_iscompatible_format"; + info->category = "/main/format_cap/"; + info->summary = "format capabilities negotiation unit test"; + info->description = + "Test that checking whether a format is compatible with a capabilities structure succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!ulaw) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + ulaw_format = ast_format_create(ulaw); + if (!ulaw_format) { + ast_test_status_update(test, "Could not create ulaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!alaw) { + ast_test_status_update(test, "Could not retrieve built-in alaw codec\n"); + return AST_TEST_FAIL; + } + + alaw_format = ast_format_create(alaw); + if (!alaw_format) { + ast_test_status_update(test, "Could not create alaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ulaw_format, 42)) { + ast_test_status_update(test, "Could not add newly created ulaw format to capabilities structure\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_iscompatible_format(caps, alaw_format) != AST_FORMAT_CMP_NOT_EQUAL) { + ast_test_status_update(test, "Alaw format is compatible with capabilities structure when it only contains ulaw\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_iscompatible_format(caps, ulaw_format) == AST_FORMAT_CMP_NOT_EQUAL) { + ast_test_status_update(test, "Ulaw format is not compatible with capabilities structure when it should be\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_get_compatible) +{ + RAII_VAR(struct ast_format_cap *, alaw_caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_format_cap *, ulaw_caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_format_cap *, compatible_caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "format_cap_get_compatible"; + info->category = "/main/format_cap/"; + info->summary = "format capabilities negotiation unit test"; + info->description = + "Test that getting the compatible formats between two capabilities structures succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + alaw_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!alaw_caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + ulaw_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!ulaw_caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + compatible_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!compatible_caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!ulaw) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + ulaw_format = ast_format_create(ulaw); + if (!ulaw_format) { + ast_test_status_update(test, "Could not create ulaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!alaw) { + ast_test_status_update(test, "Could not retrieve built-in alaw codec\n"); + return AST_TEST_FAIL; + } + + alaw_format = ast_format_create(alaw); + if (!alaw_format) { + ast_test_status_update(test, "Could not create alaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(ulaw_caps, ulaw_format, 0)) { + ast_test_status_update(test, "Could not add ulaw format to ulaw capabilities\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append(alaw_caps, alaw_format, 0)) { + ast_test_status_update(test, "Could not add alaw format to alaw capabilities\n"); + return AST_TEST_FAIL; + } + + ast_format_cap_get_compatible(ulaw_caps, alaw_caps, compatible_caps); + if (ast_format_cap_count(compatible_caps)) { + ast_test_status_update(test, "A compatible format exists when none should\n"); + return AST_TEST_FAIL; + } + + ast_format_cap_get_compatible(ulaw_caps, ulaw_caps, compatible_caps); + if (!ast_format_cap_count(compatible_caps)) { + ast_test_status_update(test, "No compatible formats exist when 1 should\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_iscompatible) +{ + RAII_VAR(struct ast_format_cap *, alaw_caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_format_cap *, ulaw_caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = "format_cap_iscompatible"; + info->category = "/main/format_cap/"; + info->summary = "format capabilities negotiation unit test"; + info->description = + "Test that checking if there are compatible formats between two capabilities structures succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + alaw_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!alaw_caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + ulaw_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!ulaw_caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!ulaw) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + ulaw_format = ast_format_create(ulaw); + if (!ulaw_format) { + ast_test_status_update(test, "Could not create ulaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!alaw) { + ast_test_status_update(test, "Could not retrieve built-in alaw codec\n"); + return AST_TEST_FAIL; + } + + alaw_format = ast_format_create(alaw); + if (!alaw_format) { + ast_test_status_update(test, "Could not create alaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(ulaw_caps, ulaw_format, 0)) { + ast_test_status_update(test, "Could not add ulaw format to ulaw capabilities\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append(alaw_caps, alaw_format, 0)) { + ast_test_status_update(test, "Could not add alaw format to alaw capabilities\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_iscompatible(ulaw_caps, alaw_caps)) { + ast_test_status_update(test, "Two capability structures that should not be compatible are\n"); + return AST_TEST_FAIL; + } else if (!ast_format_cap_iscompatible(ulaw_caps, ulaw_caps)) { + ast_test_status_update(test, "Capability structure is not compatible with itself\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_get_names) +{ + RAII_VAR(struct ast_format_cap *, empty_caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_format_cap *, multi_caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_format_cap *, alaw_caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_format_cap *, ulaw_caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup); + struct ast_str *buffer = ast_str_alloca(128); + + switch (cmd) { + case TEST_INIT: + info->name = "format_cap_get_names"; + info->category = "/main/format_cap/"; + info->summary = "Test getting the names of formats"; + info->description = + "Test that obtaining the names from a format capabilities structure\n" + "produces the expected output.\n"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + empty_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!empty_caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + multi_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!multi_caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + alaw_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!alaw_caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + ulaw_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!ulaw_caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!ulaw) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + ulaw_format = ast_format_create(ulaw); + if (!ulaw_format) { + ast_test_status_update(test, "Could not create ulaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!alaw) { + ast_test_status_update(test, "Could not retrieve built-in alaw codec\n"); + return AST_TEST_FAIL; + } + + alaw_format = ast_format_create(alaw); + if (!alaw_format) { + ast_test_status_update(test, "Could not create alaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(ulaw_caps, ulaw_format, 0)) { + ast_test_status_update(test, "Could not add ulaw format to ulaw capabilities\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append(alaw_caps, alaw_format, 0)) { + ast_test_status_update(test, "Could not add alaw format to alaw capabilities\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append(multi_caps, ulaw_format, 0)) { + ast_test_status_update(test, "Could not add ulaw format to multi capabilities\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append(multi_caps, alaw_format, 0)) { + ast_test_status_update(test, "Could not add alaw format to multi capabilities\n"); + return AST_TEST_FAIL; + } + + ast_format_cap_get_names(empty_caps, &buffer); + ast_test_validate(test, !strcmp(ast_str_buffer(buffer), "(nothing)")); + ast_format_cap_get_names(ulaw_caps, &buffer); + ast_test_validate(test, !strcmp(ast_str_buffer(buffer), "(ulaw)")); + ast_format_cap_get_names(alaw_caps, &buffer); + ast_test_validate(test, !strcmp(ast_str_buffer(buffer), "(alaw)")); + ast_format_cap_get_names(multi_caps, &buffer); + ast_test_validate(test, !strcmp(ast_str_buffer(buffer), "(ulaw|alaw)")); + + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(format_cap_best_by_type) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, h263, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, h263_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, best_format, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = "/main/format_cap/"; + info->summary = "format capabilities best by type unit test"; + info->description = + "Test that we can get the best format type out of a capabilities structure"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + ulaw = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!ulaw) { + ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n"); + return AST_TEST_FAIL; + } + + ulaw_format = ast_format_create(ulaw); + if (!ulaw_format) { + ast_test_status_update(test, "Could not create ulaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!alaw) { + ast_test_status_update(test, "Could not retrieve built-in alaw codec\n"); + return AST_TEST_FAIL; + } + + alaw_format = ast_format_create(alaw); + if (!alaw_format) { + ast_test_status_update(test, "Could not create alaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + h263 = ast_codec_get("h263", AST_MEDIA_TYPE_VIDEO, 0); + if (!h263) { + ast_test_status_update(test, "Could not retrieve built-in h263 codec\n"); + return AST_TEST_FAIL; + } + + h263_format = ast_format_create(h263); + if (!alaw_format) { + ast_test_status_update(test, "Could not create h263 format using built-in codec\n"); + return AST_TEST_FAIL; + } + + if (ast_format_cap_append(caps, ulaw_format, 0)) { + ast_test_status_update(test, "Could not add ulaw format to capabilities\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append(caps, alaw_format, 0)) { + ast_test_status_update(test, "Could not add alaw format to capabilities\n"); + return AST_TEST_FAIL; + } else if (ast_format_cap_append(caps, h263_format, 0)) { + ast_test_status_update(test, "Could not add h263 format to capabilities\n"); + return AST_TEST_FAIL; + } + + best_format = ast_format_cap_get_best_by_type(caps, AST_MEDIA_TYPE_UNKNOWN); + ast_test_validate(test, ast_format_cmp(best_format, ulaw_format) == AST_FORMAT_CMP_EQUAL); + ao2_ref(best_format, -1); + + best_format = ast_format_cap_get_best_by_type(caps, AST_MEDIA_TYPE_AUDIO); + ast_test_validate(test, ast_format_cmp(best_format, ulaw_format) == AST_FORMAT_CMP_EQUAL); + ao2_ref(best_format, -1); + + best_format = ast_format_cap_get_best_by_type(caps, AST_MEDIA_TYPE_VIDEO); + ast_test_validate(test, ast_format_cmp(best_format, h263_format) == AST_FORMAT_CMP_EQUAL); + ao2_ref(best_format, -1); + + best_format = ast_format_cap_get_best_by_type(caps, AST_MEDIA_TYPE_IMAGE); + ast_test_validate(test, best_format == NULL); + + best_format = ast_format_cap_get_best_by_type(caps, AST_MEDIA_TYPE_TEXT); + ast_test_validate(test, best_format == NULL); + + return AST_TEST_PASS; +} + +static int test_law_samples(struct ast_frame *frame) +{ + return frame->datalen; +} + +static int test_law_length(unsigned int samples) +{ + return samples; +} + +static struct ast_codec test_law = { + .name = "test_law", + .description = "format cap unit test codec", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 10, + .maximum_ms = 150, + .default_ms = 20, + .samples_count = test_law_samples, + .get_length = test_law_length, + .smooth = 1, +}; + +static enum ast_format_cmp_res test_law_cmp(const struct ast_format *format1, const struct ast_format *format2) +{ + ast_log(LOG_ERROR, "Comparing format1 %p and format2 %p\n", format1, format2); + return format1 == format2 ? AST_FORMAT_CMP_EQUAL : AST_FORMAT_CMP_NOT_EQUAL; +} + +static void test_law_destroy(struct ast_format *format) +{ +} + +static int test_law_clone(const struct ast_format *src, struct ast_format *dst) +{ + return 0; +} + +static struct ast_format_interface test_law_interface = { + .format_cmp = test_law_cmp, + .format_clone = test_law_clone, + .format_destroy = test_law_destroy, +}; + +AST_TEST_DEFINE(format_cap_replace_from_cap) +{ + RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_format_cap *, replace_caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_format_cap *, result_caps, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, ulaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, ulaw_format, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, ulaw_format_variant, NULL, ao2_cleanup); + RAII_VAR(struct ast_codec *, alaw, NULL, ao2_cleanup); + RAII_VAR(struct ast_format *, alaw_format, NULL, ao2_cleanup); + + switch (cmd) { + case TEST_INIT: + info->name = __PRETTY_FUNCTION__; + info->category = "/main/format_cap/"; + info->summary = "format capabilities adding unit test"; + info->description = + "Test that adding multiple formats to a format capabilities structure succeeds"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + replace_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + result_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps || !replace_caps || !result_caps) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + return AST_TEST_FAIL; + } + + ulaw = ast_codec_get("test_law", AST_MEDIA_TYPE_AUDIO, 8000); + if (!ulaw) { + ast_test_status_update(test, "Could not retrieve test_law codec\n"); + return AST_TEST_FAIL; + } + + ulaw_format = ast_format_create(ulaw); + if (!ulaw_format) { + ast_test_status_update(test, "Could not create ulaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + ulaw_format_variant = ast_format_create(ulaw); + if (!ulaw_format_variant) { + ast_test_status_update(test, "Could not create ulaw format variant using built-in codec\n"); + return AST_TEST_FAIL; + } + + alaw = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000); + if (!alaw) { + ast_test_status_update(test, "Could not retrieve built-in alaw codec\n"); + return AST_TEST_FAIL; + } + + alaw_format = ast_format_create(alaw); + if (!alaw_format) { + ast_test_status_update(test, "Could not create alaw format using built-in codec\n"); + return AST_TEST_FAIL; + } + + /* fill caps with ulaw and alaw */ + if (ast_format_cap_append(caps, ulaw_format, 42)) { + ast_test_status_update(test, "Could not add ulaw format to capabilities structure\n"); + return AST_TEST_FAIL; + } + if (ast_format_cap_append(caps, alaw_format, 84)) { + ast_test_status_update(test, "Could not add alaw format to capabilities structure\n"); + return AST_TEST_FAIL; + } + if (ast_format_cap_count(caps) != 2) { + ast_test_status_update(test, "Number of formats in capabilities structure should be 2 but is %zu\n", + ast_format_cap_count(caps)); + return AST_TEST_FAIL; + } + + /* fill replace_caps with the ulaw variant */ + if (ast_format_cap_append(replace_caps, ulaw_format_variant, 42)) { + ast_test_status_update(test, "Could not add ulaw format to capabilities structure\n"); + return AST_TEST_FAIL; + } + if (ast_format_cap_count(replace_caps) != 1) { + ast_test_status_update(test, "Number of formats in capabilities structure should be 1 but is %zu\n", + ast_format_cap_count(replace_caps)); + return AST_TEST_FAIL; + } + + /* fill result_caps with ulaw_variant and alaw */ + if (ast_format_cap_append(result_caps, ulaw_format_variant, 42)) { + ast_test_status_update(test, "Could not add ulaw variant to capabilities structure\n"); + return AST_TEST_FAIL; + } + if (ast_format_cap_append(result_caps, alaw_format, 84)) { + ast_test_status_update(test, "Could not add alaw format to capabilities structure\n"); + return AST_TEST_FAIL; + } + if (ast_format_cap_count(result_caps) != 2) { + ast_test_status_update(test, "Number of formats in capabilities structure should be 2 but is %zu\n", + ast_format_cap_count(result_caps)); + return AST_TEST_FAIL; + } + + /* replace caps formats from replace_caps */ + ast_format_cap_replace_from_cap(caps, replace_caps, AST_MEDIA_TYPE_UNKNOWN); + + /* compare result_caps with caps */ + if (!ast_format_cap_identical(caps, result_caps)) { + ast_test_status_update(test, "Actual and expected result caps differ\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(format_cap_alloc); + AST_TEST_UNREGISTER(format_cap_append_single); + AST_TEST_UNREGISTER(format_cap_append_multiple); + AST_TEST_UNREGISTER(format_cap_append_all_unknown); + AST_TEST_UNREGISTER(format_cap_append_all_audio); + AST_TEST_UNREGISTER(format_cap_append_duplicate); + AST_TEST_UNREGISTER(format_cap_append_from_cap); + AST_TEST_UNREGISTER(format_cap_append_from_cap_duplicate); + AST_TEST_UNREGISTER(format_cap_set_framing); + AST_TEST_UNREGISTER(format_cap_remove_single); + AST_TEST_UNREGISTER(format_cap_remove_multiple); + AST_TEST_UNREGISTER(format_cap_remove_bytype); + AST_TEST_UNREGISTER(format_cap_remove_all); + AST_TEST_UNREGISTER(format_cap_get_names); + AST_TEST_UNREGISTER(format_cap_get_compatible_format); + AST_TEST_UNREGISTER(format_cap_iscompatible_format); + AST_TEST_UNREGISTER(format_cap_get_compatible); + AST_TEST_UNREGISTER(format_cap_iscompatible); + AST_TEST_UNREGISTER(format_cap_best_by_type); + AST_TEST_UNREGISTER(format_cap_replace_from_cap); + return 0; +} + +static int load_module(void) +{ + AST_TEST_REGISTER(format_cap_alloc); + AST_TEST_REGISTER(format_cap_append_single); + AST_TEST_REGISTER(format_cap_append_multiple); + AST_TEST_REGISTER(format_cap_append_all_unknown); + AST_TEST_REGISTER(format_cap_append_all_audio); + AST_TEST_REGISTER(format_cap_append_duplicate); + AST_TEST_REGISTER(format_cap_append_from_cap); + AST_TEST_REGISTER(format_cap_append_from_cap_duplicate); + AST_TEST_REGISTER(format_cap_set_framing); + AST_TEST_REGISTER(format_cap_remove_single); + AST_TEST_REGISTER(format_cap_remove_multiple); + AST_TEST_REGISTER(format_cap_remove_bytype); + AST_TEST_REGISTER(format_cap_remove_all); + AST_TEST_REGISTER(format_cap_get_names); + AST_TEST_REGISTER(format_cap_get_compatible_format); + AST_TEST_REGISTER(format_cap_iscompatible_format); + AST_TEST_REGISTER(format_cap_get_compatible); + AST_TEST_REGISTER(format_cap_iscompatible); + AST_TEST_REGISTER(format_cap_best_by_type); + AST_TEST_REGISTER(format_cap_replace_from_cap); + ast_codec_register(&test_law); + ast_format_interface_register("test_law", &test_law_interface); + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Format capabilities API test module"); diff --git a/tests/test_voicemail_api.c b/tests/test_voicemail_api.c index 43293b0fc..ab1830298 100644 --- a/tests/test_voicemail_api.c +++ b/tests/test_voicemail_api.c @@ -43,6 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/paths.h" #include "asterisk/channel.h" #include "asterisk/app.h" +#include "asterisk/format_cache.h" /*! * \internal @@ -825,12 +826,12 @@ static struct ast_channel *test_vm_api_create_mock_channel(void) return NULL; } - ast_format_set(ast_channel_writeformat(mock_channel), AST_FORMAT_GSM, 0); + ast_channel_set_writeformat(mock_channel, ast_format_gsm); native_formats = ast_channel_nativeformats(mock_channel); - ast_format_cap_add(native_formats, ast_channel_writeformat(mock_channel)); - ast_format_set(ast_channel_rawwriteformat(mock_channel), AST_FORMAT_GSM, 0); - ast_format_set(ast_channel_readformat(mock_channel), AST_FORMAT_GSM, 0); - ast_format_set(ast_channel_rawreadformat(mock_channel), AST_FORMAT_GSM, 0); + ast_format_cap_append(native_formats, ast_channel_writeformat(mock_channel), 0); + ast_channel_set_rawwriteformat(mock_channel, ast_format_gsm); + ast_channel_set_readformat(mock_channel, ast_format_gsm); + ast_channel_set_rawreadformat(mock_channel, ast_format_gsm); ast_channel_tech_set(mock_channel, &mock_channel_tech); ast_channel_unlock(mock_channel); |