Commit 332d7920 authored by Simon Morlat's avatar Simon Morlat

send inband dtmfs when no telephone event are possible and pcmX is used

implement dtmfs playing within RingStream
parent 030250c1
......@@ -24,6 +24,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MS_DTMF_GEN_PUT MS_FILTER_METHOD(MS_DTMF_GEN_ID,0,const char)
#define MS_DTMF_GEN_PLAY MS_FILTER_METHOD(MS_DTMF_GEN_ID,0,const char) /*alias to put*/
/**Start playing a dtmf */
#define MS_DTMF_GEN_START MS_FILTER_METHOD(MS_DTMF_GEN_ID,1,const char)
/**Stop currently played dtmf*/
#define MS_DTMF_GEN_STOP MS_FILTER_METHOD_NO_ARG(MS_DTMF_GEN_ID,2)
extern MSFilterDesc ms_dtmf_gen_desc;
#endif
......@@ -53,6 +53,7 @@ struct _AudioStream
MSFilter *rtprecv;
MSFilter *rtpsend;
MSFilter *dtmfgen;
MSFilter *dtmfgen_rtp;
MSFilter *ec;/*echo canceler*/
MSFilter *volsend,*volrecv; /*MSVolumes*/
MSFilter *read_resampler;
......@@ -82,6 +83,7 @@ struct _RingStream
{
MSTicker *ticker;
MSFilter *source;
MSFilter *gendtmf;
MSFilter *sndwrite;
};
......
......@@ -66,6 +66,7 @@ void audio_stream_free(AudioStream *stream)
if (stream->ticker!=NULL) ms_ticker_destroy(stream->ticker);
if (stream->read_resampler!=NULL) ms_filter_destroy(stream->read_resampler);
if (stream->write_resampler!=NULL) ms_filter_destroy(stream->write_resampler);
if (stream->dtmfgen_rtp!=NULL) ms_filter_destroy(stream->dtmfgen_rtp);
ms_free(stream);
}
......@@ -250,6 +251,13 @@ int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char
ms_error("audiostream.c: undefined payload type.");
return -1;
}
if (rtp_profile_get_payload_from_mime (profile,"telephone-event")==NULL
&& ( strcasecmp(pt->mime_type,"pcmu")==0 || strcasecmp(pt->mime_type,"pcma")==0)){
/*if no telephone-event payload is usable and pcma or pcmu is used, we will generate
inband dtmf*/
stream->dtmfgen_rtp=ms_filter_new (MS_DTMF_GEN_ID);
}
if (ms_filter_call_method(stream->rtpsend,MS_FILTER_GET_SAMPLE_RATE,&sample_rate)!=0){
ms_error("Sample rate is unknown for RTP side !");
return -1;
......@@ -357,6 +365,8 @@ int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char
ms_connection_helper_link(&h,stream->ec,1,1);
if (stream->volsend)
ms_connection_helper_link(&h,stream->volsend,0,0);
if (stream->dtmfgen_rtp)
ms_connection_helper_link(&h,stream->dtmfgen_rtp,0,0);
ms_connection_helper_link(&h,stream->encoder,0,0);
ms_connection_helper_link(&h,stream->rtpsend,0,-1);
......@@ -578,32 +588,48 @@ RingStream * ring_start_with_cb(const char *file,int interval,MSSndCard *sndcard
int tmp;
stream=(RingStream *)ms_new0(RingStream,1);
stream->source=ms_filter_new(MS_FILE_PLAYER_ID);
if (ms_filter_call_method(stream->source,MS_FILE_PLAYER_OPEN,(void*)file)<0){
ms_filter_destroy(stream->source);
ms_free(stream);
return NULL;
}
if (file)
ms_filter_call_method(stream->source,MS_FILE_PLAYER_OPEN,(void*)file);
ms_filter_call_method(stream->source,MS_FILE_PLAYER_LOOP,&interval);
ms_filter_call_method_noarg(stream->source,MS_FILE_PLAYER_START);
if (func!=NULL)
ms_filter_set_notify_callback(stream->source,func,user_data);
stream->gendtmf=ms_filter_new(MS_DTMF_GEN_ID);
stream->sndwrite=ms_snd_card_create_writer(sndcard);
ms_filter_call_method(stream->source,MS_FILTER_GET_SAMPLE_RATE,&tmp);
ms_filter_call_method(stream->gendtmf,MS_FILTER_SET_SAMPLE_RATE,&tmp);
ms_filter_call_method(stream->sndwrite,MS_FILTER_SET_SAMPLE_RATE,&tmp);
ms_filter_call_method(stream->source,MS_FILTER_GET_NCHANNELS,&tmp);
ms_filter_call_method(stream->gendtmf,MS_FILTER_SET_NCHANNELS,&tmp);
ms_filter_call_method(stream->sndwrite,MS_FILTER_SET_NCHANNELS,&tmp);
stream->ticker=ms_ticker_new();
ms_ticker_set_name(stream->ticker,"Audio (ring) MSTicker");
ms_filter_link(stream->source,0,stream->sndwrite,0);
ms_filter_link(stream->source,0,stream->gendtmf,0);
ms_filter_link(stream->gendtmf,0,stream->sndwrite,0);
ms_ticker_attach(stream->ticker,stream->source);
return stream;
}
void ring_play_dtmf(RingStream *stream, char dtmf, int duration_ms){
if (duration_ms>0)
ms_filter_call_method(stream->gendtmf, MS_DTMF_GEN_PLAY, &dtmf);
else ms_filter_call_method(stream->gendtmf, MS_DTMF_GEN_START, &dtmf);
}
void ring_stop_dtmf(RingStream *stream){
ms_filter_call_method_noarg(stream->gendtmf, MS_DTMF_GEN_STOP);
}
void ring_stop(RingStream *stream){
ms_ticker_detach(stream->ticker,stream->source);
ms_filter_unlink(stream->source,0,stream->sndwrite,0);
ms_filter_unlink(stream->source,0,stream->gendtmf,0);
ms_filter_unlink(stream->gendtmf,0,stream->sndwrite,0);
ms_ticker_destroy(stream->ticker);
ms_filter_destroy(stream->source);
ms_filter_destroy(stream->gendtmf);
ms_filter_destroy(stream->sndwrite);
ms_free(stream);
#ifdef _WIN32_WCE
......@@ -615,10 +641,10 @@ void ring_stop(RingStream *stream){
int audio_stream_send_dtmf(AudioStream *stream, char dtmf)
{
if (stream->rtpsend)
if (stream->dtmfgen_rtp)
ms_filter_call_method(stream->dtmfgen_rtp,MS_DTMF_GEN_PLAY,&dtmf);
else if (stream->rtpsend)
ms_filter_call_method(stream->rtpsend,MS_RTP_SEND_SEND_DTMF,&dtmf);
if (stream->dtmfgen)
ms_filter_call_method(stream->dtmfgen,MS_DTMF_GEN_PUT,&dtmf);
return 0;
}
......
......@@ -18,6 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "mediastreamer2/dtmfgen.h"
#include "mediastreamer2/msticker.h"
#include <math.h>
......@@ -26,12 +27,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define M_PI 3.14159265358979323846
#endif
#define NO_SAMPLES_THRESHOLD 100 /*ms*/
#define TRAILLING_SILENCE 500 /*ms*/
struct DtmfGenState{
int rate;
int dur;
int pos;
float highfreq;
float lowfreq;
int nosamples_time;
int silence;
char dtmf;
};
......@@ -43,6 +49,8 @@ static void dtmfgen_init(MSFilter *f){
s->dur=s->rate/10;
s->pos=0;
s->dtmf=0;
s->nosamples_time=0;
s->silence=0;
f->data=s;
}
......@@ -123,45 +131,94 @@ static int dtmfgen_put(MSFilter *f, void *arg){
ms_warning("Not a dtmf key.");
return -1;
}
ms_filter_lock(f);
s->lowfreq=s->lowfreq/s->rate;
s->highfreq=s->highfreq/s->rate;
s->dur=s->rate/10; /*100 ms duration */
s->silence=0;
s->dtmf=dtmf[0];
ms_filter_unlock(f);
return 0;
}
static int dtmfgen_start(MSFilter *f, void *arg){
if (dtmfgen_put(f,arg)==0){
DtmfGenState *s=(DtmfGenState*)f->data;
s->dur=5*s->rate;
return 0;
}
return -1;
}
static int dtmfgen_stop(MSFilter *f, void *arg){
DtmfGenState *s=(DtmfGenState*)f->data;
s->dtmf=0;
return 0;
}
static int dtmfgen_set_rate(MSFilter *f, void *arg){
DtmfGenState *s=(DtmfGenState*)f->data;
s->rate=*((int*)arg);
s->dur=s->rate/10;
return 0;
}
static void write_dtmf(DtmfGenState *s , int16_t *sample, int nsamples){
int i;
for (i=0;i<nsamples && s->pos<s->dur;i++,s->pos++){
sample[i]=(int16_t)(10000.0*sin(2*M_PI*(float)s->pos*s->lowfreq));
sample[i]+=(int16_t)(10000.0*sin(2*M_PI*(float)s->pos*s->highfreq));
}
if (s->pos==s->dur){
s->pos=0;
s->dtmf=0;
s->silence=TRAILLING_SILENCE;
}
}
static void dtmfgen_process(MSFilter *f){
mblk_t *m;
DtmfGenState *s=(DtmfGenState*)f->data;
int nsamples;
while((m=ms_queue_get(f->inputs[0]))!=NULL){
if (s->dtmf!=0){
int nsamples=(m->b_wptr-m->b_rptr)/2;
int i;
int16_t *sample=(int16_t*)m->b_rptr;
for (i=0;i<nsamples && s->pos<s->dur;i++,s->pos++){
sample[i]=(int16_t)(10000.0*sin(2*M_PI*(float)s->pos*s->lowfreq));
sample[i]+=(int16_t)(10000.0*sin(2*M_PI*(float)s->pos*s->highfreq));
ms_filter_lock(f);
if (ms_queue_empty(f->inputs[0])){
s->nosamples_time+=f->ticker->interval;
if ((s->dtmf!=0 || s->silence!=0) && s->nosamples_time>NO_SAMPLES_THRESHOLD){
/*after 100 ms without stream we decide to generate our own sample
instead of writing into incoming stream samples*/
nsamples=(f->ticker->interval*s->rate)/1000;
m=allocb(nsamples*2,0);
if (s->silence==0){
write_dtmf(s,(int16_t*)m->b_wptr,nsamples);
}else{
memset(m->b_wptr,0,nsamples*2);
s->silence-=f->ticker->interval;
if (s->silence<0) s->silence=0;
}
if (s->pos==s->dur){
s->pos=0;
s->dtmf=0;
m->b_wptr+=nsamples*2;
ms_queue_put(f->outputs[0],m);
}
}else{
s->nosamples_time=0;
s->silence=0;
while((m=ms_queue_get(f->inputs[0]))!=NULL){
if (s->dtmf!=0){
nsamples=(m->b_wptr-m->b_rptr)/2;
write_dtmf(s, (int16_t*)m->b_rptr,nsamples);
}
ms_queue_put(f->outputs[0],m);
}
ms_queue_put(f->outputs[0],m);
}
ms_filter_unlock(f);
}
MSFilterMethod dtmfgen_methods[]={
{ MS_FILTER_SET_SAMPLE_RATE , dtmfgen_set_rate },
{ MS_DTMF_GEN_PUT , dtmfgen_put },
{ MS_DTMF_GEN_PLAY , dtmfgen_put },
{ MS_DTMF_GEN_START , dtmfgen_start },
{ MS_DTMF_GEN_STOP , dtmfgen_stop },
{ 0 , NULL }
};
......@@ -180,7 +237,8 @@ MSFilterDesc ms_dtmf_gen_desc={
dtmfgen_process,
NULL,
dtmfgen_uninit,
dtmfgen_methods
dtmfgen_methods,
MS_FILTER_IS_PUMP
};
#else
......@@ -195,7 +253,8 @@ MSFilterDesc ms_dtmf_gen_desc={
.init=dtmfgen_init,
.process=dtmfgen_process,
.uninit=dtmfgen_uninit,
.methods=dtmfgen_methods
.methods=dtmfgen_methods,
.flags=MS_FILTER_IS_PUMP
};
#endif
......
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