mediastream.c 21.3 KB
Newer Older
aymeric's avatar
aymeric committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

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

24 25
#include <math.h>

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

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

45 46 47 48
#ifdef __APPLE__
#include <CoreFoundation/CFRunLoop.h>
#endif

49 50 51 52 53
#ifdef ANDROID
#include <android/log.h>
#include <jni.h>
#endif

aymeric's avatar
aymeric committed
54 55
static int cond=1;

56 57 58
#ifdef VIDEO_ENABLED
static VideoStream *video=NULL;
#endif
59
static const char * capture_card=NULL;
Simon Morlat's avatar
Simon Morlat committed
60
static const char * playback_card=NULL;
61
static const char * camera=NULL;
62
static const char *infile=NULL,*outfile=NULL;
63
static float ng_threshold=-1;
64
static bool_t use_ng=FALSE;
65
static bool_t two_windows=FALSE;
jehan's avatar
jehan committed
66 67 68 69 70 71 72
static bool_t el=FALSE;
static float el_speed=-1;
static float el_thres=-1;
static float el_force=-1;
static int el_sustain=-1;
static float el_transmit_thres=-1;
static float ng_floorgain=-1;
73
static bool_t use_rc=FALSE;
74 75
static const char * zrtp_id=NULL;
static const char * zrtp_secrets=NULL;
76
static PayloadType *custom_pt=NULL;
77 78
static int video_window_id = -1;
static int preview_window_id = -1;
79

80
/* starting values echo canceller */
81
static int ec_len_ms=0, ec_delay_ms=0, ec_framesize=0;
82

jehan's avatar
jehan committed
83
static void run_media_streams(int localport, const char *remote_ip, int remoteport, int payload, const char *fmtp,
84
          int jitter, int bitrate, MSVideoSize vs, bool_t ec, bool_t agc, bool_t eq, int device_rotation);
85

aymeric's avatar
aymeric committed
86 87 88
static void stop_handler(int signum)
{
	cond--;
89 90 91 92
	if (cond<0) {
		ms_error("Brutal exit (%)\n", cond);
		exit(-1);
	}
aymeric's avatar
aymeric committed
93 94 95 96
}

static bool_t parse_addr(const char *addr, char *ip, int len, int *port)
{
smorlat's avatar
smorlat committed
97
	const char *semicolon=NULL;
aymeric's avatar
aymeric committed
98 99
	int iplen;
	int slen;
smorlat's avatar
smorlat committed
100
	const char *p;
aymeric's avatar
aymeric committed
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153

	*port=0;
	semicolon=strchr(addr,':');
	for (p=addr+strlen(addr)-1;p>addr;p--){
		if (*p==':') {
			semicolon=p;
			break;
		}
	}
	if (semicolon==NULL) return FALSE;
	iplen=semicolon-addr;
	slen=MIN(iplen,len-1);
	strncpy(ip,addr,slen);
	ip[slen]='\0';
	*port=atoi(semicolon+1);
	return TRUE;
}

static void display_items(void *user_data, uint32_t csrc, rtcp_sdes_type_t t, const char *content, uint8_t content_len){
	char str[256];
	int len=MIN(sizeof(str)-1,content_len);
	strncpy(str,content,len);
	str[len]='\0';
	switch(t){
		case RTCP_SDES_CNAME:
			ms_message("Found CNAME=%s",str);
		break;
		case RTCP_SDES_TOOL:
			ms_message("Found TOOL=%s",str);
		break;
		case RTCP_SDES_NOTE:
			ms_message("Found NOTE=%s",str);
		break;
		default:
			ms_message("Unhandled SDES item (%s)",str);
	}
}

static void parse_rtcp(mblk_t *m){
	do{
		if (rtcp_is_RR(m)){
			ms_message("Receiving RTCP RR");
		}else if (rtcp_is_SR(m)){
			ms_message("Receiving RTCP SR");
		}else if (rtcp_is_SDES(m)){
			ms_message("Receiving RTCP SDES");
			rtcp_sdes_parse(m,display_items,NULL);
		}else {
			ms_message("Receiving unhandled RTCP message");
		}
	}while(rtcp_next_packet(m));
}

