mediastream.c 34.2 KB
Newer Older
aymeric's avatar
aymeric committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
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.
*/

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

smorlat's avatar
smorlat committed
24 25
#include <math.h>

aymeric's avatar
aymeric committed
26
#include "mediastreamer2/mediastream.h"
smorlat's avatar
smorlat committed
27
#include "mediastreamer2/msequalizer.h"
28
#include "mediastreamer2/msvolume.h"
aymeric's avatar
aymeric committed
29 30 31 32
#ifdef VIDEO_ENABLED
#include "mediastreamer2/msv4l.h"
#endif

33
#include <ctype.h>
aymeric's avatar
aymeric committed
34 35 36 37
#include <signal.h>
#include <sys/types.h>
#ifndef WIN32
#include <unistd.h>
38 39
#else
#include <malloc.h>
aymeric's avatar
aymeric committed
40 41 42 43 44
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

45 46 47
#ifdef __APPLE__
#include <CoreFoundation/CFRunLoop.h>
#endif
Simon Morlat's avatar
Simon Morlat committed
48 49
#if  defined(__ios) || defined (ANDROID)
#ifdef __ios
jehan's avatar
jehan committed
50
#import <UIKit/UIKit.h>
jehan's avatar
jehan committed
51
#include <AudioToolbox/AudioToolbox.h>
Simon Morlat's avatar
Simon Morlat committed
52
#endif
jehan's avatar
jehan committed
53
extern void ms_set_video_stream(VideoStream* video);
jehan's avatar
jehan committed
54 55 56
#ifdef HAVE_X264
extern void libmsx264_init();
#endif
jehan's avatar
jehan committed
57 58 59
#ifdef HAVE_SILK
extern void libmssilk_init();
#endif 
jehan's avatar
jehan committed
60
#endif
61

62 63 64 65 66
#ifdef ANDROID
#include <android/log.h>
#include <jni.h>
#endif

67 68
#include <ortp/b64.h>

69 70 71
#define MEDIASTREAM_MAX_ICE_CANDIDATES 3


aymeric's avatar
aymeric committed
72 73 74
static int cond=1;


75

76 77 78 79 80 81
typedef struct _MediastreamIceCandidate {
	char ip[64];
	char type[6];
	int port;
} MediastreamIceCandidate;

82 83
typedef struct _MediastreamDatas {
	int localport,remoteport,payload;
84
	char ip[64];
85 86 87 88 89 90 91 92 93
	char *fmtp;
	int jitter;
	int bitrate;
	MSVideoSize vs;
	bool_t ec;
	bool_t agc;
	bool_t eq;
	bool_t is_verbose;
	int device_rotation;
94

95 96 97 98 99 100 101 102 103 104 105
#ifdef VIDEO_ENABLED
	VideoStream *video;
#endif
	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;
106 107 108
	bool_t use_rc;
	bool_t enable_srtp;
	bool_t pad[3];
109 110 111 112 113 114 115 116 117 118 119 120
	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;
121 122
	char* srtp_local_master_key;
	char* srtp_remote_master_key;
123
	int netsim_bw;
Yann Diorcet's avatar
Yann Diorcet committed
124
	int netsim_lossrate;
125
	float zoom;
126
	float zoom_cx, zoom_cy;
127 128 129 130 131 132
	
	AudioStream *audio;	
	PayloadType *pt;
	RtpSession *session;
	OrtpEvQueue *q;
	RtpProfile *profile;
133

Ghislain MARY's avatar
Ghislain MARY committed
134
	IceSession *ice_session;
135 136 137 138
	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;
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
} MediastreamDatas;

// 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);
/* run loop */
void run_interactive_loop(MediastreamDatas* args);
void run_non_interactive_loop(MediastreamDatas* args);
/* exit */
void clear_mediastreams(MediastreamDatas* args);

// HELPER METHODS
static void stop_handler(int signum);
static bool_t parse_addr(const char *addr, char *ip, int len, int *port);
157
static bool_t parse_ice_addr(char* addr, char* type, int type_len, char* ip, int ip_len, int* port);
158 159 160 161 162 163
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 PayloadType* create_custom_payload_type(const char *type, const char *subtype, const char *rate, int number);
static PayloadType* parse_custom_payload(const char *name);
static bool_t parse_window_ids(const char *ids, int* video_id, int* preview_id);
164

165 166
const char *usage="mediastream --local <port> --remote <ip:port> \n"
								"--payload <payload type number or payload name like 'audio/pmcu/8000'>\n"
Guillaume Beraudo's avatar
Guillaume Beraudo committed
167 168 169
								"[ --fmtp <fmtpline> ]\n"
								"[ --jitter <miliseconds> ]\n"
								"[ --width <pixels> ]\n"
smorlat's avatar
smorlat committed
170
								"[ --height <pixels> ]\n"
Guillaume Beraudo's avatar
Guillaume Beraudo committed
171 172
								"[ --bitrate <bits per seconds> ]\n"
								"[ --ec (enable echo canceller) ]\n"
173 174
								"[ --ec-tail <echo canceller tail length in ms> ]\n"
								"[ --ec-delay <echo canceller delay in ms> ]\n"
175
								"[ --ec-framesize <echo canceller framesize in samples> ]\n"
Guillaume Beraudo's avatar
Guillaume Beraudo committed
176 177 178 179 180 181 182 183
								"[ --agc (enable automatic gain control) ]\n"
								"[ --ng (enable noise gate)] \n"
								"[ --ng-threshold <(float) [0-1]> (noise gate threshold) ]\n"
								"[ --ng-floorgain <(float) [0-1]> (gain applied to the signal when its energy is below the threshold.) ]\n"
								"[ --capture-card <name> ]\n"
								"[ --playback-card <name> ]\n"
								"[ --infile	<input wav file> specify a wav file to be used for input, instead of soundcard ]\n"
								"[ --outfile <output wav file> specify a wav file to write audio into, instead of soundcard ]\n"
jehan's avatar
jehan committed
184 185 186 187 188 189
								"[ --camera <camera id as listed at startup> ]\n"
								"[ --el (enable echo limiter) ]\n"
								"[ --el-speed <(float) [0-1]> (gain changes are smoothed with a coefficent) ]\n"
								"[ --el-thres <(float) [0-1]> (Threshold above which the system becomes active) ]\n"
								"[ --el-force <(float) [0-1]> (The proportional coefficient controlling the mic attenuation) ]\n"
								"[ --el-sustain <(int)> (Time in milliseconds for which the attenuation is kept unchanged after) ]\n"
190
								"[ --el-transmit-thres <(float) [0-1]> (TO BE DOCUMENTED) ]\n"
Guillaume Beraudo's avatar
Guillaume Beraudo committed
191
								"[ --rc (enable adaptive rate control) ]\n"
Guillaume Beraudo's avatar
Guillaume Beraudo committed
192
								"[ --zrtp <secrets file> (enable zrtp) ]\n"
Guillaume Beraudo's avatar
Guillaume Beraudo committed
193
								"[ --verbose (most verbose messages) ]\n"
194
								"[ --video-windows-id <video surface:preview surface>]\n"
195
								"[ --srtp <local master_key> <remote master_key> (enable srtp, master key is generated if absent from comand line)\n"
196
								"[ --netsim-bandwidth <bandwidth limit in bits/s> (simulates a network download bandwidth limit)\n"
Yann Diorcet's avatar
Yann Diorcet committed
197
								"[ --netsim-lossrate <0-100> (simulates a network lost rate)\n"
198
								"[ --zoom zoomfactor]\n"
199 200
								"[ --ice-local-candidate <ip:port:[host|srflx|prflx|relay]> ]\n"
								"[ --ice-remote-candidate <ip:port:[host|srflx|prflx|relay]> ]\n"
Guillaume Beraudo's avatar
Guillaume Beraudo committed
201
		;
aymeric's avatar
aymeric committed
202

jehan's avatar
jehan committed
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
#if TARGET_OS_IPHONE
int g_argc;
char** g_argv;
static int _main(int argc, char * argv[]);
 
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
227

jehan's avatar
jehan committed
228
#if !__APPLE__ && !ANDROID
aymeric's avatar
aymeric committed
229
int main(int argc, char * argv[])
jehan's avatar
jehan committed
230 231
#endif

