summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES5
-rw-r--r--apps/app_chanspy.c6
-rw-r--r--apps/app_jack.c2
-rw-r--r--apps/app_mixmonitor.c2
-rw-r--r--bridges/bridge_multiplexed.c19
-rw-r--r--bridges/bridge_softmix.c173
-rw-r--r--channels/chan_gtalk.c2
-rw-r--r--channels/chan_iax2.c2
-rw-r--r--channels/chan_jingle.c2
-rw-r--r--channels/chan_sip.c41
-rw-r--r--channels/chan_skinny.c11
-rw-r--r--channels/iax2.h2
-rw-r--r--codecs/Makefile12
-rw-r--r--codecs/codec_resample.c207
-rw-r--r--codecs/codec_speex.c44
-rw-r--r--codecs/speex/arch.h241
-rw-r--r--codecs/speex/fixed_generic.h106
-rw-r--r--codecs/speex/resample.c1124
-rw-r--r--codecs/speex/resample_sse.h128
-rw-r--r--codecs/speex/speex_resampler.h342
-rw-r--r--codecs/speex/stack_alloc.h115
-rw-r--r--configs/codecs.conf.sample71
-rw-r--r--formats/format_attr_silk.c215
-rw-r--r--funcs/func_pitchshift.c5
-rw-r--r--funcs/func_speex.c10
-rw-r--r--funcs/func_volume.c2
-rw-r--r--include/asterisk/_private.h12
-rw-r--r--include/asterisk/audiohook.h12
-rw-r--r--include/asterisk/format.h162
-rw-r--r--include/asterisk/format_cap.h29
-rw-r--r--include/asterisk/frame.h70
-rw-r--r--include/asterisk/rtp_engine.h22
-rw-r--r--include/asterisk/silk.h44
-rw-r--r--include/asterisk/slinfactory.h4
-rw-r--r--include/asterisk/time.h2
-rw-r--r--include/asterisk/translate.h10
-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
-rw-r--r--res/res_mutestream.c2
-rw-r--r--res/res_rtp_asterisk.c4
50 files changed, 4445 insertions, 845 deletions
diff --git a/CHANGES b/CHANGES
index 1f7552c79..b55fb47bf 100644
--- a/CHANGES
+++ b/CHANGES
@@ -40,6 +40,11 @@ CDR
* The filter option in cdr_adaptive_odbc now supports negating the argument,
thus allowing records which do NOT match the specified filter.
+CODECS
+--------------------------
+ * Ability to define custom SILK formats in codecs.conf.
+ * Addition of speex32 audio format with translation.
+
Dialplan Variables
------------------
* Added ASTETCDIR, ASTMODDIR, ASTVARLIBDIR, ASTDBDIR, ASTKEYDIR, ASTDATADIR,
diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c
index 1fc544afb..274bb2202 100644
--- a/apps/app_chanspy.c
+++ b/apps/app_chanspy.c
@@ -541,15 +541,15 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto
memset(&csth, 0, sizeof(csth));
ast_copy_flags(&csth.spy_audiohook, flags, AST_FLAGS_ALL);
- ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
+ ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy", 0);
if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
ast_audiohook_destroy(&csth.spy_audiohook);
return 0;
}
- ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
- ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy");
+ ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy", 0);
+ ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy", 0);
if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
}
diff --git a/apps/app_jack.c b/apps/app_jack.c
index d073451a8..07ab8da79 100644
--- a/apps/app_jack.c
+++ b/apps/app_jack.c
@@ -885,7 +885,7 @@ static int enable_jack_hook(struct ast_channel *chan, char *data)
goto return_error;
jack_data->has_audiohook = 1;
- ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK");
+ ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK", 0);
jack_data->audiohook.manipulate_callback = jack_hook_callback;
datastore->data = jack_data;
diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c
index 8e6adead1..63454895f 100644
--- a/apps/app_mixmonitor.c
+++ b/apps/app_mixmonitor.c
@@ -426,7 +426,7 @@ static void launch_monitor_thread(struct ast_channel *chan, const char *filename
}
/* Setup the actual spy before creating our thread */
- if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) {
+ if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type, 0)) {
mixmonitor_free(mixmonitor);
return;
}
diff --git a/bridges/bridge_multiplexed.c b/bridges/bridge_multiplexed.c
index 0d2b3e254..5a3de43d8 100644
--- a/bridges/bridge_multiplexed.c
+++ b/bridges/bridge_multiplexed.c
@@ -219,6 +219,9 @@ static void *multiplexed_thread_function(void *data)
winner = ast_waitfor_nandfds(multiplexed_thread->chans, multiplexed_thread->service_count, &fds, 1, NULL, &outfd, &to);
multiplexed_thread->waiting = 0;
ao2_lock(multiplexed_thread);
+ if (multiplexed_thread->thread == AST_PTHREADT_STOP) {
+ break;
+ }
if (outfd > -1) {
int nudge;
@@ -230,7 +233,21 @@ static void *multiplexed_thread_function(void *data)
}
}
if (winner && winner->bridge) {
- ast_bridge_handle_trip(winner->bridge, NULL, winner, -1);
+ struct ast_bridge *bridge = winner->bridge;
+ int stop = 0;
+ ao2_unlock(multiplexed_thread);
+ while ((bridge = winner->bridge) && ao2_trylock(bridge)) {
+ sched_yield();
+ if (multiplexed_thread->thread == AST_PTHREADT_STOP) {
+ stop = 1;
+ break;
+ }
+ }
+ if (!stop && bridge) {
+ ast_bridge_handle_trip(bridge, NULL, winner, -1);
+ ao2_unlock(bridge);
+ }
+ ao2_lock(multiplexed_thread);
}
}
diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c
index b25ab99fa..1ac2780de 100644
--- a/bridges/bridge_softmix.c
+++ b/bridges/bridge_softmix.c
@@ -52,14 +52,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/astobj2.h"
#include "asterisk/timing.h"
+#define MAX_DATALEN 3840
+
/*! \brief Interval at which mixing will take place. Valid options are 10, 20, and 40. */
#define SOFTMIX_INTERVAL 20
/*! \brief Size of the buffer used for sample manipulation */
-#define SOFTMIX_DATALEN (160 * (SOFTMIX_INTERVAL / 10))
+#define SOFTMIX_DATALEN(rate) ((rate/50) * (SOFTMIX_INTERVAL / 10))
/*! \brief Number of samples we are dealing with */
-#define SOFTMIX_SAMPLES (SOFTMIX_DATALEN / 2)
+#define SOFTMIX_SAMPLES(rate) (SOFTMIX_DATALEN(rate) / 2)
/*! \brief Define used to turn on 16 kHz audio support */
/* #define SOFTMIX_16_SUPPORT */
@@ -77,40 +79,74 @@ struct softmix_channel {
/*! Bit used to indicate that a frame is available to be written out to the channel */
int have_frame:1;
/*! Buffer containing final mixed audio from all sources */
- short final_buf[SOFTMIX_DATALEN];
+ short final_buf[MAX_DATALEN];
/*! Buffer containing only the audio from the channel */
- short our_buf[SOFTMIX_DATALEN];
+ short our_buf[MAX_DATALEN];
+};
+
+struct softmix_bridge_data {
+ struct ast_timer *timer;
+ unsigned int internal_rate;
};
/*! \brief Function called when a bridge is created */
static int softmix_bridge_create(struct ast_bridge *bridge)
{
- struct ast_timer *timer;
+ struct softmix_bridge_data *bridge_data;
- if (!(timer = ast_timer_open())) {
+ if (!(bridge_data = ast_calloc(1, sizeof(*bridge_data)))) {
+ return -1;
+ }
+ if (!(bridge_data->timer = ast_timer_open())) {
+ ast_free(bridge_data);
return -1;
}
- bridge->bridge_pvt = timer;
+ /* start at 8khz, let it grow from there */
+ bridge_data->internal_rate = 8000;
+ bridge->bridge_pvt = bridge_data;
return 0;
}
/*! \brief Function called when a bridge is destroyed */
static int softmix_bridge_destroy(struct ast_bridge *bridge)
{
+ struct softmix_bridge_data *bridge_data = bridge->bridge_pvt;
if (!bridge->bridge_pvt) {
return -1;
}
- ast_timer_close((struct ast_timer *) bridge->bridge_pvt);
-
+ ast_timer_close(bridge_data->timer);
+ ast_free(bridge_data);
return 0;
}
+static void set_softmix_bridge_data(int rate, struct ast_bridge_channel *bridge_channel, int reset)
+{
+ struct softmix_channel *sc = bridge_channel->bridge_pvt;
+ if (reset) {
+ ast_slinfactory_destroy(&sc->factory);
+ }
+ /* Setup frame parameters */
+ sc->frame.frametype = AST_FRAME_VOICE;
+
+ ast_format_set(&sc->frame.subclass.format, ast_format_slin_by_rate(rate), 0);
+ sc->frame.data.ptr = sc->final_buf;
+ sc->frame.datalen = SOFTMIX_DATALEN(rate);
+ sc->frame.samples = SOFTMIX_SAMPLES(rate);
+
+ /* Setup smoother */
+ ast_slinfactory_init_with_format(&sc->factory, &sc->frame.subclass.format);
+
+ ast_set_read_format(bridge_channel->chan, &sc->frame.subclass.format);
+ ast_set_write_format(bridge_channel->chan, &sc->frame.subclass.format);
+}
+
/*! \brief Function called when a channel is joined into the bridge */
static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
{
struct softmix_channel *sc = NULL;
+ struct softmix_bridge_data *bridge_data = bridge->bridge_pvt;
/* Create a new softmix_channel structure and allocate various things on it */
if (!(sc = ast_calloc(1, sizeof(*sc)))) {
@@ -120,23 +156,11 @@ static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chan
/* Can't forget the lock */
ast_mutex_init(&sc->lock);
- /* Setup smoother */
- ast_slinfactory_init(&sc->factory);
-
- /* Setup frame parameters */
- sc->frame.frametype = AST_FRAME_VOICE;
-#ifdef SOFTMIX_16_SUPPORT
- ast_format_set(&sc->frame.subclass.format, AST_FORMAT_SLINEAR16, 0);
-#else
- ast_format_set(&sc->frame.subclass.format, AST_FORMAT_SLINEAR, 0);
-#endif
- sc->frame.data.ptr = sc->final_buf;
- sc->frame.datalen = SOFTMIX_DATALEN;
- sc->frame.samples = SOFTMIX_SAMPLES;
-
/* Can't forget to record our pvt structure within the bridged channel structure */
bridge_channel->bridge_pvt = sc;
+ set_softmix_bridge_data(bridge_data->internal_rate, bridge_channel, 0);
+
return 0;
}
@@ -170,11 +194,7 @@ static enum ast_bridge_write_result softmix_bridge_write(struct ast_bridge *brid
ast_mutex_lock(&sc->lock);
/* If a frame was provided add it to the smoother */
-#ifdef SOFTMIX_16_SUPPORT
- if (frame->frametype == AST_FRAME_VOICE && frame->subclass.format.id == AST_FORMAT_SLINEAR16) {
-#else
- if (frame->frametype == AST_FRAME_VOICE && frame->subclass.format.id == AST_FORMAT_SLINEAR) {
-#endif
+ if (frame->frametype == AST_FRAME_VOICE && ast_format_is_slinear(&frame->subclass.format)) {
ast_slinfactory_feed(&sc->factory, frame);
}
@@ -210,29 +230,54 @@ static int softmix_bridge_poke(struct ast_bridge *bridge, struct ast_bridge_chan
/*! \brief Function which acts as the mixing thread */
static int softmix_bridge_thread(struct ast_bridge *bridge)
{
- struct ast_timer *timer = (struct ast_timer *) bridge->bridge_pvt;
+ struct {
+ /*! Each index represents a sample rate used above the internal rate. */
+ unsigned int sample_rates[8];
+ /*! Each index represents the number of channels using the same index in the sample_rates array. */
+ unsigned int num_channels[8];
+ /*! the number of channels above the internal sample rate */
+ unsigned int num_above_internal_rate;
+ /*! the number of channels at the internal sample rate */
+ unsigned int num_at_internal_rate;
+ /*! the absolute highest sample rate supported by any channel in the bridge */
+ unsigned int highest_supported_rate;
+ } stats;
+ struct softmix_bridge_data *bridge_data = bridge->bridge_pvt;
+ struct ast_timer *timer = bridge_data->timer;
int timingfd = ast_timer_fd(timer);
+ int update_all_rates = 0; /* set this when the internal sample rate has changed */
+ int i;
ast_timer_set_rate(timer, (1000 / SOFTMIX_INTERVAL));
while (!bridge->stop && !bridge->refresh && bridge->array_num) {
struct ast_bridge_channel *bridge_channel = NULL;
- short buf[SOFTMIX_DATALEN] = {0, };
+ short buf[MAX_DATALEN] = {0, };
int timeout = -1;
+ /* these variables help determine if a rate change is required */
+ memset(&stats, 0, sizeof(stats));
+ stats.highest_supported_rate = 8000;
+
/* Go through pulling audio from each factory that has it available */
AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
struct softmix_channel *sc = bridge_channel->bridge_pvt;
+ int channel_native_rate;
ast_mutex_lock(&sc->lock);
+ if (update_all_rates) {
+ set_softmix_bridge_data(bridge_data->internal_rate, bridge_channel, 1);
+ }
+
/* Try to get audio from the factory if available */
- if (ast_slinfactory_available(&sc->factory) >= SOFTMIX_SAMPLES && ast_slinfactory_read(&sc->factory, sc->our_buf, SOFTMIX_SAMPLES)) {
+ if (ast_slinfactory_available(&sc->factory) >= SOFTMIX_SAMPLES(bridge_data->internal_rate) &&
+ ast_slinfactory_read(&sc->factory, sc->our_buf, SOFTMIX_SAMPLES(bridge_data->internal_rate))) {
short *data1, *data2;
int i;
/* Put into the local final buffer */
- for (i = 0, data1 = buf, data2 = sc->our_buf; i < SOFTMIX_DATALEN; i++, data1++, data2++)
+ for (i = 0, data1 = buf, data2 = sc->our_buf; i < SOFTMIX_DATALEN(bridge_data->internal_rate); i++, data1++, data2++)
ast_slinear_saturated_add(data1, data2);
/* Yay we have our own audio */
sc->have_audio = 1;
@@ -240,6 +285,30 @@ static int softmix_bridge_thread(struct ast_bridge *bridge)
/* Awww we don't have audio ;( */
sc->have_audio = 0;
}
+
+ /* Gather stats about channel sample rates. */
+ channel_native_rate = MAX(ast_format_rate(&bridge_channel->chan->rawwriteformat),
+ ast_format_rate(&bridge_channel->chan->rawreadformat));
+
+ if (channel_native_rate > stats.highest_supported_rate) {
+ stats.highest_supported_rate = channel_native_rate;
+ }
+ if (channel_native_rate > bridge_data->internal_rate) {
+ for (i = 0; i < ARRAY_LEN(stats.sample_rates); i++) {
+ if (stats.sample_rates[i] == channel_native_rate) {
+ stats.num_channels[i]++;
+ break;
+ } else if (!stats.sample_rates[i]) {
+ stats.sample_rates[i] = channel_native_rate;
+ stats.num_channels[i]++;
+ break;
+ }
+ }
+ stats.num_above_internal_rate++;
+ } else if (channel_native_rate == bridge_data->internal_rate) {
+ stats.num_at_internal_rate++;
+ }
+
ast_mutex_unlock(&sc->lock);
}
@@ -253,7 +322,7 @@ static int softmix_bridge_thread(struct ast_bridge *bridge)
/* If we provided audio then take it out */
if (sc->have_audio) {
- for (i = 0; i < SOFTMIX_DATALEN; i++) {
+ for (i = 0; i < SOFTMIX_DATALEN(bridge_data->internal_rate); i++) {
ast_slinear_saturated_subtract(&sc->final_buf[i], &sc->our_buf[i]);
}
}
@@ -265,6 +334,44 @@ static int softmix_bridge_thread(struct ast_bridge *bridge)
pthread_kill(bridge_channel->thread, SIGURG);
}
+ /* Re-adjust the internal bridge sample rate if
+ * 1. two or more channels support a higher sample rate
+ * 2. no channels support the current sample rate or a higher rate
+ */
+ if (stats.num_above_internal_rate >= 2) {
+ /* the highest rate is just used as a starting point */
+ unsigned int best_rate = stats.highest_supported_rate;
+ int best_index = -1;
+
+ /* 1. pick the best sample rate two or more channels support
+ * 2. if two or more channels do not support the same rate, pick the
+ * lowest sample rate that is still above the internal rate. */
+ for (i = 0; ((i < ARRAY_LEN(stats.num_channels)) && stats.num_channels[i]); i++) {
+ if ((stats.num_channels[i] >= 2 && (best_index == -1)) ||
+ ((best_index != -1) &&
+ (stats.num_channels[i] >= 2) &&
+ (stats.sample_rates[best_index] < stats.sample_rates[i]))) {
+
+ best_rate = stats.sample_rates[i];
+ best_index = i;
+ } else if (best_index == -1) {
+ best_rate = MIN(best_rate, stats.sample_rates[i]);
+ }
+ }
+
+ ast_debug(1, " Bridge changed from %d To %d\n", bridge_data->internal_rate, best_rate);
+ bridge_data->internal_rate = best_rate;
+ update_all_rates = 1;
+ } else if (!stats.num_at_internal_rate && !stats.num_above_internal_rate) {
+ update_all_rates = 1;
+ /* in this case, the highest supported rate is actually lower than the internal rate */
+ bridge_data->internal_rate = stats.highest_supported_rate;
+ ast_debug(1, " Bridge changed from %d to %d\n", bridge_data->internal_rate, stats.highest_supported_rate);
+ update_all_rates = 1;
+ } else {
+ update_all_rates = 0;
+ }
+
ao2_unlock(bridge);
/* Wait for the timing source to tell us to wake up and get things done */
diff --git a/channels/chan_gtalk.c b/channels/chan_gtalk.c
index a284520af..d8dd736e4 100644
--- a/channels/chan_gtalk.c
+++ b/channels/chan_gtalk.c
@@ -285,7 +285,7 @@ static struct gtalk *find_gtalk(char *name, char *connection)
static int add_codec_to_answer(const struct gtalk_pvt *p, struct ast_format *codec, iks *dcodecs)
{
int res = 0;
- char *format = ast_getformatname(codec);
+ const char *format = ast_getformatname(codec);
if (!strcasecmp("ulaw", format)) {
iks *payload_eg711u, *payload_pcmu;
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 6087a823a..ab28ec6dc 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -1668,7 +1668,7 @@ static iax2_format iax2_best_codec(iax2_format formats)
return ast_format_to_old_bitfield(&tmpfmt);
}
-char *iax2_getformatname(iax2_format format)
+const char *iax2_getformatname(iax2_format format)
{
struct ast_format tmpfmt;
if (!(ast_format_from_old_bitfield(&tmpfmt, format))) {
diff --git a/channels/chan_jingle.c b/channels/chan_jingle.c
index 93d81d954..311f4c91c 100644
--- a/channels/chan_jingle.c
+++ b/channels/chan_jingle.c
@@ -257,7 +257,7 @@ static struct jingle *find_jingle(char *name, char *connection)
static void add_codec_to_answer(const struct jingle_pvt *p, struct ast_format *codec, iks *dcodecs)
{
- char *format = ast_getformatname(codec);
+ const char *format = ast_getformatname(codec);
if (!strcasecmp("ulaw", format)) {
iks *payload_eg711u, *payload_pcmu;
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 06e23ad07..4d9408f38 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -8885,11 +8885,10 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
}
ast_debug(4, "We have an owner, now see if we need to change this call\n");
-
- if (!(ast_format_cap_has_joint(p->owner->nativeformats, p->jointcaps)) && ast_format_cap_has_type(p->jointcaps, AST_FORMAT_TYPE_AUDIO)) {
+ if (ast_format_cap_has_type(p->jointcaps, AST_FORMAT_TYPE_AUDIO)) {
if (debug) {
char s1[SIPBUFSIZE], s2[SIPBUFSIZE];
- ast_debug(1, "Oooh, we need to change our audio formats since our peer supports only %s and not %s\n",
+ ast_debug(1, "Setting native formats after processing SDP. peer joint formats %s, old nativeformats %s\n",
ast_getformatname_multiple(s1, SIPBUFSIZE, p->jointcaps),
ast_getformatname_multiple(s2, SIPBUFSIZE, p->owner->nativeformats));
}
@@ -9109,13 +9108,12 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_
ast_verbose("Discarded description format %s for ID %d\n", mimeSubtype, codec);
}
} else if (sscanf(a, "fmtp: %30u %63s", &codec, fmtp_string) == 2) {
- struct ast_rtp_payload_type payload;
+ struct ast_format *format;
- payload = ast_rtp_codecs_payload_lookup(newaudiortp, codec);
- if (payload.format.id && payload.asterisk_format) {
+ if ((format = ast_rtp_codecs_get_payload_format(newaudiortp, codec))) {
unsigned int bit_rate;
- switch ((int) payload.format.id) {
+ switch ((int) format->id) {
case AST_FORMAT_SIREN7:
if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) {
if (bit_rate != 32000) {
@@ -9145,6 +9143,21 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_
found = TRUE;
}
}
+ break;
+ case AST_FORMAT_SILK:
+ {
+ int val = 0;
+ if (sscanf(fmtp_string, "maxaveragebitrate=%30u", &val) == 1) {
+ ast_format_append(format, SILK_ATTR_KEY_MAX_BITRATE, val, AST_FORMAT_ATTR_END);
+ }
+ if (sscanf(fmtp_string, "usedtx=%30u", &val) == 1) {
+ ast_format_append(format, SILK_ATTR_KEY_DTX, val ? 1 : 0, AST_FORMAT_ATTR_END);
+ }
+ if (sscanf(fmtp_string, "useinbandfec=%30u", &val) == 1) {
+ ast_format_append(format, SILK_ATTR_KEY_FEC, val ? 1 : 0, AST_FORMAT_ATTR_END);
+ }
+ break;
+ }
}
}
}
@@ -10505,6 +10518,20 @@ static void add_codec_to_sdp(const struct sip_pvt *p,
/* Indicate that we only expect 64Kbps */
ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=64000\r\n", rtp_code);
break;
+ case AST_FORMAT_SILK:
+ {
+ int val = 0;
+ if (!ast_format_get_value(format, SILK_ATTR_KEY_MAX_BITRATE, &val) && val > 5000 && val < 40000) {
+ ast_str_append(a_buf, 0, "a=fmtp:%d maxaveragebitrate=%u\r\n", rtp_code, val);
+ }
+ if (!ast_format_get_value(format, SILK_ATTR_KEY_DTX, &val)) {
+ ast_str_append(a_buf, 0, "a=fmtp:%d usedtx=%u\r\n", rtp_code, val ? 1 : 0);
+ }
+ if (!ast_format_get_value(format, SILK_ATTR_KEY_FEC, &val)) {
+ ast_str_append(a_buf, 0, "a=fmtp:%d useinbandfec=%u\r\n", rtp_code, val ? 1 : 0);
+ }
+ break;
+ }
}
if (fmt.cur_ms && (fmt.cur_ms < *min_packet_size))
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index 3d485fff3..dc8738e1c 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -1796,7 +1796,7 @@ static struct ast_format *codec_skinny2ast(enum skinny_codecs skinnycodec, struc
}
}
-static int codec_ast2skinny(struct ast_format *astcodec)
+static int codec_ast2skinny(const struct ast_format *astcodec)
{
switch (astcodec->id) {
case AST_FORMAT_ALAW:
@@ -2289,7 +2289,7 @@ static void transmit_connect(struct skinny_device *d, struct skinny_subchannel *
req->data.openreceivechannel.conferenceId = htolel(sub->callid);
req->data.openreceivechannel.partyId = htolel(sub->callid);
req->data.openreceivechannel.packets = htolel(fmt.cur_ms);
- req->data.openreceivechannel.capability = htolel(codec_ast2skinny(ast_format_set(&tmpfmt, fmt.id, 0)));
+ req->data.openreceivechannel.capability = htolel(codec_ast2skinny(&fmt.format));
req->data.openreceivechannel.echo = htolel(0);
req->data.openreceivechannel.bitrate = htolel(0);
transmit_response(d, req);
@@ -2494,7 +2494,6 @@ static void transmit_stopmediatransmission(struct skinny_device *d, struct skinn
static void transmit_startmediatransmission(struct skinny_device *d, struct skinny_subchannel *sub, struct sockaddr_in dest, struct ast_format_list fmt)
{
struct skinny_req *req;
- struct ast_format tmpfmt;
if (!(req = req_alloc(sizeof(struct start_media_transmission_message), START_MEDIA_TRANSMISSION_MESSAGE)))
return;
@@ -2504,7 +2503,7 @@ static void transmit_startmediatransmission(struct skinny_device *d, struct skin
req->data.startmedia.remoteIp = dest.sin_addr.s_addr;
req->data.startmedia.remotePort = htolel(ntohs(dest.sin_port));
req->data.startmedia.packetSize = htolel(fmt.cur_ms);
- req->data.startmedia.payloadType = htolel(codec_ast2skinny(ast_format_set(&tmpfmt, fmt.id, 0)));
+ req->data.startmedia.payloadType = htolel(codec_ast2skinny(&fmt.format));
req->data.startmedia.qualifier.precedence = htolel(127);
req->data.startmedia.qualifier.vad = htolel(0);
req->data.startmedia.qualifier.packets = htolel(0);
@@ -2986,7 +2985,7 @@ static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp_instance *r
fmt = ast_codec_pref_getsize(&l->prefs, &tmpfmt);
if (skinnydebug)
- ast_verb(1, "Setting payloadType to '%s' (%d ms)\n", ast_getformatname(ast_format_set(&tmpfmt, fmt.id, 0)), fmt.cur_ms);
+ ast_verb(1, "Setting payloadType to '%s' (%d ms)\n", ast_getformatname(&fmt.format), fmt.cur_ms);
if (!(l->directmedia) || (l->nat)){
ast_rtp_instance_get_local_address(rtp, &us_tmp);
@@ -5760,7 +5759,7 @@ static int handle_open_receive_channel_ack_message(struct skinny_req *req, struc
fmt = ast_codec_pref_getsize(&l->prefs, &tmpfmt);
if (skinnydebug)
- ast_verb(1, "Setting payloadType to '%s' (%d ms)\n", ast_getformatname(ast_format_set(&tmpfmt, fmt.id, 0)), fmt.cur_ms);
+ ast_verb(1, "Setting payloadType to '%s' (%d ms)\n", ast_getformatname(&fmt.format), fmt.cur_ms);
transmit_startmediatransmission(d, sub, us, fmt);
diff --git a/channels/iax2.h b/channels/iax2.h
index d579ed8aa..87e7bf398 100644
--- a/channels/iax2.h
+++ b/channels/iax2.h
@@ -218,7 +218,7 @@ enum iax_frame_subclass {
typedef int64_t iax2_format;
/*!\brief iax2 wrapper function for ast_getformatname */
-char *iax2_getformatname(iax2_format format);
+const char *iax2_getformatname(iax2_format format);
/*! Full frames are always delivered reliably */
struct ast_iax2_full_hdr {
diff --git a/codecs/Makefile b/codecs/Makefile
index 846c16364..6ef08daed 100644
--- a/codecs/Makefile
+++ b/codecs/Makefile
@@ -29,11 +29,13 @@ GSM_INCLUDE:=-Igsm/inc
$(if $(filter codec_gsm,$(EMBEDDED_MODS)),modules.link,codec_gsm.so): gsm/lib/libgsm.a
endif
+
clean::
$(MAKE) -C gsm clean
$(MAKE) -C lpc10 clean
$(MAKE) -C ilbc clean
rm -f g722/*.[oa]
+ rm -f speex/*.[oa]
gsm/lib/libgsm.a:
@mkdir -p gsm/lib
@@ -47,7 +49,17 @@ $(if $(filter codec_lpc10,$(EMBEDDED_MODS)),modules.link,codec_lpc10.so): $(LIBL
$(LIBILBC):
@$(MAKE) -C ilbc all _ASTCFLAGS="$(filter-out -Wmissing-prototypes -Wmissing-declarations -Wshadow,$(_ASTCFLAGS)) $(AST_NO_STRICT_OVERFLOW)"
+
$(if $(filter codec_ilbc,$(EMBEDDED_MODS)),modules.link,codec_ilbc.so): $(LIBILBC)
$(if $(filter codec_g722,$(EMBEDDED_MODS)),modules.link,codec_g722.so): g722/g722_encode.o g722/g722_decode.o
g722/g722_encode.o g722/g722_decode.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,codec_g722)
+
+ifeq ($(BUILD_CPU),x86_64)
+SPEEX_RESAMPLE_CFLAGS:=-fPIC
+else
+SPEEX_RESAMPLE_CFLAGS:=
+endif
+
+$(if $(filter codec_resample,$(EMBEDDED_MODS)),modules.link,codec_resample.so): speex/resample.o
+speex/resample.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,codec_resample) $(SPEEX_RESAMPLE_CFLAGS)
diff --git a/codecs/codec_resample.c b/codecs/codec_resample.c
index 80823bb7c..20bbc5c9b 100644
--- a/codecs/codec_resample.c
+++ b/codecs/codec_resample.c
@@ -1,9 +1,10 @@
/*
* Asterisk -- An open source telephony toolkit.
*
- * Copyright (C) 2007, Digium, Inc.
+ * Copyright (C) 2011, Digium, Inc.
*
* Russell Bryant <russell@digium.com>
+ * David Vossel <dvossel@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
@@ -21,9 +22,6 @@
*
* \brief Resample slinear audio
*
- * \note To install libresample, check it out of the following repository:
- * <code>$ svn co http://svn.digium.com/svn/thirdparty/libresample/trunk</code>
- *
* \ingroup codecs
*/
@@ -32,170 +30,75 @@
***/
#include "asterisk.h"
+#include "speex/speex_resampler.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-/* These are for SHRT_MAX and FLT_MAX -- { */
-#if defined(__Darwin__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__CYGWIN__)
-#include <float.h>
-#else
-#include <values.h>
-#endif
-#include <limits.h>
-/* } */
-
-#include <libresample.h>
-
#include "asterisk/module.h"
#include "asterisk/translate.h"
-
#include "asterisk/slin.h"
-#define RESAMPLER_QUALITY 1
-
#define OUTBUF_SIZE 8096
-struct slin16_to_slin8_pvt {
- void *resampler;
- float resample_factor;
-};
-
-struct slin8_to_slin16_pvt {
- void *resampler;
- float resample_factor;
+static struct ast_translator *translators;
+static int trans_size;
+static int id_list[] = {
+ AST_FORMAT_SLINEAR,
+ AST_FORMAT_SLINEAR12,
+ AST_FORMAT_SLINEAR16,
+ AST_FORMAT_SLINEAR24,
+ AST_FORMAT_SLINEAR32,
+ AST_FORMAT_SLINEAR44,
+ AST_FORMAT_SLINEAR48,
+ AST_FORMAT_SLINEAR96,
+ AST_FORMAT_SLINEAR192,
};
-static int slin16_to_slin8_new(struct ast_trans_pvt *pvt)
+static int resamp_new(struct ast_trans_pvt *pvt)
{
- struct slin16_to_slin8_pvt *resamp_pvt = pvt->pvt;
+ int err;
- resamp_pvt->resample_factor = 8000.0 / 16000.0;
-
- if (!(resamp_pvt->resampler = resample_open(RESAMPLER_QUALITY, resamp_pvt->resample_factor, resamp_pvt->resample_factor)))
- return -1;
-
- return 0;
-}
-
-static int slin8_to_slin16_new(struct ast_trans_pvt *pvt)
-{
- struct slin8_to_slin16_pvt *resamp_pvt = pvt->pvt;
-
- resamp_pvt->resample_factor = 16000.0 / 8000.0;
-
- if (!(resamp_pvt->resampler = resample_open(RESAMPLER_QUALITY, resamp_pvt->resample_factor, resamp_pvt->resample_factor)))
+ if (!(pvt->pvt = speex_resampler_init(1, ast_format_rate(&pvt->t->src_format), ast_format_rate(&pvt->t->dst_format), 5, &err))) {
return -1;
+ }
return 0;
}
-static void slin16_to_slin8_destroy(struct ast_trans_pvt *pvt)
-{
- struct slin16_to_slin8_pvt *resamp_pvt = pvt->pvt;
-
- if (resamp_pvt->resampler)
- resample_close(resamp_pvt->resampler);
-}
-
-static void slin8_to_slin16_destroy(struct ast_trans_pvt *pvt)
+static void resamp_destroy(struct ast_trans_pvt *pvt)
{
- struct slin8_to_slin16_pvt *resamp_pvt = pvt->pvt;
-
- if (resamp_pvt->resampler)
- resample_close(resamp_pvt->resampler);
+ SpeexResamplerState *resamp_pvt = pvt->pvt;
+ speex_resampler_destroy(resamp_pvt);
}
-static int resample_frame(struct ast_trans_pvt *pvt,
- void *resampler, float resample_factor, struct ast_frame *f)
+static int resamp_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
{
- int total_in_buf_used = 0;
- int total_out_buf_used = 0;
- int16_t *in_buf = (int16_t *) f->data.ptr;
- int16_t *out_buf = pvt->outbuf.i16 + pvt->samples;
- float in_buf_f[f->samples];
- float out_buf_f[2048];
- int res = 0;
- int i;
-
- for (i = 0; i < f->samples; i++)
- in_buf_f[i] = in_buf[i] * (FLT_MAX / SHRT_MAX);
-
- while (total_in_buf_used < f->samples) {
- int in_buf_used, out_buf_used;
+ SpeexResamplerState *resamp_pvt = pvt->pvt;
+ unsigned int out_samples = (OUTBUF_SIZE / sizeof(int16_t)) - pvt->samples;
+ unsigned int in_samples = f->samples;
- out_buf_used = resample_process(resampler, resample_factor,
- &in_buf_f[total_in_buf_used], f->samples - total_in_buf_used,
- 0, &in_buf_used,
- &out_buf_f[total_out_buf_used], ARRAY_LEN(out_buf_f) - total_out_buf_used);
+ speex_resampler_process_int(resamp_pvt,
+ 0,
+ f->data.ptr,
+ &in_samples,
+ pvt->outbuf.i16 + pvt->samples,
+ &out_samples);
- if (out_buf_used < 0)
- break;
+ pvt->samples += out_samples;
+ pvt->datalen += out_samples * 2;
- total_out_buf_used += out_buf_used;
- total_in_buf_used += in_buf_used;
-
- if (total_out_buf_used == ARRAY_LEN(out_buf_f)) {
- ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n");
- res = -1;
- break;
- }
- }
-
- for (i = 0; i < total_out_buf_used; i++)
- out_buf[i] = out_buf_f[i] * (SHRT_MAX / FLT_MAX);
-
- pvt->samples += total_out_buf_used;
- pvt->datalen += (total_out_buf_used * sizeof(int16_t));
-
- return res;
-}
-
-static int slin16_to_slin8_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
-{
- struct slin16_to_slin8_pvt *resamp_pvt = pvt->pvt;
- void *resampler = resamp_pvt->resampler;
- float resample_factor = resamp_pvt->resample_factor;
-
- return resample_frame(pvt, resampler, resample_factor, f);
-}
-
-static int slin8_to_slin16_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
-{
- struct slin8_to_slin16_pvt *resamp_pvt = pvt->pvt;
- void *resampler = resamp_pvt->resampler;
- float resample_factor = resamp_pvt->resample_factor;
-
- return resample_frame(pvt, resampler, resample_factor, f);
+ return 0;
}
-static struct ast_translator slin16_to_slin8 = {
- .name = "slin16_to_slin8",
- .newpvt = slin16_to_slin8_new,
- .destroy = slin16_to_slin8_destroy,
- .framein = slin16_to_slin8_framein,
- .sample = slin16_sample,
- .desc_size = sizeof(struct slin16_to_slin8_pvt),
- .buffer_samples = (OUTBUF_SIZE / sizeof(int16_t)),
- .buf_size = OUTBUF_SIZE,
-};
-
-static struct ast_translator slin8_to_slin16 = {
- .name = "slin8_to_slin16",
- .newpvt = slin8_to_slin16_new,
- .destroy = slin8_to_slin16_destroy,
- .framein = slin8_to_slin16_framein,
- .sample = slin8_sample,
- .desc_size = sizeof(struct slin8_to_slin16_pvt),
- .buffer_samples = (OUTBUF_SIZE / sizeof(int16_t)),
- .buf_size = OUTBUF_SIZE,
-};
-
static int unload_module(void)
{
int res = 0;
+ int idx;
- res |= ast_unregister_translator(&slin16_to_slin8);
- res |= ast_unregister_translator(&slin8_to_slin16);
+ for (idx = 0; idx < trans_size; idx++) {
+ res |= ast_unregister_translator(&translators[idx]);
+ }
+ ast_free(translators);
return res;
}
@@ -203,15 +106,33 @@ static int unload_module(void)
static int load_module(void)
{
int res = 0;
+ int x, y, idx = 0;
- ast_format_set(&slin16_to_slin8.src_format, AST_FORMAT_SLINEAR16, 0);
- ast_format_set(&slin16_to_slin8.dst_format, AST_FORMAT_SLINEAR, 0);
+ trans_size = ARRAY_LEN(id_list) * ARRAY_LEN(id_list);
+ if (!(translators = ast_calloc(1, sizeof(struct ast_translator) * trans_size))) {
+ return AST_MODULE_LOAD_FAILURE;
+ }
- ast_format_set(&slin8_to_slin16.src_format, AST_FORMAT_SLINEAR, 0);
- ast_format_set(&slin8_to_slin16.dst_format, AST_FORMAT_SLINEAR16, 0);
+ for (x = 0; x < ARRAY_LEN(id_list); x++) {
+ for (y = 0; y < ARRAY_LEN(id_list); y++) {
+ if (x == y) {
+ continue;
+ }
+ translators[idx].newpvt = resamp_new;
+ translators[idx].destroy = resamp_destroy;
+ translators[idx].framein = resamp_framein;
+ translators[idx].desc_size = 0;
+ translators[idx].buffer_samples = (OUTBUF_SIZE / sizeof(int16_t));
+ translators[idx].buf_size = OUTBUF_SIZE;
+ ast_format_set(&translators[idx].src_format, id_list[x], 0);
+ ast_format_set(&translators[idx].dst_format, id_list[y], 0);
+ snprintf(translators[idx].name, sizeof(translators[idx].name), "slin %dkhz -> %dkhz",
+ ast_format_rate(&translators[idx].src_format), ast_format_rate(&translators[idx].dst_format));
+ res |= ast_register_translator(&translators[idx]);
+ idx++;
+ }
- res |= ast_register_translator(&slin16_to_slin8);
- res |= ast_register_translator(&slin8_to_slin16);
+ }
return AST_MODULE_LOAD_SUCCESS;
}
diff --git a/codecs/codec_speex.c b/codecs/codec_speex.c
index aaaa1bea2..d48e21f28 100644
--- a/codecs/codec_speex.c
+++ b/codecs/codec_speex.c
@@ -148,6 +148,11 @@ static int lin16tospeexwb_new(struct ast_trans_pvt *pvt)
return speex_encoder_construct(pvt, &speex_wb_mode, 16000);
}
+static int lin32tospeexuwb_new(struct ast_trans_pvt *pvt)
+{
+ return speex_encoder_construct(pvt, &speex_uwb_mode, 32000);
+}
+
static int speex_decoder_construct(struct ast_trans_pvt *pvt, const SpeexMode *profile)
{
struct speex_coder_pvt *tmp = pvt->pvt;
@@ -173,6 +178,11 @@ static int speexwbtolin16_new(struct ast_trans_pvt *pvt)
return speex_decoder_construct(pvt, &speex_wb_mode);
}
+static int speexuwbtolin32_new(struct ast_trans_pvt *pvt)
+{
+ return speex_decoder_construct(pvt, &speex_uwb_mode);
+}
+
/*! \brief convert and store into outbuf */
static int speextolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
{
@@ -376,6 +386,28 @@ static struct ast_translator lin16tospeexwb = {
.buf_size = BUFFER_SAMPLES * 2, /* XXX maybe a lot less ? */
};
+static struct ast_translator speexuwbtolin32 = {
+ .name = "speexuwbtolin32",
+ .newpvt = speexuwbtolin32_new,
+ .framein = speextolin_framein,
+ .destroy = speextolin_destroy,
+ .desc_size = sizeof(struct speex_coder_pvt),
+ .buffer_samples = BUFFER_SAMPLES,
+ .buf_size = BUFFER_SAMPLES * 2,
+ .native_plc = 1,
+};
+
+static struct ast_translator lin32tospeexuwb = {
+ .name = "lin32tospeexuwb",
+ .newpvt = lin32tospeexuwb_new,
+ .framein = lintospeex_framein,
+ .frameout = lintospeex_frameout,
+ .destroy = lintospeex_destroy,
+ .desc_size = sizeof(struct speex_coder_pvt),
+ .buffer_samples = BUFFER_SAMPLES,
+ .buf_size = BUFFER_SAMPLES * 2, /* XXX maybe a lot less ? */
+};
+
static int parse_config(int reload)
{
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
@@ -486,6 +518,9 @@ static int unload_module(void)
res |= ast_unregister_translator(&lintospeex);
res |= ast_unregister_translator(&speexwbtolin16);
res |= ast_unregister_translator(&lin16tospeexwb);
+ res |= ast_unregister_translator(&speexuwbtolin32);
+ res |= ast_unregister_translator(&lin32tospeexuwb);
+
return res;
}
@@ -510,10 +545,19 @@ static int load_module(void)
ast_format_set(&lin16tospeexwb.src_format, AST_FORMAT_SLINEAR16, 0);
ast_format_set(&lin16tospeexwb.dst_format, AST_FORMAT_SPEEX16, 0);
+ ast_format_set(&speexuwbtolin32.src_format, AST_FORMAT_SPEEX32, 0);
+ ast_format_set(&speexuwbtolin32.dst_format, AST_FORMAT_SLINEAR32, 0);
+
+ ast_format_set(&lin32tospeexuwb.src_format, AST_FORMAT_SLINEAR32, 0);
+ ast_format_set(&lin32tospeexuwb.dst_format, AST_FORMAT_SPEEX32, 0);
+
res |= ast_register_translator(&speextolin);
res |= ast_register_translator(&lintospeex);
res |= ast_register_translator(&speexwbtolin16);
res |= ast_register_translator(&lin16tospeexwb);
+ res |= ast_register_translator(&speexuwbtolin32);
+ res |= ast_register_translator(&lin32tospeexuwb);
+
return res;
}
diff --git a/codecs/speex/arch.h b/codecs/speex/arch.h
new file mode 100644
index 000000000..af42e645d
--- /dev/null
+++ b/codecs/speex/arch.h
@@ -0,0 +1,241 @@
+/* Copyright (C) 2003 Jean-Marc Valin */
+/**
+ @file arch.h
+ @brief Various architecture definitions Speex
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Xiph.org Foundation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef ARCH_H
+#define ARCH_H
+
+#ifndef SPEEX_VERSION
+#define SPEEX_MAJOR_VERSION 1 /**< Major Speex version. */
+#define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */
+#define SPEEX_MICRO_VERSION 15 /**< Micro Speex version. */
+#define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */
+#define SPEEX_VERSION "speex-1.2beta3" /**< Speex version string. */
+#endif
+
+#define FIXED_POINT
+
+/* A couple test to catch stupid option combinations */
+#ifdef FIXED_POINT
+
+#ifdef FLOATING_POINT
+#error You cannot compile as floating point and fixed point at the same time
+#endif
+#ifdef _USE_SSE
+#error SSE is only for floating-point
+#endif
+#if ((defined (ARM4_ASM)||defined (ARM4_ASM)) && defined(BFIN_ASM)) || (defined (ARM4_ASM)&&defined(ARM5E_ASM))
+#error Make up your mind. What CPU do you have?
+#endif
+#ifdef VORBIS_PSYCHO
+#error Vorbis-psy model currently not implemented in fixed-point
+#endif
+
+#else
+
+#ifndef FLOATING_POINT
+#error You now need to define either FIXED_POINT or FLOATING_POINT
+#endif
+#if defined (ARM4_ASM) || defined(ARM5E_ASM) || defined(BFIN_ASM)
+#error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions?
+#endif
+#ifdef FIXED_POINT_DEBUG
+#error "Don't you think enabling fixed-point is a good thing to do if you want to debug that?"
+#endif
+
+
+#endif
+
+#ifndef OUTSIDE_SPEEX
+#include "speex/speex_types.h"
+#endif
+
+#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */
+#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */
+#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */
+#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */
+#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */
+#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */
+#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */
+
+#ifdef FIXED_POINT
+
+typedef spx_int16_t spx_word16_t;
+typedef spx_int32_t spx_word32_t;
+typedef spx_word32_t spx_mem_t;
+typedef spx_word16_t spx_coef_t;
+typedef spx_word16_t spx_lsp_t;
+typedef spx_word32_t spx_sig_t;
+
+#define Q15ONE 32767
+
+#define LPC_SCALING 8192
+#define SIG_SCALING 16384
+#define LSP_SCALING 8192.
+#define GAMMA_SCALING 32768.
+#define GAIN_SCALING 64
+#define GAIN_SCALING_1 0.015625
+
+#define LPC_SHIFT 13
+#define LSP_SHIFT 13
+#define SIG_SHIFT 14
+#define GAIN_SHIFT 6
+
+#define VERY_SMALL 0
+#define VERY_LARGE32 ((spx_word32_t)2147483647)
+#define VERY_LARGE16 ((spx_word16_t)32767)
+#define Q15_ONE ((spx_word16_t)32767)
+
+
+#ifdef FIXED_DEBUG
+#include "fixed_debug.h"
+#else
+
+#include "fixed_generic.h"
+
+#ifdef ARM5E_ASM
+#include "fixed_arm5e.h"
+#elif defined (ARM4_ASM)
+#include "fixed_arm4.h"
+#elif defined (BFIN_ASM)
+#include "fixed_bfin.h"
+#endif
+
+#endif
+
+
+#else
+
+typedef float spx_mem_t;
+typedef float spx_coef_t;
+typedef float spx_lsp_t;
+typedef float spx_sig_t;
+typedef float spx_word16_t;
+typedef float spx_word32_t;
+
+#define Q15ONE 1.0f
+#define LPC_SCALING 1.f
+#define SIG_SCALING 1.f
+#define LSP_SCALING 1.f
+#define GAMMA_SCALING 1.f
+#define GAIN_SCALING 1.f
+#define GAIN_SCALING_1 1.f
+
+
+#define VERY_SMALL 1e-15f
+#define VERY_LARGE32 1e15f
+#define VERY_LARGE16 1e15f
+#define Q15_ONE ((spx_word16_t)1.f)
+
+#define QCONST16(x,bits) (x)
+#define QCONST32(x,bits) (x)
+
+#define NEG16(x) (-(x))
+#define NEG32(x) (-(x))
+#define EXTRACT16(x) (x)
+#define EXTEND32(x) (x)
+#define SHR16(a,shift) (a)
+#define SHL16(a,shift) (a)
+#define SHR32(a,shift) (a)
+#define SHL32(a,shift) (a)
+#define PSHR16(a,shift) (a)
+#define PSHR32(a,shift) (a)
+#define VSHR32(a,shift) (a)
+#define SATURATE16(x,a) (x)
+#define SATURATE32(x,a) (x)
+
+#define PSHR(a,shift) (a)
+#define SHR(a,shift) (a)
+#define SHL(a,shift) (a)
+#define SATURATE(x,a) (x)
+
+#define ADD16(a,b) ((a)+(b))
+#define SUB16(a,b) ((a)-(b))
+#define ADD32(a,b) ((a)+(b))
+#define SUB32(a,b) ((a)-(b))
+#define MULT16_16_16(a,b) ((a)*(b))
+#define MULT16_16(a,b) ((spx_word32_t)(a)*(spx_word32_t)(b))
+#define MAC16_16(c,a,b) ((c)+(spx_word32_t)(a)*(spx_word32_t)(b))
+
+#define MULT16_32_Q11(a,b) ((a)*(b))
+#define MULT16_32_Q13(a,b) ((a)*(b))
+#define MULT16_32_Q14(a,b) ((a)*(b))
+#define MULT16_32_Q15(a,b) ((a)*(b))
+#define MULT16_32_P15(a,b) ((a)*(b))
+
+#define MAC16_32_Q11(c,a,b) ((c)+(a)*(b))
+#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b))
+
+#define MAC16_16_Q11(c,a,b) ((c)+(a)*(b))
+#define MAC16_16_Q13(c,a,b) ((c)+(a)*(b))
+#define MAC16_16_P13(c,a,b) ((c)+(a)*(b))
+#define MULT16_16_Q11_32(a,b) ((a)*(b))
+#define MULT16_16_Q13(a,b) ((a)*(b))
+#define MULT16_16_Q14(a,b) ((a)*(b))
+#define MULT16_16_Q15(a,b) ((a)*(b))
+#define MULT16_16_P15(a,b) ((a)*(b))
+#define MULT16_16_P13(a,b) ((a)*(b))
+#define MULT16_16_P14(a,b) ((a)*(b))
+
+#define DIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b))
+#define PDIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b))
+#define DIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b))
+#define PDIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b))
+
+
+#endif
+
+
+#if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
+
+/* 2 on TI C5x DSP */
+#define BYTES_PER_CHAR 2
+#define BITS_PER_CHAR 16
+#define LOG2_BITS_PER_CHAR 4
+
+#else
+
+#define BYTES_PER_CHAR 1
+#define BITS_PER_CHAR 8
+#define LOG2_BITS_PER_CHAR 3
+
+#endif
+
+
+
+#ifdef FIXED_DEBUG
+extern long long spx_mips;
+#endif
+
+
+#endif
diff --git a/codecs/speex/fixed_generic.h b/codecs/speex/fixed_generic.h
new file mode 100644
index 000000000..3fb096ed9
--- /dev/null
+++ b/codecs/speex/fixed_generic.h
@@ -0,0 +1,106 @@
+/* Copyright (C) 2003 Jean-Marc Valin */
+/**
+ @file fixed_generic.h
+ @brief Generic fixed-point operations
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Xiph.org Foundation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FIXED_GENERIC_H
+#define FIXED_GENERIC_H
+
+#define QCONST16(x,bits) ((spx_word16_t)(.5+(x)*(((spx_word32_t)1)<<(bits))))
+#define QCONST32(x,bits) ((spx_word32_t)(.5+(x)*(((spx_word32_t)1)<<(bits))))
+
+#define NEG16(x) (-(x))
+#define NEG32(x) (-(x))
+#define EXTRACT16(x) ((spx_word16_t)(x))
+#define EXTEND32(x) ((spx_word32_t)(x))
+#define SHR16(a,shift) ((a) >> (shift))
+#define SHL16(a,shift) ((a) << (shift))
+#define SHR32(a,shift) ((a) >> (shift))
+#define SHL32(a,shift) ((a) << (shift))
+#define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift))
+#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift))
+#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
+#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
+#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
+
+#define SHR(a,shift) ((a) >> (shift))
+#define SHL(a,shift) ((spx_word32_t)(a) << (shift))
+#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift))
+#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
+
+
+#define ADD16(a,b) ((spx_word16_t)((spx_word16_t)(a)+(spx_word16_t)(b)))
+#define SUB16(a,b) ((spx_word16_t)(a)-(spx_word16_t)(b))
+#define ADD32(a,b) ((spx_word32_t)(a)+(spx_word32_t)(b))
+#define SUB32(a,b) ((spx_word32_t)(a)-(spx_word32_t)(b))
+
+
+/* result fits in 16 bits */
+#define MULT16_16_16(a,b) ((((spx_word16_t)(a))*((spx_word16_t)(b))))
+
+/* (spx_word32_t)(spx_word16_t) gives TI compiler a hint that it's 16x16->32 multiply */
+#define MULT16_16(a,b) (((spx_word32_t)(spx_word16_t)(a))*((spx_word32_t)(spx_word16_t)(b)))
+
+#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b))))
+#define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12))
+#define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13))
+#define MULT16_32_Q14(a,b) ADD32(MULT16_16((a),SHR((b),14)), SHR(MULT16_16((a),((b)&0x00003fff)),14))
+
+#define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))
+#define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)))
+
+#define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15))
+#define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))
+#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)))
+
+
+#define MAC16_16_Q11(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),11)))
+#define MAC16_16_Q13(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),13)))
+#define MAC16_16_P13(c,a,b) (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13)))
+
+#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11))
+#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13))
+#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14))
+#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15))
+
+#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13))
+#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14))
+#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15))
+
+#define MUL_16_32_R15(a,bh,bl) ADD32(MULT16_16((a),(bh)), SHR(MULT16_16((a),(bl)),15))
+
+#define DIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a))/((spx_word16_t)(b))))
+#define PDIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word16_t)(b))))
+#define DIV32(a,b) (((spx_word32_t)(a))/((spx_word32_t)(b)))
+#define PDIV32(a,b) (((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word32_t)(b)))
+
+#endif
diff --git a/codecs/speex/resample.c b/codecs/speex/resample.c
new file mode 100644
index 000000000..2b0395180
--- /dev/null
+++ b/codecs/speex/resample.c
@@ -0,0 +1,1124 @@
+/* Copyright (C) 2007-2008 Jean-Marc Valin
+ Copyright (C) 2008 Thorvald Natvig
+
+ File: resample.c
+ Arbitrary resampling code
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ The design goals of this code are:
+ - Very fast algorithm
+ - SIMD-friendly algorithm
+ - Low memory requirement
+ - Good *perceptual* quality (and not best SNR)
+
+ Warning: This resampler is relatively new. Although I think I got rid of
+ all the major bugs and I don't expect the API to change anymore, there
+ may be something I've missed. So use with caution.
+
+ This algorithm is based on this original resampling algorithm:
+ Smith, Julius O. Digital Audio Resampling Home Page
+ Center for Computer Research in Music and Acoustics (CCRMA),
+ Stanford University, 2007.
+ Web published at http://www-ccrma.stanford.edu/~jos/resample/.
+
+ There is one main difference, though. This resampler uses cubic
+ interpolation instead of linear interpolation in the above paper. This
+ makes the table much smaller and makes it possible to compute that table
+ on a per-stream basis. In turn, being able to tweak the table for each
+ stream makes it possible to both reduce complexity on simple ratios
+ (e.g. 2/3), and get rid of the rounding operations in the inner loop.
+ The latter both reduces CPU time and makes the algorithm more SIMD-friendly.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+static void *speex_alloc (int size) {return calloc(size,1);}
+static void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);}
+static void speex_free (void *ptr) {free(ptr);}
+#include "speex_resampler.h"
+#include "arch.h"
+
+#include "stack_alloc.h"
+#include <math.h>
+
+#ifndef M_PI
+#define M_PI 3.14159263
+#endif
+
+#ifdef FIXED_POINT
+#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x)))
+#else
+#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))
+#endif
+
+#define IMAX(a,b) ((a) > (b) ? (a) : (b))
+#define IMIN(a,b) ((a) < (b) ? (a) : (b))
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifdef _USE_SSE
+#include "resample_sse.h"
+#endif
+
+/* Numer of elements to allocate on the stack */
+#ifdef VAR_ARRAYS
+#define FIXED_STACK_ALLOC 8192
+#else
+#define FIXED_STACK_ALLOC 1024
+#endif
+
+typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *);
+
+struct SpeexResamplerState_ {
+ spx_uint32_t in_rate;
+ spx_uint32_t out_rate;
+ spx_uint32_t num_rate;
+ spx_uint32_t den_rate;
+
+ int quality;
+ spx_uint32_t nb_channels;
+ spx_uint32_t filt_len;
+ spx_uint32_t mem_alloc_size;
+ spx_uint32_t buffer_size;
+ int int_advance;
+ int frac_advance;
+ float cutoff;
+ spx_uint32_t oversample;
+ int initialised;
+ int started;
+
+ /* These are per-channel */
+ spx_int32_t *last_sample;
+ spx_uint32_t *samp_frac_num;
+ spx_uint32_t *magic_samples;
+
+ spx_word16_t *mem;
+ spx_word16_t *sinc_table;
+ spx_uint32_t sinc_table_length;
+ resampler_basic_func resampler_ptr;
+
+ int in_stride;
+ int out_stride;
+} ;
+
+static double kaiser12_table[68] = {
+ 0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076,
+ 0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014,
+ 0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601,
+ 0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014,
+ 0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490,
+ 0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546,
+ 0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178,
+ 0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947,
+ 0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058,
+ 0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438,
+ 0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734,
+ 0.00001000, 0.00000000};
+/*
+static double kaiser12_table[36] = {
+ 0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741,
+ 0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762,
+ 0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274,
+ 0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466,
+ 0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291,
+ 0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000};
+*/
+static double kaiser10_table[36] = {
+ 0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446,
+ 0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347,
+ 0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962,
+ 0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451,
+ 0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739,
+ 0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000};
+
+static double kaiser8_table[36] = {
+ 0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200,
+ 0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126,
+ 0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272,
+ 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758,
+ 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490,
+ 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000};
+
+static double kaiser6_table[36] = {
+ 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003,
+ 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565,
+ 0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561,
+ 0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058,
+ 0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600,
+ 0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000};
+
+struct FuncDef {
+ double *table;
+ int oversample;
+};
+
+static struct FuncDef _KAISER12 = {kaiser12_table, 64};
+#define KAISER12 (&_KAISER12)
+/*static struct FuncDef _KAISER12 = {kaiser12_table, 32};
+#define KAISER12 (&_KAISER12)*/
+static struct FuncDef _KAISER10 = {kaiser10_table, 32};
+#define KAISER10 (&_KAISER10)
+static struct FuncDef _KAISER8 = {kaiser8_table, 32};
+#define KAISER8 (&_KAISER8)
+static struct FuncDef _KAISER6 = {kaiser6_table, 32};
+#define KAISER6 (&_KAISER6)
+
+struct QualityMapping {
+ int base_length;
+ int oversample;
+ float downsample_bandwidth;
+ float upsample_bandwidth;
+ struct FuncDef *window_func;
+};
+
+
+/* This table maps conversion quality to internal parameters. There are two
+ reasons that explain why the up-sampling bandwidth is larger than the
+ down-sampling bandwidth:
+ 1) When up-sampling, we can assume that the spectrum is already attenuated
+ close to the Nyquist rate (from an A/D or a previous resampling filter)
+ 2) Any aliasing that occurs very close to the Nyquist rate will be masked
+ by the sinusoids/noise just below the Nyquist rate (guaranteed only for
+ up-sampling).
+*/
+static const struct QualityMapping quality_map[11] = {
+ { 8, 4, 0.830f, 0.860f, KAISER6 }, /* Q0 */
+ { 16, 4, 0.850f, 0.880f, KAISER6 }, /* Q1 */
+ { 32, 4, 0.882f, 0.910f, KAISER6 }, /* Q2 */ /* 82.3% cutoff ( ~60 dB stop) 6 */
+ { 48, 8, 0.895f, 0.917f, KAISER8 }, /* Q3 */ /* 84.9% cutoff ( ~80 dB stop) 8 */
+ { 64, 8, 0.921f, 0.940f, KAISER8 }, /* Q4 */ /* 88.7% cutoff ( ~80 dB stop) 8 */
+ { 80, 16, 0.922f, 0.940f, KAISER10}, /* Q5 */ /* 89.1% cutoff (~100 dB stop) 10 */
+ { 96, 16, 0.940f, 0.945f, KAISER10}, /* Q6 */ /* 91.5% cutoff (~100 dB stop) 10 */
+ {128, 16, 0.950f, 0.950f, KAISER10}, /* Q7 */ /* 93.1% cutoff (~100 dB stop) 10 */
+ {160, 16, 0.960f, 0.960f, KAISER10}, /* Q8 */ /* 94.5% cutoff (~100 dB stop) 10 */
+ {192, 32, 0.968f, 0.968f, KAISER12}, /* Q9 */ /* 95.5% cutoff (~100 dB stop) 10 */
+ {256, 32, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */
+};
+/*8,24,40,56,80,104,128,160,200,256,320*/
+static double compute_func(float x, struct FuncDef *func)
+{
+ float y, frac;
+ double interp[4];
+ int ind;
+ y = x*func->oversample;
+ ind = (int)floor(y);
+ frac = (y-ind);
+ /* CSE with handle the repeated powers */
+ interp[3] = -0.1666666667*frac + 0.1666666667*(frac*frac*frac);
+ interp[2] = frac + 0.5*(frac*frac) - 0.5*(frac*frac*frac);
+ /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
+ interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac);
+ /* Just to make sure we don't have rounding problems */
+ interp[1] = 1.f-interp[3]-interp[2]-interp[0];
+
+ /*sum = frac*accum[1] + (1-frac)*accum[2];*/
+ return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3];
+}
+
+#if 0
+#include <stdio.h>
+int main(int argc, char **argv)
+{
+ int i;
+ for (i=0;i<256;i++)
+ {
+ printf ("%f\n", compute_func(i/256., KAISER12));
+ }
+ return 0;
+}
+#endif
+
+#ifdef FIXED_POINT
+/* The slow way of computing a sinc for the table. Should improve that some day */
+static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func)
+{
+ /*fprintf (stderr, "%f ", x);*/
+ float xx = x * cutoff;
+ if (fabs(x)<1e-6f)
+ return WORD2INT(32768.*cutoff);
+ else if (fabs(x) > .5f*N)
+ return 0;
+ /*FIXME: Can it really be any slower than this? */
+ return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func));
+}
+#else
+/* The slow way of computing a sinc for the table. Should improve that some day */
+static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func)
+{
+ /*fprintf (stderr, "%f ", x);*/
+ float xx = x * cutoff;
+ if (fabs(x)<1e-6)
+ return cutoff;
+ else if (fabs(x) > .5*N)
+ return 0;
+ /*FIXME: Can it really be any slower than this? */
+ return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func);
+}
+#endif
+
+#ifdef FIXED_POINT
+static void cubic_coef(spx_word16_t x, spx_word16_t interp[4])
+{
+ /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
+ but I know it's MMSE-optimal on a sinc */
+ spx_word16_t x2, x3;
+ x2 = MULT16_16_P15(x, x);
+ x3 = MULT16_16_P15(x, x2);
+ interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15);
+ interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1));
+ interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15);
+ /* Just to make sure we don't have rounding problems */
+ interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3];
+ if (interp[2]<32767)
+ interp[2]+=1;
+}
+#else
+static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4])
+{
+ /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
+ but I know it's MMSE-optimal on a sinc */
+ interp[0] = -0.16667f*frac + 0.16667f*frac*frac*frac;
+ interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac;
+ /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
+ interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac;
+ /* Just to make sure we don't have rounding problems */
+ interp[2] = 1.-interp[0]-interp[1]-interp[3];
+}
+#endif
+
+static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
+{
+ const int N = st->filt_len;
+ int out_sample = 0;
+ int last_sample = st->last_sample[channel_index];
+ spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
+ const spx_word16_t *sinc_table = st->sinc_table;
+ const int out_stride = st->out_stride;
+ const int int_advance = st->int_advance;
+ const int frac_advance = st->frac_advance;
+ const spx_uint32_t den_rate = st->den_rate;
+ spx_word32_t sum;
+ int j;
+
+ while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
+ {
+ const spx_word16_t *sinc = & sinc_table[samp_frac_num*N];
+ const spx_word16_t *iptr = & in[last_sample];
+
+#ifndef OVERRIDE_INNER_PRODUCT_SINGLE
+ float accum[4] = {0,0,0,0};
+
+ for(j=0;j<N;j+=4) {
+ accum[0] += sinc[j]*iptr[j];
+ accum[1] += sinc[j+1]*iptr[j+1];
+ accum[2] += sinc[j+2]*iptr[j+2];
+ accum[3] += sinc[j+3]*iptr[j+3];
+ }
+ sum = accum[0] + accum[1] + accum[2] + accum[3];
+#else
+ sum = inner_product_single(sinc, iptr, N);
+#endif
+
+ out[out_stride * out_sample++] = PSHR32(sum, 15);
+ last_sample += int_advance;
+ samp_frac_num += frac_advance;
+ if (samp_frac_num >= den_rate)
+ {
+ samp_frac_num -= den_rate;
+ last_sample++;
+ }
+ }
+
+ st->last_sample[channel_index] = last_sample;
+ st->samp_frac_num[channel_index] = samp_frac_num;
+ return out_sample;
+}
+
+#ifdef FIXED_POINT
+#else
+/* This is the same as the previous function, except with a double-precision accumulator */
+static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
+{
+ const int N = st->filt_len;
+ int out_sample = 0;
+ int last_sample = st->last_sample[channel_index];
+ spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
+ const spx_word16_t *sinc_table = st->sinc_table;
+ const int out_stride = st->out_stride;
+ const int int_advance = st->int_advance;
+ const int frac_advance = st->frac_advance;
+ const spx_uint32_t den_rate = st->den_rate;
+ double sum;
+ int j;
+
+ while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
+ {
+ const spx_word16_t *sinc = & sinc_table[samp_frac_num*N];
+ const spx_word16_t *iptr = & in[last_sample];
+
+#ifndef OVERRIDE_INNER_PRODUCT_DOUBLE
+ double accum[4] = {0,0,0,0};
+
+ for(j=0;j<N;j+=4) {
+ accum[0] += sinc[j]*iptr[j];
+ accum[1] += sinc[j+1]*iptr[j+1];
+ accum[2] += sinc[j+2]*iptr[j+2];
+ accum[3] += sinc[j+3]*iptr[j+3];
+ }
+ sum = accum[0] + accum[1] + accum[2] + accum[3];
+#else
+ sum = inner_product_double(sinc, iptr, N);
+#endif
+
+ out[out_stride * out_sample++] = PSHR32(sum, 15);
+ last_sample += int_advance;
+ samp_frac_num += frac_advance;
+ if (samp_frac_num >= den_rate)
+ {
+ samp_frac_num -= den_rate;
+ last_sample++;
+ }
+ }
+
+ st->last_sample[channel_index] = last_sample;
+ st->samp_frac_num[channel_index] = samp_frac_num;
+ return out_sample;
+}
+#endif
+
+static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
+{
+ const int N = st->filt_len;
+ int out_sample = 0;
+ int last_sample = st->last_sample[channel_index];
+ spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
+ const int out_stride = st->out_stride;
+ const int int_advance = st->int_advance;
+ const int frac_advance = st->frac_advance;
+ const spx_uint32_t den_rate = st->den_rate;
+ int j;
+ spx_word32_t sum;
+
+ while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
+ {
+ const spx_word16_t *iptr = & in[last_sample];
+
+ const int offset = samp_frac_num*st->oversample/st->den_rate;
+#ifdef FIXED_POINT
+ const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);
+#else
+ const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;
+#endif
+ spx_word16_t interp[4];
+
+
+#ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE
+ spx_word32_t accum[4] = {0,0,0,0};
+
+ for(j=0;j<N;j++) {
+ const spx_word16_t curr_in=iptr[j];
+ accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
+ accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
+ accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
+ accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
+ }
+
+ cubic_coef(frac, interp);
+ sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]);
+#else
+ cubic_coef(frac, interp);
+ sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
+#endif
+
+ out[out_stride * out_sample++] = PSHR32(sum,15);
+ last_sample += int_advance;
+ samp_frac_num += frac_advance;
+ if (samp_frac_num >= den_rate)
+ {
+ samp_frac_num -= den_rate;
+ last_sample++;
+ }
+ }
+
+ st->last_sample[channel_index] = last_sample;
+ st->samp_frac_num[channel_index] = samp_frac_num;
+ return out_sample;
+}
+
+#ifdef FIXED_POINT
+#else
+/* This is the same as the previous function, except with a double-precision accumulator */
+static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
+{
+ const int N = st->filt_len;
+ int out_sample = 0;
+ int last_sample = st->last_sample[channel_index];
+ spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
+ const int out_stride = st->out_stride;
+ const int int_advance = st->int_advance;
+ const int frac_advance = st->frac_advance;
+ const spx_uint32_t den_rate = st->den_rate;
+ int j;
+ spx_word32_t sum;
+
+ while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
+ {
+ const spx_word16_t *iptr = & in[last_sample];
+
+ const int offset = samp_frac_num*st->oversample/st->den_rate;
+#ifdef FIXED_POINT
+ const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);
+#else
+ const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;
+#endif
+ spx_word16_t interp[4];
+
+
+#ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE
+ double accum[4] = {0,0,0,0};
+
+ for(j=0;j<N;j++) {
+ const double curr_in=iptr[j];
+ accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
+ accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
+ accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
+ accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
+ }
+
+ cubic_coef(frac, interp);
+ sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]);
+#else
+ cubic_coef(frac, interp);
+ sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
+#endif
+
+ out[out_stride * out_sample++] = PSHR32(sum,15);
+ last_sample += int_advance;
+ samp_frac_num += frac_advance;
+ if (samp_frac_num >= den_rate)
+ {
+ samp_frac_num -= den_rate;
+ last_sample++;
+ }
+ }
+
+ st->last_sample[channel_index] = last_sample;
+ st->samp_frac_num[channel_index] = samp_frac_num;
+ return out_sample;
+}
+#endif
+
+static void update_filter(SpeexResamplerState *st)
+{
+ spx_uint32_t old_length;
+
+ old_length = st->filt_len;
+ st->oversample = quality_map[st->quality].oversample;
+ st->filt_len = quality_map[st->quality].base_length;
+
+ if (st->num_rate > st->den_rate)
+ {
+ /* down-sampling */
+ st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate;
+ /* FIXME: divide the numerator and denominator by a certain amount if they're too large */
+ st->filt_len = st->filt_len*st->num_rate / st->den_rate;
+ /* Round down to make sure we have a multiple of 4 */
+ st->filt_len &= (~0x3);
+ if (2*st->den_rate < st->num_rate)
+ st->oversample >>= 1;
+ if (4*st->den_rate < st->num_rate)
+ st->oversample >>= 1;
+ if (8*st->den_rate < st->num_rate)
+ st->oversample >>= 1;
+ if (16*st->den_rate < st->num_rate)
+ st->oversample >>= 1;
+ if (st->oversample < 1)
+ st->oversample = 1;
+ } else {
+ /* up-sampling */
+ st->cutoff = quality_map[st->quality].upsample_bandwidth;
+ }
+
+ /* Choose the resampling type that requires the least amount of memory */
+ if (st->den_rate <= st->oversample)
+ {
+ spx_uint32_t i;
+ if (!st->sinc_table)
+ st->sinc_table = (spx_word16_t *)speex_alloc(st->filt_len*st->den_rate*sizeof(spx_word16_t));
+ else if (st->sinc_table_length < st->filt_len*st->den_rate)
+ {
+ st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,st->filt_len*st->den_rate*sizeof(spx_word16_t));
+ st->sinc_table_length = st->filt_len*st->den_rate;
+ }
+ for (i=0;i<st->den_rate;i++)
+ {
+ spx_int32_t j;
+ for (j=0;j<st->filt_len;j++)
+ {
+ st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-(spx_int32_t)st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len, quality_map[st->quality].window_func);
+ }
+ }
+#ifdef FIXED_POINT
+ st->resampler_ptr = resampler_basic_direct_single;
+#else
+ if (st->quality>8)
+ st->resampler_ptr = resampler_basic_direct_double;
+ else
+ st->resampler_ptr = resampler_basic_direct_single;
+#endif
+ /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/
+ } else {
+ spx_int32_t i;
+ if (!st->sinc_table)
+ st->sinc_table = (spx_word16_t *)speex_alloc((st->filt_len*st->oversample+8)*sizeof(spx_word16_t));
+ else if (st->sinc_table_length < st->filt_len*st->oversample+8)
+ {
+ st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,(st->filt_len*st->oversample+8)*sizeof(spx_word16_t));
+ st->sinc_table_length = st->filt_len*st->oversample+8;
+ }
+ for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++)
+ st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func);
+#ifdef FIXED_POINT
+ st->resampler_ptr = resampler_basic_interpolate_single;
+#else
+ if (st->quality>8)
+ st->resampler_ptr = resampler_basic_interpolate_double;
+ else
+ st->resampler_ptr = resampler_basic_interpolate_single;
+#endif
+ /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/
+ }
+ st->int_advance = st->num_rate/st->den_rate;
+ st->frac_advance = st->num_rate%st->den_rate;
+
+
+ /* Here's the place where we update the filter memory to take into account
+ the change in filter length. It's probably the messiest part of the code
+ due to handling of lots of corner cases. */
+ if (!st->mem)
+ {
+ spx_uint32_t i;
+ st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
+ st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
+ for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)
+ st->mem[i] = 0;
+ /*speex_warning("init filter");*/
+ } else if (!st->started)
+ {
+ spx_uint32_t i;
+ st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
+ st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
+ for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)
+ st->mem[i] = 0;
+ /*speex_warning("reinit filter");*/
+ } else if (st->filt_len > old_length)
+ {
+ spx_int32_t i;
+ /* Increase the filter length */
+ /*speex_warning("increase filter size");*/
+ int old_alloc_size = st->mem_alloc_size;
+ if ((st->filt_len-1 + st->buffer_size) > st->mem_alloc_size)
+ {
+ st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
+ st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
+ }
+ for (i=st->nb_channels-1;i>=0;i--)
+ {
+ spx_int32_t j;
+ spx_uint32_t olen = old_length;
+ /*if (st->magic_samples[i])*/
+ {
+ /* Try and remove the magic samples as if nothing had happened */
+
+ /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */
+ olen = old_length + 2*st->magic_samples[i];
+ for (j=old_length-2+st->magic_samples[i];j>=0;j--)
+ st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]] = st->mem[i*old_alloc_size+j];
+ for (j=0;j<st->magic_samples[i];j++)
+ st->mem[i*st->mem_alloc_size+j] = 0;
+ st->magic_samples[i] = 0;
+ }
+ if (st->filt_len > olen)
+ {
+ /* If the new filter length is still bigger than the "augmented" length */
+ /* Copy data going backward */
+ for (j=0;j<olen-1;j++)
+ st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*st->mem_alloc_size+(olen-2-j)];
+ /* Then put zeros for lack of anything better */
+ for (;j<st->filt_len-1;j++)
+ st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0;
+ /* Adjust last_sample */
+ st->last_sample[i] += (st->filt_len - olen)/2;
+ } else {
+ /* Put back some of the magic! */
+ st->magic_samples[i] = (olen - st->filt_len)/2;
+ for (j=0;j<st->filt_len-1+st->magic_samples[i];j++)
+ st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];
+ }
+ }
+ } else if (st->filt_len < old_length)
+ {
+ spx_uint32_t i;
+ /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic"
+ samples so they can be used directly as input the next time(s) */
+ for (i=0;i<st->nb_channels;i++)
+ {
+ spx_uint32_t j;
+ spx_uint32_t old_magic = st->magic_samples[i];
+ st->magic_samples[i] = (old_length - st->filt_len)/2;
+ /* We must copy some of the memory that's no longer used */
+ /* Copy data going backward */
+ for (j=0;j<st->filt_len-1+st->magic_samples[i]+old_magic;j++)
+ st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];
+ st->magic_samples[i] += old_magic;
+ }
+ }
+
+}
+
+ SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
+{
+ return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err);
+}
+
+ SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
+{
+ spx_uint32_t i;
+ SpeexResamplerState *st;
+ if (quality > 10 || quality < 0)
+ {
+ if (err)
+ *err = RESAMPLER_ERR_INVALID_ARG;
+ return NULL;
+ }
+ st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState));
+ st->initialised = 0;
+ st->started = 0;
+ st->in_rate = 0;
+ st->out_rate = 0;
+ st->num_rate = 0;
+ st->den_rate = 0;
+ st->quality = -1;
+ st->sinc_table_length = 0;
+ st->mem_alloc_size = 0;
+ st->filt_len = 0;
+ st->mem = 0;
+ st->resampler_ptr = 0;
+
+ st->cutoff = 1.f;
+ st->nb_channels = nb_channels;
+ st->in_stride = 1;
+ st->out_stride = 1;
+
+#ifdef FIXED_POINT
+ st->buffer_size = 160;
+#else
+ st->buffer_size = 160;
+#endif
+
+ /* Per channel data */
+ st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int));
+ st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
+ st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
+ for (i=0;i<nb_channels;i++)
+ {
+ st->last_sample[i] = 0;
+ st->magic_samples[i] = 0;
+ st->samp_frac_num[i] = 0;
+ }
+
+ speex_resampler_set_quality(st, quality);
+ speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate);
+
+
+ update_filter(st);
+
+ st->initialised = 1;
+ if (err)
+ *err = RESAMPLER_ERR_SUCCESS;
+
+ return st;
+}
+
+ void speex_resampler_destroy(SpeexResamplerState *st)
+{
+ speex_free(st->mem);
+ speex_free(st->sinc_table);
+ speex_free(st->last_sample);
+ speex_free(st->magic_samples);
+ speex_free(st->samp_frac_num);
+ speex_free(st);
+}
+
+static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
+{
+ int j=0;
+ const int N = st->filt_len;
+ int out_sample = 0;
+ spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;
+ spx_uint32_t ilen;
+
+ st->started = 1;
+
+ /* Call the right resampler through the function ptr */
+ out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len);
+
+ if (st->last_sample[channel_index] < (spx_int32_t)*in_len)
+ *in_len = st->last_sample[channel_index];
+ *out_len = out_sample;
+ st->last_sample[channel_index] -= *in_len;
+
+ ilen = *in_len;
+
+ for(j=0;j<N-1;++j)
+ mem[j] = mem[j+ilen];
+
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_index, spx_word16_t **out, spx_uint32_t out_len) {
+ spx_uint32_t tmp_in_len = st->magic_samples[channel_index];
+ spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;
+ const int N = st->filt_len;
+
+ speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len);
+
+ st->magic_samples[channel_index] -= tmp_in_len;
+
+ /* If we couldn't process all "magic" input samples, save the rest for next time */
+ if (st->magic_samples[channel_index])
+ {
+ spx_uint32_t i;
+ for (i=0;i<st->magic_samples[channel_index];i++)
+ mem[N-1+i]=mem[N-1+i+tmp_in_len];
+ }
+ *out += out_len*st->out_stride;
+ return out_len;
+}
+
+#ifdef FIXED_POINT
+ int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
+#else
+ int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
+#endif
+{
+ int j;
+ spx_uint32_t ilen = *in_len;
+ spx_uint32_t olen = *out_len;
+ spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;
+ const int filt_offs = st->filt_len - 1;
+ const spx_uint32_t xlen = st->mem_alloc_size - filt_offs;
+ const int istride = st->in_stride;
+
+ if (st->magic_samples[channel_index])
+ olen -= speex_resampler_magic(st, channel_index, &out, olen);
+ if (! st->magic_samples[channel_index]) {
+ while (ilen && olen) {
+ spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;
+ spx_uint32_t ochunk = olen;
+
+ if (in) {
+ for(j=0;j<ichunk;++j)
+ x[j+filt_offs]=in[j*istride];
+ } else {
+ for(j=0;j<ichunk;++j)
+ x[j+filt_offs]=0;
+ }
+ speex_resampler_process_native(st, channel_index, &ichunk, out, &ochunk);
+ ilen -= ichunk;
+ olen -= ochunk;
+ out += ochunk * st->out_stride;
+ if (in)
+ in += ichunk * istride;
+ }
+ }
+ *in_len -= ilen;
+ *out_len -= olen;
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+#ifdef FIXED_POINT
+ int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
+#else
+ int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
+#endif
+{
+ int j;
+ const int istride_save = st->in_stride;
+ const int ostride_save = st->out_stride;
+ spx_uint32_t ilen = *in_len;
+ spx_uint32_t olen = *out_len;
+ spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;
+ const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1);
+#ifdef VAR_ARRAYS
+ const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC;
+ VARDECL(spx_word16_t *ystack);
+ ALLOC(ystack, ylen, spx_word16_t);
+#else
+ const unsigned int ylen = FIXED_STACK_ALLOC;
+ spx_word16_t ystack[FIXED_STACK_ALLOC];
+#endif
+
+ st->out_stride = 1;
+
+ while (ilen && olen) {
+ spx_word16_t *y = ystack;
+ spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;
+ spx_uint32_t ochunk = (olen > ylen) ? ylen : olen;
+ spx_uint32_t omagic = 0;
+
+ if (st->magic_samples[channel_index]) {
+ omagic = speex_resampler_magic(st, channel_index, &y, ochunk);
+ ochunk -= omagic;
+ olen -= omagic;
+ }
+ if (! st->magic_samples[channel_index]) {
+ if (in) {
+ for(j=0;j<ichunk;++j)
+#ifdef FIXED_POINT
+ x[j+st->filt_len-1]=WORD2INT(in[j*istride_save]);
+#else
+ x[j+st->filt_len-1]=in[j*istride_save];
+#endif
+ } else {
+ for(j=0;j<ichunk;++j)
+ x[j+st->filt_len-1]=0;
+ }
+
+ speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk);
+ } else {
+ ichunk = 0;
+ ochunk = 0;
+ }
+
+ for (j=0;j<ochunk+omagic;++j)
+#ifdef FIXED_POINT
+ out[j*ostride_save] = ystack[j];
+#else
+ out[j*ostride_save] = WORD2INT(ystack[j]);
+#endif
+
+ ilen -= ichunk;
+ olen -= ochunk;
+ out += (ochunk+omagic) * ostride_save;
+ if (in)
+ in += ichunk * istride_save;
+ }
+ st->out_stride = ostride_save;
+ *in_len -= ilen;
+ *out_len -= olen;
+
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+ int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
+{
+ spx_uint32_t i;
+ int istride_save, ostride_save;
+ spx_uint32_t bak_len = *out_len;
+ istride_save = st->in_stride;
+ ostride_save = st->out_stride;
+ st->in_stride = st->out_stride = st->nb_channels;
+ for (i=0;i<st->nb_channels;i++)
+ {
+ *out_len = bak_len;
+ if (in != NULL)
+ speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len);
+ else
+ speex_resampler_process_float(st, i, NULL, in_len, out+i, out_len);
+ }
+ st->in_stride = istride_save;
+ st->out_stride = ostride_save;
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+ int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
+{
+ spx_uint32_t i;
+ int istride_save, ostride_save;
+ spx_uint32_t bak_len = *out_len;
+ istride_save = st->in_stride;
+ ostride_save = st->out_stride;
+ st->in_stride = st->out_stride = st->nb_channels;
+ for (i=0;i<st->nb_channels;i++)
+ {
+ *out_len = bak_len;
+ if (in != NULL)
+ speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len);
+ else
+ speex_resampler_process_int(st, i, NULL, in_len, out+i, out_len);
+ }
+ st->in_stride = istride_save;
+ st->out_stride = ostride_save;
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+ int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate)
+{
+ return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate);
+}
+
+ void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate)
+{
+ *in_rate = st->in_rate;
+ *out_rate = st->out_rate;
+}
+
+ int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate)
+{
+ spx_uint32_t fact;
+ spx_uint32_t old_den;
+ spx_uint32_t i;
+ if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den)
+ return RESAMPLER_ERR_SUCCESS;
+
+ old_den = st->den_rate;
+ st->in_rate = in_rate;
+ st->out_rate = out_rate;
+ st->num_rate = ratio_num;
+ st->den_rate = ratio_den;
+ /* FIXME: This is terribly inefficient, but who cares (at least for now)? */
+ for (fact=2;fact<=IMIN(st->num_rate, st->den_rate);fact++)
+ {
+ while ((st->num_rate % fact == 0) && (st->den_rate % fact == 0))
+ {
+ st->num_rate /= fact;
+ st->den_rate /= fact;
+ }
+ }
+
+ if (old_den > 0)
+ {
+ for (i=0;i<st->nb_channels;i++)
+ {
+ st->samp_frac_num[i]=st->samp_frac_num[i]*st->den_rate/old_den;
+ /* Safety net */
+ if (st->samp_frac_num[i] >= st->den_rate)
+ st->samp_frac_num[i] = st->den_rate-1;
+ }
+ }
+
+ if (st->initialised)
+ update_filter(st);
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+ void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den)
+{
+ *ratio_num = st->num_rate;
+ *ratio_den = st->den_rate;
+}
+
+ int speex_resampler_set_quality(SpeexResamplerState *st, int quality)
+{
+ if (quality > 10 || quality < 0)
+ return RESAMPLER_ERR_INVALID_ARG;
+ if (st->quality == quality)
+ return RESAMPLER_ERR_SUCCESS;
+ st->quality = quality;
+ if (st->initialised)
+ update_filter(st);
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+ void speex_resampler_get_quality(SpeexResamplerState *st, int *quality)
+{
+ *quality = st->quality;
+}
+
+ void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride)
+{
+ st->in_stride = stride;
+}
+
+ void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride)
+{
+ *stride = st->in_stride;
+}
+
+ void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride)
+{
+ st->out_stride = stride;
+}
+
+ void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride)
+{
+ *stride = st->out_stride;
+}
+
+ int speex_resampler_get_input_latency(SpeexResamplerState *st)
+{
+ return st->filt_len / 2;
+}
+
+ int speex_resampler_get_output_latency(SpeexResamplerState *st)
+{
+ return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate;
+}
+
+ int speex_resampler_skip_zeros(SpeexResamplerState *st)
+{
+ spx_uint32_t i;
+ for (i=0;i<st->nb_channels;i++)
+ st->last_sample[i] = st->filt_len/2;
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+ int speex_resampler_reset_mem(SpeexResamplerState *st)
+{
+ spx_uint32_t i;
+ for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
+ st->mem[i] = 0;
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+ const char *speex_resampler_strerror(int err)
+{
+ switch (err)
+ {
+ case RESAMPLER_ERR_SUCCESS:
+ return "Success.";
+ case RESAMPLER_ERR_ALLOC_FAILED:
+ return "Memory allocation failed.";
+ case RESAMPLER_ERR_BAD_STATE:
+ return "Bad resampler state.";
+ case RESAMPLER_ERR_INVALID_ARG:
+ return "Invalid argument.";
+ case RESAMPLER_ERR_PTR_OVERLAP:
+ return "Input and output buffers overlap.";
+ default:
+ return "Unknown error. Bad error code or strange version mismatch.";
+ }
+}
diff --git a/codecs/speex/resample_sse.h b/codecs/speex/resample_sse.h
new file mode 100644
index 000000000..4bd35a2d0
--- /dev/null
+++ b/codecs/speex/resample_sse.h
@@ -0,0 +1,128 @@
+/* Copyright (C) 2007-2008 Jean-Marc Valin
+ * Copyright (C) 2008 Thorvald Natvig
+ */
+/**
+ @file resample_sse.h
+ @brief Resampler functions (SSE version)
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Xiph.org Foundation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <xmmintrin.h>
+
+#define OVERRIDE_INNER_PRODUCT_SINGLE
+static inline float inner_product_single(const float *a, const float *b, unsigned int len)
+{
+ int i;
+ float ret;
+ __m128 sum = _mm_setzero_ps();
+ for (i=0;i<len;i+=8)
+ {
+ sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+i), _mm_loadu_ps(b+i)));
+ sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+i+4), _mm_loadu_ps(b+i+4)));
+ }
+ sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum));
+ sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55));
+ _mm_store_ss(&ret, sum);
+ return ret;
+}
+
+#define OVERRIDE_INTERPOLATE_PRODUCT_SINGLE
+static inline float interpolate_product_single(const float *a, const float *b, unsigned int len, const spx_uint32_t oversample, float *frac) {
+ int i;
+ float ret;
+ __m128 sum = _mm_setzero_ps();
+ __m128 f = _mm_loadu_ps(frac);
+ for(i=0;i<len;i+=2)
+ {
+ sum = _mm_add_ps(sum, _mm_mul_ps(_mm_load1_ps(a+i), _mm_loadu_ps(b+i*oversample)));
+ sum = _mm_add_ps(sum, _mm_mul_ps(_mm_load1_ps(a+i+1), _mm_loadu_ps(b+(i+1)*oversample)));
+ }
+ sum = _mm_mul_ps(f, sum);
+ sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum));
+ sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55));
+ _mm_store_ss(&ret, sum);
+ return ret;
+}
+
+#ifdef _USE_SSE2
+#include <emmintrin.h>
+#define OVERRIDE_INNER_PRODUCT_DOUBLE
+
+static inline double inner_product_double(const float *a, const float *b, unsigned int len)
+{
+ int i;
+ double ret;
+ __m128d sum = _mm_setzero_pd();
+ __m128 t;
+ for (i=0;i<len;i+=8)
+ {
+ t = _mm_mul_ps(_mm_loadu_ps(a+i), _mm_loadu_ps(b+i));
+ sum = _mm_add_pd(sum, _mm_cvtps_pd(t));
+ sum = _mm_add_pd(sum, _mm_cvtps_pd(_mm_movehl_ps(t, t)));
+
+ t = _mm_mul_ps(_mm_loadu_ps(a+i+4), _mm_loadu_ps(b+i+4));
+ sum = _mm_add_pd(sum, _mm_cvtps_pd(t));
+ sum = _mm_add_pd(sum, _mm_cvtps_pd(_mm_movehl_ps(t, t)));
+ }
+ sum = _mm_add_sd(sum, (__m128d) _mm_movehl_ps((__m128) sum, (__m128) sum));
+ _mm_store_sd(&ret, sum);
+ return ret;
+}
+
+#define OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE
+static inline double interpolate_product_double(const float *a, const float *b, unsigned int len, const spx_uint32_t oversample, float *frac) {
+ int i;
+ double ret;
+ __m128d sum;
+ __m128d sum1 = _mm_setzero_pd();
+ __m128d sum2 = _mm_setzero_pd();
+ __m128 f = _mm_loadu_ps(frac);
+ __m128d f1 = _mm_cvtps_pd(f);
+ __m128d f2 = _mm_cvtps_pd(_mm_movehl_ps(f,f));
+ __m128 t;
+ for(i=0;i<len;i+=2)
+ {
+ t = _mm_mul_ps(_mm_load1_ps(a+i), _mm_loadu_ps(b+i*oversample));
+ sum1 = _mm_add_pd(sum1, _mm_cvtps_pd(t));
+ sum2 = _mm_add_pd(sum2, _mm_cvtps_pd(_mm_movehl_ps(t, t)));
+
+ t = _mm_mul_ps(_mm_load1_ps(a+i+1), _mm_loadu_ps(b+(i+1)*oversample));
+ sum1 = _mm_add_pd(sum1, _mm_cvtps_pd(t));
+ sum2 = _mm_add_pd(sum2, _mm_cvtps_pd(_mm_movehl_ps(t, t)));
+ }
+ sum1 = _mm_mul_pd(f1, sum1);
+ sum2 = _mm_mul_pd(f2, sum2);
+ sum = _mm_add_pd(sum1, sum2);
+ sum = _mm_add_sd(sum, (__m128d) _mm_movehl_ps((__m128) sum, (__m128) sum));
+ _mm_store_sd(&ret, sum);
+ return ret;
+}
+
+#endif
diff --git a/codecs/speex/speex_resampler.h b/codecs/speex/speex_resampler.h
new file mode 100644
index 000000000..0247e180e
--- /dev/null
+++ b/codecs/speex/speex_resampler.h
@@ -0,0 +1,342 @@
+/* Copyright (C) 2007 Jean-Marc Valin
+
+ File: speex_resampler.h
+ Resampling code
+
+ The design goals of this code are:
+ - Very fast algorithm
+ - Low memory requirement
+ - Good *perceptual* quality (and not best SNR)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef SPEEX_RESAMPLER_H
+#define SPEEX_RESAMPLER_H
+
+#define OUTSIDE_SPEEX
+
+#ifdef OUTSIDE_SPEEX
+
+/********* WARNING: MENTAL SANITY ENDS HERE *************/
+
+/* If the resampler is defined outside of Speex, we change the symbol names so that
+ there won't be any clash if linking with Speex later on. */
+
+#define RANDOM_PREFIX ast
+#ifndef RANDOM_PREFIX
+#error "Please define RANDOM_PREFIX (above) to something specific to your project to prevent symbol name clashes"
+#endif
+
+#define CAT_PREFIX2(a,b) a ## b
+#define CAT_PREFIX(a,b) CAT_PREFIX2(a, b)
+
+#define speex_resampler_init CAT_PREFIX(RANDOM_PREFIX,_resampler_init)
+#define speex_resampler_init_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_init_frac)
+#define speex_resampler_destroy CAT_PREFIX(RANDOM_PREFIX,_resampler_destroy)
+#define speex_resampler_process_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_float)
+#define speex_resampler_process_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_int)
+#define speex_resampler_process_interleaved_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_float)
+#define speex_resampler_process_interleaved_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_int)
+#define speex_resampler_set_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate)
+#define speex_resampler_get_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_get_rate)
+#define speex_resampler_set_rate_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate_frac)
+#define speex_resampler_get_ratio CAT_PREFIX(RANDOM_PREFIX,_resampler_get_ratio)
+#define speex_resampler_set_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_set_quality)
+#define speex_resampler_get_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_get_quality)
+#define speex_resampler_set_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_input_stride)
+#define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride)
+#define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride)
+#define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride)
+#define speex_resampler_get_input_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_latency)
+#define speex_resampler_get_output_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_latency)
+#define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros)
+#define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem)
+#define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror)
+
+#define spx_int16_t short
+#define spx_int32_t int
+#define spx_uint16_t unsigned short
+#define spx_uint32_t unsigned int
+
+#else /* OUTSIDE_SPEEX */
+
+#include "speex/speex_types.h"
+
+#endif /* OUTSIDE_SPEEX */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SPEEX_RESAMPLER_QUALITY_MAX 10
+#define SPEEX_RESAMPLER_QUALITY_MIN 0
+#define SPEEX_RESAMPLER_QUALITY_DEFAULT 4
+#define SPEEX_RESAMPLER_QUALITY_VOIP 3
+#define SPEEX_RESAMPLER_QUALITY_DESKTOP 5
+
+enum {
+ RESAMPLER_ERR_SUCCESS = 0,
+ RESAMPLER_ERR_ALLOC_FAILED = 1,
+ RESAMPLER_ERR_BAD_STATE = 2,
+ RESAMPLER_ERR_INVALID_ARG = 3,
+ RESAMPLER_ERR_PTR_OVERLAP = 4,
+
+ RESAMPLER_ERR_MAX_ERROR
+};
+
+struct SpeexResamplerState_;
+typedef struct SpeexResamplerState_ SpeexResamplerState;
+
+/** Create a new resampler with integer input and output rates.
+ * @param nb_channels Number of channels to be processed
+ * @param in_rate Input sampling rate (integer number of Hz).
+ * @param out_rate Output sampling rate (integer number of Hz).
+ * @param quality Resampling quality between 0 and 10, where 0 has poor quality
+ * and 10 has very high quality.
+ * @return Newly created resampler state
+ * @retval NULL Error: not enough memory
+ */
+SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels,
+ spx_uint32_t in_rate,
+ spx_uint32_t out_rate,
+ int quality,
+ int *err);
+
+/** Create a new resampler with fractional input/output rates. The sampling
+ * rate ratio is an arbitrary rational number with both the numerator and
+ * denominator being 32-bit integers.
+ * @param nb_channels Number of channels to be processed
+ * @param ratio_num Numerator of the sampling rate ratio
+ * @param ratio_den Denominator of the sampling rate ratio
+ * @param in_rate Input sampling rate rounded to the nearest integer (in Hz).
+ * @param out_rate Output sampling rate rounded to the nearest integer (in Hz).
+ * @param quality Resampling quality between 0 and 10, where 0 has poor quality
+ * and 10 has very high quality.
+ * @return Newly created resampler state
+ * @retval NULL Error: not enough memory
+ */
+SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels,
+ spx_uint32_t ratio_num,
+ spx_uint32_t ratio_den,
+ spx_uint32_t in_rate,
+ spx_uint32_t out_rate,
+ int quality,
+ int *err);
+
+/** Destroy a resampler state.
+ * @param st Resampler state
+ */
+void speex_resampler_destroy(SpeexResamplerState *st);
+
+/** Resample a float array. The input and output buffers must *not* overlap.
+ * @param st Resampler state
+ * @param channel_index Index of the channel to process for the multi-channel
+ * base (0 otherwise)
+ * @param in Input buffer
+ * @param in_len Number of input samples in the input buffer. Returns the
+ * number of samples processed
+ * @param out Output buffer
+ * @param out_len Size of the output buffer. Returns the number of samples written
+ */
+int speex_resampler_process_float(SpeexResamplerState *st,
+ spx_uint32_t channel_index,
+ const float *in,
+ spx_uint32_t *in_len,
+ float *out,
+ spx_uint32_t *out_len);
+
+/** Resample an int array. The input and output buffers must *not* overlap.
+ * @param st Resampler state
+ * @param channel_index Index of the channel to process for the multi-channel
+ * base (0 otherwise)
+ * @param in Input buffer
+ * @param in_len Number of input samples in the input buffer. Returns the number
+ * of samples processed
+ * @param out Output buffer
+ * @param out_len Size of the output buffer. Returns the number of samples written
+ */
+int speex_resampler_process_int(SpeexResamplerState *st,
+ spx_uint32_t channel_index,
+ const spx_int16_t *in,
+ spx_uint32_t *in_len,
+ spx_int16_t *out,
+ spx_uint32_t *out_len);
+
+/** Resample an interleaved float array. The input and output buffers must *not* overlap.
+ * @param st Resampler state
+ * @param in Input buffer
+ * @param in_len Number of input samples in the input buffer. Returns the number
+ * of samples processed. This is all per-channel.
+ * @param out Output buffer
+ * @param out_len Size of the output buffer. Returns the number of samples written.
+ * This is all per-channel.
+ */
+int speex_resampler_process_interleaved_float(SpeexResamplerState *st,
+ const float *in,
+ spx_uint32_t *in_len,
+ float *out,
+ spx_uint32_t *out_len);
+
+/** Resample an interleaved int array. The input and output buffers must *not* overlap.
+ * @param st Resampler state
+ * @param in Input buffer
+ * @param in_len Number of input samples in the input buffer. Returns the number
+ * of samples processed. This is all per-channel.
+ * @param out Output buffer
+ * @param out_len Size of the output buffer. Returns the number of samples written.
+ * This is all per-channel.
+ */
+int speex_resampler_process_interleaved_int(SpeexResamplerState *st,
+ const spx_int16_t *in,
+ spx_uint32_t *in_len,
+ spx_int16_t *out,
+ spx_uint32_t *out_len);
+
+/** Set (change) the input/output sampling rates (integer value).
+ * @param st Resampler state
+ * @param in_rate Input sampling rate (integer number of Hz).
+ * @param out_rate Output sampling rate (integer number of Hz).
+ */
+int speex_resampler_set_rate(SpeexResamplerState *st,
+ spx_uint32_t in_rate,
+ spx_uint32_t out_rate);
+
+/** Get the current input/output sampling rates (integer value).
+ * @param st Resampler state
+ * @param in_rate Input sampling rate (integer number of Hz) copied.
+ * @param out_rate Output sampling rate (integer number of Hz) copied.
+ */
+void speex_resampler_get_rate(SpeexResamplerState *st,
+ spx_uint32_t *in_rate,
+ spx_uint32_t *out_rate);
+
+/** Set (change) the input/output sampling rates and resampling ratio
+ * (fractional values in Hz supported).
+ * @param st Resampler state
+ * @param ratio_num Numerator of the sampling rate ratio
+ * @param ratio_den Denominator of the sampling rate ratio
+ * @param in_rate Input sampling rate rounded to the nearest integer (in Hz).
+ * @param out_rate Output sampling rate rounded to the nearest integer (in Hz).
+ */
+int speex_resampler_set_rate_frac(SpeexResamplerState *st,
+ spx_uint32_t ratio_num,
+ spx_uint32_t ratio_den,
+ spx_uint32_t in_rate,
+ spx_uint32_t out_rate);
+
+/** Get the current resampling ratio. This will be reduced to the least
+ * common denominator.
+ * @param st Resampler state
+ * @param ratio_num Numerator of the sampling rate ratio copied
+ * @param ratio_den Denominator of the sampling rate ratio copied
+ */
+void speex_resampler_get_ratio(SpeexResamplerState *st,
+ spx_uint32_t *ratio_num,
+ spx_uint32_t *ratio_den);
+
+/** Set (change) the conversion quality.
+ * @param st Resampler state
+ * @param quality Resampling quality between 0 and 10, where 0 has poor
+ * quality and 10 has very high quality.
+ */
+int speex_resampler_set_quality(SpeexResamplerState *st,
+ int quality);
+
+/** Get the conversion quality.
+ * @param st Resampler state
+ * @param quality Resampling quality between 0 and 10, where 0 has poor
+ * quality and 10 has very high quality.
+ */
+void speex_resampler_get_quality(SpeexResamplerState *st,
+ int *quality);
+
+/** Set (change) the input stride.
+ * @param st Resampler state
+ * @param stride Input stride
+ */
+void speex_resampler_set_input_stride(SpeexResamplerState *st,
+ spx_uint32_t stride);
+
+/** Get the input stride.
+ * @param st Resampler state
+ * @param stride Input stride copied
+ */
+void speex_resampler_get_input_stride(SpeexResamplerState *st,
+ spx_uint32_t *stride);
+
+/** Set (change) the output stride.
+ * @param st Resampler state
+ * @param stride Output stride
+ */
+void speex_resampler_set_output_stride(SpeexResamplerState *st,
+ spx_uint32_t stride);
+
+/** Get the output stride.
+ * @param st Resampler state copied
+ * @param stride Output stride
+ */
+void speex_resampler_get_output_stride(SpeexResamplerState *st,
+ spx_uint32_t *stride);
+
+/** Get the latency in input samples introduced by the resampler.
+ * @param st Resampler state
+ */
+int speex_resampler_get_input_latency(SpeexResamplerState *st);
+
+/** Get the latency in output samples introduced by the resampler.
+ * @param st Resampler state
+ */
+int speex_resampler_get_output_latency(SpeexResamplerState *st);
+
+/** Make sure that the first samples to go out of the resamplers don't have
+ * leading zeros. This is only useful before starting to use a newly created
+ * resampler. It is recommended to use that when resampling an audio file, as
+ * it will generate a file with the same length. For real-time processing,
+ * it is probably easier not to use this call (so that the output duration
+ * is the same for the first frame).
+ * @param st Resampler state
+ */
+int speex_resampler_skip_zeros(SpeexResamplerState *st);
+
+/** Reset a resampler so a new (unrelated) stream can be processed.
+ * @param st Resampler state
+ */
+int speex_resampler_reset_mem(SpeexResamplerState *st);
+
+/** Returns the English meaning for an error code
+ * @param err Error code
+ * @return English string
+ */
+const char *speex_resampler_strerror(int err);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/codecs/speex/stack_alloc.h b/codecs/speex/stack_alloc.h
new file mode 100644
index 000000000..5264e666b
--- /dev/null
+++ b/codecs/speex/stack_alloc.h
@@ -0,0 +1,115 @@
+/* Copyright (C) 2002 Jean-Marc Valin */
+/**
+ @file stack_alloc.h
+ @brief Temporary memory allocation on stack
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Xiph.org Foundation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef STACK_ALLOC_H
+#define STACK_ALLOC_H
+
+#ifdef USE_ALLOCA
+# ifdef WIN32
+# include <malloc.h>
+# else
+# ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# include <stdlib.h>
+# endif
+# endif
+#endif
+
+/**
+ * @def ALIGN(stack, size)
+ *
+ * Aligns the stack to a 'size' boundary
+ *
+ * @param stack Stack
+ * @param size New size boundary
+ */
+
+/**
+ * @def PUSH(stack, size, type)
+ *
+ * Allocates 'size' elements of type 'type' on the stack
+ *
+ * @param stack Stack
+ * @param size Number of elements
+ * @param type Type of element
+ */
+
+/**
+ * @def VARDECL(var)
+ *
+ * Declare variable on stack
+ *
+ * @param var Variable to declare
+ */
+
+/**
+ * @def ALLOC(var, size, type)
+ *
+ * Allocate 'size' elements of 'type' on stack
+ *
+ * @param var Name of variable to allocate
+ * @param size Number of elements
+ * @param type Type of element
+ */
+
+#ifdef ENABLE_VALGRIND
+
+#include <valgrind/memcheck.h>
+
+#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
+
+#define PUSH(stack, size, type) (VALGRIND_MAKE_NOACCESS(stack, 1000),ALIGN((stack),sizeof(type)),VALGRIND_MAKE_WRITABLE(stack, ((size)*sizeof(type))),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type))))
+
+#else
+
+#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
+
+#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type))))
+
+#endif
+
+#if defined(VAR_ARRAYS)
+#define VARDECL(var)
+#define ALLOC(var, size, type) type var[size]
+#elif defined(USE_ALLOCA)
+#define VARDECL(var) var
+#define ALLOC(var, size, type) var = alloca(sizeof(type)*(size))
+#else
+#define VARDECL(var) var
+#define ALLOC(var, size, type) var = PUSH(stack, size, type)
+#endif
+
+
+#endif
diff --git a/configs/codecs.conf.sample b/configs/codecs.conf.sample
index c8caeab60..4404d4a0c 100644
--- a/configs/codecs.conf.sample
+++ b/configs/codecs.conf.sample
@@ -63,3 +63,74 @@ pp_dereverb_level => 0.3
; this determines whether to perform generic PLC
; there is a minor performance penalty for this
genericplc => true
+
+; Generate custom formats for formats requiring attributes.
+; After defining the custom format, the name used in defining
+; the format can be used throughout Asterisk in the format 'allow'
+; and 'disallow' options.
+;
+; Example: silk8 is a predefined custom format in this config file.
+; Once this config file is loaded, silk8 can be used anywhere a
+; peer's codec capabilities are defined.
+;
+; In sip.conf 'silk8' can be defined as a capability for a peer.
+; [peer1]
+; type=peer
+; host=dynamic
+; disallow=all
+; allow=silk8 ;custom codec defined in codecs.conf
+;
+; LIMITATIONS
+; Custom formats can only be defined at startup. Any changes to this
+; file made after startup will not take into effect until after Asterisk
+; is restarted.
+;
+
+; Default Custom SILK format definitions, only one custom SILK format per
+; sample rate is allowed.
+[silk8]
+type=silk
+samprate=8000
+fec=true ; turn on or off encoding with forward error correction.
+ ; On recommended, off by default.
+packetloss_percentage=10 ; Estimated packet loss percentage in uplink direction. This
+ ; affects how much redundancy is built in when using fec.
+ ; The higher the percentage, the larger amount of bandwidth is
+ ; used. Default is 0%, 10% is recommended when fec is in use.
+
+maxbitrate=10000 ; Use the table below to make sure a useful bitrate is choosen
+ ; for maxbitrate. If not set or value is not within the bounds
+ ; of the encoder, a default value is chosen.
+ ;
+ ; sample rate | bitrate range
+ ; 8khz | 5000 - 20000 bps
+ ; 12khz | 7000 - 25000 bps
+ ; 16khz | 8000 - 30000 bps
+ ; 24khz | 20000- 40000 bps
+ ;
+;dtx=true ; Encode using discontinuous transmission mode or not. Turning this
+ ; on will save bandwidth during periods of silence at the cost of
+ ; increased computational complexity. Off by default.
+
+[silk12]
+type=silk
+samprate=12000
+maxbitrate=12000
+fec=true
+packetloss_percentage=10;
+
+[silk16]
+type=silk
+samprate=16000
+maxbitrate=20000
+fec=true
+packetloss_percentage=10;
+
+
+[silk24]
+type=silk
+samprate=24000
+maxbitrate=30000
+fec=true
+packetloss_percentage=10;
+
diff --git a/formats/format_attr_silk.c b/formats/format_attr_silk.c
new file mode 100644
index 000000000..49122fe80
--- /dev/null
+++ b/formats/format_attr_silk.c
@@ -0,0 +1,215 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2011, Digium, Inc.
+ *
+ * David Vossel <dvossel@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief SILK format attribute interface
+ *
+ * \author David Vossel <dvossel@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/module.h"
+#include "asterisk/format.h"
+
+/*!
+ * \brief SILK attribute structure.
+ *
+ * \note The only attribute that affects compatibility here is the sample rate.
+ */
+struct silk_attr {
+ unsigned int samplerate;
+ unsigned int maxbitrate;
+ unsigned int dtx;
+ unsigned int fec;
+ unsigned int packetloss_percentage;
+};
+
+static enum ast_format_cmp_res silk_cmp(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2)
+{
+ struct silk_attr *attr1 = (struct silk_attr *) fattr1;
+ struct silk_attr *attr2 = (struct silk_attr *) fattr2;
+
+ if (attr1->samplerate == attr2->samplerate) {
+ return AST_FORMAT_CMP_EQUAL;
+ }
+ return AST_FORMAT_CMP_NOT_EQUAL;
+}
+
+static int silk_get_val(const struct ast_format_attr *fattr, int key, void *result)
+{
+ const struct silk_attr *attr = (struct silk_attr *) fattr;
+ int *val = result;
+
+ switch (key) {
+ case SILK_ATTR_KEY_SAMP_RATE:
+ *val = attr->samplerate;
+ break;
+ case SILK_ATTR_KEY_MAX_BITRATE:
+ *val = attr->maxbitrate;
+ break;
+ case SILK_ATTR_KEY_DTX:
+ *val = attr->dtx;
+ break;
+ case SILK_ATTR_KEY_FEC:
+ *val = attr->fec;
+ break;
+ case SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE:
+ *val = attr->packetloss_percentage;
+ break;
+ default:
+ return -1;
+ ast_log(LOG_WARNING, "unknown attribute type %d\n", key);
+ }
+ return 0;
+}
+
+static int silk_isset(const struct ast_format_attr *fattr, va_list ap)
+{
+ enum silk_attr_keys key;
+ const struct silk_attr *attr = (struct silk_attr *) fattr;
+
+ for (key = va_arg(ap, int);
+ key != AST_FORMAT_ATTR_END;
+ key = va_arg(ap, int))
+ {
+ switch (key) {
+ case SILK_ATTR_KEY_SAMP_RATE:
+ if (attr->samplerate != (va_arg(ap, int))) {
+ return -1;
+ }
+ break;
+ case SILK_ATTR_KEY_MAX_BITRATE:
+ if (attr->maxbitrate != (va_arg(ap, int))) {
+ return -1;
+ }
+ break;
+ case SILK_ATTR_KEY_DTX:
+ if (attr->dtx != (va_arg(ap, int))) {
+ return -1;
+ }
+ break;
+ case SILK_ATTR_KEY_FEC:
+ if (attr->fec != (va_arg(ap, int))) {
+ return -1;
+ }
+ break;
+ case SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE:
+ if (attr->packetloss_percentage != (va_arg(ap, int))) {
+ return -1;
+ }
+ break;
+ default:
+ return -1;
+ ast_log(LOG_WARNING, "unknown attribute type %d\n", key);
+ }
+ }
+ return 0;
+}
+static int silk_getjoint(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result)
+{
+ struct silk_attr *attr1 = (struct silk_attr *) fattr1;
+ struct silk_attr *attr2 = (struct silk_attr *) fattr2;
+ struct silk_attr *attr_res = (struct silk_attr *) result;
+ int joint = -1;
+
+ attr_res->samplerate = attr1->samplerate & attr2->samplerate;
+ /* sample rate is the only attribute that has any bearing on if joint capabilities exist or not */
+ if (attr_res->samplerate) {
+ joint = 0;
+ }
+ /* Take the lowest max bitrate */
+ attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate);
+
+ /* Only do dtx if both sides want it. DTX is a trade off between
+ * computational complexity and bandwidth. */
+ attr_res->dtx = attr1->dtx && attr2->dtx ? 1 : 0;
+
+ /* Only do FEC if both sides want it. If a peer specifically requests not
+ * to receive with FEC, it may be a waste of bandwidth. */
+ attr_res->fec = attr1->fec && attr2->fec ? 1 : 0;
+
+ /* Use the maximum packetloss percentage between the two attributes. This affects how
+ * much redundancy is used in the FEC. */
+ attr_res->packetloss_percentage = MAX(attr1->packetloss_percentage, attr2->packetloss_percentage);
+ return joint;
+}
+
+static void silk_set(struct ast_format_attr *fattr, va_list ap)
+{
+ enum silk_attr_keys key;
+ struct silk_attr *attr = (struct silk_attr *) fattr;
+
+ for (key = va_arg(ap, int);
+ key != AST_FORMAT_ATTR_END;
+ key = va_arg(ap, int))
+ {
+ switch (key) {
+ case SILK_ATTR_KEY_SAMP_RATE:
+ attr->samplerate = (va_arg(ap, int));
+ break;
+ case SILK_ATTR_KEY_MAX_BITRATE:
+ attr->maxbitrate = (va_arg(ap, int));
+ break;
+ case SILK_ATTR_KEY_DTX:
+ attr->dtx = (va_arg(ap, int));
+ break;
+ case SILK_ATTR_KEY_FEC:
+ attr->fec = (va_arg(ap, int));
+ break;
+ case SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE:
+ attr->packetloss_percentage = (va_arg(ap, int));
+ break;
+ default:
+ ast_log(LOG_WARNING, "unknown attribute type %d\n", key);
+ }
+ }
+}
+
+static struct ast_format_attr_interface silk_interface = {
+ .id = AST_FORMAT_SILK,
+ .format_attr_cmp = silk_cmp,
+ .format_attr_get_joint = silk_getjoint,
+ .format_attr_set = silk_set,
+ .format_attr_isset = silk_isset,
+ .format_attr_get_val = silk_get_val,
+};
+
+static int load_module(void)
+{
+ if (ast_format_attr_reg_interface(&silk_interface)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ ast_format_attr_unreg_interface(&silk_interface);
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SILK Format Attribute Module",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_CHANNEL_DEPEND,
+);
diff --git a/funcs/func_pitchshift.c b/funcs/func_pitchshift.c
index 36fa2f6c4..b14894712 100644
--- a/funcs/func_pitchshift.c
+++ b/funcs/func_pitchshift.c
@@ -170,8 +170,7 @@ static int pitchshift_cb(struct ast_audiohook *audiohook, struct ast_channel *ch
}
if ((audiohook->status == AST_AUDIOHOOK_STATUS_DONE) ||
(f->frametype != AST_FRAME_VOICE) ||
- ((f->subclass.format.id != AST_FORMAT_SLINEAR) &&
- (f->subclass.format.id != AST_FORMAT_SLINEAR16))) {
+ !(ast_format_is_slinear(&f->subclass.format))) {
return -1;
}
@@ -209,7 +208,7 @@ static int pitchshift_helper(struct ast_channel *chan, const char *cmd, char *da
return 0;
}
- ast_audiohook_init(&shift->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "pitch_shift");
+ ast_audiohook_init(&shift->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "pitch_shift", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
shift->audiohook.manipulate_callback = pitchshift_cb;
datastore->data = shift;
new = 1;
diff --git a/funcs/func_speex.c b/funcs/func_speex.c
index 4b8b3a3d6..51cea99e1 100644
--- a/funcs/func_speex.c
+++ b/funcs/func_speex.c
@@ -105,6 +105,7 @@ struct speex_direction_info {
struct speex_info {
struct ast_audiohook audiohook;
+ int lastrate;
struct speex_direction_info *tx, *rx;
};
@@ -163,12 +164,13 @@ static int speex_callback(struct ast_audiohook *audiohook, struct ast_channel *c
return -1;
}
- if (sdi->samples != frame->samples) {
+ if ((sdi->samples != frame->samples) || (ast_format_rate(&frame->subclass.format) != si->lastrate)) {
+ si->lastrate = ast_format_rate(&frame->subclass.format);
if (sdi->state) {
speex_preprocess_state_destroy(sdi->state);
}
- if (!(sdi->state = speex_preprocess_state_init((sdi->samples = frame->samples), 8000))) {
+ if (!(sdi->state = speex_preprocess_state_init((sdi->samples = frame->samples), si->lastrate))) {
return -1;
}
@@ -212,9 +214,9 @@ static int speex_write(struct ast_channel *chan, const char *cmd, char *data, co
return 0;
}
- ast_audiohook_init(&si->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "speex");
+ ast_audiohook_init(&si->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "speex", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
si->audiohook.manipulate_callback = speex_callback;
-
+ si->lastrate = 8000;
is_new = 1;
} else {
ast_channel_unlock(chan);
diff --git a/funcs/func_volume.c b/funcs/func_volume.c
index 88153f603..e94a4edc7 100644
--- a/funcs/func_volume.c
+++ b/funcs/func_volume.c
@@ -132,7 +132,7 @@ static int volume_write(struct ast_channel *chan, const char *cmd, char *data, c
ast_datastore_free(datastore);
return 0;
}
- ast_audiohook_init(&vi->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume");
+ ast_audiohook_init(&vi->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
vi->audiohook.manipulate_callback = volume_callback;
ast_set_flag(&vi->audiohook, AST_AUDIOHOOK_WANTS_DTMF);
is_new = 1;
diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h
index 560c8c169..a0b171254 100644
--- a/include/asterisk/_private.h
+++ b/include/asterisk/_private.h
@@ -90,4 +90,16 @@ int ast_xmldoc_load_documentation(void);
*/
int ast_plc_reload(void);
+/*!
+ * \brief Init the ast_format attribute interface register container.
+ */
+int ast_format_attr_init(void);
+
+/*!
+ * \brief Init the Asterisk global format list after all format attribute modules have been loaded
+ */
+int ast_format_list_init(void);
+
+/*! \brief initializes the rtp engine arrays */
+int ast_rtp_engine_init(void);
#endif /* _ASTERISK__PRIVATE_H */
diff --git a/include/asterisk/audiohook.h b/include/asterisk/audiohook.h
index 75e2c8763..798a6d6e0 100644
--- a/include/asterisk/audiohook.h
+++ b/include/asterisk/audiohook.h
@@ -65,7 +65,12 @@ enum ast_audiohook_flags {
AST_AUDIOHOOK_MUTE_WRITE = (1 << 5), /*!< audiohook should be mute frames written */
};
-#define AST_AUDIOHOOK_SYNC_TOLERANCE 100 /*< Tolerance in milliseconds for audiohooks synchronization */
+enum ast_audiohook_init_flags {
+ /*! Audiohook manipulate callback is capable of handling slinear at any sample rate.
+ * Without enabling this flag on initialization the manipulation callback is guaranteed
+ * 8khz audio only. */
+ AST_AUDIOHOOK_MANIPULATE_ALL_RATES = (1 << 0),
+};
struct ast_audiohook;
@@ -97,6 +102,7 @@ struct ast_audiohook {
ast_cond_t trigger; /*!< Trigger condition (if enabled) */
enum ast_audiohook_type type; /*!< Type of audiohook */
enum ast_audiohook_status status; /*!< Status of the audiohook */
+ enum ast_audiohook_init_flags init_flags; /*!< Init flags */
const char *source; /*!< Who this audiohook ultimately belongs to */
unsigned int flags; /*!< Flags on the audiohook */
struct ast_slinfactory read_factory; /*!< Factory where frames read from the channel, or read from the whisper source will go through */
@@ -107,6 +113,7 @@ struct ast_audiohook {
struct ast_trans_pvt *trans_pvt; /*!< Translation path for reading frames */
ast_audiohook_manipulate_callback manipulate_callback; /*!< Manipulation callback */
struct ast_audiohook_options options; /*!< Applicable options */
+ unsigned int hook_internal_samp_rate; /*!< internal read/write sample rate on the audiohook.*/
AST_LIST_ENTRY(ast_audiohook) list; /*!< Linked list information */
};
@@ -116,9 +123,10 @@ struct ast_audiohook_list;
* \param audiohook Audiohook structure
* \param type Type of audiohook to initialize this as
* \param source Who is initializing this audiohook
+ * \param init flags
* \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 flags);
/*! \brief Destroys an audiohook structure
* \param audiohook Audiohook structure
diff --git a/include/asterisk/format.h b/include/asterisk/format.h
index 09212abc8..67e4178a2 100644
--- a/include/asterisk/format.h
+++ b/include/asterisk/format.h
@@ -26,8 +26,9 @@
#ifndef _AST_FORMAT_H_
#define _AST_FORMAT_H_
+#include "asterisk/astobj2.h"
+#include "asterisk/silk.h"
#define AST_FORMAT_ATTR_SIZE 128
-
#define AST_FORMAT_INC 100000
/*! This is the value that ends a var list of format attribute
@@ -55,32 +56,49 @@ enum ast_format_id {
AST_FORMAT_G726_AAL2 = 5 + AST_FORMAT_TYPE_AUDIO,
/*! ADPCM (IMA) */
AST_FORMAT_ADPCM = 6 + AST_FORMAT_TYPE_AUDIO,
- /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
- AST_FORMAT_SLINEAR = 7 + AST_FORMAT_TYPE_AUDIO,
/*! LPC10, 180 samples/frame */
- AST_FORMAT_LPC10 = 8 + AST_FORMAT_TYPE_AUDIO,
+ AST_FORMAT_LPC10 = 7 + AST_FORMAT_TYPE_AUDIO,
/*! G.729A audio */
- AST_FORMAT_G729A = 9 + AST_FORMAT_TYPE_AUDIO,
+ AST_FORMAT_G729A = 8 + AST_FORMAT_TYPE_AUDIO,
/*! SpeeX Free Compression */
- AST_FORMAT_SPEEX = 10 + AST_FORMAT_TYPE_AUDIO,
+ AST_FORMAT_SPEEX = 9 + AST_FORMAT_TYPE_AUDIO,
/*! iLBC Free Compression */
- AST_FORMAT_ILBC = 11 + AST_FORMAT_TYPE_AUDIO,
+ AST_FORMAT_ILBC = 10 + AST_FORMAT_TYPE_AUDIO,
/*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
- AST_FORMAT_G726 = 12 + AST_FORMAT_TYPE_AUDIO,
+ AST_FORMAT_G726 = 11 + AST_FORMAT_TYPE_AUDIO,
/*! G.722 */
- AST_FORMAT_G722 = 13 + AST_FORMAT_TYPE_AUDIO,
+ AST_FORMAT_G722 = 12 + AST_FORMAT_TYPE_AUDIO,
/*! G.722.1 (also known as Siren7, 32kbps assumed) */
- AST_FORMAT_SIREN7 = 14 + AST_FORMAT_TYPE_AUDIO,
+ AST_FORMAT_SIREN7 = 13 + AST_FORMAT_TYPE_AUDIO,
/*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
- AST_FORMAT_SIREN14 = 15 + AST_FORMAT_TYPE_AUDIO,
- /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
- AST_FORMAT_SLINEAR16 = 16 + AST_FORMAT_TYPE_AUDIO,
+ AST_FORMAT_SIREN14 = 14 + AST_FORMAT_TYPE_AUDIO,
/*! G.719 (64 kbps assumed) */
- AST_FORMAT_G719 = 17 + AST_FORMAT_TYPE_AUDIO,
+ AST_FORMAT_G719 = 15 + AST_FORMAT_TYPE_AUDIO,
/*! SpeeX Wideband (16kHz) Free Compression */
- AST_FORMAT_SPEEX16 = 18 + AST_FORMAT_TYPE_AUDIO,
+ AST_FORMAT_SPEEX16 = 16 + AST_FORMAT_TYPE_AUDIO,
/*! Raw mu-law data (G.711) */
- AST_FORMAT_TESTLAW = 19 + AST_FORMAT_TYPE_AUDIO,
+ AST_FORMAT_TESTLAW = 17 + AST_FORMAT_TYPE_AUDIO,
+ /*! SILK format */
+ AST_FORMAT_SILK = 18 + AST_FORMAT_TYPE_AUDIO,
+ /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
+ AST_FORMAT_SLINEAR = 19 + AST_FORMAT_TYPE_AUDIO,
+ /*! Raw 16-bit Signed Linear (12000 Hz) PCM */
+ AST_FORMAT_SLINEAR12 = 20 + AST_FORMAT_TYPE_AUDIO,
+ /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
+ AST_FORMAT_SLINEAR16 = 21 + AST_FORMAT_TYPE_AUDIO,
+ /*! Raw 16-bit Signed Linear (24000 Hz) PCM */
+ AST_FORMAT_SLINEAR24 = 22 + AST_FORMAT_TYPE_AUDIO,
+ /*! Raw 16-bit Signed Linear (32000 Hz) PCM */
+ AST_FORMAT_SLINEAR32 = 23 + AST_FORMAT_TYPE_AUDIO,
+ /*! Raw 16-bit Signed Linear (44100 Hz) PCM just because we can. */
+ AST_FORMAT_SLINEAR44 = 24 + AST_FORMAT_TYPE_AUDIO,
+ /*! Raw 16-bit Signed Linear (48000 Hz) PCM */
+ AST_FORMAT_SLINEAR48 = 25 + AST_FORMAT_TYPE_AUDIO,
+ /*! Raw 16-bit Signed Linear (96000 Hz) PCM */
+ AST_FORMAT_SLINEAR96 = 26 + AST_FORMAT_TYPE_AUDIO,
+ /*! Raw 16-bit Signed Linear (192000 Hz) PCM. maybe we're taking this too far. */
+ AST_FORMAT_SLINEAR192 = 27 + AST_FORMAT_TYPE_AUDIO,
+ AST_FORMAT_SPEEX32 = 28 + AST_FORMAT_TYPE_AUDIO,
/*! H.261 Video */
AST_FORMAT_H261 = 1 + AST_FORMAT_TYPE_VIDEO,
@@ -107,6 +125,7 @@ enum ast_format_id {
/*! Determine what type of media a ast_format_id is. */
#define AST_FORMAT_GET_TYPE(id) (((int) (id / AST_FORMAT_INC)) * AST_FORMAT_INC)
+
/*! \brief This structure contains the buffer used for format attributes */
struct ast_format_attr {
/*! The buffer formats can use to represent attributes */
@@ -133,6 +152,22 @@ enum ast_format_cmp_res {
AST_FORMAT_CMP_SUBSET,
};
+/*! \brief Definition of supported media formats (codecs) */
+struct ast_format_list {
+ struct ast_format format; /*!< The unique format. */
+ char name[64]; /*!< short name */
+ unsigned int samplespersecond; /*!< Number of samples per second (8000/16000) */
+ char desc[128]; /*!< Description */
+ int fr_len; /*!< Single frame length in bytes */
+ int min_ms; /*!< Min value */
+ int max_ms; /*!< Max value */
+ int inc_ms; /*!< Increment */
+ int def_ms; /*!< Default value */
+ unsigned int flags; /*!< Smoother flags */
+ int cur_ms; /*!< Current value */
+ int custom_entry;
+};
+
/*! \brief A format must register an attribute interface if it requires the use of the format attributes void pointer */
struct ast_format_attr_interface {
/*! format type */
@@ -154,6 +189,34 @@ struct ast_format_attr_interface {
/*! \brief Set format capabilities from a list of key value pairs ending with AST_FORMAT_ATTR_END.
* \note This function does not need to call va_end of the va_list. */
void (* const format_attr_set)(struct ast_format_attr *format_attr, va_list ap);
+
+ /*!
+ * \brief Find out if format capabilities in va_list are in format.
+ * \note This function does not need to call va_end of the va_list.
+ *
+ * \note This function is optional. In many cases the format_attr_cmp
+ * function can be used to derive these results. If it is possible
+ * that some format attributes have no bearing on the equality of two formats, this
+ * function must exist.
+ *
+ * \retval 0 if all attributes exist
+ * \retval -1 if any of the attributes not present
+ */
+ int (* const format_attr_isset)(const struct ast_format_attr *format_attr, va_list ap);
+
+ /*
+ * \brief Return a value for a specific format key. Return that value in the void pointer.
+ *
+ * \note It is not expected that all key value pairs can be returned, but those that can should
+ * be documented as such.
+ *
+ * \note This function is optional if key value pairs are not allowed to be accessed. This
+ * will result in -1 always being returned.
+ *
+ * \retval 0 Success, value was found and copied into void pointer.
+ * \retval -1 failure, Value was either not found, or not allowed to be accessed.
+ */
+ int (* const format_attr_get_val)(const struct ast_format_attr *format_attr, int key, void *val);
};
/*!
@@ -218,7 +281,18 @@ void ast_format_clear(struct ast_format *format);
* \return 0, The format key value pairs are within the capabilities defined in this structure.
* \return -1, The format key value pairs are _NOT_ within the capabilities of this structure.
*/
-int ast_format_isset(struct ast_format *format, ... );
+int ast_format_isset(const struct ast_format *format, ... );
+
+/*!
+ * \brief Get a value from a format containing attributes.
+ * \note The key represents the format attribute to be retrieved, and the void pointer
+ * is to the structure that value will be stored in. It must be known what structure a
+ * key represents.
+ *
+ * \retval 0, success
+ * \retval -1, failure
+ */
+int ast_format_get_value(const struct ast_format *format, int key, void *value);
/*!
* \brief Compare ast_formats structures
@@ -287,6 +361,52 @@ struct ast_format *ast_format_from_old_bitfield(struct ast_format *dst, uint64_t
enum ast_format_id ast_format_id_from_old_bitfield(uint64_t src);
/*!
+ * \brief Retrieve the global format list in a read only array.
+ * \note ast_format_list_destroy must be called on every format
+ * list retrieved from this function.
+ */
+const struct ast_format_list *ast_format_list_get(size_t *size);
+
+/*!
+ * \brief Destroy an ast_format_list gotten from ast_format_list_get()
+ */
+const struct ast_format_list *ast_format_list_destroy(const struct ast_format_list *list);
+
+/*! \brief Get the name of a format
+ * \param format id of format
+ * \return A static string containing the name of the format or "unknown" if unknown.
+ */
+const char* ast_getformatname(const struct ast_format *format);
+
+/*! \brief Returns a string containing all formats pertaining to an format id.
+ * \param buf a buffer for the output string
+ * \param size size of buf (bytes)
+ * \param format id.
+ * \return The return value is buf.
+ */
+char* ast_getformatname_multiple_byid(char *buf, size_t size, enum ast_format_id id);
+
+/*!
+ * \brief Gets a format from a name.
+ * \param name string of format
+ * \param format structure to return the format in.
+ * \return This returns the format pointer given to it on success and NULL on failure
+ */
+struct ast_format *ast_getformatbyname(const char *name, struct ast_format *format);
+
+/*!
+ * \brief Get a name from a format
+ * \param format to get name of
+ * \return This returns a static string identifying the format on success, 0 on error.
+ */
+const char *ast_codec2str(struct ast_format *format);
+
+/*!
+ * \brief Get the sample rate for a given format.
+ */
+int ast_format_rate(const struct ast_format *format);
+
+/*!
* \brief register ast_format_attr_interface with core.
*
* \retval 0 success
@@ -303,8 +423,12 @@ int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interf
int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface);
/*!
- * \brief Init the ast_format attribute interface register container.
+ * \brief Determine if a format is 16bit signed linear of any sample rate.
*/
-int ast_format_attr_init(void);
+int ast_format_is_slinear(const struct ast_format *format);
+/*!
+ * \brief Get the best slinear format id for a given sample rate
+ */
+enum ast_format_id ast_format_slin_by_rate(unsigned int rate);
#endif /* _AST_FORMAT_H */
diff --git a/include/asterisk/format_cap.h b/include/asterisk/format_cap.h
index cdb5421f9..234767685 100644
--- a/include/asterisk/format_cap.h
+++ b/include/asterisk/format_cap.h
@@ -70,7 +70,7 @@ void *ast_format_cap_destroy(struct ast_format_cap *cap);
* what is placed in the ast_format_cap structure. The actual
* input format ptr is not stored.
*/
-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);
/*!
* \brief Add all formats Asterisk knows about for a specific type to
@@ -155,6 +155,15 @@ void ast_format_cap_remove_all(struct ast_format_cap *cap);
void ast_format_cap_set(struct ast_format_cap *cap, struct ast_format *format);
/*!
+ * \brief Find if input ast_format is within the capabilities of the ast_format_cap object
+ * then return the compatible format from the capabilities structure in the result.
+ *
+ * \retval 1 format is compatible with formats held in ast_format_cap object.
+ * \retval 0 format is not compatible with any formats in ast_format_cap object.
+ */
+int ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format, struct ast_format *result);
+
+/*!
* \brief Find if ast_format is within the capabilities of the ast_format_cap object.
*
* retval 1 format is compatible with formats held in ast_format_cap object.
@@ -163,6 +172,14 @@ void ast_format_cap_set(struct ast_format_cap *cap, struct ast_format *format);
int ast_format_cap_iscompatible(const struct ast_format_cap *cap, const struct ast_format *format);
/*!
+ * \brief Finds the best quality audio format for a given format id and returns it in result.
+ *
+ * \retval 1 format found and set to result structure.
+ * \retval 0 no format found, result structure is cleared.
+ */
+int ast_format_cap_best_byid(const struct ast_format_cap *cap, enum ast_format_id, struct ast_format *result);
+
+/*!
* \brief is cap1 identical to cap2
*
* retval 1 true, identical
@@ -278,4 +295,14 @@ uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap);
*/
void ast_format_cap_from_old_bitfield(struct ast_format_cap *dst, uint64_t src);
+/*! \brief Get the names of a set of formats
+ * \param buf a buffer for the output string
+ * \param size size of buf (bytes)
+ * \param format the format (combined IDs of codecs)
+ * Prints a list of readable codec names corresponding to "format".
+ * ex: for format=AST_FORMAT_GSM|AST_FORMAT_SPEEX|AST_FORMAT_ILBC it will return "0x602 (GSM|SPEEX|ILBC)"
+ * \return The return value is buf.
+ */
+char* ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap);
+
#endif /* _AST_FORMATCAP_H */
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index 63cbb952f..e02df42ed 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -427,23 +427,6 @@ struct ast_option_header {
uint8_t data[0];
};
-
-/*! \brief Definition of supported media formats (codecs) */
-struct ast_format_list {
- enum ast_format_id id; /*!< The format unique id */
- char *name; /*!< short name */
- int samplespersecond; /*!< Number of samples per second (8000/16000) */
- char *desc; /*!< Description */
- int fr_len; /*!< Single frame length in bytes */
- int min_ms; /*!< Min value */
- int max_ms; /*!< Max value */
- int inc_ms; /*!< Increment */
- int def_ms; /*!< Default value */
- unsigned int flags; /*!< Smoother flags */
- int cur_ms; /*!< Current value */
-};
-
-
/*! \brief Requests a frame to be allocated
*
* \param source
@@ -505,37 +488,6 @@ void ast_swapcopy_samples(void *dst, const void *src, int samples);
*/
int ast_parse_allow_disallow(struct ast_codec_pref *pref, struct ast_format_cap *cap, const char *list, int allowing);
-/*! \brief Get the name of a format
- * \param format id of format
- * \return A static string containing the name of the format or "unknown" if unknown.
- */
-char* ast_getformatname(struct ast_format *format);
-
-/*! \brief Get the names of a set of formats
- * \param buf a buffer for the output string
- * \param size size of buf (bytes)
- * \param format the format (combined IDs of codecs)
- * Prints a list of readable codec names corresponding to "format".
- * ex: for format=AST_FORMAT_GSM|AST_FORMAT_SPEEX|AST_FORMAT_ILBC it will return "0x602 (GSM|SPEEX|ILBC)"
- * \return The return value is buf.
- */
-char* ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap);
-
-/*!
- * \brief Gets a format from a name.
- * \param name string of format
- * \param format structure to return the format in.
- * \return This returns the format pointer given to it on success and NULL on failure
- */
-struct ast_format *ast_getformatbyname(const char *name, struct ast_format *format);
-
-/*! \brief Get a name from a format
- * Gets a name from a format
- * \param format to get name of
- * \return This returns a static string identifying the format on success, 0 on error.
- */
-char *ast_codec2str(struct ast_format *format);
-
/*! \name AST_Smoother
*/
/*@{ */
@@ -582,8 +534,6 @@ struct ast_frame *ast_smoother_read(struct ast_smoother *s);
#endif
/*@} Doxygen marker */
-const struct ast_format_list *ast_get_format_list_index(int index);
-const struct ast_format_list *ast_get_format_list(size_t *size);
void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix);
/*! \brief Returns the number of samples contained in the frame */
@@ -622,26 +572,6 @@ int ast_frame_adjust_volume(struct ast_frame *f, int adjustment);
int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2);
/*!
- * \brief Get the sample rate for a given format.
- */
-static force_inline int ast_format_rate(struct ast_format *format)
-{
- switch (format->id) {
- case AST_FORMAT_G722:
- case AST_FORMAT_SLINEAR16:
- case AST_FORMAT_SIREN7:
- case AST_FORMAT_SPEEX16:
- return 16000;
- case AST_FORMAT_SIREN14:
- return 32000;
- case AST_FORMAT_G719:
- return 48000;
- default:
- return 8000;
- }
-}
-
-/*!
* \brief Clear all audio samples from an ast_frame. The frame must be AST_FRAME_VOICE and AST_FORMAT_SLINEAR
*/
int ast_frame_clear(struct ast_frame *frame);
diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h
index f13538321..4c5753e84 100644
--- a/include/asterisk/rtp_engine.h
+++ b/include/asterisk/rtp_engine.h
@@ -1048,6 +1048,19 @@ void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp
struct ast_rtp_payload_type ast_rtp_codecs_payload_lookup(struct ast_rtp_codecs *codecs, int payload);
/*!
+ * \brief Retrieve the actual ast_format stored on the codecs structure for a specific payload
+ *
+ * \param codecs Codecs structure to look in
+ * \param payload Numerical payload to look up
+ *
+ * \retval pointer to format structure on success
+ * \retval NULL on failure
+ *
+ * \since 1.10
+ */
+struct ast_format *ast_rtp_codecs_get_payload_format(struct ast_rtp_codecs *codecs, int payload);
+
+/*!
* \brief Get the sample rate associated with known RTP payload types
*
* \param asterisk_format True if the value in format is to be used.
@@ -1798,6 +1811,15 @@ struct ast_channel *ast_rtp_instance_get_chan(struct ast_rtp_instance *instance)
int ast_rtp_instance_add_srtp_policy(struct ast_rtp_instance *instance, struct ast_srtp_policy *policy);
struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance);
+/*! \brief Custom formats declared in codecs.conf at startup must be communicated to the rtp_engine
+ * so their mime type can payload number can be initialized. */
+int ast_rtp_engine_load_format(const struct ast_format *format);
+
+/*! \brief Formats requiring the use of a format attribute interface must have that
+ * interface registered in order for the rtp engine to handle it correctly. If an
+ * attribute interface is unloaded, this function must be called to notify the rtp_engine. */
+int ast_rtp_engine_unload_format(const struct ast_format *format);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
diff --git a/include/asterisk/silk.h b/include/asterisk/silk.h
new file mode 100644
index 000000000..5da827e7e
--- /dev/null
+++ b/include/asterisk/silk.h
@@ -0,0 +1,44 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2011, Digium, Inc.
+ *
+ * David Vossel <dvossel@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief SILK Format Attributes
+ *
+ * \author David Vossel <dvossel@digium.com>
+ */
+#ifndef _AST_FORMAT_SILK_H_
+#define _AST_FORMAT_SILK_H_
+
+/*! SILK format attribute key value pairs, all are accessible through ast_format_get_value()*/
+enum silk_attr_keys {
+ SILK_ATTR_KEY_SAMP_RATE, /*!< value is silk_attr_vals enum */
+ SILK_ATTR_KEY_DTX, /*!< value is an int, 1 dtx is enabled, 0 dtx not enabled. */
+ SILK_ATTR_KEY_FEC, /*!< value is an int, 1 encode with FEC, 0 do not use FEC. */
+ SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE, /*!< value is an int (0-100), Represents estimated packetloss in uplink direction.*/
+ SILK_ATTR_KEY_MAX_BITRATE, /*!< value is an int */
+};
+
+enum silk_attr_vals {
+ SILK_ATTR_VAL_SAMP_8KHZ = (1 << 0),
+ SILK_ATTR_VAL_SAMP_12KHZ = (1 << 1),
+ SILK_ATTR_VAL_SAMP_16KHZ = (1 << 2),
+ SILK_ATTR_VAL_SAMP_24KHZ = (1 << 3),
+};
+
+#endif /* _AST_FORMAT_SILK_H */
diff --git a/include/asterisk/slinfactory.h b/include/asterisk/slinfactory.h
index 003c6ac28..324c0ae28 100644
--- a/include/asterisk/slinfactory.h
+++ b/include/asterisk/slinfactory.h
@@ -56,11 +56,11 @@ void ast_slinfactory_init(struct ast_slinfactory *sf);
* \brief Initialize a slinfactory
*
* \param sf The slinfactory to initialize
- * \param sample_rate The output sample rate desired
+ * \param slin_out the slinear output format desired.
*
* \return 0 on success, non-zero on failure
*/
-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);
/*!
* \brief Destroy the contents of a slinfactory
diff --git a/include/asterisk/time.h b/include/asterisk/time.h
index 2ffc691b8..c78ff2db0 100644
--- a/include/asterisk/time.h
+++ b/include/asterisk/time.h
@@ -171,7 +171,7 @@ struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec),
AST_INLINE_API(
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate),
{
- return ast_tv(_nsamp / _rate, ((_nsamp % _rate) * (4000000 / _rate)) / 4); /* this calculation is accurate up to 32000Hz. */
+ return ast_tv(_nsamp / _rate, (_nsamp % _rate) * (1000000 / (float) _rate));
}
)
diff --git a/include/asterisk/translate.h b/include/asterisk/translate.h
index 7e73cd1b1..8545f0ae5 100644
--- a/include/asterisk/translate.h
+++ b/include/asterisk/translate.h
@@ -133,7 +133,7 @@ enum ast_trans_cost_table {
* Generic plc is only available for dstfmt = SLINEAR
*/
struct ast_translator {
- const char name[80]; /*!< Name of translator */
+ char name[80]; /*!< Name of translator */
struct ast_format src_format; /*!< Source format */
struct ast_format dst_format; /*!< Destination format */
@@ -204,6 +204,12 @@ struct ast_translator {
struct ast_trans_pvt {
struct ast_translator *t;
struct ast_frame f; /*!< used in frameout */
+ /*! If a translation path using a format with attributes requires the output
+ * to be a specific set of attributes, this variable will be set describing those
+ * attributes to the translator. Otherwise, the translator must choose a set
+ * of format attributes for the destination that preserves the quality of the
+ * audio in the best way possible. */
+ struct ast_format explicit_dst;
int samples; /*!< samples available in outbuf */
/*! \brief actual space used in outbuf */
int datalen;
@@ -213,7 +219,7 @@ struct ast_trans_pvt {
unsigned char *uc; /*!< the useful portion of the buffer */
int16_t *i16;
uint8_t *ui8;
- } outbuf;
+ } outbuf;
plc_state_t *plc; /*!< optional plc pointer */
struct ast_trans_pvt *next; /*!< next in translator chain */
struct timeval nextin;
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;
}
diff --git a/res/res_mutestream.c b/res/res_mutestream.c
index 4faf46478..41b2fd831 100644
--- a/res/res_mutestream.c
+++ b/res/res_mutestream.c
@@ -173,7 +173,7 @@ static struct ast_datastore *initialize_mutehook(struct ast_channel *chan)
ast_datastore_free(datastore);
return NULL;
}
- ast_audiohook_init(&mute->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Mute");
+ ast_audiohook_init(&mute->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Mute", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
mute->audiohook.manipulate_callback = mute_callback;
datastore->data = mute;
return datastore;
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index 0082fda96..b2004efab 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -1250,6 +1250,8 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr
switch (subclass.id) {
case AST_FORMAT_SPEEX:
case AST_FORMAT_SPEEX16:
+ case AST_FORMAT_SPEEX32:
+ case AST_FORMAT_SILK:
case AST_FORMAT_G723_1:
case AST_FORMAT_SIREN7:
case AST_FORMAT_SIREN14:
@@ -2292,7 +2294,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
if (AST_FORMAT_GET_TYPE(rtp->f.subclass.format.id) == AST_FORMAT_TYPE_AUDIO) {
rtp->f.samples = ast_codec_get_samples(&rtp->f);
- if ((rtp->f.subclass.format.id == AST_FORMAT_SLINEAR) || (rtp->f.subclass.format.id == AST_FORMAT_SLINEAR16)) {
+ if (ast_format_is_slinear(&rtp->f.subclass.format)) {
ast_frame_byteswap_be(&rtp->f);
}
calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);