mediastream.c 42.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 17 18 19 20
/*
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.
*/


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 32 33
#include <signal.h>
#include <sys/types.h>
#ifndef WIN32
#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 43 44
#ifdef __APPLE__
#include <CoreFoundation/CFRunLoop.h>
#endif
45 46
#if  TARGET_OS_IPHONE || defined (ANDROID)
#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
jehan's avatar
jehan committed
50
extern void ms_set_video_stream(VideoStream* video);
jehan's avatar
jehan committed
51 52 53
#ifdef HAVE_X264
extern void libmsx264_init();
#endif
54 55 56
#ifdef HAVE_OPENH264
extern void libmsopenh264_init();
#endif
jehan's avatar
jehan committed
57 58
#ifdef HAVE_SILK
extern void libmssilk_init();
59
#endif
60 61
#ifdef HAVE_WEBRTC
extern void libmswebrtc_init();
62
#endif
jehan's avatar
jehan committed
63
#endif
64

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

70 71
#include <ortp/b64.h>

72 73 74 75 76 77

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


78 79
#define MEDIASTREAM_MAX_ICE_CANDIDATES 3

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


83 84 85 86 87 88
typedef struct _MediastreamIceCandidate {
	char ip[64];
	char type[6];
	int port;
} MediastreamIceCandidate;

89 90
typedef struct _MediastreamDatas {
	int localport,remoteport,payload;
91
	char ip[64];
92 93 94
	char *fmtp;
	int jitter;
	int bitrate;
95
	int mtu;
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
	MSVideoSize vs;
	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;
111
	bool_t use_rc;
112

113
	bool_t enable_srtp;
114
	bool_t interactive;
115
	bool_t enable_avpf;
116
	bool_t enable_rtcp;
117

118 119
	bool_t freeze_on_error;
	bool_t pad[3];
120 121 122 123 124 125 126 127 128 129 130 131
	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;
132 133
	char* srtp_local_master_key;
	char* srtp_remote_master_key;
134
	OrtpNetworkSimulatorParams netsim;
135
	float zoom;
136
	float zoom_cx, zoom_cy;
137 138

	AudioStream *audio;
139 140 141 142
	PayloadType *pt;
	RtpSession *session;
	OrtpEvQueue *q;
	RtpProfile *profile;
143

Ghislain MARY's avatar
Ghislain MARY committed
144
	IceSession *ice_session;
145 146 147 148
	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;
149
	char * video_display_filter;
150
	FILE * logfile;
151
	bool_t enable_speaker;
152 153
} MediastreamDatas;

154

155 156
// MAIN METHODS
/* init default arguments */
157
MediastreamDatas* init_default_args(void);
158 159 160 161
/* parse args */
bool_t parse_args(int argc, char** argv, MediastreamDatas* out);
/* setup streams */
void setup_media_streams(MediastreamDatas* args);
162 163
/* run loop*/
void mediastream_run_loop(MediastreamDatas* args);
164 165 166 167
/* exit */
void clear_mediastreams(MediastreamDatas* args);

// HELPER METHODS
168
void stop_handler(int signum);
169
static bool_t parse_addr(const char *addr, char *ip, int len, int *port);
170
static bool_t parse_ice_addr(char* addr, char* type, int type_len, char* ip, int ip_len, int* port);
171 172 173 174
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);
175

176 177 178 179 180
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"
181
								"[ --bitrate <bits per seconds> ]\n"
182 183
								"[ --camera <camera id as listed at startup> ]\n"
								"[ --capture-card <name> ]\n"
184
								"[ --ec (enable echo canceller) ]\n"
185
								"[ --ec-delay <echo canceller delay in ms> ]\n"
186
								"[ --ec-framesize <echo canceller framesize in samples> ]\n"
187
								"[ --ec-tail <echo canceller tail length in ms> ]\n"
jehan's avatar
jehan committed
188 189
								"[ --el (enable echo limiter) ]\n"
								"[ --el-force <(float) [0-1]> (The proportional coefficient controlling the mic attenuation) ]\n"
190
								"[ --el-speed <(float) [0-1]> (gain changes are smoothed with a coefficent) ]\n"
jehan's avatar
jehan committed
191
								"[ --el-sustain <(int)> (Time in milliseconds for which the attenuation is kept unchanged after) ]\n"
192
								"[ --el-thres <(float) [0-1]> (Threshold above which the system becomes active) ]\n"
193
								"[ --el-transmit-thres <(float) [0-1]> (TO BE DOCUMENTED) ]\n"
194 195 196
								"[ --fmtp <fmtpline> ]\n"
								"[ --freeze-on-error (for video, stop upon decoding error until next valid frame) ]\n"
								"[ --height <pixels> ]\n"
197 198
								"[ --ice-local-candidate <ip:port:[host|srflx|prflx|relay]> ]\n"
								"[ --ice-remote-candidate <ip:port:[host|srflx|prflx|relay]> ]\n"
199 200 201 202
								"[ --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"
203
								"[ --mtu <mtu> (specify MTU)]\n"
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
								"[ --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"
								"[ --rc (enable adaptive rate control) ]\n"
								"[ --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"
226 227 228
								#if TARGET_OS_IPHONE
								"[ --speaker route audio to speaker ]\n"
								#endif
229
								;
aymeric's avatar
aymeric committed
230

jehan's avatar
jehan committed
231 232 233 234
#if TARGET_OS_IPHONE
int g_argc;
char** g_argv;
static int _main(int argc, char * argv[]);
235

jehan's avatar
jehan committed
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
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
255

jehan's avatar
jehan committed
256
#if !__APPLE__ && !ANDROID
aymeric's avatar
aymeric committed
257
int main(int argc, char * argv[])
jehan's avatar
jehan committed
258 259
#endif

260
#if !ANDROID && !TARGET_OS_MAC || TARGET_OS_IPHONE
aymeric's avatar
aymeric committed
261
{
262
	MediastreamDatas* args;
263
	cond = 1;
264

265
	args = init_default_args();
266

267 268
	if (!parse_args(argc, argv, args)){
		printf("%s",usage);
269
		return 0;
270
	}
271

272
	setup_media_streams(args);
273

274
	mediastream_run_loop(args);
275

276
	clear_mediastreams(args);
277

278
	free(args);
279

280
	return 0;
281 282 283 284 285
}

#endif


286
MediastreamDatas* init_default_args(void) {
287
	MediastreamDatas* args = (MediastreamDatas*)ms_malloc0(sizeof(MediastreamDatas));
288 289 290 291 292 293 294 295 296 297
	args->localport=0;
	args->remoteport=0;
	args->payload=0;
	memset(args->ip, 0, sizeof(args->ip));
	args->fmtp=NULL;
	args->jitter=50;
	args->bitrate=0;
	args->ec=FALSE;
	args->agc=FALSE;
	args->eq=FALSE;
298
	args->interactive=FALSE;
299 300
	args->is_verbose=FALSE;
	args->device_rotation=-1;
aymeric's avatar
aymeric committed
301

302
#ifdef VIDEO_ENABLED
303
	args->video=NULL;
304
#endif
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
	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->use_rc=FALSE;
	args->zrtp_secrets=NULL;
	args->custom_pt=NULL;
	args->video_window_id = -1;
	args->preview_window_id = -1;
324
	args->enable_avpf = TRUE;
325
	args->enable_rtcp = TRUE;
326 327
	/* starting values echo canceller */
	args->ec_len_ms=args->ec_delay_ms=args->ec_framesize=0;
328 329
	args->enable_srtp = FALSE;
	args->srtp_local_master_key = args->srtp_remote_master_key = NULL;
330
	args->zoom = 1.0;
331
	args->zoom_cx = args->zoom_cy = 0.5;
332 333 334 335 336 337

	args->audio = NULL;
	args->session = NULL;
	args->pt = NULL;
	args->q = NULL;
	args->profile = NULL;
338
	args->logfile = NULL;
339

Ghislain MARY's avatar
Ghislain MARY committed
340
	args->ice_session = NULL;
341 342 343
	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;
344
	args->video_display_filter=NULL;
345

346
	return args;
347 348
}