232
#if !ANDROID && !TARGET_OS_MAC || TARGET_OS_IPHONE
aymeric's avatar
aymeric committed
233
{
234
	MediastreamDatas* args;
235
	cond = 1;
236

237
	args = init_default_args();
238

239 240
	if (!parse_args(argc, argv, args))
		return 0;
241

242
	setup_media_streams(args);
243

244 245 246 247 248 249
	if (args->eq)
		run_interactive_loop(args);
	else
		run_non_interactive_loop(args);
	
	clear_mediastreams(args);
250

251 252 253
	free(args);
	
	return 0;
254 255 256 257 258
}

#endif


259
MediastreamDatas* init_default_args() {
260
	MediastreamDatas* args = (MediastreamDatas*)ms_malloc0(sizeof(MediastreamDatas));
261 262 263 264 265 266 267 268 269 270 271 272
	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;
	args->is_verbose=FALSE;
	args->device_rotation=-1;
aymeric's avatar
aymeric committed
273

274
#ifdef VIDEO_ENABLED
275
	args->video=NULL;
276
#endif
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
	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;
	/* starting values echo canceller */
	args->ec_len_ms=args->ec_delay_ms=args->ec_framesize=0;
298 299
	args->enable_srtp = FALSE;
	args->srtp_local_master_key = args->srtp_remote_master_key = NULL;
300
	args->zoom = 1.0;
301
	args->zoom_cx = args->zoom_cy = 0.5;
302 303 304 305 306 307 308

	args->audio = NULL;
	args->session = NULL;
	args->pt = NULL;
	args->q = NULL;
	args->profile = NULL;

Ghislain MARY's avatar
Ghislain MARY committed
309
	args->ice_session = NULL;
310 311 312 313
	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;

314
	return args;
315 316
}

