audiostream.c 39.2 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
	rtp_session_set_payload_type(stream->ms.sessions.rtp_session,0);
195
	rtp_session_enable_rtcp(stream->ms.sessions.rtp_session, FALSE);
196
	ms_filter_call_method(stream->dummy,MS_RTP_RECV_SET_SESSION,stream->ms.sessions.rtp_session);
197

Simon Morlat's avatar
Simon Morlat committed
198
	if (captcard && playcard){
199
#ifdef __ios
Simon Morlat's avatar
Simon Morlat committed
200 201 202
		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);
203
#else
Ghislain MARY's avatar
Ghislain MARY committed
204 205
		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
206
#endif
207
	} else {
Ghislain MARY's avatar
Ghislain MARY committed
208 209
		stream->ms.voidsink=ms_filter_new(MS_VOID_SINK_ID);
		ms_filter_link(stream->dummy,0,stream->ms.voidsink,0);
210
	}
211 212 213
	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
214 215
}

Simon Morlat's avatar
Simon Morlat committed
216
static void _audio_stream_unprepare_sound(AudioStream *stream, bool_t keep_sound_resources){
217
	if (stream->ms.state==MSStreamPreparing){
Simon Morlat's avatar
Simon Morlat committed
218
		stop_preload_graph(stream);
219
#ifdef __ios
Simon Morlat's avatar
Simon Morlat committed
220 221 222 223 224 225
		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
226
#endif
227
	}
228
	stream->ms.state=MSStreamInitialized;
Simon Morlat's avatar
Simon Morlat committed
229 230
}

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

235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
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
255
	int master=0;
256 257 258 259 260 261 262 263 264 265 266 267 268
	
	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
269
	ms_filter_call_method(stream->local_mixer,MS_AUDIO_MIXER_SET_MASTER_CHANNEL,&master);
270 271 272
	ms_filter_add_notify_callback(stream->local_player,player_callback,stream,TRUE);
}

273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
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;
}

289
static int audio_stream_get_rtcp_xr_signal_level(unsigned long userdata) {
290 291 292 293
	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);
294
		return (int)volume;
295 296 297 298
	}
	return ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
}

299
static int audio_stream_get_rtcp_xr_noise_level(unsigned long userdata) {
300 301 302 303
	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);
304
		return (int)volume;
305 306 307 308 309 310 311 312 313 314 315 316 317 318
	}
	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);
}

319 320
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,
321 322
	MSSndCard *playcard, MSSndCard *captcard, bool_t use_ec){
	RtpSession *rtps=stream->ms.sessions.rtp_session;
Simon Morlat's avatar
Simon Morlat committed
323
	PayloadType *pt,*tel_ev;
324 325
	int tmp;
	MSConnectionHelper h;
326
	int sample_rate;
jehan's avatar
jehan committed
327
	MSRtpPayloadPickerContext picker_context;
328
	int nchannels;
329
	bool_t has_builtin_ec=FALSE;
330 331 332 333 334 335 336 337
	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
338 339

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

350
	if (rem_rtp_port>0)
Ghislain MARY's avatar
Ghislain MARY committed
351 352 353
		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);
354
	stream->ms.sessions.rtp_session=rtps;
Jehan Monnier's avatar
Jehan Monnier committed
355

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