349
bool_t parse_args(int argc, char** argv, MediastreamDatas* out) {
aymeric's avatar
aymeric committed
350
	int i;
jehan's avatar
jehan committed
351

aymeric's avatar
aymeric committed
352
	if (argc<4) {
353
		ms_error("Expected at least 3 arguments.\n");
354
		return FALSE;
aymeric's avatar
aymeric committed
355
	}
356 357

	/* default size */
358 359
	out->vs.width=MS_VIDEO_SIZE_CIF_W;
	out->vs.height=MS_VIDEO_SIZE_CIF_H;
360

aymeric's avatar
aymeric committed
361
	for (i=1;i<argc;i++){
362 363 364 365
		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
366
			i++;
367 368 369 370 371
			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
372 373
		}else if (strcmp(argv[i],"--remote")==0){
			i++;
374
			if (!parse_addr(argv[i],out->ip,sizeof(out->ip),&out->remoteport)) {
375
				ms_error("Failed to parse remote address '%s'\n",argv[i]);
376
				return FALSE;
aymeric's avatar
aymeric committed
377
			}
378
			ms_message("Remote addr: ip=%s port=%i\n",out->ip,out->remoteport);
379 380 381 382
		}else if (strcmp(argv[i],"--ice-local-candidate")==0) {
			MediastreamIceCandidate *candidate;
			i++;
			if (out->ice_local_candidates_nb>=MEDIASTREAM_MAX_ICE_CANDIDATES) {
383
				ms_warning("Ignore ICE local candidate \"%s\" (maximum %d candidates allowed)\n",argv[i],MEDIASTREAM_MAX_ICE_CANDIDATES);
384 385 386 387
				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)) {
388
				ms_error("Failed to parse ICE local candidates '%s'\n", argv[i]);
389 390 391
				return FALSE;
			}
			out->ice_local_candidates_nb++;
392
			ms_message("ICE local candidate: type=%s ip=%s port=%i\n",candidate->type,candidate->ip,candidate->port);
393 394 395 396
		}else if (strcmp(argv[i],"--ice-remote-candidate")==0) {
			MediastreamIceCandidate *candidate;
			i++;
			if (out->ice_remote_candidates_nb>=MEDIASTREAM_MAX_ICE_CANDIDATES) {
397
				ms_warning("Ignore ICE remote candidate \"%s\" (maximum %d candidates allowed)\n",argv[i],MEDIASTREAM_MAX_ICE_CANDIDATES);
398 399 400 401
				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)) {
402
				ms_error("Failed to parse ICE remote candidates '%s'\n", argv[i]);
403 404 405
				return FALSE;
			}
			out->ice_remote_candidates_nb++;
406
			ms_message("ICE remote candidate: type=%s ip=%s port=%i\n",candidate->type,candidate->ip,candidate->port);
