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