mediastream.c 44.8 KB
Newer Older
aymeric's avatar
aymeric committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
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
17
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
aymeric's avatar
aymeric committed
18 19 20
*/


21
#include <math.h>
22
#include "common.h"
23
#include "mediastreamer2/msequalizer.h"
24
#include "mediastreamer2/msvolume.h"
aymeric's avatar
aymeric committed
25 26 27 28
#ifdef VIDEO_ENABLED
#include "mediastreamer2/msv4l.h"
#endif

29
#include <ctype.h>
aymeric's avatar
aymeric committed
30 31
#include <signal.h>
#include <sys/types.h>
32
#ifndef _WIN32
aymeric's avatar
aymeric committed
33
#include <unistd.h>
34
#include <poll.h>
35 36
#else
#include <malloc.h>
aymeric's avatar
aymeric committed
37 38 39 40 41
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

42
#ifdef TARGET_OS_MAC
43 44
#include <CoreFoundation/CFRunLoop.h>
#endif
45

46
#if TARGET_OS_IPHONE
jehan's avatar
jehan committed
47
#import <UIKit/UIKit.h>
jehan's avatar
jehan committed
48
#include <AudioToolbox/AudioToolbox.h>
49
#endif
50 51

#if  TARGET_OS_IPHONE || defined (ANDROID)
jehan's avatar
jehan committed
52
extern void ms_set_video_stream(VideoStream* video);
53
#if TARGET_OS_IPHONE || defined(HAVE_X264)
jehan's avatar
jehan committed
54 55
extern void libmsx264_init();
#endif
56
#if TARGET_OS_IPHONE || defined(HAVE_OPENH264)
57 58
extern void libmsopenh264_init();
#endif
59
#if TARGET_OS_IPHONE || defined(HAVE_SILK)
jehan's avatar
jehan committed
60
extern void libmssilk_init();
61
#endif
62
#if TARGET_OS_IPHONE || defined(HAVE_WEBRTC)
63
extern void libmswebrtc_init();
64
#endif
65
#endif // TARGET_OS_IPHONE || defined (ANDROID)
66

67 68 69 70 71
#ifdef ANDROID
#include <android/log.h>
#include <jni.h>
#endif

72 73
#include <ortp/b64.h>

74 75 76 77 78 79

#ifdef HAVE_CONFIG_H
#include "mediastreamer-config.h"
#endif


80 81
#define MEDIASTREAM_MAX_ICE_CANDIDATES 3

aymeric's avatar
aymeric committed
82 83
static int cond=1;

84 85 86 87 88 89
typedef enum _RcAlgo{
	RCAlgoNone,
	RCAlgoSimple,
	RCAlgoAdvanced,
	RCAlgoInvalid
}RcAlgo;
aymeric's avatar
aymeric committed
90

91 92 93 94 95 96
typedef struct _MediastreamIceCandidate {
	char ip[64];
	char type[6];
	int port;
} MediastreamIceCandidate;

97
typedef struct _MediastreamDatas {
98
	MSFactory *factory;
99
	int localport,remoteport,payload;
100
	char ip[64];
101 102
	char *send_fmtp;
	char *recv_fmtp;
103 104
	int jitter;
	int bitrate;
105
	int mtu;
106
	MSVideoSize vs;
107
	RcAlgo rc_algo;
108 109 110 111 112 113 114 115 116 117 118 119 120 121
	bool_t ec;
	bool_t agc;
	bool_t eq;
	bool_t is_verbose;
	int device_rotation;
	VideoStream *video;
	char * capture_card;
	char * playback_card;
	char * camera;
	char *infile,*outfile;
	float ng_threshold;
	bool_t use_ng;
	bool_t two_windows;
	bool_t el;
122
	bool_t enable_srtp;
123
	
124
	bool_t interactive;
125
	bool_t enable_avpf;
126
	bool_t enable_rtcp;
127
	bool_t freeze_on_error;
128
	
129 130 131 132 133 134 135 136 137 138 139 140
	float el_speed;
	float el_thres;
	float el_force;
	int el_sustain;
	float el_transmit_thres;
	float ng_floorgain;
	char * zrtp_secrets;
	PayloadType *custom_pt;
	int video_window_id;
	int preview_window_id;
	/* starting values echo canceller */
	int ec_len_ms, ec_delay_ms, ec_framesize;
141 142
	char* srtp_local_master_key;
	char* srtp_remote_master_key;
143
	OrtpNetworkSimulatorParams netsim;
144
	float zoom;
145
	float zoom_cx, zoom_cy;
146 147

	AudioStream *audio;
148 149 150 151
	PayloadType *pt;
	RtpSession *session;
	OrtpEvQueue *q;
	RtpProfile *profile;
152
	MSBandwidthController *bw_controller;
153

Ghislain MARY's avatar
Ghislain MARY committed
154
	IceSession *ice_session;
155 156 157 158
	MediastreamIceCandidate ice_local_candidates[MEDIASTREAM_MAX_ICE_CANDIDATES];
	MediastreamIceCandidate ice_remote_candidates[MEDIASTREAM_MAX_ICE_CANDIDATES];
	int ice_local_candidates_nb;
	int ice_remote_candidates_nb;
159
	char * video_display_filter;
160
	FILE * logfile;
161
	bool_t enable_speaker;
162 163
} MediastreamDatas;

164

165 166
// MAIN METHODS
/* init default arguments */
167
MediastreamDatas* init_default_args(void);
168 169 170 171
/* parse args */
bool_t parse_args(int argc, char** argv, MediastreamDatas* out);
/* setup streams */
void setup_media_streams(MediastreamDatas* args);
172 173
/* run loop*/
void mediastream_run_loop(MediastreamDatas* args);
174 175 176 177
/* exit */
void clear_mediastreams(MediastreamDatas* args);

// HELPER METHODS
178
void stop_handler(int signum);
179 180
static bool_t parse_addr(const char *addr, char *ip, size_t len, int *port);
static bool_t parse_ice_addr(char* addr, char* type, size_t type_len, char* ip, size_t ip_len, int* port);
181 182 183 184
static void display_items(void *user_data, uint32_t csrc, rtcp_sdes_type_t t, const char *content, uint8_t content_len);
static void parse_rtcp(mblk_t *m);
static void parse_events(RtpSession *session, OrtpEvQueue *q);
static bool_t parse_window_ids(const char *ids, int* video_id, int* preview_id);
185
static RcAlgo parse_rc_algo(const char *algo);
186

