parent
555a541680
commit
1245ccfefb
|
@ -57,6 +57,7 @@ SPANDSP=@PBX_SPANDSP@
|
||||||
SPEEX=@PBX_SPEEX@
|
SPEEX=@PBX_SPEEX@
|
||||||
SPEEXDSP=@PBX_SPEEXDSP@
|
SPEEXDSP=@PBX_SPEEXDSP@
|
||||||
SPEEX_PREPROCESS=@PBX_SPEEX_PREPROCESS@
|
SPEEX_PREPROCESS=@PBX_SPEEX_PREPROCESS@
|
||||||
|
VEVS=@PBX_VEVS@
|
||||||
SQLITE3=@PBX_SQLITE3@
|
SQLITE3=@PBX_SQLITE3@
|
||||||
SRTP=@PBX_SRTP@
|
SRTP=@PBX_SRTP@
|
||||||
SS7=@PBX_SS7@
|
SS7=@PBX_SS7@
|
||||||
|
|
|
@ -0,0 +1,285 @@
|
||||||
|
/*
|
||||||
|
* Asterisk -- An open source telephony toolkit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \file
|
||||||
|
*
|
||||||
|
* \brief Translate between signed linear and Vocal EVS codec
|
||||||
|
*
|
||||||
|
* \ingroup codecs
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*** MODULEINFO
|
||||||
|
<depend>vevs</depend>
|
||||||
|
***/
|
||||||
|
|
||||||
|
#include "asterisk.h"
|
||||||
|
|
||||||
|
#include "asterisk/translate.h"
|
||||||
|
#include "asterisk/config.h"
|
||||||
|
#include "asterisk/module.h"
|
||||||
|
#include "asterisk/utils.h"
|
||||||
|
#include "asterisk/linkedlists.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#define uint8 uint8_t
|
||||||
|
#define uint16 uint16_t
|
||||||
|
#define uint32 uint32_t
|
||||||
|
#define vbool bool
|
||||||
|
#define sint15 int16_t
|
||||||
|
#include "vocal-evs/evs.h"
|
||||||
|
|
||||||
|
#define BUFFER_SAMPLES 8000 /* 0.5 seconds @ 16 kHz */
|
||||||
|
#define BUFFER_FRAMES 8192 /* Enough for about 0.5 seconds @ 128 Kbps */
|
||||||
|
|
||||||
|
/* Sample frame data */
|
||||||
|
|
||||||
|
#include "asterisk/slin.h"
|
||||||
|
#include "ex_vevs.h"
|
||||||
|
|
||||||
|
/* Encoder and decoder instances */
|
||||||
|
|
||||||
|
struct evs_enc_pvt {
|
||||||
|
evs_enc_ctx_t enc; /* Encoder states */
|
||||||
|
int chunk; /* Size of chunk to encode (in samples) */
|
||||||
|
int16_t buf[BUFFER_SAMPLES]; /* Buffer to store received uncompressed audio */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct evs_dec_pvt {
|
||||||
|
evs_dec_ctx_t dec; /* Decoder states */
|
||||||
|
int chunk; /* Size of chunk to decode (in samples) */
|
||||||
|
};
|
||||||
|
|
||||||
|
#warning hacking
|
||||||
|
int vocal_evs_init_coder (evs_enc_ctx_t *ctx, uint16 bandwidth, uint16 sampling_frequency, uint32 bitrate, vbool dtx_enable) { return 320; }
|
||||||
|
int vocal_evs_process_coder (evs_enc_ctx_t *ctx, uint8 *enc_data, uint16 enc_data_size, const sint15 *enc_samples, uint16 sample_count) { return 320; }
|
||||||
|
int vocal_evs_close_coder (evs_enc_ctx_t *ctx) { return 0; }
|
||||||
|
int vocal_evs_init_decoder (evs_dec_ctx_t *ctx, uint16 sampling_frequency) { return 320; }
|
||||||
|
int vocal_evs_process_decoder (evs_dec_ctx_t *ctx, sint15 *dec_samples, uint16 max_sample_count, uint8 *dec_data, uint16 dec_data_size) { return 320; }
|
||||||
|
int vocal_evs_close_decoder (evs_dec_ctx_t *ctx) { return 0; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Create and destroy codec intances */
|
||||||
|
|
||||||
|
static int evs_enc_new(struct ast_trans_pvt *pvt)
|
||||||
|
{
|
||||||
|
struct evs_enc_pvt *enc = pvt->pvt;
|
||||||
|
const unsigned int sample_rate = pvt->t->src_codec.sample_rate;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
memset(enc, 0, sizeof(*enc));
|
||||||
|
rc = vocal_evs_init_coder(&enc->enc, EVS_BW_NB, EVS_SF_16K, EVS_BR_5K90, false);
|
||||||
|
if (rc <= 0) {
|
||||||
|
ast_log(LOG_ERROR, "Error creating the Vocal EVS encoder\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
enc->chunk = rc;
|
||||||
|
|
||||||
|
ast_debug(3, "Created encoder (Vocal EVS) with sample rate %d\n", sample_rate);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void evs_enc_destroy(struct ast_trans_pvt *pvt)
|
||||||
|
{
|
||||||
|
struct evs_enc_pvt *enc = pvt->pvt;
|
||||||
|
|
||||||
|
vocal_evs_close_coder(&enc->enc);
|
||||||
|
|
||||||
|
ast_debug(3, "Destroyed encoder (Vocal EVS)\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int evs_dec_new(struct ast_trans_pvt *pvt)
|
||||||
|
{
|
||||||
|
struct evs_dec_pvt *dec = pvt->pvt;
|
||||||
|
const unsigned int sample_rate = pvt->t->src_codec.sample_rate;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
memset(dec, 0, sizeof(*dec));
|
||||||
|
rc = vocal_evs_init_decoder(&dec->dec, EVS_SF_16K);
|
||||||
|
if (rc <= 0) {
|
||||||
|
ast_log(LOG_ERROR, "Error creating the Vocal EVS decoder\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
dec->chunk = rc;
|
||||||
|
|
||||||
|
ast_debug(3, "Created decoder (Vocal EVS) with sample rate %d\n", sample_rate);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void evs_dec_destroy(struct ast_trans_pvt *pvt)
|
||||||
|
{
|
||||||
|
struct evs_dec_pvt *dec = pvt->pvt;
|
||||||
|
|
||||||
|
vocal_evs_close_decoder(&dec->dec);
|
||||||
|
|
||||||
|
ast_debug(3, "Destroyed encoder (Vocal EVS)\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encoder */
|
||||||
|
|
||||||
|
static int lintoevs_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
|
||||||
|
{
|
||||||
|
struct evs_enc_pvt *enc = pvt->pvt;
|
||||||
|
|
||||||
|
/* XXX We should look at how old the rest of our stream is, and if it
|
||||||
|
is too old, then we should overwrite it entirely, otherwise we can
|
||||||
|
get artifacts of earlier talk that do not belong */
|
||||||
|
if (pvt->samples + f->samples > BUFFER_SAMPLES) {
|
||||||
|
ast_log(LOG_WARNING, "Out of buffer space\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(enc->buf + pvt->samples, f->data.ptr, f->datalen);
|
||||||
|
pvt->samples += f->samples;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ast_frame *lintoevs_frameout(struct ast_trans_pvt *pvt)
|
||||||
|
{
|
||||||
|
struct evs_enc_pvt *enc = pvt->pvt;
|
||||||
|
struct ast_frame *result = NULL;
|
||||||
|
struct ast_frame *last = NULL;
|
||||||
|
int samples = 0; /* output samples */
|
||||||
|
|
||||||
|
while (pvt->samples >= enc->chunk) {
|
||||||
|
struct ast_frame *current;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = vocal_evs_process_coder(&enc->enc, pvt->outbuf.uc, BUFFER_FRAMES, enc->buf, enc->chunk);
|
||||||
|
if (rc <= 0) {
|
||||||
|
ast_log(LOG_ERROR, "Error encoding with Vocal EVS encoder\n");
|
||||||
|
pvt->samples = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
samples += enc->chunk;
|
||||||
|
pvt->samples -= enc->chunk;
|
||||||
|
current = ast_trans_frameout(pvt, rc, enc->chunk);
|
||||||
|
if (!current) {
|
||||||
|
continue;
|
||||||
|
} else if (last) {
|
||||||
|
/* Append frame */
|
||||||
|
AST_LIST_NEXT(last, frame_list) = current;
|
||||||
|
} else {
|
||||||
|
/* Return first frame */
|
||||||
|
result = current;
|
||||||
|
}
|
||||||
|
last = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move the data at the end of the buffer to the front */
|
||||||
|
if (samples) {
|
||||||
|
memmove(enc->buf, enc->buf + samples, pvt->samples * sizeof(int16_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decoder */
|
||||||
|
|
||||||
|
static int evstolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
|
||||||
|
{
|
||||||
|
struct evs_dec_pvt *dec = pvt->pvt;
|
||||||
|
int16_t *dst = pvt->outbuf.i16;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (BUFFER_SAMPLES - pvt->samples < dec->chunk) {
|
||||||
|
ast_log(LOG_WARNING, "Out of buffer space\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->datalen == 0) {
|
||||||
|
ast_log(LOG_DEBUG, "Conceal missing EVS frame.\n");
|
||||||
|
/* The documentation does not give a hint on how bad frames indicated and if they are concealed at all. This may not work!*/
|
||||||
|
rc = vocal_evs_process_decoder(&dec->dec, dst + pvt->samples, BUFFER_SAMPLES - pvt->samples, NULL, 0);
|
||||||
|
if (rc <= 0) {
|
||||||
|
ast_log(LOG_ERROR, "Error concealing missing EVS frame with Vocal EVS decoder\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rc = vocal_evs_process_decoder(&dec->dec, dst + pvt->samples, BUFFER_SAMPLES - pvt->samples, f->data.ptr, f->datalen);
|
||||||
|
if (rc <= 0) {
|
||||||
|
ast_log(LOG_ERROR, "Error decoding with Vocal EVS decoder\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pvt->samples += rc;
|
||||||
|
pvt->datalen += rc * sizeof(int16_t);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ast_translator lintoevs = {
|
||||||
|
.name = "lintovevs",
|
||||||
|
.src_codec = {
|
||||||
|
.name = "slin",
|
||||||
|
.type = AST_MEDIA_TYPE_AUDIO,
|
||||||
|
.sample_rate = 16000,
|
||||||
|
},
|
||||||
|
.dst_codec = {
|
||||||
|
.name = "vevs",
|
||||||
|
.type = AST_MEDIA_TYPE_AUDIO,
|
||||||
|
.sample_rate = 16000,
|
||||||
|
},
|
||||||
|
.format = "vevs",
|
||||||
|
.newpvt = evs_enc_new,
|
||||||
|
.framein = lintoevs_framein,
|
||||||
|
.frameout = lintoevs_frameout,
|
||||||
|
.destroy = evs_enc_destroy,
|
||||||
|
.sample = slin16_sample,
|
||||||
|
.buf_size = BUFFER_FRAMES,
|
||||||
|
.desc_size = sizeof (struct evs_enc_pvt ),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ast_translator evstolin = {
|
||||||
|
.name = "vevstolin",
|
||||||
|
.src_codec = {
|
||||||
|
.name = "vevs",
|
||||||
|
.type = AST_MEDIA_TYPE_AUDIO,
|
||||||
|
.sample_rate = 16000,
|
||||||
|
},
|
||||||
|
.dst_codec = {
|
||||||
|
.name = "slin",
|
||||||
|
.type = AST_MEDIA_TYPE_AUDIO,
|
||||||
|
.sample_rate = 16000,
|
||||||
|
},
|
||||||
|
.format = "slin",
|
||||||
|
.newpvt = evs_dec_new,
|
||||||
|
.framein = evstolin_framein,
|
||||||
|
.destroy = evs_dec_destroy,
|
||||||
|
.sample = vevs_sample,
|
||||||
|
.buffer_samples = BUFFER_SAMPLES,
|
||||||
|
.buf_size = BUFFER_SAMPLES * 2,
|
||||||
|
.desc_size = sizeof (struct evs_dec_pvt ),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int unload_module(void)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = ast_unregister_translator(&lintoevs);
|
||||||
|
res |= ast_unregister_translator(&evstolin);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int load_module(void)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = ast_register_translator(&evstolin);
|
||||||
|
res |= ast_register_translator(&lintoevs);
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
unload_module();
|
||||||
|
return AST_MODULE_LOAD_DECLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AST_MODULE_LOAD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Vocal EVS Coder/Decoder",
|
||||||
|
.support_level = AST_MODULE_SUPPORT_CORE,
|
||||||
|
.load = load_module,
|
||||||
|
.unload = unload_module,
|
||||||
|
);
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include "asterisk/format_cache.h" /* for ast_format_evs */
|
||||||
|
#include "asterisk/frame.h" /* for ast_frame, etc */
|
||||||
|
|
||||||
|
static uint8_t ex_vevs[] = { /* PRIMARY_16400, WB */
|
||||||
|
0x05, 0x51, 0x63, 0x4e, 0xa7, 0x87, 0x0c, 0xc4,
|
||||||
|
0x50, 0x3c, 0xcf, 0x60, 0x19, 0xbf, 0xd3, 0x93,
|
||||||
|
0xf4, 0xd9, 0x49, 0xac, 0x89, 0xce, 0x4c, 0x4d,
|
||||||
|
0x5e, 0x01, 0xff, 0x80, 0x00, 0x17, 0x17, 0xd5,
|
||||||
|
0x73, 0x7b, 0xd5, 0x1d, 0xe1, 0xcf, 0x65, 0x0b,
|
||||||
|
0xee, 0x95
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ast_frame *vevs_sample(void)
|
||||||
|
{
|
||||||
|
static struct ast_frame f = {
|
||||||
|
.frametype = AST_FRAME_VOICE,
|
||||||
|
.datalen = sizeof(ex_vevs),
|
||||||
|
.samples = 320,
|
||||||
|
.mallocd = 0,
|
||||||
|
.offset = 0,
|
||||||
|
.src = __PRETTY_FUNCTION__,
|
||||||
|
.data.ptr = ex_vevs,
|
||||||
|
};
|
||||||
|
|
||||||
|
f.subclass.format = ast_format_vevs;
|
||||||
|
|
||||||
|
return &f;
|
||||||
|
}
|
|
@ -1017,6 +1017,10 @@ PBX_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK
|
||||||
PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_DIR
|
PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_DIR
|
||||||
PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_INCLUDE
|
PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_INCLUDE
|
||||||
PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_LIB
|
PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_LIB
|
||||||
|
PBX_VEVS
|
||||||
|
VEVS_DIR
|
||||||
|
VEVS_INCLUDE
|
||||||
|
VEVS_LIB
|
||||||
PBX_BEANSTALK
|
PBX_BEANSTALK
|
||||||
BEANSTALK_DIR
|
BEANSTALK_DIR
|
||||||
BEANSTALK_INCLUDE
|
BEANSTALK_INCLUDE
|
||||||
|
@ -2216,6 +2220,7 @@ Optional Packages:
|
||||||
--with-opusfile=PATH use Opusfile files in PATH
|
--with-opusfile=PATH use Opusfile files in PATH
|
||||||
--with-postgres=PATH use PostgreSQL files in PATH
|
--with-postgres=PATH use PostgreSQL files in PATH
|
||||||
--with-beanstalk=PATH use Beanstalk Job Queue files in PATH
|
--with-beanstalk=PATH use Beanstalk Job Queue files in PATH
|
||||||
|
--with-bluetooth=PATH use Vocal EVS Audio Decoder/Encoder files in PATH
|
||||||
--with-pjproject=PATH use PJPROJECT files in PATH
|
--with-pjproject=PATH use PJPROJECT files in PATH
|
||||||
--with-popt=PATH use popt files in PATH
|
--with-popt=PATH use popt files in PATH
|
||||||
--with-portaudio=PATH use PortAudio files in PATH
|
--with-portaudio=PATH use PortAudio files in PATH
|
||||||
|
@ -13151,6 +13156,41 @@ fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#FIXME
|
||||||
|
|
||||||
|
VEVS_DESCRIP="Vocal EVS Audio Decoder/Encoder"
|
||||||
|
VEVS_OPTION="bluetooth"
|
||||||
|
PBX_VEVS=0
|
||||||
|
|
||||||
|
# Check whether --with-bluetooth was given.
|
||||||
|
if test ${with_bluetooth+y}
|
||||||
|
then :
|
||||||
|
withval=$with_bluetooth;
|
||||||
|
case ${withval} in
|
||||||
|
n|no)
|
||||||
|
USE_VEVS=no
|
||||||
|
# -1 is a magic value used by menuselect to know that the package
|
||||||
|
# was disabled, other than 'not found'
|
||||||
|
PBX_VEVS=-1
|
||||||
|
;;
|
||||||
|
y|ye|yes)
|
||||||
|
ac_mandatory_list="${ac_mandatory_list} VEVS"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
VEVS_DIR="${withval}"
|
||||||
|
ac_mandatory_list="${ac_mandatory_list} VEVS"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#AST_EXT_LIB_SETUP([VEVS], [Vocal EVS Audio Decoder/Encoder], [vocal-evs])
|
||||||
|
|
||||||
if test "x${PBX_PJPROJECT}" != "x1" ; then
|
if test "x${PBX_PJPROJECT}" != "x1" ; then
|
||||||
|
|
||||||
|
@ -26471,6 +26511,105 @@ fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#FIXME
|
||||||
|
|
||||||
|
if test "x${PBX_VEVS}" != "x1" -a "${USE_VEVS}" != "no"; then
|
||||||
|
pbxlibdir=""
|
||||||
|
# if --with-VEVS=DIR has been specified, use it.
|
||||||
|
if test "x${VEVS_DIR}" != "x"; then
|
||||||
|
if test -d ${VEVS_DIR}/lib; then
|
||||||
|
pbxlibdir="-L${VEVS_DIR}/lib"
|
||||||
|
else
|
||||||
|
pbxlibdir="-L${VEVS_DIR}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
|
||||||
|
CFLAGS="${CFLAGS} "
|
||||||
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ba2str in -lbluetooth" >&5
|
||||||
|
printf %s "checking for ba2str in -lbluetooth... " >&6; }
|
||||||
|
if test ${ac_cv_lib_bluetooth_ba2str+y}
|
||||||
|
then :
|
||||||
|
printf %s "(cached) " >&6
|
||||||
|
else $as_nop
|
||||||
|
ac_check_lib_save_LIBS=$LIBS
|
||||||
|
LIBS="-lbluetooth ${pbxlibdir} $LIBS"
|
||||||
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
|
/* end confdefs.h. */
|
||||||
|
|
||||||
|
/* Override any GCC internal prototype to avoid an error.
|
||||||
|
Use char because int might match the return type of a GCC
|
||||||
|
builtin and then its argument prototype would still apply. */
|
||||||
|
char ba2str ();
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
return ba2str ();
|
||||||
|
;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_ACEOF
|
||||||
|
if ac_fn_c_try_link "$LINENO"
|
||||||
|
then :
|
||||||
|
ac_cv_lib_bluetooth_ba2str=yes
|
||||||
|
else $as_nop
|
||||||
|
ac_cv_lib_bluetooth_ba2str=no
|
||||||
|
fi
|
||||||
|
rm -f core conftest.err conftest.$ac_objext conftest.beam \
|
||||||
|
conftest$ac_exeext conftest.$ac_ext
|
||||||
|
LIBS=$ac_check_lib_save_LIBS
|
||||||
|
fi
|
||||||
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bluetooth_ba2str" >&5
|
||||||
|
printf "%s\n" "$ac_cv_lib_bluetooth_ba2str" >&6; }
|
||||||
|
if test "x$ac_cv_lib_bluetooth_ba2str" = xyes
|
||||||
|
then :
|
||||||
|
AST_VEVS_FOUND=yes
|
||||||
|
else $as_nop
|
||||||
|
AST_VEVS_FOUND=no
|
||||||
|
fi
|
||||||
|
|
||||||
|
CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
|
||||||
|
|
||||||
|
|
||||||
|
# now check for the header.
|
||||||
|
if test "${AST_VEVS_FOUND}" = "yes"; then
|
||||||
|
VEVS_LIB="${pbxlibdir} -lbluetooth "
|
||||||
|
# if --with-VEVS=DIR has been specified, use it.
|
||||||
|
if test "x${VEVS_DIR}" != "x"; then
|
||||||
|
VEVS_INCLUDE="-I${VEVS_DIR}/include"
|
||||||
|
fi
|
||||||
|
VEVS_INCLUDE="${VEVS_INCLUDE} "
|
||||||
|
|
||||||
|
# check for the header
|
||||||
|
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
|
||||||
|
CPPFLAGS="${CPPFLAGS} ${VEVS_INCLUDE}"
|
||||||
|
ac_fn_c_check_header_compile "$LINENO" "bluetooth/bluetooth.h" "ac_cv_header_bluetooth_bluetooth_h" "$ac_includes_default"
|
||||||
|
if test "x$ac_cv_header_bluetooth_bluetooth_h" = xyes
|
||||||
|
then :
|
||||||
|
VEVS_HEADER_FOUND=1
|
||||||
|
else $as_nop
|
||||||
|
VEVS_HEADER_FOUND=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
|
||||||
|
|
||||||
|
if test "x${VEVS_HEADER_FOUND}" = "x0" ; then
|
||||||
|
VEVS_LIB=""
|
||||||
|
VEVS_INCLUDE=""
|
||||||
|
else
|
||||||
|
|
||||||
|
PBX_VEVS=1
|
||||||
|
cat >>confdefs.h <<_ACEOF
|
||||||
|
#define HAVE_VEVS 1
|
||||||
|
_ACEOF
|
||||||
|
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
#AST_EXT_LIB_CHECK([VEVS], [vocal-evs], [vevs_enc], [vocal-evs/evs.h])
|
||||||
|
|
||||||
PG_CONFIG=":"
|
PG_CONFIG=":"
|
||||||
if test "${USE_PGSQL}" != "no"; then
|
if test "${USE_PGSQL}" != "no"; then
|
||||||
if test "x${PGSQL_DIR}" != "x"; then
|
if test "x${PGSQL_DIR}" != "x"; then
|
||||||
|
|
|
@ -579,6 +579,9 @@ AST_EXT_LIB_SETUP([OPUS], [Opus], [opus])
|
||||||
AST_EXT_LIB_SETUP([OPUSFILE], [Opusfile], [opusfile])
|
AST_EXT_LIB_SETUP([OPUSFILE], [Opusfile], [opusfile])
|
||||||
AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres])
|
AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres])
|
||||||
AST_EXT_LIB_SETUP([BEANSTALK], [Beanstalk Job Queue], [beanstalk])
|
AST_EXT_LIB_SETUP([BEANSTALK], [Beanstalk Job Queue], [beanstalk])
|
||||||
|
#FIXME
|
||||||
|
AST_EXT_LIB_SETUP([VEVS], [Vocal EVS Audio Decoder/Encoder], [bluetooth])
|
||||||
|
#AST_EXT_LIB_SETUP([VEVS], [Vocal EVS Audio Decoder/Encoder], [vocal-evs])
|
||||||
|
|
||||||
if test "x${PBX_PJPROJECT}" != "x1" ; then
|
if test "x${PBX_PJPROJECT}" != "x1" ; then
|
||||||
AST_EXT_LIB_SETUP([PJPROJECT], [PJPROJECT], [pjproject])
|
AST_EXT_LIB_SETUP([PJPROJECT], [PJPROJECT], [pjproject])
|
||||||
|
@ -2409,6 +2412,10 @@ AST_EXT_LIB_CHECK([BLUETOOTH], [bluetooth], [ba2str], [bluetooth/bluetooth.h])
|
||||||
|
|
||||||
AST_EXT_LIB_CHECK([BEANSTALK], [beanstalk], [bs_version], [beanstalk.h])
|
AST_EXT_LIB_CHECK([BEANSTALK], [beanstalk], [bs_version], [beanstalk.h])
|
||||||
|
|
||||||
|
#FIXME
|
||||||
|
AST_EXT_LIB_CHECK([VEVS], [bluetooth], [ba2str], [bluetooth/bluetooth.h])
|
||||||
|
#AST_EXT_LIB_CHECK([VEVS], [vocal-evs], [vevs_enc], [vocal-evs/evs.h])
|
||||||
|
|
||||||
PG_CONFIG=":"
|
PG_CONFIG=":"
|
||||||
if test "${USE_PGSQL}" != "no"; then
|
if test "${USE_PGSQL}" != "no"; then
|
||||||
if test "x${PGSQL_DIR}" != "x"; then
|
if test "x${PGSQL_DIR}" != "x"; then
|
||||||
|
|
|
@ -1226,6 +1226,9 @@
|
||||||
/* Define to 1 if you have the `vasprintf' function. */
|
/* Define to 1 if you have the `vasprintf' function. */
|
||||||
#undef HAVE_VASPRINTF
|
#undef HAVE_VASPRINTF
|
||||||
|
|
||||||
|
/* Define to 1 if you have the Vocal EVS Audio Decoder/Encoder library. */
|
||||||
|
#undef HAVE_VEVS
|
||||||
|
|
||||||
/* Define to 1 if you have the `vfork' function. */
|
/* Define to 1 if you have the `vfork' function. */
|
||||||
#undef HAVE_VFORK
|
#undef HAVE_VFORK
|
||||||
|
|
||||||
|
|
|
@ -245,6 +245,10 @@ extern struct ast_format *ast_format_silk8;
|
||||||
extern struct ast_format *ast_format_silk12;
|
extern struct ast_format *ast_format_silk12;
|
||||||
extern struct ast_format *ast_format_silk16;
|
extern struct ast_format *ast_format_silk16;
|
||||||
extern struct ast_format *ast_format_silk24;
|
extern struct ast_format *ast_format_silk24;
|
||||||
|
/*!
|
||||||
|
* \brief Built-in cached Vocal EVS format.
|
||||||
|
*/
|
||||||
|
extern struct ast_format *ast_format_vevs;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Initialize format cache support within the core.
|
* \brief Initialize format cache support within the core.
|
||||||
|
|
|
@ -925,6 +925,16 @@ static struct ast_codec silk24 = {
|
||||||
.samples_count = silk_samples
|
.samples_count = silk_samples
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct ast_codec vevs = {
|
||||||
|
.name = "vevs",
|
||||||
|
.description = "Vocal EVS",
|
||||||
|
.type = AST_MEDIA_TYPE_AUDIO,
|
||||||
|
.sample_rate = 16000,
|
||||||
|
.minimum_ms = 20,
|
||||||
|
.maximum_ms = 300,
|
||||||
|
.default_ms = 20,
|
||||||
|
};
|
||||||
|
|
||||||
#define CODEC_REGISTER_AND_CACHE(codec) \
|
#define CODEC_REGISTER_AND_CACHE(codec) \
|
||||||
({ \
|
({ \
|
||||||
int __res_ ## __LINE__ = 0; \
|
int __res_ ## __LINE__ = 0; \
|
||||||
|
@ -1003,6 +1013,7 @@ int ast_codec_builtin_init(void)
|
||||||
res |= CODEC_REGISTER_AND_CACHE_NAMED("silk12", silk12);
|
res |= CODEC_REGISTER_AND_CACHE_NAMED("silk12", silk12);
|
||||||
res |= CODEC_REGISTER_AND_CACHE_NAMED("silk16", silk16);
|
res |= CODEC_REGISTER_AND_CACHE_NAMED("silk16", silk16);
|
||||||
res |= CODEC_REGISTER_AND_CACHE_NAMED("silk24", silk24);
|
res |= CODEC_REGISTER_AND_CACHE_NAMED("silk24", silk24);
|
||||||
|
res |= CODEC_REGISTER_AND_CACHE(vevs);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,6 +252,10 @@ struct ast_format *ast_format_silk8;
|
||||||
struct ast_format *ast_format_silk12;
|
struct ast_format *ast_format_silk12;
|
||||||
struct ast_format *ast_format_silk16;
|
struct ast_format *ast_format_silk16;
|
||||||
struct ast_format *ast_format_silk24;
|
struct ast_format *ast_format_silk24;
|
||||||
|
/*!
|
||||||
|
* \brief Built-in cached Vocal EVS format.
|
||||||
|
*/
|
||||||
|
struct ast_format *ast_format_vevs;
|
||||||
|
|
||||||
/*! \brief Number of buckets to use for the media format cache (should be prime for performance reasons) */
|
/*! \brief Number of buckets to use for the media format cache (should be prime for performance reasons) */
|
||||||
#define CACHE_BUCKETS 53
|
#define CACHE_BUCKETS 53
|
||||||
|
@ -359,6 +363,7 @@ static void format_cache_shutdown(void)
|
||||||
ao2_replace(ast_format_silk12, NULL);
|
ao2_replace(ast_format_silk12, NULL);
|
||||||
ao2_replace(ast_format_silk16, NULL);
|
ao2_replace(ast_format_silk16, NULL);
|
||||||
ao2_replace(ast_format_silk24, NULL);
|
ao2_replace(ast_format_silk24, NULL);
|
||||||
|
ao2_replace(ast_format_vevs, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ast_format_cache_init(void)
|
int ast_format_cache_init(void)
|
||||||
|
@ -468,6 +473,8 @@ static void set_cached_format(const char *name, struct ast_format *format)
|
||||||
ao2_replace(ast_format_silk16, format);
|
ao2_replace(ast_format_silk16, format);
|
||||||
} else if (!strcmp(name, "silk24")) {
|
} else if (!strcmp(name, "silk24")) {
|
||||||
ao2_replace(ast_format_silk24, format);
|
ao2_replace(ast_format_silk24, format);
|
||||||
|
} else if (!strcmp(name, "vevs")) {
|
||||||
|
ao2_replace(ast_format_vevs, format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3724,6 +3724,7 @@ int ast_rtp_engine_init(void)
|
||||||
set_next_mime_type(ast_format_opus, 0, "audio", "opus", 48000);
|
set_next_mime_type(ast_format_opus, 0, "audio", "opus", 48000);
|
||||||
set_next_mime_type(ast_format_vp8, 0, "video", "VP8", 90000);
|
set_next_mime_type(ast_format_vp8, 0, "video", "VP8", 90000);
|
||||||
set_next_mime_type(ast_format_vp9, 0, "video", "VP9", 90000);
|
set_next_mime_type(ast_format_vp9, 0, "video", "VP9", 90000);
|
||||||
|
set_next_mime_type(ast_format_vevs, 0, "audio", "EVS", 16000);
|
||||||
|
|
||||||
/* Define the static rtp payload mappings */
|
/* Define the static rtp payload mappings */
|
||||||
add_static_payload(0, ast_format_ulaw, 0);
|
add_static_payload(0, ast_format_ulaw, 0);
|
||||||
|
|
|
@ -351,4 +351,7 @@ SNDFILE_LIB=@SNDFILE_LIB@
|
||||||
BEANSTALK_INCLUDE=@BEANSTALK_INCLUDE@
|
BEANSTALK_INCLUDE=@BEANSTALK_INCLUDE@
|
||||||
BEANSTALK_LIB=@BEANSTALK_LIB@
|
BEANSTALK_LIB=@BEANSTALK_LIB@
|
||||||
|
|
||||||
|
VEVS_INCLUDE=@VEVS_INCLUDE@
|
||||||
|
VEVS_LIB=@VEVS_LIB@
|
||||||
|
|
||||||
HAVE_SBIN_LAUNCHD=@PBX_LAUNCHD@
|
HAVE_SBIN_LAUNCHD=@PBX_LAUNCHD@
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
/*** MODULEINFO
|
||||||
|
<support_level>core</support_level>
|
||||||
|
***/
|
||||||
|
|
||||||
|
#include "asterisk.h"
|
||||||
|
|
||||||
|
#include <ctype.h> /* for tolower */
|
||||||
|
|
||||||
|
#include "asterisk/module.h"
|
||||||
|
#include "asterisk/format.h"
|
||||||
|
#include "asterisk/logger.h" /* for ast_log, LOG_WARNING */
|
||||||
|
#include "asterisk/strings.h" /* for ast_str_append */
|
||||||
|
#include "asterisk/utils.h" /* for MAX, MIN */
|
||||||
|
|
||||||
|
struct evs_attr {
|
||||||
|
int dummy;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void evs_destroy(struct ast_format *format)
|
||||||
|
{
|
||||||
|
struct evs_attr *attr = ast_format_get_attribute_data(format);
|
||||||
|
|
||||||
|
ast_free(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void attr_init(struct evs_attr *attr)
|
||||||
|
{
|
||||||
|
memset(attr, 0, sizeof(*attr));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int evs_clone(const struct ast_format *src, struct ast_format *dst)
|
||||||
|
{
|
||||||
|
struct evs_attr *original = ast_format_get_attribute_data(src);
|
||||||
|
struct evs_attr *attr = ast_malloc(sizeof(*attr));
|
||||||
|
|
||||||
|
#warning hacking
|
||||||
|
abort();
|
||||||
|
if (!attr) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (original) {
|
||||||
|
*attr = *original;
|
||||||
|
} else {
|
||||||
|
attr_init(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_format_set_attribute_data(dst, attr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ast_format *evs_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
|
||||||
|
{
|
||||||
|
char *attribs = ast_strdupa(attributes), *attrib;
|
||||||
|
struct ast_format *cloned;
|
||||||
|
struct evs_attr *attr;
|
||||||
|
// unsigned int val;
|
||||||
|
|
||||||
|
cloned = ast_format_clone(format);
|
||||||
|
if (!cloned) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
attr = ast_format_get_attribute_data(cloned);
|
||||||
|
|
||||||
|
/* lower-case everything, so we are case-insensitive */
|
||||||
|
for (attrib = attribs; *attrib; ++attrib) {
|
||||||
|
*attrib = tolower(*attrib);
|
||||||
|
} /* based on channels/chan_sip.c:process_a_sdp_image() */
|
||||||
|
|
||||||
|
ast_log(LOG_WARNING, "Unhandled received attribute '%s', please fix!\n", attrib);
|
||||||
|
|
||||||
|
return cloned;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void evs_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
|
||||||
|
{
|
||||||
|
struct evs_attr *attr = ast_format_get_attribute_data(format);
|
||||||
|
|
||||||
|
#warning hacking
|
||||||
|
// if (!attr) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
ast_str_append(str, 0, "a=fmtp:%u br=5.9; bw=nb-wb\r\n", payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum ast_format_cmp_res evs_cmp(const struct ast_format *format1, const struct ast_format *format2)
|
||||||
|
{
|
||||||
|
if (ast_format_get_sample_rate(format1) == ast_format_get_sample_rate(format2)) {
|
||||||
|
return AST_FORMAT_CMP_EQUAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AST_FORMAT_CMP_NOT_EQUAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ast_format *evs_getjoint(const struct ast_format *format1, const struct ast_format *format2)
|
||||||
|
{
|
||||||
|
struct evs_attr *attr1 = ast_format_get_attribute_data(format1);
|
||||||
|
struct evs_attr *attr2 = ast_format_get_attribute_data(format2);
|
||||||
|
struct ast_format *jointformat;
|
||||||
|
struct evs_attr *attr_res;
|
||||||
|
|
||||||
|
if (ast_format_get_sample_rate(format1) != ast_format_get_sample_rate(format2)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
jointformat = ast_format_clone(format1);
|
||||||
|
if (!jointformat) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
attr_res = ast_format_get_attribute_data(jointformat);
|
||||||
|
|
||||||
|
if (!attr1 || !attr2) {
|
||||||
|
attr_init(attr_res);
|
||||||
|
} else {
|
||||||
|
/* Take the lowest max bitrate */
|
||||||
|
// attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return jointformat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ast_format_interface evs_interface = {
|
||||||
|
.format_destroy = evs_destroy,
|
||||||
|
.format_clone = evs_clone,
|
||||||
|
.format_cmp = evs_cmp,
|
||||||
|
.format_get_joint = evs_getjoint,
|
||||||
|
.format_parse_sdp_fmtp = evs_parse_sdp_fmtp,
|
||||||
|
.format_generate_sdp_fmtp = evs_generate_sdp_fmtp,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int load_module(void)
|
||||||
|
{
|
||||||
|
if (ast_format_interface_register("vevs", &evs_interface)) {
|
||||||
|
return AST_MODULE_LOAD_DECLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AST_MODULE_LOAD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int unload_module(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Vocal EVS Format Attribute Module",
|
||||||
|
.support_level = AST_MODULE_SUPPORT_CORE,
|
||||||
|
.load = load_module,
|
||||||
|
.unload = unload_module,
|
||||||
|
.load_pri = AST_MODPRI_CHANNEL_DEPEND,
|
||||||
|
);
|
Loading…
Reference in New Issue