source: verona/phapi/phms_audiostream.c @ 131:acaf0886270b

Last change on this file since 131:acaf0886270b was 131:acaf0886270b, checked in by Vadim Lebedev <vadim@…>, 2 years ago

BIG patch to bring old verona to the XXX level

File size: 37.3 KB
Line 
1/*
2mediastreamer2 library - modular sound and video processing and streaming
3
4 * Copyright (C) 2008 Halina Nowak <halina@mbdsys.com>
5 * Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)
6
7This program is free software; you can redistribute it and/or
8modify it under the terms of the GNU General Public License
9as published by the Free Software Foundation; either version 2
10of the License, or (at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program; if not, write to the Free Software
19Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 */
21
22#include "phglobal.h"
23
24#ifdef HAVE_CONFIG_H
25#include "mediastreamer-config.h"
26#endif
27
28#ifdef INET6
29#include <sys/types.h>
30#ifndef WIN32
31#include <sys/socket.h>
32#include <netdb.h>
33#endif
34#endif
35
36
37#include <mediastreamer2/mediastream.h>
38#include <mediastreamer2/allfilters.h>
39#include <mediastreamer2/mscommon.h>
40#include <mediastreamer2/msvolume.h>
41
42#include <mediastreamer2/dtmfgen.h>
43#include <mediastreamer2/mssndcard.h>
44#include <mediastreamer2/msrtp.h>
45#include <mediastreamer2/msfileplayer.h>
46#include <mediastreamer2/msfilerec.h>
47#include <osip2/osip.h>
48
49#if defined(OS_WIN32) || defined(_WIN32_WCE)
50#define snprintf _snprintf
51#ifndef _WIN32_WCE
52#define strncasecmp strnicmp
53#endif /* !_WIN32_WCE */
54#define strcasecmp stricmp
55#endif
56
57
58
59#include "phapi.h"
60#include "phms.h"
61#include "phms_audiostream.h"
62
63void rtp_session_rtcp_parse(RtpSession *session, mblk_t *mp);
64
65
66#ifndef USE_PHMS_AUDIOSTREAM
67int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char *remip,int remport,
68                int rem_rtcp_port, int payload,int jitt_comp, const char *infile, const char *outfile,
69                MSSndCard *playcard, MSSndCard *captcard, bool_t use_ec);
70#endif
71
72
73#ifdef ENABLE_PORTAUDIO
74//extern MSSndCardDesc pasnd_card_desc;
75#endif
76
77#define MAX_RTP_SIZE    1500
78
79/** Default size of jitter buffer (ms). */
80const int DEFAULT_JITTER_BUFFER = 120;
81//const int DEFAULT_JITTER_BUFFER = 60;
82//const int DEFAULT_JITTER_BUFFER = RTP_DEFAULT_JITTER_TIME;
83
84/** Environment variable setting jitter buffer (ms). */
85const char* JITTER_BUFFER_ENV = "PH_JITTER_BUFFER_MS";
86
87void audio_stream_change_decoder(AudioStream *stream, int payload);
88
89
90void ph_media_audio_init()
91{
92        return;
93}
94
95void audio_display_stats(RtpSession *session)
96{
97        JBParameters par;
98        rtp_stats_display(rtp_session_get_stats(session),"Audio session's RTP statistics");
99        rtp_session_get_jitter_buffer_params(session, &par);
100        ortp_log(ORTP_MESSAGE, "jitter min_size %d",par.min_size);
101        ortp_log(ORTP_MESSAGE, "jitter nom_size %d",par.nom_size);
102        ortp_log(ORTP_MESSAGE, "jitter max_size %d", par.max_size);
103        ortp_log(ORTP_MESSAGE, "adaptive jitter:%d", par.adaptive);
104        ortp_log(ORTP_MESSAGE, "rtp max_rq_size:%d", par.max_packets);
105}
106
107
108/* this code is not part of the library itself, it is part of the mediastream program */
109void audio_stream_free(AudioStream *stream);
110void phms_audio_stream_free(AudioStream *stream)
111{
112        if (stream->session!=NULL)
113        {
114                // Wengo Julien - Add OWSL support
115                if (stream->session->rtp.tr)
116                {
117                        ph_rtp_transport_data_t *user_data = stream->session->rtp.tr->data;
118
119                        if (user_data)
120                        {
121#if defined(OS_WIN32) || defined(_WIN32_WCE)
122                                closesocket(user_data->rtp_sock);
123                                closesocket(user_data->rtcp_sock);
124#else
125                                close(user_data->rtp_sock);
126                                close(user_data->rtcp_sock);
127#endif
128                        }
129                }
130                rtp_session_destroy(stream->session);
131        }
132        if (stream->rtpsend!=NULL) ms_filter_destroy(stream->rtpsend);
133        if (stream->rtprecv!=NULL) ms_filter_destroy(stream->rtprecv);
134        if (stream->volsend!=NULL) ms_filter_destroy(stream->volsend);
135        if (stream->volrecv!=NULL) ms_filter_destroy(stream->volrecv);
136        if (stream->soundread!=NULL) ms_filter_destroy(stream->soundread);
137        if (stream->dtmfgen2!=NULL) ms_filter_destroy(stream->dtmfgen2);
138        if (stream->soundwrite!=NULL) ms_filter_destroy(stream->soundwrite);
139        if (stream->encoder!=NULL) ms_filter_destroy(stream->encoder);
140        if (stream->decoder!=NULL) ms_filter_destroy(stream->decoder);
141        if (stream->dtmfgen!=NULL) ms_filter_destroy(stream->dtmfgen);
142        if (stream->ec!=NULL)   ms_filter_destroy(stream->ec);
143#ifdef PH_FORCE_16KHZ
144        if (stream->downsample!=NULL)   ms_filter_destroy(stream->downsample);
145        if (stream->upsample!=NULL)     ms_filter_destroy(stream->upsample);
146#endif
147        if (stream->ticker!=NULL) ms_ticker_destroy(stream->ticker);
148        ms_free(stream);
149}
150
151static void phms_payload_type_changed(RtpSession *session, unsigned long data){
152        AudioStream *stream=(AudioStream*)data;
153        int pt=rtp_session_get_recv_payload_type(stream->session);
154        audio_stream_change_decoder(stream,pt);
155}
156
157static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
158
159static void phms_on_dtmf_received(RtpSession *s, int dtmf, void * user_data)
160{
161        struct ph_msession_s *ms = (struct ph_msession_s *)user_data;
162        phms_audio_stream_t *phstream;
163        AudioStream *stream;
164        MSFilter* dtmfgen= NULL;
165
166        phstream = (phms_audio_stream_t *)(ms->streams[PH_MSTREAM_AUDIO1].streamerData);
167        if (!phstream)
168                return;
169
170        stream = (AudioStream *)(phstream->stream);
171        if (!stream)
172                return;
173
174        if(stream)
175        {
176                dtmfgen=(MSFilter*)stream->dtmfgen;
177        }
178        else
179        {
180                ms_message("No AudioStream!");
181                return;
182        }
183        if (dtmf>15){
184                ms_warning("Unsupported telephone-event type.");
185                return;
186        }
187        ms_message("Receiving dtmf %c.",dtmf_tab[dtmf]);
188        if (dtmfgen!=NULL)
189        {
190                ms_filter_call_method(dtmfgen,MS_DTMF_GEN_PUT,&dtmf_tab[dtmf]);
191        }
192        if (ms && ms->cbkInfo)
193        {
194                /*  announce reception of DTMF event */
195                ms->dtmfCallback(ms->cbkInfo, dtmf_tab[dtmf]);
196        }
197}
198
199#if 0
200
201static void on_timestamp_jump(RtpSession *s,uint32_t* ts, void * user_data)
202{
203        ms_warning("The remote sip-phone has send data with a future timestamp: %u,"
204                        "resynchronising session.",*ts);
205        rtp_session_reset(s);
206}
207
208#endif
209
210MSSndCard *phms_get_read_soundcard(const char *device)
211{
212        int devlen=0;
213        char *in;
214        char *temp;
215        ph_config_t *cfg = ph_get_config();
216        if(device == NULL)
217        {
218                device = cfg->audio_dev;
219        }
220
221        devlen = strlen(device);
222        if (devlen != 0)
223        {
224                char *devid;
225
226                temp = alloca(devlen);
227                strcpy(temp, device);
228                if ((in = strstr(temp,"IN=")) != NULL)
229                {
230                        devid = strtok(in + 3, ";");
231                        if (devid != NULL)
232                                return ms_snd_card_manager_get_card(ms_snd_card_manager_get(),devid);
233                }
234        }
235        return(ms_snd_card_manager_get_default_capture_card(ms_snd_card_manager_get()));
236}
237
238MSSndCard *phms_get_write_soundcard(const char *device)
239{
240        int devlen=0;
241        char *temp;
242        char *out;
243        ph_config_t *cfg = ph_get_config();
244
245        if(device == NULL)
246        {
247                device = cfg->audio_dev;
248        }
249
250        devlen = strlen(device);
251        if (devlen != 0)
252        {
253                char *devid;
254
255                temp = alloca(devlen);
256                strcpy(temp, device);
257                if ((out = strstr(temp,"OUT=")) != NULL)
258                {
259                        devid = strtok(out + 4, ";");
260                        if (devid != NULL)
261                                return ms_snd_card_manager_get_card(ms_snd_card_manager_get(),devid);
262                }
263
264        }
265        return(ms_snd_card_manager_get_default_playback_card(ms_snd_card_manager_get()));
266}
267
268MSFilter *phms_get_soundread(char *device)
269{
270        MSSndCard *soundcard=phms_get_read_soundcard(device);
271        if(soundcard)
272                return(ms_snd_card_create_reader(soundcard));
273        else
274                return NULL;
275}
276MSFilter *phms_get_soundwrite(char *device)
277{
278        MSSndCard *soundcard=phms_get_write_soundcard(device);
279        if(soundcard)
280                return(ms_snd_card_create_writer(soundcard));
281        else
282                return NULL;
283}
284phms_audio_stream_t* phms_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)
285{
286        phms_audio_stream_t *audio_stream;
287        if (playcard==NULL) {
288                ms_error("No playback card.");
289                return NULL;
290        }
291        if (captcard==NULL) {
292                ms_error("No capture card.");
293                return NULL;
294        }
295        audio_stream = malloc(sizeof(*audio_stream));
296        audio_stream->capt_sndcard = captcard;
297        audio_stream->play_sndcard = playcard;
298        audio_stream->stream = audio_stream_start_with_sndcards(prof,locport,remip,remport,profile,jitt_comp,playcard,captcard,use_ec);
299        return audio_stream;
300}
301
302
303int phms_audio_init();
304
305#if 0
306//TODO: il faut porter les modifs d'halina sur MSTicker et sur pasnd/autres sndcard pour que cette fonction soit util.
307static int force_audio_timebase(MSFilter *filter, int yesno)
308{
309        int tmp = yesno;
310        if(filter)
311                return (ms_filter_call_method(filter, MS_FILTER_SET_AUDIO_TIMEBASE, &tmp));
312        return -1;
313}
314
315#else
316
317static int force_audio_timebase(MSFilter *filter, int yesno){return 0;}
318
319#endif
320
321
322static int link_full_audio_call(AudioStream *stream)
323{
324        if (stream->ec !=NULL){
325                //              FILTER_LINK(stream->dtmfgen2,0,stream->ec,1);
326                //              FILTER_LINK(stream->ec,1,stream->encoder,0);
327#ifdef PH_FORCE_16KHZ
328                FILTER_LINK(stream->soundread,0,stream->volsend,0);
329                FILTER_LINK(stream->volsend,0,stream->downsample,0);
330                FILTER_LINK(stream->downsample,0,stream->ec,1);
331                FILTER_LINK(stream->ec,0,stream->upsample,0);
332                FILTER_LINK(stream->upsample,0,stream->volrecv,0);
333                FILTER_LINK(stream->volrecv,0,stream->soundwrite,0);
334#else
335                FILTER_LINK(stream->soundread,0,stream->volsend,0);
336                FILTER_LINK(stream->volsend,0,stream->ec,1);
337                FILTER_LINK(stream->ec,0,stream->volrecv,0);
338                FILTER_LINK(stream->volrecv,0,stream->soundwrite,0);
339#endif         
340                FILTER_LINK(stream->ec,1,stream->dtmfgen2,0);
341                FILTER_LINK(stream->dtmfgen2, 0,stream->encoder,0);
342                FILTER_LINK(stream->dtmfgen,0,stream->ec,0);
343
344        }else{
345#ifdef PH_FORCE_16KHZ
346                FILTER_LINK(stream->soundread,0,stream->volsend,0);
347                FILTER_LINK(stream->volsend,0,stream->downsample,0);
348                FILTER_LINK(stream->downsample,0,stream->dtmfgen2,0);
349                FILTER_LINK(stream->dtmfgen,0,stream->upsample,0);
350                FILTER_LINK(stream->upsample,0,stream->volrecv,0);
351                FILTER_LINK(stream->volrecv,0,stream->soundwrite,0);
352#else
353                FILTER_LINK(stream->soundread,0,stream->volsend,0);
354                FILTER_LINK(stream->volsend,0,stream->dtmfgen2,0);
355                FILTER_LINK(stream->dtmfgen,0,stream->volrecv,0);
356                FILTER_LINK(stream->volrecv,0,stream->soundwrite,0);
357#endif         
358                FILTER_LINK(stream->dtmfgen2,0,stream->encoder,0);
359        }
360        FILTER_LINK(stream->encoder,0,stream->rtpsend,0);
361        FILTER_LINK(stream->rtprecv,0,stream->decoder,0);
362        FILTER_LINK(stream->decoder,0,stream->dtmfgen,0);
363        return 0;
364}
365
366static int unlink_full_audio_call(AudioStream *stream)
367{
368
369        if (stream->ec!=NULL){
370#ifdef PH_FORCE_16KHZ
371                FILTER_UNLINK(stream->soundread,0,stream->volsend,0);
372                FILTER_UNLINK(stream->volsend,0,stream->downsample,0);
373                FILTER_UNLINK(stream->downsample,0, stream->ec,1);
374                FILTER_UNLINK(stream->ec,0,stream->upsample,0);
375                FILTER_UNLINK(stream->upsample,0,stream->volrecv,0);
376                FILTER_UNLINK(stream->volrecv,0,stream->soundwrite,0);
377#else
378                FILTER_UNLINK(stream->soundread,0,stream->volsend,0);
379                FILTER_UNLINK(stream->volsend,0,stream->ec,1);
380                FILTER_UNLINK(stream->ec,0,stream->volrecv,0);
381                FILTER_UNLINK(stream->volrecv,0,stream->soundwrite,0);
382#endif                 
383                FILTER_UNLINK(stream->ec,1,stream->dtmfgen2,0);
384                FILTER_UNLINK(stream->dtmfgen2, 0,stream->encoder,0);
385                FILTER_UNLINK(stream->dtmfgen,0,stream->ec,0);
386        }else{
387#ifdef PH_FORCE_16KHZ
388                FILTER_UNLINK(stream->soundread,0,stream->volsend,0);
389                FILTER_UNLINK(stream->volsend,0,stream->downsample,0);
390                FILTER_UNLINK(stream->downsample,0,stream->dtmfgen2,0);
391                FILTER_UNLINK(stream->dtmfgen,0,stream->upsample,0);
392                FILTER_UNLINK(stream->upsample,0,stream->volrecv,0);
393                FILTER_UNLINK(stream->volrecv,0,stream->soundwrite,0);
394#else
395                FILTER_UNLINK(stream->soundread,0,stream->volsend,0);
396                FILTER_UNLINK(stream->volsend,0,stream->dtmfgen2,0);
397                FILTER_UNLINK(stream->dtmfgen,0,stream->volrecv,0);
398                FILTER_UNLINK(stream->volrecv,0,stream->soundwrite,0);
399#endif                 
400                FILTER_UNLINK(stream->dtmfgen2,0,stream->encoder,0);
401        }
402
403        FILTER_UNLINK(stream->encoder,0,stream->rtpsend,0);
404        FILTER_UNLINK(stream->rtprecv,0,stream->decoder,0);
405        FILTER_UNLINK(stream->decoder,0,stream->dtmfgen,0);
406        return 0;
407}
408
409static void
410phms_on_qos_change(RtpSession *rtp_session,  struct ph_msession_s *s)
411{
412        RtpQosInfo* qos = &rtp_session->qos;
413        int newx = !qos->curx;
414
415        printf("QOS seq=%u tot.losses=%u remotej=%u int.losses=%u int.packets=%u lossf=%u rtt=%u\n",
416                        qos->data[newx].seqnum, qos->data[newx].total_losses, qos->data[newx].remote_jitter,
417                        qos->data[newx].interval_losses, qos->data[newx].interval_packets, qos->data[newx].loss_fraction, qos->data[newx].rtt);
418
419}
420
421int phms_audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char *remip,int remport,
422                int rem_rtcp_port, int payload,int jitt_comp, const char *infile, const char *outfile,
423                MSSndCard *playcard, MSSndCard *captcard, bool_t use_ec, struct ph_msession_s *msession, int use_tr_sock)
424{
425        RtpSession *rtps=stream->session;
426        int jitt = jitt_comp;
427        PayloadType *pt;
428        int dtmf_dur = 160;
429        int tmp;
430        int clock_rate;
431        int framesize = 160;
432
433        rtp_session_set_profile(rtps,profile);
434
435
436        if (!use_tr_sock)
437        {
438                if (remport>0 && rem_rtcp_port>0)
439                        rtp_session_set_remote_addr_full(rtps,remip,remport,rem_rtcp_port);
440                else if (remport>0)
441                        rtp_session_set_remote_addr(rtps,remip,remport);
442        }
443        else
444        {
445                rtp_session_set_sockets(rtps, remport, rem_rtcp_port);
446        }
447
448
449        rtp_session_set_payload_type(rtps,payload);
450
451        if (!jitt)
452        {
453                jitt = ph_getenv_int(JITTER_BUFFER_ENV, DEFAULT_JITTER_BUFFER);
454        }
455        rtp_session_set_jitter_compensation(rtps,jitt);
456        rtp_session_enable_adaptive_jitter_compensation(rtps,FALSE);
457
458        rtp_session_enable_rtcp(rtps, FALSE);
459        if (remport>0)
460                ms_filter_call_method(stream->rtpsend,MS_RTP_SEND_SET_SESSION,rtps);
461        //ms_filter_call_method(stream->rtpsend, MS_FILTER_SET_DTMF_DURATION, &dtmf_dur);
462        stream->rtprecv=ms_filter_new(MS_RTP_RECV_ID);
463        ms_filter_call_method(stream->rtprecv,MS_RTP_RECV_SET_SESSION,rtps);
464        stream->session=rtps;
465
466        stream->dtmfgen=ms_filter_new(MS_DTMF_GEN_ID);
467        rtp_session_signal_connect(rtps,"telephone-event",(RtpCallback)phms_on_dtmf_received,(unsigned long)msession);
468        rtp_session_signal_connect(rtps,"payload_type_changed",(RtpCallback)phms_payload_type_changed,(unsigned long)stream);
469        rtp_session_signal_connect(rtps, "qos_event",  (RtpCallback) phms_on_qos_change, (unsigned long)msession);
470        //ms_filter_call_method(stream->rtpsend, MS_FILTER_SET_DTMF_DURATION, &dtmf_dur);
471
472        /* creates the local part */
473        if (captcard!=NULL) stream->soundread=ms_snd_card_create_reader(captcard);
474        else {
475                stream->soundread=ms_filter_new(MS_FILE_PLAYER_ID);
476                if (infile!=NULL) audio_stream_play(stream,infile);
477        }
478        if (playcard!=NULL) stream->soundwrite=ms_snd_card_create_writer(playcard);
479        else {
480                stream->soundwrite=ms_filter_new(MS_FILE_REC_ID);
481                if (outfile!=NULL) audio_stream_record(stream,outfile);
482        }
483        stream->dtmfgen2=ms_filter_new(MS_DTMF_GEN_ID);
484        //      ms_filter_call_method(stream->dtmfgen2, MS_FILTER_SET_DTMF_DURATION, &dtmf_dur);
485
486        /* creates the couple of encoder/decoder */
487        pt=rtp_profile_get_payload(profile,payload);
488        if (pt==NULL){
489                ms_error("audiostream.c: undefined payload type.");
490                return -1;
491        }
492        clock_rate = pt->clock_rate;
493#ifdef PH_FORCE_16KHZ
494        if(clock_rate == 8000)
495        {
496                clock_rate = 16000;
497        }
498
499        ms_warning("resample %d to %d",pt->clock_rate, clock_rate);
500        stream->downsample = ms_filter_new(MS_RESAMPLE_ID);
501        stream->upsample = ms_filter_new(MS_RESAMPLE_ID);
502        ms_filter_call_method(stream->downsample, MS_FILTER_SET_OUTPUT_SAMPLE_RATE, &pt->clock_rate);
503        ms_filter_call_method(stream->downsample, MS_FILTER_SET_SAMPLE_RATE, &clock_rate);
504        ms_filter_call_method(stream->upsample, MS_FILTER_SET_OUTPUT_SAMPLE_RATE, &clock_rate);
505        ms_filter_call_method(stream->upsample, MS_FILTER_SET_SAMPLE_RATE, &pt->clock_rate);
506
507#endif
508
509        stream->encoder=ms_filter_create_encoder(pt->mime_type);
510        stream->decoder=ms_filter_create_decoder(pt->mime_type);
511        if ((stream->encoder==NULL) || (stream->decoder==NULL)){
512                /* big problem: we have not a registered codec for this payload...*/
513                ms_error("mediastream.c: No decoder available for payload %i.",payload);
514                return -1;
515        }
516        ms_warning("use ec %i",use_ec);
517        if (use_ec) {
518                stream->ec=ms_filter_new(MS_SPEEX_EC_ID);
519                ms_filter_call_method(stream->ec,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate);
520                //ms_filter_call_method(stream->ec,MS_FILTER_SET_FRAMESIZE,&framesize);
521        }
522        else
523        {
524                stream->ec = NULL;
525        }
526
527        stream->volsend=ms_filter_new(MS_VOLUME_ID);
528        stream->volrecv=ms_filter_new(MS_VOLUME_ID);
529        /* give the sound filters some properties */
530
531
532        ms_filter_call_method(stream->soundread,MS_FILTER_SET_SAMPLE_RATE,&clock_rate);
533        ms_filter_call_method(stream->soundwrite,MS_FILTER_SET_SAMPLE_RATE,&clock_rate);
534        tmp=1;
535        ms_filter_call_method(stream->soundwrite,MS_FILTER_SET_NCHANNELS, &tmp);
536
537        /* give the encoder/decoder some parameters*/
538        ms_filter_call_method(stream->encoder,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate);
539        ms_message("Payload's bitrate is %i",pt->normal_bitrate);
540        if (pt->normal_bitrate>0){
541                ms_message("Setting audio encoder network bitrate to %i",pt->normal_bitrate);
542                ms_filter_call_method(stream->encoder,MS_FILTER_SET_BITRATE,&pt->normal_bitrate);
543        }
544        ms_filter_call_method(stream->decoder,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate);
545        ms_filter_call_method(stream->dtmfgen,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate);
546        ms_filter_call_method(stream->dtmfgen2,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate);
547
548        if (pt->send_fmtp!=NULL) ms_filter_call_method(stream->encoder,MS_FILTER_ADD_FMTP, (void*)pt->send_fmtp);
549        if (pt->recv_fmtp!=NULL) ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp);
550
551        /* and then connect all */
552        /* tip: draw yourself the picture if you don't understand */
553
554
555        /* create ticker */
556        stream->ticker=ms_ticker_new();
557
558        link_full_audio_call(stream);
559
560        ms_ticker_attach(stream->ticker,stream->rtprecv);
561        if(!use_ec)
562                ms_ticker_attach(stream->ticker,stream->soundread);
563        force_audio_timebase(stream->soundread, 1);
564        return 0;
565}
566
567phms_audio_stream_t*
568phms_audio_stream_start(RtpProfile *prof,int locport,const char *remip,int remport,int rem_rtcp_port,int payload,int jitt_comp,bool_t use_ec, struct ph_msession_s *ms, const char *device, int use_tr_sock)
569{
570        MSSndCard *capt_sndcard = 0, *play_sndcard = 0;
571        AudioStream *stream;
572        RtpSession *rtps;
573        char *infile = 0, *outfile=0;
574
575#ifdef ENABLE_PORTAUDIO
576        //      ms_reload_snd_card(&pasnd_card_desc);
577#endif
578
579        if ((infile = strstr(device,"INFILE=")) != NULL && (outfile = strstr(device,"OUTFILE=")) != NULL)
580        {
581                infile = strtok(infile + 7, ";");
582                if (infile == NULL)
583                        return NULL;
584
585                outfile = strtok(outfile + 8, ";");
586                if (outfile == NULL)
587                        return NULL;
588        }
589        else
590        {
591                capt_sndcard=phms_get_read_soundcard(device);
592                play_sndcard=phms_get_write_soundcard(device);
593        }
594
595        stream=audio_stream_new(locport, ms_is_ipv6(remip));
596
597        rtps=stream->session;
598
599        rtp_session_set_profile(rtps,prof);
600
601
602        if (!use_tr_sock)
603        {
604                if (remport>0 && rem_rtcp_port>0)
605                        rtp_session_set_remote_addr_full(rtps,remip,remport,rem_rtcp_port);
606                else if (remport>0)
607                        rtp_session_set_remote_addr(rtps,remip,remport);
608        }
609        else
610        {
611                rtp_session_set_sockets(rtps, remport, rem_rtcp_port);
612        }
613
614        ms_filter_call_method(stream->rtpsend,MS_RTP_SEND_SET_SESSION,rtps);
615        rtp_session_signal_connect(rtps, "qos_event",  (RtpCallback) phms_on_qos_change, (unsigned long) ms);
616        rtp_session_signal_connect(rtps,"telephone-event",(RtpCallback)phms_on_dtmf_received,(unsigned long)ms);
617        rtp_session_signal_connect(rtps,"rtcp_packet",(RtpCallback)rtp_session_rtcp_parse, 0);
618        rtp_session_enable_jitter_buffer(rtps,1);
619
620        stream->session=rtps;
621        stream->use_gc = 1;
622
623#ifdef USE_PHMS_AUDIOSTREAM
624        if(0==phms_audio_stream_start_full(stream, prof,remip,remport, rem_rtcp_port, payload, jitt_comp,NULL,NULL, play_sndcard, capt_sndcard, use_ec, ms, use_tr_sock))
625#else
626                if(0==audio_stream_start_full(stream, prof,remip,0, rem_rtcp_port, payload, jitt_comp, infile, outfile, play_sndcard, capt_sndcard, use_ec))
627#endif
628                {
629                        phms_audio_stream_t *audio_stream = osip_malloc(sizeof(*audio_stream));
630                        audio_stream->stream = stream;
631                        audio_stream->capt_sndcard = capt_sndcard;
632                        audio_stream->play_sndcard = play_sndcard;
633                        if (infile) //auto loop at eof
634                        {
635                                int loop = 0; //ms before relooping, -1 to disable
636                                ms_filter_call_method(stream->soundread,MS_FILE_PLAYER_LOOP,&loop);
637                        }
638                        return audio_stream;
639                }
640                else
641                {
642#ifdef USE_PHMS_AUDIOSTREAM
643                        phms_audio_stream_free(stream);
644#else
645                        audio_stream_free(stream);
646#endif
647                }
648        return NULL;
649}
650
651void phms_audio_stream_set_soft_recv_volume_gain(ph_msession_t *s, float gain)
652{
653        phms_audio_stream_t* stream = (phms_audio_stream_t*)s->streams[PH_MSTREAM_AUDIO1].streamerData;
654        if (stream && stream->stream && stream->stream->volrecv)
655                ms_filter_call_method(stream->stream->volrecv, MS_VOLUME_SET_GAIN, &gain);
656}
657void phms_audio_stream_set_soft_send_volume_gain(ph_msession_t *s, float gain)
658{
659        phms_audio_stream_t* stream = (phms_audio_stream_t*)s->streams[PH_MSTREAM_AUDIO1].streamerData;
660        if (stream && stream->stream && stream->stream->volsend)
661                ms_filter_call_method(stream->stream->volsend, MS_VOLUME_SET_GAIN, &gain);
662}
663
664void phms_audio_stream_set_recv_volume_level(ph_msession_t *s, int level)
665{
666        phms_audio_stream_t* stream = (phms_audio_stream_t*)s->streams[PH_MSTREAM_AUDIO1].streamerData;
667        if (stream->play_sndcard) ms_snd_card_set_level(stream->play_sndcard,MS_SND_CARD_PLAYBACK,level);
668
669}
670void phms_audio_stream_set_send_volume_level(ph_msession_t *s, int level)
671{
672        phms_audio_stream_t* stream = (phms_audio_stream_t*)s->streams[PH_MSTREAM_AUDIO1].streamerData;
673        if (stream->capt_sndcard) ms_snd_card_set_level(stream->play_sndcard,MS_SND_CARD_CAPTURE,level);
674}
675
676void phms_audio_stream_mute_playback(ph_msession_t *s, int val)
677{
678        phms_audio_stream_t* stream = (phms_audio_stream_t*)s->streams[PH_MSTREAM_AUDIO1].streamerData;
679        if (stream->capt_sndcard) ms_snd_card_set_control(stream->capt_sndcard,MS_SND_CARD_PLAYBACK_MUTE, val);
680}
681
682void phms_audio_stream_mute_capture(ph_msession_t *s, int val)
683{
684        phms_audio_stream_t* stream = (phms_audio_stream_t*)s->streams[PH_MSTREAM_AUDIO1].streamerData;
685        if (stream->capt_sndcard) ms_snd_card_set_control(stream->capt_sndcard,MS_SND_CARD_CAPTURE_MUTE, val);
686}
687
688AudioStream *phms_audio_stream_new(int locport, bool_t ipv6){
689        return audio_stream_new(locport, ipv6);
690}
691
692void phms_audio_stream_stop(AudioStream * stream)
693{
694        audio_display_stats(stream->session);
695
696        if (stream->ticker){
697                force_audio_timebase(stream->soundread, 0);
698                ms_ticker_detach(stream->ticker,stream->soundread);
699                ms_ticker_detach(stream->ticker,stream->rtprecv);
700        }
701        if (stream->ec!=NULL){
702#ifdef PH_FORCE_16KHZ
703                FILTER_UNLINK(stream->soundread,0,stream->volsend,0);
704                FILTER_UNLINK(stream->volsend,0,stream->downsample,0);
705                FILTER_UNLINK(stream->downsample,0, stream->ec,1);
706                FILTER_UNLINK(stream->ec,0,stream->upsample,0);
707                FILTER_UNLINK(stream->upsample,0,stream->volrecv,0);
708                FILTER_UNLINK(stream->volrecv,0,stream->soundwrite,0);
709#else
710                FILTER_UNLINK(stream->soundread,0,stream->volsend,0);
711                FILTER_UNLINK(stream->volsend,0,stream->ec,1);
712                FILTER_UNLINK(stream->ec,0,stream->volrecv,0);
713                FILTER_UNLINK(stream->volrecv,0,stream->soundwrite,0);
714#endif
715                FILTER_UNLINK(stream->ec,1,stream->dtmfgen2,0);
716                FILTER_UNLINK(stream->dtmfgen2, 0,stream->encoder,0);
717                FILTER_UNLINK(stream->dtmfgen,0,stream->ec,0);
718        }else{
719#ifdef PH_FORCE_16KHZ
720                FILTER_UNLINK(stream->soundread,0,stream->volsend,0);
721                FILTER_UNLINK(stream->volsend,0,stream->downsample,0);
722                FILTER_UNLINK(stream->downsample,0,stream->dtmfgen2,0);
723                FILTER_UNLINK(stream->dtmfgen,0,stream->upsample,0);
724                FILTER_UNLINK(stream->upsample,0,stream->volrecv,0);
725                FILTER_UNLINK(stream->volrecv,0,stream->soundwrite,0);
726#else
727                FILTER_UNLINK(stream->soundread,0,stream->volsend,0);
728                FILTER_UNLINK(stream->volsend,0,stream->dtmfgen2,0);
729                FILTER_UNLINK(stream->dtmfgen,0,stream->volrecv,0);
730                FILTER_UNLINK(stream->volrecv,0,stream->soundwrite,0);
731#endif
732                FILTER_UNLINK(stream->dtmfgen2,0,stream->encoder,0);
733        }
734
735        FILTER_UNLINK(stream->encoder,0,stream->rtpsend,0);
736        FILTER_UNLINK(stream->rtprecv,0,stream->decoder,0);
737        FILTER_UNLINK(stream->decoder,0,stream->dtmfgen,0);
738
739        if (stream->session!=NULL) rtp_session_destroy(stream->session);
740        if (stream->rtpsend!=NULL) ms_filter_destroy(stream->rtpsend);
741        if (stream->rtprecv!=NULL) ms_filter_destroy(stream->rtprecv);
742        if (stream->volsend!=NULL) ms_filter_destroy(stream->volsend);
743        if (stream->volrecv!=NULL) ms_filter_destroy(stream->volrecv);
744        if (stream->soundread!=NULL) ms_filter_destroy(stream->soundread);
745        if (stream->soundwrite!=NULL) ms_filter_destroy(stream->soundwrite);
746        if (stream->encoder!=NULL) ms_filter_destroy(stream->encoder);
747        if (stream->decoder!=NULL) ms_filter_destroy(stream->decoder);
748        if (stream->dtmfgen!=NULL) ms_filter_destroy(stream->dtmfgen);
749        if (stream->dtmfgen2!=NULL) ms_filter_destroy(stream->dtmfgen2);
750        if (stream->ec!=NULL)   ms_filter_destroy(stream->ec);
751        if (stream->ticker!=NULL) ms_ticker_destroy(stream->ticker);
752        ms_free(stream);
753}
754
755int phms_audio_send_dtmf(struct ph_msession_s *s, int dtmf, int mode)
756{
757        phms_audio_stream_t *phstream;
758        AudioStream *stream;
759
760        phstream = (phms_audio_stream_t *)(s->streams[PH_MSTREAM_AUDIO1].streamerData);
761        if (!phstream)
762                return -1;
763        stream = (AudioStream *)(phstream->stream);
764        if (!stream)
765                return -1;
766        if (!mode || mode > DTMF_BOTH)
767        {
768                mode = DTMF_BOTH;
769        }
770        //      stream->sent_dtmfs=mode;
771        return(audio_stream_send_dtmf(stream, dtmf));
772}
773
774int phms_audio_stream_suspend(AudioStream *stream,  int traffictype)
775{
776        MSTicker *ticker = stream->ticker;
777        if(stream->ticker)
778        {
779                //ms_mutex_lock(&ticker->lock);
780                force_audio_timebase(stream->soundread, 0);
781                if(stream->soundread && (traffictype & PH_MSTREAM_TRAFFIC_OUT))
782                {
783                        ms_ticker_detach(stream->ticker, stream->soundread);
784                }
785                if(stream->rtprecv && (traffictype & PH_MSTREAM_TRAFFIC_IN))
786                {
787                        ms_ticker_detach(stream->ticker, stream->rtprecv);
788                }
789                //ms_mutex_unlock(&ticker->lock);
790        }
791        return 0;
792}
793int phms_audio_stream_resume(AudioStream *stream,  int traffictype)
794{
795        MSTicker *ticker = stream->ticker;
796
797        if(stream->ticker)
798        {
799                //ms_mutex_lock(&ticker->lock);
800                if(stream->soundread && (traffictype & PH_MSTREAM_TRAFFIC_OUT))
801                {
802                        ms_ticker_attach(stream->ticker, stream->soundread);
803                }
804                if(stream->rtprecv  && (traffictype & PH_MSTREAM_TRAFFIC_IN))
805                {
806                        ms_ticker_attach(stream->ticker, stream->rtprecv);
807                }
808                //ms_mutex_unlock(&ticker->lock);
809                force_audio_timebase(stream->soundread, 1);
810        }
811        return 0;
812}
813
814int phms_audio_send_sound_file(struct ph_msession_s *s, const char *filename)
815{
816        AudioStream *stream;
817        phms_audio_stream_t *phstream;
818
819        if (!filename)
820                return -1;
821
822        phstream = (phms_audio_stream_t *)(s->streams[PH_MSTREAM_AUDIO1].streamerData);
823        if (!phstream)
824                return -1;
825
826        stream = (AudioStream *)(phstream->stream);
827        if (!stream)
828                return -1;
829
830        stream = (AudioStream *)(s->streams[PH_MSTREAM_AUDIO1].streamerData);
831        audio_stream_play(stream, filename);
832        return 0;
833}
834
835int phms_audio_conf_suspend_stream(struct ph_msession_s *s)
836{
837        struct ph_mstream_params_s *msp = &s->streams[PH_MSTREAM_AUDIO1];
838        AudioStream *pas = (AudioStream *) msp->streamerData;
839        phms_audio_conf_stream_t *pcs = (phms_audio_conf_stream_t*)(s->audio_conf);
840        MSTicker *ticker = pcs->ticker;
841
842        //ms_mutex_lock(&ticker->lock);
843        if(s->confflags == PH_MSESSION_CONF_MASTER)
844        {
845                FILTER_UNLINK(pcs->conf, 1,  pas->encoder,0);
846        }
847        else
848        {
849                FILTER_UNLINK(pcs->conf, 2,  pas->encoder,0);
850        }
851        FILTER_UNLINK(pas->rtprecv, 0,  pas->decoder,0);
852        //ms_mutex_unlock(&ticker->lock);
853        return 0;
854}
855int phms_audio_conf_resume_stream(struct ph_msession_s *s)
856{
857        struct ph_mstream_params_s *msp = &s->streams[PH_MSTREAM_AUDIO1];
858        AudioStream *pas = (AudioStream *) msp->streamerData;
859        phms_audio_conf_stream_t *pcs = (phms_audio_conf_stream_t*)(s->audio_conf);
860        MSTicker *ticker = pcs->ticker;
861
862        //ms_mutex_lock(&ticker->lock);
863        if(s->confflags == PH_MSESSION_CONF_MASTER)
864        {
865                FILTER_LINK(pcs->conf, 1,  pas->encoder,0);
866        }
867        else
868        {
869                FILTER_LINK(pcs->conf, 2,  pas->encoder,0);
870        }
871        FILTER_LINK(pas->rtprecv, 0,  pas->decoder,0);
872        //ms_mutex_unlock(&ticker->lock);
873        return 0;
874}
875
876// used to relink a call after the conference
877
878static int relink_audio_call(AudioStream *pas, int flags)
879{
880        if(pas->ec != NULL)
881        {
882#ifdef PH_FORCE_16KHZ
883                FILTER_LINK(pas->soundread, 0, pas->downsample,0);
884                FILTER_LINK(pas->downsample, 0, pas->ec,1);
885                FILTER_LINK(pas->ec,0, pas->upsample,0);
886                FILTER_LINK(pas->upsample,0, pas->soundwrite,0);
887#else
888                FILTER_LINK(pas->soundread, 0, pas->ec,1);
889                FILTER_LINK(pas->ec,0, pas->soundwrite,0);
890#endif         
891                FILTER_LINK(pas->dtmfgen,0, pas->ec,0);
892                FILTER_LINK(pas->ec,1, pas->dtmfgen2,0);
893                FILTER_LINK(pas->dtmfgen2, 0, pas->encoder, 0);
894        }
895        else
896        {
897#ifdef PH_FORCE_16KHZ
898                FILTER_LINK(pas->soundread, 0, pas->downsample, 0);
899                FILTER_LINK(pas->downsample, 0, pas->dtmfgen2, 0);
900                FILTER_LINK(pas->dtmfgen,0, pas->upsample,0);
901                FILTER_LINK(pas->upsample,0, pas->soundwrite,0);
902#else
903                FILTER_LINK(pas->soundread, 0, pas->dtmfgen2, 0);
904                FILTER_LINK(pas->dtmfgen,0, pas->soundwrite,0);
905#endif         
906                FILTER_LINK(pas->dtmfgen2, 0, pas->encoder,0);
907        }
908        if(flags & PH_MSTREAM_FLAG_SUSPENDED)
909        {
910                FILTER_LINK(pas->rtprecv, 0,  pas->decoder,0);
911        }
912        return 0;
913}
914// used to unlink the call entering the conference
915
916static void unlink_audio_call(AudioStream *pas)
917{
918        force_audio_timebase(pas->soundread, 0);
919        if(pas->ec != NULL)
920        {
921#ifdef PH_FORCE_16KHZ
922                FILTER_UNLINK(pas->soundread, 0, pas->downsample,0);
923                FILTER_UNLINK(pas->downsample, 0, pas->ec,1);
924                FILTER_UNLINK(pas->ec,0, pas->upsample,0);
925                FILTER_UNLINK(pas->upsample,0, pas->soundwrite,0);
926#else
927                FILTER_UNLINK(pas->soundread, 0, pas->ec,1);
928                FILTER_UNLINK(pas->ec,0, pas->soundwrite,0);
929#endif         
930                FILTER_UNLINK(pas->dtmfgen,0, pas->ec,0);
931                FILTER_UNLINK(pas->ec,1, pas->dtmfgen2,0);
932                FILTER_UNLINK(pas->dtmfgen2, 0, pas->encoder, 0);
933        }
934        else
935        {
936#ifdef PH_FORCE_16KHZ
937                FILTER_UNLINK(pas->soundread, 0, pas->downsample, 0);
938                FILTER_UNLINK(pas->downsample, 0, pas->dtmfgen2, 0);
939                FILTER_UNLINK(pas->dtmfgen,0, pas->upsample,0);
940                FILTER_UNLINK(pas->upsample,0, pas->soundwrite,0);
941#else
942                FILTER_UNLINK(pas->soundread, 0, pas->dtmfgen2, 0);
943                FILTER_UNLINK(pas->dtmfgen,0, pas->soundwrite,0);
944#endif         
945                FILTER_UNLINK(pas->dtmfgen2, 0, pas->encoder,0);
946        }
947}
948
949int phms_audio_conf_start(struct ph_msession_s *s1, struct ph_msession_s *s2)
950{
951        phms_audio_conf_stream_t *pcs;
952        int clock_rate, use_ec;
953        bool_t vad;
954        int tmp=1;
955        struct ph_mstream_params_s *msp1 = &s1->streams[PH_MSTREAM_AUDIO1];
956        struct ph_mstream_params_s *msp2 = &s2->streams[PH_MSTREAM_AUDIO1];
957        AudioStream *pas1 = (AudioStream *) msp1->streamerData;
958        AudioStream *pas2 = (AudioStream *) msp2->streamerData;
959
960        use_ec = (msp1->flags)&PH_MSTREAM_FLAG_AEC || (msp2->flags)&PH_MSTREAM_FLAG_AEC;
961        vad = (((msp1->flags)&PH_MSTREAM_FLAG_VAD) && ((msp2->flags)&PH_MSTREAM_FLAG_VAD))?TRUE:FALSE;
962        clock_rate = msp1->ipayloads[0].rate;
963
964        if(use_ec && (pas1->ec==NULL || pas2->ec==NULL))
965                return phms_error();
966
967        if(!use_ec && (pas1->ec!=NULL || pas2->ec!=NULL))
968                return phms_error();
969
970        pcs=(phms_audio_conf_stream_t*)malloc(sizeof(phms_audio_conf_stream_t));
971#ifdef USE_NEW_SOUNDREAD
972        pcs->soundread = phms_get_soundread(NULL);
973        if(pcs->soundread == NULL)
974        {
975                free(pcs);
976                return phms_error();
977        }
978        ms_filter_call_method(pcs->soundread,MS_FILTER_SET_SAMPLE_RATE,&clock_rate);
979#endif 
980        s1->audio_conf = s2->audio_conf = pcs;
981        pcs->s[0] = s1;
982        pcs->s[1] = s2;
983
984        force_audio_timebase(pas1->soundread, 0);
985        force_audio_timebase(pas2->soundread, 0);
986
987        pcs->conf = ms_filter_new(MS_CONF_ID);
988        ms_filter_call_method(pcs->conf, MS_FILTER_SET_SAMPLE_RATE, &clock_rate);
989        ms_filter_call_method(pcs->conf, MS_FILTER_ENABLE_VAD, &vad);
990        ms_filter_call_method(pcs->conf, MS_FILTER_ENABLE_DIRECTMODE, &tmp);
991
992        if(use_ec)
993        {
994                pcs->ec = ms_filter_new(MS_SPEEX_EC_ID);
995                ms_filter_call_method(pcs->ec, MS_FILTER_SET_SAMPLE_RATE, &clock_rate);
996        }
997        else
998        {
999                pcs->ec = NULL;
1000        }
1001        pcs->ticker=ms_ticker_new();
1002
1003        // Unlink involved streams
1004
1005
1006        unlink_audio_call(pas1);
1007        unlink_audio_call(pas2);
1008
1009        if(use_ec)
1010        {
1011#ifdef PH_FORCE_16KHZ
1012                FILTER_LINK(pas1->soundread, 0,pas1->downsample,0);
1013                FILTER_LINK(pas1->downsample, 0,pcs->ec,1);
1014                FILTER_LINK(pcs->ec, 0, pas1->upsample, 0);
1015                FILTER_LINK(pas1->upsample, 0, pas1->soundwrite, 0);
1016#else
1017                FILTER_LINK(pas1->soundread, 0,pcs->ec,1);
1018                FILTER_LINK(pcs->ec, 0, pas1->soundwrite, 0);
1019#endif         
1020                FILTER_LINK(pcs->conf, 0, pcs->ec, 0);
1021                FILTER_LINK(pcs->ec, 1, pas1->dtmfgen2, 0);
1022                FILTER_LINK(pas1->dtmfgen2, 0, pcs->conf, 0);
1023        }
1024        else
1025        {
1026#ifdef PH_FORCE_16KHZ
1027                FILTER_LINK(pas1->soundread, 0,   pas1->downsample, 0);
1028                FILTER_LINK(pas1->downsample, 0,   pas1->dtmfgen2, 0);
1029                FILTER_LINK(pcs->conf, 0, pas1->upsample, 0);
1030                FILTER_LINK(pas1->upsample, 0, pas1->soundwrite, 0);
1031#else
1032                FILTER_LINK(pas1->soundread, 0,   pas1->dtmfgen2, 0);
1033                FILTER_LINK(pcs->conf, 0, pas1->soundwrite, 0);
1034#endif         
1035                FILTER_LINK(pas1->dtmfgen2, 0, pcs->conf, 0);
1036        }
1037
1038        // Link other mixers
1039        FILTER_LINK(pas1->dtmfgen, 0, pcs->conf,1);
1040        FILTER_LINK(pas2->dtmfgen, 0, pcs->conf,2);
1041
1042        FILTER_LINK(pcs->conf, 1,  pas1->encoder,0);
1043        FILTER_LINK(pcs->conf, 2,  pas2->encoder,0);
1044
1045        ms_ticker_attach(pcs->ticker, pas1->rtprecv);
1046        ms_ticker_attach(pcs->ticker, pas2->rtprecv);
1047        ms_ticker_attach(pcs->ticker, pas1->soundread);
1048
1049        force_audio_timebase(pas1->soundread, 1);
1050
1051        return 0;
1052}
1053/**
1054 * @brief function that unties to sessions that were previously binded for a conference
1055 */
1056void phms_conf_destroy (phms_audio_conf_stream_t *pcs)
1057{
1058        // local filters
1059        if(pcs->conf != NULL)
1060                ms_filter_destroy(pcs->conf);
1061        //      if(pcs->soundread != NULL)
1062        //              ms_filter_destroy(pcs->soundread);
1063        if(pcs->ec != NULL)
1064                ms_filter_destroy(pcs->ec);
1065        if(pcs->ticker != NULL)
1066                ms_ticker_destroy(pcs->ticker);
1067
1068        free(pcs);
1069}
1070/**
1071 * @brief function that unties to sessions that were previously binded for a conference
1072 */
1073int phms_audio_stream_conf_unlink(struct ph_msession_s *s1, struct ph_msession_s *s2)
1074{
1075        int use_ec1, use_ec2;
1076        struct ph_mstream_params_s *msp1 = &s1->streams[PH_MSTREAM_AUDIO1];
1077        AudioStream *pas1 = (AudioStream *) msp1->streamerData;
1078        struct ph_mstream_params_s *msp2 = &s2->streams[PH_MSTREAM_AUDIO1];
1079        AudioStream *pas2 = (AudioStream *) msp2->streamerData;
1080        phms_audio_conf_stream_t *pcs;
1081
1082        use_ec1 = (msp1->flags)&PH_MSTREAM_FLAG_AEC;
1083        use_ec2 = (msp2->flags)&PH_MSTREAM_FLAG_AEC;
1084
1085        if(s1->audio_conf == s2->audio_conf)
1086        {
1087                MSTicker *ticker;
1088                pcs=(phms_audio_conf_stream_t*)(s1->audio_conf);
1089                ticker = pcs->ticker;
1090
1091                // Stop conference
1092                if(ticker)
1093                {
1094                        force_audio_timebase(pas1->soundread, 0);
1095                        ms_ticker_detach(ticker, pas1->soundread);
1096                        ms_ticker_detach(ticker, pas1->rtprecv);
1097                        ms_ticker_detach(ticker, pas2->rtprecv);
1098                }
1099                else
1100                        return(phms_error());
1101
1102                // Unlink involved streams
1103                if((use_ec1 || use_ec2) && (pcs->ec != NULL))
1104                {
1105#ifdef PH_FORCE_16KHZ
1106                        FILTER_UNLINK(pas1->soundread, 0,  pas1->downsample, 0);
1107                        FILTER_UNLINK(pas1->downsample, 0,  pcs->ec, 1);
1108                        FILTER_UNLINK(pcs->ec, 0,  pas1->upsample, 0);
1109                        FILTER_UNLINK(pas1->upsample, 0,  pas1->soundwrite, 0);
1110#else
1111                        FILTER_UNLINK(pas1->soundread, 0, pcs->ec, 1);
1112                        FILTER_UNLINK(pcs->ec, 0, pas1->soundwrite, 0);
1113#endif                 
1114                        FILTER_UNLINK(pcs->conf, 0,  pcs->ec, 0);
1115                        FILTER_UNLINK(pcs->ec, 1, pas1->dtmfgen2, 0);
1116                        FILTER_UNLINK(pas1->dtmfgen2, 0,pcs->conf, 0);
1117                }
1118                else
1119                {
1120#ifdef PH_FORCE_16KHZ
1121                        FILTER_UNLINK(pas1->soundread, 0,  pas1->downsample, 0);
1122                        FILTER_UNLINK(pas1->downsample, 0,  pas1->dtmfgen2, 0);
1123                        FILTER_UNLINK(pcs->conf, 0,  pas1->upsample, 0);
1124                        FILTER_UNLINK(pas1->upsample, 0,  pas1->soundwrite, 0);
1125#else
1126                        FILTER_UNLINK(pas1->soundread, 0, pas1->dtmfgen2, 1);
1127                        FILTER_UNLINK(pcs->conf, 0, pas1->soundwrite, 0);
1128#endif                 
1129                        FILTER_UNLINK(pas1->dtmfgen2, 0,pcs->conf, 0);
1130                }
1131
1132                //              FILTER_UNLINK(pcs->soundread, 0, pas1->dtmfgen2,0);
1133
1134                s1->audio_conf = s2->audio_conf = NULL;
1135
1136                // Unlink other calls' tx/rx paths
1137                FILTER_UNLINK(pas1->dtmfgen, 0, pcs->conf,1);
1138                FILTER_UNLINK(pas2->dtmfgen, 0, pcs->conf,2);
1139
1140                if(!(msp1->flags & PH_MSTREAM_FLAG_SUSPENDED))
1141                        FILTER_UNLINK(pcs->conf, 1,  pas1->encoder,0);
1142
1143                if(!(msp2->flags & PH_MSTREAM_FLAG_SUSPENDED))
1144                        FILTER_UNLINK(pcs->conf, 2,  pas2->encoder,0);
1145
1146                // destroy conference
1147                phms_conf_destroy (pcs);
1148
1149                // Relink streams
1150
1151                relink_audio_call(pas1, msp1->flags);
1152                relink_audio_call(pas2, msp2->flags);
1153
1154                return 0;
1155        }
1156        return 0;
1157}
1158
1159/**
1160 * @brief will be used in the future to properly stop a conf
1161 */
1162int phms_audio_conf_stop(struct ph_msession_s *s1, struct ph_msession_s *s2)
1163{
1164        return(phms_audio_stream_conf_unlink(s1,s2));
1165}
1166
1167int phms_audio_get_playback_sndcard_list(ph_audio_card_desc_t** device_tab)
1168{
1169        int device_num;
1170        const MSList *card_list = ms_snd_card_manager_get_list(ms_snd_card_manager_get());
1171        int pos = 0;
1172        int i = 0;
1173
1174        device_num = ms_list_size(card_list);
1175        if (device_num == 0)
1176                return 0;
1177        *device_tab = osip_malloc(device_num * (sizeof(**device_tab) + 1));
1178        for(;(card_list = ms_list_next(card_list)) != NULL; pos++)
1179        {
1180                if (((MSSndCard *)(card_list->data))->capabilities & MS_SND_CARD_CAP_PLAYBACK)
1181                {
1182                        ((*device_tab)[i]).idx = pos;
1183                        ((*device_tab)[i]).id = osip_strdup(((MSSndCard *)(card_list->data))->id);
1184                        ((*device_tab)[i]).name = osip_strdup(((MSSndCard *)(card_list->data))->name);
1185                        ((*device_tab)[i]).capabilities = ((MSSndCard *)(card_list->data))->capabilities;
1186                        i++;
1187                }
1188        }
1189
1190        return i;
1191}
1192
1193int phms_audio_get_capture_sndcard_list(ph_audio_card_desc_t** device_tab)
1194{
1195        int device_num;
1196        const MSList *card_list = ms_snd_card_manager_get_list(ms_snd_card_manager_get());
1197        int pos = 0;
1198        int i = 0;
1199
1200        device_num = ms_list_size(card_list);
1201        if (device_num == 0)
1202                return 0;
1203        *device_tab = osip_malloc(device_num * (sizeof(**device_tab) + 1));
1204        for(;(card_list = ms_list_next(card_list)) != NULL; pos++)
1205        {
1206                if (((MSSndCard *)(card_list->data))->capabilities & MS_SND_CARD_CAP_CAPTURE)
1207                {
1208                        ((*device_tab)[i]).idx = pos;
1209                        ((*device_tab)[i]).id = osip_strdup(((MSSndCard *)(card_list->data))->id);
1210                        ((*device_tab)[i]).name = osip_strdup(((MSSndCard *)(card_list->data))->name);
1211                        ((*device_tab)[i]).capabilities = ((MSSndCard *)(card_list->data))->capabilities;
1212                        i++;
1213                }
1214        }
1215
1216        return i;
1217}
1218
Note: See TracBrowser for help on using the repository browser.