]> sjero.net Git - linphone/blob - linphone/mediastreamer2/src/audiostream.c
remote ortp and add it as a submodule instead.
[linphone] / linphone / mediastreamer2 / src / audiostream.c
1 /*
2 mediastreamer2 library - modular sound and video processing and streaming
3 Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 */
19
20
21 #ifdef HAVE_CONFIG_H
22 #include "mediastreamer-config.h"
23 #endif
24
25 #include "mediastreamer2/mediastream.h"
26
27 #include "mediastreamer2/dtmfgen.h"
28 #include "mediastreamer2/mssndcard.h"
29 #include "mediastreamer2/msrtp.h"
30 #include "mediastreamer2/msfileplayer.h"
31 #include "mediastreamer2/msfilerec.h"
32 #include "mediastreamer2/msvolume.h"
33 #include "mediastreamer2/msequalizer.h"
34 #include "mediastreamer2/msspeexec.h"
35
36 #ifdef INET6
37         #include <sys/types.h>
38 #ifndef WIN32
39         #include <sys/socket.h>
40         #include <netdb.h>
41 #endif
42 #endif
43
44
45 #define MAX_RTP_SIZE    1500
46
47
48 /* this code is not part of the library itself, it is part of the mediastream program */
49 void audio_stream_free(AudioStream *stream)
50 {
51         if (stream->session!=NULL) rtp_session_destroy(stream->session);
52         if (stream->rtpsend!=NULL) ms_filter_destroy(stream->rtpsend);
53         if (stream->rtprecv!=NULL) ms_filter_destroy(stream->rtprecv);
54         if (stream->soundread!=NULL) ms_filter_destroy(stream->soundread);
55         if (stream->soundwrite!=NULL) ms_filter_destroy(stream->soundwrite);
56         if (stream->encoder!=NULL) ms_filter_destroy(stream->encoder);
57         if (stream->decoder!=NULL) ms_filter_destroy(stream->decoder);
58         if (stream->dtmfgen!=NULL) ms_filter_destroy(stream->dtmfgen);
59         if (stream->ec!=NULL)   ms_filter_destroy(stream->ec);
60         if (stream->volrecv!=NULL) ms_filter_destroy(stream->volrecv);
61         if (stream->volsend!=NULL) ms_filter_destroy(stream->volsend);
62         if (stream->equalizer!=NULL) ms_filter_destroy(stream->equalizer);
63         if (stream->ticker!=NULL) ms_ticker_destroy(stream->ticker);
64         if (stream->read_resampler!=NULL) ms_filter_destroy(stream->read_resampler);
65         if (stream->write_resampler!=NULL) ms_filter_destroy(stream->write_resampler);
66         ms_free(stream);
67 }
68
69 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
70
71 static void on_dtmf_received(RtpSession *s, int dtmf, void * user_data)
72 {
73         AudioStream *stream=(AudioStream*)user_data;
74         if (dtmf>15){
75                 ms_warning("Unsupported telephone-event type.");
76                 return;
77         }
78         ms_message("Receiving dtmf %c.",dtmf_tab[dtmf]);
79         if (stream->dtmfgen!=NULL && stream->play_dtmfs){
80                 ms_filter_call_method(stream->dtmfgen,MS_DTMF_GEN_PUT,&dtmf_tab[dtmf]);
81         }
82 }
83
84 #if 0
85
86 static void on_timestamp_jump(RtpSession *s,uint32_t* ts, void * user_data)
87 {
88         ms_warning("The remote sip-phone has send data with a future timestamp: %u,"
89                         "resynchronising session.",*ts);
90         rtp_session_reset(s);
91 }
92
93 #endif
94
95
96 bool_t ms_is_ipv6(const char *remote){
97         bool_t ret=FALSE;
98 #ifdef INET6
99         struct addrinfo hints, *res0;
100
101         int err;
102         memset(&hints, 0, sizeof(hints));
103         hints.ai_family = PF_UNSPEC;
104         hints.ai_socktype = SOCK_DGRAM;
105         err = getaddrinfo(remote,"8000", &hints, &res0);
106         if (err!=0) {
107                 ms_warning ("get_local_addr_for: %s", gai_strerror(err));
108                 return FALSE;
109         }
110         ret=(res0->ai_addr->sa_family==AF_INET6);
111         freeaddrinfo(res0);
112 #endif
113         return ret;
114 }
115
116 static void audio_stream_configure_resampler(MSFilter *resampler,MSFilter *from,MSFilter *to) {
117         int from_rate=0, to_rate=0;
118         ms_filter_call_method(from,MS_FILTER_GET_SAMPLE_RATE,&from_rate);
119         ms_filter_call_method(to,MS_FILTER_GET_SAMPLE_RATE,&to_rate);
120         ms_filter_call_method(resampler,MS_FILTER_SET_SAMPLE_RATE,&from_rate);
121         ms_filter_call_method(resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&to_rate);
122         ms_debug("configuring from rate[%i] to rate [%i]",from_rate,to_rate);
123 }
124
125 RtpSession * create_duplex_rtpsession( int locport, bool_t ipv6){
126         RtpSession *rtpr;
127         rtpr=rtp_session_new(RTP_SESSION_SENDRECV);
128         rtp_session_set_recv_buf_size(rtpr,MAX_RTP_SIZE);
129         rtp_session_set_scheduling_mode(rtpr,0);
130         rtp_session_set_blocking_mode(rtpr,0);
131         rtp_session_enable_adaptive_jitter_compensation(rtpr,TRUE);
132         rtp_session_set_symmetric_rtp(rtpr,TRUE);
133         rtp_session_set_local_addr(rtpr,ipv6 ? "::" : "0.0.0.0",locport);
134         rtp_session_signal_connect(rtpr,"timestamp_jump",(RtpCallback)rtp_session_resync,(long)NULL);
135         rtp_session_signal_connect(rtpr,"ssrc_changed",(RtpCallback)rtp_session_resync,(long)NULL);
136         return rtpr;
137 }
138
139 #if defined(_WIN32_WCE)
140 time_t
141 ms_time (time_t *t)
142 {
143     DWORD timemillis = GetTickCount();
144         if (timemillis>0)
145         {
146                 if (t!=NULL)
147                         *t = timemillis/1000;
148         }
149         return timemillis/1000;
150 }
151 #endif
152
153 bool_t audio_stream_alive(AudioStream * stream, int timeout){
154         RtpSession *session=stream->session;
155         const rtp_stats_t *stats=rtp_session_get_stats(session);
156         if (stats->recv!=0){
157                 if (stats->recv!=stream->last_packet_count){
158                         stream->last_packet_count=stats->recv;
159                         stream->last_packet_time=ms_time(NULL);
160                 }else{
161                         if (ms_time(NULL)-stream->last_packet_time>timeout){
162                                 /* more than timeout seconds of inactivity*/
163                                 return FALSE;
164                         }
165                 }
166         }
167         return TRUE;
168 }
169
170 /*this function must be called from the MSTicker thread:
171 it replaces one filter by another one.
172 This is a dirty hack that works anyway.
173 It would be interesting to have something that does the job
174 simplier within the MSTicker api
175 */
176 void audio_stream_change_decoder(AudioStream *stream, int payload){
177         RtpSession *session=stream->session;
178         RtpProfile *prof=rtp_session_get_profile(session);
179         PayloadType *pt=rtp_profile_get_payload(prof,payload);
180         if (pt!=NULL){
181                 MSFilter *dec=ms_filter_create_decoder(pt->mime_type);
182                 if (dec!=NULL){
183                         ms_filter_unlink(stream->rtprecv, 0, stream->decoder, 0);
184                         ms_filter_unlink(stream->decoder,0,stream->dtmfgen,0);
185                         ms_filter_postprocess(stream->decoder);
186                         ms_filter_destroy(stream->decoder);
187                         stream->decoder=dec;
188                         if (pt->recv_fmtp!=NULL)
189                                 ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp);
190                         ms_filter_link (stream->rtprecv, 0, stream->decoder, 0);
191                         ms_filter_link (stream->decoder,0 , stream->dtmfgen, 0);
192                         ms_filter_preprocess(stream->decoder,stream->ticker);
193
194                 }else{
195                         ms_warning("No decoder found for %s",pt->mime_type);
196                 }
197         }else{
198                 ms_warning("No payload defined with number %i",payload);
199         }
200 }
201
202 static void payload_type_changed(RtpSession *session, unsigned long data){
203         AudioStream *stream=(AudioStream*)data;
204         int pt=rtp_session_get_recv_payload_type(stream->session);
205         audio_stream_change_decoder(stream,pt);
206 }
207
208
209 int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char *remip,int remport,
210         int rem_rtcp_port, int payload,int jitt_comp, const char *infile, const char *outfile,
211         MSSndCard *playcard, MSSndCard *captcard, bool_t use_ec)
212 {
213         RtpSession *rtps=stream->session;
214         PayloadType *pt;
215         int tmp;
216         MSConnectionHelper h;
217
218         rtp_session_set_profile(rtps,profile);
219         if (remport>0) rtp_session_set_remote_addr_full(rtps,remip,remport,rem_rtcp_port);
220         rtp_session_set_payload_type(rtps,payload);
221         rtp_session_set_jitter_compensation(rtps,jitt_comp);
222
223         if (remport>0)
224                 ms_filter_call_method(stream->rtpsend,MS_RTP_SEND_SET_SESSION,rtps);
225         stream->rtprecv=ms_filter_new(MS_RTP_RECV_ID);
226         ms_filter_call_method(stream->rtprecv,MS_RTP_RECV_SET_SESSION,rtps);
227         stream->session=rtps;
228
229         stream->dtmfgen=ms_filter_new(MS_DTMF_GEN_ID);
230         rtp_session_signal_connect(rtps,"telephone-event",(RtpCallback)on_dtmf_received,(unsigned long)stream);
231         rtp_session_signal_connect(rtps,"payload_type_changed",(RtpCallback)payload_type_changed,(unsigned long)stream);
232
233         /* creates the local part */
234         if (captcard!=NULL) stream->soundread=ms_snd_card_create_reader(captcard);
235         else {
236                 stream->soundread=ms_filter_new(MS_FILE_PLAYER_ID);
237                 stream->read_resampler=ms_filter_new(MS_RESAMPLE_ID);
238                 if (infile!=NULL) audio_stream_play(stream,infile);
239         }
240         if (playcard!=NULL) stream->soundwrite=ms_snd_card_create_writer(playcard);
241         else {
242                 stream->soundwrite=ms_filter_new(MS_FILE_REC_ID);
243                 if (outfile!=NULL) audio_stream_record(stream,outfile);
244         }
245
246         /* creates the couple of encoder/decoder */
247         pt=rtp_profile_get_payload(profile,payload);
248         if (pt==NULL){
249                 ms_error("audiostream.c: undefined payload type.");
250                 return -1;
251         }
252         stream->encoder=ms_filter_create_encoder(pt->mime_type);
253         stream->decoder=ms_filter_create_decoder(pt->mime_type);
254         if ((stream->encoder==NULL) || (stream->decoder==NULL)){
255                 /* big problem: we have not a registered codec for this payload...*/
256                 ms_error("mediastream.c: No decoder available for payload %i.",payload);
257                 return -1;
258         }
259
260         if (use_ec) {
261                 stream->ec=ms_filter_new(MS_SPEEX_EC_ID);
262                 ms_filter_call_method(stream->ec,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate);
263                 if (stream->ec_tail_len!=0)
264                         ms_filter_call_method(stream->ec,MS_SPEEX_EC_SET_TAIL_LENGTH,&stream->ec_tail_len);
265                 if (stream->ec_delay!=0)
266                         ms_filter_call_method(stream->ec,MS_SPEEX_EC_SET_DELAY,&stream->ec_delay);
267                 if (stream->ec_framesize!=0)
268                         ms_filter_call_method(stream->ec,MS_SPEEX_EC_SET_FRAME_SIZE,&stream->ec_framesize);
269         }
270
271         if (stream->el_type!=ELInactive || stream->use_gc || stream->use_ng){
272                 stream->volsend=ms_filter_new(MS_VOLUME_ID);
273                 stream->volrecv=ms_filter_new(MS_VOLUME_ID);
274                 if (stream->el_type!=ELInactive){
275                         if (stream->el_type==ELControlSpeaker)
276                                 ms_filter_call_method(stream->volrecv,MS_VOLUME_SET_PEER,stream->volsend);
277                         else ms_filter_call_method(stream->volsend,MS_VOLUME_SET_PEER,stream->volrecv);
278                 }
279                 if (stream->use_ng){
280                         int tmp=1;
281                         ms_filter_call_method(stream->volsend,MS_VOLUME_ENABLE_NOISE_GATE,&tmp);
282                 }
283         }
284
285         if (stream->use_agc){
286                 int tmp=1;
287                 if (stream->volsend==NULL)
288                         stream->volsend=ms_filter_new(MS_VOLUME_ID);
289                 ms_filter_call_method(stream->volsend,MS_VOLUME_ENABLE_AGC,&tmp);
290         }
291
292         /* give the sound filters some properties */
293         if (ms_filter_call_method(stream->soundread,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate) != 0) {
294                 /* need to add resampler*/
295                 if (stream->read_resampler == NULL) stream->read_resampler=ms_filter_new(MS_RESAMPLE_ID);
296         }
297
298         if (ms_filter_call_method(stream->soundwrite,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate) != 0) {
299                 /* need to add resampler*/
300                 if (stream->write_resampler == NULL) stream->write_resampler=ms_filter_new(MS_RESAMPLE_ID);
301         }
302
303
304         tmp=1;
305         ms_filter_call_method(stream->soundwrite,MS_FILTER_SET_NCHANNELS, &tmp);
306
307         /* give the encoder/decoder some parameters*/
308         ms_filter_call_method(stream->encoder,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate);
309         ms_message("Payload's bitrate is %i",pt->normal_bitrate);
310         if (pt->normal_bitrate>0){
311                 ms_message("Setting audio encoder network bitrate to %i",pt->normal_bitrate);
312                 ms_filter_call_method(stream->encoder,MS_FILTER_SET_BITRATE,&pt->normal_bitrate);
313         }
314         ms_filter_call_method(stream->decoder,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate);
315
316         if (pt->send_fmtp!=NULL) ms_filter_call_method(stream->encoder,MS_FILTER_ADD_FMTP, (void*)pt->send_fmtp);
317         if (pt->recv_fmtp!=NULL) ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp);
318
319         /*create the equalizer*/
320         stream->equalizer=ms_filter_new(MS_EQUALIZER_ID);
321         tmp=stream->eq_active;
322         ms_filter_call_method(stream->equalizer,MS_EQUALIZER_SET_ACTIVE,&tmp);
323         /*configure resampler if needed*/
324         if (stream->read_resampler){
325                 audio_stream_configure_resampler(stream->read_resampler,stream->soundread,stream->rtpsend);
326         }
327
328         if (stream->write_resampler){
329                 audio_stream_configure_resampler(stream->write_resampler,stream->rtprecv,stream->soundwrite);
330         }
331         /* and then connect all */
332         /* tip: draw yourself the picture if you don't understand */
333
334         /*sending graph*/
335         ms_connection_helper_start(&h);
336         ms_connection_helper_link(&h,stream->soundread,-1,0);
337         if (stream->read_resampler)
338                 ms_connection_helper_link(&h,stream->read_resampler,0,0);
339         if (stream->ec)
340                 ms_connection_helper_link(&h,stream->ec,1,1);
341         if (stream->volsend)
342                 ms_connection_helper_link(&h,stream->volsend,0,0);
343         ms_connection_helper_link(&h,stream->encoder,0,0);
344         ms_connection_helper_link(&h,stream->rtpsend,0,-1);
345
346         /*receiving graph*/
347         ms_connection_helper_start(&h);
348         ms_connection_helper_link(&h,stream->rtprecv,-1,0);
349         ms_connection_helper_link(&h,stream->decoder,0,0);
350         ms_connection_helper_link(&h,stream->dtmfgen,0,0);
351         if (stream->equalizer)
352                 ms_connection_helper_link(&h,stream->equalizer,0,0);
353         if (stream->volrecv)
354                 ms_connection_helper_link(&h,stream->volrecv,0,0);
355         if (stream->ec)
356                 ms_connection_helper_link(&h,stream->ec,0,0);
357         if (stream->write_resampler)
358                 ms_connection_helper_link(&h,stream->write_resampler,0,0);
359         ms_connection_helper_link(&h,stream->soundwrite,0,-1);
360
361         /* create ticker */
362         stream->ticker=ms_ticker_new();
363         ms_ticker_set_name(stream->ticker,"Audio MSTicker");
364         ms_ticker_attach(stream->ticker,stream->soundread);
365         ms_ticker_attach(stream->ticker,stream->rtprecv);
366
367         return 0;
368 }
369
370
371 int audio_stream_start_with_files(AudioStream *stream, RtpProfile *prof,const char *remip, int remport,
372         int rem_rtcp_port, int pt,int jitt_comp, const char *infile, const char * outfile)
373 {
374         return audio_stream_start_full(stream,prof,remip,remport,rem_rtcp_port,pt,jitt_comp,infile,outfile,NULL,NULL,FALSE);
375 }
376
377 AudioStream * audio_stream_start(RtpProfile *prof,int locport,const char *remip,int remport,int profile,int jitt_comp,bool_t use_ec)
378 {
379         MSSndCard *sndcard_playback;
380         MSSndCard *sndcard_capture;
381         AudioStream *stream;
382         sndcard_capture=ms_snd_card_manager_get_default_capture_card(ms_snd_card_manager_get());
383         sndcard_playback=ms_snd_card_manager_get_default_playback_card(ms_snd_card_manager_get());
384         if (sndcard_capture==NULL || sndcard_playback==NULL)
385                 return NULL;
386         stream=audio_stream_new(locport, ms_is_ipv6(remip));
387         if (audio_stream_start_full(stream,prof,remip,remport,remport+1,profile,jitt_comp,NULL,NULL,sndcard_playback,sndcard_capture,use_ec)==0) return stream;
388         audio_stream_free(stream);
389         return NULL;
390 }
391
392 AudioStream *audio_stream_start_with_sndcards(RtpProfile *prof,int locport,const char *remip,int remport,int profile,int jitt_comp,MSSndCard *playcard, MSSndCard *captcard, bool_t use_ec)
393 {
394         AudioStream *stream;
395         if (playcard==NULL) {
396                 ms_error("No playback card.");
397                 return NULL;
398         }
399         if (captcard==NULL) {
400                 ms_error("No capture card.");
401                 return NULL;
402         }
403         stream=audio_stream_new(locport, ms_is_ipv6(remip));
404         if (audio_stream_start_full(stream,prof,remip,remport,remport+1,profile,jitt_comp,NULL,NULL,playcard,captcard,use_ec)==0) return stream;
405         audio_stream_free(stream);
406         return NULL;
407 }
408
409 void audio_stream_set_rtcp_information(AudioStream *st, const char *cname, const char *tool){
410         if (st->session!=NULL){
411                 rtp_session_set_source_description(st->session,cname,NULL,NULL,NULL,NULL,tool , "This is free software (GPL) !");
412         }
413 }
414
415 void audio_stream_play(AudioStream *st, const char *name){
416         if (ms_filter_get_id(st->soundread)==MS_FILE_PLAYER_ID){
417                 ms_filter_call_method_noarg(st->soundread,MS_FILE_PLAYER_CLOSE);
418                 ms_filter_call_method(st->soundread,MS_FILE_PLAYER_OPEN,(void*)name);
419                 if (st->read_resampler){
420                         audio_stream_configure_resampler(st,st->soundread,st->rtpsend);
421                 }
422                 ms_filter_call_method_noarg(st->soundread,MS_FILE_PLAYER_START);
423         }else{
424                 ms_error("Cannot play file: the stream hasn't been started with"
425                 " audio_stream_start_with_files");
426         }
427 }
428
429 void audio_stream_record(AudioStream *st, const char *name){
430         if (ms_filter_get_id(st->soundwrite)==MS_FILE_REC_ID){
431                 ms_filter_call_method_noarg(st->soundwrite,MS_FILE_REC_CLOSE);
432                 ms_filter_call_method(st->soundwrite,MS_FILE_REC_OPEN,(void*)name);
433                 ms_filter_call_method_noarg(st->soundwrite,MS_FILE_REC_START);
434         }else{
435                 ms_error("Cannot record file: the stream hasn't been started with"
436                 " audio_stream_start_with_files");
437         }
438 }
439
440
441 AudioStream *audio_stream_new(int locport, bool_t ipv6){
442         AudioStream *stream=(AudioStream *)ms_new0(AudioStream,1);
443         stream->session=create_duplex_rtpsession(locport,ipv6);
444         stream->rtpsend=ms_filter_new(MS_RTP_SEND_ID);
445         stream->play_dtmfs=TRUE;
446         stream->use_gc=FALSE;
447         stream->use_agc=FALSE;
448         stream->use_ng=FALSE;
449         return stream;
450 }
451
452 void audio_stream_play_received_dtmfs(AudioStream *st, bool_t yesno){
453         st->play_dtmfs=yesno;
454 }
455
456 int audio_stream_start_now(AudioStream *stream, RtpProfile * prof,  const char *remip, int remport, int rem_rtcp_port, int payload_type, int jitt_comp, MSSndCard *playcard, MSSndCard *captcard, bool_t use_ec){
457         return audio_stream_start_full(stream,prof,remip,remport,rem_rtcp_port,
458                 payload_type,jitt_comp,NULL,NULL,playcard,captcard,use_ec);
459 }
460
461 void audio_stream_set_relay_session_id(AudioStream *stream, const char *id){
462         ms_filter_call_method(stream->rtpsend, MS_RTP_SEND_SET_RELAY_SESSION_ID,(void*)id);
463 }
464
465 void audio_stream_set_echo_canceller_params(AudioStream *st, int tail_len_ms, int delay_ms, int framesize){
466         st->ec_tail_len=tail_len_ms;
467         st->ec_delay=delay_ms;
468         st->ec_framesize=framesize;
469 }
470
471 void audio_stream_enable_echo_limiter(AudioStream *stream, EchoLimiterType type){
472         stream->el_type=type;
473 }
474
475 void audio_stream_enable_gain_control(AudioStream *stream, bool_t val){
476         stream->use_gc=val;
477 }
478
479 void audio_stream_enable_automatic_gain_control(AudioStream *stream, bool_t val){
480         stream->use_agc=val;
481 }
482
483 void audio_stream_enable_noise_gate(AudioStream *stream, bool_t val){
484         stream->use_ng=val;
485 }
486
487 void audio_stream_set_mic_gain(AudioStream *stream, float gain){
488         if (stream->volsend){
489                 ms_filter_call_method(stream->volsend,MS_VOLUME_SET_GAIN,&gain);
490         }else ms_warning("Could not apply gain: gain control wasn't activated. "
491                         "Use audio_stream_enable_gain_control() before starting the stream.");
492 }
493
494 void audio_stream_enable_equalizer(AudioStream *stream, bool_t enabled){
495         stream->eq_active=enabled;
496         if (stream->equalizer){
497                 int tmp=enabled;
498                 ms_filter_call_method(stream->equalizer,MS_EQUALIZER_SET_ACTIVE,&tmp);
499         }
500 }
501
502 void audio_stream_equalizer_set_gain(AudioStream *stream, int frequency, float gain, int freq_width){
503         if (stream->equalizer){
504                 MSEqualizerGain d;
505                 d.frequency=frequency;
506                 d.gain=gain;
507                 d.width=freq_width;
508                 ms_filter_call_method(stream->equalizer,MS_EQUALIZER_SET_GAIN,&d);
509         }
510 }
511
512 void audio_stream_stop(AudioStream * stream)
513 {
514         if (stream->ticker){
515                 MSConnectionHelper h;
516                 ms_ticker_detach(stream->ticker,stream->soundread);
517                 ms_ticker_detach(stream->ticker,stream->rtprecv);
518
519                 rtp_stats_display(rtp_session_get_stats(stream->session),"Audio session's RTP statistics");
520
521                 /*dismantle the outgoing graph*/
522                 ms_connection_helper_start(&h);
523                 ms_connection_helper_unlink(&h,stream->soundread,-1,0);
524                 if (stream->read_resampler!=NULL)
525                         ms_connection_helper_unlink(&h,stream->read_resampler,0,0);
526                 if (stream->ec!=NULL)
527                         ms_connection_helper_unlink(&h,stream->ec,1,1);
528                 if (stream->volsend!=NULL)
529                         ms_connection_helper_unlink(&h,stream->volsend,0,0);
530                 ms_connection_helper_unlink(&h,stream->encoder,0,0);
531                 ms_connection_helper_unlink(&h,stream->rtpsend,0,-1);
532
533                 /*dismantle the receiving graph*/
534                 ms_connection_helper_start(&h);
535                 ms_connection_helper_unlink(&h,stream->rtprecv,-1,0);
536                 ms_connection_helper_unlink(&h,stream->decoder,0,0);
537                 ms_connection_helper_unlink(&h,stream->dtmfgen,0,0);
538                 if (stream->equalizer)
539                         ms_connection_helper_unlink(&h,stream->equalizer,0,0);
540                 if (stream->volrecv!=NULL)
541                         ms_connection_helper_unlink(&h,stream->volrecv,0,0);
542                 if (stream->ec!=NULL)
543                         ms_connection_helper_unlink(&h,stream->ec,0,0);
544                 if (stream->write_resampler!=NULL)
545                         ms_connection_helper_unlink(&h,stream->write_resampler,0,0);
546                 ms_connection_helper_unlink(&h,stream->soundwrite,0,-1);
547
548         }
549         audio_stream_free(stream);
550 }
551
552 RingStream * ring_start(const char *file, int interval, MSSndCard *sndcard){
553    return ring_start_with_cb(file,interval,sndcard,NULL,NULL);
554 }
555
556 RingStream * ring_start_with_cb(const char *file,int interval,MSSndCard *sndcard, MSFilterNotifyFunc func,void * user_data)
557 {
558         RingStream *stream;
559         int tmp;
560         stream=(RingStream *)ms_new0(RingStream,1);
561         stream->source=ms_filter_new(MS_FILE_PLAYER_ID);
562         if (ms_filter_call_method(stream->source,MS_FILE_PLAYER_OPEN,(void*)file)<0){
563                 ms_filter_destroy(stream->source);
564                 ms_free(stream);
565                 return NULL;
566         }
567         ms_filter_call_method(stream->source,MS_FILE_PLAYER_LOOP,&interval);
568         ms_filter_call_method_noarg(stream->source,MS_FILE_PLAYER_START);
569         if (func!=NULL)
570                 ms_filter_set_notify_callback(stream->source,func,user_data);
571         stream->sndwrite=ms_snd_card_create_writer(sndcard);
572         ms_filter_call_method(stream->source,MS_FILTER_GET_SAMPLE_RATE,&tmp);
573         ms_filter_call_method(stream->sndwrite,MS_FILTER_SET_SAMPLE_RATE,&tmp);
574         ms_filter_call_method(stream->source,MS_FILTER_GET_NCHANNELS,&tmp);
575         ms_filter_call_method(stream->sndwrite,MS_FILTER_SET_NCHANNELS,&tmp);
576         stream->ticker=ms_ticker_new();
577         ms_ticker_set_name(stream->ticker,"Audio (ring) MSTicker");
578         ms_filter_link(stream->source,0,stream->sndwrite,0);
579         ms_ticker_attach(stream->ticker,stream->source);
580         return stream;
581 }
582
583 void ring_stop(RingStream *stream){
584         ms_ticker_detach(stream->ticker,stream->source);
585         ms_filter_unlink(stream->source,0,stream->sndwrite,0);
586         ms_ticker_destroy(stream->ticker);
587         ms_filter_destroy(stream->source);
588         ms_filter_destroy(stream->sndwrite);
589         ms_free(stream);
590 #ifdef _WIN32_WCE
591         ms_warning("Sleeping a bit after closing the audio device...");
592         ms_sleep(1);
593 #endif
594 }
595
596
597 int audio_stream_send_dtmf(AudioStream *stream, char dtmf)
598 {
599         if (stream->rtpsend)
600                 ms_filter_call_method(stream->rtpsend,MS_RTP_SEND_SEND_DTMF,&dtmf);
601         if (stream->dtmfgen)
602                 ms_filter_call_method(stream->dtmfgen,MS_DTMF_GEN_PUT,&dtmf);
603         return 0;
604 }