mediastream.c 41.7 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 152
} MediastreamDatas;

153

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

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

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

jehan's avatar
jehan committed
227 228 229 230
#if TARGET_OS_IPHONE
int g_argc;
char** g_argv;
static int _main(int argc, char * argv[]);
231

jehan's avatar
jehan committed
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
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
251

jehan's avatar
jehan committed
252
#if !__APPLE__ && !ANDROID
aymeric's avatar
aymeric committed
253
int main(int argc, char * argv[])
jehan's avatar
jehan committed
254 255
#endif

256
#if !ANDROID && !TARGET_OS_MAC || TARGET_OS_IPHONE
aymeric's avatar
aymeric committed
257
{
258
	MediastreamDatas* args;
259
	cond = 1;
260

261
	args = init_default_args();
262

263 264
	if (!parse_args(argc, argv, args)){
		printf("%s",usage);
265
		return 0;
266
	}
267

268
	setup_media_streams(args);
269

270
	mediastream_run_loop(args);
271

272
	clear_mediastreams(args);
273

274
	free(args);
275

276
	return 0;
277 278 279 280 281
}

#endif


282
MediastreamDatas* init_default_args() {
283
	MediastreamDatas* args = (MediastreamDatas*)ms_malloc0(sizeof(MediastreamDatas));
284 285 286 287 288 289 290 291 292 293
	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;
294
	args->interactive=FALSE;
295 296
	args->is_verbose=FALSE;
	args->device_rotation=-1;
aymeric's avatar
aymeric committed
297

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

	args->audio = NULL;
	args->session = NULL;
	args->pt = NULL;
	args->q = NULL;
	args->profile = NULL;
334
	args->logfile = NULL;
335

Ghislain MARY's avatar
Ghislain MARY committed
336
	args->ice_session = NULL;
337 338 339
	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;
340
	args->video_display_filter=NULL;
341

342
	return args;
343 344
}

345
bool_t parse_args(int argc, char** argv, MediastreamDatas* out) {
aymeric's avatar
aymeric committed
346
	int i;
jehan's avatar
jehan committed
347

aymeric's avatar
aymeric committed
348
	if (argc<4) {
349
		ms_error("Expected at least 3 arguments.\n");
350
		return FALSE;
aymeric's avatar
aymeric committed
351
	}
352 353

	/* default size */
354 355
	out->vs.width=MS_VIDEO_SIZE_CIF_W;
	out->vs.height=MS_VIDEO_SIZE_CIF_H;
356

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

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

jehan's avatar
jehan committed
637

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

652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
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;
}
667

668
void setup_media_streams(MediastreamDatas* args) {
669
	/*create the rtp session */
670
#ifdef VIDEO_ENABLED
Sylvain Berfini's avatar
Sylvain Berfini committed
671
	MSWebCam *cam=NULL;
672
#endif
673
	ortp_init();
674 675
	if (args->logfile)
		ortp_set_log_file(args->logfile);
676

677
	if (args->is_verbose) {
678 679 680
		ortp_set_log_level_mask(ORTP_DEBUG|ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
	} else {
		ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
aymeric's avatar
aymeric committed
681
	}
682

Simon Morlat's avatar
Simon Morlat committed
683
	ms_init();
jehan's avatar
jehan committed
684

685
#if TARGET_OS_IPHONE || defined(ANDROID)
jehan's avatar
jehan committed
686
#if defined (HAVE_X264) && defined (VIDEO_ENABLED)
687
	libmsx264_init(); /*no plugin on IOS/Android */
jehan's avatar
jehan committed
688
#endif
689 690 691
#if defined (HAVE_OPENH264) && defined (VIDEO_ENABLED)
	libmsopenh264_init(); /*no plugin on IOS/Android */
#endif
jehan's avatar
jehan committed
692
#if defined (HAVE_SILK)
693
	libmssilk_init(); /*no plugin on IOS/Android */
jehan's avatar
jehan committed
694
#endif
695 696
#if defined (HAVE_WEBRTC)
	libmswebrtc_init();
697
#endif
698 699

#endif /* IPHONE | ANDROID */
700

701 702 703 704
	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);
705
	rtp_profile_set_payload(&av_profile,114,args->custom_pt);
706
	rtp_profile_set_payload(&av_profile,115,&payload_type_lpc1015);
707
#ifdef VIDEO_ENABLED
708
	cam=ms_web_cam_new(ms_mire_webcam_desc_get());
Simon Morlat's avatar
Simon Morlat committed
709 710
	if (cam) ms_web_cam_manager_add_cam(ms_web_cam_manager_get(), cam);
	cam=NULL;
711

712 713 714 715 716 717
	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);
