summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorDavid Vossel <dvossel@digium.com>2011-02-22 23:04:49 +0000
committerDavid Vossel <dvossel@digium.com>2011-02-22 23:04:49 +0000
commitd760e81f37b231a99865a40f67838c51079ed4f8 (patch)
treeb061487de973558358757bd1b6e457aaccf41638 /main
parent736133f874f270be81810c2c1fb36c47e6a479bf (diff)
Media Project Phase2: SILK 8khz-24khz, SLINEAR 8khz-192khz, SPEEX 32khz, hd audio ConfBridge, and other stuff
-Functional changes 1. Dynamic global format list build by codecs defined in codecs.conf 2. SILK 8khz, 12khz, 16khz, and 24khz with custom attributes defined in codecs.conf 3. Negotiation of SILK attributes in chan_sip. 4. SPEEX 32khz with translation 5. SLINEAR 8khz, 12khz, 24khz, 32khz, 44.1khz, 48khz, 96khz, 192khz with translation using codec_resample.c 6. Various changes to RTP code required to properly handle the dynamic format list and formats with attributes. 7. ConfBridge now dynamically jumps to the best possible sample rate. This allows for conferences to take advantage of HD audio (Which sounds awesome) 8. Audiohooks are no longer limited to 8khz audio, and most effects have been updated to take advantage of this such as Volume, DENOISE, PITCH_SHIFT. 9. codec_resample now uses its own code rather than depending on libresample. -Organizational changes Global format list is moved from frame.c to format.c Various format specific functions moved from frame.c to format.c Review: https://reviewboard.asterisk.org/r/1104/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@308582 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main')
-rw-r--r--main/asterisk.c3
-rw-r--r--main/audiohook.c265
-rw-r--r--main/bridging.c4
-rw-r--r--main/channel.c20
-rw-r--r--main/data.c13
-rw-r--r--main/format.c796
-rw-r--r--main/format_cap.c99
-rw-r--r--main/format_pref.c70
-rw-r--r--main/frame.c285
-rw-r--r--main/rtp_engine.c334
-rw-r--r--main/slinfactory.c19
-rw-r--r--main/translate.c120
12 files changed, 1489 insertions, 539 deletions
diff --git a/main/asterisk.c b/main/asterisk.c
index ad8b38103..846848da8 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -143,6 +143,7 @@ int daemon(int, int); /* defined in libresolv of all places */
#include "asterisk/poll-compat.h"
#include "asterisk/ccss.h"
#include "asterisk/test.h"
+#include "asterisk/rtp_engine.h"
#include "asterisk/format.h"
#include "asterisk/aoc.h"
@@ -3708,6 +3709,8 @@ int main(int argc, char *argv[])
astobj2_init();
ast_format_attr_init();
+ ast_format_list_init();
+ ast_rtp_engine_init();
ast_autoservice_init();
diff --git a/main/audiohook.c b/main/audiohook.c
index 6b2df6416..9fd2ca957 100644
--- a/main/audiohook.c
+++ b/main/audiohook.c
@@ -38,12 +38,22 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/frame.h"
#include "asterisk/translate.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_audiohook_list {
+ /* If all the audiohooks in this list are capable
+ * of processing slinear at any sample rate, this
+ * variable will be set and the sample rate will
+ * be preserved during ast_audiohook_write_list()*/
+ int native_slin_compatible;
+ int list_internal_samp_rate;/*!< Internal sample rate used when writing to the audiohook list */
+
struct ast_audiohook_translate in_translate[2];
struct ast_audiohook_translate out_translate[2];
AST_LIST_HEAD_NOLOCK(, ast_audiohook) spy_list;
@@ -51,13 +61,44 @@ struct ast_audiohook_list {
AST_LIST_HEAD_NOLOCK(, ast_audiohook) manipulate_list;
};
+static int audiohook_set_internal_rate(struct ast_audiohook *audiohook, int rate, int reset)
+{
+ struct ast_format slin;
+
+ if (audiohook->hook_internal_samp_rate == rate) {
+ return 0;
+ }
+
+ audiohook->hook_internal_samp_rate = rate;
+
+ ast_format_set(&slin, ast_format_slin_by_rate(rate), 0);
+ /* Setup the factories that are needed for this audiohook type */
+ switch (audiohook->type) {
+ case AST_AUDIOHOOK_TYPE_SPY:
+ if (reset) {
+ ast_slinfactory_destroy(&audiohook->read_factory);
+ }
+ ast_slinfactory_init_with_format(&audiohook->read_factory, &slin);
+ /* fall through */
+ case AST_AUDIOHOOK_TYPE_WHISPER:
+ if (reset) {
+ ast_slinfactory_destroy(&audiohook->write_factory);
+ }
+ ast_slinfactory_init_with_format(&audiohook->write_factory, &slin);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
/*! \brief Initialize an audiohook structure
* \param audiohook Audiohook structure
* \param type
* \param source
* \return Returns 0 on success, -1 on failure
*/
-int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source)
+int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags init_flags)
{
/* Need to keep the type and source */
audiohook->type = type;
@@ -67,16 +108,10 @@ int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type
ast_mutex_init(&audiohook->lock);
ast_cond_init(&audiohook->trigger, NULL);
- /* Setup the factories that are needed for this audiohook type */
- switch (type) {
- case AST_AUDIOHOOK_TYPE_SPY:
- ast_slinfactory_init(&audiohook->read_factory);
- case AST_AUDIOHOOK_TYPE_WHISPER:
- ast_slinfactory_init(&audiohook->write_factory);
- break;
- default:
- break;
- }
+ audiohook->init_flags = init_flags;
+
+ /* initialize internal rate at 8khz, this will adjust if necessary */
+ audiohook_set_internal_rate(audiohook, 8000, 0);
/* Since we are just starting out... this audiohook is new */
ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_NEW);
@@ -133,9 +168,9 @@ int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohoo
*rwtime = ast_tvnow();
our_factory_samples = ast_slinfactory_available(factory);
- our_factory_ms = ast_tvdiff_ms(*rwtime, previous_time) + (our_factory_samples / 8);
+ our_factory_ms = ast_tvdiff_ms(*rwtime, previous_time) + (our_factory_samples / (audiohook->hook_internal_samp_rate / 1000));
other_factory_samples = ast_slinfactory_available(other_factory);
- other_factory_ms = other_factory_samples / 8;
+ other_factory_ms = other_factory_samples / (audiohook->hook_internal_samp_rate / 1000);
if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC) && other_factory_samples && (our_factory_ms - other_factory_ms > AST_AUDIOHOOK_SYNC_TOLERANCE)) {
ast_debug(1, "Flushing audiohook %p so it remains in sync\n", audiohook);
@@ -143,7 +178,7 @@ int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohoo
ast_slinfactory_flush(other_factory);
}
- if (ast_test_flag(audiohook, AST_AUDIOHOOK_SMALL_QUEUE) && (our_factory_samples > 640 || other_factory_samples > 640)) {
+ if (ast_test_flag(audiohook, AST_AUDIOHOOK_SMALL_QUEUE) && ((our_factory_ms > AST_AUDIOHOOK_SMALL_QUEUE_TOLERANCE) || (other_factory_ms > AST_AUDIOHOOK_SMALL_QUEUE_TOLERANCE))) {
ast_debug(1, "Audiohook %p has stale audio in its factories. Flushing them both\n", audiohook);
ast_slinfactory_flush(factory);
ast_slinfactory_flush(other_factory);
@@ -186,7 +221,7 @@ static struct ast_frame *audiohook_read_frame_single(struct ast_audiohook *audio
.datalen = sizeof(buf),
.samples = samples,
};
- ast_format_set(&frame.subclass.format, AST_FORMAT_SLINEAR, 0);
+ 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))
@@ -213,7 +248,7 @@ 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_SLINEAR, 0);
+ 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);
@@ -296,7 +331,7 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho
/*! \brief Reads a frame in from the audiohook structure
* \param audiohook Audiohook structure
- * \param samples Number of samples wanted
+ * \param samples Number of samples wanted in requested output format
* \param direction Direction the audio frame came from
* \param format Format of frame remote side wants back
* \return Returns frame on success, NULL on failure
@@ -305,23 +340,39 @@ struct ast_frame *ast_audiohook_read_frame(struct ast_audiohook *audiohook, size
{
struct ast_frame *read_frame = NULL, *final_frame = NULL;
struct ast_format tmp_fmt;
+ 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)) {
+ 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 {
+ samples_converted = samples * (ast_format_rate(format) / (float) audiohook->hook_internal_samp_rate);
+ }
- if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ? audiohook_read_frame_both(audiohook, samples) : audiohook_read_frame_single(audiohook, samples, direction))))
+ if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ?
+ audiohook_read_frame_both(audiohook, samples_converted) :
+ audiohook_read_frame_single(audiohook, samples_converted, direction)))) {
return NULL;
+ }
/* If they don't want signed linear back out, we'll have to send it through the translation path */
- if (format->id != AST_FORMAT_SLINEAR) {
+ if (format->id != ast_format_slin_by_rate(audiohook->hook_internal_samp_rate)) {
/* Rebuild translation path if different format then previously */
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_SLINEAR, 0)))) {
+ 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)))) {
ast_frfree(read_frame);
return NULL;
}
+ ast_format_copy(&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);
@@ -332,6 +383,18 @@ struct ast_frame *ast_audiohook_read_frame(struct ast_audiohook *audiohook, size
return final_frame;
}
+static void audiohook_list_set_samplerate_compatibility(struct ast_audiohook_list *audiohook_list)
+{
+ struct ast_audiohook *ah = NULL;
+ audiohook_list->native_slin_compatible = 1;
+ AST_LIST_TRAVERSE(&audiohook_list->manipulate_list, ah, list) {
+ if (!(ah->init_flags & AST_AUDIOHOOK_MANIPULATE_ALL_RATES)) {
+ audiohook_list->native_slin_compatible = 0;
+ return;
+ }
+ }
+}
+
/*! \brief Attach audiohook to channel
* \param chan Channel
* \param audiohook Audiohook structure
@@ -350,6 +413,8 @@ int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audioho
AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->spy_list);
AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->whisper_list);
AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->manipulate_list);
+ /* This sample rate will adjust as necessary when writing to the list. */
+ chan->audiohooks->list_internal_samp_rate = 8000;
}
/* Drop into respective list */
@@ -360,6 +425,10 @@ int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audioho
else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
AST_LIST_INSERT_TAIL(&chan->audiohooks->manipulate_list, audiohook, list);
+
+ audiohook_set_internal_rate(audiohook, chan->audiohooks->list_internal_samp_rate, 1);
+ audiohook_list_set_samplerate_compatibility(chan->audiohooks);
+
/* Change status over to running since it is now attached */
ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_RUNNING);
@@ -546,6 +615,7 @@ int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audioho
else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
AST_LIST_REMOVE(&chan->audiohooks->manipulate_list, audiohook, list);
+ audiohook_list_set_samplerate_compatibility(chan->audiohooks);
ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
ast_channel_unlock(chan);
@@ -563,11 +633,13 @@ int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audioho
static struct ast_frame *dtmf_audiohook_write_list(struct ast_channel *chan, struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
{
struct ast_audiohook *audiohook = NULL;
+ int removed = 0;
AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
ast_audiohook_lock(audiohook);
if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
AST_LIST_REMOVE_CURRENT(list);
+ removed = 1;
ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
ast_audiohook_unlock(audiohook);
audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
@@ -579,9 +651,77 @@ static struct ast_frame *dtmf_audiohook_write_list(struct ast_channel *chan, str
}
AST_LIST_TRAVERSE_SAFE_END;
+ /* if an audiohook got removed, reset samplerate compatibility */
+ if (removed) {
+ audiohook_list_set_samplerate_compatibility(audiohook_list);
+ }
return frame;
}
+static struct ast_frame *audiohook_list_translate_to_slin(struct ast_audiohook_list *audiohook_list,
+ enum ast_audiohook_direction direction, struct ast_frame *frame)
+{
+ 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;
+
+ /* If we are capable of maintaining doing samplerates other that 8khz, update
+ * the internal audiohook_list's rate and higher samplerate audio arrives. By
+ * updating the list's rate, all the audiohooks in the list will be updated as well
+ * 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);
+ }
+
+ slin_id = ast_format_slin_by_rate(audiohook_list->list_internal_samp_rate);
+
+ if (frame->subclass.format.id == slin_id) {
+ return new_frame;
+ }
+
+ 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))) {
+ return NULL;
+ }
+ ast_format_copy(&in_translate->format, &frame->subclass.format);
+ }
+ if (!(new_frame = ast_translate(in_translate->trans_pvt, frame, 0))) {
+ return NULL;
+ }
+
+ return new_frame;
+}
+
+static struct ast_frame *audiohook_list_translate_to_native(struct ast_audiohook_list *audiohook_list,
+ enum ast_audiohook_direction direction, struct ast_frame *slin_frame, struct ast_format *outformat)
+{
+ 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) {
+ /* rebuild translators if necessary */
+ 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))) {
+ return NULL;
+ }
+ ast_format_copy(&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))) {
+ return NULL;
+ }
+ }
+ return outframe;
+}
+
/*!
* \brief Pass an AUDIO frame off to be handled by the audiohook core
*
@@ -595,15 +735,9 @@ static struct ast_frame *dtmf_audiohook_write_list(struct ast_channel *chan, str
* SLINEAR format for Part_2.
* Part_2: Send middle_frame off to spies and manipulators. At this point middle_frame is
* either a new frame as result of the translation, or points directly to the start_frame
- * because no translation to SLINEAR audio was required. The result of this part
- * is end_frame will be updated to point to middle_frame if any audiohook manipulation
- * took place.
- * Part_3: Translate end_frame's audio back into the format of start frame if necessary.
- * At this point if middle_frame != end_frame, we are guaranteed that no manipulation
- * took place and middle_frame can be freed as it was translated... If middle_frame was
- * not translated and still pointed to start_frame, it would be equal to end_frame as well
- * regardless if manipulation took place which would not result in this free. The result
- * of this part is end_frame is guaranteed to be the format of start_frame for the return.
+ * because no translation to SLINEAR audio was required.
+ * Part_3: Translate end_frame's audio back into the format of start frame if necessary. This
+ * is only necessary if manipulation of middle_frame occurred.
*
* \param chan Channel that the list is coming off of
* \param audiohook_list List of audiohooks
@@ -613,27 +747,17 @@ static struct ast_frame *dtmf_audiohook_write_list(struct ast_channel *chan, str
*/
static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
{
- struct ast_audiohook_translate *in_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->in_translate[0] : &audiohook_list->in_translate[1]);
- struct ast_audiohook_translate *out_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->out_translate[0] : &audiohook_list->out_translate[1]);
struct ast_frame *start_frame = frame, *middle_frame = frame, *end_frame = frame;
struct ast_audiohook *audiohook = NULL;
- struct ast_format tmp_fmt;
- int samples = frame->samples;
+ int samples;
+ int middle_frame_manipulated = 0;
+ int removed = 0;
/* ---Part_1. translate start_frame to SLINEAR if necessary. */
- /* If the frame coming in is not signed linear we have to send it through the in_translate path */
- if (frame->subclass.format.id != AST_FORMAT_SLINEAR) {
- 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, AST_FORMAT_SLINEAR, 0), &frame->subclass.format)))
- return frame;
- ast_format_copy(&in_translate->format, &frame->subclass.format);
- }
- if (!(middle_frame = ast_translate(in_translate->trans_pvt, frame, 0)))
- return frame;
- samples = middle_frame->samples;
+ if (!(middle_frame = audiohook_list_translate_to_slin(audiohook_list, direction, start_frame))) {
+ return frame;
}
+ samples = middle_frame->samples;
/* ---Part_2: Send middle_frame to spy and manipulator lists. middle_frame is guaranteed to be SLINEAR here.*/
/* Queue up signed linear frame to each spy */
@@ -641,10 +765,12 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st
ast_audiohook_lock(audiohook);
if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
AST_LIST_REMOVE_CURRENT(list);
+ removed = 1;
ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
ast_audiohook_unlock(audiohook);
continue;
}
+ audiohook_set_internal_rate(audiohook, audiohook_list->list_internal_samp_rate, 1);
ast_audiohook_write_frame(audiohook, direction, middle_frame);
ast_audiohook_unlock(audiohook);
}
@@ -659,10 +785,12 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st
ast_audiohook_lock(audiohook);
if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
AST_LIST_REMOVE_CURRENT(list);
+ removed = 1;
ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
ast_audiohook_unlock(audiohook);
continue;
}
+ audiohook_set_internal_rate(audiohook, audiohook_list->list_internal_samp_rate, 1);
if (ast_slinfactory_available(&audiohook->write_factory) >= samples && ast_slinfactory_read(&audiohook->write_factory, read_buf, samples)) {
/* Take audio from this whisper source and combine it into our main buffer */
for (i = 0, data1 = combine_buf, data2 = read_buf; i < samples; i++, data1++, data2++)
@@ -672,9 +800,10 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st
}
AST_LIST_TRAVERSE_SAFE_END;
/* We take all of the combined whisper sources and combine them into the audio being written out */
- for (i = 0, data1 = middle_frame->data.ptr, data2 = combine_buf; i < samples; i++, data1++, data2++)
+ for (i = 0, data1 = middle_frame->data.ptr, data2 = combine_buf; i < samples; i++, data1++, data2++) {
ast_slinear_saturated_add(data1, data2);
- end_frame = middle_frame;
+ }
+ middle_frame_manipulated = 1;
}
/* Pass off frame to manipulate audiohooks */
@@ -683,12 +812,14 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st
ast_audiohook_lock(audiohook);
if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
AST_LIST_REMOVE_CURRENT(list);
+ removed = 1;
ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
ast_audiohook_unlock(audiohook);
/* We basically drop all of our links to the manipulate audiohook and prod it to do it's own destructive things */
audiohook->manipulate_callback(audiohook, chan, NULL, direction);
continue;
}
+ audiohook_set_internal_rate(audiohook, audiohook_list->list_internal_samp_rate, 1);
/* Feed in frame to manipulation. */
if (audiohook->manipulate_callback(audiohook, chan, middle_frame, direction)) {
/* XXX IGNORE FAILURE */
@@ -700,35 +831,27 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st
ast_audiohook_unlock(audiohook);
}
AST_LIST_TRAVERSE_SAFE_END;
- end_frame = middle_frame;
+ middle_frame_manipulated = 1;
}
/* ---Part_3: Decide what to do with the end_frame (whether to transcode or not) */
- if (middle_frame == end_frame) {
- /* Middle frame was modified and became the end frame... let's see if we need to transcode */
- if (ast_format_cmp(&end_frame->subclass.format, &start_frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
- if (ast_format_cmp(&out_translate->format, &start_frame->subclass.format) == 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(&start_frame->subclass.format, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0)))) {
- /* We can't transcode this... drop our middle frame and return the original */
- ast_frfree(middle_frame);
- return start_frame;
- }
- ast_format_copy(&out_translate->format, &start_frame->subclass.format);
- }
- /* Transcode from our middle (signed linear) frame to new format of the frame that came in */
- if (!(end_frame = ast_translate(out_translate->trans_pvt, middle_frame, 0))) {
- /* Failed to transcode the frame... drop it and return the original */
- ast_frfree(middle_frame);
- return start_frame;
- }
- /* Here's the scoop... middle frame is no longer of use to us */
- ast_frfree(middle_frame);
+ if (middle_frame_manipulated) {
+ 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;
}
} else {
- /* No frame was modified, we can just drop our middle frame and pass the frame we got in out */
+ end_frame = start_frame;
+ }
+ /* clean up our middle_frame if required */
+ if (middle_frame != end_frame) {
ast_frfree(middle_frame);
+ middle_frame = NULL;
+ }
+
+ /* Before returning, if an audiohook got removed, reset samplerate compatibility */
+ if (removed) {
+ audiohook_list_set_samplerate_compatibility(audiohook_list);
}
return end_frame;
@@ -956,7 +1079,7 @@ static struct audiohook_volume *audiohook_volume_get(struct ast_channel *chan, i
}
/* Setup our audiohook structure so we can manipulate the audio */
- ast_audiohook_init(&audiohook_volume->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume");
+ ast_audiohook_init(&audiohook_volume->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
audiohook_volume->audiohook.manipulate_callback = audiohook_volume_callback;
/* Attach the audiohook_volume blob to the datastore and attach to the channel */
diff --git a/main/bridging.c b/main/bridging.c
index 9de02aa34..f988d9694 100644
--- a/main/bridging.c
+++ b/main/bridging.c
@@ -721,11 +721,11 @@ static enum ast_bridge_channel_state bridge_channel_join_multithreaded(struct as
/* Wait for data to either come from the channel or us to be signalled */
if (!bridge_channel->suspended) {
- ast_debug(1, "Going into a multithreaded waitfor for bridge channel %p of bridge %p\n", bridge_channel, bridge_channel->bridge);
+ ast_debug(10, "Going into a multithreaded waitfor for bridge channel %p of bridge %p\n", bridge_channel, bridge_channel->bridge);
chan = ast_waitfor_nandfds(&bridge_channel->chan, 1, fds, nfds, NULL, &outfd, &ms);
} else {
ast_mutex_lock(&bridge_channel->lock);
- ast_debug(1, "Going into a multithreaded signal wait for bridge channel %p of bridge %p\n", bridge_channel, bridge_channel->bridge);
+ ast_debug(10, "Going into a multithreaded signal wait for bridge channel %p of bridge %p\n", bridge_channel, bridge_channel->bridge);
ast_cond_wait(&bridge_channel->cond, &bridge_channel->lock);
ast_mutex_unlock(&bridge_channel->lock);
}
diff --git a/main/channel.c b/main/channel.c
index 093d5f619..404732823 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -1006,7 +1006,14 @@ struct ast_format *ast_best_codec(struct ast_format_cap *cap, struct ast_format
/*! 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,
@@ -1020,8 +1027,11 @@ struct ast_format *ast_best_codec(struct ast_format_cap *cap, struct ast_format
/*! 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,
+ /*! SILK is pretty awesome. */
+ AST_FORMAT_SILK,
/*! Ick, LPC10 sounds terrible, but at least we have code for it, if you're tacky enough
to use it */
AST_FORMAT_LPC10,
@@ -1035,7 +1045,7 @@ struct ast_format *ast_best_codec(struct ast_format_cap *cap, struct ast_format
/* Find the first preferred codec in the format given */
for (x = 0; x < ARRAY_LEN(prefs); x++) {
- if (ast_format_cap_iscompatible(cap, ast_format_set(result, prefs[x], 0))) {
+ if (ast_format_cap_best_byid(cap, prefs[x], result)) {
return result;
}
}
@@ -5778,12 +5788,16 @@ static int ast_channel_make_compatible_helper(struct ast_channel *from, struct a
* no direct conversion available. If generic PLC is
* desired, then transcoding via SLINEAR is a requirement
*/
- use_slin = (best_src_fmt.id == AST_FORMAT_SLINEAR || best_dst_fmt.id == AST_FORMAT_SLINEAR);
+ use_slin = ast_format_is_slinear(&best_src_fmt) || ast_format_is_slinear(&best_dst_fmt) ? 1 : 0;
if ((ast_format_cmp(&best_src_fmt, &best_dst_fmt) == AST_FORMAT_CMP_NOT_EQUAL) &&
(ast_opt_generic_plc || ast_opt_transcode_via_slin) &&
(ast_translate_path_steps(&best_dst_fmt, &best_src_fmt) != 1 || use_slin)) {
- ast_format_set(&best_dst_fmt, AST_FORMAT_SLINEAR, 0);
+ 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);
+
+ /* pick the best signed linear format based upon what preserves the sample rate the best. */
+ ast_format_set(&best_dst_fmt, ast_format_slin_by_rate(best_sample_rate), 0);
}
if (ast_set_read_format(from, &best_dst_fmt) < 0) {
diff --git a/main/data.c b/main/data.c
index 3ca2f7c27..2503cb57d 100644
--- a/main/data.c
+++ b/main/data.c
@@ -3111,11 +3111,12 @@ int ast_data_add_codec(struct ast_data *root, const char *node_name, struct ast_
if (!codecs) {
return -1;
}
- fmlist = ast_get_format_list(&fmlist_size);
+ fmlist = ast_format_list_get(&fmlist_size);
for (x = 0; x < fmlist_size; x++) {
- if (fmlist[x].id == format->id) {
+ 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);
@@ -3124,6 +3125,7 @@ int ast_data_add_codec(struct ast_data *root, const char *node_name, struct ast_
ast_data_add_int(codec, "frame_length", fmlist[x].fr_len);
}
}
+ ast_format_list_destroy(fmlist);
return 0;
}
@@ -3133,18 +3135,18 @@ int ast_data_add_codecs(struct ast_data *root, const char *node_name, struct ast
struct ast_data *codecs, *codec;
size_t fmlist_size;
const struct ast_format_list *fmlist;
- struct ast_format tmp_fmt;
int x;
codecs = ast_data_add_node(root, node_name);
if (!codecs) {
return -1;
}
- fmlist = ast_get_format_list(&fmlist_size);
+ fmlist = ast_format_list_get(&fmlist_size);
for (x = 0; x < fmlist_size; x++) {
- if (ast_format_cap_iscompatible(cap, ast_format_set(&tmp_fmt, fmlist[x].id, 0))) {
+ 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);
@@ -3153,6 +3155,7 @@ int ast_data_add_codecs(struct ast_data *root, const char *node_name, struct ast
ast_data_add_int(codec, "frame_length", fmlist[x].fr_len);
}
}
+ ast_format_list_destroy(fmlist);
return 0;
}
diff --git a/main/format.c b/main/format.c
index d77d244a6..28b15ae21 100644
--- a/main/format.c
+++ b/main/format.c
@@ -4,6 +4,7 @@
* Copyright (C) 2010, Digium, Inc.
*
* David Vossel <dvossel@digium.com>
+ * Mark Spencer <markster@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
@@ -21,6 +22,7 @@
* \brief Format API
*
* \author David Vossel <dvossel@digium.com>
+ * \author Mark Spencer <markster@digium.com>
*/
#include "asterisk.h"
@@ -32,6 +34,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
#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"
/*! This is the container for all the format attribute interfaces.
* An ao2 container was chosen for fast lookup. */
@@ -51,6 +60,17 @@ struct interface_ao2_wrapper {
ast_rwlock_t wraplock;
};
+/*! \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;
@@ -86,6 +106,23 @@ int ast_format_get_video_mark(const struct ast_format *format)
return format->fattr.rtp_marker_bit;
}
+static int has_interface(const struct ast_format *format)
+{
+ struct interface_ao2_wrapper *wrapper;
+ struct interface_ao2_wrapper tmp_wrapper = {
+ .id = format->id,
+ };
+
+ ast_rwlock_rdlock(&ilock);
+ if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) {
+ ast_rwlock_unlock(&ilock);
+ return 0;
+ }
+ ast_rwlock_unlock(&ilock);
+ ao2_ref(wrapper, -1);
+ return 1;
+}
+
static struct interface_ao2_wrapper *find_interface(const struct ast_format *format)
{
struct interface_ao2_wrapper *wrapper;
@@ -166,7 +203,7 @@ void ast_format_clear(struct ast_format *format)
/*! \internal
* \brief determine if a list of attribute key value pairs are set on a format
*/
-static int format_isset_helper(struct ast_format *format, va_list ap)
+static int format_isset_helper(const struct ast_format *format, va_list ap)
{
int res;
struct interface_ao2_wrapper *wrapper;
@@ -189,18 +226,24 @@ static int format_isset_helper(struct ast_format *format, va_list ap)
return -1;
}
- 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);
+ /* 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;
+ }
ast_rwlock_unlock(&wrapper->wraplock);
ao2_ref(wrapper, -1);
- return (res == AST_FORMAT_CMP_NOT_EQUAL) ? -1 : 0;
+ return res;
}
-int ast_format_isset(struct ast_format *format, ... )
+int ast_format_isset(const struct ast_format *format, ... )
{
va_list ap;
int res;
@@ -211,6 +254,29 @@ int ast_format_isset(struct ast_format *format, ... )
return res;
}
+int ast_format_get_value(const struct ast_format *format, int key, void *value)
+{
+ int res = 0;
+ struct interface_ao2_wrapper *wrapper;
+ if (!(wrapper = find_interface(format))) {
+ return -1;
+ }
+ ast_rwlock_rdlock(&wrapper->wraplock);
+ if (!wrapper->interface ||
+ !wrapper->interface->format_attr_get_val) {
+
+ ast_rwlock_unlock(&wrapper->wraplock);
+ ao2_ref(wrapper, -1);
+ return -1;
+ }
+
+ res = wrapper->interface->format_attr_get_val(&format->fattr, key, value);
+
+ ast_rwlock_unlock(&wrapper->wraplock);
+ ao2_ref(wrapper, -1);
+
+ return res;
+}
/*! \internal
* \brief cmp format attributes using an interface
@@ -372,6 +438,8 @@ uint64_t ast_format_id_to_old_bitfield(enum ast_format_id id)
/*! T.140 Text format - ITU T.140, RFC 4103 */
case AST_FORMAT_T140:
return (1ULL << 27);
+ default:
+ return 0; /* not supported by old bitfield. */
}
return 0;
@@ -486,20 +554,709 @@ enum ast_format_id ast_format_id_from_old_bitfield(uint64_t src)
return 0;
}
+int ast_format_is_slinear(const struct ast_format *format)
+{
+ 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;
+}
+
+enum ast_format_id ast_format_slin_by_rate(unsigned int rate)
+{
+ 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 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;
+ }
+ }
+ 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) = ')';
+ }
+ 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;
+ }
+ 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))) {
+
+ ast_format_copy(result, &f_list[x].format);
+ f_list = ast_format_list_destroy(f_list);
+ return result;
+ }
+ }
+ 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;
+}
+
+int ast_format_rate(const struct ast_format *format)
+{
+ 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;
+ }
+ default:
+ return 8000;
+ }
+}
+
+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:
+ return NULL;
+ }
+
+ if ((a->argc < 3) || (a->argc > 4)) {
+ return CLI_SHOWUSAGE;
+ }
+
+ 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");
+ }
+
+ 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;
+ }
+}
+
+static char *show_codec_n(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ 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;
+ }
+
+ 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);
+ break;
+ }
+ }
+
+ if (!found) {
+ ast_cli(a->fd, "Codec %d not found\n", format_id);
+ }
+
+ f_list = ast_format_list_destroy(f_list);
+ return CLI_SUCCESS;
+}
+
+/* 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"),
+};
+int init_framer(void)
+{
+ ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
+ return 0;
+}
+
+static int format_list_add_custom(struct ast_format_list *new)
+{
+ struct ast_format_list *entry;
+ 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);
+ return 0;
+}
+
+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;
+}
+static int list_hash_cb(const void *obj, const int flags)
+{
+ return ao2_container_count(format_list);
+}
+
+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);
+ }
+
+ /* 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++;
+ }
+ ao2_iterator_destroy(&it);
+
+ ast_rwlock_unlock(&format_list_array_lock);
+ return 0;
+}
+static int format_list_init(void)
+{
+ struct ast_format tmpfmt;
+ if (!(format_list = ao2_container_alloc(283, list_hash_cb, list_cmp_cb))) {
+ return -1;
+ }
+ /* 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, "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) */
+
+ return 0;
+}
+
+int ast_format_list_init()
+{
+ 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;
+ }
+
+ return 0;
+init_list_cleanup:
+
+ ast_rwlock_destroy(&format_list_array_lock);
+ ao2_ref(format_list, -1);
+ if (format_list_array) {
+ ao2_ref(format_list_array, -1);
+ }
+ return -1;
+}
+
int ast_format_attr_init()
{
+ ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
if (ast_rwlock_init(&ilock)) {
return -1;
}
+
if (!(interfaces = ao2_container_alloc(283, interface_hash_cb, interface_cmp_cb))) {
ast_rwlock_destroy(&ilock);
+ goto init_cleanup;
+ }
+ return 0;
+
+init_cleanup:
+ ast_rwlock_destroy(&ilock);
+ if (interfaces) {
+ ao2_ref(interfaces, -1);
+ }
+ return -1;
+}
+
+static int custom_silk_format(struct ast_format_list *entry, unsigned int maxbitrate, int usedtx, int usefec, int packetloss_percentage)
+{
+ 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 %d\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;
+}
+
+static int conf_process_format_name(const char *name, enum ast_format_id *id)
+{
+ if (!strcasecmp(name, "silk")) {
+ *id = AST_FORMAT_SILK;
+ } else {
+ *id = 0;
+ return -1;
+ }
+ return 0;
+}
+
+static int conf_process_sample_rate(const char *rate, unsigned int *result)
+{
+ 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, "48000")) {
+ *result = 48000;
+ } else {
+ *result = 0;
return -1;
}
+
+ return 0;
+}
+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 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, "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;
+ 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;
}
int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interface)
{
+ 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,
@@ -530,11 +1287,25 @@ int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interf
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);
+ }
+ }
+
return 0;
}
int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface)
{
+ 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,
@@ -554,5 +1325,16 @@ int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *inte
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();
+
return 0;
}
diff --git a/main/format_cap.c b/main/format_cap.c
index c8bdd4fa3..3ef0e74d3 100644
--- a/main/format_cap.c
+++ b/main/format_cap.c
@@ -99,7 +99,7 @@ void *ast_format_cap_destroy(struct ast_format_cap *cap)
return NULL;
}
-void ast_format_cap_add(struct ast_format_cap *cap, struct ast_format *format)
+void ast_format_cap_add(struct ast_format_cap *cap, const struct ast_format *format)
{
struct ast_format *fnew;
@@ -122,26 +122,26 @@ void ast_format_cap_add_all_by_type(struct ast_format_cap *cap, enum ast_format_
{
int x;
size_t f_len = 0;
- struct ast_format tmp_fmt;
- const struct ast_format_list *f_list = ast_get_format_list(&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_GET_TYPE(f_list[x].id) == type) {
- ast_format_cap_add(cap, ast_format_set(&tmp_fmt, f_list[x].id, 0));
+ if (AST_FORMAT_GET_TYPE(f_list[x].format.id) == type) {
+ ast_format_cap_add(cap, &f_list[x].format);
}
}
+ ast_format_list_destroy(f_list);
}
void ast_format_cap_add_all(struct ast_format_cap *cap)
{
int x;
size_t f_len = 0;
- struct ast_format tmp_fmt;
- const struct ast_format_list *f_list = ast_get_format_list(&f_len);
+ const struct ast_format_list *f_list = ast_format_list_get(&f_len);
for (x = 0; x < f_len; x++) {
- ast_format_cap_add(cap, ast_format_set(&tmp_fmt, f_list[x].id, 0));
+ ast_format_cap_add(cap, &f_list[x].format);
}
+ ast_format_list_destroy(f_list);
}
static int append_cb(void *obj, void *arg, int flag)
@@ -288,6 +288,21 @@ void ast_format_cap_set(struct ast_format_cap *cap, struct ast_format *format)
ast_format_cap_add(cap, format);
}
+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 *f;
+ struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
+ f = ao2_find(tmp_cap->formats, (struct ast_format *) format, OBJ_POINTER | tmp_cap->nolock);
+
+ if (f) {
+ ast_format_copy(result, f);
+ ao2_ref(f, -1);
+ return 1;
+ }
+ ast_format_clear(result);
+ return 0;
+}
+
int ast_format_cap_iscompatible(const struct ast_format_cap *cap, const struct ast_format *format)
{
struct ast_format *f;
@@ -302,6 +317,38 @@ int ast_format_cap_iscompatible(const struct ast_format_cap *cap, const struct a
return 0;
}
+struct byid_data {
+ struct ast_format *result;
+ enum ast_format_id id;
+};
+static int find_best_byid_cb(void *obj, void *arg, int flag)
+{
+ struct ast_format *format = obj;
+ struct byid_data *data = arg;
+
+ if (data->id != format->id) {
+ return 0;
+ }
+ if (!data->result->id || (ast_format_rate(data->result) < ast_format_rate(format))) {
+ ast_format_copy(data->result, format);
+ }
+ 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 | cap->nolock,
+ find_best_byid_cb,
+ &data);
+ return result->id ? 1 : 0;
+}
+
/*! \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
@@ -525,6 +572,42 @@ int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *form
return 0;
}
+char *ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap)
+{
+ 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;
+ }
+ }
+ 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;
+}
+
uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap)
{
uint64_t res = 0;
diff --git a/main/format_pref.c b/main/format_pref.c
index 26801b648..f24dbec27 100644
--- a/main/format_pref.c
+++ b/main/format_pref.c
@@ -34,7 +34,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
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_get_format_list(&f_len);
+ const const struct ast_format_list *f_list = ast_format_list_get(&f_len);
int x, differential = (int) 'A', mem;
char *from, *to;
@@ -57,9 +57,10 @@ void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size,
}
to[x] = right ? (from[x] + differential) : (from[x] - differential);
if (!right && to[x] && (to[x] < f_len)) {
- ast_format_set(&pref->formats[x], f_list[to[x]-1].id , 0);
+ 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)
@@ -67,7 +68,7 @@ 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;
- char *formatname;
+ const char *formatname;
memset(buf, 0, size);
total_len = size;
@@ -116,23 +117,27 @@ void ast_codec_pref_remove(struct ast_codec_pref *pref, struct ast_format *forma
struct ast_codec_pref oldorder;
int x, y = 0;
size_t f_len = 0;
- const struct ast_format_list *f_list = ast_get_format_list(&f_len);
+ const const struct ast_format_list *f_list;
- if (!pref->order[0])
+ 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])
+ if (!oldorder.order[x]) {
break;
- if (f_list[oldorder.order[x]-1].id != format->id) {
+ }
+ 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 codec to list */
@@ -140,12 +145,12 @@ 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_get_format_list(&f_len);
+ 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 (f_list[x].id == format->id) {
+ if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
newindex = x + 1;
break;
}
@@ -161,6 +166,7 @@ int ast_codec_pref_append(struct ast_codec_pref *pref, struct ast_format *format
}
}
+ ast_format_list_destroy(f_list);
return x;
}
@@ -169,18 +175,20 @@ void ast_codec_pref_prepend(struct ast_codec_pref *pref, struct ast_format *form
{
int x, newindex = 0;
size_t f_len = 0;
- const struct ast_format_list *f_list = ast_get_format_list(&f_len);
+ 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 (f_list[x].id == format->id) {
+ if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
newindex = x + 1;
break;
}
}
/* Done if its unknown */
- if (!newindex)
+ 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++) {
@@ -188,8 +196,10 @@ void ast_codec_pref_prepend(struct ast_codec_pref *pref, struct ast_format *form
break;
}
- if (only_if_existing && !pref->order[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) */
@@ -203,6 +213,7 @@ void ast_codec_pref_prepend(struct ast_codec_pref *pref, struct ast_format *form
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 */
@@ -210,17 +221,19 @@ int ast_codec_pref_setsize(struct ast_codec_pref *pref, struct ast_format *forma
{
int x, idx = -1;
size_t f_len = 0;
- const struct ast_format_list *f_list = ast_get_format_list(&f_len);
+ const struct ast_format_list *f_list = ast_format_list_get(&f_len);
for (x = 0; x < f_len; x++) {
- if (f_list[x].id == format->id) {
+ if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
idx = x;
break;
}
}
- if (idx < 0)
+ if (idx < 0) {
+ ast_format_list_destroy(f_list);
return -1;
+ }
/* size validation */
if (!framems)
@@ -242,6 +255,7 @@ int ast_codec_pref_setsize(struct ast_codec_pref *pref, struct ast_format *forma
}
}
+ ast_format_list_destroy(f_list);
return x;
}
@@ -249,12 +263,12 @@ int ast_codec_pref_setsize(struct ast_codec_pref *pref, struct ast_format *forma
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, };
+ struct ast_format_list fmt = { { 0, }, };
size_t f_len = 0;
- const struct ast_format_list *f_list = ast_get_format_list(&f_len);
+ const struct ast_format_list *f_list = ast_format_list_get(&f_len);
for (x = 0; x < f_len; x++) {
- if (f_list[x].id == format->id) {
+ if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
fmt = f_list[x];
idx = x;
break;
@@ -282,7 +296,7 @@ struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, struc
framems = f_list[idx].max_ms;
fmt.cur_ms = framems;
-
+ ast_format_list_destroy(f_list);
return fmt;
}
@@ -291,27 +305,23 @@ struct ast_format *ast_codec_choose(struct ast_codec_pref *pref, struct ast_form
{
int x, slot, found;
size_t f_len = 0;
- struct ast_format tmp_fmt;
-
- const struct ast_format_list *f_list = ast_get_format_list(&f_len);
-
- ast_format_clear(result);
+ 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_iscompatible(cap, ast_format_set(&tmp_fmt, f_list[slot-1].id, 0))) {
- found = 1; /*format is found and stored in tmp_fmt */
+ if (ast_format_cap_get_compatible_format(cap, &f_list[slot-1].format, result)) {
+ found = 1; /*format is found and stored in result */
break;
}
}
- if (found && (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_AUDIO)) {
- ast_format_copy(result, &tmp_fmt);
+ 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 6805fea46..d82a46313 100644
--- a/main/frame.c
+++ b/main/frame.c
@@ -92,38 +92,6 @@ struct ast_smoother {
int len;
};
-/*! \brief Definition of supported media formats (codecs) */
-static const struct ast_format_list AST_FORMAT_LIST[] = {
- { AST_FORMAT_G723_1 , "g723", 8000, "G.723.1", 20, 30, 300, 30, 30 }, /*!< G723.1 */
- { AST_FORMAT_GSM, "gsm", 8000, "GSM", 33, 20, 300, 20, 20 }, /*!< codec_gsm.c */
- { AST_FORMAT_ULAW, "ulaw", 8000, "G.711 u-law", 80, 10, 150, 10, 20 }, /*!< codec_ulaw.c */
- { AST_FORMAT_ALAW, "alaw", 8000, "G.711 A-law", 80, 10, 150, 10, 20 }, /*!< codec_alaw.c */
- { AST_FORMAT_G726, "g726", 8000, "G.726 RFC3551", 40, 10, 300, 10, 20 }, /*!< codec_g726.c */
- { AST_FORMAT_ADPCM, "adpcm" , 8000, "ADPCM", 40, 10, 300, 10, 20 }, /*!< codec_adpcm.c */
- { AST_FORMAT_SLINEAR, "slin", 8000, "16 bit Signed Linear PCM", 160, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE }, /*!< Signed linear */
- { AST_FORMAT_LPC10, "lpc10", 8000, "LPC10", 7, 20, 20, 20, 20 }, /*!< codec_lpc10.c */
- { AST_FORMAT_G729A, "g729", 8000, "G.729A", 10, 10, 230, 10, 20, AST_SMOOTHER_FLAG_G729 }, /*!< Binary commercial distribution */
- { AST_FORMAT_SPEEX, "speex", 8000, "SpeeX", 10, 10, 60, 10, 20 }, /*!< codec_speex.c */
- { AST_FORMAT_SPEEX16, "speex16", 16000, "SpeeX 16khz", 10, 10, 60, 10, 20 }, /*!< codec_speex.c */
- { AST_FORMAT_ILBC, "ilbc", 8000, "iLBC", 50, 30, 30, 30, 30 }, /*!< codec_ilbc.c */ /* inc=30ms - workaround */
- { AST_FORMAT_G726_AAL2, "g726aal2", 8000, "G.726 AAL2", 40, 10, 300, 10, 20 }, /*!< codec_g726.c */
- { AST_FORMAT_G722, "g722", 16000, "G722", 80, 10, 150, 10, 20 }, /*!< codec_g722.c */
- { AST_FORMAT_SLINEAR16, "slin16", 16000, "16 bit Signed Linear PCM (16kHz)", 320, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE }, /*!< Signed linear (16kHz) */
- { AST_FORMAT_JPEG, "jpeg", 0, "JPEG image"}, /*!< See format_jpeg.c */
- { AST_FORMAT_PNG, "png", 0, "PNG image"}, /*!< PNG Image format */
- { AST_FORMAT_H261, "h261", 0, "H.261 Video" }, /*!< H.261 Video Passthrough */
- { AST_FORMAT_H263, "h263", 0, "H.263 Video" }, /*!< H.263 Passthrough support, see format_h263.c */
- { AST_FORMAT_H263_PLUS, "h263p", 0, "H.263+ Video" }, /*!< H.263plus passthrough support See format_h263.c */
- { AST_FORMAT_H264, "h264", 0, "H.264 Video" }, /*!< Passthrough support, see format_h263.c */
- { AST_FORMAT_MP4_VIDEO, "mpeg4", 0, "MPEG4 Video" }, /*!< Passthrough support for MPEG4 */
- { AST_FORMAT_T140RED, "red", 1, "T.140 Realtime Text with redundancy"}, /*!< Redundant T.140 Realtime Text */
- { AST_FORMAT_T140, "t140", 0, "Passthrough T.140 Realtime Text" }, /*!< Passthrough support for T.140 Realtime Text */
- { AST_FORMAT_SIREN7, "siren7", 16000, "ITU G.722.1 (Siren7, licensed from Polycom)", 80, 20, 80, 20, 20 }, /*!< Binary commercial distribution */
- { AST_FORMAT_SIREN14, "siren14", 32000, "ITU G.722.1 Annex C, (Siren14, licensed from Polycom)", 120, 20, 80, 20, 20 }, /*!< Binary commercial distribution */
- { AST_FORMAT_TESTLAW, "testlaw", 8000, "G.711 test-law", 80, 10, 150, 10, 20 }, /*!< codec_ulaw.c */
- { AST_FORMAT_G719, "g719", 48000, "ITU G.719", 160, 20, 80, 20, 20 },
-};
-
struct ast_frame ast_null_frame = { AST_FRAME_NULL, };
static int smoother_frame_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
@@ -554,218 +522,6 @@ void ast_swapcopy_samples(void *dst, const void *src, int samples)
dst_s[i] = (src_s[i]<<8) | (src_s[i]>>8);
}
-
-const struct ast_format_list *ast_get_format_list_index(int idx)
-{
- return &AST_FORMAT_LIST[idx];
-}
-
-const struct ast_format_list *ast_get_format_list(size_t *size)
-{
- *size = ARRAY_LEN(AST_FORMAT_LIST);
- return AST_FORMAT_LIST;
-}
-
-char* ast_getformatname(struct ast_format *format)
-{
- int x;
- char *ret = "unknown";
- for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- if (AST_FORMAT_LIST[x].id == format->id) {
- ret = AST_FORMAT_LIST[x].name;
- break;
- }
- }
- return ret;
-}
-
-char *ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap)
-{
- int x;
- unsigned len;
- char *start, *end = buf;
- struct ast_format tmp_fmt;
-
- if (!size)
- return buf;
- snprintf(end, size, "(");
- len = strlen(end);
- end += len;
- size -= len;
- start = end;
- for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- ast_format_set(&tmp_fmt, AST_FORMAT_LIST[x].id, 0);
- if (ast_format_cap_iscompatible(cap, &tmp_fmt)) {
- snprintf(end, size, "%s|", AST_FORMAT_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) = ')';
- return buf;
-}
-
-static struct ast_codec_alias_table {
- char *alias;
- 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;
- }
- return in;
-}
-
-struct ast_format *ast_getformatbyname(const char *name, struct ast_format *result)
-{
- int x;
-
- for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- if (!strcasecmp(AST_FORMAT_LIST[x].name,name) ||
- !strcasecmp(AST_FORMAT_LIST[x].name, ast_expand_codec_alias(name))) {
-
- ast_format_set(result, AST_FORMAT_LIST[x].id, 0);
- return result;
- }
- }
-
- return NULL;
-}
-
-char *ast_codec2str(struct ast_format *format)
-{
- int x;
- char *ret = "unknown";
- for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- if (AST_FORMAT_LIST[x].id == format->id) {
- ret = AST_FORMAT_LIST[x].desc;
- break;
- }
- }
- return ret;
-}
-
-static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
- int x, found=0;
-
- 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");
-
- for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- if (a->argc == 4) {
- if (!strcasecmp(a->argv[3], "audio")) {
- if (AST_FORMAT_GET_TYPE(AST_FORMAT_LIST[x].id) != AST_FORMAT_TYPE_AUDIO) {
- continue;
- }
- } else if (!strcasecmp(a->argv[3], "video")) {
- if (AST_FORMAT_GET_TYPE(AST_FORMAT_LIST[x].id) != AST_FORMAT_TYPE_VIDEO) {
- continue;
- }
- } else if (!strcasecmp(a->argv[3], "image")) {
- if (AST_FORMAT_GET_TYPE(AST_FORMAT_LIST[x].id) != AST_FORMAT_TYPE_IMAGE) {
- continue;
- }
- } else if (!strcasecmp(a->argv[3], "text")) {
- if (AST_FORMAT_GET_TYPE(AST_FORMAT_LIST[x].id) != AST_FORMAT_TYPE_TEXT) {
- continue;
- }
- } else {
- continue;
- }
- }
-
- ast_cli(a->fd, "%8u %5s %8s (%s)\n",
- AST_FORMAT_LIST[x].id,
- (AST_FORMAT_GET_TYPE(AST_FORMAT_LIST[x].id) == AST_FORMAT_TYPE_AUDIO) ? "audio" :
- (AST_FORMAT_GET_TYPE(AST_FORMAT_LIST[x].id) == AST_FORMAT_TYPE_IMAGE) ? "image" :
- (AST_FORMAT_GET_TYPE(AST_FORMAT_LIST[x].id) == AST_FORMAT_TYPE_VIDEO) ? "video" :
- (AST_FORMAT_GET_TYPE(AST_FORMAT_LIST[x].id) == AST_FORMAT_TYPE_TEXT) ? "text" :
- "(unk)",
- AST_FORMAT_LIST[x].name,
- AST_FORMAT_LIST[x].desc);
- found = 1;
- }
-
- if (!found) {
- return CLI_SHOWUSAGE;
- } else {
- return CLI_SUCCESS;
- }
-}
-
-static char *show_codec_n(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
- enum ast_format_id format_id;
- int x, found = 0;
- int type_punned_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;
- }
- format_id = type_punned_codec;
-
- for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- if (AST_FORMAT_LIST[x].id == format_id) {
- found = 1;
- ast_cli(a->fd, "%11u %s\n", (unsigned int) format_id, AST_FORMAT_LIST[x].desc);
- break;
- }
- }
-
- if (!found)
- ast_cli(a->fd, "Codec %d not found\n", format_id);
-
- return CLI_SUCCESS;
-}
-
/*! Dump a frame for debugging purposes */
void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix)
{
@@ -972,19 +728,6 @@ void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix)
term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
}
-
-/* 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"),
-};
-
-int init_framer(void)
-{
- ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
- return 0;
-}
-
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;
@@ -1202,6 +945,9 @@ int ast_codec_get_samples(struct ast_frame *f)
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;
@@ -1246,6 +992,25 @@ int ast_codec_get_samples(struct ast_frame *f)
/* 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;
+ }
default:
ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(&f->subclass.format));
}
@@ -1310,11 +1075,13 @@ int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
short *fdata = f->data.ptr;
short adjust_value = abs(adjustment);
- if ((f->frametype != AST_FRAME_VOICE) || (f->subclass.format.id != AST_FORMAT_SLINEAR))
+ if ((f->frametype != AST_FRAME_VOICE) || !(ast_format_is_slinear(&f->subclass.format))) {
return -1;
+ }
- if (!adjustment)
+ if (!adjustment) {
return 0;
+ }
for (count = 0; count < f->samples; count++) {
if (adjustment > 0) {
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 738b58fae..b2543893a 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -39,6 +39,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/pbx.h"
#include "asterisk/translate.h"
#include "asterisk/netsock2.h"
+#include "asterisk/_private.h"
struct ast_srtp_res *res_srtp = NULL;
struct ast_srtp_policy_res *res_srtp_policy = NULL;
@@ -83,50 +84,14 @@ static AST_RWLIST_HEAD_STATIC(glues, ast_rtp_glue);
/*! The following array defines the MIME Media type (and subtype) for each
of our codecs, or RTP-specific data type. */
-static const struct ast_rtp_mime_type {
+static struct ast_rtp_mime_type {
struct ast_rtp_payload_type payload_type;
char *type;
char *subtype;
unsigned int sample_rate;
-} ast_rtp_mime_types[] = {
- {{1, {.id = AST_FORMAT_G723_1}, 0}, "audio", "G723", 8000},
- {{1, {.id = AST_FORMAT_GSM}, 0}, "audio", "GSM", 8000},
- {{1, {.id = AST_FORMAT_ULAW}, 0}, "audio", "PCMU", 8000},
- {{1, {.id = AST_FORMAT_ULAW}, 0}, "audio", "G711U", 8000},
- {{1, {.id = AST_FORMAT_ALAW}, 0}, "audio", "PCMA", 8000},
- {{1, {.id = AST_FORMAT_ALAW}, 0}, "audio", "G711A", 8000},
- {{1, {.id = AST_FORMAT_G726}, 0}, "audio", "G726-32", 8000},
- {{1, {.id = AST_FORMAT_ADPCM}, 0}, "audio", "DVI4", 8000},
- {{1, {.id = AST_FORMAT_SLINEAR}, 0}, "audio", "L16", 8000},
- {{1, {.id = AST_FORMAT_SLINEAR16}, 0}, "audio", "L16", 16000},
- {{1, {.id = AST_FORMAT_LPC10}, 0}, "audio", "LPC", 8000},
- {{1, {.id = AST_FORMAT_G729A}, 0}, "audio", "G729", 8000},
- {{1, {.id = AST_FORMAT_G729A}, 0}, "audio", "G729A", 8000},
- {{1, {.id = AST_FORMAT_G729A}, 0}, "audio", "G.729", 8000},
- {{1, {.id = AST_FORMAT_SPEEX}, 0}, "audio", "speex", 8000},
- {{1, {.id = AST_FORMAT_SPEEX16}, 0}, "audio", "speex", 16000},
- {{1, {.id = 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
- */
- {{1, {.id = AST_FORMAT_G722}, 0}, "audio", "G722", 8000},
- {{1, {.id = AST_FORMAT_G726_AAL2}, 0}, "audio", "AAL2-G726-32", 8000},
- {{0, {.id = 0}, AST_RTP_DTMF}, "audio", "telephone-event", 8000},
- {{0, {.id = 0}, AST_RTP_CISCO_DTMF}, "audio", "cisco-telephone-event", 8000},
- {{0, {.id = 0}, AST_RTP_CN}, "audio", "CN", 8000},
- {{1, {.id = AST_FORMAT_JPEG}, 0}, "video", "JPEG", 90000},
- {{1, {.id = AST_FORMAT_PNG}, 0}, "video", "PNG", 90000},
- {{1, {.id = AST_FORMAT_H261}, 0}, "video", "H261", 90000},
- {{1, {.id = AST_FORMAT_H263}, 0}, "video", "H263", 90000},
- {{1, {.id = AST_FORMAT_H263_PLUS}, 0}, "video", "h263-1998", 90000},
- {{1, {.id = AST_FORMAT_H264}, 0}, "video", "H264", 90000},
- {{1, {.id = AST_FORMAT_MP4_VIDEO}, 0}, "video", "MP4V-ES", 90000},
- {{1, {.id = AST_FORMAT_T140RED}, 0}, "text", "RED", 1000},
- {{1, {.id = AST_FORMAT_T140}, 0}, "text", "T140", 1000},
- {{1, {.id = AST_FORMAT_SIREN7}, 0}, "audio", "G7221", 16000},
- {{1, {.id = AST_FORMAT_SIREN14}, 0}, "audio", "G7221", 32000},
- {{1, {.id = AST_FORMAT_G719}, 0}, "audio", "G719", 48000},
-};
+} ast_rtp_mime_types[128]; /* This will Likely not need to grow any time soon. */
+static ast_rwlock_t mime_types_lock;
+static int mime_types_len = 0;
/*!
* \brief Mapping between Asterisk codecs and rtp payload types
@@ -138,46 +103,8 @@ static const struct ast_rtp_mime_type {
* See http://www.iana.org/assignments/rtp-parameters for a list of
* assigned values
*/
-static const struct ast_rtp_payload_type static_RTP_PT[AST_RTP_MAX_PT] = {
- [0] = {1, {.id = AST_FORMAT_ULAW}, 0},
- #ifdef USE_DEPRECATED_G726
- [2] = {1, {.id = AST_FORMAT_G726}, 0},/* Technically this is G.721, but if Cisco can do it, so can we... */
- #endif
- [3] = {1, {.id = AST_FORMAT_GSM}, 0},
- [4] = {1, {.id = AST_FORMAT_G723_1}, 0},
- [5] = {1, {.id = AST_FORMAT_ADPCM}, 0},/* 8 kHz */
- [6] = {1, {.id = AST_FORMAT_ADPCM}, 0}, /* 16 kHz */
- [7] = {1, {.id = AST_FORMAT_LPC10}, 0},
- [8] = {1, {.id = AST_FORMAT_ALAW}, 0},
- [9] = {1, {.id = AST_FORMAT_G722}, 0},
- [10] = {1, {.id = AST_FORMAT_SLINEAR}, 0}, /* 2 channels */
- [11] = {1, {.id = AST_FORMAT_SLINEAR}, 0}, /* 1 channel */
- [13] = {0, {.id = 0}, AST_RTP_CN},
- [16] = {1, {.id = AST_FORMAT_ADPCM}, 0}, /* 11.025 kHz */
- [17] = {1, {.id = AST_FORMAT_ADPCM}, 0}, /* 22.050 kHz */
- [18] = {1, {.id = AST_FORMAT_G729A}, 0},
- [19] = {0, {.id = 0}, AST_RTP_CN}, /* Also used for CN */
- [26] = {1, {.id = AST_FORMAT_JPEG}, 0},
- [31] = {1, {.id = AST_FORMAT_H261}, 0},
- [34] = {1, {.id = AST_FORMAT_H263}, 0},
- [97] = {1, {.id = AST_FORMAT_ILBC}, 0},
- [98] = {1, {.id = AST_FORMAT_H263_PLUS}, 0},
- [99] = {1, {.id = AST_FORMAT_H264}, 0},
- [101] = {0, {.id = 0}, AST_RTP_DTMF},
- [102] = {1, {.id = AST_FORMAT_SIREN7}, 0},
- [103] = {1, {.id = AST_FORMAT_H263_PLUS}, 0},
- [104] = {1, {.id = AST_FORMAT_MP4_VIDEO}, 0},
- [105] = {1, {.id = AST_FORMAT_T140RED}, 0}, /* Real time text chat (with redundancy encoding) */
- [106] = {1, {.id = AST_FORMAT_T140}, 0}, /* Real time text chat */
- [110] = {1, {.id = AST_FORMAT_SPEEX}, 0},
- [111] = {1, {.id = AST_FORMAT_G726}, 0},
- [112] = {1, {.id = AST_FORMAT_G726_AAL2}, 0},
- [115] = {1, {.id = AST_FORMAT_SIREN14}, 0},
- [116] = {1, {.id = AST_FORMAT_G719}, 0},
- [117] = {1, {.id = AST_FORMAT_SPEEX16}, 0},
- [118] = {1, {.id = AST_FORMAT_SLINEAR16}, 0}, /* 16 Khz signed linear */
- [121] = {0, {.id = 0}, AST_RTP_CISCO_DTMF}, /* Must be type 121 */
-};
+static struct ast_rtp_payload_type static_RTP_PT[AST_RTP_MAX_PT];
+static ast_rwlock_t static_RTP_PT_lock;
int ast_rtp_engine_register2(struct ast_rtp_engine *engine, struct ast_module *module)
{
@@ -497,6 +424,7 @@ void ast_rtp_codecs_payloads_default(struct ast_rtp_codecs *codecs, struct ast_r
{
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) {
@@ -508,6 +436,7 @@ void ast_rtp_codecs_payloads_default(struct ast_rtp_codecs *codecs, struct ast_r
}
}
}
+ 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)
@@ -529,7 +458,10 @@ void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_cod
void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload)
{
+
+ ast_rwlock_rdlock(&static_RTP_PT_lock);
if (payload < 0 || payload >= AST_RTP_MAX_PT || (!static_RTP_PT[payload].rtp_code && !static_RTP_PT[payload].asterisk_format)) {
+ ast_rwlock_unlock(&static_RTP_PT_lock);
return;
}
@@ -542,6 +474,7 @@ void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct as
if (instance && instance->engine && instance->engine->payload_set) {
instance->engine->payload_set(instance, payload, codecs->payloads[payload].asterisk_format, &codecs->payloads[payload].format, codecs->payloads[payload].rtp_code);
}
+ ast_rwlock_unlock(&static_RTP_PT_lock);
}
int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int pt,
@@ -555,7 +488,8 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs,
if (pt < 0 || pt >= AST_RTP_MAX_PT)
return -1; /* bogus payload type */
- for (i = 0; i < ARRAY_LEN(ast_rtp_mime_types); ++i) {
+ ast_rwlock_rdlock(&mime_types_lock);
+ for (i = 0; i < mime_types_len; ++i) {
const struct ast_rtp_mime_type *t = &ast_rtp_mime_types[i];
if (strcasecmp(mimesubtype, t->subtype)) {
@@ -587,6 +521,7 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs,
break;
}
+ ast_rwlock_unlock(&mime_types_lock);
return (found ? 0 : -2);
}
@@ -626,12 +561,26 @@ struct ast_rtp_payload_type ast_rtp_codecs_payload_lookup(struct ast_rtp_codecs
ast_format_copy(&result.format, &codecs->payloads[payload].format);
if (!result.rtp_code && !result.asterisk_format) {
+ ast_rwlock_rdlock(&static_RTP_PT_lock);
result = static_RTP_PT[payload];
+ ast_rwlock_unlock(&static_RTP_PT_lock);
}
return result;
}
+
+struct ast_format *ast_rtp_codecs_get_payload_format(struct ast_rtp_codecs *codecs, int payload)
+{
+ if (payload < 0 || payload >= AST_RTP_MAX_PT) {
+ return NULL;
+ }
+ if (!codecs->payloads[payload].asterisk_format) {
+ return NULL;
+ }
+ return &codecs->payloads[payload].format;
+}
+
void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_format_cap *astformats, int *nonastformats)
{
int i;
@@ -654,7 +603,7 @@ void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_fo
int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code)
{
int i;
-
+ int res = -1;
for (i = 0; i < AST_RTP_MAX_PT; i++) {
if (codecs->payloads[i].asterisk_format && asterisk_format && format &&
(ast_format_cmp(format, &codecs->payloads[i].format) != AST_FORMAT_CMP_NOT_EQUAL)) {
@@ -665,56 +614,71 @@ int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_form
}
}
+ 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)) {
- return i;
+ res = i;
+ break;
} else if (!static_RTP_PT[i].asterisk_format && !asterisk_format &&
(static_RTP_PT[i].rtp_code == code)) {
- return i;
+ res = i;
+ break;
}
}
+ ast_rwlock_unlock(&static_RTP_PT_lock);
- return -1;
+ 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;
+ const char *res = "";
- for (i = 0; i < ARRAY_LEN(ast_rtp_mime_types); i++) {
+ 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)) {
- return "G726-32";
+ res = "G726-32";
+ break;
} else {
- return ast_rtp_mime_types[i].subtype;
+ res = ast_rtp_mime_types[i].subtype;
+ break;
}
} else if (!ast_rtp_mime_types[i].payload_type.asterisk_format && !asterisk_format &&
ast_rtp_mime_types[i].payload_type.rtp_code == code) {
- return ast_rtp_mime_types[i].subtype;
+ res = ast_rtp_mime_types[i].subtype;
+ break;
}
}
+ ast_rwlock_unlock(&mime_types_lock);
- return "";
+ return res;
}
unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, struct ast_format *format, int code)
{
unsigned int i;
+ unsigned int res = 0;
- for (i = 0; i < ARRAY_LEN(ast_rtp_mime_types); ++i) {
+ 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)) {
- return ast_rtp_mime_types[i].sample_rate;
+ res = ast_rtp_mime_types[i].sample_rate;
+ break;
} else if (!ast_rtp_mime_types[i].payload_type.asterisk_format && !asterisk_format &&
ast_rtp_mime_types[i].payload_type.rtp_code == code) {
- return ast_rtp_mime_types[i].sample_rate;
+ res = ast_rtp_mime_types[i].sample_rate;
+ break;
}
}
+ ast_rwlock_unlock(&mime_types_lock);
- return 0;
+ return res;
}
char *ast_rtp_lookup_mime_multiple2(struct ast_str *buf, struct ast_format_cap *ast_format_capability, int rtp_capability, const int asterisk_format, enum ast_rtp_options options)
@@ -1879,3 +1843,185 @@ struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance)
{
return instance->srtp;
}
+
+static void set_next_mime_type(const struct ast_format *format, int rtp_code, char *type, char *subtype, unsigned int sample_rate)
+{
+ int x = mime_types_len;
+ if (ARRAY_LEN(ast_rtp_mime_types) == mime_types_len) {
+ return;
+ }
+
+ ast_rwlock_wrlock(&mime_types_lock);
+ if (format) {
+ ast_rtp_mime_types[x].payload_type.asterisk_format = 1;
+ ast_format_copy(&ast_rtp_mime_types[x].payload_type.format, 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_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)
+{
+ int x;
+ ast_rwlock_wrlock(&static_RTP_PT_lock);
+ if (map < 0) {
+ /* find next available dynamic payload slot */
+ for (x = 96; x < 127; x++) {
+ if (!static_RTP_PT[x].asterisk_format && !static_RTP_PT[x].rtp_code) {
+ map = x;
+ break;
+ }
+ }
+ }
+
+ if (map < 0) {
+ ast_log(LOG_WARNING, "No Dynamic RTP mapping avaliable for format %s\n" ,ast_getformatname(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);
+ } 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)
+{
+ 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;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int ast_rtp_engine_unload_format(const struct ast_format *format)
+{
+ int x;
+ int y = 0;
+
+ 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));
+ }
+ }
+ 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) {
+ continue;
+ }
+ ast_rtp_mime_types[y] = ast_rtp_mime_types[x];
+ y++;
+ }
+ mime_types_len = y;
+ ast_rwlock_unlock(&mime_types_lock);
+ return 0;
+}
+
+int ast_rtp_engine_init()
+{
+ struct ast_format tmpfmt;
+
+ ast_rwlock_init(&mime_types_lock);
+ ast_rwlock_init(&static_RTP_PT_lock);
+
+ /* 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_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);
+ /* 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(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);
+
+ /* Define the static rtp payload mappings */
+ add_static_payload(0, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0), 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... */
+ #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(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(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(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(121, NULL, AST_RTP_CISCO_DTMF); /* Must be type 121 */
+
+ return 0;
+}
diff --git a/main/slinfactory.c b/main/slinfactory.c
index f7363ab4b..338305b40 100644
--- a/main/slinfactory.c
+++ b/main/slinfactory.c
@@ -39,20 +39,14 @@ void ast_slinfactory_init(struct ast_slinfactory *sf)
ast_format_set(&sf->output_format, AST_FORMAT_SLINEAR, 0);
}
-int ast_slinfactory_init_rate(struct ast_slinfactory *sf, unsigned int sample_rate)
+int ast_slinfactory_init_with_format(struct ast_slinfactory *sf, const struct ast_format *slin_out)
{
memset(sf, 0, sizeof(*sf));
sf->offset = sf->hold;
- switch (sample_rate) {
- case 8000:
- ast_format_set(&sf->output_format, AST_FORMAT_SLINEAR, 0);
- break;
- case 16000:
- ast_format_set(&sf->output_format, AST_FORMAT_SLINEAR16, 0);
- break;
- default:
+ if (!ast_format_is_slinear(slin_out)) {
return -1;
}
+ ast_format_copy(&sf->output_format, slin_out);
return 0;
}
@@ -93,8 +87,11 @@ int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
if (!sf->trans) {
if (!(sf->trans = ast_translator_build_path(&sf->output_format, &f->subclass.format))) {
- ast_log(LOG_WARNING, "Cannot build a path from %s to %s\n", ast_getformatname(&f->subclass.format),
- ast_getformatname(&sf->output_format));
+ ast_log(LOG_WARNING, "Cannot build a path from %s (%d)to %s (%d)\n",
+ ast_getformatname(&f->subclass.format),
+ f->subclass.format.id,
+ ast_getformatname(&sf->output_format),
+ sf->output_format.id);
return 0;
}
ast_format_copy(&sf->format, &f->subclass.format);
diff --git a/main/translate.c b/main/translate.c
index 553e70cde..caba2d393 100644
--- a/main/translate.c
+++ b/main/translate.c
@@ -273,7 +273,7 @@ static struct translator_path *matrix_get(unsigned int x, unsigned int y)
* \brief Allocate the descriptor, required outbuf space,
* and possibly desc.
*/
-static void *newpvt(struct ast_translator *t)
+static void *newpvt(struct ast_translator *t, const struct ast_format *explicit_dst)
{
struct ast_trans_pvt *pvt;
int len;
@@ -287,16 +287,23 @@ static void *newpvt(struct ast_translator *t)
if (t->buf_size)
len += AST_FRIENDLY_OFFSET + t->buf_size;
pvt = ast_calloc(1, len);
- if (!pvt)
+ if (!pvt) {
return NULL;
+ }
pvt->t = t;
ofs = (char *)(pvt + 1); /* pointer to data space */
if (t->desc_size) { /* first comes the descriptor */
pvt->pvt = ofs;
ofs += t->desc_size;
}
- if (t->buf_size) /* finally buffer and header */
+ 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);
+ }
/* call local init routine, if present */
if (t->newpvt && t->newpvt(pvt)) {
ast_free(pvt);
@@ -424,6 +431,7 @@ 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);
@@ -434,7 +442,10 @@ struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct a
AST_RWLIST_UNLOCK(&translators);
return NULL;
}
- if (!(cur = newpvt(t))) {
+ 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);
ast_log(LOG_WARNING, "Failed to build translator step from %s to %s\n",
@@ -565,12 +576,12 @@ static void generate_computational_cost(struct ast_translator *t, int seconds)
/* If they don't make samples, give them a terrible score */
if (!t->sample) {
- ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name);
+ ast_debug(3, "Translator '%s' does not produce sample frames.\n", t->name);
t->comp_cost = 999999;
return;
}
- pvt = newpvt(t);
+ pvt = newpvt(t, NULL);
if (!pvt) {
ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
t->comp_cost = 999999;
@@ -641,13 +652,8 @@ static int generate_table_cost(struct ast_format *src, struct ast_format *dst)
* table cost. */
return 0;
}
- if ((src->id == AST_FORMAT_SLINEAR) || (src->id == AST_FORMAT_SLINEAR16)) {
- src_ll = 1;
- }
- if ((dst->id == AST_FORMAT_SLINEAR) || (dst->id == AST_FORMAT_SLINEAR16)) {
- dst_ll = 1;
- }
-
+ src_ll = ast_format_is_slinear(src);
+ dst_ll = ast_format_is_slinear(dst);
if (src_ll) {
if (dst_ll && (src_rate == dst_rate)) {
return AST_TRANS_COST_LL_LL_ORIGSAMP;
@@ -778,16 +784,17 @@ static void matrix_rebuild(int samples)
const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **str)
{
struct ast_trans_pvt *pn = p;
+ char tmp[256];
if (!p || !p->t) {
return "";
}
- ast_str_set(str, 0, "%s", ast_getformatname(&p->t->src_format));
+ 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(&p->t->dst_format));
+ ast_str_append(str, 0, "->%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), p->t->dst_format.id));
}
return ast_str_buffer(*str);
@@ -800,10 +807,10 @@ static char *complete_trans_path_choice(const char *line, const char *word, int
int i;
char *ret = NULL;
size_t len = 0;
- const struct ast_format_list *format_list = ast_get_format_list(&len);
+ const struct ast_format_list *format_list = ast_format_list_get(&len);
for (i = 0; i < len; i++) {
- if (AST_FORMAT_GET_TYPE(format_list[i].id) != AST_FORMAT_TYPE_AUDIO) {
+ if (AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) {
continue;
}
if (!strncasecmp(word, format_list[i].name, wordlen) && ++which > state) {
@@ -811,6 +818,7 @@ static char *complete_trans_path_choice(const char *line, const char *word, int
break;
}
}
+ ast_format_list_destroy(format_list);
return ret;
}
@@ -835,46 +843,56 @@ static void handle_cli_recalc(struct ast_cli_args *a)
static char *handle_show_translation_table(struct ast_cli_args *a)
{
- int x, y;
+ int x, y, i, k;
int curlen = 0, longest = 0;
- struct ast_format tmp_fmt;
+ int f_len = 0;
+ const struct ast_format_list *f_list = ast_format_list_get((size_t *) &f_len);
+ struct ast_str *out = ast_str_create(1024);
+
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 (x = 0; x < cur_max_index; x++) {
+ for (i = 0; i < f_len; i++) {
/* translation only applies to audio right now. */
- if (AST_FORMAT_GET_TYPE(index2format(x)) != AST_FORMAT_TYPE_AUDIO)
+ if (AST_FORMAT_GET_TYPE(f_list[i].format.id) != AST_FORMAT_TYPE_AUDIO)
continue;
- curlen = strlen(ast_getformatname(ast_format_set(&tmp_fmt, index2format(x), 0)));
+ curlen = strlen(ast_getformatname(&f_list[i].format));
if (curlen > longest) {
longest = curlen;
}
}
- for (x = -1; x < cur_max_index; x++) {
- struct ast_str *out = ast_str_alloca(256);
+ for (i = -1; i < f_len; i++) {
+ x = -1;
+ if ((i >= 0) && ((x = format2index(f_list[i].format.id)) == -1)) {
+ continue;
+ }
/* translation only applies to audio right now. */
- if (x >= 0 && (AST_FORMAT_GET_TYPE(index2format(x)) != AST_FORMAT_TYPE_AUDIO)) {
+ if (i >= 0 && (AST_FORMAT_GET_TYPE(f_list[i].format.id) != AST_FORMAT_TYPE_AUDIO)) {
continue;
}
/*Go ahead and move to next iteration if dealing with an unknown codec*/
- if (x >= 0 && !strcmp(ast_getformatname(ast_format_set(&tmp_fmt, index2format(x), 0)), "unknown")) {
+ if (i >= 0 && !strcmp(ast_getformatname(&f_list[i].format), "unknown")) {
continue;
}
- ast_str_set(&out, -1, " ");
- for (y = -1; y < cur_max_index; y++) {
+ ast_str_set(&out, 0, " ");
+ for (k = -1; k < f_len; k++) {
+ y = -1;
+ if ((k >= 0) && ((y = format2index(f_list[k].format.id)) == -1)) {
+ continue;
+ }
/* translation only applies to audio right now. */
- if (y >= 0 && (AST_FORMAT_GET_TYPE(index2format(y)) != AST_FORMAT_TYPE_AUDIO)) {
+ 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 (y >= 0 && !strcmp(ast_getformatname(ast_format_set(&tmp_fmt, index2format(y), 0)), "unknown")) {
+ if (k >= 0 && !strcmp(ast_getformatname(&f_list[k].format), "unknown")) {
continue;
}
- if (y >= 0) {
- curlen = strlen(ast_getformatname(ast_format_set(&tmp_fmt, index2format(y), 0)));
+ if (k >= 0) {
+ curlen = strlen(ast_getformatname(&f_list[k].format));
}
if (curlen < 5) {
curlen = 5;
@@ -882,25 +900,27 @@ 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, -1, "%*d", curlen + 1, (matrix_get(x, y)->table_cost/100));
- } else if (x == -1 && y >= 0) {
+ ast_str_append(&out, 0, "%*d", curlen + 1, (matrix_get(x, y)->table_cost/100));
+ } else if (i == -1 && k >= 0) {
/* Top row - use a dynamic size */
- ast_str_append(&out, -1, "%*s", curlen + 1, ast_getformatname(ast_format_set(&tmp_fmt, index2format(y), 0)));
- } else if (y == -1 && x >= 0) {
+ ast_str_append(&out, 0, "%*s", curlen + 1, ast_getformatname(&f_list[k].format));
+ } else if (k == -1 && i >= 0) {
/* Left column - use a static size. */
- ast_str_append(&out, -1, "%*s", longest, ast_getformatname(ast_format_set(&tmp_fmt, index2format(x), 0)));
+ ast_str_append(&out, 0, "%*s", longest, ast_getformatname(&f_list[i].format));
} else if (x >= 0 && y >= 0) {
/* Codec not supported */
- ast_str_append(&out, -1, "%*s", curlen + 1, "-");
+ ast_str_append(&out, 0, "%*s", curlen + 1, "-");
} else {
/* Upper left hand corner */
- ast_str_append(&out, -1, "%*s", longest, "");
+ ast_str_append(&out, 0, "%*s", longest, "");
}
}
- ast_str_append(&out, -1, "\n");
+ ast_str_append(&out, 0, "\n");
ast_cli(a->fd, "%s", ast_str_buffer(out));
}
+ ast_free(out);
AST_RWLIST_UNLOCK(&translators);
+ ast_format_list_destroy(f_list);
return CLI_SUCCESS;
}
@@ -909,23 +929,24 @@ static char *handle_show_translation_path(struct ast_cli_args *a)
struct ast_format input_src_format;
size_t len = 0;
int i;
- const struct ast_format_list *format_list = ast_get_format_list(&len);
- struct ast_str *str = ast_str_alloca(256);
+ const struct ast_format_list *format_list = ast_format_list_get(&len);
+ struct ast_str *str = ast_str_alloca(1024);
struct ast_translator *step;
+ char tmp[256];
ast_format_clear(&input_src_format);
-
for (i = 0; i < len; i++) {
- if (AST_FORMAT_GET_TYPE(format_list[i].id) != AST_FORMAT_TYPE_AUDIO) {
+ 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_set(&input_src_format, format_list[i].id, 0);
+ 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);
return CLI_FAILURE;
}
@@ -934,21 +955,21 @@ static char *handle_show_translation_path(struct ast_cli_args *a)
for (i = 0; i < len; i++) {
int src;
int dst;
- if ((AST_FORMAT_GET_TYPE(format_list[i].id) != AST_FORMAT_TYPE_AUDIO) || (format_list[i].id == input_src_format.id)) {
+ if ((AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) || (format_list[i].format.id == input_src_format.id)) {
continue;
}
- dst = format2index(format_list[i].id);
+ dst = format2index(format_list[i].format.id);
src = format2index(input_src_format.id);
ast_str_reset(str);
if ((len >= cur_max_index) && (src != -1) && (dst != -1) && matrix_get(src, dst)->step) {
- ast_str_append(&str, 0, "%s", ast_getformatname(&matrix_get(src, dst)->step->src_format));
+ 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;
}
- ast_str_append(&str, 0, "->%s", ast_getformatname(&step->dst_format));
+ ast_str_append(&str, 0, "->%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), step->dst_format.id));
src = step->dst_fmt_index;
}
}
@@ -960,6 +981,7 @@ static char *handle_show_translation_path(struct ast_cli_args *a)
}
AST_RWLIST_UNLOCK(&translators);
+ ast_format_list_destroy(format_list);
return CLI_SUCCESS;
}