187 188 189 190 191
const char *usage="mediastream --local <port>\n"
								"--remote <ip:port> \n"
								"[--help (display this help) ]\n"
								"[--payload <payload type number or payload name like 'audio/pmcu/8000'> ]\n"
								"[ --agc (enable automatic gain control) ]\n"
192
								"[ --bitrate <bits per seconds> ]\n"
193 194
								"[ --camera <camera id as listed at startup> ]\n"
								"[ --capture-card <name> ]\n"
195
								"[ --ec (enable echo canceller) ]\n"
196
								"[ --ec-delay <echo canceller delay in ms> ]\n"
197
								"[ --ec-framesize <echo canceller framesize in samples> ]\n"
198
								"[ --ec-tail <echo canceller tail length in ms> ]\n"
jehan's avatar
jehan committed
199 200
								"[ --el (enable echo limiter) ]\n"
								"[ --el-force <(float) [0-1]> (The proportional coefficient controlling the mic attenuation) ]\n"
201
								"[ --el-speed <(float) [0-1]> (gain changes are smoothed with a coefficent) ]\n"
jehan's avatar
jehan committed
202
								"[ --el-sustain <(int)> (Time in milliseconds for which the attenuation is kept unchanged after) ]\n"
203
								"[ --el-thres <(float) [0-1]> (Threshold above which the system becomes active) ]\n"
204
								"[ --el-transmit-thres <(float) [0-1]> (TO BE DOCUMENTED) ]\n"
205
								"[ --fmtp <fmtpline> ]\n"
206
								"[ --recv_fmtp <fmtpline passed to decoder> ]\n"
207 208
								"[ --freeze-on-error (for video, stop upon decoding error until next valid frame) ]\n"
								"[ --height <pixels> ]\n"
209 210
								"[ --ice-local-candidate <ip:port:[host|srflx|prflx|relay]> ]\n"
								"[ --ice-remote-candidate <ip:port:[host|srflx|prflx|relay]> ]\n"
211 212 213 214
								"[ --infile <input wav file> specify a wav file to be used for input, instead of soundcard ]\n"
								"[ --interactive (run in interactive mode) ]\n"
								"[ --jitter <miliseconds> ]\n"
								"[ --log <file> ]\n"
215
								"[ --mtu <mtu> (specify MTU)]\n"
216 217 218 219 220 221 222 223 224 225 226 227 228 229
								"[ --netsim-bandwidth <bandwidth limit in bits/s> (simulates a network download bandwidth limit) ]\n"
								"[ --netsim-consecutive-loss-probability <0-1> (to simulate bursts of lost packets) ]\n"
								"[ --netsim-jitter-burst-density <0-10> (density of gap/burst events, 1.0=one gap/burst per second in average) ]\n"
								"[ --netsim-jitter-strength <0-100> (strength of the jitter simulation) ]\n"
								"[ --netsim-latency <latency in ms> (simulates a network latency) ]\n"
								"[ --netsim-lossrate <0-100> (simulates a network lost rate) ]\n"
								"[ --netsim-mode inbound|outboud (whether network simulation is applied to incoming (default) or outgoing stream) ]\n"
								"[ --ng (enable noise gate)] \n"
								"[ --ng-floorgain <(float) [0-1]> (gain applied to the signal when its energy is below the threshold.) ]\n"
								"[ --ng-threshold <(float) [0-1]> (noise gate threshold) ]\n"
								"[ --no-avpf ]\n"
								"[ --no-rtcp ]\n"
								"[ --outfile <output wav file> specify a wav file to write audio into, instead of soundcard ]\n"
								"[ --playback-card <name> ]\n"
230
								"[ --rc <rate control algorithm> possible values are: none, simple, advanced ]\n"
231 232 233 234 235 236 237
								"[ --srtp <local master_key> <remote master_key> (enable srtp, master key is generated if absent from comand line) ]\n"
								"[ --verbose (most verbose messages) ]\n"
								"[ --video-display-filter <name> ]\n"
								"[ --video-windows-id <video surface:preview surface >]\n"
								"[ --width <pixels> ]\n"
								"[ --zoom zoom factor ]\n"
								"[ --zrtp <secrets file> (enable zrtp) ]\n"
238 239 240
								#if TARGET_OS_IPHONE
								"[ --speaker route audio to speaker ]\n"
								#endif
241
								;
aymeric's avatar
aymeric committed
242

jehan's avatar
jehan committed
243 244 245 246
#if TARGET_OS_IPHONE
int g_argc;
char** g_argv;
static int _main(int argc, char * argv[]);
247

jehan's avatar
jehan committed
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
static void* apple_main(void* data) {
	 _main(g_argc,g_argv);
	 return NULL;
	}
int main(int argc, char * argv[]) {
	pthread_t main_thread;
	g_argc=argc;
	g_argv=argv;
	pthread_create(&main_thread,NULL,apple_main,NULL);
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	int value = UIApplicationMain(0, nil, nil, nil);
	[pool release];
	return value;
	cond=0;
	pthread_join(main_thread,NULL);
	return 0;
}
static int _main(int argc, char * argv[])
#endif
267

268
#if !TARGET_OS_MAC && !ANDROID
aymeric's avatar
aymeric committed
269
int main(int argc, char * argv[])
jehan's avatar
jehan committed
270 271
#endif

272
#if !ANDROID && !TARGET_OS_MAC || TARGET_OS_IPHONE
aymeric's avatar
aymeric committed
273
{
274
	MediastreamDatas* args;
275
	cond = 1;
276

277
	args = init_default_args();
278

279 280
	if (!parse_args(argc, argv, args)){
		printf("%s",usage);
281
		return 0;
282
	}
283

284
	setup_media_streams(args);
285

286
	mediastream_run_loop(args);
287

288
	clear_mediastreams(args);
289

290
	free(args);
291

292
	return 0;
293 294 295 296 297
}

#endif


