audiostream.c 38.9 KB
Newer Older
aymeric's avatar
aymeric committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/


#include "mediastreamer2/mediastream.h"

#include "mediastreamer2/dtmfgen.h"
#include "mediastreamer2/mssndcard.h"
#include "mediastreamer2/msrtp.h"
#include "mediastreamer2/msfileplayer.h"
#include "mediastreamer2/msfilerec.h"
28
#include "mediastreamer2/msvolume.h"
smorlat's avatar
smorlat committed
29
#include "mediastreamer2/msequalizer.h"
30 31
#include "mediastreamer2/mstee.h"
#include "mediastreamer2/msaudiomixer.h"
32
#include "mediastreamer2/mscodecutils.h"
Ghislain MARY's avatar
Ghislain MARY committed
33
#include "private.h"
aymeric's avatar
aymeric committed
34

35 36 37 38 39 40 41
#ifdef HAVE_CONFIG_H
#include "mediastreamer-config.h"
#endif




42 43
#include <sys/types.h>

aymeric's avatar
aymeric committed
44 45 46 47 48
#ifndef WIN32
	#include <sys/socket.h>
	#include <netdb.h>
#endif

49
static void audio_stream_free(AudioStream *stream) {
Ghislain MARY's avatar
Ghislain MARY committed
50
	media_stream_free(&stream->ms);
aymeric's avatar
aymeric committed
51 52 53
	if (stream->soundread!=NULL) ms_filter_destroy(stream->soundread);
	if (stream->soundwrite!=NULL) ms_filter_destroy(stream->soundwrite);
	if (stream->dtmfgen!=NULL) ms_filter_destroy(stream->dtmfgen);
54
	if (stream->plc!=NULL)	ms_filter_destroy(stream->plc);
aymeric's avatar
aymeric committed
55
	if (stream->ec!=NULL)	ms_filter_destroy(stream->ec);
56 57
	if (stream->volrecv!=NULL) ms_filter_destroy(stream->volrecv);
	if (stream->volsend!=NULL) ms_filter_destroy(stream->volsend);
58
	if (stream->equalizer!=NULL) ms_filter_destroy(stream->equalizer);
jehan's avatar
jehan committed
59 60
	if (stream->read_resampler!=NULL) ms_filter_destroy(stream->read_resampler);
	if (stream->write_resampler!=NULL) ms_filter_destroy(stream->write_resampler);
61
	if (stream->dtmfgen_rtp!=NULL) ms_filter_destroy(stream->dtmfgen_rtp);
Simon Morlat's avatar
Simon Morlat committed
62
	if (stream->dummy) ms_filter_destroy(stream->dummy);
63 64 65 66
	if (stream->recv_tee) ms_filter_destroy(stream->recv_tee);
	if (stream->send_tee) ms_filter_destroy(stream->send_tee);
	if (stream->recorder) ms_filter_destroy(stream->recorder);
	if (stream->recorder_mixer) ms_filter_destroy(stream->recorder_mixer);
67 68 69
	if (stream->local_mixer) ms_filter_destroy(stream->local_mixer);
	if (stream->local_player) ms_filter_destroy(stream->local_player);
	if (stream->local_player_resampler) ms_filter_destroy(stream->local_player_resampler);
70
	if (stream->recorder_file) ms_free(stream->recorder_file);
aymeric's avatar
aymeric committed
71 72 73 74 75 76 77
	ms_free(stream);
}

static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};

static void on_dtmf_received(RtpSession *s, int dtmf, void * user_data)
{
smorlat's avatar
smorlat committed
78
	AudioStream *stream=(AudioStream*)user_data;
aymeric's avatar
aymeric committed
79 80 81 82 83
	if (dtmf>15){
		ms_warning("Unsupported telephone-event type.");
		return;
	}
	ms_message("Receiving dtmf %c.",dtmf_tab[dtmf]);
smorlat's avatar
smorlat committed
84 85
	if (stream->dtmfgen!=NULL && stream->play_dtmfs){
		ms_filter_call_method(stream->dtmfgen,MS_DTMF_GEN_PUT,&dtmf_tab[dtmf]);
aymeric's avatar
aymeric committed
86 87 88
	}
}

89 90 91 92 93
/*
 * note: since not all filters implement MS_FILTER_GET_SAMPLE_RATE, fallback_from_rate and fallback_to_rate are expected to provide sample rates
 * obtained by another context, such as the RTP clock rate for example.
 */
static void audio_stream_configure_resampler(MSFilter *resampler,MSFilter *from, MSFilter *to, int fallback_from_rate, int fallback_to_rate) {
94
	int from_rate=0, to_rate=0;
95
	int from_channels = 0, to_channels = 0;
96 97
	ms_filter_call_method(from,MS_FILTER_GET_SAMPLE_RATE,&from_rate);
	ms_filter_call_method(to,MS_FILTER_GET_SAMPLE_RATE,&to_rate);
98 99
	ms_filter_call_method(from, MS_FILTER_GET_NCHANNELS, &from_channels);
	ms_filter_call_method(to, MS_FILTER_GET_NCHANNELS, &to_channels);
100 101 102 103 104 105 106 107
	if (from_channels == 0) {
		from_channels = 1;
		ms_error("Filter %s does not implement the MS_FILTER_GET_NCHANNELS method", from->desc->name);
	}
	if (to_channels == 0) {
		to_channels = 1;
		ms_error("Filter %s does not implement the MS_FILTER_GET_NCHANNELS method", to->desc->name);
	}
108
	if (from_rate == 0){
109 110
		ms_error("Filter %s does not implement the MS_FILTER_GET_SAMPLE_RATE method", from->desc->name);
		from_rate=fallback_from_rate;
111 112
	}
	if (to_rate == 0){
113 114
		ms_error("Filter %s does not implement the MS_FILTER_GET_SAMPLE_RATE method", to->desc->name);
		to_rate=fallback_to_rate;
115
	}
116 117
	ms_filter_call_method(resampler,MS_FILTER_SET_SAMPLE_RATE,&from_rate);
	ms_filter_call_method(resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&to_rate);
118 119 120 121
	ms_filter_call_method(resampler, MS_FILTER_SET_NCHANNELS, &from_channels);
	ms_filter_call_method(resampler, MS_FILTER_SET_OUTPUT_NCHANNELS, &to_channels);
	ms_message("configuring %s-->%s from rate [%i] to rate [%i] and from channel [%i] to channel [%i]",
	           from->desc->name, to->desc->name, from_rate, to_rate, from_channels, to_channels);
122 123
}

