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

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;
#define MS_FILTER_SET_MAX_GAIN MS_FILTER_BASE_METHOD(25,int)
#define MS_VIDEO_CAPTURE_SET_AUTOFOCUS MS_FILTER_BASE_METHOD(26,int)
/* 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_CHANNEL_VOLUME MS_FILTER_EVENT(MS_CONF_ID, 3, void*)
......
......@@ -116,12 +116,17 @@ bool_t ms_is_ipv6(const char *remote){
static void audio_stream_configure_resampler(MSFilter *resampler,MSFilter *from,MSFilter *to) {
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(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_OUTPUT_SAMPLE_RATE,&to_rate);
ms_message("configuring %s-->%s from rate[%i] to rate [%i]",
from->desc->name, to->desc->name, from_rate,to_rate);
ms_filter_call_method(from, MS_FILTER_GET_NCHANNELS, &from_channels);
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){
......@@ -514,6 +519,8 @@ int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char
}
/*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){
audio_stream_configure_resampler(stream->read_resampler,stream->soundread,stream->rtpsend);
}
......
......@@ -35,7 +35,8 @@ typedef struct _ResampleData{
uint32_t ts;
uint32_t input_rate;
uint32_t output_rate;
int nchannels;
int in_nchannels;
int out_nchannels;
SpeexResamplerState *handle;
} ResampleData;
......@@ -46,7 +47,7 @@ static ResampleData * resample_data_new(){
obj->input_rate=8000;
obj->output_rate=16000;
obj->handle=NULL;
obj->nchannels=1;
obj->in_nchannels=obj->out_nchannels=1;
return obj;
}
......@@ -83,13 +84,38 @@ static void resample_uninit(MSFilter *obj){
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){
ResampleData *dt=(ResampleData*)obj->data;
mblk_t *m;
mblk_t *im, *om = NULL, *om_chan = NULL;
if (dt->output_rate==dt->input_rate){
while((m=ms_queue_get(obj->inputs[0]))!=NULL){
ms_queue_put(obj->outputs[0],m);
while((im=ms_queue_get(obj->inputs[0]))!=NULL){
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;
}
......@@ -104,26 +130,26 @@ static void resample_process_ms2(MSFilter *obj){
}
if (dt->handle==NULL){
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){
unsigned int inlen=(m->b_wptr-m->b_rptr)/(2*dt->nchannels);
while((im=ms_queue_get(obj->inputs[0]))!=NULL){
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 inlen_orig=inlen;
mblk_t *om=allocb(outlen*2*dt->nchannels,0);
mblk_meta_copy(m, om);
if (dt->nchannels==1){
om=allocb(outlen*2*dt->in_nchannels,0);
mblk_meta_copy(im, om);
if (dt->in_nchannels==1){
speex_resampler_process_int(dt->handle,
0,
(int16_t*)m->b_rptr,
(int16_t*)im->b_rptr,
&inlen,
(int16_t*)om->b_wptr,
&outlen);
}else{
speex_resampler_process_interleaved_int(dt->handle,
(int16_t*)m->b_rptr,
(int16_t*)im->b_rptr,
&inlen,
(int16_t*)om->b_wptr,
&outlen);
......@@ -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",
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);
dt->ts+=outlen;
ms_queue_put(obj->outputs[0],om);
freemsg(m);
if (resample_channel_adapt(dt->in_nchannels, dt->out_nchannels, om, &om_chan) == 0) {
ms_queue_put(obj->outputs[0], om);
} else {
ms_queue_put(obj->outputs[0], om_chan);
freemsg(om);
}
freemsg(im);
}
ms_filter_unlock(obj);
}
......@@ -154,15 +185,28 @@ static int ms_resample_set_output_sr(MSFilter *obj, void *arg){
return 0;
}
static int set_nchannels(MSFilter *f, void *arg){
static int set_input_nchannels(MSFilter *f, void *arg){
ResampleData *dt=(ResampleData*)f->data;
int chans=*(int*)arg;
ms_filter_lock(f);
if (dt->nchannels!=chans && dt->handle!=NULL){
if (dt->in_nchannels!=chans && dt->handle!=NULL){
speex_resampler_destroy(dt->handle);
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);
return 0;
}
......@@ -170,7 +214,8 @@ static int set_nchannels(MSFilter *f, void *arg){
static MSFilterMethod methods[]={
{ MS_FILTER_SET_SAMPLE_RATE , ms_resample_set_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 }
};
......
......@@ -36,6 +36,7 @@ struct SenderData {
int64_t last_sent_time;
uint32_t skip_until;
int rate;
int nchannels;
int dtmf_duration;
int dtmf_ts_step;
uint32_t dtmf_ts_cur;
......@@ -59,6 +60,7 @@ static void sender_init(MSFilter * f)
d->skip_until = 0;
d->skip = FALSE;
d->rate = 8000;
d->nchannels = 1;
d->dtmf = 0;
d->dtmf_start = FALSE;
d->dtmf_duration = 800;
......@@ -166,6 +168,18 @@ static int sender_get_sr(MSFilter *f, void *arg){
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*/
static uint32_t get_cur_timestamp(MSFilter * f, mblk_t *im)
{
......@@ -365,6 +379,8 @@ static MSFilterMethod sender_methods[] = {
{MS_RTP_SEND_SEND_DTMF, sender_send_dtmf},
{MS_RTP_SEND_SET_RELAY_SESSION_ID, sender_set_relay_session_id},
{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 },
{0, NULL}
};
......@@ -409,6 +425,7 @@ MSFilterDesc ms_rtp_send_desc = {
struct ReceiverData {
RtpSession *session;
int rate;
int nchannels;
bool_t starting;
};
......@@ -419,6 +436,7 @@ static void receiver_init(MSFilter * f)
ReceiverData *d = (ReceiverData *)ms_new(ReceiverData, 1);
d->session = NULL;
d->rate = 8000;
d->nchannels = 1;
f->data = d;
}
......@@ -470,6 +488,18 @@ static int receiver_get_sr(MSFilter *f, void *arg){
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){
ReceiverData *d = (ReceiverData *) f->data;
d->starting=TRUE;
......@@ -506,6 +536,8 @@ static void receiver_process(MSFilter * f)
static MSFilterMethod receiver_methods[] = {
{ MS_RTP_RECV_SET_SESSION , receiver_set_session },
{ MS_FILTER_GET_SAMPLE_RATE , receiver_get_sr },
{ MS_FILTER_GET_NCHANNELS , receiver_get_ch },
{ MS_FILTER_SET_NCHANNELS , receiver_set_ch },
{ 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