298
MediastreamDatas* init_default_args(void) {
299
	MediastreamDatas* args = (MediastreamDatas*)ms_malloc0(sizeof(MediastreamDatas));
300 301 302 303
	args->localport=0;
	args->remoteport=0;
	args->payload=0;
	memset(args->ip, 0, sizeof(args->ip));
304 305
	args->send_fmtp=NULL;
	args->recv_fmtp=NULL;
306 307 308 309 310
	args->jitter=50;
	args->bitrate=0;
	args->ec=FALSE;
	args->agc=FALSE;
	args->eq=FALSE;
311
	args->interactive=FALSE;
312 313
	args->is_verbose=FALSE;
	args->device_rotation=-1;
314
	args->rc_algo = RCAlgoNone;
aymeric's avatar
aymeric committed
315

316
#ifdef VIDEO_ENABLED
317
	args->video=NULL;
318
#endif
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
	args->capture_card=NULL;
	args->playback_card=NULL;
	args->camera=NULL;
	args->infile=args->outfile=NULL;
	args->ng_threshold=-1;
	args->use_ng=FALSE;
	args->two_windows=FALSE;
	args->el=FALSE;
	args->el_speed=-1;
	args->el_thres=-1;
	args->el_force=-1;
	args->el_sustain=-1;
	args->el_transmit_thres=-1;
	args->ng_floorgain=-1;
	args->zrtp_secrets=NULL;
	args->custom_pt=NULL;
	args->video_window_id = -1;
	args->preview_window_id = -1;
337
	args->enable_avpf = TRUE;
338
	args->enable_rtcp = TRUE;
339 340
	/* starting values echo canceller */
	args->ec_len_ms=args->ec_delay_ms=args->ec_framesize=0;
341 342
	args->enable_srtp = FALSE;
	args->srtp_local_master_key = args->srtp_remote_master_key = NULL;
343
	args->zoom = 1.0;
344
	args->zoom_cx = args->zoom_cy = 0.5;
345 346 347 348 349 350

	args->audio = NULL;
	args->session = NULL;
	args->pt = NULL;
	args->q = NULL;
	args->profile = NULL;
351
	args->logfile = NULL;
352

Ghislain MARY's avatar
Ghislain MARY committed
353
	args->ice_session = NULL;
354 355 356
	memset(args->ice_local_candidates, 0, sizeof(args->ice_local_candidates));
	memset(args->ice_remote_candidates, 0, sizeof(args->ice_remote_candidates));
	args->ice_local_candidates_nb = args->ice_remote_candidates_nb = 0;
357
	args->video_display_filter=NULL;
358

359
	return args;
360 361
}