jehan's avatar
jehan committed
124 125 126
static void audio_stream_process_rtcp(MediaStream *media_stream, mblk_t *m){
	AudioStream *stream=(AudioStream*)media_stream;
	stream->last_packet_time=ms_time(NULL);
127
	do{
128
		const report_block_t *rb=NULL;
129 130
		if (rtcp_is_SR(m)){
			rb=rtcp_SR_get_report_block(m,0);
131 132 133 134 135
		}else if (rtcp_is_RR(m)){
			rb=rtcp_RR_get_report_block(m,0);
		}
		if (rb){
			unsigned int ij;
136
			float rt=rtp_session_get_round_trip_propagation(stream->ms.sessions.rtp_session);
137 138 139
			float flost;
			ij=report_block_get_interarrival_jitter(rb);
			flost=(float)(100.0*report_block_get_fraction_lost(rb)/256.0);
jehan's avatar
jehan committed
140 141
			ms_message("audio_stream_iterate[%p]: remote statistics available\n\tremote's interarrival jitter=%u\n"
			           "\tremote's lost packets percentage since last report=%f\n\tround trip time=%f seconds",stream,ij,flost,rt);
Ghislain MARY's avatar
Ghislain MARY committed
142
			if (stream->ms.rc) ms_bitrate_controller_process_rtcp(stream->ms.rc,m);
143
			if (stream->ms.qi) ms_quality_indicator_update_from_feedback(stream->ms.qi,m);
144 145 146 147
		}
	}while(rtcp_next_packet(m));
}

148
void audio_stream_iterate(AudioStream *stream){
149
	media_stream_iterate(&stream->ms);
150 151 152
}

bool_t audio_stream_alive(AudioStream * stream, int timeout){
153
	const rtp_stats_t *stats=rtp_session_get_stats(stream->ms.sessions.rtp_session);
154
	if (stats->recv!=0){
aymeric's avatar
aymeric committed
155 156
		if (stats->recv!=stream->last_packet_count){
			stream->last_packet_count=stats->recv;
Simon Morlat's avatar
Simon Morlat committed
157
			stream->last_packet_time=ms_time(NULL);
158 159
		}
	}
160 161 162
	if (ms_time(NULL)-stream->last_packet_time>timeout){
		/* more than timeout seconds of inactivity*/
		return FALSE;
aymeric's avatar
aymeric committed
163 164 165 166
	}
	return TRUE;
}

jehan's avatar
jehan committed
167 168
/*invoked from FEC capable filters*/
static  mblk_t* audio_stream_payload_picker(MSRtpPayloadPickerContext* context,unsigned int sequence_number) {
169
	return rtp_session_pick_with_cseq(((AudioStream*)(context->filter_graph_manager))->ms.sessions.rtp_session, sequence_number);
Simon Morlat's avatar
Simon Morlat committed
170 171 172
}

static void stop_preload_graph(AudioStream *stream){
173 174
	ms_ticker_detach(stream->ms.sessions.ticker,stream->dummy);
	
Ghislain MARY's avatar
Ghislain MARY committed
175 176 177 178
	if (stream->ms.voidsink) {
		ms_filter_unlink(stream->dummy,0,stream->ms.voidsink,0);
		ms_filter_destroy(stream->ms.voidsink);
		stream->ms.voidsink=NULL;
179 180
	}else if (stream->soundwrite) {
		ms_filter_unlink(stream->dummy,0,stream->soundwrite,0);
181
	}
Simon Morlat's avatar
Simon Morlat committed
182 183 184 185 186
	ms_filter_destroy(stream->dummy);
	stream->dummy=NULL;
}

bool_t audio_stream_started(AudioStream *stream){
187
	return stream->ms.start_time!=0;
Simon Morlat's avatar
Simon Morlat committed
188 189
}

190
/* This function is used either on IOS to workaround the long time to initialize the Audio Unit or for ICE candidates gathering. */
Simon Morlat's avatar
Simon Morlat committed
191
void audio_stream_prepare_sound(AudioStream *stream, MSSndCard *playcard, MSSndCard *captcard){
192 193
	audio_stream_unprepare_sound(stream);
	stream->dummy=ms_filter_new(MS_RTP_RECV_ID);
194 195
	rtp_session_set_payload_type(stream->ms.sessions.rtp_session,0);
	ms_filter_call_method(stream->dummy,MS_RTP_RECV_SET_SESSION,stream->ms.sessions.rtp_session);
196

Simon Morlat's avatar
Simon Morlat committed
197
	if (captcard && playcard){
198
#ifdef __ios
Simon Morlat's avatar
Simon Morlat committed
199 200 201
		stream->soundread=ms_snd_card_create_reader(captcard);
		stream->soundwrite=ms_snd_card_create_writer(playcard);
		ms_filter_link(stream->dummy,0,stream->soundwrite,0);
202
#else
Ghislain MARY's avatar
Ghislain MARY committed
203 204
		stream->ms.voidsink=ms_filter_new(MS_VOID_SINK_ID);
		ms_filter_link(stream->dummy,0,stream->ms.voidsink,0);
Simon Morlat's avatar
Simon Morlat committed
205
#endif
206
	} else {
Ghislain MARY's avatar
Ghislain MARY committed
207 208
		stream->ms.voidsink=ms_filter_new(MS_VOID_SINK_ID);
		ms_filter_link(stream->dummy,0,stream->ms.voidsink,0);
209
	}
210 211 212
	if (stream->ms.sessions.ticker == NULL) media_stream_start_ticker(&stream->ms);
	ms_ticker_attach(stream->ms.sessions.ticker,stream->dummy);
	stream->ms.state=MSStreamPreparing;
Simon Morlat's avatar
Simon Morlat committed
213 214
}

Simon Morlat's avatar
Simon Morlat committed
215
static void _audio_stream_unprepare_sound(AudioStream *stream, bool_t keep_sound_resources){
216
	if (stream->ms.state==MSStreamPreparing){
Simon Morlat's avatar
Simon Morlat committed
217
		stop_preload_graph(stream);
218
#ifdef __ios
Simon Morlat's avatar
Simon Morlat committed
219 220 221 222 223 224
		if (!keep_sound_resources){
			if (stream->soundread) ms_filter_destroy(stream->soundread);
			stream->soundread=NULL;
			if (stream->soundwrite) ms_filter_destroy(stream->soundwrite);
			stream->soundwrite=NULL;
		}
Simon Morlat's avatar
Simon Morlat committed
225
#endif
226
	}
227
	stream->ms.state=MSStreamInitialized;
Simon Morlat's avatar
Simon Morlat committed
228 229
}

Simon Morlat's avatar
Simon Morlat committed
230 231 232 233
void audio_stream_unprepare_sound(AudioStream *stream){
	_audio_stream_unprepare_sound(stream,FALSE);
}