718
	rtp_profile_set_payload(&av_profile,103,&payload_type_vp8);
719

720
	args->video=NULL;
aymeric's avatar
aymeric committed
721
#endif
722 723
	args->profile=rtp_profile_clone_full(&av_profile);
	args->q=ortp_ev_queue_new();
724

725
	if (args->mtu) ms_set_mtu(args->mtu);
726 727
	ms_filter_enable_statistics(TRUE);
	ms_filter_reset_statistics();
Ghislain MARY's avatar
Ghislain MARY committed
728
	args->ice_session=ice_session_new();
Ghislain MARY's avatar
Ghislain MARY committed
729 730 731 732
	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);
733

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

752
	if (args->pt->normal_bitrate==0){
753
		ms_error("Default bitrate specified for codec %s/%i. "
754 755 756
			"Please specify a network bitrate with --bitrate option.\n",args->pt->mime_type,args->pt->clock_rate);
		exit(-1);
	}
aymeric's avatar
aymeric committed
757

758 759 760 761 762
	// 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
763 764
			char tmp[30];
			snprintf(tmp,sizeof(tmp),"%08x%08x%08x%08x",rand(),rand(),rand(),rand());
765 766 767 768 769 770
			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
771 772
			char tmp[30];
			snprintf(tmp,sizeof(tmp),"%08x%08x%08x%08x",rand(),rand(),rand(),rand());
773 774 775 776 777
			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);
		}
778
	}
779

780
	if (args->pt->type!=PAYLOAD_VIDEO){
781
		MSSndCardManager *manager=ms_snd_card_manager_get();
782
		MSSndCard *capt= args->capture_card==NULL ? ms_snd_card_manager_get_default_capture_card(manager) :
783 784 785
				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);
786
		args->audio=audio_stream_new(args->localport,args->localport+1,ms_is_ipv6(args->ip));
787 788 789 790 791
		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);
792
		
793
		ms_message("Starting audio stream.\n");
794

795
		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,
796
								args->outfile==NULL ? play : NULL ,args->infile==NULL ? capt : NULL,args->infile!=NULL ? FALSE: args->ec);
797

798
		if (args->ice_local_candidates_nb || args->ice_remote_candidates_nb) {
799
			args->audio->ms.ice_check_list = ice_check_list_new();
800
			rtp_session_set_pktinfo(args->audio->ms.sessions.rtp_session,TRUE);
801
			ice_session_add_check_list(args->ice_session, args->audio->ms.ice_check_list, 0);
802
		}
803 804 805 806 807
		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];
808 809
				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);
810 811 812
			}
		}
		if (args->ice_remote_candidates_nb) {
813
			char foundation[4];
814 815 816 817
			MediastreamIceCandidate *candidate;
			int c;
			for (c=0;c<args->ice_remote_candidates_nb;c++){
				candidate=&args->ice_remote_candidates[c];
818 819
				memset(foundation, '\0', sizeof(foundation));
				snprintf(foundation, sizeof(foundation) - 1, "%u", c + 1);
820 821
				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);
822 823 824
			}
		}

825 826 827 828 829 830 831 832 833 834 835 836
		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
837 838

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

850
			#ifndef TARGET_OS_IPHONE
Guillaume Beraudo's avatar
Guillaume Beraudo committed
851
			if (args->zrtp_secrets != NULL) {
852
				MSZrtpParams params;
853 854
				params.zid_file=args->zrtp_secrets;
				audio_stream_enable_zrtp(args->audio,&params);
855
			}