362
bool_t parse_args(int argc, char** argv, MediastreamDatas* out) {
aymeric's avatar
aymeric committed
363
	int i;
jehan's avatar
jehan committed
364

aymeric's avatar
aymeric committed
365
	if (argc<4) {
366
		ms_error("Expected at least 3 arguments.\n");
367
		return FALSE;
aymeric's avatar
aymeric committed
368
	}
369 370

	/* default size */
371 372
	out->vs.width=MS_VIDEO_SIZE_CIF_W;
	out->vs.height=MS_VIDEO_SIZE_CIF_H;
373

aymeric's avatar
aymeric committed
374
	for (i=1;i<argc;i++){
375 376 377 378
		if (strcmp(argv[i],"--help")==0 || strcmp(argv[i],"-h")==0) {
			return FALSE;
		}else if (strcmp(argv[i],"--local")==0){
			char *is_invalid;
aymeric's avatar
aymeric committed
379
			i++;
380 381 382 383 384
			out->localport = strtol(argv[i],&is_invalid,10);
			if (*is_invalid!='\0'){
				ms_error("Failed to parse local port '%s'\n",argv[i]);
				return 0;
			}
aymeric's avatar
aymeric committed
385 386
		}else if (strcmp(argv[i],"--remote")==0){
			i++;
387
			if (!parse_addr(argv[i],out->ip,sizeof(out->ip),&out->remoteport)) {
388
				ms_error("Failed to parse remote address '%s'\n",argv[i]);
389
				return FALSE;
aymeric's avatar
aymeric committed
390
			}
391
			ms_message("Remote addr: ip=%s port=%i\n",out->ip,out->remoteport);
392 393 394 395
		}else if (strcmp(argv[i],"--ice-local-candidate")==0) {
			MediastreamIceCandidate *candidate;
			i++;
			if (out->ice_local_candidates_nb>=MEDIASTREAM_MAX_ICE_CANDIDATES) {
396
				ms_warning("Ignore ICE local candidate \"%s\" (maximum %d candidates allowed)\n",argv[i],MEDIASTREAM_MAX_ICE_CANDIDATES);
397 398 399 400
				continue;
			}
			candidate=&out->ice_local_candidates[out->ice_local_candidates_nb];
			if (!parse_ice_addr(argv[i],candidate->type,sizeof(candidate->type),candidate->ip,sizeof(candidate->ip),&candidate->port)) {
401
				ms_error("Failed to parse ICE local candidates '%s'\n", argv[i]);
402 403 404
				return FALSE;
			}
			out->ice_local_candidates_nb++;
405
			ms_message("ICE local candidate: type=%s ip=%s port=%i\n",candidate->type,candidate->ip,candidate->port);
406 407 408 409
		}else if (strcmp(argv[i],"--ice-remote-candidate")==0) {
			MediastreamIceCandidate *candidate;
			i++;
			if (out->ice_remote_candidates_nb>=MEDIASTREAM_MAX_ICE_CANDIDATES) {
410
				ms_warning("Ignore ICE remote candidate \"%s\" (maximum %d candidates allowed)\n",argv[i],MEDIASTREAM_MAX_ICE_CANDIDATES);
411 412 413 414
				continue;
			}
			candidate=&out->ice_remote_candidates[out->ice_remote_candidates_nb];
			if (!parse_ice_addr(argv[i],candidate->type,sizeof(candidate->type),candidate->ip,sizeof(candidate->ip),&candidate->port)) {
415
				ms_error("Failed to parse ICE remote candidates '%s'\n", argv[i]);
416 417 418
				return FALSE;
			}
			out->ice_remote_candidates_nb++;
419
			ms_message("ICE remote candidate: type=%s ip=%s port=%i\n",candidate->type,candidate->ip,candidate->port);
aymeric's avatar
aymeric committed
420 421
		}else if (strcmp(argv[i],"--payload")==0){
			i++;
422
			if (isdigit(argv[i][0])){
423
				out->payload=atoi(argv[i]);
424
			}else {
425
				out->payload=114;
426
				out->custom_pt=ms_tools_parse_custom_payload(argv[i]);
427
			}
aymeric's avatar
aymeric committed
428 429
		}else if (strcmp(argv[i],"--fmtp")==0){
			i++;
430 431 432 433
			out->send_fmtp=argv[i];
		}else if (strcmp(argv[i],"--recv_fmtp")==0){
			i++;
			out->recv_fmtp=argv[i];
aymeric's avatar
aymeric committed
434 435
		}else if (strcmp(argv[i],"--jitter")==0){
			i++;
436
			out->jitter=atoi(argv[i]);
aymeric's avatar
aymeric committed
437 438
		}else if (strcmp(argv[i],"--bitrate")==0){
			i++;
439
			out->bitrate=atoi(argv[i]);
440 441
		}else if (strcmp(argv[i],"--width")==0){
			i++;
442
			out->vs.width=atoi(argv[i]);
443 444
		}else if (strcmp(argv[i],"--height")==0){
			i++;
445
			out->vs.height=atoi(argv[i]);
446 447
		}else if (strcmp(argv[i],"--capture-card")==0){
			i++;
448
			out->capture_card=argv[i];
Simon Morlat's avatar
Simon Morlat committed
449 450
		}else if (strcmp(argv[i],"--playback-card")==0){
			i++;
451
			out->playback_card=argv[i];
aymeric's avatar
aymeric committed
452
		}else if (strcmp(argv[i],"--ec")==0){
453
			out->ec=TRUE;
454 455
		}else if (strcmp(argv[i],"--ec-tail")==0){
			i++;
456
			out->ec_len_ms=atoi(argv[i]);
457 458
		}else if (strcmp(argv[i],"--ec-delay")==0){
			i++;
459
			out->ec_delay_ms=atoi(argv[i]);
460 461
		}else if (strcmp(argv[i],"--ec-framesize")==0){
			i++;
462
			out->ec_framesize=atoi(argv[i]);
463
		}else if (strcmp(argv[i],"--agc")==0){
464
			out->agc=TRUE;
smorlat's avatar
smorlat committed
465
		}else if (strcmp(argv[i],"--eq")==0){
466
			out->eq=TRUE;
467
		}else if (strcmp(argv[i],"--ng")==0){
468
			out->use_ng=1;
469
		}else if (strcmp(argv[i],"--rc")==0){
470 471 472 473 474 475
			i++;
			out->rc_algo = parse_rc_algo(argv[i]);
			if (out->rc_algo == RCAlgoInvalid){
				ms_error("Invalid argument for --rc");
				return FALSE;
			}
476 477
		}else if (strcmp(argv[i],"--ng-threshold")==0){
			i++;
478
			out->ng_threshold=(float)atof(argv[i]);
jehan's avatar
jehan committed
479 480
		}else if (strcmp(argv[i],"--ng-floorgain")==0){
			i++;
481
			out->ng_floorgain=(float)atof(argv[i]);
482
		}else if (strcmp(argv[i],"--two-windows")==0){
483
			out->two_windows=TRUE;
484 485
		}else if (strcmp(argv[i],"--infile")==0){
			i++;
486
			out->infile=argv[i];
487 488
		}else if (strcmp(argv[i],"--outfile")==0){
			i++;
489
			out->outfile=argv[i];
490 491
		}else if (strcmp(argv[i],"--camera")==0){
			i++;
492
			out->camera=argv[i];
jehan's avatar
jehan committed
493
		}else if (strcmp(argv[i],"--el")==0){
494
			out->el=TRUE;
jehan's avatar
jehan committed
495 496
		}else if (strcmp(argv[i],"--el-speed")==0){
			i++;
497
			out->el_speed=(float)atof(argv[i]);
jehan's avatar
jehan committed
498 499
		}else if (strcmp(argv[i],"--el-thres")==0){
			i++;
500
			out->el_thres=(float)atof(argv[i]);
jehan's avatar
jehan committed
501 502
		}else if (strcmp(argv[i],"--el-force")==0){
			i++;
503
			out->el_force=(float)atof(argv[i]);
jehan's avatar
jehan committed
504 505
		}else if (strcmp(argv[i],"--el-sustain")==0){
			i++;
506
			out->el_sustain=atoi(argv[i]);
jehan's avatar
jehan committed
507 508
		}else if (strcmp(argv[i],"--el-transmit-thres")==0){
			i++;
509
			out->el_transmit_thres=(float)atof(argv[i]);
510
		} else if (strcmp(argv[i],"--zrtp")==0){
511
			out->zrtp_secrets=argv[++i];
512
		} else if (strcmp(argv[i],"--verbose")==0){
513
			out->is_verbose=TRUE;
514 515
		} else if (strcmp(argv[i], "--video-windows-id")==0) {
			i++;
516
			if (!parse_window_ids(argv[i],&out->video_window_id, &out->preview_window_id)) {
517
				ms_error("Failed to parse window ids '%s'\n",argv[i]);
518
				return FALSE;
519
			}
520
		} else if (strcmp(argv[i], "--device-rotation")==0) {
521
			i++;
522
			out->device_rotation=atoi(argv[i]);
523
		} else if (strcmp(argv[i], "--srtp")==0) {
524
			if (!ms_srtp_supported()) {
jehan's avatar
jehan committed
525
				ms_error("srtp support not enabled");
526 527 528 529 530 531 532 533 534
				return FALSE;
			}
			out->enable_srtp = TRUE;
			i++;
			// check if we're being given keys
			if (i + 1 < argc) {
				out->srtp_local_master_key = argv[i++];
				out->srtp_remote_master_key = argv[i++];
			}
535 536
		} else if (strcmp(argv[i],"--netsim-bandwidth")==0){
			i++;
537
			if (i<argc){
538
				out->netsim.max_bandwidth=(float)atoi(argv[i]);
539 540 541 542 543 544 545 546
				out->netsim.enabled=TRUE;
			}else{
				ms_error("Missing argument for --netsim-bandwidth");
				return FALSE;
			}
		}else if (strcmp(argv[i],"--netsim-lossrate")==0){
			i++;
			if (i<argc){
547
				out->netsim.loss_rate=(float)atoi(argv[i]);
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
				if (out->netsim.loss_rate < 0 || out->netsim.loss_rate>100) {
					ms_error("Loss rate must be between 0 and 100.");
					return FALSE;
				}
				out->netsim.enabled=TRUE;
			}else{
				ms_error("Missing argument for --netsim-lossrate");
				return FALSE;
			}
		}else if (strcmp(argv[i],"--netsim-consecutive-loss-probability")==0){
			i++;
			if (i<argc){
				sscanf(argv[i],"%f",&out->netsim.consecutive_loss_probability);
				if (out->netsim.consecutive_loss_probability < 0 || out->netsim.consecutive_loss_probability>1) {
					ms_error("The consecutive loss probability must be between 0 and 1.");
					return FALSE;
				}
565

566 567 568 569 570 571
				out->netsim.enabled=TRUE;
			}else{
				ms_error("Missing argument for --netsim-consecutive-loss-probability");
				return FALSE;
			}
		}else if (strcmp(argv[i], "--netsim-latency") == 0) {
Yann Diorcet's avatar
Yann Diorcet committed
572
			i++;
573 574 575 576 577 578
			if (i<argc){
				out->netsim.latency = atoi(argv[i]);
				out->netsim.enabled=TRUE;
			}else{
				ms_error("Missing argument for --netsim-latency");
				return FALSE;
Yann Diorcet's avatar
Yann Diorcet committed
579
			}
580 581 582 583 584 585 586 587 588 589 590 591
		}else if (strcmp(argv[i], "--netsim-jitter-burst-density") == 0) {
			i++;
			if (i<argc){
				sscanf(argv[i],"%f",&out->netsim.jitter_burst_density);
				if (out->netsim.jitter_burst_density<0 || out->netsim.jitter_burst_density>10){
					ms_error("The jitter burst density must be between 0 and 10");
					return FALSE;
				}
				out->netsim.enabled=TRUE;
			}else{
				ms_error("Missing argument for --netsim-jitter-burst-density");
				return FALSE;
Yann Diorcet's avatar
Yann Diorcet committed
592
			}
593
		}else if (strcmp(argv[i], "--netsim-jitter-strength") == 0) {
594
			i++;
595 596 597 598 599 600 601 602 603 604 605
			if (i<argc){
				sscanf(argv[i],"%f",&out->netsim.jitter_strength);
				if (out->netsim.jitter_strength<0 || out->netsim.jitter_strength>100){
					ms_error("The jitter strength must be between 0 and 100.");
					return FALSE;
				}
				out->netsim.enabled=TRUE;
			}else{
				ms_error("Missing argument for --netsim-jitter-strength");
				return FALSE;
			}
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
		}else if (strcmp(argv[i], "--netsim-mode") == 0) {
			i++;
			if (i<argc){
				if (strcmp(argv[i],"inbound")==0)
					out->netsim.mode=OrtpNetworkSimulatorInbound;
				else if (strcmp(argv[i],"outbound")==0){
					out->netsim.mode=OrtpNetworkSimulatorOutbound;
				}else{
					ms_error("Invalid value for --netsim-mode");
					return FALSE;
				}
				out->netsim.enabled=TRUE;
			}else{
				ms_error("Missing argument for --netsim-dir");
				return FALSE;
			}
622
		}else if (strcmp(argv[i],"--zoom")==0){
623
			i++;
624 625 626 627
			if (sscanf(argv[i], "%f,%f,%f", &out->zoom, &out->zoom_cx, &out->zoom_cy) != 3) {
				ms_error("Invalid zoom triplet");
				return FALSE;
			}
628
		} else if (strcmp(argv[i],"--mtu")==0){
629 630 631 632 633
			i++;
			if (sscanf(argv[i], "%i", &out->mtu) != 1) {
				ms_error("Invalid mtu value");
				return FALSE;
			}
634
		} else if (strcmp(argv[i],"--interactive")==0){
635
			out->interactive=TRUE;
636 637
		} else if (strcmp(argv[i], "--no-avpf") == 0) {
			out->enable_avpf = FALSE;
638 639
		} else if (strcmp(argv[i], "--no-rtcp") == 0) {
			out->enable_rtcp = FALSE;
640
		} else if (strcmp(argv[i],"--help")==0) {
641
			return FALSE;
642 643 644
		} else if (strcmp(argv[i],"--video-display-filter")==0) {
			i++;
			out->video_display_filter=argv[i];
645 646 647
		} else if (strcmp(argv[i], "--log") == 0) {
			i++;
			out->logfile = fopen(argv[i], "a+");
648 649
		} else if (strcmp(argv[i], "--freeze-on-error") == 0) {
			out->freeze_on_error=TRUE;
650 651
		} else if (strcmp(argv[i], "--speaker") == 0) {
			out->enable_speaker=TRUE;
652
		} else {
653
			ms_error("Unknown option '%s'\n", argv[i]);
654
			return FALSE;
aymeric's avatar
aymeric committed
655
		}
656
	}
657 658 659 660
	if (out->netsim.jitter_burst_density>0 && out->netsim.max_bandwidth==0){
		ms_error("Jitter probability settings requires --netsim-bandwidth to be set.");
		return FALSE;
	}
661 662
	return TRUE;
}
663

