| 1 | /* |
|---|
| 2 | mediastreamer2 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 | |
|---|
| 7 | This program is free software; you can redistribute it and/or |
|---|
| 8 | modify it under the terms of the GNU General Public License |
|---|
| 9 | as published by the Free Software Foundation; either version 2 |
|---|
| 10 | of the License, or (at your option) any later version. |
|---|
| 11 | |
|---|
| 12 | This program is distributed in the hope that it will be useful, |
|---|
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 15 | GNU General Public License for more details. |
|---|
| 16 | |
|---|
| 17 | You should have received a copy of the GNU General Public License |
|---|
| 18 | along with this program; if not, write to the Free Software |
|---|
| 19 | Foundation, 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 | |
|---|
| 63 | void rtp_session_rtcp_parse(RtpSession *session, mblk_t *mp); |
|---|
| 64 | |
|---|
| 65 | |
|---|
| 66 | #ifndef USE_PHMS_AUDIOSTREAM |
|---|
| 67 | int 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). */ |
|---|
| 80 | const 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). */ |
|---|
| 85 | const char* JITTER_BUFFER_ENV = "PH_JITTER_BUFFER_MS"; |
|---|
| 86 | |
|---|
| 87 | void audio_stream_change_decoder(AudioStream *stream, int payload); |
|---|
| 88 | |
|---|
| 89 | |
|---|
| 90 | void ph_media_audio_init() |
|---|
| 91 | { |
|---|
| 92 | return; |
|---|
| 93 | } |
|---|
| 94 | |
|---|
| 95 | void 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 */ |
|---|
| 109 | void audio_stream_free(AudioStream *stream); |
|---|
| 110 | void 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 | |
|---|
| 151 | static 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 | |
|---|
| 157 | static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; |
|---|
| 158 | |
|---|
| 159 | static 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 | |
|---|
| 201 | static 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 | |
|---|
| 210 | MSSndCard *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 | |
|---|
| 238 | MSSndCard *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 | |
|---|
| 268 | MSFilter *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 | } |
|---|
| 276 | MSFilter *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 | } |
|---|
| 284 | phms_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 | |
|---|
| 303 | int 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. |
|---|
| 307 | static 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 | |
|---|
| 317 | static int force_audio_timebase(MSFilter *filter, int yesno){return 0;} |
|---|
| 318 | |
|---|
| 319 | #endif |
|---|
| 320 | |
|---|
| 321 | |
|---|
| 322 | static 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 | |
|---|
| 366 | static 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 | |
|---|
| 409 | static void |
|---|
| 410 | phms_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 | |
|---|
| 421 | int 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 | |
|---|
| 567 | phms_audio_stream_t* |
|---|
| 568 | phms_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 | |
|---|
| 651 | void 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 | } |
|---|
| 657 | void 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 | |
|---|
| 664 | void 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 | } |
|---|
| 670 | void 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 | |
|---|
| 676 | void 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 | |
|---|
| 682 | void 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 | |
|---|
| 688 | AudioStream *phms_audio_stream_new(int locport, bool_t ipv6){ |
|---|
| 689 | return audio_stream_new(locport, ipv6); |
|---|
| 690 | } |
|---|
| 691 | |
|---|
| 692 | void 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 | |
|---|
| 755 | int 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 | |
|---|
| 774 | int 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 | } |
|---|
| 793 | int 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 | |
|---|
| 814 | int 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 | |
|---|
| 835 | int 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 | } |
|---|
| 855 | int 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 | |
|---|
| 878 | static 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 | |
|---|
| 916 | static 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 | |
|---|
| 949 | int 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 | */ |
|---|
| 1056 | void 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 | */ |
|---|
| 1073 | int 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 | */ |
|---|
| 1162 | int 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 | |
|---|
| 1167 | int 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 i = 0; |
|---|
| 1172 | |
|---|
| 1173 | device_num = ms_list_size(card_list); |
|---|
| 1174 | if (device_num == 0) |
|---|
| 1175 | return 0; |
|---|
| 1176 | *device_tab = osip_malloc(device_num * (sizeof(**device_tab) + 1)); |
|---|
| 1177 | for(;card_list != NULL; card_list = card_list->next) |
|---|
| 1178 | { |
|---|
| 1179 | MSSndCard * card = (MSSndCard *)(card_list->data); |
|---|
| 1180 | if (card->capabilities & MS_SND_CARD_CAP_PLAYBACK) |
|---|
| 1181 | { |
|---|
| 1182 | ((*device_tab)[i]).id = osip_strdup(card->id); |
|---|
| 1183 | ((*device_tab)[i]).name = osip_strdup(card->name); |
|---|
| 1184 | ((*device_tab)[i]).capabilities = card->capabilities; |
|---|
| 1185 | i++; |
|---|
| 1186 | } |
|---|
| 1187 | } |
|---|
| 1188 | |
|---|
| 1189 | return i; |
|---|
| 1190 | } |
|---|
| 1191 | |
|---|
| 1192 | int phms_audio_get_capture_sndcard_list(ph_audio_card_desc_t** device_tab) |
|---|
| 1193 | { |
|---|
| 1194 | int device_num; |
|---|
| 1195 | const MSList *card_list = ms_snd_card_manager_get_list(ms_snd_card_manager_get()); |
|---|
| 1196 | int i = 0; |
|---|
| 1197 | |
|---|
| 1198 | device_num = ms_list_size(card_list); |
|---|
| 1199 | if (device_num == 0) |
|---|
| 1200 | return 0; |
|---|
| 1201 | *device_tab = osip_malloc(device_num * (sizeof(**device_tab) + 1)); |
|---|
| 1202 | for(;card_list != NULL; card_list = card_list->next) |
|---|
| 1203 | { |
|---|
| 1204 | MSSndCard * card = (MSSndCard *)(card_list->data); |
|---|
| 1205 | if (card->capabilities & MS_SND_CARD_CAP_CAPTURE) |
|---|
| 1206 | { |
|---|
| 1207 | ((*device_tab)[i]).id = osip_strdup(card->id); |
|---|
| 1208 | ((*device_tab)[i]).name = osip_strdup(card->name); |
|---|
| 1209 | ((*device_tab)[i]).capabilities = card->capabilities; |
|---|
| 1210 | i++; |
|---|
| 1211 | } |
|---|
| 1212 | } |
|---|
| 1213 | |
|---|
| 1214 | return i; |
|---|
| 1215 | } |
|---|
| 1216 | |
|---|