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

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