summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
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;
}