summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorMatthew Jordan <mjordan@digium.com>2014-07-20 22:06:33 +0000
committerMatthew Jordan <mjordan@digium.com>2014-07-20 22:06:33 +0000
commita2c912e9972c91973ea66902d217746133f96026 (patch)
tree50e01d14ba62950e3f78766d5ba435ba51ca327d /main
parentb299052e203807c9a2111eb2cd919246d7589cb3 (diff)
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was fast but had a few limitations. 1. Asterisk was limited in how many formats it could handle. 2. Formats, being a bit field, could not include any attribute information. A format was strictly its type, e.g., "this is ulaw". This was changed in Asterisk 10 (see https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for notes on that work) which led to the creation of the ast_format structure. This structure allowed Asterisk to handle attributes and bundle information with a format. Additionally, ast_format_cap was created to act as a container for multiple formats that, together, formed the capability of some entity. Another mechanism was added to allow logic to be registered which performed format attribute negotiation. Everywhere throughout the codebase Asterisk was changed to use this strategy. Unfortunately, in software, there is no free lunch. These new capabilities came at a cost. Performance analysis and profiling showed that we spend an inordinate amount of time comparing, copying, and generally manipulating formats and their related structures. Basic prototyping has shown that a reasonably large performance improvement could be made in this area. This patch is the result of that project, which overhauled the media format architecture and its usage in Asterisk to improve performance. Generally, the new philosophy for handling formats is as follows: * The ast_format structure is reference counted. This removed a large amount of the memory allocations and copying that was done in prior versions. * In order to prevent race conditions while keeping things performant, the ast_format structure is immutable by convention and lock-free. Violate this tenet at your peril! * Because formats are reference counted, codecs are also reference counted. The Asterisk core generally provides built-in codecs and caches the ast_format structures created to represent them. Generally, to prevent inordinate amounts of module reference bumping, codecs and formats can be added at run-time but cannot be removed. * All compatibility with the bit field representation of codecs/formats has been moved to a compatibility API. The primary user of this representation is chan_iax2, which must continue to maintain its bit-field usage of formats for interoperability concerns. * When a format is negotiated with attributes, or when a format cannot be represented by one of the cached formats, a new format object is created or cloned from an existing format. That format may have the same codec underlying it, but is a different format than a version of the format with different attributes or without attributes. * While formats are reference counted objects, the reference count maintained on the format should be manipulated with care. Formats are generally cached and will persist for the lifetime of Asterisk and do not explicitly need to have their lifetime modified. An exception to this is when the user of a format does not know where the format came from *and* the user may outlive the provider of the format. This occurs, for example, when a format is read from a channel: the channel may have a format with attributes (hence, non-cached) and the user of the format may last longer than the channel (if the reference to the channel is released prior to the format's reference). For more information on this work, see the API design notes: https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite Finally, this work was the culmination of a large number of developer's efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the work in the Asterisk core, chan_sip, and was an invaluable resource in peer reviews throughout this project. There were a substantial number of patches contributed during this work; the following issues/patch names simply reflect some of the work (and will cause the release scripts to give attribution to the individuals who work on them). Reviews: https://reviewboard.asterisk.org/r/3814 https://reviewboard.asterisk.org/r/3808 https://reviewboard.asterisk.org/r/3805 https://reviewboard.asterisk.org/r/3803 https://reviewboard.asterisk.org/r/3801 https://reviewboard.asterisk.org/r/3798 https://reviewboard.asterisk.org/r/3800 https://reviewboard.asterisk.org/r/3794 https://reviewboard.asterisk.org/r/3793 https://reviewboard.asterisk.org/r/3792 https://reviewboard.asterisk.org/r/3791 https://reviewboard.asterisk.org/r/3790 https://reviewboard.asterisk.org/r/3789 https://reviewboard.asterisk.org/r/3788 https://reviewboard.asterisk.org/r/3787 https://reviewboard.asterisk.org/r/3786 https://reviewboard.asterisk.org/r/3784 https://reviewboard.asterisk.org/r/3783 https://reviewboard.asterisk.org/r/3778 https://reviewboard.asterisk.org/r/3774 https://reviewboard.asterisk.org/r/3775 https://reviewboard.asterisk.org/r/3772 https://reviewboard.asterisk.org/r/3761 https://reviewboard.asterisk.org/r/3754 https://reviewboard.asterisk.org/r/3753 https://reviewboard.asterisk.org/r/3751 https://reviewboard.asterisk.org/r/3750 https://reviewboard.asterisk.org/r/3748 https://reviewboard.asterisk.org/r/3747 https://reviewboard.asterisk.org/r/3746 https://reviewboard.asterisk.org/r/3742 https://reviewboard.asterisk.org/r/3740 https://reviewboard.asterisk.org/r/3739 https://reviewboard.asterisk.org/r/3738 https://reviewboard.asterisk.org/r/3737 https://reviewboard.asterisk.org/r/3736 https://reviewboard.asterisk.org/r/3734 https://reviewboard.asterisk.org/r/3722 https://reviewboard.asterisk.org/r/3713 https://reviewboard.asterisk.org/r/3703 https://reviewboard.asterisk.org/r/3689 https://reviewboard.asterisk.org/r/3687 https://reviewboard.asterisk.org/r/3674 https://reviewboard.asterisk.org/r/3671 https://reviewboard.asterisk.org/r/3667 https://reviewboard.asterisk.org/r/3665 https://reviewboard.asterisk.org/r/3625 https://reviewboard.asterisk.org/r/3602 https://reviewboard.asterisk.org/r/3519 https://reviewboard.asterisk.org/r/3518 https://reviewboard.asterisk.org/r/3516 https://reviewboard.asterisk.org/r/3515 https://reviewboard.asterisk.org/r/3512 https://reviewboard.asterisk.org/r/3506 https://reviewboard.asterisk.org/r/3413 https://reviewboard.asterisk.org/r/3410 https://reviewboard.asterisk.org/r/3387 https://reviewboard.asterisk.org/r/3388 https://reviewboard.asterisk.org/r/3389 https://reviewboard.asterisk.org/r/3390 https://reviewboard.asterisk.org/r/3321 https://reviewboard.asterisk.org/r/3320 https://reviewboard.asterisk.org/r/3319 https://reviewboard.asterisk.org/r/3318 https://reviewboard.asterisk.org/r/3266 https://reviewboard.asterisk.org/r/3265 https://reviewboard.asterisk.org/r/3234 https://reviewboard.asterisk.org/r/3178 ASTERISK-23114 #close Reported by: mjordan media_formats_translation_core.diff uploaded by kharwell (License 6464) rb3506.diff uploaded by mjordan (License 6283) media_format_app_file.diff uploaded by kharwell (License 6464) misc-2.diff uploaded by file (License 5000) chan_mild-3.diff uploaded by file (License 5000) chan_obscure.diff uploaded by file (License 5000) jingle.diff uploaded by file (License 5000) funcs.diff uploaded by file (License 5000) formats.diff uploaded by file (License 5000) core.diff uploaded by file (License 5000) bridges.diff uploaded by file (License 5000) mf-codecs-2.diff uploaded by file (License 5000) mf-app_fax.diff uploaded by file (License 5000) mf-apps-3.diff uploaded by file (License 5000) media-formats-3.diff uploaded by file (License 5000) ASTERISK-23715 rb3713.patch uploaded by coreyfarrell (License 5909) rb3689.patch uploaded by mjordan (License 6283) ASTERISK-23957 rb3722.patch uploaded by mjordan (License 6283) mf-attributes-3.diff uploaded by file (License 5000) ASTERISK-23958 Tested by: jrose rb3822.patch uploaded by coreyfarrell (License 5909) rb3800.patch uploaded by jrose (License 6182) chan_sip.diff uploaded by mjordan (License 6283) rb3747.patch uploaded by jrose (License 6182) ASTERISK-23959 #close Tested by: sgriepentrog, mjordan, coreyfarrell sip_cleanup.diff uploaded by opticron (License 6273) chan_sip_caps.diff uploaded by mjordan (License 6283) rb3751.patch uploaded by coreyfarrell (License 5909) chan_sip-3.diff uploaded by file (License 5000) ASTERISK-23960 #close Tested by: opticron direct_media.diff uploaded by opticron (License 6273) pjsip-direct-media.diff uploaded by file (License 5000) format_cap_remove.diff uploaded by opticron (License 6273) media_format_fixes.diff uploaded by opticron (License 6273) chan_pjsip-2.diff uploaded by file (License 5000) ASTERISK-23966 #close Tested by: rmudgett rb3803.patch uploaded by rmudgetti (License 5621) chan_dahdi.diff uploaded by file (License 5000) ASTERISK-24064 #close Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose rb3814.patch uploaded by rmudgett (License 5621) moh_cleanup.diff uploaded by opticron (License 6273) bridge_leak.diff uploaded by opticron (License 6273) translate.diff uploaded by file (License 5000) rb3795.patch uploaded by rmudgett (License 5621) tls_fix.diff uploaded by mjordan (License 6283) fax-mf-fix-2.diff uploaded by file (License 5000) rtp_transfer_stuff uploaded by mjordan (License 6283) rb3787.patch uploaded by rmudgett (License 5621) media-formats-explicit-translate-format-3.diff uploaded by file (License 5000) format_cache_case_fix.diff uploaded by opticron (License 6273) rb3774.patch uploaded by rmudgett (License 5621) rb3775.patch uploaded by rmudgett (License 5621) rtp_engine_fix.diff uploaded by opticron (License 6273) rtp_crash_fix.diff uploaded by opticron (License 6273) rb3753.patch uploaded by mjordan (License 6283) rb3750.patch uploaded by mjordan (License 6283) rb3748.patch uploaded by rmudgett (License 5621) media_format_fixes.diff uploaded by opticron (License 6273) rb3740.patch uploaded by mjordan (License 6283) rb3739.patch uploaded by mjordan (License 6283) rb3734.patch uploaded by mjordan (License 6283) rb3689.patch uploaded by mjordan (License 6283) rb3674.patch uploaded by coreyfarrell (License 5909) rb3671.patch uploaded by coreyfarrell (License 5909) rb3667.patch uploaded by coreyfarrell (License 5909) rb3665.patch uploaded by mjordan (License 6283) rb3625.patch uploaded by coreyfarrell (License 5909) rb3602.patch uploaded by coreyfarrell (License 5909) format_compatibility-2.diff uploaded by file (License 5000) core.diff uploaded by file (License 5000) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main')
-rw-r--r--main/abstract_jb.c21
-rw-r--r--main/app.c37
-rw-r--r--main/asterisk.c24
-rw-r--r--main/audiohook.c67
-rw-r--r--main/bridge.c50
-rw-r--r--main/bridge_basic.c11
-rw-r--r--main/bridge_channel.c26
-rw-r--r--main/callerid.c1
-rw-r--r--main/ccss.c10
-rw-r--r--main/channel.c434
-rw-r--r--main/channel_internal_api.c48
-rw-r--r--main/cli.c8
-rw-r--r--main/codec.c381
-rw-r--r--main/codec_builtin.c845
-rw-r--r--main/config_options.c6
-rw-r--r--main/core_local.c13
-rw-r--r--main/core_unreal.c41
-rw-r--r--main/data.c82
-rw-r--r--main/dial.c10
-rw-r--r--main/dsp.c86
-rw-r--r--main/file.c123
-rw-r--r--main/format.c1473
-rw-r--r--main/format_cache.c519
-rw-r--r--main/format_cap.c937
-rw-r--r--main/format_compatibility.c274
-rw-r--r--main/format_pref.c380
-rw-r--r--main/frame.c583
-rw-r--r--main/image.c4
-rw-r--r--main/indications.c17
-rw-r--r--main/manager.c22
-rw-r--r--main/media_index.c17
-rw-r--r--main/rtp_engine.c687
-rw-r--r--main/slinfactory.c34
-rw-r--r--main/smoother.c227
-rw-r--r--main/sorcery.c8
-rw-r--r--main/sounds_index.c16
-rw-r--r--main/translate.c775
-rw-r--r--main/utils.c4
38 files changed, 4390 insertions, 3911 deletions
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;
}