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,¶ms);
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