adds speex 16khz audio support

(closes issue #17501)
Reported by: fabled
Patches:
      asterisk-trunk-speex-wideband-v2.patch uploaded by fabled (license 448)
Tested by: malcolmd, fabled, dvossel



git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@271231 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
David Vossel
2010-06-17 17:23:43 +00:00
parent 0ef5550742
commit b00f58da25
7 changed files with 88 additions and 29 deletions

View File

@@ -500,6 +500,8 @@ Miscellaneous
* Distributed devicestate now supports the use of the XMPP protocol, in addition to * Distributed devicestate now supports the use of the XMPP protocol, in addition to
AIS. For more information, please see doc/distributed_devstate-XMPP.txt AIS. For more information, please see doc/distributed_devstate-XMPP.txt
* The addition of G.719 pass-through support. * The addition of G.719 pass-through support.
* Added support for 16khz Speex audio. This can be enabled by using 'allow=speex16'
during device configuration.
CLI Changes CLI Changes

View File

@@ -97,12 +97,11 @@ struct speex_coder_pvt {
#endif #endif
}; };
static int speex_encoder_construct(struct ast_trans_pvt *pvt, const SpeexMode *profile, int sampling_rate)
static int lintospeex_new(struct ast_trans_pvt *pvt)
{ {
struct speex_coder_pvt *tmp = pvt->pvt; struct speex_coder_pvt *tmp = pvt->pvt;
if (!(tmp->speex = speex_encoder_init(&speex_nb_mode))) if (!(tmp->speex = speex_encoder_init(profile)))
return -1; return -1;
speex_bits_init(&tmp->bits); speex_bits_init(&tmp->bits);
@@ -111,7 +110,7 @@ static int lintospeex_new(struct ast_trans_pvt *pvt)
speex_encoder_ctl(tmp->speex, SPEEX_SET_COMPLEXITY, &complexity); speex_encoder_ctl(tmp->speex, SPEEX_SET_COMPLEXITY, &complexity);
#ifdef _SPEEX_TYPES_H #ifdef _SPEEX_TYPES_H
if (preproc) { if (preproc) {
tmp->pp = speex_preprocess_state_init(tmp->framesize, 8000); /* XXX what is this 8000 ? */ tmp->pp = speex_preprocess_state_init(tmp->framesize, sampling_rate);
speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_VAD, &pp_vad); speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_VAD, &pp_vad);
speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC, &pp_agc); speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC, &pp_agc);
speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &pp_agc_level); speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &pp_agc_level);
@@ -139,11 +138,21 @@ static int lintospeex_new(struct ast_trans_pvt *pvt)
return 0; return 0;
} }
static int speextolin_new(struct ast_trans_pvt *pvt) static int lintospeex_new(struct ast_trans_pvt *pvt)
{
return speex_encoder_construct(pvt, &speex_nb_mode, 8000);
}
static int lin16tospeexwb_new(struct ast_trans_pvt *pvt)
{
return speex_encoder_construct(pvt, &speex_wb_mode, 16000);
}
static int speex_decoder_construct(struct ast_trans_pvt *pvt, const SpeexMode *profile)
{ {
struct speex_coder_pvt *tmp = pvt->pvt; struct speex_coder_pvt *tmp = pvt->pvt;
if (!(tmp->speex = speex_decoder_init(&speex_nb_mode))) if (!(tmp->speex = speex_decoder_init(profile)))
return -1; return -1;
speex_bits_init(&tmp->bits); speex_bits_init(&tmp->bits);
@@ -154,6 +163,16 @@ static int speextolin_new(struct ast_trans_pvt *pvt)
return 0; return 0;
} }
static int speextolin_new(struct ast_trans_pvt *pvt)
{
return speex_decoder_construct(pvt, &speex_nb_mode);
}
static int speexwbtolin16_new(struct ast_trans_pvt *pvt)
{
return speex_decoder_construct(pvt, &speex_wb_mode);
}
/*! \brief convert and store into outbuf */ /*! \brief convert and store into outbuf */
static int speextolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) static int speextolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
{ {
@@ -337,6 +356,34 @@ static struct ast_translator lintospeex = {
.buf_size = BUFFER_SAMPLES * 2, /* XXX maybe a lot less ? */ .buf_size = BUFFER_SAMPLES * 2, /* XXX maybe a lot less ? */
}; };
static struct ast_translator speexwbtolin16 = {
.name = "speexwbtolin16",
.srcfmt = AST_FORMAT_SPEEX16,
.dstfmt = AST_FORMAT_SLINEAR16,
.newpvt = speexwbtolin16_new,
.framein = speextolin_framein,
.destroy = speextolin_destroy,
.sample = speex_sample,
.desc_size = sizeof(struct speex_coder_pvt),
.buffer_samples = BUFFER_SAMPLES,
.buf_size = BUFFER_SAMPLES * 2,
.native_plc = 1,
};
static struct ast_translator lin16tospeexwb = {
.name = "lin16tospeexwb",
.srcfmt = AST_FORMAT_SLINEAR16,
.dstfmt = AST_FORMAT_SPEEX16,
.newpvt = lin16tospeexwb_new,
.framein = lintospeex_framein,
.frameout = lintospeex_frameout,
.destroy = lintospeex_destroy,
.sample = slin8_sample,
.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) static int parse_config(int reload)
{ {
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
@@ -441,28 +488,29 @@ static int reload(void)
static int unload_module(void) static int unload_module(void)
{ {
int res; int res = 0;
res = ast_unregister_translator(&lintospeex);
res |= ast_unregister_translator(&speextolin); res |= ast_unregister_translator(&speextolin);
res |= ast_unregister_translator(&lintospeex);
res |= ast_unregister_translator(&speexwbtolin16);
res |= ast_unregister_translator(&lin16tospeexwb);
return res; return res;
} }
static int load_module(void) static int load_module(void)
{ {
int res; int res = 0;
if (parse_config(0)) if (parse_config(0))
return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_DECLINE;
res=ast_register_translator(&speextolin);
if (!res) res |= ast_register_translator(&speextolin);
res=ast_register_translator(&lintospeex); res |= ast_register_translator(&lintospeex);
else res |= ast_register_translator(&speexwbtolin16);
ast_unregister_translator(&speextolin); res |= ast_register_translator(&lin16tospeexwb);
if (res)
return AST_MODULE_LOAD_FAILURE; return res;
return AST_MODULE_LOAD_SUCCESS;
} }
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Speex Coder/Decoder", AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Speex Coder/Decoder",

View File

@@ -296,8 +296,10 @@ extern struct ast_frame ast_null_frame;
#define AST_FORMAT_TEXT_MASK (((1ULL << 30)-1) & ~(AST_FORMAT_AUDIO_MASK) & ~(AST_FORMAT_VIDEO_MASK)) #define AST_FORMAT_TEXT_MASK (((1ULL << 30)-1) & ~(AST_FORMAT_AUDIO_MASK) & ~(AST_FORMAT_VIDEO_MASK))
/*! G.719 (64 kbps assumed) */ /*! G.719 (64 kbps assumed) */
#define AST_FORMAT_G719 (1ULL << 32) #define AST_FORMAT_G719 (1ULL << 32)
/*! SpeeX Wideband (16kHz) Free Compression */
#define AST_FORMAT_SPEEX16 (1ULL << 33)
/*! Raw mu-law data (G.711) */ /*! Raw mu-law data (G.711) */
#define AST_FORMAT_TESTLAW (1ULL << 47) #define AST_FORMAT_TESTLAW (1ULL << 47)
/*! Reserved bit - do not use */ /*! Reserved bit - do not use */
#define AST_FORMAT_RESERVED (1ULL << 63) #define AST_FORMAT_RESERVED (1ULL << 63)
@@ -745,6 +747,7 @@ static force_inline int ast_format_rate(format_t format)
case AST_FORMAT_G722: case AST_FORMAT_G722:
case AST_FORMAT_SLINEAR16: case AST_FORMAT_SLINEAR16:
case AST_FORMAT_SIREN7: case AST_FORMAT_SIREN7:
case AST_FORMAT_SPEEX16:
return 16000; return 16000;
case AST_FORMAT_SIREN14: case AST_FORMAT_SIREN14:
return 32000; return 32000;

View File

@@ -813,6 +813,7 @@ format_t ast_best_codec(format_t fmts)
/*! iLBC is not too bad */ /*! iLBC is not too bad */
AST_FORMAT_ILBC, AST_FORMAT_ILBC,
/*! Speex is free, but computationally more expensive than GSM */ /*! Speex is free, but computationally more expensive than GSM */
AST_FORMAT_SPEEX16,
AST_FORMAT_SPEEX, AST_FORMAT_SPEEX,
/*! Ick, LPC10 sounds terrible, but at least we have code for it, if you're tacky enough /*! Ick, LPC10 sounds terrible, but at least we have code for it, if you're tacky enough
to use it */ to use it */

View File

@@ -104,6 +104,7 @@ static const struct ast_format_list AST_FORMAT_LIST[] = {
{ AST_FORMAT_LPC10, "lpc10", 8000, "LPC10", 7, 20, 20, 20, 20 }, /*!< codec_lpc10.c */ { 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_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_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_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_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_G722, "g722", 16000, "G722", 80, 10, 150, 10, 20 }, /*!< codec_g722.c */
@@ -119,7 +120,7 @@ static const struct ast_format_list AST_FORMAT_LIST[] = {
{ AST_FORMAT_T140, "t140", 0, "Passthrough T.140 Realtime Text" }, /*!< Passthrough support for 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_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_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_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 }, { AST_FORMAT_G719, "g719", 48000, "ITU G.719", 160, 20, 80, 20, 20 },
}; };
@@ -1354,7 +1355,7 @@ static unsigned char get_n_bits_at(unsigned char *data, int n, int bit)
static int speex_get_wb_sz_at(unsigned char *data, int len, int bit) static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
{ {
static const int SpeexWBSubModeSz[] = { static const int SpeexWBSubModeSz[] = {
0, 36, 112, 192, 4, 36, 112, 192,
352, 0, 0, 0 }; 352, 0, 0, 0 };
int off = bit; int off = bit;
unsigned char c; unsigned char c;
@@ -1407,12 +1408,8 @@ static int speex_samples(unsigned char *data, int len)
} }
bit += off; bit += off;
if ((len * 8 - bit) == 0) { if ((len * 8 - bit) < 5)
break; break;
} else if ((len * 8 - bit) < 5) {
ast_log(LOG_WARNING, "Not enough bits remaining after wide band for speex samples.\n");
break;
}
/* get control bits */ /* get control bits */
c = get_n_bits_at(data, 5, bit); c = get_n_bits_at(data, 5, bit);
@@ -1427,12 +1424,14 @@ static int speex_samples(unsigned char *data, int len)
bit += 4; bit += 4;
bit += SpeexInBandSz[c]; bit += SpeexInBandSz[c];
} else if (c == 13) { } else if (c == 13) {
/* user in-band; next 5 bits contain msg len */ /* user in-band; next 4 bits contain msg len */
c = get_n_bits_at(data, 5, bit); c = get_n_bits_at(data, 4, bit);
bit += 5; bit += 4;
bit += c * 8; /* after which it's 5-bit signal id + c bytes of data */
bit += 5 + c * 8;
} else if (c > 8) { } else if (c > 8) {
/* unknown */ /* unknown */
ast_log(LOG_WARNING, "Unknown speex control frame %d\n", c);
break; break;
} else { } else {
/* skip number bits for submode (less the 5 control bits) */ /* skip number bits for submode (less the 5 control bits) */
@@ -1452,6 +1451,9 @@ int ast_codec_get_samples(struct ast_frame *f)
case AST_FORMAT_SPEEX: case AST_FORMAT_SPEEX:
samples = speex_samples(f->data.ptr, f->datalen); samples = speex_samples(f->data.ptr, f->datalen);
break; break;
case AST_FORMAT_SPEEX16:
samples = 2 * speex_samples(f->data.ptr, f->datalen);
break;
case AST_FORMAT_G723_1: case AST_FORMAT_G723_1:
samples = g723_samples(f->data.ptr, f->datalen); samples = g723_samples(f->data.ptr, f->datalen);
break; break;

View File

@@ -102,6 +102,7 @@ static const struct ast_rtp_mime_type {
{{1, AST_FORMAT_G729A}, "audio", "G729A", 8000}, {{1, AST_FORMAT_G729A}, "audio", "G729A", 8000},
{{1, AST_FORMAT_G729A}, "audio", "G.729", 8000}, {{1, AST_FORMAT_G729A}, "audio", "G.729", 8000},
{{1, AST_FORMAT_SPEEX}, "audio", "speex", 8000}, {{1, AST_FORMAT_SPEEX}, "audio", "speex", 8000},
{{1, AST_FORMAT_SPEEX16}, "audio", "speex", 16000},
{{1, AST_FORMAT_ILBC}, "audio", "iLBC", 8000}, {{1, AST_FORMAT_ILBC}, "audio", "iLBC", 8000},
/* this is the sample rate listed in the RTP profile for the G.722 /* this is the sample rate listed in the RTP profile for the G.722
codec, *NOT* the actual sample rate of the media stream codec, *NOT* the actual sample rate of the media stream
@@ -171,6 +172,7 @@ static const struct ast_rtp_payload_type static_RTP_PT[AST_RTP_MAX_PT] = {
[112] = {1, AST_FORMAT_G726_AAL2}, [112] = {1, AST_FORMAT_G726_AAL2},
[115] = {1, AST_FORMAT_SIREN14}, [115] = {1, AST_FORMAT_SIREN14},
[116] = {1, AST_FORMAT_G719}, [116] = {1, AST_FORMAT_G719},
[117] = {1, AST_FORMAT_SPEEX16},
[121] = {0, AST_RTP_CISCO_DTMF}, /* Must be type 121 */ [121] = {0, AST_RTP_CISCO_DTMF}, /* Must be type 121 */
}; };

View File

@@ -1228,6 +1228,7 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr
switch (subclass) { switch (subclass) {
case AST_FORMAT_SPEEX: case AST_FORMAT_SPEEX:
case AST_FORMAT_SPEEX16:
case AST_FORMAT_G723_1: case AST_FORMAT_G723_1:
case AST_FORMAT_SIREN7: case AST_FORMAT_SIREN7:
case AST_FORMAT_SIREN14: case AST_FORMAT_SIREN14: