source: mediastreamer2/src/audiostream.c @ 1002:980eb537ba69

Last change on this file since 1002:980eb537ba69 was 1002:980eb537ba69, checked in by Simon Morlat <simon.morlat@…>, 3 years ago

make speex encoder use a generic interface

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