aymeric's avatar
aymeric committed
407 408
		}else if (strcmp(argv[i],"--payload")==0){
			i++;
409
			if (isdigit(argv[i][0])){
410
				out->payload=atoi(argv[i]);
411
			}else {
412
				out->payload=114;
413
				out->custom_pt=ms_tools_parse_custom_payload(argv[i]);
414
			}
aymeric's avatar
aymeric committed
415 416
		}else if (strcmp(argv[i],"--fmtp")==0){
			i++;
417
			out->fmtp=argv[i];
aymeric's avatar
aymeric committed
418 419
		}else if (strcmp(argv[i],"--jitter")==0){
			i++;
420
			out->jitter=atoi(argv[i]);
aymeric's avatar
aymeric committed
421 422
		}else if (strcmp(argv[i],"--bitrate")==0){
			i++;
423
			out->bitrate=atoi(argv[i]);
424 425
		}else if (strcmp(argv[i],"--width")==0){
			i++;
426
			out->vs.width=atoi(argv[i]);
427 428
		}else if (strcmp(argv[i],"--height")==0){
			i++;
429
			out->vs.height=atoi(argv[i]);
430 431
		}else if (strcmp(argv[i],"--capture-card")==0){
			i++;
432
			out->capture_card=argv[i];
Simon Morlat's avatar
Simon Morlat committed
433 434
		}else if (strcmp(argv[i],"--playback-card")==0){
			i++;
435
			out->playback_card=argv[i];
aymeric's avatar
aymeric committed
436
		}else if (strcmp(argv[i],"--ec")==0){
437
			out->ec=TRUE;
438 439
		}else if (strcmp(argv[i],"--ec-tail")==0){
			i++;
440
			out->ec_len_ms=atoi(argv[i]);
441 442
		}else if (strcmp(argv[i],"--ec-delay")==0){
			i++;
443
			out->ec_delay_ms=atoi(argv[i]);
444 445
		}else if (strcmp(argv[i],"--ec-framesize")==0){
			i++;
446
			out->ec_framesize=atoi(argv[i]);
447
		}else if (strcmp(argv[i],"--agc")==0){
448
			out->agc=TRUE;
smorlat's avatar
smorlat committed
449
		}else if (strcmp(argv[i],"--eq")==0){
450
			out->eq=TRUE;
451
		}else if (strcmp(argv[i],"--ng")==0){
452
			out->use_ng=1;
453
		}else if (strcmp(argv[i],"--rc")==0){
454
			out->use_rc=1;
455 456
		}else if (strcmp(argv[i],"--ng-threshold")==0){
			i++;
457
			out->ng_threshold=atof(argv[i]);
jehan's avatar
jehan committed
458 459
		}else if (strcmp(argv[i],"--ng-floorgain")==0){
			i++;
460
			out->ng_floorgain=atof(argv[i]);
461
		}else if (strcmp(argv[i],"--two-windows")==0){
462
			out->two_windows=TRUE;
463 464
		}else if (strcmp(argv[i],"--infile")==0){
			i++;
465
			out->infile=argv[i];
466 467
		}else if (strcmp(argv[i],"--outfile")==0){
			i++;
468
			out->outfile=argv[i];
469 470
		}else if (strcmp(argv[i],"--camera")==0){
			i++;
471
			out->camera=argv[i];
jehan's avatar
jehan committed
472
		}else if (strcmp(argv[i],"--el")==0){
473
			out->el=TRUE;
jehan's avatar
jehan committed
474 475
		}else if (strcmp(argv[i],"--el-speed")==0){
			i++;
476
			out->el_speed=atof(argv[i]);
jehan's avatar
jehan committed
477 478
		}else if (strcmp(argv[i],"--el-thres")==0){
			i++;
479
			out->el_thres=atof(argv[i]);
jehan's avatar
jehan committed
480 481
		}else if (strcmp(argv[i],"--el-force")==0){
			i++;
482
			out->el_force=atof(argv[i]);
jehan's avatar
jehan committed
483 484
		}else if (strcmp(argv[i],"--el-sustain")==0){
			i++;
485
			out->el_sustain=atoi(argv[i]);
jehan's avatar
jehan committed
486 487
		}else if (strcmp(argv[i],"--el-transmit-thres")==0){
			i++;
488
			out->el_transmit_thres=atof(argv[i]);
489
		} else if (strcmp(argv[i],"--zrtp")==0){
490
			out->zrtp_secrets=argv[++i];
491
		} else if (strcmp(argv[i],"--verbose")==0){
492
			out->is_verbose=TRUE;
493 494
		} else if (strcmp(argv[i], "--video-windows-id")==0) {
			i++;
495
			if (!parse_window_ids(argv[i],&out->video_window_id, &out->preview_window_id)) {
496
				ms_error("Failed to parse window ids '%s'\n",argv[i]);
497
				return FALSE;
498
			}
499
		} else if (strcmp(argv[i], "--device-rotation")==0) {
500
			i++;
501
			out->device_rotation=atoi(argv[i]);
502
		} else if (strcmp(argv[i], "--srtp")==0) {
503
			if (!ms_srtp_supported()) {
jehan's avatar
jehan committed
504
				ms_error("srtp support not enabled");
505 506 507 508 509 510 511 512 513
				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++];
			}
514 515
		} else if (strcmp(argv[i],"--netsim-bandwidth")==0){
			i++;
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
			if (i<argc){
				out->netsim.max_bandwidth=atoi(argv[i]);
				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){
				out->netsim.loss_rate=atoi(argv[i]);
				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;
				}
544

545 546 547 548 549 550
				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
551
			i++;
552 553 554 555 556 557
			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
558
			}
559 560 561 562 563 564 565 566 567 568 569 570
		}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
571
			}
572
		}else if (strcmp(argv[i], "--netsim-jitter-strength") == 0) {
573
			i++;
574 575 576 577 578 579 580 581 582 583 584
			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;
			}
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
		}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;
			}