jehan's avatar
jehan committed
664

665 666 667 668 669
#ifdef VIDEO_ENABLED
static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args) {
	MediastreamDatas *md = (MediastreamDatas *)user_pointer;
	switch (event_id) {
		case MS_VIDEO_DECODER_DECODING_ERRORS:
Ghislain MARY's avatar
Ghislain MARY committed
670
			ms_warning("Decoding error on videostream [%p]", md->video);
671 672
			break;
		case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
Ghislain MARY's avatar
Ghislain MARY committed
673
			ms_message("First video frame decoded successfully on videostream [%p]", md->video);
674 675 676 677 678
			break;
	}
}
#endif

679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
static MSSndCard *get_sound_card(MSSndCardManager *manager, const char* card_name) {
	MSSndCard *play = ms_snd_card_manager_get_card(manager,card_name);
	if (play == NULL) {
		const MSList *list = ms_snd_card_manager_get_list(manager);
		char * cards = ms_strdup("");
		while (list) {
			MSSndCard *card = (MSSndCard*)list->data;
			cards = ms_strcat_printf(cards, "- %s\n", ms_snd_card_get_string_id(card));
			list = list->next;
		}
		ms_fatal("Specified card '%s' but could not find it. Available cards are:\n%s", card_name, cards);
		ms_free(cards);
	}
	return play;
}
694

695
void setup_media_streams(MediastreamDatas* args) {
696
	/*create the rtp session */
697
#ifdef VIDEO_ENABLED
Sylvain Berfini's avatar
Sylvain Berfini committed
698
	MSWebCam *cam=NULL;
699
#endif
700
	MSFactory *factory;
701
	ortp_init();
702 703
	if (args->logfile)
		ortp_set_log_file(args->logfile);
704

705
	if (args->is_verbose) {
706
		ortp_set_log_level_mask(ORTP_LOG_DOMAIN, ORTP_DEBUG|ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
707
	} else {
708
		ortp_set_log_level_mask(ORTP_LOG_DOMAIN, ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
aymeric's avatar
aymeric committed
709
	}
710

711
	args->factory = factory = ms_factory_new_with_voip();
jehan's avatar
jehan committed
712

713
#if TARGET_OS_IPHONE || defined(ANDROID)
714
#if TARGET_OS_IPHONE || (defined(HAVE_X264) && defined(VIDEO_ENABLED))
715
	libmsx264_init(); /*no plugin on IOS/Android */
jehan's avatar
jehan committed
716
#endif
717
#if TARGET_OS_IPHONE || (defined (HAVE_OPENH264) && defined (VIDEO_ENABLED))
718 719
	libmsopenh264_init(); /*no plugin on IOS/Android */
#endif
720
#if TARGET_OS_IPHONE || defined (HAVE_SILK)
721
	libmssilk_init(); /*no plugin on IOS/Android */
jehan's avatar
jehan committed
722
#endif
723
#if TARGET_OS_IPHONE || defined (HAVE_WEBRTC)
724
	libmswebrtc_init();
725
#endif
726 727

#endif /* IPHONE | ANDROID */
728

729 730 731 732
	rtp_profile_set_payload(&av_profile,110,&payload_type_speex_nb);
	rtp_profile_set_payload(&av_profile,111,&payload_type_speex_wb);
	rtp_profile_set_payload(&av_profile,112,&payload_type_ilbc);
	rtp_profile_set_payload(&av_profile,113,&payload_type_amr);
733
	rtp_profile_set_payload(&av_profile,114,args->custom_pt);
734
	rtp_profile_set_payload(&av_profile,115,&payload_type_lpc1015);
735
#ifdef VIDEO_ENABLED
736
	cam=ms_web_cam_new(ms_mire_webcam_desc_get());
737
	if (cam) ms_web_cam_manager_add_cam(ms_factory_get_web_cam_manager(factory), cam);
Simon Morlat's avatar
Simon Morlat committed
738
	cam=NULL;
739

740 741 742 743 744 745
	rtp_profile_set_payload(&av_profile,26,&payload_type_jpeg);
	rtp_profile_set_payload(&av_profile,98,&payload_type_h263_1998);
	rtp_profile_set_payload(&av_profile,97,&payload_type_theora);
	rtp_profile_set_payload(&av_profile,99,&payload_type_mp4v);
	rtp_profile_set_payload(&av_profile,100,&payload_type_x_snow);
	rtp_profile_set_payload(&av_profile,102,&payload_type_h264);
746
	rtp_profile_set_payload(&av_profile,103,&payload_type_vp8);
747

748
	args->video=NULL;
aymeric's avatar
aymeric committed
749
#endif
750 751
	args->profile=rtp_profile_clone_full(&av_profile);
	args->q=ortp_ev_queue_new();
752 753 754 755
	
	if (args->rc_algo == RCAlgoAdvanced){
		args->bw_controller = ms_bandwidth_controller_new();
	}
756

757 758 759
	if (args->mtu) ms_factory_set_mtu(factory, args->mtu);
	ms_factory_enable_statistics(factory, TRUE);
	ms_factory_reset_statistics(factory);
760

Ghislain MARY's avatar
Ghislain MARY committed
761
	args->ice_session=ice_session_new();
Ghislain MARY's avatar
Ghislain MARY committed
762 763 764 765
	ice_session_set_remote_credentials(args->ice_session,"1234","1234567890abcdef123456");
	// ICE local credentials are assigned when creating the ICE session, but force them here to simplify testing
	ice_session_set_local_credentials(args->ice_session,"1234","1234567890abcdef123456");
	ice_dump_session(args->ice_session);
766

aymeric's avatar
aymeric committed
767
	signal(SIGINT,stop_handler);
768 769
	args->pt=rtp_profile_get_payload(args->profile,args->payload);
	if (args->pt==NULL){
770
		ms_error("No payload defined with number %i.\n",args->payload);
aymeric's avatar
aymeric committed
771 772
		exit(-1);
	}
773
	if (args->enable_avpf == TRUE) {
774
		PayloadTypeAvpfParams avpf_params;
775
		payload_type_set_flag(args->pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
776
		avpf_params.features = PAYLOAD_TYPE_AVPF_FIR | PAYLOAD_TYPE_AVPF_PLI | PAYLOAD_TYPE_AVPF_SLI | PAYLOAD_TYPE_AVPF_RPSI;
777
		avpf_params.trr_interval = 3000;
778
		payload_type_set_avpf_params(args->pt, avpf_params);
779 780 781
	} else {
		payload_type_unset_flag(args->pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
	}
782 783
	if (args->send_fmtp!=NULL) payload_type_set_send_fmtp(args->pt,args->send_fmtp);
	if (args->recv_fmtp!=NULL) payload_type_set_recv_fmtp(args->pt,args->recv_fmtp);
784
	if (args->bitrate>0) args->pt->normal_bitrate=args->bitrate;
785

786
	if (args->pt->normal_bitrate==0){
787
		ms_error("Default bitrate specified for codec %s/%i. "
788 789 790
			"Please specify a network bitrate with --bitrate option.\n",args->pt->mime_type,args->pt->clock_rate);
		exit(-1);
	}
aymeric's avatar
aymeric committed
791

792 793 794 795 796
	// do we need to generate srtp keys ?
	if (args->enable_srtp) {
		// default profile require key-length = 30 bytes
		//  -> input : 40 b64 encoded bytes
		if (!args->srtp_local_master_key) {
jehan's avatar
jehan committed
797 798
			char tmp[30];
			snprintf(tmp,sizeof(tmp),"%08x%08x%08x%08x",rand(),rand(),rand(),rand());
799 800 801 802 803 804
			args->srtp_local_master_key = (char*) malloc(41);
			b64_encode((const char*)tmp, 30, args->srtp_local_master_key, 40);
			args->srtp_local_master_key[40] = '\0';
			ms_message("Generated local srtp key: '%s'", args->srtp_local_master_key);
		}
		if (!args->srtp_remote_master_key) {
jehan's avatar
jehan committed
805 806
			char tmp[30];
			snprintf(tmp,sizeof(tmp),"%08x%08x%08x%08x",rand(),rand(),rand(),rand());
807 808 809 810 811
			args->srtp_remote_master_key = (char*) malloc(41);
			b64_encode((const char*)tmp, 30, args->srtp_remote_master_key, 40);
			args->srtp_remote_master_key[40] = '\0';
			ms_message("Generated remote srtp key: '%s'", args->srtp_remote_master_key);
		}
812
	}
813

814
	if (args->pt->type!=PAYLOAD_VIDEO){
815
		MSSndCardManager *manager=ms_factory_get_snd_card_manager(factory);
816
		MSSndCard *capt= args->capture_card==NULL ? ms_snd_card_manager_get_default_capture_card(manager) :
817 818 819
				get_sound_card(manager,args->capture_card);
		MSSndCard *play= args->playback_card==NULL ? ms_snd_card_manager_get_default_capture_card(manager) :
				get_sound_card(manager,args->playback_card);
820
		args->audio=audio_stream_new(factory, args->localport,args->localport+1,ms_is_ipv6(args->ip));
821 822 823
		if (args->bw_controller){
			ms_bandwidth_controller_add_stream(args->bw_controller, (MediaStream*)args->audio);
		}
824 825 826 827
		audio_stream_enable_automatic_gain_control(args->audio,args->agc);
		audio_stream_enable_noise_gate(args->audio,args->use_ng);
		audio_stream_set_echo_canceller_params(args->audio,args->ec_len_ms,args->ec_delay_ms,args->ec_framesize);
		audio_stream_enable_echo_limiter(args->audio,args->el);
828
		audio_stream_enable_adaptive_bitrate_control(args->audio,args->rc_algo == RCAlgoSimple);
829 830 831 832
		if (capt)
			ms_snd_card_set_preferred_sample_rate(capt,rtp_profile_get_payload(args->profile, args->payload)->clock_rate);
		if (play)
			ms_snd_card_set_preferred_sample_rate(play,rtp_profile_get_payload(args->profile, args->payload)->clock_rate);
833
		ms_message("Starting audio stream.\n");
834

835
		audio_stream_start_full(args->audio,args->profile,args->ip,args->remoteport,args->ip,args->enable_rtcp?args->remoteport+1:-1, args->payload, args->jitter,args->infile,args->outfile,
836
								args->outfile==NULL ? play : NULL ,args->infile==NULL ? capt : NULL,args->infile!=NULL ? FALSE: args->ec);
837

838
		if (args->ice_local_candidates_nb || args->ice_remote_candidates_nb) {
839
			args->audio->ms.ice_check_list = ice_check_list_new();
840
			rtp_session_set_pktinfo(args->audio->ms.sessions.rtp_session,TRUE);
841
			ice_session_add_check_list(args->ice_session, args->audio->ms.ice_check_list, 0);
842
		}
843 844 845 846 847
		if (args->ice_local_candidates_nb) {
			MediastreamIceCandidate *candidate;
			int c;
			for (c=0;c<args->ice_local_candidates_nb;c++){
				candidate=&args->ice_local_candidates[c];
848 849
				ice_add_local_candidate(args->audio->ms.ice_check_list,candidate->type,AF_INET,candidate->ip,candidate->port,1,NULL);
				ice_add_local_candidate(args->audio->ms.ice_check_list,candidate->type,AF_INET,candidate->ip,candidate->port+1,2,NULL);
850 851 852
			}
		}
		if (args->ice_remote_candidates_nb) {
853
			char foundation[4];
854 855 856 857
			MediastreamIceCandidate *candidate;
			int c;
			for (c=0;c<args->ice_remote_candidates_nb;c++){
				candidate=&args->ice_remote_candidates[c];
858 859
				memset(foundation, '\0', sizeof(foundation));
				snprintf(foundation, sizeof(foundation) - 1, "%u", c + 1);
860 861
				ice_add_remote_candidate(args->audio->ms.ice_check_list,candidate->type,AF_INET,candidate->ip,candidate->port,1,0,foundation,FALSE);
				ice_add_remote_candidate(args->audio->ms.ice_check_list,candidate->type,AF_INET,candidate->ip,candidate->port+1,2,0,foundation,FALSE);
862 863 864
			}
		}

865 866 867 868 869 870 871 872 873 874 875 876
		if (args->audio) {
			if (args->el) {
				if (args->el_speed!=-1)
					ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_EA_SPEED,&args->el_speed);
				if (args->el_force!=-1)
					ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_EA_FORCE,&args->el_force);
				if (args->el_thres!=-1)
					ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_EA_THRESHOLD,&args->el_thres);
				if (args->el_sustain!=-1)
					ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_EA_SUSTAIN,&args->el_sustain);
				if (args->el_transmit_thres!=-1)
					ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&args->el_transmit_thres);
jehan's avatar
jehan committed
877 878

			}
879 880 881 882
			if (args->use_ng){
				if (args->ng_threshold!=-1) {
					ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&args->ng_threshold);
					ms_filter_call_method(args->audio->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&args->ng_threshold);
jehan's avatar
jehan committed
883
				}
884 885 886
				if (args->ng_floorgain != -1) {
					ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&args->ng_floorgain);
					ms_filter_call_method(args->audio->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&args->ng_floorgain);
jehan's avatar
jehan committed
887 888
				}
			}