317
bool_t parse_args(int argc, char** argv, MediastreamDatas* out) {
aymeric's avatar
aymeric committed
318
	int i;
jehan's avatar
jehan committed
319

aymeric's avatar
aymeric committed
320
	if (argc<4) {
Simon Morlat's avatar
Simon Morlat committed
321
		printf("%s",usage);
322
		return FALSE;
aymeric's avatar
aymeric committed
323
	}
324 325

	/* default size */
326 327
	out->vs.width=MS_VIDEO_SIZE_CIF_W;
	out->vs.height=MS_VIDEO_SIZE_CIF_H;
328

aymeric's avatar
aymeric committed
329 330 331
	for (i=1;i<argc;i++){
		if (strcmp(argv[i],"--local")==0){
			i++;
332
			out->localport=atoi(argv[i]);
aymeric's avatar
aymeric committed
333 334
		}else if (strcmp(argv[i],"--remote")==0){
			i++;
335
			if (!parse_addr(argv[i],out->ip,sizeof(out->ip),&out->remoteport)) {
Simon Morlat's avatar
Simon Morlat committed
336
				printf("%s",usage);
337
				return FALSE;
aymeric's avatar
aymeric committed
338
			}
339
			printf("Remote addr: ip=%s port=%i\n",out->ip,out->remoteport);
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
		}else if (strcmp(argv[i],"--ice-local-candidate")==0) {
			MediastreamIceCandidate *candidate;
			i++;
			if (out->ice_local_candidates_nb>=MEDIASTREAM_MAX_ICE_CANDIDATES) {
				printf("Ignore ICE local candidate \"%s\" (maximum %d candidates allowed)\n",argv[i],MEDIASTREAM_MAX_ICE_CANDIDATES);
				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)) {
				printf("%s",usage);
				return FALSE;
			}
			out->ice_local_candidates_nb++;
			printf("ICE local candidate: type=%s ip=%s port=%i\n",candidate->type,candidate->ip,candidate->port);
		}else if (strcmp(argv[i],"--ice-remote-candidate")==0) {
			MediastreamIceCandidate *candidate;
			i++;
			if (out->ice_remote_candidates_nb>=MEDIASTREAM_MAX_ICE_CANDIDATES) {
				printf("Ignore ICE remote candidate \"%s\" (maximum %d candidates allowed)\n",argv[i],MEDIASTREAM_MAX_ICE_CANDIDATES);
				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)) {
				printf("%s",usage);
				return FALSE;
			}
			out->ice_remote_candidates_nb++;
			printf("ICE remote candidate: type=%s ip=%s port=%i\n",candidate->type,candidate->ip,candidate->port);
aymeric's avatar
aymeric committed
368 369
		}else if (strcmp(argv[i],"--payload")==0){
			i++;
370
			if (isdigit(argv[i][0])){
371
				out->payload=atoi(argv[i]);
372
			}else {
373 374
				out->payload=114;
				out->custom_pt=parse_custom_payload(argv[i]);
375
			}
aymeric's avatar
aymeric committed
376 377
		}else if (strcmp(argv[i],"--fmtp")==0){
			i++;
378
			out->fmtp=argv[i];
aymeric's avatar
aymeric committed
379 380
		}else if (strcmp(argv[i],"--jitter")==0){
			i++;
381
			out->jitter=atoi(argv[i]);
aymeric's avatar
aymeric committed
382 383
		}else if (strcmp(argv[i],"--bitrate")==0){
			i++;
384
			out->bitrate=atoi(argv[i]);
smorlat's avatar
smorlat committed
385 386
		}else if (strcmp(argv[i],"--width")==0){
			i++;
387
			out->vs.width=atoi(argv[i]);
smorlat's avatar
smorlat committed
388 389
		}else if (strcmp(argv[i],"--height")==0){
			i++;
390
			out->vs.height=atoi(argv[i]);
391 392
		}else if (strcmp(argv[i],"--capture-card")==0){
			i++;
393
			out->capture_card=argv[i];
Simon Morlat's avatar
Simon Morlat committed
394 395
		}else if (strcmp(argv[i],"--playback-card")==0){
			i++;
396
			out->playback_card=argv[i];
aymeric's avatar
aymeric committed
397
		}else if (strcmp(argv[i],"--ec")==0){
398
			out->ec=TRUE;
399 400
		}else if (strcmp(argv[i],"--ec-tail")==0){
			i++;
401
			out->ec_len_ms=atoi(argv[i]);
402 403
		}else if (strcmp(argv[i],"--ec-delay")==0){
			i++;
404
			out->ec_delay_ms=atoi(argv[i]);
405 406
		}else if (strcmp(argv[i],"--ec-framesize")==0){
			i++;
407
			out->ec_framesize=atoi(argv[i]);
408
		}else if (strcmp(argv[i],"--agc")==0){
409
			out->agc=TRUE;
smorlat's avatar
smorlat committed
410
		}else if (strcmp(argv[i],"--eq")==0){
411
			out->eq=TRUE;
412
		}else if (strcmp(argv[i],"--ng")==0){
413
			out->use_ng=1;
414
		}else if (strcmp(argv[i],"--rc")==0){
415
			out->use_rc=1;
416 417
		}else if (strcmp(argv[i],"--ng-threshold")==0){
			i++;
418
			out->ng_threshold=atof(argv[i]);
jehan's avatar
jehan committed
419 420
		}else if (strcmp(argv[i],"--ng-floorgain")==0){
			i++;
421
			out->ng_floorgain=atof(argv[i]);
422
		}else if (strcmp(argv[i],"--two-windows")==0){
423
			out->two_windows=TRUE;
424 425
		}else if (strcmp(argv[i],"--infile")==0){
			i++;
426
			out->infile=argv[i];
427 428
		}else if (strcmp(argv[i],"--outfile")==0){
			i++;
429
			out->outfile=argv[i];
430 431
		}else if (strcmp(argv[i],"--camera")==0){
			i++;
432
			out->camera=argv[i];
jehan's avatar
jehan committed
433
		}else if (strcmp(argv[i],"--el")==0){
434
			out->el=TRUE;
jehan's avatar
jehan committed
435 436
		}else if (strcmp(argv[i],"--el-speed")==0){
			i++;
437
			out->el_speed=atof(argv[i]);
jehan's avatar
jehan committed
438 439
		}else if (strcmp(argv[i],"--el-thres")==0){
			i++;
440
			out->el_thres=atof(argv[i]);
jehan's avatar
jehan committed
441 442
		}else if (strcmp(argv[i],"--el-force")==0){
			i++;
443
			out->el_force=atof(argv[i]);
jehan's avatar
jehan committed
444 445
		}else if (strcmp(argv[i],"--el-sustain")==0){
			i++;
446
			out->el_sustain=atoi(argv[i]);
jehan's avatar
jehan committed
447 448
		}else if (strcmp(argv[i],"--el-transmit-thres")==0){
			i++;
449
			out->el_transmit_thres=atof(argv[i]);
Guillaume Beraudo's avatar
Guillaume Beraudo committed
450
		} else if (strcmp(argv[i],"--zrtp")==0){
451
			out->zrtp_secrets=argv[++i];
Guillaume Beraudo's avatar
Guillaume Beraudo committed
452
		} else if (strcmp(argv[i],"--verbose")==0){
453
			out->is_verbose=TRUE;
454 455
		} else if (strcmp(argv[i], "--video-windows-id")==0) {
			i++;
456
			if (!parse_window_ids(argv[i],&out->video_window_id, &out->preview_window_id)) {
457
				printf("%s",usage);
458
				return FALSE;
459
			}
460
		} else if (strcmp(argv[i], "--device-rotation")==0) {
461
			i++;
462
			out->device_rotation=atoi(argv[i]);
463 464 465 466 467 468 469 470 471 472 473 474
		} else if (strcmp(argv[i], "--srtp")==0) {
			if (!ortp_srtp_supported()) {
				ms_error("ortp srtp support not enabled");
				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++];
			}
