Commit 982f6628 authored by Simon Morlat's avatar Simon Morlat

added an event queue to trigger filter's notification using the application...

added an event queue to trigger filter's notification using the application own thread (instead of MSTicker previously)
parent 91bf54ac
......@@ -5,6 +5,7 @@ mediastreamer2_include_HEADERS= ice.h \
msfilter.h \
msqueue.h \
mscommon.h \
mseventqueue.h \
allfilters.h \
msticker.h \
msrtp.h \
......@@ -26,7 +27,8 @@ mediastreamer2_include_HEADERS= ice.h \
msspeexec.h \
msinterfaces.h \
mschanadapter.h \
msaudiomixer.h
msaudiomixer.h \
msitc.h
EXTRA_DIST=$(mediastreamer2_include_HEADERS)
......@@ -93,7 +93,9 @@ typedef enum MSFilterId{
MS_PULSE_WRITE_ID,
MS_DRAWDIB_DISPLAY_ID,
MS_CHANNEL_ADAPTER_ID,
MS_AUDIO_MIXER_ID
MS_AUDIO_MIXER_ID,
MS_ITC_SINK_ID,
MS_ITC_SOURCE_ID
} MSFilterId;
......
......@@ -16,8 +16,8 @@ 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 mstee_h
#define mstee_h
#ifndef msaudiomixer_h
#define msaudiomixer_h
#include "msfilter.h"
......
......@@ -169,6 +169,8 @@ struct _MSSndCardDesc;
void ms_sleep(int seconds);
void ms_usleep(uint64_t usec);
/**
* The max payload size allowed.
* Filters that generate data that can be sent through RTP should make packets
......
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2010 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 mseventqueue_h
#define mseventqueue_h
typedef struct _MSEventQueue MSEventQueue;
MSEventQueue *ms_event_queue_new();
void ms_set_global_event_queue(MSEventQueue *q);
void ms_event_queue_pump(MSEventQueue *q);
void ms_event_queue_destroy(MSEventQueue *q);
#endif
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2010 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 msitc_h
#define msitc_h
#include "msfilter.h"
#define MS_ITC_SINK_CONNECT MS_FILTER_METHOD(MS_ITC_SINK_ID,0,MSFilter)
#endif
......@@ -16,6 +16,7 @@ libmediastreamer_la_SOURCES= mscommon.c \
msfilter.c \
msqueue.c \
msticker.c \
eventqueue.c \
alaw.c \
ulaw.c \
mssndcard.c \
......@@ -38,7 +39,8 @@ libmediastreamer_la_SOURCES= mscommon.c \
kiss_fftr.h \
equalizer.c \
chanadapt.c \
audiomixer.c
audiomixer.c \
itc.c
#dummy c++ file to force libtool to use c++ linking (because of msdscap-mingw.cc)
nodist_EXTRA_libmediastreamer_la_SOURCES = dummy.cxx
......
......@@ -60,7 +60,7 @@ static void mixer_preprocess(MSFilter *f){
MixerState *s=(MixerState *)f->data;
s->purgeoffset=MAX_LATENCY*(float)(2*s->nchannels*s->rate);
s->bytespertick=(2*s->nchannels*s->rate*f->ticker->interval)/1000;
s->sum=ms_malloc0(s->bytespertick);
s->sum=ms_malloc0((s->bytespertick/2)*sizeof(int32_t));
}
static void mixer_postprocess(MSFilter *f){
......@@ -109,18 +109,20 @@ static void mixer_process(MSFilter *f){
for(i=0;i<MIXER_MAX_CHANNELS;++i){
MSQueue *q=f->inputs[i];
ms_bufferizer_put_from_queue(&s->channels[i],q);
if (ms_bufferizer_get_avail(&s->channels[i])>=s->bytespertick){
ms_bufferizer_read(&s->channels[i],tmpbuf,s->bytespertick);
if (s->gains[i]==1)
accumulate(s->sum,(int16_t*)tmpbuf,nwords);
else
accumulate_mpy(s->sum,(int16_t*)tmpbuf,nwords,s->gains[i]);
got_something=TRUE;
}
if (ms_bufferizer_get_avail(&s->channels[i])>s->purgeoffset){
ms_warning("Too much data in channel %i",i);
ms_bufferizer_flush (&s->channels[i]);
if (q){
ms_bufferizer_put_from_queue(&s->channels[i],q);
if (ms_bufferizer_get_avail(&s->channels[i])>=s->bytespertick){
ms_bufferizer_read(&s->channels[i],tmpbuf,s->bytespertick);
if (s->gains[i]==1)
accumulate(s->sum,(int16_t*)tmpbuf,nwords);
else
accumulate_mpy(s->sum,(int16_t*)tmpbuf,nwords,s->gains[i]);
got_something=TRUE;
}
if (ms_bufferizer_get_avail(&s->channels[i])>s->purgeoffset){
ms_warning("Too much data in channel %i",i);
ms_bufferizer_flush (&s->channels[i]);
}
}
}
if (got_something){
......@@ -181,7 +183,7 @@ MSFilterDesc ms_audio_mixer_desc={
MS_FILTER_OTHER,
NULL,
MIXER_MAX_CHANNELS,
MIXER_MAX_CHANNELS,
1,
mixer_init,
mixer_preprocess,
mixer_process,
......
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2010 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.
*/
#include "mediastreamer2/mseventqueue.h"
#include "mediastreamer2/msfilter.h"
#ifndef MS_EVENT_BUF_SIZE
#define MS_EVENT_BUF_SIZE 8192
#endif
struct _MSEventQueue{
ms_mutex_t mutex; /*could be replaced by an atomic counter for freeroom*/
uint8_t *rptr;
uint8_t *wptr;
uint8_t *endptr;
uint8_t *lim;
int freeroom;
int size;
uint8_t buffer[MS_EVENT_BUF_SIZE];
};
static void write_event(MSEventQueue *q, MSFilter *f, unsigned int ev_id, void *arg){
int argsize=ev_id & 0xffff;
int size=argsize+16;
uint8_t *nextpos=q->wptr+size;
if (q->freeroom<size){
ms_error("Dropped event, no more free space in event buffer !");
return;
}
if (nextpos>q->lim){
/* need to wrap around */
q->endptr=q->wptr;
q->wptr=q->buffer;
nextpos=q->wptr+size;
}
*(long*)q->wptr=(long)f;
*(long*)(q->wptr+8)=(long)ev_id;
if (argsize>0) memcpy(q->wptr+16,arg,argsize);
q->wptr=nextpos;
ms_mutex_lock(&q->mutex);
q->freeroom-=size;
ms_mutex_unlock(&q->mutex);
}
static bool_t read_event(MSEventQueue *q){
int available=q->size-q->freeroom;
if (available>0){
MSFilter *f;
unsigned int id;
void *data;
int argsize=id & 0xffff;
int evsize=argsize+16;
f=(MSFilter *)*(long*)(q->rptr);
id=(unsigned int)*(long*)(q->rptr+8);
data=q->rptr+16;
if (f->notify!=NULL)
f->notify(f->notify_ud,id,argsize>0 ? data : NULL);
q->rptr+=evsize;
if (q->rptr>=q->endptr){
q->rptr=q->buffer;
}
ms_mutex_lock(&q->mutex);
q->freeroom+=evsize;
ms_mutex_unlock(&q->mutex);
return TRUE;
}
return FALSE;
}
MSEventQueue *ms_event_queue_new(){
MSEventQueue *q=ms_new0(MSEventQueue,1);
int bufsize=MS_EVENT_BUF_SIZE;
ms_mutex_init(&q->mutex,NULL);
q->lim=q->buffer+bufsize;
q->freeroom=bufsize;
q->wptr=q->rptr=q->buffer;
q->endptr=q->lim;
q->size=bufsize;
return q;
}
void ms_event_queue_destroy(MSEventQueue *q){
ms_mutex_destroy(&q->mutex);
ms_free(q);
}
static MSEventQueue *ms_global_event_queue=NULL;
void ms_set_global_event_queue(MSEventQueue *q){
ms_global_event_queue=q;
}
void ms_event_queue_pump(MSEventQueue *q){
while(read_event(q)){
}
}
void ms_filter_notify(MSFilter *f, unsigned int id, void *arg){
if (f->notify!=NULL){
if (ms_global_event_queue==NULL){
/* synchronous notification */
f->notify(f->notify_ud,id,arg);
}else{
write_event(ms_global_event_queue,f,id,arg);
}
}
}
void ms_filter_notify_no_arg(MSFilter *f, unsigned int id){
ms_filter_notify(f,id,NULL);
}
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2010 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.
*/
#include "mediastreamer2/msitc.h"
typedef struct SourceState{
ms_mutex_t mutex;
MSQueue q;
}SourceState;
static void itc_source_init(MSFilter *f){
SourceState *s=ms_new(SourceState,1);
ms_mutex_init(&s->mutex,NULL);
ms_queue_init(&s->q);
f->data=s;
}
static void itc_source_uninit(MSFilter *f){
SourceState *s=(SourceState *)f->data;
ms_mutex_destroy(&s->mutex);
ms_queue_flush (&s->q);
ms_free(s);
}
static void itc_source_queue_packet(MSFilter *f, mblk_t *m){
SourceState *s=(SourceState *)f->data;
ms_mutex_lock(&s->mutex);
ms_queue_put(&s->q,m);
ms_mutex_unlock(&s->mutex);
}
static void itc_source_process(MSFilter *f){
SourceState *s=(SourceState *)f->data;
mblk_t *m;
ms_mutex_lock(&s->mutex);
while((m=ms_queue_get(&s->q))!=NULL){
ms_mutex_unlock(&s->mutex);
ms_queue_put(f->outputs[0],m);
ms_mutex_lock(&s->mutex);
}
ms_mutex_unlock(&s->mutex);
}
#ifdef _MSC_VER
MSFilterDesc ms_itc_source_desc={
MS_ITC_SOURCE_ID,
"MSItcSource",
N_("Inter ticker communication filter."),
MS_FILTER_OTHER,
NULL,
0,
1,
itc_source_init,
NULL,
itc_source_process,
NULL,
itc_source_uninit,
NULL
};
#else
MSFilterDesc ms_itc_source_desc={
.id=MS_ITC_SOURCE_ID,
.name="MSItcSource",
.text=N_("Inter ticker communication filter."),
.category=MS_FILTER_OTHER,
.ninputs=0,
.noutputs=1,
.init=itc_source_init,
.process=itc_source_process,
.uninit=itc_source_uninit,
};
#endif
static void itc_sink_process(MSFilter *f){
MSFilter *other=f->data;
mblk_t *im;
while((im=ms_queue_get(f->inputs[0]))!=NULL){
itc_source_queue_packet(other,im);
}
}
static int itc_sink_connect(MSFilter *f, void *data){
f->data=data;
return 0;
}
static MSFilterMethod sink_methods[]={
{ MS_ITC_SINK_CONNECT , itc_sink_connect },
{ 0, NULL }
};
#ifdef _MSC_VER
MSFilterDesc ms_itc_sink_desc={
MS_ITC_SINK_ID,
"MSItcSink",
N_("Inter ticker communication filter."),
MS_FILTER_OTHER,
NULL,
1,
0,
NULL,
NULL,
itc_sink_process,
NULL,
NULL,
sink_methods
};
#else
MSFilterDesc ms_itc_sink_desc={
.id=MS_ITC_SINK_ID,
.name="MSItcSink",
.text=N_("Inter ticker communication filter."),
.category=MS_FILTER_OTHER,
.ninputs=1,
.noutputs=0,
.process=itc_sink_process,
.methods=sink_methods
};
#endif
MS_FILTER_DESC_EXPORT(ms_itc_source_desc)
MS_FILTER_DESC_EXPORT(ms_itc_sink_desc)
......@@ -606,6 +606,21 @@ void ms_sleep(int seconds){
#endif
}
void ms_usleep(uint64_t usec){
#ifdef WIN32
Sleep(usec/1000);
#else
struct timespec ts,rem;
int err;
ts.tv_sec=usec/1000000LL;
ts.tv_nsec=(usec%1000000LL)*1000;
do {
err=nanosleep(&ts,&rem);
ts=rem;
}while(err==-1 && errno==EINTR);
#endif
}
#define DEFAULT_MAX_PAYLOAD_SIZE 1440
static int max_payload_size=DEFAULT_MAX_PAYLOAD_SIZE;
......
......@@ -123,6 +123,7 @@ MSFilterId ms_filter_get_id(MSFilter *f){
int ms_filter_link(MSFilter *f1, int pin1, MSFilter *f2, int pin2){
MSQueue *q;
ms_message("ms_filter_link: %s:%p,%i-->%s:%p,%i",f1->desc->name,f1,pin1,f2->desc->name,f2,pin2);
ms_return_val_if_fail(pin1<f1->desc->noutputs, -1);
ms_return_val_if_fail(pin2<f2->desc->ninputs, -1);
ms_return_val_if_fail(f1->outputs[pin1]==NULL,-1);
......@@ -130,12 +131,12 @@ int ms_filter_link(MSFilter *f1, int pin1, MSFilter *f2, int pin2){
q=ms_queue_new(f1,pin1,f2,pin2);
f1->outputs[pin1]=q;
f2->inputs[pin2]=q;
ms_message("ms_filter_link: %s:%p,%i-->%s:%p,%i",f1->desc->name,f1,pin1,f2->desc->name,f2,pin2);
return 0;
}
int ms_filter_unlink(MSFilter *f1, int pin1, MSFilter *f2, int pin2){
MSQueue *q;
ms_message("ms_filter_unlink: %s:%p,%i-->%s:%p,%i",f1->desc->name,f1,pin1,f2->desc->name,f2,pin2);
ms_return_val_if_fail(f1, -1);
ms_return_val_if_fail(f2, -1);
ms_return_val_if_fail(pin1<f1->desc->noutputs, -1);
......@@ -146,7 +147,6 @@ int ms_filter_unlink(MSFilter *f1, int pin1, MSFilter *f2, int pin2){
q=f1->outputs[pin1];
f1->outputs[pin1]=f2->inputs[pin2]=0;
ms_queue_destroy(q);
ms_message("ms_filter_unlink: %s:%p,%i-->%s:%p,%i",f1->desc->name,f1,pin1,f2->desc->name,f2,pin2);
return 0;
}
......@@ -224,15 +224,6 @@ bool_t ms_filter_inputs_have_data(MSFilter *f){
return FALSE;
}
void ms_filter_notify(MSFilter *f, unsigned int id, void *arg){
if (f->notify!=NULL)
f->notify(f->notify_ud,id,arg);
}
void ms_filter_notify_no_arg(MSFilter *f, unsigned int id){
if (f->notify!=NULL)
f->notify(f->notify_ud,id,NULL);
}
static void find_filters(MSList **filters, MSFilter *f ){
......
......@@ -31,9 +31,8 @@ typedef struct _ResampleData{
uint32_t ts;
uint32_t input_rate;
uint32_t output_rate;
int nchannels;
SpeexResamplerState *handle;
int nb_unprocessed;
} ResampleData;
static ResampleData * resample_data_new(){
......@@ -43,8 +42,7 @@ static ResampleData * resample_data_new(){
obj->input_rate=8000;
obj->output_rate=16000;
obj->handle=NULL;
obj->nb_unprocessed=0;
obj->nchannels=1;
return obj;
}
......@@ -60,89 +58,9 @@ static void resample_init(MSFilter *obj){
}
static void resample_uninit(MSFilter *obj){
resample_data_destroy((ResampleData*)obj->data);
resample_data_destroy((ResampleData*)obj->data);
}
#if 0
static void resample_process_ms2(MSFilter *obj){
ResampleData *dt=(ResampleData*)obj->data;
MSBufferizer *bz=dt->bz;
uint8_t buffer[2240];
int size_of_input;
int size_of_output;
mblk_t *m;
if (dt->output_rate==dt->input_rate)
{
while((m=ms_queue_get(obj->inputs[0]))!=NULL){
ms_queue_put(obj->outputs[0],m);
}
return;
}
if (dt->handle!=NULL){
unsigned int inrate=0, outrate=0;
speex_resampler_get_rate(dt->handle,&inrate,&outrate);
if (inrate!=dt->input_rate || outrate!=dt->output_rate){
speex_resampler_destroy(dt->handle);
dt->handle=0;
}
}
if (dt->handle==NULL){
int err=0;
dt->handle=speex_resampler_init(1, dt->input_rate, dt->output_rate, SPEEX_RESAMPLER_QUALITY_VOIP, &err);
}
if (dt->input_rate<dt->output_rate)
size_of_input=320*dt->input_rate/8000;
else
size_of_input=320*dt->input_rate/8000;
size_of_output = (size_of_input * dt->output_rate)/dt->input_rate;
while((m=ms_queue_get(obj->inputs[0]))!=NULL){
ms_bufferizer_put(bz,m);
}
while (ms_bufferizer_read(bz,buffer,size_of_input)==size_of_input){
mblk_t *obl=allocb(size_of_output,0);
float *in;
float *out;
spx_uint32_t in_len;
spx_uint32_t out_len;
int err;
short *data = (short*)buffer;
short *data_out = (short*)obl->b_wptr;
int i;
spx_uint32_t idx;
in = (float*) alloca((size_of_input/2)*sizeof(float));
out = (float*) alloca((size_of_output/2)*sizeof(float));
/* Convert the samples to floats */
for (i = 0; i < size_of_input/2; i++)
in[i] = (float) data[i];
in_len = size_of_input/2;
out_len = size_of_output/2;
err = speex_resampler_process_float(dt->handle, 0, in, &in_len, out, &out_len);
/* ms_message("resampling info: err=%i in_len=%i, out_len=%i", err, in_len, out_len); */
for (idx=0;idx<out_len;idx++)
data_out[idx]=(short)floor(.5+out[idx]);
obl->b_wptr=obl->b_wptr+(out_len*2); /* size_of_output; */
mblk_set_timestamp_info(obl,dt->ts);
dt->ts+=160;
ms_queue_put(obj->outputs[0],obl);
}
}
#else
static void resample_process_ms2(MSFilter *obj){
ResampleData *dt=(ResampleData*)obj->data;
mblk_t *m;
......@@ -151,9 +69,9 @@ static void resample_process_ms2(MSFilter *obj){
while((m=ms_queue_get(obj->inputs[0]))!=NULL){
ms_queue_put(obj->outputs[0],m);
}
return;
return;
}
ms_filter_lock(obj);
if (dt->handle!=NULL){
unsigned int inrate=0, outrate=0;
speex_resampler_get_rate(dt->handle,&inrate,&outrate);
......@@ -164,53 +82,68 @@ static void resample_process_ms2(MSFilter *obj){
}
if (dt->handle==NULL){
int err=0;
dt->handle=speex_resampler_init(1, dt->input_rate, dt->output_rate, SPEEX_RESAMPLER_QUALITY_VOIP, &err);
dt->handle=speex_resampler_init(dt->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;
unsigned int inlen=(m->b_wptr-m->b_rptr)/(2*dt->nchannels);
unsigned int outlen=((inlen*dt->output_rate)/dt->input_rate)+1;
unsigned int inlen_orig=inlen;
mblk_t *om=allocb(outlen*2,0);
speex_resampler_process_int(dt->handle,
0,
(int16_t*)m->b_rptr,
&inlen,
(int16_t*)om->b_wptr,
&outlen);
mblk_t *om=allocb(outlen*2*dt->nchannels,0);
if (dt->nchannels==1){
speex_resampler_process_int(dt->handle,
0,
(int16_t*)m->b_rptr,
&inlen,
(int16_t*)om->b_wptr,
&outlen);
}else{
speex_resampler_process_interleaved_int(dt->handle,
(int16_t*)m->b_rptr,
&inlen,
(int16_t*)om->b_wptr,
&outlen);
}
if (inlen_orig!=inlen){
ms_error("Bug in resampler ! only %u samples consumed instead of %u, out=%u",
inlen,inlen_orig,outlen);
}
om->b_wptr+=outlen*2;
om->b_wptr+=outlen*2*dt->nchannels;
mblk_set_timestamp_info(om,dt->ts);
dt->ts+=outlen;
ms_queue_put(obj->outputs[0],om);
freemsg(m);
}
ms_filter_unlock(obj);
}
#endif
static int ms_resample_set_sr(MSFilter *obj, void *arg){
ResampleData *dt=(ResampleData*)obj->data;
dt->input_rate=((int*)arg)[0];
return 0;
}
int ms_resample_set_sr(MSFilter *obj, void *arg){
ResampleData *dt=(ResampleData*)obj->data;
dt->input_rate=((int*)arg)[0];
return 0;
static int ms_resample_set_output_sr(MSFilter *obj, void *arg){
ResampleData *dt=(ResampleData*)obj->data;
dt->output_rate=((int*)arg)[0];
return 0;
}
int ms_resample_set_output_sr(MSFilter *obj, void *arg){
ResampleData *dt=(ResampleData*)obj->data;
dt->output_rate=((int*)arg)[0];
return 0;
static int set_nchannels(MSFilter *f, void *arg){
ResampleData *dt=(ResampleData*)f->data;
ms_filter_lock(f);
dt->nchannels=*(int*)arg;
ms_filter_unlock(f);
return 0;
}
static MSFilterMethod enc_methods[]={
{ MS_FILTER_SET_SAMPLE_RATE , ms_resample_set_sr },
{ MS_FILTER_SET_OUTPUT_SAMPLE_RATE , ms_resample_set_output_sr },
{ 0 , NULL }
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 },
{ 0 , NULL }
};
#ifdef _MSC_VER
......@@ -218,7 +151,7 @@ static MSFilterMethod enc_methods[]={
MSFilterDesc ms_resample_desc={
MS_RESAMPLE_ID,
"MSResample",
N_("frequency resampler"),
N_("Audio resampler"