889

Guillaume Beraudo's avatar
Guillaume Beraudo committed
890
			if (args->zrtp_secrets != NULL) {
891
				MSZrtpParams params;
892 893
				params.zid_file=args->zrtp_secrets;
				audio_stream_enable_zrtp(args->audio,&params);
894
			}
895

896

897
			args->session=args->audio->ms.sessions.rtp_session;
898
		}
899

900
		if (args->enable_srtp) {
901
			ms_message("SRTP enabled: %d",
902
				audio_stream_enable_srtp(
903
					args->audio,
jehan's avatar
jehan committed
904
					MS_AES_128_SHA1_80,
905
					args->srtp_local_master_key,
906 907
					args->srtp_remote_master_key));
		}
908 909 910 911 912 913 914 915 916 917 918
	#if TARGET_OS_IPHONE
		if (args->enable_speaker) {
				ms_message("Setting audio route to spaker");
				UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
				if (AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride),&audioRouteOverride) != kAudioSessionNoError) {
					ms_error("Cannot set route to speaker");
				};
		}
	#endif


aymeric's avatar
aymeric committed
919 920
	}else{
#ifdef VIDEO_ENABLED
921 922 923
		float zoom[] = {
			args->zoom,
			args->zoom_cx, args->zoom_cy };
924
		MSMediaStreamIO iodef = MS_MEDIA_STREAM_IO_INITIALIZER;
925

926
		if (args->eq){
smorlat's avatar
smorlat committed
927 928 929
			ms_fatal("Cannot put an audio equalizer in a video stream !");
			exit(-1);
		}
930
		ms_message("Starting video stream.\n");
931
		args->video=video_stream_new(factory, args->localport, args->localport+1, ms_is_ipv6(args->ip));
932 933 934
		if (args->bw_controller){
			ms_bandwidth_controller_add_stream(args->bw_controller, (MediaStream*)args->video);
		}
935 936
		if (args->video_display_filter)
			video_stream_set_display_filter_name(args->video, args->video_display_filter);
937

938
#ifdef ANDROID
939 940
		if (args->device_rotation >= 0)
			video_stream_set_device_rotation(args->video, args->device_rotation);
941
#endif
942 943
		video_stream_set_sent_video_size(args->video,args->vs);
		video_stream_use_preview_video_window(args->video,args->two_windows);
944
#if TARGET_OS_IPHONE
jehan's avatar
jehan committed
945 946 947
		NSBundle* myBundle = [NSBundle mainBundle];
		const char*  nowebcam = [[myBundle pathForResource:@"nowebcamCIF"ofType:@"jpg"] cStringUsingEncoding:[NSString defaultCStringEncoding]];
		ms_static_image_set_default_image(nowebcam);
948
		NSUInteger cpucount = [[NSProcessInfo processInfo] processorCount];
949 950
		ms_factory_set_cpu_count(args->audio->ms.factory, cpucount);
		//ms_set_cpu_count(cpucount);
jehan's avatar
jehan committed
951
#endif
952
		video_stream_set_event_callback(args->video,video_stream_event_cb, args);
953
		video_stream_set_freeze_on_error(args->video,args->freeze_on_error);
954
		video_stream_enable_adaptive_bitrate_control(args->video, args->rc_algo == RCAlgoSimple);
955
		if (args->camera)
956
			cam=ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(factory),args->camera);