475 476 477
		} else if (strcmp(argv[i],"--netsim-bandwidth")==0){
			i++;
			out->netsim_bw=atoi(argv[i]);
Yann Diorcet's avatar
Yann Diorcet committed
478 479 480 481 482 483 484 485 486 487 488 489
		} else if (strcmp(argv[i],"--netsim-lossrate")==0){
			i++;
			out->netsim_lossrate=atoi(argv[i]);
			if(out->netsim_lossrate < 0) {
				ms_warning("%d < 0, wrong value for --lost-rate: set to 0", out->netsim_lossrate);
				out->netsim_lossrate=0;
			}
			if(out->netsim_lossrate > 100) {
				ms_warning("%d > 100, wrong value for --lost-rate: set to 100", out->netsim_lossrate);
				out->netsim_lossrate=100;
			}
		} else if (strcmp(argv[i],"--zoom")==0){
490
			i++;
491 492 493 494
			if (sscanf(argv[i], "%f,%f,%f", &out->zoom, &out->zoom_cx, &out->zoom_cy) != 3) {
				ms_error("Invalid zoom triplet");
				return FALSE;
			}
495
		} else if (strcmp(argv[i],"--help")==0){
jehan's avatar
jehan committed
496
			printf("%s",usage);
497
			return FALSE;
aymeric's avatar
aymeric committed
498
		}
Guillaume Beraudo's avatar
Guillaume Beraudo committed
499
	}
500 501
	return TRUE;
}
Guillaume Beraudo's avatar
Guillaume Beraudo committed
502

jehan's avatar
jehan committed
503

504
void setup_media_streams(MediastreamDatas* args) {
Guillaume Beraudo's avatar
Guillaume Beraudo committed
505
	/*create the rtp session */
506
	OrtpNetworkSimulatorParams params={0};
507
#ifdef VIDEO_ENABLED	
Sylvain Berfini's avatar
Sylvain Berfini committed
508
	MSWebCam *cam=NULL;
509
#endif
Guillaume Beraudo's avatar
Guillaume Beraudo committed
510
	ortp_init();
511
	if (args->is_verbose) {
Guillaume Beraudo's avatar
Guillaume Beraudo committed
512 513 514
		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
515
	}
516

jehan's avatar
jehan committed
517

Simon Morlat's avatar
Simon Morlat committed
518
#if defined(__ios) || defined(ANDROID)
jehan's avatar
jehan committed
519 520 521 522 523 524 525 526 527
#if defined (HAVE_X264) && defined (VIDEO_ENABLED)
	libmsx264_init(); /*no plugin on IOS*/
#endif
#if defined (HAVE_SILK)
	libmssilk_init(); /*no plugin on IOS*/
#endif
	
#endif
	
Guillaume Beraudo's avatar
Guillaume Beraudo committed
528 529 530 531
	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);
532
	rtp_profile_set_payload(&av_profile,114,args->custom_pt);
533
	rtp_profile_set_payload(&av_profile,115,&payload_type_lpc1015);
Guillaume Beraudo's avatar
Guillaume Beraudo committed
534
#ifdef VIDEO_ENABLED
535
#if defined (__ios) && defined (HAVE_X264)
536 537
	libmsx264_init(); /*no plugin on IOS*/