601
		}else if (strcmp(argv[i],"--zoom")==0){
602
			i++;
603 604 605 606
			if (sscanf(argv[i], "%f,%f,%f", &out->zoom, &out->zoom_cx, &out->zoom_cy) != 3) {
				ms_error("Invalid zoom triplet");
				return FALSE;
			}
607
		} else if (strcmp(argv[i],"--mtu")==0){
608 609 610 611 612
			i++;
			if (sscanf(argv[i], "%i", &out->mtu) != 1) {
				ms_error("Invalid mtu value");
				return FALSE;
			}
613
		} else if (strcmp(argv[i],"--interactive")==0){
614
			out->interactive=TRUE;
615 616
		} else if (strcmp(argv[i], "--no-avpf") == 0) {
			out->enable_avpf = FALSE;
617 618
		} else if (strcmp(argv[i], "--no-rtcp") == 0) {
			out->enable_rtcp = FALSE;
619
		} else if (strcmp(argv[i],"--help")==0) {
620
			return FALSE;
621 622 623
		} else if (strcmp(argv[i],"--video-display-filter")==0) {
			i++;
			out->video_display_filter=argv[i];
624 625 626
		} else if (strcmp(argv[i], "--log") == 0) {
			i++;
			out->logfile = fopen(argv[i], "a+");
627 628
		} else if (strcmp(argv[i], "--freeze-on-error") == 0) {
			out->freeze_on_error=TRUE;
629 630
		} else if (strcmp(argv[i], "--speaker") == 0) {
			out->enable_speaker=TRUE;
631
		} else {
632
			ms_error("Unknown option '%s'\n", argv[i]);
633
			return FALSE;
aymeric's avatar
aymeric committed
634
		}
635
	}
636 637 638 639
	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;
	}
640 641
	return TRUE;
}
642

jehan's avatar
jehan committed
643

644 645 646 647 648
#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
649
			ms_warning("Decoding error on videostream [%p]", md->video);
650 651
			break;
		case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
Ghislain MARY's avatar
Ghislain MARY committed
652
			ms_message("First video frame decoded successfully on videostream [%p]", md->video);
653 654 655 656 657
			break;
	}
}
#endif

658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
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;
}
673

674
void setup_media_streams(MediastreamDatas* args) {
675
	/*create the rtp session */
676
#ifdef VIDEO_ENABLED
Sylvain Berfini's avatar
Sylvain Berfini committed
677
	MSWebCam *cam=NULL;
678
#endif
679
	MSFactory *factory;
680
	ortp_init();
681 682
	if (args->logfile)
		ortp_set_log_file(args->logfile);
683

684
	if (args->is_verbose) {
685
		ortp_set_log_level_mask(ORTP_LOG_DOMAIN, ORTP_DEBUG|ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
686
	} else {
687
		ortp_set_log_level_mask(ORTP_LOG_DOMAIN, ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
aymeric's avatar
aymeric committed
688
	}
689

690
	factory = ms_factory_new_with_voip();
jehan's avatar
jehan committed
691

692
#if TARGET_OS_IPHONE || defined(ANDROID)
jehan's avatar
jehan committed
693
#if defined (HAVE_X264) && defined (VIDEO_ENABLED)
694
	libmsx264_init(); /*no plugin on IOS/Android */
jehan's avatar
jehan committed
695
#endif
696 697 698
#if defined (HAVE_OPENH264) && defined (VIDEO_ENABLED)
	libmsopenh264_init(); /*no plugin on IOS/Android */
#endif
jehan's avatar
jehan committed
699
#if defined (HAVE_SILK)
700
	libmssilk_init(); /*no plugin on IOS/Android */
jehan's avatar
jehan committed
701
#endif
702 703
#if defined (HAVE_WEBRTC)
	libmswebrtc_init();
704
#endif
705 706

#endif /* IPHONE | ANDROID */
707

708 709 710 711
	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);
712
	rtp_profile_set_payload(&av_profile,114,args->custom_pt);
713
	rtp_profile_set_payload(&av_profile,115,&payload_type_lpc1015);
714
#ifdef VIDEO_ENABLED
715
	cam=ms_web_cam_new(ms_mire_webcam_desc_get());
716
	if (cam) ms_web_cam_manager_add_cam(ms_factory_get_web_cam_manager(factory), cam);
Simon Morlat's avatar
Simon Morlat committed
717
	cam=NULL;
718

719 720 721 722 723 724
	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);
725
	rtp_profile_set_payload(&av_profile,103,&payload_type_vp8);
726

727
	args->video=NULL;
aymeric's avatar
aymeric committed
728
#endif
729 730
	args->profile=rtp_profile_clone_full(&av_profile);
	args->q=ortp_ev_queue_new();
731

732 733 734 735
	if (args->mtu) ms_factory_set_mtu(factory, args->mtu);
	ms_factory_enable_statistics(factory, TRUE);
	ms_factory_reset_statistics(factory);
	
Ghislain MARY's avatar
Ghislain MARY committed
736
	args->ice_session=ice_session_new();
Ghislain MARY's avatar
Ghislain MARY committed
737 738 739 740
	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);