856
			#endif
857

858
			args->session=args->audio->ms.sessions.rtp_session;
859
		}
860

861
		if (args->enable_srtp) {
862
			ms_message("SRTP enabled: %d",
863
				audio_stream_enable_srtp(
864
					args->audio,
jehan's avatar
jehan committed
865
					MS_AES_128_SHA1_80,
866
					args->srtp_local_master_key,
867 868
					args->srtp_remote_master_key));
		}
aymeric's avatar
aymeric committed
869 870
	}else{
#ifdef VIDEO_ENABLED
871 872 873
		float zoom[] = {
			args->zoom,
			args->zoom_cx, args->zoom_cy };
874
		MSMediaStreamIO iodef = MS_MEDIA_STREAM_IO_INITIALIZER;
875

876
		if (args->eq){
smorlat's avatar
smorlat committed
877 878 879
			ms_fatal("Cannot put an audio equalizer in a video stream !");
			exit(-1);
		}
880
		ms_message("Starting video stream.\n");
881
		args->video=video_stream_new(args->localport, args->localport+1, ms_is_ipv6(args->ip));
882 883
		if (args->video_display_filter)
			video_stream_set_display_filter_name(args->video, args->video_display_filter);
884

885
#ifdef ANDROID
886 887
		if (args->device_rotation >= 0)
			video_stream_set_device_rotation(args->video, args->device_rotation);
888
#endif
889 890
		video_stream_set_sent_video_size(args->video,args->vs);
		video_stream_use_preview_video_window(args->video,args->two_windows);
891
#if TARGET_OS_IPHONE
jehan's avatar
jehan committed
892 893 894
		NSBundle* myBundle = [NSBundle mainBundle];
		const char*  nowebcam = [[myBundle pathForResource:@"nowebcamCIF"ofType:@"jpg"] cStringUsingEncoding:[NSString defaultCStringEncoding]];
		ms_static_image_set_default_image(nowebcam);
895 896
		NSUInteger cpucount = [[NSProcessInfo processInfo] processorCount];
		ms_set_cpu_count(cpucount);
jehan's avatar
jehan committed
897
#endif
898
		video_stream_set_event_callback(args->video,video_stream_event_cb, args);
899
		video_stream_set_freeze_on_error(args->video,args->freeze_on_error);
900
		video_stream_enable_adaptive_bitrate_control(args->video,args->use_rc);
901 902
		if (args->camera)
			cam=ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),args->camera);
903 904
		if (cam==NULL)
			cam=ms_web_cam_manager_get_default_cam(ms_web_cam_manager_get());
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
		
		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,
922
					args->ip,args->remoteport,
923
					args->ip,args->enable_rtcp?args->remoteport+1:-1,
924
					args->payload,
925
					&iodef
926
					);
927
		args->session=args->video->ms.sessions.rtp_session;
928

929
		ms_filter_call_method(args->video->output,MS_VIDEO_DISPLAY_ZOOM, zoom);
930
		if (args->enable_srtp) {
931
			ms_message("SRTP enabled: %d",
932
				video_stream_enable_strp(
933
					args->video,
jehan's avatar
jehan committed
934
					MS_AES_128_SHA1_80,
935
					args->srtp_local_master_key,
936 937
					args->srtp_remote_master_key));
		}
aymeric's avatar
aymeric committed
938
#else
939
		ms_error("Error: video support not compiled.\n");
aymeric's avatar
aymeric committed
940 941
#endif
	}
942 943 944
	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
945
	ice_session_choose_default_remote_candidates(args->ice_session);
Ghislain MARY's avatar
Ghislain MARY committed
946
	ice_session_start_connectivity_checks(args->ice_session);
947

948 949
	if (args->netsim.enabled){
		rtp_session_enable_network_simulation(args->session,&args->netsim);
950
	}
951 952 953
}