#endif
Guillaume Beraudo's avatar
Guillaume Beraudo committed
538 539 540 541 542 543
	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);
544
	rtp_profile_set_payload(&av_profile,103,&payload_type_vp8);
545 546
	
	args->video=NULL;
aymeric's avatar
aymeric committed
547
#endif
548 549
	args->profile=rtp_profile_clone_full(&av_profile);
	args->q=ortp_ev_queue_new();
jehan's avatar
jehan committed
550

aymeric's avatar
aymeric committed
551
	ms_init();
552 553
	ms_filter_enable_statistics(TRUE);
	ms_filter_reset_statistics();
Ghislain MARY's avatar
Ghislain MARY committed
554
	args->ice_session=ice_session_new();
Ghislain MARY's avatar
Ghislain MARY committed
555 556 557 558
	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);
559

aymeric's avatar
aymeric committed
560
	signal(SIGINT,stop_handler);
561 562 563
	args->pt=rtp_profile_get_payload(args->profile,args->payload);
	if (args->pt==NULL){
		printf("Error: no payload defined with number %i.",args->payload);
aymeric's avatar
aymeric committed
564 565
		exit(-1);
	}
566 567
	if (args->fmtp!=NULL) payload_type_set_send_fmtp(args->pt,args->fmtp);
	if (args->bitrate>0) args->pt->normal_bitrate=args->bitrate;
aymeric's avatar
aymeric committed
568

569 570 571 572 573 574
	// 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) {
			uint8_t tmp[30];			
Sylvain Berfini's avatar
Sylvain Berfini committed
575
			ortp_crypto_get_random(tmp, 30);
576 577 578 579 580 581 582
			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) {
			uint8_t tmp[30];			
Sylvain Berfini's avatar
Sylvain Berfini committed
583
			ortp_crypto_get_random(tmp, 30);
584 585 586 587 588 589 590
			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);
		}
	}	

591
	if (args->pt->type!=PAYLOAD_VIDEO){
592
		MSSndCardManager *manager=ms_snd_card_manager_get();
593 594 595 596
		MSSndCard *capt= args->capture_card==NULL ? ms_snd_card_manager_get_default_capture_card(manager) :
				ms_snd_card_manager_get_card(manager,args->capture_card);
		MSSndCard *play= args->playback_card==NULL ? ms_snd_card_manager_get_default_playback_card(manager) :
				ms_snd_card_manager_get_card(manager,args->playback_card);
597
		args->audio=audio_stream_new(args->localport,args->localport+1,ms_is_ipv6(args->ip));
598 599 600 601 602
		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);
Simon Morlat's avatar
Simon Morlat committed
603
		printf("Starting audio stream.\n");
604

605
		audio_stream_start_full(args->audio,args->profile,args->ip,args->remoteport,args->ip,args->remoteport+1, args->payload, args->jitter,args->infile,args->outfile,
606 607
		                        args->outfile==NULL ? play : NULL ,args->infile==NULL ? capt : NULL,args->infile!=NULL ? FALSE: args->ec);

608
		if (args->ice_local_candidates_nb || args->ice_remote_candidates_nb) {
Ghislain MARY's avatar
Ghislain MARY committed
609 610 611
			args->audio->ms.ice_check_list = ice_check_list_new();
			rtp_session_set_pktinfo(args->audio->ms.session,TRUE);
			ice_session_add_check_list(args->ice_session, args->audio->ms.ice_check_list);
612
		}
613 614 615 616 617
		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];
Ghislain MARY's avatar
Ghislain MARY committed
618 619
				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);
620 621 622
			}
		}
		if (args->ice_remote_candidates_nb) {
623
			char foundation[4];
624 625 626 627
			MediastreamIceCandidate *candidate;
			int c;
			for (c=0;c<args->ice_remote_candidates_nb;c++){
				candidate=&args->ice_remote_candidates[c];
628 629
				memset(foundation, '\0', sizeof(foundation));
				snprintf(foundation, sizeof(foundation) - 1, "%u", c + 1);
Ghislain MARY's avatar
Ghislain MARY committed
630 631
				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);
632 633 634
			}
		}

635 636 637 638 639 640 641 642 643 644 645 646
		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
647 648

			}
649 650 651 652
			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
653
				}
654 655 656
				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
657 658
				}
			}