234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
static void player_callback(void *ud, MSFilter *f, unsigned int id, void *arg){
	AudioStream *stream=(AudioStream *)ud;
	int sr=0;
	int channels=0;
	switch(id){
		case MS_PLAYER_FORMAT_CHANGED:
			ms_filter_call_method(f,MS_FILTER_GET_SAMPLE_RATE,&sr);
			ms_filter_call_method(f,MS_FILTER_GET_NCHANNELS,&channels);
			if (f==stream->local_player){
				ms_filter_call_method(stream->local_player_resampler,MS_FILTER_SET_SAMPLE_RATE,&sr);
				ms_filter_call_method(stream->local_player_resampler,MS_FILTER_SET_NCHANNELS,&channels);
			}
		break;
		default:
		break;
	}
}

static void setup_local_player(AudioStream *stream, int samplerate, int channels){
	MSConnectionHelper cnx;
Simon Morlat's avatar
Simon Morlat committed
254
	int master=0;
255 256 257 258 259 260 261 262 263 264 265 266 267
	
	stream->local_player=ms_filter_new(MS_FILE_PLAYER_ID);
	stream->local_player_resampler=ms_filter_new(MS_RESAMPLE_ID);
	
	ms_connection_helper_start(&cnx);
	ms_connection_helper_link(&cnx,stream->local_player,-1,0);
	ms_connection_helper_link(&cnx,stream->local_player_resampler,0,0);
	ms_connection_helper_link(&cnx,stream->local_mixer,1,-1);
	
	ms_filter_call_method(stream->local_player_resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&samplerate);
	ms_filter_call_method(stream->local_player_resampler,MS_FILTER_SET_OUTPUT_NCHANNELS,&channels);
	ms_filter_call_method(stream->local_mixer,MS_FILTER_SET_SAMPLE_RATE,&samplerate);
	ms_filter_call_method(stream->local_mixer,MS_FILTER_SET_NCHANNELS,&channels);
Simon Morlat's avatar
Simon Morlat committed
268
	ms_filter_call_method(stream->local_mixer,MS_AUDIO_MIXER_SET_MASTER_CHANNEL,&master);
269 270 271
	ms_filter_add_notify_callback(stream->local_player,player_callback,stream,TRUE);
}

272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
static OrtpRtcpXrPlcStatus audio_stream_get_rtcp_xr_plc_status(unsigned long userdata) {
	AudioStream *stream = (AudioStream *)userdata;
	if ((stream->features & AUDIO_STREAM_FEATURE_PLC) != 0) {
		int decoder_have_plc = 0;
		if (ms_filter_has_method(stream->ms.decoder, MS_AUDIO_DECODER_HAVE_PLC)) {
			ms_filter_call_method(stream->ms.decoder, MS_AUDIO_DECODER_HAVE_PLC, &decoder_have_plc);
		}
		if (decoder_have_plc == 0) {
			return OrtpRtcpXrSilencePlc;
		} else {
			return OrtpRtcpXrEnhancedPlc;
		}
	}
	return OrtpRtcpXrNoPlc;
}

288
static int audio_stream_get_rtcp_xr_signal_level(unsigned long userdata) {
289 290 291 292
	AudioStream *stream = (AudioStream *)userdata;
	if ((stream->features & AUDIO_STREAM_FEATURE_VOL_RCV) != 0) {
		float volume;
		ms_filter_call_method(stream->volrecv, MS_VOLUME_GET_MAX, &volume);
293
		return (int)volume;
294 295 296 297
	}
	return ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
}

298
static int audio_stream_get_rtcp_xr_noise_level(unsigned long userdata) {
299 300 301 302
	AudioStream *stream = (AudioStream *)userdata;
	if ((stream->features & AUDIO_STREAM_FEATURE_VOL_RCV) != 0) {
		float volume;
		ms_filter_call_method(stream->volrecv, MS_VOLUME_GET_MIN, &volume);
303
		return (int)volume;
304 305 306 307 308 309 310 311 312 313 314 315 316 317
	}
	return ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
}

static float audio_stream_get_rtcp_xr_average_quality_rating(unsigned long userdata) {
	AudioStream *stream = (AudioStream *)userdata;
	return audio_stream_get_average_quality_rating(stream);
}

static float audio_stream_get_rtcp_xr_average_lq_quality_rating(unsigned long userdata) {
	AudioStream *stream = (AudioStream *)userdata;
	return audio_stream_get_average_lq_quality_rating(stream);
}

318 319
int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char *rem_rtp_ip,int rem_rtp_port,
	const char *rem_rtcp_ip, int rem_rtcp_port, int payload,int jitt_comp, const char *infile, const char *outfile,