741

aymeric's avatar
aymeric committed
742
	signal(SIGINT,stop_handler);
743 744
	args->pt=rtp_profile_get_payload(args->profile,args->payload);
	if (args->pt==NULL){
745
		ms_error("No payload defined with number %i.\n",args->payload);
aymeric's avatar
aymeric committed
746 747
		exit(-1);
	}
748
	if (args->enable_avpf == TRUE) {
749
		PayloadTypeAvpfParams avpf_params;
750
		payload_type_set_flag(args->pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
751
		avpf_params.features = PAYLOAD_TYPE_AVPF_FIR | PAYLOAD_TYPE_AVPF_PLI | PAYLOAD_TYPE_AVPF_SLI | PAYLOAD_TYPE_AVPF_RPSI;
752
		avpf_params.trr_interval = 3000;
753
		payload_type_set_avpf_params(args->pt, avpf_params);
754 755 756
	} else {
		payload_type_unset_flag(args->pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
	}
757 758
	if (args->fmtp!=NULL) payload_type_set_send_fmtp(args->pt,args->fmtp);
	if (args->bitrate>0) args->pt->normal_bitrate=args->bitrate;
759

760
	if (args->pt->normal_bitrate==0){
761
		ms_error("Default bitrate specified for codec %s/%i. "
762 763 764
			"Please specify a network bitrate with --bitrate option.\n",args->pt->mime_type,args->pt->clock_rate);
		exit(-1);
	}
aymeric's avatar
aymeric committed
765

766 767 768 769 770
	// 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
771 772
			char tmp[30];
			snprintf(tmp,sizeof(tmp),"%08x%08x%08x%08x",rand(),rand(),rand(),rand());
773 774 775 776 777 778
			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
779 780
			char tmp[30];
			snprintf(tmp,sizeof(tmp),"%08x%08x%08x%08x",rand(),rand(),rand(),rand());
781 782 783 784 785
			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);
		}
786
	}
787

788
	if (args->pt->type!=PAYLOAD_VIDEO){
789
		MSSndCardManager *manager=ms_factory_get_snd_card_manager(factory);
790
		MSSndCard *capt= args->capture_card==NULL ? ms_snd_card_manager_get_default_capture_card(manager) :
791 792 793
				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);
794
		args->audio=audio_stream_new(factory, args->localport,args->localport+1,ms_is_ipv6(args->ip));
795 796 797 798 799
		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);
		audio_stream_enable_adaptive_bitrate_control(args->audio,args->use_rc);
800 801 802 803
		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);
804
		ms_message("Starting audio stream.\n");
805

806
		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,
807
								args->outfile==NULL ? play : NULL ,args->infile==NULL ? capt : NULL,args->infile!=NULL ? FALSE: args->ec);
808

809
		if (args->ice_local_candidates_nb || args->ice_remote_candidates_nb) {
810
			args->audio->ms.ice_check_list = ice_check_list_new();
811
			rtp_session_set_pktinfo(args->audio->ms.sessions.rtp_session,TRUE);
812
			ice_session_add_check_list(args->ice_session, args->audio->ms.ice_check_list, 0);
813
		}
814 815 816 817 818
		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];
819 820
				ice_add_local_candidate(args->audio->ms.ice_check_list,candidate->type,candidate->ip,candidate->port,1,NULL);
				ice_add_local_candidate(args->audio->ms.ice_check_list,candidate->type,candidate->ip,candidate->port+1,2,NULL);
821 822 823
			}
		}
		if (args->ice_remote_candidates_nb) {
824
			char foundation[4];
825 826 827 828
			MediastreamIceCandidate *candidate;
			int c;
			for (c=0;c<args->ice_remote_candidates_nb;c++){
				candidate=&args->ice_remote_candidates[c];
829 830
				memset(foundation, '\0', sizeof(foundation));
				snprintf(foundation, sizeof(foundation) - 1, "%u", c + 1);
831 832
				ice_add_remote_candidate(args->audio->ms.ice_check_list,candidate->type,candidate->ip,candidate->port,1,0,foundation,FALSE);
				ice_add_remote_candidate(args->audio->ms.ice_check_list,candidate->type,candidate->ip,candidate->port+1,2,0,foundation,FALSE);
833 834 835
			}
		}

836 837 838 839 840 841 842 843 844 845 846 847
		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
848 849

			}
850 851 852 853
			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
854
				}
855 856 857
				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
858 859
				}
			}
860

Guillaume Beraudo's avatar
Guillaume Beraudo committed
861
			if (args->zrtp_secrets != NULL) {
862
				MSZrtpParams params;
863 864
				params.zid_file=args->zrtp_secrets;
				audio_stream_enable_zrtp(args->audio,&params);
865
			}
866
			
867

868
			args->session=args->audio->ms.sessions.rtp_session;
869
		}
870

871
		if (args->enable_srtp) {
872
			ms_message("SRTP enabled: %d",
873
				audio_stream_enable_srtp(
874
					args->audio,
jehan's avatar
jehan committed
875
					MS_AES_128_SHA1_80,
876
					args->srtp_local_master_key,
877 878
					args->srtp_remote_master_key));
		}
879 880 881 882 883 884 885 886 887 888 889
	#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
890 891
	}else{
#ifdef VIDEO_ENABLED
892 893 894
		float zoom[] = {
			args->zoom,
			args->zoom_cx, args->zoom_cy };
895
		MSMediaStreamIO iodef = MS_MEDIA_STREAM_IO_INITIALIZER;
896

897
		if (args->eq){
smorlat's avatar
smorlat committed
898 899 900
			ms_fatal("Cannot put an audio equalizer in a video stream !");
			exit(-1);
		}
901
		ms_message("Starting video stream.\n");
902
		args->video=video_stream_new(factory, args->localport, args->localport+1, ms_is_ipv6(args->ip));
903 904
		if (args->video_display_filter)
			video_stream_set_display_filter_name(args->video, args->video_display_filter);
905

906
#ifdef ANDROID
907 908
		if (args->device_rotation >= 0)
			video_stream_set_device_rotation(args->video, args->device_rotation);
909
#endif
910 911
		video_stream_set_sent_video_size(args->video,args->vs);
		video_stream_use_preview_video_window(args->video,args->two_windows);
912
#if TARGET_OS_IPHONE
jehan's avatar
jehan committed
913 914 915
		NSBundle* myBundle = [NSBundle mainBundle];
		const char*  nowebcam = [[myBundle pathForResource:@"nowebcamCIF"ofType:@"jpg"] cStringUsingEncoding:[NSString defaultCStringEncoding]];
		ms_static_image_set_default_image(nowebcam);
916
		NSUInteger cpucount = [[NSProcessInfo processInfo] processorCount];
917 918
		ms_factory_set_cpu_count(args->audio->ms.factory, cpucount);
		//ms_set_cpu_count(cpucount);
jehan's avatar
jehan committed
919
#endif
920
		video_stream_set_event_callback(args->video,video_stream_event_cb, args);
921
		video_stream_set_freeze_on_error(args->video,args->freeze_on_error);
922
		video_stream_enable_adaptive_bitrate_control(args->video,args->use_rc);
923
		if (args->camera)
924
			cam=ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(factory),args->camera);
925
		if (cam==NULL)
926
			cam=ms_web_cam_manager_get_default_cam(ms_factory_get_web_cam_manager(factory));
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943
		
		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,
944
					args->ip,args->remoteport,
945
					args->ip,args->enable_rtcp?args->remoteport+1:-1,
946
					args->payload,
947
					&iodef
948
					);
949
		args->session=args->video->ms.sessions.rtp_session;
950

951
		ms_filter_call_method(args->video->output,MS_VIDEO_DISPLAY_ZOOM, zoom);
952
		if (args->enable_srtp) {
953
			ms_message("SRTP enabled: %d",
954
				video_stream_enable_strp(
955
					args->video,
jehan's avatar
jehan committed
956
					MS_AES_128_SHA1_80,
957
					args->srtp_local_master_key,
958 959
					args->srtp_remote_master_key));
		}
aymeric's avatar
aymeric committed
960
#else
961
		ms_error("Error: video support not compiled.\n");
aymeric's avatar
aymeric committed
962 963
#endif
	}
964 965 966
	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
967
	ice_session_choose_default_remote_candidates(args->ice_session);
Ghislain MARY's avatar
Ghislain MARY committed
968
	ice_session_start_connectivity_checks(args->ice_session);
969

970 971
	if (args->netsim.enabled){
		rtp_session_enable_network_simulation(args->session,&args->netsim);
972
	}
973 974 975
}


976
static void mediastream_tool_iterate(MediastreamDatas* args) {
977 978 979
#ifndef WIN32
	struct pollfd pfd;
	int err;
980

981 982
	if (args->interactive){
		pfd.fd=STDIN_FILENO;
983
		pfd.events=POLLIN;
984
		pfd.revents=0;
985

986
		err=poll(&pfd,1,10);
987
		if (err==1 && (pfd.revents & POLLIN)){
988 989 990 991 992
			char commands[128];
			int intarg;
			commands[127]='\0';
			ms_sleep(1);  /* ensure following text be printed after ortp messages */
			if (args->eq)
993
			ms_message("\nPlease enter equalizer requests, such as 'eq active 1', 'eq active 0', 'eq 1200 0.1 200'\n");
994 995 996 997 998 999 1000

			if (fgets(commands,sizeof(commands)-1,stdin)!=NULL){
				int active,freq,freq_width;

				float gain;
				if (sscanf(commands,"eq active %i",&active)==1){
					audio_stream_enable_equalizer(args->audio,active);
1001
					ms_message("OK\n");
1002 1003
				}else if (sscanf(commands,"eq %i %f %i",&freq,&gain,&freq_width)==3){
					audio_stream_equalizer_set_gain(args->audio,freq,gain,freq_width);
1004
					ms_message("OK\n");
1005 1006
				}else if (sscanf(commands,"eq %i %f",&freq,&gain)==2){
					audio_stream_equalizer_set_gain(args->audio,freq,gain,0);
1007
					ms_message("OK\n");
1008 1009 1010 1011 1012 1013 1014 1015
				}else if (strstr(commands,"dump")){
					int n=0,i;
					float *t;
					ms_filter_call_method(args->audio->equalizer,MS_EQUALIZER_GET_NUM_FREQUENCIES,&n);
					t=(float*)alloca(sizeof(float)*n);
					ms_filter_call_method(args->audio->equalizer,MS_EQUALIZER_DUMP_STATE,t);
					for(i=0;i<n;++i){
						if (fabs(t[i]-1)>0.01){
1016
						ms_message("%i:%f:0 ",(i*args->pt->clock_rate)/(2*n),t[i]);
1017
						}
1018
					}
1019
					ms_message("\nOK\n");
1020
				}else if (sscanf(commands,"lossrate %i",&intarg)==1){
1021 1022 1023 1024 1025 1026 1027 1028
					args->netsim.enabled=TRUE;
					args->netsim.loss_rate=intarg;
					rtp_session_enable_network_simulation(args->session,&args->netsim);
				}else if (sscanf(commands,"bandwidth %i",&intarg)==1){
					args->netsim.enabled=TRUE;
					args->netsim.max_bandwidth=intarg;
					rtp_session_enable_network_simulation(args->session,&args->netsim);
				}else if (strstr(commands,"quit")){
1029
					cond=0;
1030
				}else ms_warning("Cannot understand this.\n");
1031
			}
1032 1033
		}else if (err==-1 && errno!=EINTR){
			ms_fatal("mediastream's poll() returned %s",strerror(errno));
1034
		}
1035 1036
	}else{
		ms_usleep(10000);
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
	}
#else
	MSG msg;
	Sleep(10);
	while (PeekMessage(&msg, NULL, 0, 0,1)){
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	/*no interactive mode on windows*/
#endif
1047 1048
}

1049
void mediastream_run_loop(MediastreamDatas* args) {
1050 1051
	rtp_session_register_event_queue(args->session,args->q);

1052
#if TARGET_OS_IPHONE
jehan's avatar
jehan committed
1053
	if (args->video) ms_set_video_stream(args->video); /*for IOS*/
1054
#endif
1055

1056 1057 1058
	while(cond)
	{
		int n;
1059
		for(n=0;n<500 && cond;++n){
1060
			mediastream_tool_iterate(args);
1061 1062 1063 1064 1065 1066 1067
#if defined(VIDEO_ENABLED)
			if (args->video) video_stream_iterate(args->video);
#endif
			if (args->audio) audio_stream_iterate(args->audio);
		}
		rtp_stats_display(rtp_session_get_stats(args->session),"RTP stats");
		if (args->session){
1068 1069
			float audio_load = 0;
			float video_load = 0;
1070

1071
			ms_message("Bandwidth usage: download=%f kbits/sec, upload=%f kbits/sec\n",