mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-20 20:48:07 +00:00
Merge branch 'dev_audio_bypass'
This commit is contained in:
commit
537fc5370f
8 changed files with 646 additions and 1 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit c01ab3c2df96a2aad53edde9b4759344ed3a5bad
|
||||
Subproject commit 128815537044ea17808a0a5843b2762364f8203d
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
set(SOURCE_FILES
|
||||
accountmanager.c
|
||||
audio_bypass_tester.c
|
||||
call_tester.c
|
||||
complex_sip_call_tester.c
|
||||
dtmf_tester.c
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
TESTER_SOUNDS = sounds/ahbahouaismaisbon.wav \
|
||||
sounds/hello8000.wav \
|
||||
sounds/hello44100.wav \
|
||||
sounds/oldphone.wav \
|
||||
sounds/sintel_trailer_opus_h264.mkv \
|
||||
sounds/sintel_trailer_pcmu_h264.mkv \
|
||||
|
|
@ -112,6 +113,7 @@ lib_LTLIBRARIES = liblinphonetester.la
|
|||
|
||||
liblinphonetester_la_SOURCES = \
|
||||
accountmanager.c \
|
||||
audio_bypass_tester.c \
|
||||
call_tester.c \
|
||||
complex_sip_call_tester.c \
|
||||
dtmf_tester.c \
|
||||
|
|
|
|||
501
tester/audio_bypass_tester.c
Normal file
501
tester/audio_bypass_tester.c
Normal file
|
|
@ -0,0 +1,501 @@
|
|||
/*
|
||||
liblinphone_tester - liblinphone test suite
|
||||
Copyright (C) 2013 Belledonne Communications SARL
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "liblinphone_tester.h"
|
||||
#include "private.h"
|
||||
#include "audio_bypass_wav_header.h" // This is a copy of mediastreamer2/src/audiofilters/wav_header.h
|
||||
|
||||
/**********************************************************************
|
||||
* This is a (simpler) copy of msfileplay filter in mediastreamer2 *
|
||||
*********************************************************************/
|
||||
|
||||
struct _PlayerData{
|
||||
int fd;
|
||||
MSPlayerState state;
|
||||
int rate;
|
||||
int nchannels;
|
||||
int hsize;
|
||||
int loop_after;
|
||||
int pause_time;
|
||||
int count;
|
||||
int samplesize;
|
||||
char *mime;
|
||||
uint32_t ts;
|
||||
bool_t swap;
|
||||
bool_t is_raw;
|
||||
};
|
||||
|
||||
typedef struct _PlayerData PlayerData;
|
||||
|
||||
static void audio_bypass_snd_read_init(MSFilter *f) {
|
||||
PlayerData *d=ms_new0(PlayerData,1);
|
||||
d->fd=-1;
|
||||
d->state=MSPlayerClosed;
|
||||
d->swap=TRUE;
|
||||
d->rate=44100;
|
||||
d->nchannels=1;
|
||||
d->samplesize=2;
|
||||
d->mime = "L16";
|
||||
d->hsize=0;
|
||||
d->loop_after=-1; /*by default, don't loop*/
|
||||
d->pause_time=0;
|
||||
d->count=0;
|
||||
d->ts=0;
|
||||
d->is_raw=TRUE;
|
||||
f->data=d;
|
||||
}
|
||||
|
||||
int ms_read_wav_header_from_fd(wave_header_t *header,int fd){
|
||||
int count;
|
||||
int skip;
|
||||
int hsize=0;
|
||||
riff_t *riff_chunk=&header->riff_chunk;
|
||||
format_t *format_chunk=&header->format_chunk;
|
||||
data_t *data_chunk=&header->data_chunk;
|
||||
|
||||
unsigned long len=0;
|
||||
|
||||
len = read(fd, (char*)riff_chunk, sizeof(riff_t)) ;
|
||||
if (len != sizeof(riff_t)){
|
||||
goto not_a_wav;
|
||||
}
|
||||
|
||||
if (0!=strncmp(riff_chunk->riff, "RIFF", 4) || 0!=strncmp(riff_chunk->wave, "WAVE", 4)){
|
||||
goto not_a_wav;
|
||||
}
|
||||
|
||||
len = read(fd, (char*)format_chunk, sizeof(format_t)) ;
|
||||
if (len != sizeof(format_t)){
|
||||
ms_warning("Wrong wav header: cannot read file");
|
||||
goto not_a_wav;
|
||||
}
|
||||
|
||||
if ((skip=le_uint32(format_chunk->len)-0x10)>0)
|
||||
{
|
||||
lseek(fd,skip,SEEK_CUR);
|
||||
}
|
||||
hsize=sizeof(wave_header_t)-0x10+le_uint32(format_chunk->len);
|
||||
|
||||
count=0;
|
||||
do{
|
||||
len = read(fd, data_chunk, sizeof(data_t)) ;
|
||||
if (len != sizeof(data_t)){
|
||||
ms_warning("Wrong wav header: cannot read file");
|
||||
goto not_a_wav;
|
||||
}
|
||||
if (strncmp(data_chunk->data, "data", 4)!=0){
|
||||
ms_warning("skipping chunk=%c%c%c%c len=%i", data_chunk->data[0],data_chunk->data[1],data_chunk->data[2],data_chunk->data[3], data_chunk->len);
|
||||
lseek(fd,le_uint32(data_chunk->len),SEEK_CUR);
|
||||
count++;
|
||||
hsize+=len+le_uint32(data_chunk->len);
|
||||
}else{
|
||||
hsize+=len;
|
||||
break;
|
||||
}
|
||||
}while(count<30);
|
||||
return hsize;
|
||||
|
||||
not_a_wav:
|
||||
/*rewind*/
|
||||
lseek(fd,0,SEEK_SET);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int read_wav_header(PlayerData *d){
|
||||
wave_header_t header;
|
||||
format_t *format_chunk=&header.format_chunk;
|
||||
int ret=ms_read_wav_header_from_fd(&header,d->fd);
|
||||
|
||||
d->samplesize=le_uint16(format_chunk->blockalign)/d->nchannels;
|
||||
d->hsize=ret;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
if (le_uint16(format_chunk->blockalign)==le_uint16(format_chunk->channel) * 2)
|
||||
d->swap=TRUE;
|
||||
#endif
|
||||
d->is_raw=FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void audio_bypass_snd_read_preprocess(MSFilter *f) {
|
||||
PlayerData *d=(PlayerData*)f->data;
|
||||
int fd;
|
||||
const char *file=bc_tester_res("sounds/hello44100.wav");
|
||||
|
||||
if ((fd=open(file,O_RDONLY|O_BINARY))==-1){
|
||||
ms_warning("MSFilePlayer[%p]: failed to open %s: %s",f,file,strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
d->state=MSPlayerPaused;
|
||||
d->fd=fd;
|
||||
d->ts=0;
|
||||
if (read_wav_header(d)!=0 && strstr(file,".wav")){
|
||||
ms_warning("File %s has .wav extension but wav header could be found.",file);
|
||||
}
|
||||
ms_filter_notify_no_arg(f,MS_FILTER_OUTPUT_FMT_CHANGED);
|
||||
ms_message("MSFilePlayer[%p]: %s opened: rate=%i,channel=%i",f,file,d->rate,d->nchannels);
|
||||
|
||||
if (d->state==MSPlayerPaused)
|
||||
d->state=MSPlayerPlaying;
|
||||
return;
|
||||
}
|
||||
|
||||
static void swap_bytes(unsigned char *bytes, int len){
|
||||
int i;
|
||||
unsigned char tmp;
|
||||
for(i=0;i<len;i+=2){
|
||||
tmp=bytes[i];
|
||||
bytes[i]=bytes[i+1];
|
||||
bytes[i+1]=tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_bypass_snd_read_process(MSFilter *f) {
|
||||
PlayerData *d=(PlayerData*)f->data;
|
||||
int nsamples=(f->ticker->interval*d->rate*d->nchannels)/1000;
|
||||
int bytes;
|
||||
/*send an even number of samples each tick. At 22050Hz the number of samples per 10 ms chunk is odd.
|
||||
Odd size buffer of samples cause troubles to alsa. Fixing in alsa is difficult, so workaround here.
|
||||
*/
|
||||
if (nsamples & 0x1 ) { //odd number of samples
|
||||
if (d->count & 0x1 )
|
||||
nsamples++;
|
||||
else
|
||||
nsamples--;
|
||||
}
|
||||
bytes=nsamples*d->samplesize;
|
||||
d->count++;
|
||||
ms_filter_lock(f);
|
||||
if (d->state==MSPlayerPlaying){
|
||||
{
|
||||
int err;
|
||||
mblk_t *om=allocb(bytes,0);
|
||||
if (d->pause_time>0){
|
||||
err=bytes;
|
||||
memset(om->b_wptr,0,bytes);
|
||||
d->pause_time-=f->ticker->interval;
|
||||
}else{
|
||||
err=read(d->fd,om->b_wptr,bytes);
|
||||
if (d->swap) swap_bytes(om->b_wptr,bytes);
|
||||
}
|
||||
if (err>=0){
|
||||
if (err!=0){
|
||||
if (err<bytes)
|
||||
memset(om->b_wptr+err,0,bytes-err);
|
||||
om->b_wptr+=bytes;
|
||||
mblk_set_timestamp_info(om,d->ts);
|
||||
d->ts+=nsamples;
|
||||
ms_queue_put(f->outputs[0],om);
|
||||
}else freemsg(om);
|
||||
if (err<bytes){
|
||||
ms_filter_notify_no_arg(f,MS_PLAYER_EOF);
|
||||
/*for compatibility:*/
|
||||
lseek(d->fd,d->hsize,SEEK_SET);
|
||||
|
||||
/* special value for playing file only once */
|
||||
if (d->loop_after<0)
|
||||
{
|
||||
d->state=MSPlayerPaused;
|
||||
ms_filter_unlock(f);
|
||||
return;
|
||||
}
|
||||
|
||||
if (d->loop_after>=0){
|
||||
d->pause_time=d->loop_after;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
ms_warning("Fail to read %i bytes: %s",bytes,strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
ms_filter_unlock(f);
|
||||
}
|
||||
|
||||
static void audio_bypass_snd_read_postprocess(MSFilter *f) {
|
||||
PlayerData *d=(PlayerData*)f->data;
|
||||
ms_filter_lock(f);
|
||||
if (d->state!=MSPlayerClosed){
|
||||
d->state=MSPlayerPaused;
|
||||
lseek(d->fd,d->hsize,SEEK_SET);
|
||||
}
|
||||
ms_filter_unlock(f);
|
||||
if (d->fd!=-1) close(d->fd);
|
||||
d->fd=-1;
|
||||
d->state=MSPlayerClosed;
|
||||
}
|
||||
|
||||
static void audio_bypass_snd_read_uninit(MSFilter *f) {
|
||||
PlayerData *d=(PlayerData*)f->data;
|
||||
ms_free(d);
|
||||
}
|
||||
|
||||
static int audio_bypass_snd_read_set_sample_rate(MSFilter *f, void *arg) { // This is to prevent ms2 to put a resampler between this filter and the rtpsend
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int audio_bypass_snd_read_set_nchannels(MSFilter *f, void *arg) { // This is to prevent ms2 to put a resampler between this filter and the rtpsend
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int audio_bypass_snd_read_get_sample_rate(MSFilter *f, void *arg) {
|
||||
int *sample_rate = (int *)arg;
|
||||
*sample_rate = 44100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int audio_bypass_snd_read_get_nchannels(MSFilter *f, void *arg) {
|
||||
int *nchannels = (int *)arg;
|
||||
*nchannels = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int audio_bypass_snd_read_get_fmt(MSFilter *f, void *arg) {
|
||||
MSPinFormat *pinFmt = (MSPinFormat *)arg;
|
||||
pinFmt->fmt = ms_factory_get_audio_format(f->factory, "L16", 44100, 1, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MSFilterMethod audio_bypass_snd_read_methods[] = {
|
||||
{ MS_FILTER_SET_SAMPLE_RATE, audio_bypass_snd_read_set_sample_rate },
|
||||
{ MS_FILTER_SET_NCHANNELS, audio_bypass_snd_read_set_nchannels },
|
||||
{ MS_FILTER_GET_SAMPLE_RATE, audio_bypass_snd_read_get_sample_rate },
|
||||
{ MS_FILTER_GET_NCHANNELS, audio_bypass_snd_read_get_nchannels },
|
||||
{ MS_FILTER_GET_OUTPUT_FMT, audio_bypass_snd_read_get_fmt },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
MSFilterDesc audio_bypass_snd_read_desc = {
|
||||
MS_FILTER_PLUGIN_ID,
|
||||
"AudioBypassReader",
|
||||
"audio bypass source",
|
||||
MS_FILTER_OTHER,
|
||||
NULL,
|
||||
0,
|
||||
1,
|
||||
audio_bypass_snd_read_init,
|
||||
audio_bypass_snd_read_preprocess,
|
||||
audio_bypass_snd_read_process,
|
||||
audio_bypass_snd_read_postprocess,
|
||||
audio_bypass_snd_read_uninit,
|
||||
audio_bypass_snd_read_methods
|
||||
};
|
||||
|
||||
static void audio_bypass_snd_write_init(MSFilter *f) {
|
||||
|
||||
}
|
||||
|
||||
static void audio_bypass_snd_write_preprocess(MSFilter *f) {
|
||||
|
||||
}
|
||||
|
||||
static void audio_bypass_snd_write_process(MSFilter *f) {
|
||||
mblk_t *m = ms_queue_get(f->inputs[0]);
|
||||
ms_free(m);
|
||||
}
|
||||
|
||||
static void audio_bypass_snd_write_postprocess(MSFilter *f) {
|
||||
|
||||
}
|
||||
|
||||
static void audio_bypass_snd_write_uninit(MSFilter *f) {
|
||||
|
||||
}
|
||||
|
||||
static int audio_bypass_snd_write_set_sample_rate(MSFilter *f, void *arg) { // This is to prevent ms2 to put a resampler between this filter and the rtprecv
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int audio_bypass_snd_write_set_nchannels(MSFilter *f, void *arg) { // This is to prevent ms2 to put a resampler between this filter and the rtprecv
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int audio_bypass_snd_write_get_sample_rate(MSFilter *f, void *arg) {
|
||||
int *sample_rate = (int*)arg;
|
||||
*sample_rate = 44100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int audio_bypass_snd_write_get_nchannels(MSFilter *obj, void *arg) {
|
||||
int *nchannels = (int*)arg;
|
||||
*nchannels = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int audio_bypass_snd_write_get_fmt(MSFilter *f, void *arg) {
|
||||
MSPinFormat *pinFmt = (MSPinFormat *)arg;
|
||||
pinFmt->fmt = ms_factory_get_audio_format(f->factory, "L16", 44100, 1, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MSFilterMethod audio_bypass_snd_write_methods[] = {
|
||||
{ MS_FILTER_SET_SAMPLE_RATE, audio_bypass_snd_write_set_sample_rate },
|
||||
{ MS_FILTER_SET_NCHANNELS, audio_bypass_snd_write_set_nchannels },
|
||||
{ MS_FILTER_GET_SAMPLE_RATE, audio_bypass_snd_write_get_sample_rate },
|
||||
{ MS_FILTER_GET_NCHANNELS, audio_bypass_snd_write_get_nchannels },
|
||||
{ MS_FILTER_GET_OUTPUT_FMT, audio_bypass_snd_write_get_fmt },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
MSFilterDesc audio_bypass_snd_write_desc = {
|
||||
MS_FILTER_PLUGIN_ID,
|
||||
"AudioBypassWriter",
|
||||
"audio bypass output",
|
||||
MS_FILTER_OTHER,
|
||||
NULL,
|
||||
1,
|
||||
0,
|
||||
audio_bypass_snd_write_init,
|
||||
audio_bypass_snd_write_preprocess,
|
||||
audio_bypass_snd_write_process,
|
||||
audio_bypass_snd_write_postprocess,
|
||||
audio_bypass_snd_write_uninit,
|
||||
audio_bypass_snd_write_methods
|
||||
};
|
||||
|
||||
static MSFilter* audio_bypass_snd_card_create_reader(MSSndCard *sndcard) {
|
||||
MSFactory *factory = ms_snd_card_get_factory(sndcard);
|
||||
MSFilter *f = ms_factory_create_filter_from_desc(factory, &audio_bypass_snd_read_desc);
|
||||
return f;
|
||||
}
|
||||
|
||||
static MSFilter* audio_bypass_snd_card_create_writer(MSSndCard *sndcard) {
|
||||
MSFactory *factory = ms_snd_card_get_factory(sndcard);
|
||||
MSFilter *f = ms_factory_create_filter_from_desc(factory, &audio_bypass_snd_write_desc);
|
||||
return f;
|
||||
}
|
||||
|
||||
static void audio_bypass_snd_card_detect(MSSndCardManager *m);
|
||||
|
||||
MSSndCardDesc audio_bypass_snd_card_desc = {
|
||||
"audioBypass",
|
||||
audio_bypass_snd_card_detect,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
audio_bypass_snd_card_create_reader,
|
||||
audio_bypass_snd_card_create_writer,
|
||||
NULL
|
||||
};
|
||||
|
||||
static MSSndCard* create_audio_bypass_snd_card(void) {
|
||||
MSSndCard* sndcard;
|
||||
sndcard = ms_snd_card_new(&audio_bypass_snd_card_desc);
|
||||
sndcard->data = NULL;
|
||||
sndcard->name = ms_strdup("audio bypass sound card");
|
||||
sndcard->capabilities = MS_SND_CARD_CAP_PLAYBACK | MS_SND_CARD_CAP_CAPTURE;
|
||||
sndcard->latency = 0;
|
||||
return sndcard;
|
||||
}
|
||||
|
||||
#define AUDIO_BYPASS_SOUNDCARD "audioBypass: audio bypass sound card"
|
||||
|
||||
static void audio_bypass_snd_card_detect(MSSndCardManager *m) {
|
||||
ms_snd_card_manager_add_card(m, create_audio_bypass_snd_card());
|
||||
}
|
||||
|
||||
static void only_enable_payload(LinphoneCore *lc, const char *mime, int rate, int channels) {
|
||||
const MSList *elem = linphone_core_get_audio_codecs(lc);
|
||||
PayloadType *pt;
|
||||
|
||||
for(; elem != NULL; elem = elem->next) {
|
||||
pt = (PayloadType *)elem->data;
|
||||
linphone_core_enable_payload_type(lc, pt, FALSE);
|
||||
}
|
||||
pt = linphone_core_find_payload_type(lc, mime, rate, channels);
|
||||
if (BC_ASSERT_PTR_NOT_NULL(pt)) {
|
||||
linphone_core_enable_payload_type(lc, pt, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_bypass(void) {
|
||||
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
|
||||
LinphoneCore *marie_lc = marie->lc;
|
||||
MSFactory *marie_factory = linphone_core_get_ms_factory(marie_lc);
|
||||
MSSndCardManager *marie_sndcard_manager = ms_factory_get_snd_card_manager(marie_factory);
|
||||
|
||||
LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc");
|
||||
LinphoneCore *pauline_lc = pauline->lc;
|
||||
MSFactory *pauline_factory = linphone_core_get_ms_factory(pauline_lc);
|
||||
MSSndCardManager *pauline_sndcard_manager = ms_factory_get_snd_card_manager(pauline_factory);
|
||||
|
||||
bool_t call_ok;
|
||||
char *hellopath = bc_tester_res("sounds/hello44100.wav");
|
||||
char *recordpath = bc_tester_file("audiobypass-record.wav");
|
||||
double similar=1;
|
||||
const double threshold = 0.85;
|
||||
|
||||
lp_config_set_string(marie_lc->config, "sound", "features", "None");
|
||||
lp_config_set_string(pauline_lc->config, "sound", "features", "None");
|
||||
|
||||
/*make sure the record file doesn't already exists, otherwise this test will append new samples to it*/
|
||||
unlink(recordpath);
|
||||
|
||||
// Enable L16 audio codec
|
||||
only_enable_payload(marie_lc, "L16", 44100, 1);
|
||||
only_enable_payload(pauline_lc, "L16", 44100, 1);
|
||||
|
||||
// Add our custom sound card
|
||||
ms_snd_card_manager_register_desc(marie_sndcard_manager, &audio_bypass_snd_card_desc);
|
||||
ms_snd_card_manager_register_desc(pauline_sndcard_manager, &audio_bypass_snd_card_desc);
|
||||
linphone_core_reload_sound_devices(marie_lc);
|
||||
linphone_core_reload_sound_devices(pauline_lc);
|
||||
linphone_core_set_playback_device(marie_lc, AUDIO_BYPASS_SOUNDCARD);
|
||||
linphone_core_set_playback_device(pauline_lc, AUDIO_BYPASS_SOUNDCARD);
|
||||
linphone_core_set_capture_device(marie_lc, AUDIO_BYPASS_SOUNDCARD);
|
||||
linphone_core_set_capture_device(pauline_lc, AUDIO_BYPASS_SOUNDCARD);
|
||||
BC_ASSERT_STRING_EQUAL(linphone_core_get_capture_device(marie_lc), AUDIO_BYPASS_SOUNDCARD);
|
||||
BC_ASSERT_STRING_EQUAL(linphone_core_get_capture_device(pauline_lc), AUDIO_BYPASS_SOUNDCARD);
|
||||
BC_ASSERT_STRING_EQUAL(linphone_core_get_playback_device(marie_lc), AUDIO_BYPASS_SOUNDCARD);
|
||||
BC_ASSERT_STRING_EQUAL(linphone_core_get_playback_device(pauline_lc), AUDIO_BYPASS_SOUNDCARD);
|
||||
|
||||
linphone_core_use_files(pauline_lc, TRUE);
|
||||
linphone_core_set_play_file(pauline_lc, NULL);
|
||||
linphone_core_set_record_file(pauline_lc, recordpath);
|
||||
|
||||
call_ok = call(marie, pauline);
|
||||
BC_ASSERT_TRUE(call_ok);
|
||||
if (!call_ok) goto end;
|
||||
|
||||
BC_ASSERT_STRING_EQUAL(linphone_call_params_get_used_audio_codec(linphone_call_get_current_params(linphone_core_get_current_call(marie_lc)))->mime_type, "L16");
|
||||
|
||||
wait_for_until(pauline_lc, marie_lc, NULL, 0, 22000); //hello44100.wav is 22 seconds long
|
||||
end_call(marie, pauline);
|
||||
|
||||
BC_ASSERT_EQUAL(ms_audio_diff(hellopath, recordpath, &similar, &audio_cmp_params, NULL, NULL), 0, int, "%d");
|
||||
BC_ASSERT_GREATER(similar, threshold, double, "%g");
|
||||
BC_ASSERT_LOWER(similar, 1.0, double, "%g");
|
||||
|
||||
end:
|
||||
bc_free(recordpath);
|
||||
bc_free(hellopath);
|
||||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
}
|
||||
|
||||
test_t audio_bypass_tests[] = {
|
||||
TEST_NO_TAG("Audio Bypass", audio_bypass)
|
||||
};
|
||||
|
||||
test_suite_t audio_bypass_suite = { "Audio Bypass", NULL, NULL,
|
||||
liblinphone_tester_before_each, liblinphone_tester_after_each,
|
||||
sizeof(audio_bypass_tests) / sizeof(audio_bypass_tests[0]), audio_bypass_tests };
|
||||
139
tester/audio_bypass_wav_header.h
Normal file
139
tester/audio_bypass_wav_header.h
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
mediastreamer2 library - modular sound and video processing and streaming
|
||||
Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef waveheader_h
|
||||
#define waveheader_h
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <io.h>
|
||||
# ifndef R_OK
|
||||
# define R_OK 0x2
|
||||
# endif
|
||||
# ifndef W_OK
|
||||
# define W_OK 0x6
|
||||
# endif
|
||||
# ifndef F_OK
|
||||
# define F_OK 0x0
|
||||
# endif
|
||||
|
||||
# ifndef S_IRUSR
|
||||
# define S_IRUSR S_IREAD
|
||||
# endif
|
||||
|
||||
# ifndef S_IWUSR
|
||||
# define S_IWUSR S_IWRITE
|
||||
# endif
|
||||
|
||||
# define open _open
|
||||
# define read _read
|
||||
# define write _write
|
||||
# define close _close
|
||||
# define access _access
|
||||
# define lseek _lseek
|
||||
#else /*_WIN32*/
|
||||
|
||||
# ifndef O_BINARY
|
||||
# define O_BINARY 0
|
||||
# endif
|
||||
|
||||
#endif /*!_WIN32*/
|
||||
|
||||
#ifdef swap16
|
||||
#else
|
||||
/* all integer in wav header must be read in least endian order */
|
||||
static MS2_INLINE uint16_t swap16(uint16_t a)
|
||||
{
|
||||
return ((a & 0xFF) << 8) | ((a & 0xFF00) >> 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef swap32
|
||||
#else
|
||||
static MS2_INLINE uint32_t swap32(uint32_t a)
|
||||
{
|
||||
return ((a & 0xFF) << 24) | ((a & 0xFF00) << 8) |
|
||||
((a & 0xFF0000) >> 8) | ((a & 0xFF000000) >> 24);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define le_uint32(a) (swap32((a)))
|
||||
#define le_uint16(a) (swap16((a)))
|
||||
#define le_int16(a) ( (int16_t) swap16((uint16_t)((a))) )
|
||||
#else
|
||||
#define le_uint32(a) (a)
|
||||
#define le_uint16(a) (a)
|
||||
#define le_int16(a) (a)
|
||||
#endif
|
||||
|
||||
typedef struct _riff_t {
|
||||
char riff[4] ; /* "RIFF" (ASCII characters) */
|
||||
uint32_t len ; /* Length of package (binary, little endian) */
|
||||
char wave[4] ; /* "WAVE" (ASCII characters) */
|
||||
} riff_t;
|
||||
|
||||
/* The FORMAT chunk */
|
||||
|
||||
typedef struct _format_t {
|
||||
char fmt[4] ; /* "fmt_" (ASCII characters) */
|
||||
uint32_t len ; /* length of FORMAT chunk (always 0x10) */
|
||||
uint16_t type; /* codec type*/
|
||||
uint16_t channel ; /* Channel numbers (0x01 = mono, 0x02 = stereo) */
|
||||
uint32_t rate ; /* Sample rate (binary, in Hz) */
|
||||
uint32_t bps ; /* Average Bytes Per Second */
|
||||
uint16_t blockalign ; /*number of bytes per sample */
|
||||
uint16_t bitpspl ; /* bits per sample */
|
||||
} format_t;
|
||||
|
||||
/* The DATA chunk */
|
||||
|
||||
typedef struct _data_t {
|
||||
char data[4] ; /* "data" (ASCII characters) */
|
||||
uint32_t len ; /* length of data */
|
||||
} data_t;
|
||||
|
||||
typedef struct _wave_header_t
|
||||
{
|
||||
riff_t riff_chunk;
|
||||
format_t format_chunk;
|
||||
data_t data_chunk;
|
||||
} wave_header_t;
|
||||
|
||||
#ifndef _WIN32
|
||||
#define WAVE_FORMAT_PCM 0x0001
|
||||
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
|
||||
#define WAVE_FORMAT_ALAW 0x0006
|
||||
#define WAVE_FORMAT_MULAW 0x0007
|
||||
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
|
||||
#endif
|
||||
|
||||
#define wave_header_get_format_type(header) le_uint16((header)->format_chunk.type)
|
||||
#define wave_header_get_rate(header) le_uint32((header)->format_chunk.rate)
|
||||
#define wave_header_get_channel(header) le_uint16((header)->format_chunk.channel)
|
||||
#define wave_header_get_bpsmpl(header) \
|
||||
le_uint16((header)->format_chunk.blockalign)
|
||||
|
||||
int ms_read_wav_header_from_fd(wave_header_t *header,int fd);
|
||||
|
||||
#endif
|
||||
|
|
@ -61,6 +61,7 @@ extern test_suite_t multicast_call_test_suite;
|
|||
extern test_suite_t multi_call_test_suite;
|
||||
extern test_suite_t proxy_config_test_suite;
|
||||
extern test_suite_t vcard_test_suite;
|
||||
extern test_suite_t audio_bypass_suite;
|
||||
#if HAVE_SIPP
|
||||
extern test_suite_t complex_sip_call_test_suite;
|
||||
#endif
|
||||
|
|
|
|||
BIN
tester/sounds/hello44100.wav
Normal file
BIN
tester/sounds/hello44100.wav
Normal file
Binary file not shown.
|
|
@ -480,6 +480,7 @@ void liblinphone_tester_add_suites() {
|
|||
bc_tester_add_suite(&tunnel_test_suite);
|
||||
bc_tester_add_suite(&offeranswer_test_suite);
|
||||
bc_tester_add_suite(&call_test_suite);
|
||||
bc_tester_add_suite(&audio_bypass_suite);
|
||||
bc_tester_add_suite(&multi_call_test_suite);
|
||||
bc_tester_add_suite(&message_test_suite);
|
||||
bc_tester_add_suite(&presence_test_suite);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue