PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/submodules/jliblinphone/submodules/linphone/mediastreamer2/tests/mediastream.c

https://bitbucket.org/secollab/linphone-blackberry-mikey-sakke
C | 1115 lines | 973 code | 105 blank | 37 comment | 154 complexity | 193bfb0a77c2386a27ddd69b4fe568d2 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0, GPL-3.0, LGPL-2.1
  1. /*
  2. mediastreamer2 library - modular sound and video processing and streaming
  3. Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. */
  16. #ifdef HAVE_CONFIG_H
  17. #include "mediastreamer-config.h"
  18. #endif
  19. #include <math.h>
  20. #include "mediastreamer2/mediastream.h"
  21. #include "mediastreamer2/msequalizer.h"
  22. #include "mediastreamer2/msvolume.h"
  23. #ifdef VIDEO_ENABLED
  24. #include "mediastreamer2/msv4l.h"
  25. #endif
  26. #include <ctype.h>
  27. #include <signal.h>
  28. #include <sys/types.h>
  29. #ifndef WIN32
  30. #include <unistd.h>
  31. #else
  32. #include <malloc.h>
  33. #endif
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #ifdef __APPLE__
  38. #include <CoreFoundation/CFRunLoop.h>
  39. #endif
  40. #if defined(__ios) || defined (ANDROID)
  41. #ifdef __ios
  42. #import <UIKit/UIKit.h>
  43. #include <AudioToolbox/AudioToolbox.h>
  44. #endif
  45. extern void ms_set_video_stream(VideoStream* video);
  46. #ifdef HAVE_X264
  47. extern void libmsx264_init();
  48. #endif
  49. #ifdef HAVE_SILK
  50. extern void libmssilk_init();
  51. #endif
  52. #endif
  53. #ifdef ANDROID
  54. #include <android/log.h>
  55. #include <jni.h>
  56. #endif
  57. #include <ortp/b64.h>
  58. #define MEDIASTREAM_MAX_ICE_CANDIDATES 3
  59. static int cond=1;
  60. typedef struct _MediastreamIceCandidate {
  61. char ip[64];
  62. char type[6];
  63. int port;
  64. } MediastreamIceCandidate;
  65. typedef struct _MediastreamDatas {
  66. int localport,remoteport,payload;
  67. char ip[64];
  68. char *fmtp;
  69. int jitter;
  70. int bitrate;
  71. MSVideoSize vs;
  72. bool_t ec;
  73. bool_t agc;
  74. bool_t eq;
  75. bool_t is_verbose;
  76. int device_rotation;
  77. #ifdef VIDEO_ENABLED
  78. VideoStream *video;
  79. #endif
  80. char * capture_card;
  81. char * playback_card;
  82. char * camera;
  83. char *infile,*outfile;
  84. float ng_threshold;
  85. bool_t use_ng;
  86. bool_t two_windows;
  87. bool_t el;
  88. bool_t use_rc;
  89. bool_t enable_srtp;
  90. bool_t pad[3];
  91. float el_speed;
  92. float el_thres;
  93. float el_force;
  94. int el_sustain;
  95. float el_transmit_thres;
  96. float ng_floorgain;
  97. char * zrtp_secrets;
  98. PayloadType *custom_pt;
  99. int video_window_id;
  100. int preview_window_id;
  101. /* starting values echo canceller */
  102. int ec_len_ms, ec_delay_ms, ec_framesize;
  103. char* srtp_local_master_key;
  104. char* srtp_remote_master_key;
  105. int netsim_bw;
  106. int netsim_lossrate;
  107. float zoom;
  108. float zoom_cx, zoom_cy;
  109. AudioStream *audio;
  110. PayloadType *pt;
  111. RtpSession *session;
  112. OrtpEvQueue *q;
  113. RtpProfile *profile;
  114. IceSession *ice_session;
  115. MediastreamIceCandidate ice_local_candidates[MEDIASTREAM_MAX_ICE_CANDIDATES];
  116. MediastreamIceCandidate ice_remote_candidates[MEDIASTREAM_MAX_ICE_CANDIDATES];
  117. int ice_local_candidates_nb;
  118. int ice_remote_candidates_nb;
  119. } MediastreamDatas;
  120. // MAIN METHODS
  121. /* init default arguments */
  122. MediastreamDatas* init_default_args();
  123. /* parse args */
  124. bool_t parse_args(int argc, char** argv, MediastreamDatas* out);
  125. /* setup streams */
  126. void setup_media_streams(MediastreamDatas* args);
  127. /* run loop */
  128. void run_interactive_loop(MediastreamDatas* args);
  129. void run_non_interactive_loop(MediastreamDatas* args);
  130. /* exit */
  131. void clear_mediastreams(MediastreamDatas* args);
  132. // HELPER METHODS
  133. static void stop_handler(int signum);
  134. static bool_t parse_addr(const char *addr, char *ip, int len, int *port);
  135. static bool_t parse_ice_addr(char* addr, char* type, int type_len, char* ip, int ip_len, int* port);
  136. static void display_items(void *user_data, uint32_t csrc, rtcp_sdes_type_t t, const char *content, uint8_t content_len);
  137. static void parse_rtcp(mblk_t *m);
  138. static void parse_events(RtpSession *session, OrtpEvQueue *q);
  139. static PayloadType* create_custom_payload_type(const char *type, const char *subtype, const char *rate, int number);
  140. static PayloadType* parse_custom_payload(const char *name);
  141. static bool_t parse_window_ids(const char *ids, int* video_id, int* preview_id);
  142. const char *usage="mediastream --local <port> --remote <ip:port> \n"
  143. "--payload <payload type number or payload name like 'audio/pmcu/8000'>\n"
  144. "[ --fmtp <fmtpline> ]\n"
  145. "[ --jitter <miliseconds> ]\n"
  146. "[ --width <pixels> ]\n"
  147. "[ --height <pixels> ]\n"
  148. "[ --bitrate <bits per seconds> ]\n"
  149. "[ --ec (enable echo canceller) ]\n"
  150. "[ --ec-tail <echo canceller tail length in ms> ]\n"
  151. "[ --ec-delay <echo canceller delay in ms> ]\n"
  152. "[ --ec-framesize <echo canceller framesize in samples> ]\n"
  153. "[ --agc (enable automatic gain control) ]\n"
  154. "[ --ng (enable noise gate)] \n"
  155. "[ --ng-threshold <(float) [0-1]> (noise gate threshold) ]\n"
  156. "[ --ng-floorgain <(float) [0-1]> (gain applied to the signal when its energy is below the threshold.) ]\n"
  157. "[ --capture-card <name> ]\n"
  158. "[ --playback-card <name> ]\n"
  159. "[ --infile <input wav file> specify a wav file to be used for input, instead of soundcard ]\n"
  160. "[ --outfile <output wav file> specify a wav file to write audio into, instead of soundcard ]\n"
  161. "[ --camera <camera id as listed at startup> ]\n"
  162. "[ --el (enable echo limiter) ]\n"
  163. "[ --el-speed <(float) [0-1]> (gain changes are smoothed with a coefficent) ]\n"
  164. "[ --el-thres <(float) [0-1]> (Threshold above which the system becomes active) ]\n"
  165. "[ --el-force <(float) [0-1]> (The proportional coefficient controlling the mic attenuation) ]\n"
  166. "[ --el-sustain <(int)> (Time in milliseconds for which the attenuation is kept unchanged after) ]\n"
  167. "[ --el-transmit-thres <(float) [0-1]> (TO BE DOCUMENTED) ]\n"
  168. "[ --rc (enable adaptive rate control) ]\n"
  169. "[ --zrtp <secrets file> (enable zrtp) ]\n"
  170. "[ --verbose (most verbose messages) ]\n"
  171. "[ --video-windows-id <video surface:preview surface>]\n"
  172. "[ --srtp <local master_key> <remote master_key> (enable srtp, master key is generated if absent from comand line)\n"
  173. "[ --netsim-bandwidth <bandwidth limit in bits/s> (simulates a network download bandwidth limit)\n"
  174. "[ --netsim-lossrate <0-100> (simulates a network lost rate)\n"
  175. "[ --zoom zoomfactor]\n"
  176. "[ --ice-local-candidate <ip:port:[host|srflx|prflx|relay]> ]\n"
  177. "[ --ice-remote-candidate <ip:port:[host|srflx|prflx|relay]> ]\n"
  178. ;
  179. #if TARGET_OS_IPHONE
  180. int g_argc;
  181. char** g_argv;
  182. static int _main(int argc, char * argv[]);
  183. static void* apple_main(void* data) {
  184. _main(g_argc,g_argv);
  185. return NULL;
  186. }
  187. int main(int argc, char * argv[]) {
  188. pthread_t main_thread;
  189. g_argc=argc;
  190. g_argv=argv;
  191. pthread_create(&main_thread,NULL,apple_main,NULL);
  192. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  193. int value = UIApplicationMain(0, nil, nil, nil);
  194. [pool release];
  195. return value;
  196. cond=0;
  197. pthread_join(main_thread,NULL);
  198. return 0;
  199. }
  200. static int _main(int argc, char * argv[])
  201. #endif
  202. #if !__APPLE__ && !ANDROID
  203. int main(int argc, char * argv[])
  204. #endif
  205. #if !ANDROID && !TARGET_OS_MAC || TARGET_OS_IPHONE
  206. {
  207. MediastreamDatas* args;
  208. cond = 1;
  209. args = init_default_args();
  210. if (!parse_args(argc, argv, args))
  211. return 0;
  212. setup_media_streams(args);
  213. if (args->eq)
  214. run_interactive_loop(args);
  215. else
  216. run_non_interactive_loop(args);
  217. clear_mediastreams(args);
  218. free(args);
  219. return 0;
  220. }
  221. #endif
  222. MediastreamDatas* init_default_args() {
  223. MediastreamDatas* args = (MediastreamDatas*)ms_malloc0(sizeof(MediastreamDatas));
  224. args->localport=0;
  225. args->remoteport=0;
  226. args->payload=0;
  227. memset(args->ip, 0, sizeof(args->ip));
  228. args->fmtp=NULL;
  229. args->jitter=50;
  230. args->bitrate=0;
  231. args->ec=FALSE;
  232. args->agc=FALSE;
  233. args->eq=FALSE;
  234. args->is_verbose=FALSE;
  235. args->device_rotation=-1;
  236. #ifdef VIDEO_ENABLED
  237. args->video=NULL;
  238. #endif
  239. args->capture_card=NULL;
  240. args->playback_card=NULL;
  241. args->camera=NULL;
  242. args->infile=args->outfile=NULL;
  243. args->ng_threshold=-1;
  244. args->use_ng=FALSE;
  245. args->two_windows=FALSE;
  246. args->el=FALSE;
  247. args->el_speed=-1;
  248. args->el_thres=-1;
  249. args->el_force=-1;
  250. args->el_sustain=-1;
  251. args->el_transmit_thres=-1;
  252. args->ng_floorgain=-1;
  253. args->use_rc=FALSE;
  254. args->zrtp_secrets=NULL;
  255. args->custom_pt=NULL;
  256. args->video_window_id = -1;
  257. args->preview_window_id = -1;
  258. /* starting values echo canceller */
  259. args->ec_len_ms=args->ec_delay_ms=args->ec_framesize=0;
  260. args->enable_srtp = FALSE;
  261. args->srtp_local_master_key = args->srtp_remote_master_key = NULL;
  262. args->zoom = 1.0;
  263. args->zoom_cx = args->zoom_cy = 0.5;
  264. args->audio = NULL;
  265. args->session = NULL;
  266. args->pt = NULL;
  267. args->q = NULL;
  268. args->profile = NULL;
  269. args->ice_session = NULL;
  270. memset(args->ice_local_candidates, 0, sizeof(args->ice_local_candidates));
  271. memset(args->ice_remote_candidates, 0, sizeof(args->ice_remote_candidates));
  272. args->ice_local_candidates_nb = args->ice_remote_candidates_nb = 0;
  273. return args;
  274. }
  275. bool_t parse_args(int argc, char** argv, MediastreamDatas* out) {
  276. int i;
  277. if (argc<4) {
  278. printf("%s",usage);
  279. return FALSE;
  280. }
  281. /* default size */
  282. out->vs.width=MS_VIDEO_SIZE_CIF_W;
  283. out->vs.height=MS_VIDEO_SIZE_CIF_H;
  284. for (i=1;i<argc;i++){
  285. if (strcmp(argv[i],"--local")==0){
  286. i++;
  287. out->localport=atoi(argv[i]);
  288. }else if (strcmp(argv[i],"--remote")==0){
  289. i++;
  290. if (!parse_addr(argv[i],out->ip,sizeof(out->ip),&out->remoteport)) {
  291. printf("%s",usage);
  292. return FALSE;
  293. }
  294. printf("Remote addr: ip=%s port=%i\n",out->ip,out->remoteport);
  295. }else if (strcmp(argv[i],"--ice-local-candidate")==0) {
  296. MediastreamIceCandidate *candidate;
  297. i++;
  298. if (out->ice_local_candidates_nb>=MEDIASTREAM_MAX_ICE_CANDIDATES) {
  299. printf("Ignore ICE local candidate \"%s\" (maximum %d candidates allowed)\n",argv[i],MEDIASTREAM_MAX_ICE_CANDIDATES);
  300. continue;
  301. }
  302. candidate=&out->ice_local_candidates[out->ice_local_candidates_nb];
  303. if (!parse_ice_addr(argv[i],candidate->type,sizeof(candidate->type),candidate->ip,sizeof(candidate->ip),&candidate->port)) {
  304. printf("%s",usage);
  305. return FALSE;
  306. }
  307. out->ice_local_candidates_nb++;
  308. printf("ICE local candidate: type=%s ip=%s port=%i\n",candidate->type,candidate->ip,candidate->port);
  309. }else if (strcmp(argv[i],"--ice-remote-candidate")==0) {
  310. MediastreamIceCandidate *candidate;
  311. i++;
  312. if (out->ice_remote_candidates_nb>=MEDIASTREAM_MAX_ICE_CANDIDATES) {
  313. printf("Ignore ICE remote candidate \"%s\" (maximum %d candidates allowed)\n",argv[i],MEDIASTREAM_MAX_ICE_CANDIDATES);
  314. continue;
  315. }
  316. candidate=&out->ice_remote_candidates[out->ice_remote_candidates_nb];
  317. if (!parse_ice_addr(argv[i],candidate->type,sizeof(candidate->type),candidate->ip,sizeof(candidate->ip),&candidate->port)) {
  318. printf("%s",usage);
  319. return FALSE;
  320. }
  321. out->ice_remote_candidates_nb++;
  322. printf("ICE remote candidate: type=%s ip=%s port=%i\n",candidate->type,candidate->ip,candidate->port);
  323. }else if (strcmp(argv[i],"--payload")==0){
  324. i++;
  325. if (isdigit(argv[i][0])){
  326. out->payload=atoi(argv[i]);
  327. }else {
  328. out->payload=114;
  329. out->custom_pt=parse_custom_payload(argv[i]);
  330. }
  331. }else if (strcmp(argv[i],"--fmtp")==0){
  332. i++;
  333. out->fmtp=argv[i];
  334. }else if (strcmp(argv[i],"--jitter")==0){
  335. i++;
  336. out->jitter=atoi(argv[i]);
  337. }else if (strcmp(argv[i],"--bitrate")==0){
  338. i++;
  339. out->bitrate=atoi(argv[i]);
  340. }else if (strcmp(argv[i],"--width")==0){
  341. i++;
  342. out->vs.width=atoi(argv[i]);
  343. }else if (strcmp(argv[i],"--height")==0){
  344. i++;
  345. out->vs.height=atoi(argv[i]);
  346. }else if (strcmp(argv[i],"--capture-card")==0){
  347. i++;
  348. out->capture_card=argv[i];
  349. }else if (strcmp(argv[i],"--playback-card")==0){
  350. i++;
  351. out->playback_card=argv[i];
  352. }else if (strcmp(argv[i],"--ec")==0){
  353. out->ec=TRUE;
  354. }else if (strcmp(argv[i],"--ec-tail")==0){
  355. i++;
  356. out->ec_len_ms=atoi(argv[i]);
  357. }else if (strcmp(argv[i],"--ec-delay")==0){
  358. i++;
  359. out->ec_delay_ms=atoi(argv[i]);
  360. }else if (strcmp(argv[i],"--ec-framesize")==0){
  361. i++;
  362. out->ec_framesize=atoi(argv[i]);
  363. }else if (strcmp(argv[i],"--agc")==0){
  364. out->agc=TRUE;
  365. }else if (strcmp(argv[i],"--eq")==0){
  366. out->eq=TRUE;
  367. }else if (strcmp(argv[i],"--ng")==0){
  368. out->use_ng=1;
  369. }else if (strcmp(argv[i],"--rc")==0){
  370. out->use_rc=1;
  371. }else if (strcmp(argv[i],"--ng-threshold")==0){
  372. i++;
  373. out->ng_threshold=atof(argv[i]);
  374. }else if (strcmp(argv[i],"--ng-floorgain")==0){
  375. i++;
  376. out->ng_floorgain=atof(argv[i]);
  377. }else if (strcmp(argv[i],"--two-windows")==0){
  378. out->two_windows=TRUE;
  379. }else if (strcmp(argv[i],"--infile")==0){
  380. i++;
  381. out->infile=argv[i];
  382. }else if (strcmp(argv[i],"--outfile")==0){
  383. i++;
  384. out->outfile=argv[i];
  385. }else if (strcmp(argv[i],"--camera")==0){
  386. i++;
  387. out->camera=argv[i];
  388. }else if (strcmp(argv[i],"--el")==0){
  389. out->el=TRUE;
  390. }else if (strcmp(argv[i],"--el-speed")==0){
  391. i++;
  392. out->el_speed=atof(argv[i]);
  393. }else if (strcmp(argv[i],"--el-thres")==0){
  394. i++;
  395. out->el_thres=atof(argv[i]);
  396. }else if (strcmp(argv[i],"--el-force")==0){
  397. i++;
  398. out->el_force=atof(argv[i]);
  399. }else if (strcmp(argv[i],"--el-sustain")==0){
  400. i++;
  401. out->el_sustain=atoi(argv[i]);
  402. }else if (strcmp(argv[i],"--el-transmit-thres")==0){
  403. i++;
  404. out->el_transmit_thres=atof(argv[i]);
  405. } else if (strcmp(argv[i],"--zrtp")==0){
  406. out->zrtp_secrets=argv[++i];
  407. } else if (strcmp(argv[i],"--verbose")==0){
  408. out->is_verbose=TRUE;
  409. } else if (strcmp(argv[i], "--video-windows-id")==0) {
  410. i++;
  411. if (!parse_window_ids(argv[i],&out->video_window_id, &out->preview_window_id)) {
  412. printf("%s",usage);
  413. return FALSE;
  414. }
  415. } else if (strcmp(argv[i], "--device-rotation")==0) {
  416. i++;
  417. out->device_rotation=atoi(argv[i]);
  418. } else if (strcmp(argv[i], "--srtp")==0) {
  419. if (!ortp_srtp_supported()) {
  420. ms_error("ortp srtp support not enabled");
  421. return FALSE;
  422. }
  423. out->enable_srtp = TRUE;
  424. i++;
  425. // check if we're being given keys
  426. if (i + 1 < argc) {
  427. out->srtp_local_master_key = argv[i++];
  428. out->srtp_remote_master_key = argv[i++];
  429. }
  430. } else if (strcmp(argv[i],"--netsim-bandwidth")==0){
  431. i++;
  432. out->netsim_bw=atoi(argv[i]);
  433. } else if (strcmp(argv[i],"--netsim-lossrate")==0){
  434. i++;
  435. out->netsim_lossrate=atoi(argv[i]);
  436. if(out->netsim_lossrate < 0) {
  437. ms_warning("%d < 0, wrong value for --lost-rate: set to 0", out->netsim_lossrate);
  438. out->netsim_lossrate=0;
  439. }
  440. if(out->netsim_lossrate > 100) {
  441. ms_warning("%d > 100, wrong value for --lost-rate: set to 100", out->netsim_lossrate);
  442. out->netsim_lossrate=100;
  443. }
  444. } else if (strcmp(argv[i],"--zoom")==0){
  445. i++;
  446. if (sscanf(argv[i], "%f,%f,%f", &out->zoom, &out->zoom_cx, &out->zoom_cy) != 3) {
  447. ms_error("Invalid zoom triplet");
  448. return FALSE;
  449. }
  450. } else if (strcmp(argv[i],"--help")==0){
  451. printf("%s",usage);
  452. return FALSE;
  453. }
  454. }
  455. return TRUE;
  456. }
  457. void setup_media_streams(MediastreamDatas* args) {
  458. /*create the rtp session */
  459. #ifdef VIDEO_ENABLED
  460. MSWebCam *cam=NULL;
  461. #endif
  462. ortp_init();
  463. if (args->is_verbose) {
  464. ortp_set_log_level_mask(ORTP_DEBUG|ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
  465. } else {
  466. ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
  467. }
  468. #if defined(__ios) || defined(ANDROID)
  469. #if defined (HAVE_X264) && defined (VIDEO_ENABLED)
  470. libmsx264_init(); /*no plugin on IOS*/
  471. #endif
  472. #if defined (HAVE_SILK)
  473. libmssilk_init(); /*no plugin on IOS*/
  474. #endif
  475. #endif
  476. rtp_profile_set_payload(&av_profile,110,&payload_type_speex_nb);
  477. rtp_profile_set_payload(&av_profile,111,&payload_type_speex_wb);
  478. rtp_profile_set_payload(&av_profile,112,&payload_type_ilbc);
  479. rtp_profile_set_payload(&av_profile,113,&payload_type_amr);
  480. rtp_profile_set_payload(&av_profile,114,args->custom_pt);
  481. rtp_profile_set_payload(&av_profile,115,&payload_type_lpc1015);
  482. #ifdef VIDEO_ENABLED
  483. #if defined (__ios) && defined (HAVE_X264)
  484. libmsx264_init(); /*no plugin on IOS*/
  485. #endif
  486. rtp_profile_set_payload(&av_profile,26,&payload_type_jpeg);
  487. rtp_profile_set_payload(&av_profile,98,&payload_type_h263_1998);
  488. rtp_profile_set_payload(&av_profile,97,&payload_type_theora);
  489. rtp_profile_set_payload(&av_profile,99,&payload_type_mp4v);
  490. rtp_profile_set_payload(&av_profile,100,&payload_type_x_snow);
  491. rtp_profile_set_payload(&av_profile,102,&payload_type_h264);
  492. rtp_profile_set_payload(&av_profile,103,&payload_type_vp8);
  493. args->video=NULL;
  494. #endif
  495. args->profile=rtp_profile_clone_full(&av_profile);
  496. args->q=ortp_ev_queue_new();
  497. ms_init();
  498. ms_filter_enable_statistics(TRUE);
  499. ms_filter_reset_statistics();
  500. args->ice_session=ice_session_new();
  501. ice_session_set_remote_credentials(args->ice_session,"1234","1234567890abcdef123456");
  502. // ICE local credentials are assigned when creating the ICE session, but force them here to simplify testing
  503. ice_session_set_local_credentials(args->ice_session,"1234","1234567890abcdef123456");
  504. ice_dump_session(args->ice_session);
  505. signal(SIGINT,stop_handler);
  506. args->pt=rtp_profile_get_payload(args->profile,args->payload);
  507. if (args->pt==NULL){
  508. printf("Error: no payload defined with number %i.",args->payload);
  509. exit(-1);
  510. }
  511. if (args->fmtp!=NULL) payload_type_set_send_fmtp(args->pt,args->fmtp);
  512. if (args->bitrate>0) args->pt->normal_bitrate=args->bitrate;
  513. // do we need to generate srtp keys ?
  514. if (args->enable_srtp) {
  515. // default profile require key-length = 30 bytes
  516. // -> input : 40 b64 encoded bytes
  517. if (!args->srtp_local_master_key) {
  518. uint8_t tmp[30];
  519. ortp_crypto_get_random(tmp, 30);
  520. args->srtp_local_master_key = (char*) malloc(41);
  521. b64_encode((const char*)tmp, 30, args->srtp_local_master_key, 40);
  522. args->srtp_local_master_key[40] = '\0';
  523. ms_message("Generated local srtp key: '%s'", args->srtp_local_master_key);
  524. }
  525. if (!args->srtp_remote_master_key) {
  526. uint8_t tmp[30];
  527. ortp_crypto_get_random(tmp, 30);
  528. args->srtp_remote_master_key = (char*) malloc(41);
  529. b64_encode((const char*)tmp, 30, args->srtp_remote_master_key, 40);
  530. args->srtp_remote_master_key[40] = '\0';
  531. ms_message("Generated remote srtp key: '%s'", args->srtp_remote_master_key);
  532. }
  533. }
  534. if (args->pt->type!=PAYLOAD_VIDEO){
  535. MSSndCardManager *manager=ms_snd_card_manager_get();
  536. MSSndCard *capt= args->capture_card==NULL ? ms_snd_card_manager_get_default_capture_card(manager) :
  537. ms_snd_card_manager_get_card(manager,args->capture_card);
  538. MSSndCard *play= args->playback_card==NULL ? ms_snd_card_manager_get_default_playback_card(manager) :
  539. ms_snd_card_manager_get_card(manager,args->playback_card);
  540. args->audio=audio_stream_new(args->localport,args->localport+1,ms_is_ipv6(args->ip));
  541. audio_stream_enable_automatic_gain_control(args->audio,args->agc);
  542. audio_stream_enable_noise_gate(args->audio,args->use_ng);
  543. audio_stream_set_echo_canceller_params(args->audio,args->ec_len_ms,args->ec_delay_ms,args->ec_framesize);
  544. audio_stream_enable_echo_limiter(args->audio,args->el);
  545. audio_stream_enable_adaptive_bitrate_control(args->audio,args->use_rc);
  546. printf("Starting audio stream.\n");
  547. audio_stream_start_full(args->audio,args->profile,args->ip,args->remoteport,args->ip,args->remoteport+1, args->payload, args->jitter,args->infile,args->outfile,
  548. args->outfile==NULL ? play : NULL ,args->infile==NULL ? capt : NULL,args->infile!=NULL ? FALSE: args->ec);
  549. if (args->ice_local_candidates_nb || args->ice_remote_candidates_nb) {
  550. args->audio->ice_check_list = ice_check_list_new();
  551. rtp_session_set_pktinfo(args->audio->session,TRUE);
  552. ice_session_add_check_list(args->ice_session, args->audio->ice_check_list);
  553. }
  554. if (args->ice_local_candidates_nb) {
  555. MediastreamIceCandidate *candidate;
  556. int c;
  557. for (c=0;c<args->ice_local_candidates_nb;c++){
  558. candidate=&args->ice_local_candidates[c];
  559. ice_add_local_candidate(args->audio->ice_check_list,candidate->type,candidate->ip,candidate->port,1,NULL);
  560. ice_add_local_candidate(args->audio->ice_check_list,candidate->type,candidate->ip,candidate->port+1,2,NULL);
  561. }
  562. }
  563. if (args->ice_remote_candidates_nb) {
  564. char foundation[4];
  565. MediastreamIceCandidate *candidate;
  566. int c;
  567. for (c=0;c<args->ice_remote_candidates_nb;c++){
  568. candidate=&args->ice_remote_candidates[c];
  569. memset(foundation, '\0', sizeof(foundation));
  570. snprintf(foundation, sizeof(foundation) - 1, "%u", c + 1);
  571. ice_add_remote_candidate(args->audio->ice_check_list,candidate->type,candidate->ip,candidate->port,1,0,foundation,FALSE);
  572. ice_add_remote_candidate(args->audio->ice_check_list,candidate->type,candidate->ip,candidate->port+1,2,0,foundation,FALSE);
  573. }
  574. }
  575. if (args->audio) {
  576. if (args->el) {
  577. if (args->el_speed!=-1)
  578. ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_EA_SPEED,&args->el_speed);
  579. if (args->el_force!=-1)
  580. ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_EA_FORCE,&args->el_force);
  581. if (args->el_thres!=-1)
  582. ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_EA_THRESHOLD,&args->el_thres);
  583. if (args->el_sustain!=-1)
  584. ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_EA_SUSTAIN,&args->el_sustain);
  585. if (args->el_transmit_thres!=-1)
  586. ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&args->el_transmit_thres);
  587. }
  588. if (args->use_ng){
  589. if (args->ng_threshold!=-1) {
  590. ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&args->ng_threshold);
  591. ms_filter_call_method(args->audio->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&args->ng_threshold);
  592. }
  593. if (args->ng_floorgain != -1) {
  594. ms_filter_call_method(args->audio->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&args->ng_floorgain);
  595. ms_filter_call_method(args->audio->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&args->ng_floorgain);
  596. }
  597. }
  598. #ifndef TARGET_OS_IPHONE
  599. if (args->zrtp_secrets != NULL) {
  600. OrtpZrtpParams params;
  601. params.zid_file=args->zrtp_secrets;
  602. audio_stream_enable_zrtp(args->audio,&params);
  603. }
  604. #endif
  605. args->session=args->audio->session;
  606. }
  607. if (args->enable_srtp) {
  608. ms_message("SRTP enabled: %d",
  609. audio_stream_enable_strp(
  610. args->audio,
  611. AES_128_SHA1_80,
  612. args->srtp_local_master_key,
  613. args->srtp_remote_master_key));
  614. }
  615. }else{
  616. #ifdef VIDEO_ENABLED
  617. if (args->eq){
  618. ms_fatal("Cannot put an audio equalizer in a video stream !");
  619. exit(-1);
  620. }
  621. ms_message("Starting video stream.\n");
  622. args->video=video_stream_new(args->localport, args->localport+1, ms_is_ipv6(args->ip));
  623. #ifdef ANDROID
  624. if (args->device_rotation >= 0)
  625. video_stream_set_device_rotation(args->video, args->device_rotation);
  626. #endif
  627. video_stream_set_sent_video_size(args->video,args->vs);
  628. video_stream_use_preview_video_window(args->video,args->two_windows);
  629. #ifdef __ios
  630. NSBundle* myBundle = [NSBundle mainBundle];
  631. const char* nowebcam = [[myBundle pathForResource:@"nowebcamCIF"ofType:@"jpg"] cStringUsingEncoding:[NSString defaultCStringEncoding]];
  632. ms_static_image_set_default_image(nowebcam);
  633. #endif
  634. video_stream_enable_adaptive_bitrate_control(args->video,args->use_rc);
  635. if (args->camera)
  636. cam=ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),args->camera);
  637. if (cam==NULL)
  638. cam=ms_web_cam_manager_get_default_cam(ms_web_cam_manager_get());
  639. video_stream_start(args->video,args->profile,
  640. args->ip,args->remoteport,
  641. args->ip,args->remoteport+1,
  642. args->payload,
  643. args->jitter,cam
  644. );
  645. args->session=args->video->session;
  646. float zoom[] = {
  647. args->zoom,
  648. args->zoom_cx, args->zoom_cy };
  649. ms_filter_call_method(args->video->output,MS_VIDEO_DISPLAY_ZOOM, zoom);
  650. if (args->enable_srtp) {
  651. ms_message("SRTP enabled: %d",
  652. video_stream_enable_strp(
  653. args->video,
  654. AES_128_SHA1_80,
  655. args->srtp_local_master_key,
  656. args->srtp_remote_master_key));
  657. }
  658. #else
  659. printf("Error: video support not compiled.\n");
  660. #endif
  661. }
  662. ice_session_set_base_for_srflx_candidates(args->ice_session);
  663. ice_session_compute_candidates_foundations(args->ice_session);
  664. ice_session_choose_default_candidates(args->ice_session);
  665. ice_session_choose_default_remote_candidates(args->ice_session);
  666. ice_session_start_connectivity_checks(args->ice_session);
  667. OrtpNetworkSimulatorParams params={0};
  668. if (args->netsim_bw>0){
  669. params.enabled=TRUE;
  670. params.max_bandwidth=args->netsim_bw;
  671. }
  672. if (args->netsim_lossrate>0){
  673. params.enabled=TRUE;
  674. params.loss_rate=args->netsim_lossrate;
  675. }
  676. if (params.enabled){
  677. rtp_session_enable_network_simulation(args->session,&params);
  678. }
  679. }
  680. void run_interactive_loop(MediastreamDatas* args) {
  681. char commands[128];
  682. commands[127]='\0';
  683. ms_sleep(1); /* ensure following text be printed after ortp messages */
  684. if (args->eq)
  685. printf("\nPlease enter equalizer requests, such as 'eq active 1', 'eq active 0', 'eq 1200 0.1 200'\n");
  686. while(fgets(commands,sizeof(commands)-1,stdin)!=NULL){
  687. int active,freq,freq_width;
  688. float gain;
  689. if (sscanf(commands,"eq active %i",&active)==1){
  690. audio_stream_enable_equalizer(args->audio,active);
  691. printf("OK\n");
  692. }else if (sscanf(commands,"eq %i %f %i",&freq,&gain,&freq_width)==3){
  693. audio_stream_equalizer_set_gain(args->audio,freq,gain,freq_width);
  694. printf("OK\n");
  695. }else if (sscanf(commands,"eq %i %f",&freq,&gain)==2){
  696. audio_stream_equalizer_set_gain(args->audio,freq,gain,0);
  697. printf("OK\n");
  698. }else if (strstr(commands,"dump")){
  699. int n=0,i;
  700. float *t;
  701. ms_filter_call_method(args->audio->equalizer,MS_EQUALIZER_GET_NUM_FREQUENCIES,&n);
  702. t=(float*)alloca(sizeof(float)*n);
  703. ms_filter_call_method(args->audio->equalizer,MS_EQUALIZER_DUMP_STATE,t);
  704. for(i=0;i<n;++i){
  705. if (fabs(t[i]-1)>0.01){
  706. printf("%i:%f:0 ",(i*args->pt->clock_rate)/(2*n),t[i]);
  707. }
  708. }
  709. printf("\nOK\n");
  710. } else if (strstr(commands,"quit")){
  711. break;
  712. }else printf("Cannot understand this.\n");
  713. }
  714. }
  715. void run_non_interactive_loop(MediastreamDatas* args) {
  716. rtp_session_register_event_queue(args->session,args->q);
  717. #ifdef __ios
  718. if (args->video) ms_set_video_stream(args->video); /*for IOS*/
  719. #endif
  720. while(cond)
  721. {
  722. int n;
  723. for(n=0;n<100;++n){
  724. #ifdef WIN32
  725. MSG msg;
  726. Sleep(10);
  727. while (PeekMessage(&msg, NULL, 0, 0,1)){
  728. TranslateMessage(&msg);
  729. DispatchMessage(&msg);
  730. }
  731. #else
  732. struct timespec ts;
  733. ts.tv_sec=0;
  734. ts.tv_nsec=10000000;
  735. nanosleep(&ts,NULL);
  736. #endif
  737. #if defined(VIDEO_ENABLED)
  738. if (args->video) video_stream_iterate(args->video);
  739. #endif
  740. if (args->audio) audio_stream_iterate(args->audio);
  741. }
  742. rtp_stats_display(rtp_session_get_stats(args->session),"RTP stats");
  743. if (args->session){
  744. ms_message("Bandwidth usage: download=%f kbits/sec, upload=%f kbits/sec\n",
  745. rtp_session_compute_recv_bandwidth(args->session)*1e-3,
  746. rtp_session_compute_send_bandwidth(args->session)*1e-3);
  747. parse_events(args->session,args->q);
  748. ms_message("Quality indicator : %f\n",args->audio ? audio_stream_get_quality_rating(args->audio) : -1);
  749. }
  750. }
  751. }
  752. void clear_mediastreams(MediastreamDatas* args) {
  753. ms_message("stopping all...\n");
  754. ms_message("Average quality indicator: %f",args->audio ? audio_stream_get_average_quality_rating(args->audio) : -1);
  755. if (args->audio) {
  756. audio_stream_stop(args->audio);
  757. }
  758. #ifdef VIDEO_ENABLED
  759. if (args->video) {
  760. if (args->video->ice_check_list) ice_check_list_destroy(args->video->ice_check_list);
  761. video_stream_stop(args->video);
  762. ms_filter_log_statistics();
  763. }
  764. #endif
  765. if (args->ice_session) ice_session_destroy(args->ice_session);
  766. ortp_ev_queue_destroy(args->q);
  767. rtp_profile_destroy(args->profile);
  768. ms_exit();
  769. }
  770. // ANDROID JNI WRAPPER
  771. #ifdef ANDROID
  772. JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved)
  773. {
  774. ms_set_jvm(ajvm);
  775. return JNI_VERSION_1_2;
  776. }
  777. JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_setVideoWindowId
  778. (JNIEnv *env, jobject obj, jobject id, jint _args) {
  779. MediastreamDatas* args = (MediastreamDatas*)_args;
  780. #ifdef VIDEO_ENABLED
  781. if (!args->video)
  782. return;
  783. video_stream_set_native_window_id(args->video,(unsigned long)id);
  784. #endif
  785. }
  786. JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_setVideoPreviewWindowId
  787. (JNIEnv *env, jobject obj, jobject id, jint _args) {
  788. MediastreamDatas* args = (MediastreamDatas*)_args;
  789. #ifdef VIDEO_ENABLED
  790. if (!args->video)
  791. return;
  792. video_stream_set_native_preview_window_id(args->video,(unsigned long)id);
  793. #endif
  794. }
  795. JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_setDeviceRotation
  796. (JNIEnv *env, jobject thiz, jint rotation, jint _args) {
  797. MediastreamDatas* args = (MediastreamDatas*)_args;
  798. #ifdef VIDEO_ENABLED
  799. if (!args->video)
  800. return;
  801. video_stream_set_device_rotation(args->video, rotation);
  802. #endif
  803. }
  804. JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_changeCamera
  805. (JNIEnv *env, jobject obj, jint camId, jint _args) {
  806. MediastreamDatas* args = (MediastreamDatas*)_args;
  807. #ifdef VIDEO_ENABLED
  808. if (!args->video)
  809. return;
  810. char* id = (char*)malloc(15);
  811. snprintf(id, 15, "Android%d", camId);
  812. ms_message("Changing camera, trying to use: '%s'\n", id);
  813. video_stream_change_camera(args->video, ms_web_cam_manager_get_cam(ms_web_cam_manager_get(), id));
  814. #endif
  815. }
  816. JNIEXPORT jint JNICALL Java_org_linphone_mediastream_MediastreamerActivity_stopMediaStream
  817. (JNIEnv *env, jobject obj) {
  818. ms_message("Requesting mediastream to stop\n");
  819. stop_handler(0);
  820. return 0;
  821. }
  822. JNIEXPORT jint JNICALL Java_org_linphone_mediastream_MediastreamerActivity_initDefaultArgs
  823. (JNIEnv *env, jobject obj) {
  824. cond = 1;
  825. return (unsigned int)init_default_args();
  826. }
  827. JNIEXPORT jboolean JNICALL Java_org_linphone_mediastream_MediastreamerActivity_parseArgs
  828. (JNIEnv *env, jobject obj, jint jargc, jobjectArray jargv, jint args) {
  829. // translate java String[] to c char*[]
  830. char** argv = (char**) malloc(jargc * sizeof(char*));
  831. int i;
  832. for(i=0; i<jargc; i++) {
  833. jstring arg = (jstring) (*env)->GetObjectArrayElement(env, jargv, i);
  834. const char *str = (*env)->GetStringUTFChars(env, arg, NULL);
  835. if (str == NULL)
  836. argv[i] = NULL;
  837. else {
  838. argv[i] = strdup(str);
  839. (*env)->ReleaseStringUTFChars(env, arg, str);
  840. }
  841. }
  842. bool_t result = parse_args(jargc, argv, (MediastreamDatas*)args);
  843. for(i=0; i<jargc; i++) {
  844. if (argv[i])
  845. free(argv[i]);
  846. }
  847. return result;
  848. }
  849. JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_setupMediaStreams
  850. (JNIEnv *env, jobject obj, jint args) {
  851. setup_media_streams((MediastreamDatas*)args);
  852. }
  853. JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_runLoop
  854. (JNIEnv *env, jobject obj, jint args) {
  855. run_non_interactive_loop((MediastreamDatas*)args);
  856. }
  857. JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_clear
  858. (JNIEnv *env, jobject obj, jint args) {
  859. clear_mediastreams((MediastreamDatas*)args);
  860. free((MediastreamDatas*)args);
  861. }
  862. #endif
  863. // HELPER METHODS
  864. static void stop_handler(int signum)
  865. {
  866. cond--;
  867. if (cond<0) {
  868. ms_error("Brutal exit (%d)\n", cond);
  869. exit(-1);
  870. }
  871. }
  872. static bool_t parse_addr(const char *addr, char *ip, int len, int *port)
  873. {
  874. const char *semicolon=NULL;
  875. int iplen;
  876. int slen;
  877. const char *p;
  878. *port=0;
  879. semicolon=strchr(addr,':');
  880. for (p=addr+strlen(addr)-1;p>addr;p--){
  881. if (*p==':') {
  882. semicolon=p;
  883. break;
  884. }
  885. }
  886. if (semicolon==NULL) return FALSE;
  887. iplen=semicolon-addr;
  888. slen=MIN(iplen,len-1);
  889. strncpy(ip,addr,slen);
  890. ip[slen]='\0';
  891. *port=atoi(semicolon+1);
  892. return TRUE;
  893. }
  894. static bool_t parse_ice_addr(char *addr, char *type, int type_len, char *ip, int ip_len, int *port)
  895. {
  896. char *semicolon=NULL;
  897. int slen;
  898. semicolon=strrchr(addr,':');
  899. if (semicolon==NULL) return FALSE;
  900. slen=MIN(strlen(semicolon+1),type_len);
  901. strncpy(type,semicolon+1,slen);
  902. type[slen]='\0';
  903. *semicolon='\0';
  904. return parse_addr(addr,ip,ip_len,port);
  905. }
  906. static void display_items(void *user_data, uint32_t csrc, rtcp_sdes_type_t t, const char *content, uint8_t content_len){
  907. char str[256];
  908. int len=MIN(sizeof(str)-1,content_len);
  909. strncpy(str,content,len);
  910. str[len]='\0';
  911. switch(t){
  912. case RTCP_SDES_CNAME:
  913. ms_message("Found CNAME=%s",str);
  914. break;
  915. case RTCP_SDES_TOOL:
  916. ms_message("Found TOOL=%s",str);
  917. break;
  918. case RTCP_SDES_NOTE:
  919. ms_message("Found NOTE=%s",str);
  920. break;
  921. default:
  922. ms_message("Unhandled SDES item (%s)",str);
  923. }
  924. }
  925. static void parse_rtcp(mblk_t *m){
  926. do{
  927. if (rtcp_is_RR(m)){
  928. ms_message("Receiving RTCP RR");
  929. }else if (rtcp_is_SR(m)){
  930. ms_message("Receiving RTCP SR");
  931. }else if (rtcp_is_SDES(m)){
  932. ms_message("Receiving RTCP SDES");
  933. rtcp_sdes_parse(m,display_items,NULL);
  934. }else {
  935. ms_message("Receiving unhandled RTCP message");
  936. }
  937. }while(rtcp_next_packet(m));
  938. }
  939. static void parse_events(RtpSession *session, OrtpEvQueue *q){
  940. OrtpEvent *ev;
  941. while((ev=ortp_ev_queue_get(q))!=NULL){
  942. OrtpEventData *d=ortp_event_get_data(ev);
  943. switch(ortp_event_get_type(ev)){
  944. case ORTP_EVENT_RTCP_PACKET_RECEIVED:
  945. parse_rtcp(d->packet);
  946. break;
  947. case ORTP_EVENT_RTCP_PACKET_EMITTED:
  948. ms_message("Jitter buffer size: %f ms",rtp_session_get_jitter_stats(session)->jitter_buffer_size_ms);
  949. break;
  950. default:
  951. break;
  952. }
  953. ortp_event_destroy(ev);
  954. }
  955. }
  956. static PayloadType* create_custom_payload_type(const char *type, const char *subtype, const char *rate, int number){
  957. PayloadType *pt=payload_type_new();
  958. if (strcasecmp(type,"audio")==0){
  959. pt->type=PAYLOAD_AUDIO_PACKETIZED;
  960. }else if (strcasecmp(type,"video")==0){
  961. pt->type=PAYLOAD_VIDEO;
  962. }else{
  963. fprintf(stderr,"Unsupported payload type should be audio or video, not %s\n",type);
  964. exit(-1);
  965. }
  966. pt->mime_type=ms_strdup(subtype);
  967. pt->clock_rate=atoi(rate);
  968. return pt;
  969. }
  970. static PayloadType* parse_custom_payload(const char *name){
  971. char type[64]={0};
  972. char subtype[64]={0};
  973. char clockrate[64]={0};
  974. char *separator;
  975. if (strlen(name)>=sizeof(clockrate)-1){
  976. fprintf(stderr,"Cannot parse %s: too long.\n",name);
  977. exit(-1);
  978. }
  979. separator=strchr(name,'/');
  980. if (separator){
  981. char *separator2;
  982. strncpy(type,name,separator-name);
  983. separator2=strchr(separator+1,'/');
  984. if (separator2){
  985. strncpy(subtype,separator+1,separator2-separator-1);
  986. strcpy(clockrate,separator2+1);
  987. fprintf(stdout,"Found custom payload type=%s, mime=%s, clockrate=%s\n",type,subtype,clockrate);
  988. return create_custom_payload_type(type,subtype,clockrate,114);
  989. }
  990. }
  991. fprintf(stderr,"Error parsing payload name %s.\n",name);
  992. exit(-1);
  993. }
  994. static bool_t parse_window_ids(const char *ids, int* video_id, int* preview_id)
  995. {
  996. char* copy = strdup(ids);
  997. char *semicolon=strchr(copy,':');
  998. if (semicolon==NULL) {
  999. free(copy);
  1000. return FALSE;
  1001. }
  1002. *semicolon = '\0';
  1003. *video_id=atoi(copy);
  1004. *preview_id=atoi(semicolon+1);
  1005. free(copy);
  1006. return TRUE;
  1007. }