954
static void mediastream_tool_iterate(MediastreamDatas* args) {
955 956 957
#ifndef WIN32
	struct pollfd pfd;
	int err;
958

959 960
	if (args->interactive){
		pfd.fd=STDIN_FILENO;
961
		pfd.events=POLLIN;
962
		pfd.revents=0;
963

964
		err=poll(&pfd,1,10);
965
		if (err==1 && (pfd.revents & POLLIN)){
966 967 968 969 970
			char commands[128];
			int intarg;
			commands[127]='\0';
			ms_sleep(1);  /* ensure following text be printed after ortp messages */
			if (args->eq)
971
			ms_message("\nPlease enter equalizer requests, such as 'eq active 1', 'eq active 0', 'eq 1200 0.1 200'\n");
972 973 974 975 976 977 978

			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);
979
					ms_message("OK\n");
980 981
				}else if (sscanf(commands,"eq %i %f %i",&freq,&gain,&freq_width)==3){
					audio_stream_equalizer_set_gain(args->audio,freq,gain,freq_width);
982
					ms_message("OK\n");
983 984
				}else if (sscanf(commands,"eq %i %f",&freq,&gain)==2){
					audio_stream_equalizer_set_gain(args->audio,freq,gain,0);
985
					ms_message("OK\n");
986 987 988 989 990 991 992 993
				}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){
994
						ms_message("%i:%f:0 ",(i*args->pt->clock_rate)/(2*n),t[i]);
995
						}
996
					}
997
					ms_message("\nOK\n");
998
				}else if (sscanf(commands,"lossrate %i",&intarg)==1){
999 1000 1001 1002 1003 1004 1005 1006
					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")){
1007
					cond=0;
1008
				}else ms_warning("Cannot understand this.\n");
1009
			}
1010 1011
		}else if (err==-1 && errno!=EINTR){
			ms_fatal("mediastream's poll() returned %s",strerror(errno));
1012
		}
1013 1014
	}else{
		ms_usleep(10000);
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
	}
#else
	MSG msg;
	Sleep(10);
	while (PeekMessage(&msg, NULL, 0, 0,1)){
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	/*no interactive mode on windows*/
#endif
1025 1026
}

1027
void mediastream_run_loop(MediastreamDatas* args) {
1028 1029
	rtp_session_register_event_queue(args->session,args->q);

1030
#if TARGET_OS_IPHONE
jehan's avatar
jehan committed
1031
	if (args->video) ms_set_video_stream(args->video); /*for IOS*/
1032
#endif
1033

1034 1035 1036
	while(cond)
	{
		int n;
1037
		for(n=0;n<500 && cond;++n){
1038
			mediastream_tool_iterate(args);
1039 1040 1041 1042 1043 1044 1045
#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){
1046 1047
			float audio_load = 0;
			float video_load = 0;
1048

1049
			ms_message("Bandwidth usage: download=%f kbits/sec, upload=%f kbits/sec\n",
1050 1051
				rtp_session_get_recv_bandwidth(args->session)*1e-3,
				rtp_session_get_send_bandwidth(args->session)*1e-3);
1052

1053 1054 1055 1056 1057 1058 1059 1060 1061
			if (args->audio) {
				audio_load = ms_ticker_get_average_load(args->audio->ms.sessions.ticker);
			}
#if defined(VIDEO_ENABLED)
			if (args->video) {
				video_load = ms_ticker_get_average_load(args->video->ms.sessions.ticker);
			}
#endif
			ms_message("Thread processing load: audio=%f\tvideo=%f", audio_load, video_load);
1062
			parse_events(args->session,args->q);
1063
			ms_message("Quality indicator : %f\n",args->audio ? audio_stream_get_quality_rating(args->audio) : media_stream_get_quality_rating((MediaStream*)args->video));
aymeric's avatar
aymeric committed
1064
		}
Simon Morlat's avatar
Simon Morlat committed
1065
	}
1066
}
1067

1068
void clear_mediastreams(MediastreamDatas* args) {
jehan's avatar
jehan committed
1069
	ms_message("stopping all...\n");
1070
	ms_message("Average quality indicator: %f",