Guillaume Beraudo's avatar
Guillaume Beraudo committed
659

660
            #ifndef TARGET_OS_IPHONE
Guillaume Beraudo's avatar
Guillaume Beraudo committed
661
			if (args->zrtp_secrets != NULL) {
Guillaume Beraudo's avatar
Guillaume Beraudo committed
662
				OrtpZrtpParams params;
663 664
				params.zid_file=args->zrtp_secrets;
				audio_stream_enable_zrtp(args->audio,&params);
Guillaume Beraudo's avatar
Guillaume Beraudo committed
665
			}
666
            #endif
Guillaume Beraudo's avatar
Guillaume Beraudo committed
667

Ghislain MARY's avatar
Ghislain MARY committed
668
			args->session=args->audio->ms.session;
669
		}
670 671 672
		
		if (args->enable_srtp) {
			ms_message("SRTP enabled: %d", 
Ghislain MARY's avatar
Ghislain MARY committed
673
				audio_stream_enable_srtp(
674 675 676 677 678
					args->audio, 
					AES_128_SHA1_80,
					args->srtp_local_master_key, 
					args->srtp_remote_master_key));
		}
aymeric's avatar
aymeric committed
679 680
	}else{
#ifdef VIDEO_ENABLED
681 682 683 684
		float zoom[] = {
			args->zoom,
			args->zoom_cx, args->zoom_cy };

685
		if (args->eq){
smorlat's avatar
smorlat committed
686 687 688
			ms_fatal("Cannot put an audio equalizer in a video stream !");
			exit(-1);
		}
689
		ms_message("Starting video stream.\n");
690
		args->video=video_stream_new(args->localport, args->localport+1, ms_is_ipv6(args->ip));
691
#ifdef ANDROID
692 693
		if (args->device_rotation >= 0)
			video_stream_set_device_rotation(args->video, args->device_rotation);
694
#endif
695 696
		video_stream_set_sent_video_size(args->video,args->vs);
		video_stream_use_preview_video_window(args->video,args->two_windows);
Simon Morlat's avatar
Simon Morlat committed
697
#ifdef __ios
jehan's avatar
jehan committed
698 699 700 701 702
		NSBundle* myBundle = [NSBundle mainBundle];
		const char*  nowebcam = [[myBundle pathForResource:@"nowebcamCIF"ofType:@"jpg"] cStringUsingEncoding:[NSString defaultCStringEncoding]];
		ms_static_image_set_default_image(nowebcam);
#endif

703
		video_stream_enable_adaptive_bitrate_control(args->video,args->use_rc);
704 705
		if (args->camera)
			cam=ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),args->camera);
706 707
		if (cam==NULL)
			cam=ms_web_cam_manager_get_default_cam(ms_web_cam_manager_get());
708
		video_stream_start(args->video,args->profile,
709 710
					args->ip,args->remoteport,
					args->ip,args->remoteport+1,
711 712
					args->payload,
					args->jitter,cam
713
					);
Ghislain MARY's avatar
Ghislain MARY committed
714
		args->session=args->video->ms.session;
715

716
		ms_filter_call_method(args->video->output,MS_VIDEO_DISPLAY_ZOOM, zoom);
717 718 719 720 721 722 723 724
		if (args->enable_srtp) {
			ms_message("SRTP enabled: %d", 
				video_stream_enable_strp(
					args->video, 
					AES_128_SHA1_80,
					args->srtp_local_master_key, 
					args->srtp_remote_master_key));
		}
aymeric's avatar
aymeric committed
725 726 727 728
#else
		printf("Error: video support not compiled.\n");
#endif
	}
729 730 731
	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
732
	ice_session_choose_default_remote_candidates(args->ice_session);
Ghislain MARY's avatar
Ghislain MARY committed
733
	ice_session_start_connectivity_checks(args->ice_session);
734

735 736 737
	if (args->netsim_bw>0){
		params.enabled=TRUE;
		params.max_bandwidth=args->netsim_bw;
Yann Diorcet's avatar
Yann Diorcet committed
738 739 740 741 742 743
	}
	if (args->netsim_lossrate>0){
		params.enabled=TRUE;
		params.loss_rate=args->netsim_lossrate;
	}
	if (params.enabled){
744 745
		rtp_session_enable_network_simulation(args->session,&params);
	}