Simon Morlat's avatar
Simon Morlat committed
154
static void parse_events(RtpSession *session, OrtpEvQueue *q){
aymeric's avatar
aymeric committed
155
	OrtpEvent *ev;
156

aymeric's avatar
aymeric committed
157 158 159 160 161 162 163
	while((ev=ortp_ev_queue_get(q))!=NULL){
		OrtpEventData *d=ortp_event_get_data(ev);
		switch(ortp_event_get_type(ev)){
			case ORTP_EVENT_RTCP_PACKET_RECEIVED:
				parse_rtcp(d->packet);
			break;
			default:
164
			break;
aymeric's avatar
aymeric committed
165 166 167 168 169
		}
		ortp_event_destroy(ev);
	}
}

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
static void create_custom_payload_type(const char *type, const char *subtype, const char *rate, int number){
	PayloadType *pt=payload_type_new();
	if (strcasecmp(type,"audio")==0){
		pt->type=PAYLOAD_AUDIO_PACKETIZED;
	}else if (strcasecmp(type,"video")==0){
		pt->type=PAYLOAD_VIDEO;
	}else{
		fprintf(stderr,"Unsupported payload type should be audio or video, not %s\n",type);
		exit(-1);
	}
	pt->mime_type=ms_strdup(subtype);
	pt->clock_rate=atoi(rate);
	custom_pt=pt;
}

static void parse_custom_payload(const char *name){
	char type[64]={0};
	char subtype[64]={0};
	char clockrate[64]={0};
	char *separator;

	if (strlen(name)>=sizeof(clockrate)-1){
		fprintf(stderr,"Cannot parse %s: too long.\n",name);
		exit(-1);
	}
195

196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
	separator=strchr(name,'/');
	if (separator){
		char *separator2;

		strncpy(type,name,separator-name);
		separator2=strchr(separator+1,'/');
		if (separator2){
			strncpy(subtype,separator+1,separator2-separator-1);
			strcpy(clockrate,separator2+1);
			fprintf(stdout,"Found custom payload type=%s, mime=%s, clockrate=%s\n",type,subtype,clockrate);
			create_custom_payload_type(type,subtype,clockrate,114);
			return;
		}
	}
	fprintf(stderr,"Error parsing payload name %s.\n",name);
	exit(-1);
}

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
static bool_t parse_window_ids(const char *ids, int* video_id, int* preview_id)
{
	char* copy = strdup(ids);
	char *semicolon=strchr(copy,':');
	if (semicolon==NULL) {
		free(copy);
		return FALSE;
	}
	*semicolon = '\0';

	*video_id=atoi(copy);
	*preview_id=atoi(semicolon+1);
	free(copy);
	return TRUE;
}

230 231
const char *usage="mediastream --local <port> --remote <ip:port> \n"
								"--payload <payload type number or payload name like 'audio/pmcu/8000'>\n"
232 233 234
								"[ --fmtp <fmtpline> ]\n"
								"[ --jitter <miliseconds> ]\n"
								"[ --width <pixels> ]\n"
smorlat's avatar
smorlat committed
235
								"[ --height <pixels> ]\n"
236 237
								"[ --bitrate <bits per seconds> ]\n"
								"[ --ec (enable echo canceller) ]\n"
238 239
								"[ --ec-tail <echo canceller tail length in ms> ]\n"
								"[ --ec-delay <echo canceller delay in ms> ]\n"
240
								"[ --ec-framesize <echo canceller framesize in samples> ]\n"
241 242 243 244 245 246 247 248
								"[ --agc (enable automatic gain control) ]\n"
								"[ --ng (enable noise gate)] \n"
								"[ --ng-threshold <(float) [0-1]> (noise gate threshold) ]\n"
								"[ --ng-floorgain <(float) [0-1]> (gain applied to the signal when its energy is below the threshold.) ]\n"
								"[ --capture-card <name> ]\n"
								"[ --playback-card <name> ]\n"
								"[ --infile	<input wav file> specify a wav file to be used for input, instead of soundcard ]\n"
								"[ --outfile <output wav file> specify a wav file to write audio into, instead of soundcard ]\n"
jehan's avatar
jehan committed
249 250 251 252 253 254
								"[ --camera <camera id as listed at startup> ]\n"
								"[ --el (enable echo limiter) ]\n"
								"[ --el-speed <(float) [0-1]> (gain changes are smoothed with a coefficent) ]\n"
								"[ --el-thres <(float) [0-1]> (Threshold above which the system becomes active) ]\n"
								"[ --el-force <(float) [0-1]> (The proportional coefficient controlling the mic attenuation) ]\n"
								"[ --el-sustain <(int)> (Time in milliseconds for which the attenuation is kept unchanged after) ]\n"
255
								"[ --el-transmit-thres <(float) [0-1]> (TO BE DOCUMENTED) ]\n"
256 257 258
								"[ --rc (enable adaptive rate control) ]\n"
								"[ --zrtp <zid> <secrets file> (enable zrtp) ]\n"
								"[ --verbose (most verbose messages) ]\n"
259
								"[ --video-windows-id <video surface:preview surface>]\n"
260
		;
aymeric's avatar
aymeric committed
261

262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
#ifdef ANDROID
//#include <execinfo.h>
int _main(int argc, char * argv[]);

static struct sigaction old_sa[NSIG];

void android_sigaction(int signal, siginfo_t *info, void *reserved)
{
	// signal crash to JAVA
	JNIEnv *env = ms_get_jni_env();
	// (*env)->CallStaticVoidMethod(env, obj, nativeCrashed);

	old_sa[signal].sa_handler(signal);
}

JNIEXPORT jint JNICALL  JNI_OnLoad(JavaVM *ajvm, void *reserved)
{
	ms_set_jvm(ajvm);

	struct sigaction handler;
	memset(&handler, 0, sizeof(sigaction));
	handler.sa_sigaction = android_sigaction;
	handler.sa_flags = SA_RESETHAND;
	#define CATCHSIG(X) sigaction(X, &handler, &old_sa[X])
	CATCHSIG(SIGILL);
	CATCHSIG(SIGABRT);
	CATCHSIG(SIGBUS);
	CATCHSIG(SIGFPE);
	CATCHSIG(SIGSEGV);
	CATCHSIG(SIGSTKFLT);
	CATCHSIG(SIGPIPE);

	return JNI_VERSION_1_2;
}

297
JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_setVideoWindowId
298 299 300 301 302 303 304 305
  (JNIEnv *env, jobject obj, jobject id) {
#ifdef VIDEO_ENABLED
	if (!video)
		return;
	video_stream_set_native_window_id(video,(unsigned long)id);
#endif
}

306
JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_setVideoPreviewWindowId
307 308 309 310 311 312 313 314
  (JNIEnv *env, jobject obj, jobject id) {
#ifdef VIDEO_ENABLED
	if (!video)
		return;
	video_stream_set_native_preview_window_id(video,(unsigned long)id);
#endif
}

315
JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_setDeviceRotation
316 317 318 319 320 321 322 323
  (JNIEnv *env, jobject thiz, jint rotation) {
#ifdef VIDEO_ENABLED
	if (!video)
		return;
	video_stream_set_device_rotation(video, rotation);
#endif
}

324
JNIEXPORT jint JNICALL Java_org_linphone_mediastream_MediastreamerActivity_stopMediaStream
325 326 327 328 329
  (JNIEnv *env, jobject obj) {
	ms_message("Requesting mediastream to stop\n");
	stop_handler(0);
	return 0;
}
aymeric's avatar
aymeric committed
330

331
JNIEXPORT void JNICALL Java_org_linphone_mediastream_MediastreamerActivity_changeCamera
332 333 334 335 336 337 338 339 340 341 342
  (JNIEnv *env, jobject obj, jint camId) {
#ifdef VIDEO_ENABLED
	if (!video)
		return;
	char* id = (char*)malloc(15);
	snprintf(id, 15, "Android%d", camId);
	ms_message("Changing camera, trying to use: '%s'\n", id);
	video_stream_change_camera(video, ms_web_cam_manager_get_cam(ms_web_cam_manager_get(), id));
#endif
}

343
JNIEXPORT jint JNICALL Java_org_linphone_mediastream_MediastreamerActivity_runMediaStream
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
  (JNIEnv *env, jobject obj, jint jargc, jobjectArray jargv) {
	// translate java String[] to c char*[]
	char** argv = (char**) malloc(jargc * sizeof(char*));
	int i, res;

	for(i=0; i<jargc; i++) {
		jstring arg = (jstring) (*env)->GetObjectArrayElement(env, jargv, i);
		const char *str = (*env)->GetStringUTFChars(env, arg, NULL);
		if (str == NULL)
			argv[i] = NULL;
		else {
			argv[i] = strdup(str);
			(*env)->ReleaseStringUTFChars(env, arg, str);
		}
	}
359

360
	res = _main(jargc, argv);
361

362 363 364 365 366 367 368 369 370 371
	for(i=0; i<jargc; i++) {
		if (argv[i])
			free(argv[i]);
	}
	return res;
}


int _main(int argc, char * argv[])
#else
aymeric's avatar
aymeric committed
372
int main(int argc, char * argv[])
373
#endif
aymeric's avatar
aymeric committed
374 375 376 377 378 379 380
{
	int i;
	int localport=0,remoteport=0,payload=0;
	char ip[50];
	const char *fmtp=NULL;
	int jitter=50;
	int bitrate=0;
381
	MSVideoSize vs;
aymeric's avatar
aymeric committed
382
	bool_t ec=FALSE;
383
	bool_t agc=FALSE;
smorlat's avatar
smorlat committed
384
	bool_t eq=FALSE;
385
	bool_t is_verbose=FALSE;
386
	int device_rotation=-1;
387

388
	cond = 1;
389

aymeric's avatar
aymeric committed
390
	if (argc<4) {
Simon Morlat's avatar
Simon Morlat committed
391
		printf("%s",usage);
aymeric's avatar
aymeric committed
392 393
		return -1;
	}
394 395 396 397 398

	/* default size */
	vs.width=MS_VIDEO_SIZE_CIF_W;
	vs.height=MS_VIDEO_SIZE_CIF_H;

aymeric's avatar
aymeric committed
399 400 401 402 403 404 405
	for (i=1;i<argc;i++){
		if (strcmp(argv[i],"--local")==0){
			i++;
			localport=atoi(argv[i]);
		}else if (strcmp(argv[i],"--remote")==0){
			i++;
			if (!parse_addr(argv[i],ip,sizeof(ip),&remoteport)) {
Simon Morlat's avatar
Simon Morlat committed
406
				printf("%s",usage);
aymeric's avatar
aymeric committed
407 408 409 410 411
				return -1;
			}
			printf("Remote addr: ip=%s port=%i\n",ip,remoteport);
		}else if (strcmp(argv[i],"--payload")==0){
			i++;
412 413 414 415 416 417
			if (isdigit(argv[i][0])){
				payload=atoi(argv[i]);
			}else {
				payload=114;
				parse_custom_payload(argv[i]);
			}
aymeric's avatar
aymeric committed
418 419 420 421 422 423 424 425 426
		}else if (strcmp(argv[i],"--fmtp")==0){
			i++;
			fmtp=argv[i];
		}else if (strcmp(argv[i],"--jitter")==0){
			i++;
			jitter=atoi(argv[i]);
		}else if (strcmp(argv[i],"--bitrate")==0){
			i++;
			bitrate=atoi(argv[i]);
427 428 429 430 431 432
		}else if (strcmp(argv[i],"--width")==0){
			i++;
			vs.width=atoi(argv[i]);
		}else if (strcmp(argv[i],"--height")==0){
			i++;
			vs.height=atoi(argv[i]);
433 434 435
		}else if (strcmp(argv[i],"--capture-card")==0){
			i++;
			capture_card=argv[i];
Simon Morlat's avatar
Simon Morlat committed
436 437 438
		}else if (strcmp(argv[i],"--playback-card")==0){
			i++;
			playback_card=argv[i];
aymeric's avatar
aymeric committed
439 440
		}else if (strcmp(argv[i],"--ec")==0){
			ec=TRUE;
441 442 443 444 445 446
		}else if (strcmp(argv[i],"--ec-tail")==0){
			i++;
			ec_len_ms=atoi(argv[i]);
		}else if (strcmp(argv[i],"--ec-delay")==0){
			i++;
			ec_delay_ms=atoi(argv[i]);
447 448 449
		}else if (strcmp(argv[i],"--ec-framesize")==0){
			i++;
			ec_framesize=atoi(argv[i]);
450 451
		}else if (strcmp(argv[i],"--agc")==0){
			agc=TRUE;
smorlat's avatar
smorlat committed
452 453
		}else if (strcmp(argv[i],"--eq")==0){
			eq=TRUE;
454 455
		}else if (strcmp(argv[i],"--ng")==0){
			use_ng=1;
456 457
		}else if (strcmp(argv[i],"--rc")==0){
			use_rc=1;
458 459 460
		}else if (strcmp(argv[i],"--ng-threshold")==0){
			i++;
			ng_threshold=atof(argv[i]);
jehan's avatar
jehan committed
461 462 463
		}else if (strcmp(argv[i],"--ng-floorgain")==0){
			i++;
			ng_floorgain=atof(argv[i]);
464 465
		}else if (strcmp(argv[i],"--two-windows")==0){
			two_windows=TRUE;
466 467 468 469 470 471
		}else if (strcmp(argv[i],"--infile")==0){
			i++;
			infile=argv[i];
		}else if (strcmp(argv[i],"--outfile")==0){
			i++;
			outfile=argv[i];
472 473 474
		}else if (strcmp(argv[i],"--camera")==0){
			i++;
			camera=argv[i];
jehan's avatar
jehan committed
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
		}else if (strcmp(argv[i],"--el")==0){
			el=TRUE;
		}else if (strcmp(argv[i],"--el-speed")==0){
			i++;
			el_speed=atof(argv[i]);
		}else if (strcmp(argv[i],"--el-thres")==0){
			i++;
			el_thres=atof(argv[i]);
		}else if (strcmp(argv[i],"--el-force")==0){
			i++;
			el_force=atof(argv[i]);
		}else if (strcmp(argv[i],"--el-sustain")==0){
			i++;
			el_sustain=atoi(argv[i]);
		}else if (strcmp(argv[i],"--el-transmit-thres")==0){
			i++;
			el_transmit_thres=atof(argv[i]);
492 493 494 495 496
		} else if (strcmp(argv[i],"--zrtp")==0){
			zrtp_id=argv[++i];
			zrtp_secrets=argv[++i];
		} else if (strcmp(argv[i],"--verbose")==0){
			is_verbose=TRUE;
497 498 499 500 501 502
		} else if (strcmp(argv[i], "--video-windows-id")==0) {
			i++;
			if (!parse_window_ids(argv[i],&video_window_id, &preview_window_id)) {
				printf("%s",usage);
				return -1;
			}
503
		} else if (strcmp(argv[i], "--device-rotation")==0) {
504
			i++;
505
			device_rotation=atoi(argv[i]);
jehan's avatar
jehan committed
506 507 508
		}else if (strcmp(argv[i],"--help")==0){
			printf("%s",usage);
			return -1;
aymeric's avatar
aymeric committed
509
		}
510 511
	}

jehan's avatar
jehan committed
512

513 514 515 516 517 518
	/*create the rtp session */
	ortp_init();
	if (is_verbose) {
		ortp_set_log_level_mask(ORTP_DEBUG|ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
	} else {
		ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
aymeric's avatar
aymeric committed
519
	}
520

521 522 523 524
	rtp_profile_set_payload(&av_profile,110,&payload_type_speex_nb);
	rtp_profile_set_payload(&av_profile,111,&payload_type_speex_wb);
	rtp_profile_set_payload(&av_profile,112,&payload_type_ilbc);
	rtp_profile_set_payload(&av_profile,113,&payload_type_amr);
525 526
	rtp_profile_set_payload(&av_profile,114,custom_pt);
	rtp_profile_set_payload(&av_profile,115,&payload_type_lpc1015);
527 528 529 530 531 532 533
#ifdef VIDEO_ENABLED
	rtp_profile_set_payload(&av_profile,26,&payload_type_jpeg);
	rtp_profile_set_payload(&av_profile,98,&payload_type_h263_1998);
	rtp_profile_set_payload(&av_profile,97,&payload_type_theora);
	rtp_profile_set_payload(&av_profile,99,&payload_type_mp4v);
	rtp_profile_set_payload(&av_profile,100,&payload_type_x_snow);
	rtp_profile_set_payload(&av_profile,102,&payload_type_h264);
534
	rtp_profile_set_payload(&av_profile,103,&payload_type_vp8);
535
#endif
536
	run_media_streams(localport,ip,remoteport,payload,fmtp,jitter,bitrate,vs,ec,agc,eq,device_rotation);
537 538 539 540 541 542 543

	ms_exit();

#ifdef VIDEO_ENABLED
	video=NULL;
#endif

aymeric's avatar
aymeric committed
544 545 546
	return 0;
}

547 548 549 550 551 552 553 554 555 556 557 558 559 560
static void run_media_streams(
	int localport, 
	const char *remote_ip, 
	int remoteport, 
	int payload, 
	const char *fmtp,
	int jitter, 
	int bitrate, 
	MSVideoSize vs, 
	bool_t ec, 
	bool_t agc, 
	bool_t eq,
	int device_rotation
) {
aymeric's avatar
aymeric committed
561 562
	AudioStream *audio=NULL;
#ifdef VIDEO_ENABLED
jehan's avatar
jehan committed
563
	MSWebCam *cam=NULL;
aymeric's avatar
aymeric committed
564 565 566 567
#endif
	RtpSession *session=NULL;
	PayloadType *pt;
	RtpProfile *profile=rtp_profile_clone_full(&av_profile);
568
	OrtpEvQueue *q=ortp_ev_queue_new();
aymeric's avatar
aymeric committed
569 570

	ms_init();
571 572 573
	ms_filter_enable_statistics(TRUE);
	ms_filter_reset_statistics();

aymeric's avatar
aymeric committed
574 575 576 577 578 579 580 581 582 583
	signal(SIGINT,stop_handler);
	pt=rtp_profile_get_payload(profile,payload);
	if (pt==NULL){
		printf("Error: no payload defined with number %i.",payload);
		exit(-1);
	}
	if (fmtp!=NULL) payload_type_set_send_fmtp(pt,fmtp);
	if (bitrate>0) pt->normal_bitrate=bitrate;

	if (pt->type!=PAYLOAD_VIDEO){
584
		MSSndCardManager *manager=ms_snd_card_manager_get();
585 586
		MSSndCard *capt= capture_card==NULL ? ms_snd_card_manager_get_default_capture_card(manager) :
				ms_snd_card_manager_get_card(manager,capture_card);
Simon Morlat's avatar
Simon Morlat committed
587 588
		MSSndCard *play= playback_card==NULL ? ms_snd_card_manager_get_default_playback_card(manager) :
				ms_snd_card_manager_get_card(manager,playback_card);
589 590
		audio=audio_stream_new(localport,ms_is_ipv6(remote_ip));
		audio_stream_enable_automatic_gain_control(audio,agc);
591
		audio_stream_enable_noise_gate(audio,use_ng);
Simon Morlat's avatar
Simon Morlat committed
592
		audio_stream_set_echo_canceller_params(audio,ec_len_ms,ec_delay_ms,ec_framesize);
jehan's avatar
jehan committed
593
		audio_stream_enable_echo_limiter(audio,el);
594
		audio_stream_enable_adaptive_bitrate_control(audio,use_rc);
Simon Morlat's avatar
Simon Morlat committed
595
		printf("Starting audio stream.\n");
596

597 598
		audio_stream_start_full(audio,profile,remote_ip,remoteport,remoteport+1, payload, jitter,infile,outfile,
		                        outfile==NULL ? play : NULL ,infile==NULL ? capt : NULL,infile!=NULL ? FALSE: ec);
599

600
		if (audio) {
jehan's avatar
jehan committed
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
			if (el) {
				if (el_speed!=-1)
					ms_filter_call_method(audio->volsend,MS_VOLUME_SET_EA_SPEED,&el_speed);
				if (el_force!=-1)
					ms_filter_call_method(audio->volsend,MS_VOLUME_SET_EA_FORCE,&el_force);
				if (el_thres!=-1)
					ms_filter_call_method(audio->volsend,MS_VOLUME_SET_EA_THRESHOLD,&el_thres);
				if (el_sustain!=-1)
					ms_filter_call_method(audio->volsend,MS_VOLUME_SET_EA_SUSTAIN,&el_sustain);
				if (el_transmit_thres!=-1)
					ms_filter_call_method(audio->volsend,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&el_transmit_thres);

			}
			if (use_ng){
				if (ng_threshold!=-1) {
					ms_filter_call_method(audio->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_threshold);
					ms_filter_call_method(audio->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_threshold);
				}
				if (ng_floorgain != -1) {
					ms_filter_call_method(audio->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
					ms_filter_call_method(audio->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
				}
			}
624 625 626 627 628 629 630 631

			if (zrtp_id != NULL) {
				OrtpZrtpParams params;
				params.zid=zrtp_id;
				params.zid_file=zrtp_secrets;
				audio_stream_enable_zrtp(audio,&params);
			}

632 633
			session=audio->session;
		}
aymeric's avatar
aymeric committed
634 635
	}else{
#ifdef VIDEO_ENABLED
smorlat's avatar
smorlat committed
636 637 638 639
		if (eq){
			ms_fatal("Cannot put an audio equalizer in a video stream !");
			exit(-1);
		}
aymeric's avatar
aymeric committed
640 641
		printf("Starting video stream.\n");
		video=video_stream_new(localport, ms_is_ipv6(remote_ip));
642 643 644 645
#ifdef ANDROID
		if (device_rotation >= 0)
			video_stream_set_device_rotation(video, device_rotation);
#endif
646
		video_stream_set_sent_video_size(video,vs);
647
		video_stream_use_preview_video_window(video,two_windows);
648

649 650 651 652
		if (camera)
			cam=ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),camera);
		if (cam==NULL)
			cam=ms_web_cam_manager_get_default_cam(ms_web_cam_manager_get());
aymeric's avatar
aymeric committed
653 654 655 656
		video_stream_start(video,profile,
					remote_ip,
					remoteport,remoteport+1,
					payload,
657 658
					jitter,cam
					);
aymeric's avatar
aymeric committed
659 660 661 662 663
		session=video->session;
#else
		printf("Error: video support not compiled.\n");
#endif
	}
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
	if (eq){ /*read from stdin interactive commands */
		char commands[128];
		commands[127]='\0';
		ms_sleep(1);  /* ensure following text be printed after ortp messages */
		if (eq)
		printf("\nPlease enter equalizer requests, such as 'eq active 1', 'eq active 0', 'eq 1200 0.1 200'\n");

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

			float gain;
			if (sscanf(commands,"eq active %i",&active)==1){
				audio_stream_enable_equalizer(audio,active);
				printf("OK\n");
			}else if (sscanf(commands,"eq %i %f %i",&freq,&gain,&freq_width)==3){
				audio_stream_equalizer_set_gain(audio,freq,gain,freq_width);
				printf("OK\n");
			}else if (sscanf(commands,"eq %i %f",&freq,&gain)==2){
				audio_stream_equalizer_set_gain(audio,freq,gain,0);
				printf("OK\n");
			}else if (strstr(commands,"dump")){
				int n=0,i;
				float *t;
				ms_filter_call_method(audio->equalizer,MS_EQUALIZER_GET_NUM_FREQUENCIES,&n);
				t=(float*)alloca(sizeof(float)*n);
				ms_filter_call_method(audio->equalizer,MS_EQUALIZER_DUMP_STATE,t);
				for(i=0;i<n;++i){
					if (fabs(t[i]-1)>0.01){
					printf("%i:%f:0 ",(i*pt->clock_rate)/(2*n),t[i]);
					}
				}
				printf("\nOK\n");
			} else if (strstr(commands,"quit")){
				break;
			}else printf("Cannot understand this.\n");
		}
700
	}else{  /* no interactive stuff - continuous debug output */
smorlat's avatar
smorlat committed
701
		rtp_session_register_event_queue(session,q);
702 703 704 705

		#ifdef __APPLE__
		CFRunLoopRun();
		#else
smorlat's avatar
smorlat committed
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
		while(cond)
		{
			int n;
			for(n=0;n<100;++n){
	#ifdef WIN32
				MSG msg;
				Sleep(10);
				while (PeekMessage(&msg, NULL, 0, 0,1)){
					TranslateMessage(&msg);
					DispatchMessage(&msg);
				}
	#else
				struct timespec ts;
				ts.tv_sec=0;
				ts.tv_nsec=10000000;
				nanosleep(&ts,NULL);
	#endif
	#if defined(VIDEO_ENABLED)
				if (video) video_stream_iterate(video);
	#endif
726
				if (audio) audio_stream_iterate(audio);
smorlat's avatar
smorlat committed
727
			}
728
			rtp_stats_display(rtp_session_get_stats(session),"RTP stats");
smorlat's avatar
smorlat committed
729
			if (session){
730
				ms_message("Bandwidth usage: download=%f kbits/sec, upload=%f kbits/sec\n",
smorlat's avatar
smorlat committed
731 732
					rtp_session_compute_recv_bandwidth(session)*1e-3,
					rtp_session_compute_send_bandwidth(session)*1e-3);
Simon Morlat's avatar
Simon Morlat committed
733
				parse_events(session,q);
734
				ms_message("Quality indicator : %f\n",audio ? audio_stream_get_quality_rating(audio) : -1);
aymeric's avatar
aymeric committed
735 736
			}
		}
737
	#endif // target MAC
Simon Morlat's avatar
Simon Morlat committed
738
	}
739

740
	printf("stopping all...\n");
741
	printf("Average quality indicator: %f",audio ? audio_stream_get_average_quality_rating(audio) : -1);
742

aymeric's avatar
aymeric committed
743 744
	if (audio) audio_stream_stop(audio);
#ifdef VIDEO_ENABLED
745 746 747 748
	if (video) {
		video_stream_stop(video);
		ms_filter_log_statistics();
	}
aymeric's avatar
aymeric committed
749 750 751 752
#endif
	ortp_ev_queue_destroy(q);
	rtp_profile_destroy(profile);
}