aymeric's avatar
aymeric committed
378 379 380 381 382 383
	/* 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;
	}
384
	nchannels=pt->channels;
Simon Morlat's avatar
Simon Morlat committed
385 386
	tel_ev=rtp_profile_get_payload_from_mime (profile,"telephone-event");

Yann Diorcet's avatar
Yann Diorcet committed
387
	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)))
388 389 390 391
	    && ( 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
392 393
	} else {
		stream->dtmfgen_rtp=NULL;
394 395
	}
	
Ghislain MARY's avatar
Ghislain MARY committed
396
	if (ms_filter_call_method(stream->ms.rtpsend,MS_FILTER_GET_SAMPLE_RATE,&sample_rate)!=0){
397 398 399
		ms_error("Sample rate is unknown for RTP side !");
		return -1;
	}
400

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

	/* 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
417 418 419 420 421 422
	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;
	}
	
423 424 425 426 427 428 429 430 431
	/* 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)");
			}
		}
	}
432 433 434
	/*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
435
	
Ghislain MARY's avatar
Ghislain MARY committed
436
	if (ms_filter_has_method(stream->ms.decoder, MS_FILTER_SET_RTP_PAYLOAD_PICKER)) {
437
		ms_message("Decoder has FEC capabilities");
jehan's avatar
jehan committed
438 439
		picker_context.filter_graph_manager=stream;
		picker_context.picker=&audio_stream_payload_picker;
Ghislain MARY's avatar
Ghislain MARY committed
440
		ms_filter_call_method(stream->ms.decoder,MS_FILTER_SET_RTP_PAYLOAD_PICKER, &picker_context);
jehan's avatar
jehan committed
441
	}
442
	if ((stream->features & AUDIO_STREAM_FEATURE_VOL_SND) != 0)
Yann Diorcet's avatar
Yann Diorcet committed
443
		stream->volsend=ms_filter_new(MS_VOLUME_ID);
Yann Diorcet's avatar
Yann Diorcet committed
444 445
	else
		stream->volsend=NULL;
446
	if ((stream->features & AUDIO_STREAM_FEATURE_VOL_RCV) != 0)
Yann Diorcet's avatar
Yann Diorcet committed
447 448 449
		stream->volrecv=ms_filter_new(MS_VOLUME_ID);
	else
		stream->volrecv=NULL;
jehan's avatar
jehan committed
450 451
	audio_stream_enable_echo_limiter(stream,stream->el_type);
	audio_stream_enable_noise_gate(stream,stream->use_ng);
452 453 454 455 456 457 458
	
	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
459

460 461 462 463 464 465 466
	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);
	}

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

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

488
	if (stream->ec){
489 490 491 492 493
		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);
			}
494
			ms_filter_call_method(stream->ec,MS_ECHO_CANCELLER_SET_DELAY,&delay_ms);
Simon Morlat's avatar
Simon Morlat committed
495 496
		}else {
			ms_message("Setting echo canceller delay with value configured by application.");
497
		}
498
		ms_filter_call_method(stream->ec,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
499
	}
500 501 502 503 504 505 506 507 508 509
	
	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);
510
		ms_filter_call_method(stream->recorder_mixer,MS_FILTER_SET_NCHANNELS,&nchannels);
511 512 513
		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);
514
		ms_filter_call_method(stream->recorder,MS_FILTER_SET_NCHANNELS,&nchannels);
515 516
		
	}
517

aymeric's avatar
aymeric committed
518
	/* give the encoder/decoder some parameters*/
519
	ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
jehan's avatar
jehan committed
520 521 522 523 524 525
	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
526
	}
527
	rtp_session_set_target_upload_bandwidth(rtps, stream->ms.target_bitrate);
528
	ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_NCHANNELS,&nchannels);
529
	ms_filter_call_method(stream->ms.decoder,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
530
	ms_filter_call_method(stream->ms.decoder,MS_FILTER_SET_NCHANNELS,&nchannels);
Jehan Monnier's avatar
Jehan Monnier committed
531

532 533 534 535 536 537 538 539 540
	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);
			}
		}
541
		ms_filter_call_method(stream->ms.encoder,MS_FILTER_ADD_FMTP, (void*)pt->send_fmtp);
542
	}
Ghislain MARY's avatar
Ghislain MARY committed
543
	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
544

smorlat's avatar
smorlat committed
545
	/*create the equalizer*/
546
	if ((stream->features & AUDIO_STREAM_FEATURE_EQUALIZER) != 0){
Yann Diorcet's avatar
Yann Diorcet committed
547
		stream->equalizer=ms_filter_new(MS_EQUALIZER_ID);
548 549 550 551 552
		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
553
		stream->equalizer=NULL;
554
	
555 556
	/*configure resamplers if needed*/
	if (stream->read_resampler){
557
		audio_stream_configure_resampler(stream->read_resampler,stream->soundread,stream->ms.encoder,8000,pt->clock_rate);
558
	}
Yann Diorcet's avatar
Yann Diorcet committed
559

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

Sylvain Berfini's avatar
Sylvain Berfini committed
582
		if (stream->plc) {
583
			ms_filter_call_method(stream->plc, MS_FILTER_SET_NCHANNELS, &nchannels);
Yann Diorcet's avatar
Yann Diorcet committed
584
			ms_filter_call_method(stream->plc, MS_FILTER_SET_SAMPLE_RATE, &sample_rate);
Sylvain Berfini's avatar
Sylvain Berfini committed
585
		}
Yann Diorcet's avatar
Yann Diorcet committed
586 587
	} else {
		stream->plc = NULL;
Yann Diorcet's avatar
Yann Diorcet committed
588
	}