Yann Diorcet's avatar
Yann Diorcet committed
746

747 748 749 750
}


void run_interactive_loop(MediastreamDatas* args) {
751 752 753
		char commands[128];
		commands[127]='\0';
		ms_sleep(1);  /* ensure following text be printed after ortp messages */
754
		if (args->eq)
755 756 757 758 759 760 761
		printf("\nPlease enter equalizer requests, such as 'eq active 1', 'eq active 0', 'eq 1200 0.1 200'\n");

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

			float gain;
			if (sscanf(commands,"eq active %i",&active)==1){
762
				audio_stream_enable_equalizer(args->audio,active);
763 764
				printf("OK\n");
			}else if (sscanf(commands,"eq %i %f %i",&freq,&gain,&freq_width)==3){
765
				audio_stream_equalizer_set_gain(args->audio,freq,gain,freq_width);
766 767
				printf("OK\n");
			}else if (sscanf(commands,"eq %i %f",&freq,&gain)==2){
768
				audio_stream_equalizer_set_gain(args->audio,freq,gain,0);
769 770 771 772
				printf("OK\n");
			}else if (strstr(commands,"dump")){
				int n=0,i;
				float *t;
773
				ms_filter_call_method(args->audio->equalizer,MS_EQUALIZER_GET_NUM_FREQUENCIES,&n);
774
				t=(float*)alloca(sizeof(float)*n);
775
				ms_filter_call_method(args->audio->equalizer,MS_EQUALIZER_DUMP_STATE,t);
776 777
				for(i=0;i<n;++i){
					if (fabs(t[i]-1)>0.01){
778
					printf("%i:%f:0 ",(i*args->pt->clock_rate)/(2*n),t[i]);
779 780 781 782 783 784 785
					}
				}
				printf("\nOK\n");
			} else if (strstr(commands,"quit")){
				break;
			}else printf("Cannot understand this.\n");
		}
786 787 788 789 790
}

void run_non_interactive_loop(MediastreamDatas* args) {
	rtp_session_register_event_queue(args->session,args->q);

791
	#ifdef __ios
jehan's avatar
jehan committed
792
	if (args->video) ms_set_video_stream(args->video); /*for IOS*/
793 794
    #endif

795 796 797 798 799 800 801 802 803 804
	while(cond)
	{
		int n;
		for(n=0;n<100;++n){
#ifdef WIN32
			MSG msg;
			Sleep(10);
			while (PeekMessage(&msg, NULL, 0, 0,1)){
				TranslateMessage(&msg);
				DispatchMessage(&msg);
aymeric's avatar
aymeric committed
805
			}
806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823
#else
			struct timespec ts;
			ts.tv_sec=0;
			ts.tv_nsec=10000000;
			nanosleep(&ts,NULL);
#endif
#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){
			ms_message("Bandwidth usage: download=%f kbits/sec, upload=%f kbits/sec\n",
				rtp_session_compute_recv_bandwidth(args->session)*1e-3,
				rtp_session_compute_send_bandwidth(args->session)*1e-3);
			parse_events(args->session,args->q);
			ms_message("Quality indicator : %f\n",args->audio ? audio_stream_get_quality_rating(args->audio) : -1);
aymeric's avatar
aymeric committed
824
		}
Simon Morlat's avatar
Simon Morlat committed
825
	}
826
}
827

828
void clear_mediastreams(MediastreamDatas* args) {
jehan's avatar
jehan committed
829
	ms_message("stopping all...\n");
830
	ms_message("Average quality indicator: %f",args->audio ? audio_stream_get_average_quality_rating(args->audio) : -1);
831

832 833 834
	if (args->audio) {
		audio_stream_stop(args->audio);
	}
aymeric's avatar
aymeric committed
835
#ifdef VIDEO_ENABLED
836
	if (args->video) {
Ghislain MARY's avatar
Ghislain MARY committed
837
		if (args->video->ms.ice_check_list) ice_check_list_destroy(args->video->ms.ice_check_list);
838
		video_stream_stop(args->video);
839 840
		ms_filter_log_statistics();
	}
aymeric's avatar
aymeric committed
841
#endif
Ghislain MARY's avatar
Ghislain MARY committed
842
	if (args->ice_session) ice_session_destroy(args->ice_session);
843 844 845 846 847