320 321
	MSSndCard *playcard, MSSndCard *captcard, bool_t use_ec){
	RtpSession *rtps=stream->ms.sessions.rtp_session;
Simon Morlat's avatar
Simon Morlat committed
322
	PayloadType *pt,*tel_ev;
323 324
	int tmp;
	MSConnectionHelper h;
325
	int sample_rate;
jehan's avatar
jehan committed
326
	MSRtpPayloadPickerContext picker_context;
327
	int nchannels;
328
	bool_t has_builtin_ec=FALSE;
329 330 331 332 333 334 335 336
	const OrtpRtcpXrMediaCallbacks rtcp_xr_media_cbs = {
		audio_stream_get_rtcp_xr_plc_status,
		audio_stream_get_rtcp_xr_signal_level,
		audio_stream_get_rtcp_xr_noise_level,
		audio_stream_get_rtcp_xr_average_quality_rating,
		audio_stream_get_rtcp_xr_average_lq_quality_rating,
		(unsigned long)stream
	};
aymeric's avatar
aymeric committed
337 338

	rtp_session_set_profile(rtps,profile);
339
	if (rem_rtp_port>0) rtp_session_set_remote_addr_full(rtps,rem_rtp_ip,rem_rtp_port,rem_rtcp_ip,rem_rtcp_port);
Simon Morlat's avatar
Simon Morlat committed
340 341 342
	if (rem_rtcp_port<=0){
		rtp_session_enable_rtcp(rtps,FALSE);
	}
aymeric's avatar
aymeric committed
343 344
	rtp_session_set_payload_type(rtps,payload);
	rtp_session_set_jitter_compensation(rtps,jitt_comp);
345
	rtp_session_set_rtcp_xr_media_callbacks(rtps, &rtcp_xr_media_cbs);
Jehan Monnier's avatar
Jehan Monnier committed
346

347
	if (rem_rtp_port>0)
Ghislain MARY's avatar
Ghislain MARY committed
348 349 350
		ms_filter_call_method(stream->ms.rtpsend,MS_RTP_SEND_SET_SESSION,rtps);
	stream->ms.rtprecv=ms_filter_new(MS_RTP_RECV_ID);
	ms_filter_call_method(stream->ms.rtprecv,MS_RTP_RECV_SET_SESSION,rtps);
351
	stream->ms.sessions.rtp_session=rtps;
Jehan Monnier's avatar
Jehan Monnier committed
352

Yann Diorcet's avatar
Yann Diorcet committed
353 354
	if((stream->features & AUDIO_STREAM_FEATURE_DTMF) != 0)
		stream->dtmfgen=ms_filter_new(MS_DTMF_GEN_ID);
Yann Diorcet's avatar
Yann Diorcet committed
355 356
	else
		stream->dtmfgen=NULL;
smorlat's avatar
smorlat committed
357
	rtp_session_signal_connect(rtps,"telephone-event",(RtpCallback)on_dtmf_received,(unsigned long)stream);
358
	rtp_session_signal_connect(rtps,"payload_type_changed",(RtpCallback)mediastream_payload_type_changed,(unsigned long)&stream->ms);
aymeric's avatar
aymeric committed
359
	/* creates the local part */
Simon Morlat's avatar
Simon Morlat committed
360 361 362
	if (captcard!=NULL){
		if (stream->soundread==NULL)
			stream->soundread=ms_snd_card_create_reader(captcard);
363
		has_builtin_ec=!!(ms_snd_card_get_capabilities(captcard) & MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER);
Simon Morlat's avatar
Simon Morlat committed
364
	}else {
aymeric's avatar
aymeric committed
365
		stream->soundread=ms_filter_new(MS_FILE_PLAYER_ID);
366
		stream->read_resampler=ms_filter_new(MS_RESAMPLE_ID);
aymeric's avatar
aymeric committed
367
	}
Simon Morlat's avatar
Simon Morlat committed
368 369 370 371
	if (playcard!=NULL) {
		if (stream->soundwrite==NULL)
			stream->soundwrite=ms_snd_card_create_writer(playcard);
	}else {
aymeric's avatar
aymeric committed
372 373
		stream->soundwrite=ms_filter_new(MS_FILE_REC_ID);
	}
Jehan Monnier's avatar
Jehan Monnier committed
374

aymeric's avatar
aymeric committed
375 376 377 378 379 380
	/* creates the couple of encoder/decoder */
	pt=rtp_profile_get_payload(profile,payload);
	if (pt==NULL){
		ms_error("audiostream.c: undefined payload type.");
		return -1;
	}
381
	nchannels=pt->channels;
Simon Morlat's avatar
Simon Morlat committed
382 383
	tel_ev=rtp_profile_get_payload_from_mime (profile,"telephone-event");

Yann Diorcet's avatar
Yann Diorcet committed
384
	if ((stream->features & AUDIO_STREAM_FEATURE_DTMF_ECHO) != 0 && (tel_ev==NULL || ( (tel_ev->flags & PAYLOAD_TYPE_FLAG_CAN_RECV) && !(tel_ev->flags & PAYLOAD_TYPE_FLAG_CAN_SEND)))
385 386 387 388
	    && ( strcasecmp(pt->mime_type,"pcmu")==0 || strcasecmp(pt->mime_type,"pcma")==0)){
		/*if no telephone-event payload is usable and pcma or pcmu is used, we will generate
		  inband dtmf*/
		stream->dtmfgen_rtp=ms_filter_new (MS_DTMF_GEN_ID);
Yann Diorcet's avatar
Yann Diorcet committed
389 390
	} else {
		stream->dtmfgen_rtp=NULL;
391 392
	}
	
Ghislain MARY's avatar
Ghislain MARY committed
393
	if (ms_filter_call_method(stream->ms.rtpsend,MS_FILTER_GET_SAMPLE_RATE,&sample_rate)!=0){
394 395 396
		ms_error("Sample rate is unknown for RTP side !");
		return -1;
	}
397

Ghislain MARY's avatar
Ghislain MARY committed
398 399
	stream->ms.encoder=ms_filter_create_encoder(pt->mime_type);
	stream->ms.decoder=ms_filter_create_decoder(pt->mime_type);
400 401 402 403 404 405 406 407 408 409 410 411 412 413

	/* sample rate is already set for rtpsend and rtprcv, check if we have to adjust it to */
	/* be able to use the echo canceller wich may be limited (webrtc aecm max frequency is 16000 Hz) */
	// First check if we need to use the echo canceller
	// Overide feature if not requested or done at sound card level
	if ( ((stream->features & AUDIO_STREAM_FEATURE_EC) && !use_ec) || has_builtin_ec )
		stream->features &=~AUDIO_STREAM_FEATURE_EC;

	/*configure the echo canceller if required */
	if ((stream->features & AUDIO_STREAM_FEATURE_EC) == 0 && stream->ec != NULL) {
		ms_filter_destroy(stream->ec);
		stream->ec=NULL;
	}

Simon Morlat's avatar
Simon Morlat committed
414 415 416 417 418 419
	if ((stream->ms.encoder==NULL) || (stream->ms.decoder==NULL)){
		/* big problem: we have not a registered codec for this payload...*/
		ms_error("audio_stream_start_full: No decoder or encoder available for payload %s.",pt->mime_type);
		return -1;
	}
	
420 421 422 423 424 425 426 427 428
	/* check echo canceller max frequency and adjust sampling rate if needed when codec used is opus */
	if (stream->ec!=NULL) {
		if ((ms_filter_get_id(stream->ms.encoder) == MS_OPUS_ENC_ID) && (ms_filter_get_id(stream->ec) == MS_WEBRTC_AEC_ID)) { /* AECM allow 8000 or 16000 Hz or it will be bypassed */
			if (sample_rate>16000) {
				sample_rate=16000;
				ms_message("Sampling rate forced to 16kHz to allow the use of WebRTC AECM (Echo canceller)");
			}
		}
	}
429 430 431
	/*hack for opus, that claims stereo all the time, but we can't support stereo yet*/
	if (strcasecmp(pt->mime_type,"opus")==0)
		nchannels=1;
Simon Morlat's avatar
Simon Morlat committed
432
	
Ghislain MARY's avatar
Ghislain MARY committed
433
	if (ms_filter_has_method(stream->ms.decoder, MS_FILTER_SET_RTP_PAYLOAD_PICKER)) {
434
		ms_message("Decoder has FEC capabilities");
jehan's avatar
jehan committed
435 436
		picker_context.filter_graph_manager=stream;
		picker_context.picker=&audio_stream_payload_picker;
Ghislain MARY's avatar
Ghislain MARY committed
437
		ms_filter_call_method(stream->ms.decoder,MS_FILTER_SET_RTP_PAYLOAD_PICKER, &picker_context);
jehan's avatar
jehan committed
438
	}
439
	if ((stream->features & AUDIO_STREAM_FEATURE_VOL_SND) != 0)
Yann Diorcet's avatar
Yann Diorcet committed
440
		stream->volsend=ms_filter_new(MS_VOLUME_ID);
Yann Diorcet's avatar
Yann Diorcet committed
441 442
	else
		stream->volsend=NULL;
443
	if ((stream->features & AUDIO_STREAM_FEATURE_VOL_RCV) != 0)
Yann Diorcet's avatar
Yann Diorcet committed
444 445 446
		stream->volrecv=ms_filter_new(MS_VOLUME_ID);
	else
		stream->volrecv=NULL;
jehan's avatar
jehan committed
447 448
	audio_stream_enable_echo_limiter(stream,stream->el_type);
	audio_stream_enable_noise_gate(stream,stream->use_ng);
449 450 451 452 453 454 455
	
	if (ms_filter_implements_interface(stream->soundread,MSFilterPlayerInterface) && infile){
		audio_stream_play(stream,infile);
	}
	if (ms_filter_implements_interface(stream->soundwrite,MSFilterPlayerInterface) && outfile){
		audio_stream_record(stream,outfile);
	}
aymeric's avatar
aymeric committed
456

457 458 459 460 461 462 463
	if (stream->use_agc){
		int tmp=1;
		if (stream->volsend==NULL)
			stream->volsend=ms_filter_new(MS_VOLUME_ID);
		ms_filter_call_method(stream->volsend,MS_VOLUME_ENABLE_AGC,&tmp);
	}

464
	if (stream->dtmfgen) {
465
		ms_filter_call_method(stream->dtmfgen,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
466
		ms_filter_call_method(stream->dtmfgen,MS_FILTER_SET_NCHANNELS,&nchannels);
467 468
	}
	if (stream->dtmfgen_rtp) {
469
		ms_filter_call_method(stream->dtmfgen_rtp,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
470
		ms_filter_call_method(stream->dtmfgen_rtp,MS_FILTER_SET_NCHANNELS,&nchannels);
471
	}
aymeric's avatar
aymeric committed
472
	/* give the sound filters some properties */
473
	if (ms_filter_call_method(stream->soundread,MS_FILTER_SET_SAMPLE_RATE,&sample_rate) != 0) {
474 475 476
		/* need to add resampler*/
		if (stream->read_resampler == NULL) stream->read_resampler=ms_filter_new(MS_RESAMPLE_ID);
	}
477
	ms_filter_call_method(stream->soundread,MS_FILTER_SET_NCHANNELS,&nchannels);
478

479
	if (ms_filter_call_method(stream->soundwrite,MS_FILTER_SET_SAMPLE_RATE,&sample_rate) != 0) {
480 481 482
		/* need to add resampler*/
		if (stream->write_resampler == NULL) stream->write_resampler=ms_filter_new(MS_RESAMPLE_ID);
	}
483
	ms_filter_call_method(stream->soundwrite,MS_FILTER_SET_NCHANNELS,&nchannels);
Jehan Monnier's avatar
Jehan Monnier committed
484

485
	if (stream->ec){
486 487 488 489 490
		if (!stream->is_ec_delay_set){
			int delay_ms=ms_snd_card_get_minimal_latency(captcard);
			if (delay_ms!=0){
				ms_message("Setting echo canceller delay with value provided by soundcard: %i ms",delay_ms);
			}
491
			ms_filter_call_method(stream->ec,MS_ECHO_CANCELLER_SET_DELAY,&delay_ms);
Simon Morlat's avatar
Simon Morlat committed
492 493
		}else {
			ms_message("Setting echo canceller delay with value configured by application.");
494
		}
495
		ms_filter_call_method(stream->ec,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
496
	}
497 498 499 500 501 502 503 504 505 506
	
	if (stream->features & AUDIO_STREAM_FEATURE_MIXED_RECORDING){
		int val=0;
		int pin=1;
		stream->recorder=ms_filter_new(MS_FILE_REC_ID);
		stream->recorder_mixer=ms_filter_new(MS_AUDIO_MIXER_ID);
		stream->recv_tee=ms_filter_new(MS_TEE_ID);
		stream->send_tee=ms_filter_new(MS_TEE_ID);
		ms_filter_call_method(stream->recorder_mixer,MS_AUDIO_MIXER_ENABLE_CONFERENCE_MODE,&val);
		ms_filter_call_method(stream->recorder_mixer,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
507
		ms_filter_call_method(stream->recorder_mixer,MS_FILTER_SET_NCHANNELS,&nchannels);
508 509 510
		ms_filter_call_method(stream->recv_tee,MS_TEE_MUTE,&pin);
		ms_filter_call_method(stream->send_tee,MS_TEE_MUTE,&pin);
		ms_filter_call_method(stream->recorder,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
511
		ms_filter_call_method(stream->recorder,MS_FILTER_SET_NCHANNELS,&nchannels);
512 513
		
	}
514

aymeric's avatar
aymeric committed
515
	/* give the encoder/decoder some parameters*/
516
	ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
jehan's avatar
jehan committed
517 518 519 520 521 522
	if (stream->ms.target_bitrate<=0) {
		ms_message("target bitrate not set for stream [%p] using payload's bitrate is %i",stream,stream->ms.target_bitrate=pt->normal_bitrate);
	}
	if (stream->ms.target_bitrate>0){
		ms_message("Setting audio encoder network bitrate to [%i] on stream [%p]",stream->ms.target_bitrate,stream);
		ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_BITRATE,&stream->ms.target_bitrate);
aymeric's avatar
aymeric committed
523
	}
524
	rtp_session_set_target_upload_bandwidth(stream->ms.sessions.rtp_session, stream->ms.target_bitrate);
525
	ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_NCHANNELS,&nchannels);
526
	ms_filter_call_method(stream->ms.decoder,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
527
	ms_filter_call_method(stream->ms.decoder,MS_FILTER_SET_NCHANNELS,&nchannels);
Jehan Monnier's avatar
Jehan Monnier committed
528

529 530 531 532 533 534 535 536 537
	if (pt->send_fmtp!=NULL) {
		char value[16]={0};
		int ptime;
		if (ms_filter_has_method(stream->ms.encoder,MS_AUDIO_ENCODER_SET_PTIME)){
			if (fmtp_get_value(pt->send_fmtp,"ptime",value,sizeof(value)-1)){
				ptime=atoi(value);
				ms_filter_call_method(stream->ms.encoder,MS_AUDIO_ENCODER_SET_PTIME,&ptime);
			}
		}
538
		ms_filter_call_method(stream->ms.encoder,MS_FILTER_ADD_FMTP, (void*)pt->send_fmtp);
539
	}
Ghislain MARY's avatar
Ghislain MARY committed
540
	if (pt->recv_fmtp!=NULL) ms_filter_call_method(stream->ms.decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp);
Jehan Monnier's avatar
Jehan Monnier committed
541

smorlat's avatar
smorlat committed
542
	/*create the equalizer*/
543
	if ((stream->features & AUDIO_STREAM_FEATURE_EQUALIZER) != 0){
Yann Diorcet's avatar
Yann Diorcet committed
544
		stream->equalizer=ms_filter_new(MS_EQUALIZER_ID);
545 546 547 548 549
		if(stream->equalizer) {
			tmp=stream->eq_active;
			ms_filter_call_method(stream->equalizer,MS_EQUALIZER_SET_ACTIVE,&tmp);
		}
	}else
Yann Diorcet's avatar
Yann Diorcet committed
550
		stream->equalizer=NULL;
551
	
552 553
	/*configure resamplers if needed*/
	if (stream->read_resampler){
554
		audio_stream_configure_resampler(stream->read_resampler,stream->soundread,stream->ms.encoder,8000,pt->clock_rate);
555
	}
Yann Diorcet's avatar
Yann Diorcet committed
556

557
	if (stream->write_resampler){
558
		audio_stream_configure_resampler(stream->write_resampler,stream->ms.decoder,stream->soundwrite,pt->clock_rate,8000);
559
	}
560
	
Ghislain MARY's avatar
Ghislain MARY committed
561
	if (stream->ms.use_rc){
562
		stream->ms.rc=ms_audio_bitrate_controller_new(stream->ms.sessions.rtp_session,stream->ms.encoder,0);
563 564
	}
	
565
	/* Create generic PLC if not handled by the decoder directly*/
Yann Diorcet's avatar
Yann Diorcet committed
566 567
	if ((stream->features & AUDIO_STREAM_FEATURE_PLC) != 0) {
		int decoder_have_plc = 0;
568 569 570
		if (ms_filter_has_method(stream->ms.decoder, MS_AUDIO_DECODER_HAVE_PLC)) {
			if (ms_filter_call_method(stream->ms.decoder, MS_AUDIO_DECODER_HAVE_PLC, &decoder_have_plc) != 0) {
				ms_warning("MS_AUDIO_DECODER_HAVE_PLC function error: enable default plc");
571 572
			}
		} else {
Yann Diorcet's avatar
Yann Diorcet committed
573 574
			ms_warning("MS_DECODER_HAVE_PLC function not implemented by the decoder: enable default plc");
		}
575
		if (decoder_have_plc == 0) {
Yann Diorcet's avatar
Yann Diorcet committed
576
			stream->plc = ms_filter_new(MS_GENERIC_PLC_ID);
577
		}
Yann Diorcet's avatar
Yann Diorcet committed
578

Sylvain Berfini's avatar
Sylvain Berfini committed
579
		if (stream->plc) {
580
			ms_filter_call_method(stream->plc, MS_FILTER_SET_NCHANNELS, &nchannels);
Yann Diorcet's avatar
Yann Diorcet committed
581
			ms_filter_call_method(stream->plc, MS_FILTER_SET_SAMPLE_RATE, &sample_rate);
Sylvain Berfini's avatar
Sylvain Berfini committed
582
		}
Yann Diorcet's avatar
Yann Diorcet committed
583 584
	} else {
		stream->plc = NULL;
Yann Diorcet's avatar
Yann Diorcet committed
585
	}
586 587 588 589
	
	if (stream->features & AUDIO_STREAM_FEATURE_LOCAL_PLAYING){
		stream->local_mixer=ms_filter_new(MS_AUDIO_MIXER_ID);
	}
Yann Diorcet's avatar
Yann Diorcet committed
590

Simon Morlat's avatar
Simon Morlat committed
591
	/* create ticker */
592 593
	if (stream->ms.sessions.ticker==NULL) media_stream_start_ticker(&stream->ms);
	if (stream->ms.state==MSStreamPreparing){
Simon Morlat's avatar
Simon Morlat committed
594 595
		/*we were using the dummy preload graph, destroy it but keep sound filters*/
		_audio_stream_unprepare_sound(stream,TRUE);
Simon Morlat's avatar
Simon Morlat committed
596 597
	}
	
aymeric's avatar
aymeric committed
598 599
	/* and then connect all */
	/* tip: draw yourself the picture if you don't understand */
Jehan Monnier's avatar
Jehan Monnier committed
600

601 602 603
	/*sending graph*/
	ms_connection_helper_start(&h);
	ms_connection_helper_link(&h,stream->soundread,-1,0);
604 605
	if (stream->read_resampler)
		ms_connection_helper_link(&h,stream->read_resampler,0,0);
606 607 608 609
	if (stream->ec)
		ms_connection_helper_link(&h,stream->ec,1,1);
	if (stream->volsend)
		ms_connection_helper_link(&h,stream->volsend,0,0);
610 611
	if (stream->dtmfgen_rtp)
		ms_connection_helper_link(&h,stream->dtmfgen_rtp,0,0);
612 613
	if (stream->send_tee)
		ms_connection_helper_link(&h,stream->send_tee,0,0);
Ghislain MARY's avatar
Ghislain MARY committed
614 615
	ms_connection_helper_link(&h,stream->ms.encoder,0,0);
	ms_connection_helper_link(&h,stream->ms.rtpsend,0,-1);
616 617 618

	/*receiving graph*/
	ms_connection_helper_start(&h);
Ghislain MARY's avatar
Ghislain MARY committed
619 620
	ms_connection_helper_link(&h,stream->ms.rtprecv,-1,0);
	ms_connection_helper_link(&h,stream->ms.decoder,0,0);
621
	if (stream->plc)
Yann Diorcet's avatar
Yann Diorcet committed
622 623 624
		ms_connection_helper_link(&h,stream->plc,0,0);
	if (stream->dtmfgen)
		ms_connection_helper_link(&h,stream->dtmfgen,0,0);
625 626
	if (stream->volrecv)
		ms_connection_helper_link(&h,stream->volrecv,0,0);
627 628
	if (stream->recv_tee)
		ms_connection_helper_link(&h,stream->recv_tee,0,0);
629 630
	if (stream->equalizer)
		ms_connection_helper_link(&h,stream->equalizer,0,0);
631 632
	if (stream->local_mixer){
		ms_connection_helper_link(&h,stream->local_mixer,0,0);
633
		setup_local_player(stream,sample_rate, nchannels);
634
	}
635 636
	if (stream->ec)
		ms_connection_helper_link(&h,stream->ec,0,0);
637 638
	if (stream->write_resampler)
		ms_connection_helper_link(&h,stream->write_resampler,0,0);
639
	ms_connection_helper_link(&h,stream->soundwrite,0,-1);
Jehan Monnier's avatar
Jehan Monnier committed
640

641 642 643 644 645 646 647
	/*call recording part, attached to both outgoing and incoming graphs*/
	if (stream->recorder){
		ms_filter_link(stream->send_tee,1,stream->recorder_mixer,0);
		ms_filter_link(stream->recv_tee,1,stream->recorder_mixer,1);
		ms_filter_link(stream->recorder_mixer,0,stream->recorder,0);
	}
	
jehan's avatar
jehan committed
648
	/*to make sure all preprocess are done before befre processing audio*/
649
	ms_ticker_attach_multiple(stream->ms.sessions.ticker
650 651 652
				,stream->soundread
				,stream->ms.rtprecv
				,NULL);
Jehan Monnier's avatar
Jehan Monnier committed
653

654
	stream->ms.start_time=stream->last_packet_time=ms_time(NULL);
655
	stream->ms.is_beginning=TRUE;
656
	stream->ms.state=MSStreamStarted;
657

aymeric's avatar
aymeric committed
658 659 660 661 662 663
	return 0;
}

int audio_stream_start_with_files(AudioStream *stream, RtpProfile *prof,const char *remip, int remport,
	int rem_rtcp_port, int pt,int jitt_comp, const char *infile, const char * outfile)
{
664
	return audio_stream_start_full(stream,prof,remip,remport,remip,rem_rtcp_port,pt,jitt_comp,infile,outfile,NULL,NULL,FALSE);
aymeric's avatar
aymeric committed
665 666 667 668
}

AudioStream * audio_stream_start(RtpProfile *prof,int locport,const char *remip,int remport,int profile,int jitt_comp,bool_t use_ec)
{
aymeric's avatar
aymeric committed
669 670
	MSSndCard *sndcard_playback;
	MSSndCard *sndcard_capture;
aymeric's avatar
aymeric committed
671
	AudioStream *stream;
aymeric's avatar
aymeric committed
672 673 674
	sndcard_capture=ms_snd_card_manager_get_default_capture_card(ms_snd_card_manager_get());
	sndcard_playback=ms_snd_card_manager_get_default_playback_card(ms_snd_card_manager_get());
	if (sndcard_capture==NULL || sndcard_playback==NULL)
aymeric's avatar
aymeric committed
675
		return NULL;
676
	stream=audio_stream_new(locport, locport+1, ms_is_ipv6(remip));
677
	if (audio_stream_start_full(stream,prof,remip,remport,remip,remport+1,profile,jitt_comp,NULL,NULL,sndcard_playback,sndcard_capture,use_ec)==0) return stream;
aymeric's avatar
aymeric committed
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
	audio_stream_free(stream);
	return NULL;
}

AudioStream *audio_stream_start_with_sndcards(RtpProfile *prof,int locport,const char *remip,int remport,int profile,int jitt_comp,MSSndCard *playcard, MSSndCard *captcard, bool_t use_ec)
{
	AudioStream *stream;
	if (playcard==NULL) {
		ms_error("No playback card.");
		return NULL;
	}
	if (captcard==NULL) {
		ms_error("No capture card.");
		return NULL;
	}
693
	stream=audio_stream_new(locport, locport+1, ms_is_ipv6(remip));
694
	if (audio_stream_start_full(stream,prof,remip,remport,remip,remport+1,profile,jitt_comp,NULL,NULL,playcard,captcard,use_ec)==0) return stream;
aymeric's avatar
aymeric committed
695 696 697 698
	audio_stream_free(stream);
	return NULL;
}

699
// Pass NULL to stop playing
aymeric's avatar
aymeric committed
700
void audio_stream_play(AudioStream *st, const char *name){
701 702 703 704
	if (st->soundread == NULL) {
		ms_warning("Cannot play file: the stream hasn't been started");
		return;
	}
aymeric's avatar
aymeric committed
705 706
	if (ms_filter_get_id(st->soundread)==MS_FILE_PLAYER_ID){
		ms_filter_call_method_noarg(st->soundread,MS_FILE_PLAYER_CLOSE);
707 708 709
		if (name != NULL) {
			ms_filter_call_method(st->soundread,MS_FILE_PLAYER_OPEN,(void*)name);
			if (st->read_resampler){
710 711 712
				int fallback_to_rate=8000;
				ms_filter_call_method(st->ms.rtpsend,MS_FILTER_GET_SAMPLE_RATE,&fallback_to_rate);
				audio_stream_configure_resampler(st->read_resampler,st->soundread,st->ms.encoder, 8000, fallback_to_rate);
713 714
			}
			ms_filter_call_method_noarg(st->soundread,MS_FILE_PLAYER_START);
715
		}
aymeric's avatar
aymeric committed
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
	}else{
		ms_error("Cannot play file: the stream hasn't been started with"
		" audio_stream_start_with_files");
	}
}

void audio_stream_record(AudioStream *st, const char *name){
	if (ms_filter_get_id(st->soundwrite)==MS_FILE_REC_ID){
		ms_filter_call_method_noarg(st->soundwrite,MS_FILE_REC_CLOSE);
		ms_filter_call_method(st->soundwrite,MS_FILE_REC_OPEN,(void*)name);
		ms_filter_call_method_noarg(st->soundwrite,MS_FILE_REC_START);
	}else{
		ms_error("Cannot record file: the stream hasn't been started with"
		" audio_stream_start_with_files");
	}
}

733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777

int audio_stream_mixed_record_open(AudioStream *st, const char* filename){
	if (!(st->features & AUDIO_STREAM_FEATURE_MIXED_RECORDING)){
		if (audio_stream_started(st)){
			ms_error("Too late - you cannot request a mixed recording when the stream is running because it did not have AUDIO_STREAM_FEATURE_MIXED_RECORDING feature.");
			return -1;
		}else{
			st->features|=AUDIO_STREAM_FEATURE_MIXED_RECORDING;
		}
	}
	if (st->recorder_file){
		audio_stream_mixed_record_stop(st);
	}
	st->recorder_file=filename ? ms_strdup(filename) : NULL;
	return 0;
}

int audio_stream_mixed_record_start(AudioStream *st){
	if (st->recorder && st->recorder_file){
		int pin=1;
		MSRecorderState state;
		ms_filter_call_method(st->recorder,MS_RECORDER_GET_STATE,&state);
		if (state==MSRecorderClosed){
			if (ms_filter_call_method(st->recorder,MS_RECORDER_OPEN,st->recorder_file)==-1)
				return -1;
		}
		ms_filter_call_method_noarg(st->recorder,MS_RECORDER_START);
		ms_filter_call_method(st->recv_tee,MS_TEE_UNMUTE,&pin);
		ms_filter_call_method(st->send_tee,MS_TEE_UNMUTE,&pin);
		return 0;
	}
	return -1;
}

int audio_stream_mixed_record_stop(AudioStream *st){
	if (st->recorder && st->recorder_file){
		int pin=1;
		ms_filter_call_method_noarg(st->recorder,MS_RECORDER_PAUSE);
		ms_filter_call_method(st->recv_tee,MS_TEE_MUTE,&pin);
		ms_filter_call_method(st->send_tee,MS_TEE_MUTE,&pin);
		ms_filter_call_method_noarg(st->recorder,MS_RECORDER_CLOSE);
	}
	return 0;
}

Yann Diorcet's avatar
Yann Diorcet committed
778 779 780 781 782 783 784
uint32_t audio_stream_get_features(AudioStream *st){
	return st->features;
}

void audio_stream_set_features(AudioStream *st, uint32_t features){
	st->features = features;
}
aymeric's avatar
aymeric committed
785

786
AudioStream *audio_stream_new_with_sessions(const MSMediaStreamSessions *sessions){
aymeric's avatar
aymeric committed
787
	AudioStream *stream=(AudioStream *)ms_new0(AudioStream,1);
788
	MSFilterDesc *ec_desc=ms_filter_lookup_by_name("MSOslec");
Simon Morlat's avatar
Simon Morlat committed
789 790 791
	
	ms_filter_enable_statistics(TRUE);
	ms_filter_reset_statistics();
Ghislain MARY's avatar
Ghislain MARY committed
792 793

	stream->ms.type = AudioStreamType;
794
	stream->ms.sessions=*sessions;
795
	/*some filters are created right now to allow configuration by the application before start() */
Ghislain MARY's avatar
Ghislain MARY committed
796 797
	stream->ms.rtpsend=ms_filter_new(MS_RTP_SEND_ID);
	stream->ms.ice_check_list=NULL;
798
	stream->ms.qi=ms_quality_indicator_new(stream->ms.sessions.rtp_session);
jehan's avatar
jehan committed
799
	stream->ms.process_rtcp=audio_stream_process_rtcp;
800
	if (ec_desc!=NULL){
801
		stream->ec=ms_filter_new_from_desc(ec_desc);
802
	}else{
803
#if defined(BUILD_WEBRTC_AECM)
Ghislain MARY's avatar
Ghislain MARY committed
804 805
		stream->ec=ms_filter_new(MS_WEBRTC_AEC_ID);
#else
806
		stream->ec=ms_filter_new(MS_SPEEX_EC_ID);
Ghislain MARY's avatar
Ghislain MARY committed
807
#endif
808
	}
Ghislain MARY's avatar
Ghislain MARY committed
809
	stream->ms.evq=ortp_ev_queue_new();
810
	rtp_session_register_event_queue(stream->ms.sessions.rtp_session,stream->ms.evq);
smorlat's avatar
smorlat committed
811
	stream->play_dtmfs=TRUE;
smorlat's avatar
smorlat committed
812
	stream->use_gc=FALSE;
813
	stream->use_agc=FALSE;
814
	stream->use_ng=FALSE;
Yann Diorcet's avatar
Yann Diorcet committed
815
	stream->features=AUDIO_STREAM_FEATURE_ALL;
aymeric's avatar
aymeric committed
816 817 818
	return stream;
}

819 820 821 822 823 824 825 826 827
AudioStream *audio_stream_new(int loc_rtp_port, int loc_rtcp_port, bool_t ipv6){
	AudioStream *obj;
	MSMediaStreamSessions sessions={0};
	sessions.rtp_session=create_duplex_rtpsession(loc_rtp_port,loc_rtcp_port,ipv6);
	obj=audio_stream_new_with_sessions(&sessions);
	obj->ms.owns_sessions=TRUE;
	return obj;
}

smorlat's avatar
smorlat committed
828 829 830 831
void audio_stream_play_received_dtmfs(AudioStream *st, bool_t yesno){
	st->play_dtmfs=yesno;
}

aymeric's avatar
aymeric committed
832
int audio_stream_start_now(AudioStream *stream, RtpProfile * prof,  const char *remip, int remport, int rem_rtcp_port, int payload_type, int jitt_comp, MSSndCard *playcard, MSSndCard *captcard, bool_t use_ec){
833
	return audio_stream_start_full(stream,prof,remip,remport,remip,rem_rtcp_port,
aymeric's avatar
aymeric committed
834 835 836 837
		payload_type,jitt_comp,NULL,NULL,playcard,captcard,use_ec);
}

void audio_stream_set_relay_session_id(AudioStream *stream, const char *id){
Ghislain MARY's avatar
Ghislain MARY committed
838
	ms_filter_call_method(stream->ms.rtpsend, MS_RTP_SEND_SET_RELAY_SESSION_ID,(void*)id);
aymeric's avatar
aymeric committed
839 840
}

841
void audio_stream_set_echo_canceller_params(AudioStream *stream, int tail_len_ms, int delay_ms, int framesize){
842
	if (stream->ec){
843
		if (tail_len_ms>0)
844
			ms_filter_call_method(stream->ec,MS_ECHO_CANCELLER_SET_TAIL_LENGTH,&tail_len_ms);
845 846
		if (delay_ms>0){
			stream->is_ec_delay_set=TRUE;
847 848
			ms_filter_call_method(stream->ec,MS_ECHO_CANCELLER_SET_DELAY,&delay_ms);
		}
849
		if (framesize>0)
850
			ms_filter_call_method(stream->ec,MS_ECHO_CANCELLER_SET_FRAMESIZE,&framesize);
851
	}
852 853
}

854 855
void audio_stream_enable_echo_limiter(AudioStream *stream, EchoLimiterType type){
	stream->el_type=type;
jehan's avatar
jehan committed
856 857 858 859 860 861 862
	if (stream->volsend){
		bool_t enable_noise_gate = stream->el_type==ELControlFull;
		ms_filter_call_method(stream->volrecv,MS_VOLUME_ENABLE_NOISE_GATE,&enable_noise_gate);
		ms_filter_call_method(stream->volsend,MS_VOLUME_SET_PEER,type!=ELInactive?stream->volrecv:NULL);
	} else {
		ms_warning("cannot set echo limiter to mode [%i] because no volume send",type);
	}
863 864
}

smorlat's avatar
smorlat committed
865