957
		if (cam==NULL)
958
			cam=ms_web_cam_manager_get_default_cam(ms_factory_get_web_cam_manager(factory));
959

960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975
		if (args->infile){
			iodef.input.type = MSResourceFile;
			iodef.input.file = args->infile;
		}else{
			iodef.input.type = MSResourceCamera;
			iodef.input.camera = cam;
		}
		if (args->outfile){
			iodef.output.type = MSResourceFile;
			iodef.output.file = args->outfile;
		}else{
			iodef.output.type = MSResourceDefault;
			iodef.output.resource_arg = NULL;
		}
		rtp_session_set_jitter_compensation(args->video->ms.sessions.rtp_session, args->jitter);
		video_stream_start_from_io(args->video, args->profile,
976
					args->ip,args->remoteport,
977
					args->ip,args->enable_rtcp?args->remoteport+1:-1,
978
					args->payload,
979
					&iodef
980
					);
981
		args->session=args->video->ms.sessions.rtp_session;
982

983
		ms_filter_call_method(args->video->output,MS_VIDEO_DISPLAY_ZOOM, zoom);
984
		if (args->enable_srtp) {
985
			ms_message("SRTP enabled: %d",
986
				video_stream_enable_strp(
987
					args->video,
jehan's avatar
jehan committed
988
					MS_AES_128_SHA1_80,
989
					args->srtp_local_master_key,
990 991
					args->srtp_remote_master_key));
		}
aymeric's avatar
aymeric committed
992
#else
993
		ms_error("Error: video support not compiled.\n");
aymeric's avatar
aymeric committed
994 995
#endif
	}
996 997 998
	ice_session_set_base_for_srflx_candidates(args->ice_session);
	ice_session_compute_candidates_foundations(args->ice_session);
	ice_session_choose_default_candidates(args->ice_session);
Ghislain MARY's avatar
Ghislain MARY committed
999
	ice_session_choose_default_remote_candidates(args->ice_session);
Ghislain MARY's avatar
Ghislain MARY committed
1000
	ice_session_start_connectivity_checks(args->ice_session);
1001

1002 1003
	if (args->netsim.enabled){
		rtp_session_enable_network_simulation(args->session,&args->netsim);
1004
	}
1005 1006 1007
}


1008
static void mediastream_tool_iterate(MediastreamDatas* args) {
1009
#ifndef _WIN32
1010 1011
	struct pollfd pfd;
	int err;
1012

1013 1014
	if (args->interactive){
		pfd.fd=STDIN_FILENO;
1015
		pfd.events=POLLIN;
1016
		pfd.revents=0;
1017

1018
		err=poll(&pfd,1,10);
1019
		if (err==1 && (pfd.revents & POLLIN)){
1020 1021 1022 1023 1024
			char commands[128];
			int intarg;
			commands[127]='\0';
			ms_sleep(1);  /* ensure following text be printed after ortp messages */
			if (args->eq)
1025
			ms_message("\nPlease enter equalizer requests, such as 'eq active 1', 'eq active 0', 'eq 1200 0.1 200'\n");
1026 1027

			if (fgets(commands,sizeof(commands)-1,stdin)!=NULL){
1028 1029
				MSEqualizerGain d = {0};
				int active;
1030
				if (sscanf(commands,"eq active %i",&active)==1){
1031
					audio_stream_enable_equalizer(args->audio, args->audio->eq_loc, active);
1032
					ms_message("OK\n");
1033 1034
				}else if (sscanf(commands,"eq %f %f %f",&d.frequency,&d.gain,&d.width)==3){
					audio_stream_equalizer_set_gain(args->audio, args->audio->eq_loc, &d);
1035
					ms_message("OK\n");