589 590 591 592
	
	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
593

Simon Morlat's avatar
Simon Morlat committed
594
	/* create ticker */
595 596
	if (stream->ms.sessions.ticker==NULL) media_stream_start_ticker(&stream->ms);
	if (stream->ms.state==MSStreamPreparing){
Simon Morlat's avatar
Simon Morlat committed
597 598
		/*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
599 600
	}
	
aymeric's avatar
aymeric committed
601 602
	/* and then connect all */
	/* tip: draw yourself the picture if you don't understand */
Jehan Monnier's avatar
Jehan Monnier committed
603

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

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

644 645 646 647 648 649 650
	/*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
651
	/*to make sure all preprocess are done before befre processing audio*/
652
	ms_ticker_attach_multiple(stream->ms.sessions.ticker
653 654 655
				,stream->soundread
				,stream->ms.rtprecv
				,NULL);
Jehan Monnier's avatar
Jehan Monnier committed
656

657
	stream->ms.start_time=stream->last_packet_time=ms_time(NULL);
658
	stream->ms.state=MSStreamStarted;
659

aymeric's avatar
aymeric committed
660 661 662 663 664 665
	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)
{
666
	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
667 668 669 670
}

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
671 672
	MSSndCard *sndcard_playback;
	MSSndCard *sndcard_capture;
aymeric's avatar
aymeric committed
673
	AudioStream *stream;
aymeric's avatar
aymeric committed
674 675 676
	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
677
		return NULL;
678
	stream=audio_stream_new(locport, locport+1, ms_is_ipv6(remip));
679
	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
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694
	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;
	}
695
	stream=audio_stream_new(locport, locport+1, ms_is_ipv6(remip));
696
	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
697 698 699 700
	audio_stream_free(stream);
	return NULL;
}

701
// Pass NULL to stop playing
aymeric's avatar
aymeric committed
702
void audio_stream_play(AudioStream *st, const char *name){
703 704 705 706
	if (st->soundread == NULL) {
		ms_warning("Cannot play file: the stream hasn't been started");
		return;
	}
aymeric's avatar
aymeric committed
707 708
	if (ms_filter_get_id(st->soundread)==MS_FILE_PLAYER_ID){
		ms_filter_call_method_noarg(st->soundread,MS_FILE_PLAYER_CLOSE);
709 710 711
		if (name != NULL) {
			ms_filter_call_method(st->soundread,MS_FILE_PLAYER_OPEN,(void*)name);
			if (st->read_resampler){
712 713 714
				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);
715 716
			}
			ms_filter_call_method_noarg(st->soundread,MS_FILE_PLAYER_START);
717
		}
aymeric's avatar
aymeric committed
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734
	}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");
	}
}

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 778 779

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
780 781 782 783 784 785 786
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
787

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

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

821 822 823 824 825 826 827 828 829
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
830 831 832 833
void audio_stream_play_received_dtmfs(AudioStream *st, bool_t yesno){
	st->play_dtmfs=yesno;
}

aymeric's avatar
aymeric committed
834
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){
835
	return audio_stream_start_full(stream,prof,remip,remport,remip,rem_rtcp_port,
aymeric's avatar
aymeric committed
836 837 838 839
		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
840
	ms_filter_call_method(stream->ms.rtpsend, MS_RTP_SEND_SET_RELAY_SESSION_ID,(void*)id);
aymeric's avatar
aymeric committed
841 842
}

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

856 857
void audio_stream_enable_echo_limiter(AudioStream *stream, EchoLimiterType type){
	stream->el_type=type;
jehan's avatar
jehan committed
858 859 860 861 862 863 864
	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);