Commit 0e62557b authored by Ghislain MARY's avatar Ghislain MARY
Browse files

Handle conversion from mono to stereo and from stereo to mono in the resample filter.

parent c7385b2e
...@@ -580,7 +580,8 @@ typedef enum _MSFilterInterfaceId MSFilterInterfaceId; ...@@ -580,7 +580,8 @@ typedef enum _MSFilterInterfaceId MSFilterInterfaceId;
#define MS_FILTER_SET_MAX_GAIN MS_FILTER_BASE_METHOD(25,int) #define MS_FILTER_SET_MAX_GAIN MS_FILTER_BASE_METHOD(25,int)
#define MS_VIDEO_CAPTURE_SET_AUTOFOCUS MS_FILTER_BASE_METHOD(26,int) #define MS_VIDEO_CAPTURE_SET_AUTOFOCUS MS_FILTER_BASE_METHOD(26,int)
/* pass value of type MSRtpPayloadPickerContext copied by the filter*/ /* pass value of type MSRtpPayloadPickerContext copied by the filter*/
#define MS_FILTER_SET_RTP_PAYLOAD_PICKER MS_FILTER_BASE_METHOD(27,void*) #define MS_FILTER_SET_RTP_PAYLOAD_PICKER MS_FILTER_BASE_METHOD(27,void*)
#define MS_FILTER_SET_OUTPUT_NCHANNELS MS_FILTER_BASE_METHOD(28,int)
#define MS_CONF_SPEEX_PREPROCESS_MIC MS_FILTER_EVENT(MS_CONF_ID, 1, void*) #define MS_CONF_SPEEX_PREPROCESS_MIC MS_FILTER_EVENT(MS_CONF_ID, 1, void*)
#define MS_CONF_CHANNEL_VOLUME MS_FILTER_EVENT(MS_CONF_ID, 3, void*) #define MS_CONF_CHANNEL_VOLUME MS_FILTER_EVENT(MS_CONF_ID, 3, void*)
......
...@@ -116,12 +116,17 @@ bool_t ms_is_ipv6(const char *remote){ ...@@ -116,12 +116,17 @@ bool_t ms_is_ipv6(const char *remote){
static void audio_stream_configure_resampler(MSFilter *resampler,MSFilter *from,MSFilter *to) { static void audio_stream_configure_resampler(MSFilter *resampler,MSFilter *from,MSFilter *to) {
int from_rate=0, to_rate=0; int from_rate=0, to_rate=0;
int from_channels = 0, to_channels = 0;
ms_filter_call_method(from,MS_FILTER_GET_SAMPLE_RATE,&from_rate); ms_filter_call_method(from,MS_FILTER_GET_SAMPLE_RATE,&from_rate);
ms_filter_call_method(to,MS_FILTER_GET_SAMPLE_RATE,&to_rate); ms_filter_call_method(to,MS_FILTER_GET_SAMPLE_RATE,&to_rate);
ms_filter_call_method(resampler,MS_FILTER_SET_SAMPLE_RATE,&from_rate); ms_filter_call_method(resampler,MS_FILTER_SET_SAMPLE_RATE,&from_rate);
ms_filter_call_method(resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&to_rate); ms_filter_call_method(resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&to_rate);
ms_message("configuring %s-->%s from rate[%i] to rate [%i]", ms_filter_call_method(from, MS_FILTER_GET_NCHANNELS, &from_channels);
from->desc->name, to->desc->name, from_rate,to_rate); ms_filter_call_method(to, MS_FILTER_GET_NCHANNELS, &to_channels);
ms_filter_call_method(resampler, MS_FILTER_SET_NCHANNELS, &from_channels);
ms_filter_call_method(resampler, MS_FILTER_SET_OUTPUT_NCHANNELS, &to_channels);
ms_message("configuring %s-->%s from rate [%i] to rate [%i] and from channel [%i] to channel [%i]",
from->desc->name, to->desc->name, from_rate, to_rate, from_channels, to_channels);
} }
static void disable_checksums(ortp_socket_t sock){ static void disable_checksums(ortp_socket_t sock){
...@@ -514,6 +519,8 @@ int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char ...@@ -514,6 +519,8 @@ int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char
} }
/*configure resampler if needed*/ /*configure resampler if needed*/
ms_filter_call_method(stream->rtpsend, MS_FILTER_SET_NCHANNELS, &pt->channels);
ms_filter_call_method(stream->rtprecv, MS_FILTER_SET_NCHANNELS, &pt->channels);
if (stream->read_resampler){ if (stream->read_resampler){
audio_stream_configure_resampler(stream->read_resampler,stream->soundread,stream->rtpsend); audio_stream_configure_resampler(stream->read_resampler,stream->soundread,stream->rtpsend);
} }
......
...@@ -35,7 +35,8 @@ typedef struct _ResampleData{ ...@@ -35,7 +35,8 @@ typedef struct _ResampleData{
uint32_t ts; uint32_t ts;
uint32_t input_rate; uint32_t input_rate;
uint32_t output_rate; uint32_t output_rate;
int nchannels; int in_nchannels;
int out_nchannels;
SpeexResamplerState *handle; SpeexResamplerState *handle;
} ResampleData; } ResampleData;
...@@ -46,7 +47,7 @@ static ResampleData * resample_data_new(){ ...@@ -46,7 +47,7 @@ static ResampleData * resample_data_new(){
obj->input_rate=8000; obj->input_rate=8000;
obj->output_rate=16000; obj->output_rate=16000;
obj->handle=NULL; obj->handle=NULL;
obj->nchannels=1; obj->in_nchannels=obj->out_nchannels=1;
return obj; return obj;
} }
...@@ -83,13 +84,38 @@ static void resample_uninit(MSFilter *obj){ ...@@ -83,13 +84,38 @@ static void resample_uninit(MSFilter *obj){
resample_data_destroy((ResampleData*)obj->data); resample_data_destroy((ResampleData*)obj->data);
} }
static int resample_channel_adapt(int in_nchannels, int out_nchannels, mblk_t *im, mblk_t **om) {
if ((in_nchannels == 2) && (out_nchannels == 1)) {
int msgsize = msgdsize(im) / 2;
*om = allocb(msgsize, 0);
for (; im->b_rptr < im->b_wptr; im->b_rptr += 4, (*om)->b_wptr += 2) {
*(int16_t *)(*om)->b_wptr = *(int16_t *)im->b_rptr;
}
return 1;
} else if ((in_nchannels == 1) && (out_nchannels == 2)) {
int msgsize = msgdsize(im) * 2;
*om = allocb(msgsize, 0);
for (; im->b_rptr < im->b_wptr; im->b_rptr += 2, (*om)->b_wptr += 4) {
((int16_t *)(*om)->b_wptr)[0] = *(int16_t *)im->b_rptr;
((int16_t *)(*om)->b_wptr)[1] = *(int16_t *)im->b_rptr;
}
return 1;
}
return 0;
}
static void resample_process_ms2(MSFilter *obj){ static void resample_process_ms2(MSFilter *obj){
ResampleData *dt=(ResampleData*)obj->data; ResampleData *dt=(ResampleData*)obj->data;
mblk_t *m; mblk_t *im, *om = NULL, *om_chan = NULL;
if (dt->output_rate==dt->input_rate){ if (dt->output_rate==dt->input_rate){
while((m=ms_queue_get(obj->inputs[0]))!=NULL){ while((im=ms_queue_get(obj->inputs[0]))!=NULL){
ms_queue_put(obj->outputs[0],m); if (resample_channel_adapt(dt->in_nchannels, dt->out_nchannels, im, &om) == 0) {
ms_queue_put(obj->outputs[0], im);
} else {
ms_queue_put(obj->outputs[0], om);
freemsg(im);
}
} }
return; return;
} }
...@@ -104,26 +130,26 @@ static void resample_process_ms2(MSFilter *obj){ ...@@ -104,26 +130,26 @@ static void resample_process_ms2(MSFilter *obj){
} }
if (dt->handle==NULL){ if (dt->handle==NULL){
int err=0; int err=0;
dt->handle=speex_resampler_init(dt->nchannels, dt->input_rate, dt->output_rate, SPEEX_RESAMPLER_QUALITY_VOIP, &err); dt->handle=speex_resampler_init(dt->in_nchannels, dt->input_rate, dt->output_rate, SPEEX_RESAMPLER_QUALITY_VOIP, &err);
} }
while((m=ms_queue_get(obj->inputs[0]))!=NULL){ while((im=ms_queue_get(obj->inputs[0]))!=NULL){
unsigned int inlen=(m->b_wptr-m->b_rptr)/(2*dt->nchannels); unsigned int inlen=(im->b_wptr-im->b_rptr)/(2*dt->in_nchannels);
unsigned int outlen=((inlen*dt->output_rate)/dt->input_rate)+1; unsigned int outlen=((inlen*dt->output_rate)/dt->input_rate)+1;
unsigned int inlen_orig=inlen; unsigned int inlen_orig=inlen;
mblk_t *om=allocb(outlen*2*dt->nchannels,0); om=allocb(outlen*2*dt->in_nchannels,0);
mblk_meta_copy(m, om); mblk_meta_copy(im, om);
if (dt->nchannels==1){ if (dt->in_nchannels==1){
speex_resampler_process_int(dt->handle, speex_resampler_process_int(dt->handle,
0, 0,
(int16_t*)m->b_rptr, (int16_t*)im->b_rptr,
&inlen, &inlen,
(int16_t*)om->b_wptr, (int16_t*)om->b_wptr,
&outlen); &outlen);
}else{ }else{
speex_resampler_process_interleaved_int(dt->handle, speex_resampler_process_interleaved_int(dt->handle,
(int16_t*)m->b_rptr, (int16_t*)im->b_rptr,
&inlen, &inlen,
(int16_t*)om->b_wptr, (int16_t*)om->b_wptr,
&outlen); &outlen);
...@@ -132,11 +158,16 @@ static void resample_process_ms2(MSFilter *obj){ ...@@ -132,11 +158,16 @@ static void resample_process_ms2(MSFilter *obj){
ms_error("Bug in resampler ! only %u samples consumed instead of %u, out=%u", ms_error("Bug in resampler ! only %u samples consumed instead of %u, out=%u",
inlen,inlen_orig,outlen); inlen,inlen_orig,outlen);
} }
om->b_wptr+=outlen*2*dt->nchannels; om->b_wptr+=outlen*2*dt->in_nchannels;
mblk_set_timestamp_info(om,dt->ts); mblk_set_timestamp_info(om,dt->ts);
dt->ts+=outlen; dt->ts+=outlen;
ms_queue_put(obj->outputs[0],om); if (resample_channel_adapt(dt->in_nchannels, dt->out_nchannels, om, &om_chan) == 0) {
freemsg(m); ms_queue_put(obj->outputs[0], om);
} else {
ms_queue_put(obj->outputs[0], om_chan);
freemsg(om);
}
freemsg(im);
} }
ms_filter_unlock(obj); ms_filter_unlock(obj);
} }
...@@ -154,15 +185,28 @@ static int ms_resample_set_output_sr(MSFilter *obj, void *arg){ ...@@ -154,15 +185,28 @@ static int ms_resample_set_output_sr(MSFilter *obj, void *arg){
return 0; return 0;
} }
static int set_nchannels(MSFilter *f, void *arg){ static int set_input_nchannels(MSFilter *f, void *arg){
ResampleData *dt=(ResampleData*)f->data; ResampleData *dt=(ResampleData*)f->data;
int chans=*(int*)arg; int chans=*(int*)arg;
ms_filter_lock(f); ms_filter_lock(f);
if (dt->nchannels!=chans && dt->handle!=NULL){ if (dt->in_nchannels!=chans && dt->handle!=NULL){
speex_resampler_destroy(dt->handle); speex_resampler_destroy(dt->handle);
dt->handle=NULL; dt->handle=NULL;
} }
dt->nchannels=*(int*)arg; dt->in_nchannels=chans;
ms_filter_unlock(f);
return 0;
}
static int set_output_nchannels(MSFilter *f, void *arg) {
ResampleData *dt = (ResampleData *)f->data;
int chans = *(int *)arg;
ms_filter_lock(f);
if (dt->out_nchannels != chans && dt->handle != NULL) {
speex_resampler_destroy(dt->handle);
dt->handle = NULL;
}
dt->out_nchannels = chans;
ms_filter_unlock(f); ms_filter_unlock(f);
return 0; return 0;
} }
...@@ -170,7 +214,8 @@ static int set_nchannels(MSFilter *f, void *arg){ ...@@ -170,7 +214,8 @@ static int set_nchannels(MSFilter *f, void *arg){
static MSFilterMethod methods[]={ static MSFilterMethod methods[]={
{ MS_FILTER_SET_SAMPLE_RATE , ms_resample_set_sr }, { MS_FILTER_SET_SAMPLE_RATE , ms_resample_set_sr },
{ MS_FILTER_SET_OUTPUT_SAMPLE_RATE , ms_resample_set_output_sr }, { MS_FILTER_SET_OUTPUT_SAMPLE_RATE , ms_resample_set_output_sr },
{ MS_FILTER_SET_NCHANNELS, set_nchannels }, { MS_FILTER_SET_NCHANNELS, set_input_nchannels },
{ MS_FILTER_SET_OUTPUT_NCHANNELS, set_output_nchannels },
{ 0 , NULL } { 0 , NULL }
}; };
......
...@@ -36,6 +36,7 @@ struct SenderData { ...@@ -36,6 +36,7 @@ struct SenderData {
int64_t last_sent_time; int64_t last_sent_time;
uint32_t skip_until; uint32_t skip_until;
int rate; int rate;
int nchannels;
int dtmf_duration; int dtmf_duration;
int dtmf_ts_step; int dtmf_ts_step;
uint32_t dtmf_ts_cur; uint32_t dtmf_ts_cur;
...@@ -59,6 +60,7 @@ static void sender_init(MSFilter * f) ...@@ -59,6 +60,7 @@ static void sender_init(MSFilter * f)
d->skip_until = 0; d->skip_until = 0;
d->skip = FALSE; d->skip = FALSE;
d->rate = 8000; d->rate = 8000;
d->nchannels = 1;
d->dtmf = 0; d->dtmf = 0;
d->dtmf_start = FALSE; d->dtmf_start = FALSE;
d->dtmf_duration = 800; d->dtmf_duration = 800;
...@@ -166,6 +168,18 @@ static int sender_get_sr(MSFilter *f, void *arg){ ...@@ -166,6 +168,18 @@ static int sender_get_sr(MSFilter *f, void *arg){
return 0; return 0;
} }
static int sender_get_ch(MSFilter *f, void *arg) {
SenderData *d = (SenderData *)f->data;
*(int *)arg = d->nchannels;
return 0;
}
static int sender_set_ch(MSFilter *f, void *arg) {
SenderData *d = (SenderData *)f->data;
d->nchannels = *(int *)arg;
return 0;
}
/* the goal of that function is to return a absolute timestamp closest to real time, with respect of given packet_ts, which is a relative to an undefined origin*/ /* the goal of that function is to return a absolute timestamp closest to real time, with respect of given packet_ts, which is a relative to an undefined origin*/
static uint32_t get_cur_timestamp(MSFilter * f, mblk_t *im) static uint32_t get_cur_timestamp(MSFilter * f, mblk_t *im)
{ {
...@@ -365,6 +379,8 @@ static MSFilterMethod sender_methods[] = { ...@@ -365,6 +379,8 @@ static MSFilterMethod sender_methods[] = {
{MS_RTP_SEND_SEND_DTMF, sender_send_dtmf}, {MS_RTP_SEND_SEND_DTMF, sender_send_dtmf},
{MS_RTP_SEND_SET_RELAY_SESSION_ID, sender_set_relay_session_id}, {MS_RTP_SEND_SET_RELAY_SESSION_ID, sender_set_relay_session_id},
{MS_FILTER_GET_SAMPLE_RATE, sender_get_sr }, {MS_FILTER_GET_SAMPLE_RATE, sender_get_sr },
{MS_FILTER_GET_NCHANNELS, sender_get_ch },
{MS_FILTER_SET_NCHANNELS, sender_set_ch },
{MS_RTP_SEND_SET_DTMF_DURATION, sender_set_dtmf_duration }, {MS_RTP_SEND_SET_DTMF_DURATION, sender_set_dtmf_duration },
{0, NULL} {0, NULL}
}; };
...@@ -409,6 +425,7 @@ MSFilterDesc ms_rtp_send_desc = { ...@@ -409,6 +425,7 @@ MSFilterDesc ms_rtp_send_desc = {
struct ReceiverData { struct ReceiverData {
RtpSession *session; RtpSession *session;
int rate; int rate;
int nchannels;
bool_t starting; bool_t starting;
}; };
...@@ -419,6 +436,7 @@ static void receiver_init(MSFilter * f) ...@@ -419,6 +436,7 @@ static void receiver_init(MSFilter * f)
ReceiverData *d = (ReceiverData *)ms_new(ReceiverData, 1); ReceiverData *d = (ReceiverData *)ms_new(ReceiverData, 1);
d->session = NULL; d->session = NULL;
d->rate = 8000; d->rate = 8000;
d->nchannels = 1;
f->data = d; f->data = d;
} }
...@@ -470,6 +488,18 @@ static int receiver_get_sr(MSFilter *f, void *arg){ ...@@ -470,6 +488,18 @@ static int receiver_get_sr(MSFilter *f, void *arg){
return 0; return 0;
} }
static int receiver_get_ch(MSFilter *f, void *arg) {
ReceiverData *d = (ReceiverData *)f->data;
*(int *)arg = d->nchannels;
return 0;
}
static int receiver_set_ch(MSFilter *f, void *arg) {
ReceiverData *d = (ReceiverData *)f->data;
d->nchannels = *(int *)arg;
return 0;
}
static void receiver_preprocess(MSFilter * f){ static void receiver_preprocess(MSFilter * f){
ReceiverData *d = (ReceiverData *) f->data; ReceiverData *d = (ReceiverData *) f->data;
d->starting=TRUE; d->starting=TRUE;
...@@ -506,6 +536,8 @@ static void receiver_process(MSFilter * f) ...@@ -506,6 +536,8 @@ static void receiver_process(MSFilter * f)
static MSFilterMethod receiver_methods[] = { static MSFilterMethod receiver_methods[] = {
{ MS_RTP_RECV_SET_SESSION , receiver_set_session }, { MS_RTP_RECV_SET_SESSION , receiver_set_session },
{ MS_FILTER_GET_SAMPLE_RATE , receiver_get_sr }, { MS_FILTER_GET_SAMPLE_RATE , receiver_get_sr },
{ MS_FILTER_GET_NCHANNELS , receiver_get_ch },
{ MS_FILTER_SET_NCHANNELS , receiver_set_ch },
{ 0, NULL} { 0, NULL}
}; };
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment