dect
/
asterisk
Archived
13
0
Fork 0

Media Project Phase2: SILK 8khz-24khz, SLINEAR 8khz-192khz, SPEEX 32khz, hd audio ConfBridge, and other stuff

-Functional changes
1. Dynamic global format list build by codecs defined in codecs.conf
2. SILK 8khz, 12khz, 16khz, and 24khz with custom attributes defined in codecs.conf
3. Negotiation of SILK attributes in chan_sip.
4. SPEEX 32khz with translation
5. SLINEAR 8khz, 12khz, 24khz, 32khz, 44.1khz, 48khz, 96khz, 192khz with translation
   using codec_resample.c
6. Various changes to RTP code required to properly handle the dynamic format list
   and formats with attributes.
7. ConfBridge now dynamically jumps to the best possible sample rate.  This allows
   for conferences to take advantage of HD audio (Which sounds awesome)
8. Audiohooks are no longer limited to 8khz audio, and most effects have been
   updated to take advantage of this such as Volume, DENOISE, PITCH_SHIFT.
9. codec_resample now uses its own code rather than depending on libresample.

-Organizational changes
Global format list is moved from frame.c to format.c
Various format specific functions moved from frame.c to format.c

Review: https://reviewboard.asterisk.org/r/1104/


git-svn-id: http://svn.digium.com/svn/asterisk/trunk@308582 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
dvossel 2011-02-22 23:04:49 +00:00
parent 70442b4e17
commit f27e928f05
50 changed files with 4447 additions and 847 deletions

View File

@ -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,

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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 */

View File

@ -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;

View File

@ -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))) {

View File

@ -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;

View File

@ -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))

View File

@ -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);

View File

@ -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 {

View File

@ -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)

View File

@ -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;
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,
};
struct slin8_to_slin16_pvt {
void *resampler;
float resample_factor;
};
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)))
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 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)))
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)
{
struct slin8_to_slin16_pvt *resamp_pvt = pvt->pvt;
if (resamp_pvt->resampler)
resample_close(resamp_pvt->resampler);
}
static int resample_frame(struct ast_trans_pvt *pvt,
void *resampler, float resample_factor, 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;
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);
if (out_buf_used < 0)
break;
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;
return 0;
}
static int slin16_to_slin8_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
static void resamp_destroy(struct ast_trans_pvt *pvt)
{
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);
SpeexResamplerState *resamp_pvt = pvt->pvt;
speex_resampler_destroy(resamp_pvt);
}
static int slin8_to_slin16_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
static int resamp_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;
SpeexResamplerState *resamp_pvt = pvt->pvt;
unsigned int out_samples = (OUTBUF_SIZE / sizeof(int16_t)) - pvt->samples;
unsigned int in_samples = f->samples;
return resample_frame(pvt, resampler, resample_factor, f);
speex_resampler_process_int(resamp_pvt,
0,
f->data.ptr,
&in_samples,
pvt->outbuf.i16 + pvt->samples,
&out_samples);
pvt->samples += out_samples;
pvt->datalen += out_samples * 2;
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;
}

View File

@ -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;
}

241
codecs/speex/arch.h Normal file
View File

@ -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

View File

@ -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

1124
codecs/speex/resample.c Normal file

File diff suppressed because it is too large Load Diff

128
codecs/speex/resample_sse.h Normal file
View File

@ -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

View File

@ -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

115
codecs/speex/stack_alloc.h Normal file
View File

@ -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

View File

@ -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;

215
formats/format_attr_silk.c Normal file
View File

@ -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,
);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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 */

View File

@ -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

View File

@ -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
@ -286,6 +360,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.
*
@ -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 */

View File

@ -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
@ -154,6 +154,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.
*
@ -162,6 +171,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
*
@ -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 */

View File

@ -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 */
@ -621,26 +571,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
*/

View File

@ -1047,6 +1047,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
*
@ -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

44
include/asterisk/silk.h Normal file
View File

@ -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 */

View File

@ -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

View File

@ -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));
}
)

View File

@ -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;

View File

@ -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();

View File

@ -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;
if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ? audiohook_read_frame_both(audiohook, samples) : audiohook_read_frame_single(audiohook, samples, direction))))
/* 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_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 */

View File

@ -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);
}

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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);