1 /*
2 mediastreamer2 library - modular sound and video processing and streaming
3 Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 */
19 
20 
21 #include <math.h>
22 #include "common.h"
23 #include "mediastreamer2/msequalizer.h"
24 #include "mediastreamer2/msvolume.h"
25 #ifdef VIDEO_ENABLED
26 #include "mediastreamer2/msv4l.h"
27 #endif
28 
29 #include <ctype.h>
30 #include <signal.h>
31 #include <sys/types.h>
32 #ifndef _WIN32
33 #include <unistd.h>
34 #include <poll.h>
35 #else
36 #include <malloc.h>
37 #endif
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 
42 #ifdef TARGET_OS_MAC
43 #include <CoreFoundation/CFRunLoop.h>
44 #endif
45 
46 #if TARGET_OS_IPHONE
47 #import <UIKit/UIKit.h>
48 #include <AudioToolbox/AudioToolbox.h>
49 #endif
50 
51 #if  TARGET_OS_IPHONE || defined (__ANDROID__)
52 extern void ms_set_video_stream(VideoStream* video);
53 #if TARGET_OS_IPHONE || defined(HAVE_X264)
54 extern void libmsx264_init();
55 #endif
56 #if TARGET_OS_IPHONE || defined(HAVE_OPENH264)
57 extern void libmsopenh264_init();
58 #endif
59 #if TARGET_OS_IPHONE || defined(HAVE_SILK)
60 extern void libmssilk_init();
61 #endif
62 #if TARGET_OS_IPHONE || defined(HAVE_WEBRTC)
63 extern void libmswebrtc_init();
64 #endif
65 #endif // TARGET_OS_IPHONE || defined (__ANDROID__)
66 
67 #ifdef __ANDROID__
68 #include <android/log.h>
69 #include <jni.h>
70 #endif
71 
72 #include <ortp/b64.h>
73 
74 
75 #ifdef HAVE_CONFIG_H
76 #include "mediastreamer-config.h"
77 #endif
78 
79 
80 #define MEDIASTREAM_MAX_ICE_CANDIDATES 3
81 
82 static int cond=1;
83 
84 typedef enum _RcAlgo{
85 	RCAlgoNone,
86 	RCAlgoSimple,
87 	RCAlgoAdvanced,
88 	RCAlgoInvalid
89 }RcAlgo;
90 
91 typedef struct _MediastreamIceCandidate {
92 	char ip[64];
93 	char type[6];
94 	int port;
95 } MediastreamIceCandidate;
96 
97 typedef struct _MediastreamDatas {
98 	MSFactory *factory;
99 	int localport,remoteport,payload;
100 	char ip[64];
101 	char *send_fmtp;
102 	char *recv_fmtp;
103 	int jitter;
104 	int bitrate;
105 	int mtu;
106 	MSVideoSize vs;
107 	RcAlgo rc_algo;
108 	bool_t ec;
109 	bool_t agc;
110 	bool_t eq;
111 	bool_t is_verbose;
112 	int device_rotation;
113 	VideoStream *video;
114 	char * capture_card;
115 	char * playback_card;
116 	char * camera;
117 	char *infile,*outfile;
118 	float ng_threshold;
119 	bool_t use_ng;
120 	bool_t two_windows;
121 	bool_t el;
122 	bool_t enable_srtp;
123 
124 	bool_t interactive;
125 	bool_t enable_avpf;
126 	bool_t enable_rtcp;
127 	bool_t freeze_on_error;
128 
129 	float el_speed;
130 	float el_thres;
131 	float el_force;
132 	int el_sustain;
133 	float el_transmit_thres;
134 	float ng_floorgain;
135 	bool_t enable_zrtp;
136 	PayloadType *custom_pt;
137 	int video_window_id;
138 	int preview_window_id;
139 	/* starting values echo canceller */
140 	int ec_len_ms, ec_delay_ms, ec_framesize;
141 	char* srtp_local_master_key;
142 	char* srtp_remote_master_key;
143 	OrtpNetworkSimulatorParams netsim;
144 	float zoom;
145 	float zoom_cx, zoom_cy;
146 
147 	AudioStream *audio;
148 	PayloadType *pt;
149 	RtpSession *session;
150 	OrtpEvQueue *q;
151 	RtpProfile *profile;
152 	MSBandwidthController *bw_controller;
153 
154 	IceSession *ice_session;
155 	MediastreamIceCandidate ice_local_candidates[MEDIASTREAM_MAX_ICE_CANDIDATES];
156 	MediastreamIceCandidate ice_remote_candidates[MEDIASTREAM_MAX_ICE_CANDIDATES];
157 	int ice_local_candidates_nb;
158 	int ice_remote_candidates_nb;
159 	char * video_display_filter;
160 	FILE * logfile;
161 	bool_t enable_speaker;
162 } MediastreamDatas;
163 
164 
165 // MAIN METHODS
166 /* init default arguments */
167 MediastreamDatas* init_default_args(void);
168 /* parse args */
169 bool_t parse_args(int argc, char** argv, MediastreamDatas* out);
170 /* setup streams */
171 void setup_media_streams(MediastreamDatas* args);
172 /* run loop*/
173 void mediastream_run_loop(MediastreamDatas* args);
174 /* exit */
175 void clear_mediastreams(MediastreamDatas* args);
176 
177 // HELPER METHODS
178 void stop_handler(int signum);
179 static bool_t parse_addr(const char *addr, char *ip, size_t len, int *port);
180 static bool_t parse_ice_addr(char* addr, char* type, size_t type_len, char* ip, size_t ip_len, int* port);
181 static void display_items(void *user_data, uint32_t csrc, rtcp_sdes_type_t t, const char *content, uint8_t content_len);
182 static void parse_rtcp(mblk_t *m);
183 static void parse_events(RtpSession *session, OrtpEvQueue *q);
184 static bool_t parse_window_ids(const char *ids, int* video_id, int* preview_id);
185 static RcAlgo parse_rc_algo(const char *algo);
186 
187 const char *usage="mediastream --local <port>\n"
188 								"--remote <ip:port> \n"
189 								"[--help (display this help) ]\n"
190 								"[--payload <payload type number or payload name like 'audio/pmcu/8000'> ]\n"
191 								"[ --agc (enable automatic gain control) ]\n"
192 								"[ --bitrate <bits per seconds> ]\n"
193 								"[ --camera <camera id as listed at startup> ]\n"
194 								"[ --capture-card <name> ]\n"
195 								"[ --ec (enable echo canceller) ]\n"
196 								"[ --ec-delay <echo canceller delay in ms> ]\n"
197 								"[ --ec-framesize <echo canceller framesize in samples> ]\n"
198 								"[ --ec-tail <echo canceller tail length in ms> ]\n"
199 								"[ --el (enable echo limiter) ]\n"
200 								"[ --el-force <(float) [0-1]> (The proportional coefficient controlling the mic attenuation) ]\n"
201 								"[ --el-speed <(float) [0-1]> (gain changes are smoothed with a coefficent) ]\n"
202 								"[ --el-sustain <(int)> (Time in milliseconds for which the attenuation is kept unchanged after) ]\n"
203 								"[ --el-thres <(float) [0-1]> (Threshold above which the system becomes active) ]\n"
204 								"[ --el-transmit-thres <(float) [0-1]> (TO BE DOCUMENTED) ]\n"
205 								"[ --fmtp <fmtpline> ]\n"
206 								"[ --recv_fmtp <fmtpline passed to decoder> ]\n"
207 								"[ --freeze-on-error (for video, stop upon decoding error until next valid frame) ]\n"
208 								"[ --height <pixels> ]\n"
209 								"[ --ice-local-candidate <ip:port:[host|srflx|prflx|relay]> ]\n"
210 								"[ --ice-remote-candidate <ip:port:[host|srflx|prflx|relay]> ]\n"
211 								"[ --infile <input wav file> specify a wav file to be used for input, instead of soundcard ]\n"
212 								"[ --interactive (run in interactive mode) ]\n"
213 								"[ --jitter <miliseconds> ]\n"
214 								"[ --log <file> ]\n"
215 								"[ --mtu <mtu> (specify MTU)]\n"
216 								"[ --netsim-bandwidth <bandwidth limit in bits/s> (simulates a network download bandwidth limit) ]\n"
217 								"[ --netsim-consecutive-loss-probability <0-1> (to simulate bursts of lost packets) ]\n"
218 								"[ --netsim-jitter-burst-density <0-10> (density of gap/burst events, 1.0=one gap/burst per second in average) ]\n"
219 								"[ --netsim-jitter-strength <0-100> (strength of the jitter simulation) ]\n"
220 								"[ --netsim-latency <latency in ms> (simulates a network latency) ]\n"
221 								"[ --netsim-lossrate <0-100> (simulates a network lost rate) ]\n"
222 								"[ --netsim-mode inbound|outboud (whether network simulation is applied to incoming (default) or outgoing stream) ]\n"
223 								"[ --ng (enable noise gate)] \n"
224 								"[ --ng-floorgain <(float) [0-1]> (gain applied to the signal when its energy is below the threshold.) ]\n"
225 								"[ --ng-threshold <(float) [0-1]> (noise gate threshold) ]\n"
226 								"[ --no-avpf ]\n"
227 								"[ --no-rtcp ]\n"
228 								"[ --outfile <output wav file> specify a wav file to write audio into, instead of soundcard ]\n"
229 								"[ --playback-card <name> ]\n"
230 								"[ --rc <rate control algorithm> possible values are: none, simple, advanced ]\n"
231 								"[ --srtp <local master_key> <remote master_key> (enable srtp, master key is generated if absent from comand line) ]\n"
232 								"[ --verbose (most verbose messages) ]\n"
233 								"[ --video-display-filter <name> ]\n"
234 								"[ --video-windows-id <video surface:preview surface >]\n"
235 								"[ --width <pixels> ]\n"
236 								"[ --zoom zoom factor ]\n"
237 								"[ --zrtp (enable zrtp) ]\n"
238 								#if TARGET_OS_IPHONE
239 								"[ --speaker route audio to speaker ]\n"
240 								#endif
241 								;
242 
243 #if TARGET_OS_IPHONE
244 int g_argc;
245 char** g_argv;
246 static int _main(int argc, char * argv[]);
247 
apple_main(void * data)248 static void* apple_main(void* data) {
249 	 _main(g_argc,g_argv);
250 	 return NULL;
251 	}
main(int argc,char * argv[])252 int main(int argc, char * argv[]) {
253 	pthread_t main_thread;
254 	g_argc=argc;
255 	g_argv=argv;
256 	pthread_create(&main_thread,NULL,apple_main,NULL);
257 	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
258 	int value = UIApplicationMain(0, nil, nil, nil);
259 	[pool release];
260 	return value;
261 	cond=0;
262 	pthread_join(main_thread,NULL);
263 	return 0;
264 }
_main(int argc,char * argv[])265 static int _main(int argc, char * argv[])
266 #endif
267 
268 #if !TARGET_OS_MAC && !defined(__ANDROID__)
269 int main(int argc, char * argv[])
270 #endif
271 
272 #if !defined(__ANDROID__) && !TARGET_OS_MAC || TARGET_OS_IPHONE
273 {
274 	MediastreamDatas* args;
275 	cond = 1;
276 
277 	args = init_default_args();
278 
279 	if (!parse_args(argc, argv, args)){
280 		printf("%s",usage);
281 		return 0;
282 	}
283 
284 	setup_media_streams(args);
285 
286 	mediastream_run_loop(args);
287 
288 	clear_mediastreams(args);
289 
290 	free(args);
291 
292 	return 0;
293 }
294 
295 #endif
296 
297 
init_default_args(void)298 MediastreamDatas* init_default_args(void) {
299 	MediastreamDatas* args = (MediastreamDatas*)ms_malloc0(sizeof(MediastreamDatas));
300 	args->localport=0;
301 	args->remoteport=0;
302 	args->payload=0;
303 	memset(args->ip, 0, sizeof(args->ip));
304 	args->send_fmtp=NULL;
305 	args->recv_fmtp=NULL;
306 	args->jitter=50;
307 	args->bitrate=0;
308 	args->ec=FALSE;
309 	args->agc=FALSE;
310 	args->eq=FALSE;
311 	args->interactive=FALSE;
312 	args->is_verbose=FALSE;
313 	args->device_rotation=-1;
314 	args->rc_algo = RCAlgoNone;
315 
316 #ifdef VIDEO_ENABLED
317 	args->video=NULL;
318 #endif
319 	args->capture_card=NULL;
320 	args->playback_card=NULL;
321 	args->camera=NULL;
322 	args->infile=args->outfile=NULL;
323 	args->ng_threshold=-1;
324 	args->use_ng=FALSE;
325 	args->two_windows=FALSE;
326 	args->el=FALSE;
327 	args->el_speed=-1;
328 	args->el_thres=-1;
329 	args->el_force=-1;
330 	args->el_sustain=-1;
331 	args->el_transmit_thres=-1;
332 	args->ng_floorgain=-1;
333 	args->enable_zrtp =FALSE;
334 	args->custom_pt=NULL;
335 	args->video_window_id = -1;
336 	args->preview_window_id = -1;
337 	args->enable_avpf = TRUE;
338 	args->enable_rtcp = TRUE;
339 	/* starting values echo canceller */
340 	args->ec_len_ms=args->ec_delay_ms=args->ec_framesize=0;
341 	args->enable_srtp = FALSE;
342 	args->srtp_local_master_key = args->srtp_remote_master_key = NULL;
343 	args->zoom = 1.0;
344 	args->zoom_cx = args->zoom_cy = 0.5;
345 
346 	args->audio = NULL;
347 	args->session = NULL;
348 	args->pt = NULL;
349 	args->q = NULL;
350 	args->profile = NULL;
351 	args->logfile = NULL;
352 
353 	args->ice_session = NULL;
354 	memset(args->ice_local_candidates, 0, sizeof(args->ice_local_candidates));
355 	memset(args->ice_remote_candidates, 0, sizeof(args->ice_remote_candidates));
356 	args->ice_local_candidates_nb = args->ice_remote_candidates_nb = 0;
357 	args->video_display_filter=NULL;
358 
359 	return args;
360 }
361 
parse_args(int argc,char ** argv,MediastreamDatas * out)362 bool_t parse_args(int argc, char** argv, MediastreamDatas* out) {
363 	int i;
364 
365 	if (argc<4) {
366 		ms_error("Expected at least 3 arguments.\n");
367 		return FALSE;
368 	}
369 
370 	/* default size */
371 	out->vs.width=MS_VIDEO_SIZE_CIF_W;
372 	out->vs.height=MS_VIDEO_SIZE_CIF_H;
373 
374 	for (i=1;i<argc;i++){
375 		if (strcmp(argv[i],"--help")==0 || strcmp(argv[i],"-h")==0) {
376 			return FALSE;
377 		}else if (strcmp(argv[i],"--local")==0){
378 			char *is_invalid;
379 			i++;
380 			out->localport = strtol(argv[i],&is_invalid,10);
381 			if (*is_invalid!='\0'){
382 				ms_error("Failed to parse local port '%s'\n",argv[i]);
383 				return 0;
384 			}
385 		}else if (strcmp(argv[i],"--remote")==0){
386 			i++;
387 			if (!parse_addr(argv[i],out->ip,sizeof(out->ip),&out->remoteport)) {
388 				ms_error("Failed to parse remote address '%s'\n",argv[i]);
389 				return FALSE;
390 			}
391 			ms_message("Remote addr: ip=%s port=%i\n",out->ip,out->remoteport);
392 		}else if (strcmp(argv[i],"--ice-local-candidate")==0) {
393 			MediastreamIceCandidate *candidate;
394 			i++;
395 			if (out->ice_local_candidates_nb>=MEDIASTREAM_MAX_ICE_CANDIDATES) {
396 				ms_warning("Ignore ICE local candidate \"%s\" (maximum %d candidates allowed)\n",argv[i],MEDIASTREAM_MAX_ICE_CANDIDATES);
397 				continue;
398 			}
399 			candidate=&out->ice_local_candidates[out->ice_local_candidates_nb];
400 			if (!parse_ice_addr(argv[i],candidate->type,sizeof(candidate->type),candidate->ip,sizeof(candidate->ip),&candidate->port)) {
401 				ms_error("Failed to parse ICE local candidates '%s'\n", argv[i]);
402 				return FALSE;
403 			}
404 			out->ice_local_candidates_nb++;
405 			ms_message("ICE local candidate: type=%s ip=%s port=%i\n",candidate->type,candidate->ip,candidate->port);
406 		}else if (strcmp(argv[i],"--ice-remote-candidate")==0) {
407 			MediastreamIceCandidate *candidate;
408 			i++;
409 			if (out->ice_remote_candidates_nb>=MEDIASTREAM_MAX_ICE_CANDIDATES) {
410 				ms_warning("Ignore ICE remote candidate \"%s\" (maximum %d candidates allowed)\n",argv[i],MEDIASTREAM_MAX_ICE_CANDIDATES);
411 				continue;
412 			}
413 			candidate=&out->ice_remote_candidates[out->ice_remote_candidates_nb];
414 			if (!parse_ice_addr(argv[i],candidate->type,sizeof(candidate->type),candidate->ip,sizeof(candidate->ip),&candidate->port)) {
415 				ms_error("Failed to parse ICE remote candidates '%s'\n", argv[i]);
416 				return FALSE;
417 			}
418 			out->ice_remote_candidates_nb++;
419 			ms_message("ICE remote candidate: type=%s ip=%s port=%i\n",candidate->type,candidate->ip,candidate->port);
420 		}else if (strcmp(argv[i],"--payload")==0){
421 			i++;
422 			if (isdigit(argv[i][0])){
423 				out->payload=atoi(argv[i]);
424 			}else {
425 				out->payload=114;
426 				out->custom_pt=ms_tools_parse_custom_payload(argv[i]);
427 			}
428 		}else if (strcmp(argv[i],"--fmtp")==0){
429 			i++;
430 			out->send_fmtp=argv[i];
431 		}else if (strcmp(argv[i],"--recv_fmtp")==0){
432 			i++;
433 			out->recv_fmtp=argv[i];
434 		}else if (strcmp(argv[i],"--jitter")==0){
435 			i++;
436 			out->jitter=atoi(argv[i]);
437 		}else if (strcmp(argv[i],"--bitrate")==0){
438 			i++;
439 			out->bitrate=atoi(argv[i]);
440 		}else if (strcmp(argv[i],"--width")==0){
441 			i++;
442 			out->vs.width=atoi(argv[i]);
443 		}else if (strcmp(argv[i],"--height")==0){
444 			i++;
445 			out->vs.height=atoi(argv[i]);
446 		}else if (strcmp(argv[i],"--capture-card")==0){
447 			i++;
448 			out->capture_card=argv[i];
449 		}else if (strcmp(argv[i],"--playback-card")==0){
450 			i++;
451 			out->playback_card=argv[i];
452 		}else if (strcmp(argv[i],"--ec")==0){
453 			out->ec=TRUE;
454 		}else if (strcmp(argv[i],"--ec-tail")==0){
455 			i++;
456 			out->ec_len_ms=atoi(argv[i]);
457 		}else if (strcmp(argv[i],"--ec-delay")==0){
458 			i++;
459 			out->ec_delay_ms=atoi(argv[i]);
460 		}else if (strcmp(argv[i],"--ec-framesize")==0){
461 			i++;
462 			out->ec_framesize=atoi(argv[i]);
463 		}else if (strcmp(argv[i],"--agc")==0){
464 			out->agc=TRUE;
465 		}else if (strcmp(argv[i],"--eq")==0){
466 			out->eq=TRUE;
467 		}else if (strcmp(argv[i],"--ng")==0){
468 			out->use_ng=1;
469 		}else if (strcmp(argv[i],"--rc")==0){
470 			i++;
471 			out->rc_algo = parse_rc_algo(argv[i]);
472 			if (out->rc_algo == RCAlgoInvalid){
473 				ms_error("Invalid argument for --rc");
474 				return FALSE;
475 			}
476 		}else if (strcmp(argv[i],"--ng-threshold")==0){
477 			i++;
478 			out->ng_threshold=(float)atof(argv[i]);
479 		}else if (strcmp(argv[i],"--ng-floorgain")==0){
480 			i++;
481 			out->ng_floorgain=(float)atof(argv[i]);
482 		}else if (strcmp(argv[i],"--two-windows")==0){
483 			out->two_windows=TRUE;
484 		}else if (strcmp(argv[i],"--infile")==0){
485 			i++;
486 			out->infile=argv[i];
487 		}else if (strcmp(argv[i],"--outfile")==0){
488 			i++;
489 			out->outfile=argv[i];
490 		}else if (strcmp(argv[i],"--camera")==0){
491 			i++;
492 			out->camera=argv[i];
493 		}else if (strcmp(argv[i],"--el")==0){
494 			out->el=TRUE;
495 		}else if (strcmp(argv[i],"--el-speed")==0){
496 			i++;
497 			out->el_speed=(float)atof(argv[i]);
498 		}else if (strcmp(argv[i],"--el-thres")==0){
499 			i++;
500 			out->el_thres=(float)atof(argv[i]);
501 		}else if (strcmp(argv[i],"--el-force")==0){
502 			i++;
503 			out->el_force=(float)atof(argv[i]);
504 		}else if (strcmp(argv[i],"--el-sustain")==0){
505 			i++;
506 			out->el_sustain=atoi(argv[i]);
507 		}else if (strcmp(argv[i],"--el-transmit-thres")==0){
508 			i++;
509 			out->el_transmit_thres=(float)atof(argv[i]);
510 		} else if (strcmp(argv[i],"--zrtp")==0){
511 			out->enable_zrtp = TRUE;
512 		} else if (strcmp(argv[i],"--verbose")==0){
513 			out->is_verbose=TRUE;
514 		} else if (strcmp(argv[i], "--video-windows-id")==0) {
515 			i++;
516 			if (!parse_window_ids(argv[i],&out->video_window_id, &out->preview_window_id)) {
517 				ms_error("Failed to parse window ids '%s'\n",argv[i]);
518 				return FALSE;
519 			}
520 		} else if (strcmp(argv[i], "--device-rotation")==0) {
521 			i++;
522 			out->device_rotation=atoi(argv[i]);
523 		} else if (strcmp(argv[i], "--srtp")==0) {
524 			if (!ms_srtp_supported()) {
525 				ms_error("srtp support not enabled");
526 				return FALSE;
527 			}
528 			out->enable_srtp = TRUE;
529 			i++;
530 			// check if we're being given keys
531 			if (i + 1 < argc) {
532 				out->srtp_local_master_key = argv[i++];
533 				out->srtp_remote_master_key = argv[i++];
534 			}
535 		} else if (strcmp(argv[i],"--netsim-bandwidth")==0){
536 			i++;
537 			if (i<argc){
538 				out->netsim.max_bandwidth=(float)atoi(argv[i]);
539 				out->netsim.enabled=TRUE;
540 			}else{
541 				ms_error("Missing argument for --netsim-bandwidth");
542 				return FALSE;
543 			}
544 		}else if (strcmp(argv[i],"--netsim-lossrate")==0){
545 			i++;
546 			if (i<argc){
547 				out->netsim.loss_rate=(float)atoi(argv[i]);
548 				if (out->netsim.loss_rate < 0 || out->netsim.loss_rate>100) {
549 					ms_error("Loss rate must be between 0 and 100.");
550 					return FALSE;
551 				}
552 				out->netsim.enabled=TRUE;
553 			}else{
554 				ms_error("Missing argument for --netsim-lossrate");
555 				return FALSE;
556 			}
557 		}else if (strcmp(argv[i],"--netsim-consecutive-loss-probability")==0){
558 			i++;
559 			if (i<argc){
560 				sscanf(argv[i],"%f",&out->netsim.consecutive_loss_probability);
561 				if (out->netsim.consecutive_loss_probability < 0 || out->netsim.consecutive_loss_probability>1) {
562 					ms_error("The consecutive loss probability must be between 0 and 1.");
563 					return FALSE;
564 				}
565 
566 				out->netsim.enabled=TRUE;
567 			}else{
568 				ms_error("Missing argument for --netsim-consecutive-loss-probability");
569 				return FALSE;
570 			}
571 		}else if (strcmp(argv[i], "--netsim-latency") == 0) {
572 			i++;
573 			if (i<argc){
574 				out->netsim.latency = atoi(argv[i]);
575 				out->netsim.enabled=TRUE;
576 			}else{
577 				ms_error("Missing argument for --netsim-latency");
578 				return FALSE;
579 			}
580 		}else if (strcmp(argv[i], "--netsim-jitter-burst-density") == 0) {
581 			i++;
582 			if (i<argc){
583 				sscanf(argv[i],"%f",&out->netsim.jitter_burst_density);
584 				if (out->netsim.jitter_burst_density<0 || out->netsim.jitter_burst_density>10){
585 					ms_error("The jitter burst density must be between 0 and 10");
586 					return FALSE;
587 				}
588 				out->netsim.enabled=TRUE;
589 			}else{
590 				ms_error("Missing argument for --netsim-jitter-burst-density");
591 				return FALSE;
592 			}
593 		}else if (strcmp(argv[i], "--netsim-jitter-strength") == 0) {
594 			i++;
595 			if (i<argc){
596 				sscanf(argv[i],"%f",&out->netsim.jitter_strength);
597 				if (out->netsim.jitter_strength<0 || out->netsim.jitter_strength>100){
598 					ms_error("The jitter strength must be between 0 and 100.");
599 					return FALSE;
600 				}
601 				out->netsim.enabled=TRUE;
602 			}else{
603 				ms_error("Missing argument for --netsim-jitter-strength");
604 				return FALSE;
605 			}
606 		}else if (strcmp(argv[i], "--netsim-mode") == 0) {
607 			i++;
608 			if (i<argc){
609 				if (strcmp(argv[i],"inbound")==0)
610 					out->netsim.mode=OrtpNetworkSimulatorInbound;
611 				else if (strcmp(argv[i],"outbound")==0){
612 					out->netsim.mode=OrtpNetworkSimulatorOutbound;
613 				}else{
614 					ms_error("Invalid value for --netsim-mode");
615 					return FALSE;
616 				}
617 				out->netsim.enabled=TRUE;
618 			}else{
619 				ms_error("Missing argument for --netsim-dir");
620 				return FALSE;
621 			}
622 		}else if (strcmp(argv[i],"--zoom")==0){
623 			i++;
624 			if (sscanf(argv[i], "%f,%f,%f", &out->zoom, &out->zoom_cx, &out->zoom_cy) != 3) {
625 				ms_error("Invalid zoom triplet");
626 				return FALSE;
627 			}
628 		} else if (strcmp(argv[i],"--mtu")==0){
629 			i++;
630 			if (sscanf(argv[i], "%i", &out->mtu) != 1) {
631 				ms_error("Invalid mtu value");
632 				return FALSE;
633 			}
634 		} else if (strcmp(argv[i],"--interactive")==0){
635 			out->interactive=TRUE;
636 		} else if (strcmp(argv[i], "--no-avpf") == 0) {
637 			out->enable_avpf = FALSE;
638 		} else if (strcmp(argv[i], "--no-rtcp") == 0) {
639 			out->enable_rtcp = FALSE;
640 		} else if (strcmp(argv[i],"--help")==0) {
641 			return FALSE;
642 		} else if (strcmp(argv[i],"--video-display-filter")==0) {
643 			i++;
644 			out->video_display_filter=argv[i];
645 		} else if (strcmp(argv[i], "--log") == 0) {
646 			i++;
647 			out->logfile = fopen(argv[i], "a+");
648 		} else if (strcmp(argv[i], "--freeze-on-error") == 0) {
649 			out->freeze_on_error=TRUE;
650 		} else if (strcmp(argv[i], "--speaker") == 0) {
651 			out->enable_speaker=TRUE;
652 		} else {
653 			ms_error("Unknown option '%s'\n", argv[i]);
654 			return FALSE;
655 		}
656 	}
657 	if (out->netsim.jitter_burst_density>0 && out->netsim.max_bandwidth==0){
658 		ms_error("Jitter probability settings requires --netsim-bandwidth to be set.");
659 		return FALSE;
660 	}
661 	return TRUE;
662 }
663 
664 
665 #ifdef VIDEO_ENABLED
video_stream_event_cb(void * user_pointer,const MSFilter * f,const unsigned int event_id,const void * args)666 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args) {
667 	MediastreamDatas *md = (MediastreamDatas *)user_pointer;
668 	switch (event_id) {
669 		case MS_VIDEO_DECODER_DECODING_ERRORS:
670 			ms_warning("Decoding error on videostream [%p]", md->video);
671 			break;
672 		case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
673 			ms_message("First video frame decoded successfully on videostream [%p]", md->video);
674 			break;
675 	}
676 }
677 #endif
678 
get_sound_card(MSSndCardManager * manager,const char * card_name)679 static MSSndCard *get_sound_card(MSSndCardManager *manager, const char* card_name) {
680 	MSSndCard *play = ms_snd_card_manager_get_card(manager,card_name);
681 	if (play == NULL) {
682 		const MSList *list = ms_snd_card_manager_get_list(manager);
683 		char * cards = ms_strdup("");
684 		while (list) {
685 			MSSndCard *card = (MSSndCard*)list->data;
686 			cards = ms_strcat_printf(cards, "- %s\n", ms_snd_card_get_string_id(card));
687 			list = list->next;
688 		}
689 		ms_fatal("Specified card '%s' but could not find it. Available cards are:\n%s", card_name, cards);
690 		ms_free(cards);
691 	}
692 	return play;
693 }
694 
setup_media_streams(MediastreamDatas * args)695 void setup_media_streams(MediastreamDatas* args) {
696 	/*create the rtp session */
697 #ifdef VIDEO_ENABLED
698 	MSWebCam *cam=NULL;
699 #endif
700 	MSFactory *factory;
701 	ortp_init();
702 	if (args->logfile)
703 		ortp_set_log_file(args->logfile);
704 
705 	if (args->is_verbose) {
706 		ortp_set_log_level_mask(ORTP_LOG_DOMAIN, ORTP_DEBUG|ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
707 	} else {
708 		ortp_set_log_level_mask(ORTP_LOG_DOMAIN, ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
709 	}
710 
711 	args->factory = factory = ms_factory_new_with_voip();
712 
713 #if TARGET_OS_IPHONE || defined(__ANDROID__)
714 #if TARGET_OS_IPHONE || (defined(HAVE_X264) && defined(VIDEO_ENABLED))
715 	libmsx264_init(); /*no plugin on IOS/Android */
716 #endif
717 #if TARGET_OS_IPHONE || (defined (HAVE_OPENH264) && defined (VIDEO_ENABLED))
718 	libmsopenh264_init(); /*no plugin on IOS/Android */
719 #endif
720 #if TARGET_OS_IPHONE || defined (HAVE_SILK)
721 	libmssilk_init(); /*no plugin on IOS/Android */
722 #endif
723 #if TARGET_OS_IPHONE || defined (HAVE_WEBRTC)
724 	libmswebrtc_init();
725 #endif
726 
727 #endif /* TARGET_OS_IPHONE || defined(__ANDROID__) */
728 
729 	rtp_profile_set_payload(&av_profile,110,&payload_type_speex_nb);
730 	rtp_profile_set_payload(&av_profile,111,&payload_type_speex_wb);
731 	rtp_profile_set_payload(&av_profile,112,&payload_type_ilbc);
732 	rtp_profile_set_payload(&av_profile,113,&payload_type_amr);
733 	rtp_profile_set_payload(&av_profile,114,args->custom_pt);
734 	rtp_profile_set_payload(&av_profile,115,&payload_type_lpc1015);
735 #ifdef VIDEO_ENABLED
736 	cam=ms_web_cam_new(ms_mire_webcam_desc_get());
737 	if (cam) ms_web_cam_manager_add_cam(ms_factory_get_web_cam_manager(factory), cam);
738 	cam=NULL;
739 
740 	rtp_profile_set_payload(&av_profile,26,&payload_type_jpeg);
741 	rtp_profile_set_payload(&av_profile,98,&payload_type_h263_1998);
742 	rtp_profile_set_payload(&av_profile,97,&payload_type_theora);
743 	rtp_profile_set_payload(&av_profile,99,&payload_type_mp4v);
744 	rtp_profile_set_payload(&av_profile,100,&payload_type_x_snow);
745 	rtp_profile_set_payload(&av_profile,102,&payload_type_h264);
746 	rtp_profile_set_payload(&av_profile,103,&payload_type_vp8);
747 
748 	args->video=NULL;
749 #endif
750 	args->profile=rtp_profile_clone_full(&av_profile);
751 	args->q=ortp_ev_queue_new();
752 
753 	if (args->rc_algo == RCAlgoAdvanced){
754 		args->bw_controller = ms_bandwidth_controller_new();
755 	}
756 
757 	if (args->mtu) ms_factory_set_mtu(factory, args->mtu);
758 	ms_factory_enable_statistics(factory, TRUE);
759 	ms_factory_reset_statistics(factory);
760 
761 	args->ice_session=ice_session_new();
762 	ice_session_set_remote_credentials(args->ice_session,"1234","1234567890abcdef123456");
763 	// ICE local credentials are assigned when creating the ICE session, but force them here to simplify testing
764 	ice_session_set_local_credentials(args->ice_session,"1234","1234567890abcdef123456");
765 	ice_dump_session(args->ice_session);
766 
767 	signal(SIGINT,stop_handler);
768 	args->pt=rtp_profile_get_payload(args->profile,args->payload);
769 	if (args->pt==NULL){
770 		ms_error("No payload defined with number %i.\n",args->payload);
771 		exit(-1);
772 	}
773 	if (args->enable_avpf == TRUE) {
774 		PayloadTypeAvpfParams avpf_params;
775 		payload_type_set_flag(args->pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
776 		avpf_params.features = PAYLOAD_TYPE_AVPF_FIR | PAYLOAD_TYPE_AVPF_PLI | PAYLOAD_TYPE_AVPF_SLI | PAYLOAD_TYPE_AVPF_RPSI;
777 		avpf_params.trr_interval = 3000;
778 		payload_type_set_avpf_params(args->pt, avpf_params);
779 	} else {
780 		payload_type_unset_flag(args->pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
781 	}
782 	if (args->send_fmtp!=NULL) payload_type_set_send_fmtp(args->pt,args->send_fmtp);
783 	if (args->recv_fmtp!=NULL) payload_type_set_recv_fmtp(args->pt,args->recv_fmtp);
784 	if (args->bitrate>0) args->pt->normal_bitrate=args->bitrate;
785 
786 	if (args->pt->normal_bitrate==0){
787 		ms_error("Default bitrate specified for codec %s/%i. "
788 			"Please specify a network bitrate with --bitrate option.\n",args->pt->mime_type,args->pt->clock_rate);
789 		exit(-1);
790 	}
791 
792 	// do we need to generate srtp keys ?
793 	if (args->enable_srtp) {
794 		// default profile require key-length = 30 bytes
795 		//  -> input : 40 b64 encoded bytes
796 		if (!args->srtp_local_master_key) {
797 			char tmp[30];
798 			snprintf(tmp,sizeof(tmp),"%08x%08x%08x%08x",rand(),rand(),rand(),rand());
799 			args->srtp_local_master_key = (char*) malloc(41);
800 			b64_encode((const char*)tmp, 30, args->srtp_local_master_key, 40);
801 			args->srtp_local_master_key[40] = '\0';
802 			ms_message("Generated local srtp key: '%s'", args->srtp_local_master_key);
803 		}
804 		if (!args->srtp_remote_master_key) {
805 			char tmp[30];
806 			snprintf(tmp,sizeof(tmp),"%08x%08x%08x%08x",rand(),rand(),rand(),rand());
807 			args->srtp_remote_master_key = (char*) malloc(41);
808 			b64_encode((const char*)tmp, 30, args->srtp_remote_master_key, 40);
809 			args->srtp_remote_master_key[40] = '\0';
810 			ms_message("Generated remote srtp key: '%s'", args->srtp_remote_master_key);
811 		}
812 	}
813 
814 	if (args->pt->type!=PAYLOAD_VIDEO){
815 		MSSndCardManager *manager=ms_factory_get_snd_card_manager(factory);
816 		MSSndCard *capt= args->capture_card==NULL ? ms_snd_card_manager_get_default_capture_card(manager) :
817 				get_sound_card(manager,args->capture_card);
818 		MSSndCard *play= args->playback_card==NULL ? ms_snd_card_manager_get_default_capture_card(manager) :
819 				get_sound_card(manager,args->playback_card);
820 		args->audio=audio_stream_new(factory, args->localport,args->localport+1,ms_is_ipv6(args->ip));
821 		if (args->bw_controller){
822 			ms_bandwidth_controller_add_stream(args->bw_controller, (MediaStream*)args->audio);
823 		}
824 		audio_stream_enable_automatic_gain_control(args->audio,args->agc);
825 		audio_stream_enable_noise_gate(args->audio,args->use_ng);
826 		audio_stream_set_echo_canceller_params(args->audio,args->ec_len_ms,args->ec_delay_ms,args->ec_framesize);
827 		audio_stream_enable_echo_limiter(args->audio,args->el);
828 		audio_stream_enable_adaptive_bitrate_control(args->audio,args->rc_algo == RCAlgoSimple);
829 		if (capt)
830 			ms_snd_card_set_preferred_sample_rate(capt,rtp_profile_get_payload(args->profile, args->payload)->clock_rate);
831 		if (play)
832 			ms_snd_card_set_preferred_sample_rate(play,rtp_profile_get_payload(args->profile, args->payload)->clock_rate);
833 		ms_message("Starting audio stream.\n");
834 
835 		audio_stream_start_full(args->audio,args->profile,args->ip,args->remoteport,args->ip,args->enable_rtcp?args->remoteport+1:-1, args->payload, args->jitter,args->infile,args->outfile,
836 								args->outfile==NULL ? play : NULL ,args->infile==NULL ? capt : NULL,args->infile!=NULL ? FALSE: args->ec);
837 
838 		if (args->ice_local_candidates_nb || args->ice_remote_candidates_nb) {
839 			args->audio->ms.ice_check_list = ice_check_list_new();
840 			rtp_session_set_pktinfo(args->audio->ms.sessions.rtp_session,TRUE);
841 			ice_session_add_check_list(args->ice_session, args->audio->ms.ice_check_list, 0);
842 		}
843 		if (args->ice_local_candidates_nb) {
844 			MediastreamIceCandidate *candidate;
845 			int c;
846 			for (c=0;c<args->ice_local_candidates_nb;c++){
847 				candidate=&args->ice_local_candidates[c];
848 				ice_add_local_candidate(args->audio->ms.ice_check_list,candidate->type,AF_INET,candidate->ip,candidate->port,1,NULL);
849 				ice_add_local_candidate(args->audio->ms.ice_check_list,candidate->type,AF_INET,candidate->ip,candidate->port+1,2,NULL);
850 			}
851 		}
852 		if (args->ice_remote_candidates_nb) {
853 			char foundation[4];
854 			MediastreamIceCandidate *candidate;
855 			int c;
856 			for (c=0;c<args->ice_remote_candidates_nb;c++){
857 				candidate=&args->ice_remote_candidates[c];
858 				memset(foundation, '\0', sizeof(foundation));
859 				snprintf(foundation, sizeof(foundation) - 1, "%u", c + 1);
860 				ice_add_remote_candidate(args->audio->ms.ice_check_list,candidate->type,AF_INET,candidate->ip,candidate->port,1,0,foundation,FALSE);
861 				ice_add_remote_candidate(args->audio->ms.ice_check_list,candidate->type,AF_INET,candidate->ip,candidate->port+1,2,0,foundation,FALSE);
862 			}
863 		}
864 
865 		if (args->audio) {
866 			if (args->el) {
867 				if (args->el_speed!=-1)
868 					ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_EA_SPEED,&args->el_speed);
869 				if (args->el_force!=-1)
870 					ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_EA_FORCE,&args->el_force);
871 				if (args->el_thres!=-1)
872 					ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_EA_THRESHOLD,&args->el_thres);
873 				if (args->el_sustain!=-1)
874 					ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_EA_SUSTAIN,&args->el_sustain);
875 				if (args->el_transmit_thres!=-1)
876 					ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&args->el_transmit_thres);
877 
878 			}
879 			if (args->use_ng){
880 				if (args->ng_threshold!=-1) {
881 					ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&args->ng_threshold);
882 					ms_filter_call_method(args->audio->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&args->ng_threshold);
883 				}
884 				if (args->ng_floorgain != -1) {
885 					ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&args->ng_floorgain);
886 					ms_filter_call_method(args->audio->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&args->ng_floorgain);
887 				}
888 			}
889 
890 			if (args->enable_zrtp) {
891 				MSZrtpParams params = {0};
892 				audio_stream_enable_zrtp(args->audio,&params);
893 			}
894 
895 
896 			args->session=args->audio->ms.sessions.rtp_session;
897 		}
898 
899 		if (args->enable_srtp) {
900 			ms_message("SRTP enabled: %d",
901 				audio_stream_enable_srtp(
902 					args->audio,
903 					MS_AES_128_SHA1_80,
904 					args->srtp_local_master_key,
905 					args->srtp_remote_master_key));
906 		}
907 	#if TARGET_OS_IPHONE
908 		if (args->enable_speaker) {
909 				ms_message("Setting audio route to spaker");
910 				UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
911 				if (AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride),&audioRouteOverride) != kAudioSessionNoError) {
912 					ms_error("Cannot set route to speaker");
913 				};
914 		}
915 	#endif
916 
917 
918 	}else{
919 #ifdef VIDEO_ENABLED
920 		float zoom[] = {
921 			args->zoom,
922 			args->zoom_cx, args->zoom_cy };
923 		MSMediaStreamIO iodef = MS_MEDIA_STREAM_IO_INITIALIZER;
924 
925 		if (args->eq){
926 			ms_fatal("Cannot put an audio equalizer in a video stream !");
927 			exit(-1);
928 		}
929 		ms_message("Starting video stream.\n");
930 		args->video=video_stream_new(factory, args->localport, args->localport+1, ms_is_ipv6(args->ip));
931 		if (args->bw_controller){
932 			ms_bandwidth_controller_add_stream(args->bw_controller, (MediaStream*)args->video);
933 		}
934 		if (args->video_display_filter)
935 			video_stream_set_display_filter_name(args->video, args->video_display_filter);
936 
937 #ifdef __ANDROID__
938 		if (args->device_rotation >= 0)
939 			video_stream_set_device_rotation(args->video, args->device_rotation);
940 #endif
941 		video_stream_set_sent_video_size(args->video,args->vs);
942 		video_stream_use_preview_video_window(args->video,args->two_windows);
943 #if TARGET_OS_IPHONE
944 		NSBundle* myBundle = [NSBundle mainBundle];
945 		const char*  nowebcam = [[myBundle pathForResource:@"nowebcamCIF"ofType:@"jpg"] cStringUsingEncoding:[NSString defaultCStringEncoding]];
946 		ms_static_image_set_default_image(nowebcam);
947 		NSUInteger cpucount = [[NSProcessInfo processInfo] processorCount];
948 		ms_factory_set_cpu_count(args->audio->ms.factory, cpucount);
949 		//ms_set_cpu_count(cpucount);
950 #endif
951 		video_stream_set_event_callback(args->video,video_stream_event_cb, args);
952 		video_stream_set_freeze_on_error(args->video,args->freeze_on_error);
953 		video_stream_enable_adaptive_bitrate_control(args->video, args->rc_algo == RCAlgoSimple);
954 		if (args->camera)
955 			cam=ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(factory),args->camera);
956 		if (cam==NULL)
957 			cam=ms_web_cam_manager_get_default_cam(ms_factory_get_web_cam_manager(factory));
958 
959 		if (args->infile){
960 			iodef.input.type = MSResourceFile;
961 			iodef.input.file = args->infile;
962 		}else{
963 			iodef.input.type = MSResourceCamera;
964 			iodef.input.camera = cam;
965 		}
966 		if (args->outfile){
967 			iodef.output.type = MSResourceFile;
968 			iodef.output.file = args->outfile;
969 		}else{
970 			iodef.output.type = MSResourceDefault;
971 			iodef.output.resource_arg = NULL;
972 		}
973 		rtp_session_set_jitter_compensation(args->video->ms.sessions.rtp_session, args->jitter);
974 		video_stream_start_from_io(args->video, args->profile,
975 					args->ip,args->remoteport,
976 					args->ip,args->enable_rtcp?args->remoteport+1:-1,
977 					args->payload,
978 					&iodef
979 					);
980 		args->session=args->video->ms.sessions.rtp_session;
981 
982 		ms_filter_call_method(args->video->output,MS_VIDEO_DISPLAY_ZOOM, zoom);
983 		if (args->enable_srtp) {
984 			ms_message("SRTP enabled: %d",
985 				video_stream_enable_strp(
986 					args->video,
987 					MS_AES_128_SHA1_80,
988 					args->srtp_local_master_key,
989 					args->srtp_remote_master_key));
990 		}
991 #else
992 		ms_error("Error: video support not compiled.\n");
993 #endif
994 	}
995 	ice_session_set_base_for_srflx_candidates(args->ice_session);
996 	ice_session_compute_candidates_foundations(args->ice_session);
997 	ice_session_choose_default_candidates(args->ice_session);
998 	ice_session_choose_default_remote_candidates(args->ice_session);
999 	ice_session_start_connectivity_checks(args->ice_session);
1000 
1001 	if (args->netsim.enabled){
1002 		rtp_session_enable_network_simulation(args->session,&args->netsim);
1003 	}
1004 }
1005 
1006 
mediastream_tool_iterate(MediastreamDatas * args)1007 static void mediastream_tool_iterate(MediastreamDatas* args) {
1008 #ifndef _WIN32
1009 	struct pollfd pfd;
1010 	int err;
1011 
1012 	if (args->interactive){
1013 		pfd.fd=STDIN_FILENO;
1014 		pfd.events=POLLIN;
1015 		pfd.revents=0;
1016 
1017 		err=poll(&pfd,1,10);
1018 		if (err==1 && (pfd.revents & POLLIN)){
1019 			char commands[128];
1020 			int intarg;
1021 			commands[127]='\0';
1022 			ms_sleep(1);  /* ensure following text be printed after ortp messages */
1023 			if (args->eq)
1024 			ms_message("\nPlease enter equalizer requests, such as 'eq active 1', 'eq active 0', 'eq 1200 0.1 200'\n");
1025 
1026 			if (fgets(commands,sizeof(commands)-1,stdin)!=NULL){
1027 				MSEqualizerGain d = {0};
1028 				int active;
1029 				if (sscanf(commands,"eq active %i",&active)==1){
1030 					audio_stream_enable_equalizer(args->audio, args->audio->eq_loc, active);
1031 					ms_message("OK\n");
1032 				}else if (sscanf(commands,"eq %f %f %f",&d.frequency,&d.gain,&d.width)==3){
1033 					audio_stream_equalizer_set_gain(args->audio, args->audio->eq_loc, &d);
1034 					ms_message("OK\n");
1035 				}else if (sscanf(commands,"eq %f %f",&d.frequency,&d.gain)==2){
1036 					audio_stream_equalizer_set_gain(args->audio, args->audio->eq_loc, &d);
1037 					ms_message("OK\n");
1038 				}else if (strstr(commands,"dump")){
1039 					int n=0,i;
1040 					float *t;
1041 					MSFilter *equalizer = NULL;
1042 					if(args->audio->eq_loc == MSEqualizerHP) {
1043 						equalizer = args->audio->spk_equalizer;
1044 					} else if(args->audio->eq_loc == MSEqualizerMic) {
1045 						equalizer = args->audio->mic_equalizer;
1046 					}
1047 					if(equalizer) {
1048 						ms_filter_call_method(equalizer,MS_EQUALIZER_GET_NUM_FREQUENCIES,&n);
1049 						t=(float*)alloca(sizeof(float)*n);
1050 						ms_filter_call_method(equalizer,MS_EQUALIZER_DUMP_STATE,t);
1051 						for(i=0;i<n;++i){
1052 							if (fabs(t[i]-1)>0.01){
1053 							ms_message("%i:%f:0 ",(i*args->pt->clock_rate)/(2*n),t[i]);
1054 							}
1055 						}
1056 					}
1057 					ms_message("\nOK\n");
1058 				}else if (sscanf(commands,"lossrate %i",&intarg)==1){
1059 					args->netsim.enabled=TRUE;
1060 					args->netsim.loss_rate=intarg;
1061 					rtp_session_enable_network_simulation(args->session,&args->netsim);
1062 				}else if (sscanf(commands,"bandwidth %i",&intarg)==1){
1063 					args->netsim.enabled=TRUE;
1064 					args->netsim.max_bandwidth=intarg;
1065 					rtp_session_enable_network_simulation(args->session,&args->netsim);
1066 				}else if (strstr(commands,"quit")){
1067 					cond=0;
1068 				}else ms_warning("Cannot understand this.\n");
1069 			}
1070 		}else if (err==-1 && errno!=EINTR){
1071 			ms_fatal("mediastream's poll() returned %s",strerror(errno));
1072 		}
1073 	}else{
1074 		ms_usleep(10000);
1075 	}
1076 #else
1077 	MSG msg;
1078 	Sleep(10);
1079 	while (PeekMessage(&msg, NULL, 0, 0,1)){
1080 		TranslateMessage(&msg);
1081 		DispatchMessage(&msg);
1082 	}
1083 	/*no interactive mode on windows*/
1084 #endif
1085 }
1086 
mediastream_run_loop(MediastreamDatas * args)1087 void mediastream_run_loop(MediastreamDatas* args) {
1088 	rtp_session_register_event_queue(args->session,args->q);
1089 
1090 #if TARGET_OS_IPHONE
1091 	if (args->video) ms_set_video_stream(args->video); /*for IOS*/
1092 #endif
1093 
1094 	while(cond)
1095 	{
1096 		int n;
1097 		for(n=0;n<500 && cond;++n){
1098 			mediastream_tool_iterate(args);
1099 #if defined(VIDEO_ENABLED)
1100 			if (args->video) video_stream_iterate(args->video);
1101 #endif
1102 			if (args->audio) audio_stream_iterate(args->audio);
1103 		}
1104 		rtp_stats_display(rtp_session_get_stats(args->session),"RTP stats");
1105 		if (args->session){
1106 			float audio_load = 0;
1107 			float video_load = 0;
1108 
1109 			ms_message("Bandwidth usage: download=%f kbits/sec, upload=%f kbits/sec\n",
1110 				rtp_session_get_recv_bandwidth(args->session)*1e-3,
1111 				rtp_session_get_send_bandwidth(args->session)*1e-3);
1112 
1113 			if (args->audio) {
1114 				audio_load = ms_ticker_get_average_load(args->audio->ms.sessions.ticker);
1115 			}
1116 #if defined(VIDEO_ENABLED)
1117 			if (args->video) {
1118 				video_load = ms_ticker_get_average_load(args->video->ms.sessions.ticker);
1119 			}
1120 #endif
1121 			ms_message("Thread processing load: audio=%f\tvideo=%f", audio_load, video_load);
1122 			parse_events(args->session,args->q);
1123 			ms_message("Quality indicator : %f\n",args->audio ? audio_stream_get_quality_rating(args->audio) : media_stream_get_quality_rating((MediaStream*)args->video));
1124 		}
1125 	}
1126 }
1127 
clear_mediastreams(MediastreamDatas * args)1128 void clear_mediastreams(MediastreamDatas* args) {
1129 	ms_message("stopping all...\n");
1130 	ms_message("Average quality indicator: %f",args->audio ? audio_stream_get_average_quality_rating(args->audio) : -1);
1131 
1132 	if (args->bw_controller){
1133 		ms_bandwidth_controller_destroy(args->bw_controller);
1134 	}
1135 
1136 	if (args->audio) {
1137 		audio_stream_stop(args->audio);
1138 	}
1139 #ifdef VIDEO_ENABLED
1140 	if (args->video) {
1141 		if (args->video->ms.ice_check_list) ice_check_list_destroy(args->video->ms.ice_check_list);
1142 		video_stream_stop(args->video);
1143 		ms_factory_log_statistics(args->video->ms.factory);
1144 	}
1145 #endif
1146 	if (args->ice_session) ice_session_destroy(args->ice_session);
1147 	ortp_ev_queue_destroy(args->q);
1148 	rtp_profile_destroy(args->profile);
1149 
1150 	if (args->logfile)
1151 		fclose(args->logfile);
1152 
1153 	ms_factory_destroy(args->factory);
1154 }
1155 
1156 // ANDROID JNI WRAPPER
1157 #ifdef __ANDROID__
JNI_OnLoad(JavaVM * ajvm,void * reserved)1158 JNIEXPORT jint JNICALL  JNI_OnLoad(JavaVM *ajvm, void *reserved)
1159 {
1160 	ms_set_jvm(ajvm);
1161 
1162 	return JNI_VERSION_1_2;
1163 }
1164 
Java_org_linphone_mediastream_MediastreamerActivity_setVideoWindowId(JNIEnv * env,jobject obj,jobject id,jint _args)1165 JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_setVideoWindowId
1166   (JNIEnv *env, jobject obj, jobject id, jint _args) {
1167 #ifdef VIDEO_ENABLED
1168 	MediastreamDatas* args =  (MediastreamDatas*)_args;
1169 	if (!args->video)
1170 		return;
1171 	video_stream_set_native_window_id(args->video,id);
1172 #endif
1173 }
1174 
Java_org_linphone_mediastream_MediastreamerActivity_setVideoPreviewWindowId(JNIEnv * env,jobject obj,jobject id,jint _args)1175 JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_setVideoPreviewWindowId
1176   (JNIEnv *env, jobject obj, jobject id, jint _args) {
1177 #ifdef VIDEO_ENABLED
1178 	MediastreamDatas* args =  (MediastreamDatas*)_args;
1179 	if (!args->video)
1180 		return;
1181 	video_stream_set_native_preview_window_id(args->video,id);
1182 #endif
1183 }
1184 
Java_org_linphone_mediastream_MediastreamerActivity_setDeviceRotation(JNIEnv * env,jobject thiz,jint rotation,jint _args)1185 JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_setDeviceRotation
1186   (JNIEnv *env, jobject thiz, jint rotation, jint _args) {
1187 #ifdef VIDEO_ENABLED
1188 	MediastreamDatas* args =  (MediastreamDatas*)_args;
1189 	if (!args->video)
1190 		return;
1191 	video_stream_set_device_rotation(args->video, rotation);
1192 #endif
1193 }
1194 
Java_org_linphone_mediastream_MediastreamerActivity_changeCamera(JNIEnv * env,jobject obj,jint camId,jint _args)1195 JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_changeCamera
1196   (JNIEnv *env, jobject obj, jint camId, jint _args) {
1197 #ifdef VIDEO_ENABLED
1198 	MediastreamDatas* args =  (MediastreamDatas*)_args;
1199 	if (!args->video)
1200 		return;
1201 	char* id = (char*)malloc(15);
1202 	snprintf(id, 15, "Android%d", camId);
1203 	ms_message("Changing camera, trying to use: '%s'\n", id);
1204 	video_stream_change_camera(args->video, ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(args->video->ms.factory), id));
1205 #endif
1206 }
1207 
Java_org_linphone_mediastream_MediastreamerActivity_stopMediaStream(JNIEnv * env,jobject obj)1208 JNIEXPORT jint JNICALL Java_org_linphone_mediastream_MediastreamerActivity_stopMediaStream
1209   (JNIEnv *env, jobject obj) {
1210 	ms_message("Requesting mediastream to stop\n");
1211 	stop_handler(0);
1212 	return 0;
1213 }
1214 
Java_org_linphone_mediastream_MediastreamerActivity_initDefaultArgs(JNIEnv * env,jobject obj)1215 JNIEXPORT jint JNICALL Java_org_linphone_mediastream_MediastreamerActivity_initDefaultArgs
1216   (JNIEnv *env, jobject obj) {
1217 	cond = 1;
1218 	return (unsigned int)init_default_args();
1219 }
1220 
Java_org_linphone_mediastream_MediastreamerActivity_parseArgs(JNIEnv * env,jobject obj,jint jargc,jobjectArray jargv,jint args)1221 JNIEXPORT jboolean JNICALL Java_org_linphone_mediastream_MediastreamerActivity_parseArgs
1222   (JNIEnv *env, jobject obj, jint jargc, jobjectArray jargv, jint args) {
1223 	// translate java String[] to c char*[]
1224 	char** argv = (char**) malloc(jargc * sizeof(char*));
1225 	int i;
1226 
1227 	for(i=0; i<jargc; i++) {
1228 		jstring arg = (jstring) (*env)->GetObjectArrayElement(env, jargv, i);
1229 		const char *str = (*env)->GetStringUTFChars(env, arg, NULL);
1230 		if (str == NULL)
1231 			argv[i] = NULL;
1232 		else {
1233 			argv[i] = strdup(str);
1234 			(*env)->ReleaseStringUTFChars(env, arg, str);
1235 		}
1236 	}
1237 
1238 	bool_t result = parse_args(jargc, argv, (MediastreamDatas*)args);
1239 
1240 	for(i=0; i<jargc; i++) {
1241 		if (argv[i])
1242 			free(argv[i]);
1243 	}
1244 	return result;
1245 }
1246 
Java_org_linphone_mediastream_MediastreamerActivity_setupMediaStreams(JNIEnv * env,jobject obj,jint args)1247 JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_setupMediaStreams
1248   (JNIEnv *env, jobject obj, jint args) {
1249 	setup_media_streams((MediastreamDatas*)args);
1250 }
1251 
Java_org_linphone_mediastream_MediastreamerActivity_runLoop(JNIEnv * env,jobject obj,jint args)1252 JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_runLoop
1253   (JNIEnv *env, jobject obj, jint args) {
1254 	mediastream_run_loop((MediastreamDatas*)args);
1255 }
1256 
Java_org_linphone_mediastream_MediastreamerActivity_clear(JNIEnv * env,jobject obj,jint args)1257 JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_clear
1258   (JNIEnv *env, jobject obj, jint args) {
1259 	clear_mediastreams((MediastreamDatas*)args);
1260 	free((MediastreamDatas*)args);
1261 }
1262 #endif
1263 
1264 // HELPER METHODS
stop_handler(int signum)1265 void stop_handler(int signum)
1266 {
1267 	cond--;
1268 	if (cond<0) {
1269 		ms_error("Brutal exit (%d)\n", cond);
1270 		exit(-1);
1271 	}
1272 }
1273 
parse_addr(const char * addr,char * ip,size_t len,int * port)1274 static bool_t parse_addr(const char *addr, char *ip, size_t len, int *port)
1275 {
1276 	const char *semicolon=NULL;
1277 	size_t iplen;
1278 	int slen;
1279 	const char *p;
1280 
1281 	*port=0;
1282 
1283 	for (p=addr+strlen(addr)-1;p>addr;p--){
1284 		if (*p==':') {
1285 			semicolon=p;
1286 			break;
1287 		}
1288 	}
1289 	/*if no semicolon is present, we can assume that user provided only port*/
1290 	if (semicolon==NULL) {
1291 		const char *localhost = "127.0.0.1";
1292 		char * end;
1293 		*port = strtol(addr, &end, 10);
1294 		if (*end != '\0' || end == addr) {
1295 			return FALSE;
1296 		}
1297 		strncpy(ip,localhost, MIN(len, strlen(localhost)));
1298 		return TRUE;
1299 	}
1300 	iplen=semicolon-addr;
1301 	slen=MIN(iplen,len-1);
1302 	strncpy(ip,addr,slen);
1303 	ip[slen]='\0';
1304 	*port=atoi(semicolon+1);
1305 	return TRUE;
1306 }
1307 
parse_ice_addr(char * addr,char * type,size_t type_len,char * ip,size_t ip_len,int * port)1308 static bool_t parse_ice_addr(char *addr, char *type, size_t type_len, char *ip, size_t ip_len, int *port)
1309 {
1310 	char *semicolon=NULL;
1311 	size_t slen;
1312 
1313 	semicolon=strrchr(addr,':');
1314 	if (semicolon==NULL) return FALSE;
1315 	slen=MIN(strlen(semicolon+1),type_len);
1316 	strncpy(type,semicolon+1,slen);
1317 	type[slen]='\0';
1318 	*semicolon='\0';
1319 	return parse_addr(addr,ip,ip_len,port);
1320 }
1321 
display_items(void * user_data,uint32_t csrc,rtcp_sdes_type_t t,const char * content,uint8_t content_len)1322 static void display_items(void *user_data, uint32_t csrc, rtcp_sdes_type_t t, const char *content, uint8_t content_len){
1323 	char str[256];
1324 	int len=MIN(sizeof(str)-1,content_len);
1325 	strncpy(str,content,len);
1326 	str[len]='\0';
1327 	switch(t){
1328 		case RTCP_SDES_CNAME:
1329 			ms_message("Found CNAME=%s",str);
1330 		break;
1331 		case RTCP_SDES_TOOL:
1332 			ms_message("Found TOOL=%s",str);
1333 		break;
1334 		case RTCP_SDES_NOTE:
1335 			ms_message("Found NOTE=%s",str);
1336 		break;
1337 		default:
1338 			ms_message("Unhandled SDES item (%s)",str);
1339 	}
1340 }
1341 
parse_rtcp(mblk_t * m)1342 static void parse_rtcp(mblk_t *m){
1343 	do{
1344 		if (rtcp_is_RR(m)){
1345 			ms_message("Receiving RTCP RR");
1346 		}else if (rtcp_is_SR(m)){
1347 			ms_message("Receiving RTCP SR");
1348 		}else if (rtcp_is_SDES(m)){
1349 			ms_message("Receiving RTCP SDES");
1350 			rtcp_sdes_parse(m,display_items,NULL);
1351 		}else {
1352 			ms_message("Receiving unhandled RTCP message");
1353 		}
1354 	}while(rtcp_next_packet(m));
1355 }
1356 
parse_events(RtpSession * session,OrtpEvQueue * q)1357 static void parse_events(RtpSession *session, OrtpEvQueue *q){
1358 	OrtpEvent *ev;
1359 
1360 	while((ev=ortp_ev_queue_get(q))!=NULL){
1361 		OrtpEventData *d=ortp_event_get_data(ev);
1362 		switch(ortp_event_get_type(ev)){
1363 			case ORTP_EVENT_RTCP_PACKET_RECEIVED:
1364 				parse_rtcp(d->packet);
1365 			break;
1366 			case ORTP_EVENT_RTCP_PACKET_EMITTED:
1367 				ms_message("Jitter buffer size: %f ms",rtp_session_get_jitter_stats(session)->jitter_buffer_size_ms);
1368 			break;
1369 			default:
1370 			break;
1371 		}
1372 		ortp_event_destroy(ev);
1373 	}
1374 }
1375 
parse_window_ids(const char * ids,int * video_id,int * preview_id)1376 static bool_t parse_window_ids(const char *ids, int* video_id, int* preview_id)
1377 {
1378 	char* copy = strdup(ids);
1379 	char *semicolon=strchr(copy,':');
1380 	if (semicolon==NULL) {
1381 		free(copy);
1382 		return FALSE;
1383 	}
1384 	*semicolon = '\0';
1385 
1386 	*video_id=atoi(copy);
1387 	*preview_id=atoi(semicolon+1);
1388 	free(copy);
1389 	return TRUE;
1390 }
1391 
parse_rc_algo(const char * algo)1392 static RcAlgo parse_rc_algo(const char *algo){
1393 	if (algo == NULL) return RCAlgoInvalid;
1394 	if (strcasecmp(algo,"simple")==0) return RCAlgoSimple;
1395 	if (strcasecmp(algo, "advanced")==0) return RCAlgoAdvanced;
1396 	if (strcasecmp(algo, "none")==0) return RCAlgoNone;
1397 	return RCAlgoInvalid;
1398 }
1399