Beispiel #1
0
/*
 * List the ports in conference bridge
 */
static void ui_conf_list()
{
    unsigned i, count;
    pjsua_conf_port_id id[PJSUA_MAX_CALLS];

    printf("Conference ports:\n");

    count = PJ_ARRAY_SIZE(id);
    pjsua_enum_conf_ports(id, &count);

    for (i=0; i<count; ++i) {
	char txlist[PJSUA_MAX_CALLS*4+10];
	unsigned j;
	pjsua_conf_port_info info;

	pjsua_conf_get_port_info(id[i], &info);

	txlist[0] = '\0';
	for (j=0; j<info.listener_cnt; ++j) {
	    char s[10];
	    pj_ansi_snprintf(s, sizeof(s), "#%d ", info.listeners[j]);
	    pj_ansi_strcat(txlist, s);
	}
	printf("Port #%02d[%2dKHz/%dms/%d] %20.*s  transmitting to: %s\n",
	       info.slot_id,
	       info.clock_rate/1000,
	       info.samples_per_frame*1000/info.channel_count/info.clock_rate,
	       info.channel_count,
	       (int)info.name.slen,
	       info.name.ptr,
	       txlist);

    }
    puts("");
}
Beispiel #2
0
/*
 * This is the public API to create, initialize, register, and start the
 * TCP listener.
 */
PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
					pjsip_endpoint *endpt,
					const pjsip_tcp_transport_cfg *cfg,
					pjsip_tpfactory **p_factory
					)
{
    pj_pool_t *pool;
    pj_sock_t sock = PJ_INVALID_SOCKET;
    struct tcp_listener *listener;
    pj_activesock_cfg asock_cfg;
    pj_activesock_cb listener_cb;
    pj_sockaddr *listener_addr;
    int addr_len;
    pj_status_t status;

    /* Sanity check */
    PJ_ASSERT_RETURN(endpt && cfg->async_cnt, PJ_EINVAL);

    /* Verify that address given in a_name (if any) is valid */
    if (cfg->addr_name.host.slen) {
	pj_sockaddr tmp;

	status = pj_sockaddr_init(cfg->af, &tmp, &cfg->addr_name.host, 
				  (pj_uint16_t)cfg->addr_name.port);
	if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) ||
	    (cfg->af==pj_AF_INET() && 
	     tmp.ipv4.sin_addr.s_addr==PJ_INADDR_NONE)) 
	{
	    /* Invalid address */
	    return PJ_EINVAL;
	}
    }

    pool = pjsip_endpt_create_pool(endpt, "tcplis", POOL_LIS_INIT, 
				   POOL_LIS_INC);
    PJ_ASSERT_RETURN(pool, PJ_ENOMEM);


    listener = PJ_POOL_ZALLOC_T(pool, struct tcp_listener);
    listener->factory.pool = pool;
    listener->factory.type = cfg->af==pj_AF_INET() ? PJSIP_TRANSPORT_TCP :
						     PJSIP_TRANSPORT_TCP6;
    listener->factory.type_name = (char*)
		pjsip_transport_get_type_name(listener->factory.type);
    listener->factory.flag = 
	pjsip_transport_get_flag_from_type(listener->factory.type);
    listener->qos_type = cfg->qos_type;
    pj_memcpy(&listener->qos_params, &cfg->qos_params,
	      sizeof(cfg->qos_params));

    pj_ansi_strcpy(listener->factory.obj_name, "tcplis");
    if (listener->factory.type==PJSIP_TRANSPORT_TCP6)
	pj_ansi_strcat(listener->factory.obj_name, "6");

    status = pj_lock_create_recursive_mutex(pool, listener->factory.obj_name,
					    &listener->factory.lock);
    if (status != PJ_SUCCESS)
	goto on_error;


    /* Create socket */
    status = pj_sock_socket(cfg->af, pj_SOCK_STREAM(), 0, &sock);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Apply QoS, if specified */
    status = pj_sock_apply_qos2(sock, cfg->qos_type, &cfg->qos_params, 
				2, listener->factory.obj_name, 
				"SIP TCP listener socket");

    /* Bind address may be different than factory.local_addr because
     * factory.local_addr will be resolved below.
     */
    pj_sockaddr_cp(&listener->bound_addr, &cfg->bind_addr);

    /* Bind socket */
    listener_addr = &listener->factory.local_addr;
    pj_sockaddr_cp(listener_addr, &cfg->bind_addr);

    status = pj_sock_bind(sock, listener_addr, 
			  pj_sockaddr_get_len(listener_addr));
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Retrieve the bound address */
    addr_len = pj_sockaddr_get_len(listener_addr);
    status = pj_sock_getsockname(sock, listener_addr, &addr_len);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* If published host/IP is specified, then use that address as the
     * listener advertised address.
     */
    if (cfg->addr_name.host.slen) {
	/* Copy the address */
	listener->factory.addr_name = cfg->addr_name;
	pj_strdup(listener->factory.pool, &listener->factory.addr_name.host, 
		  &cfg->addr_name.host);
	listener->factory.addr_name.port = cfg->addr_name.port;

    } else {
	/* No published address is given, use the bound address */

	/* If the address returns 0.0.0.0, use the default
	 * interface address as the transport's address.
	 */
	if (!pj_sockaddr_has_addr(listener_addr)) {
	    pj_sockaddr hostip;

	    status = pj_gethostip(listener->bound_addr.addr.sa_family,
	                          &hostip);
	    if (status != PJ_SUCCESS)
		goto on_error;

	    pj_sockaddr_copy_addr(listener_addr, &hostip);
	}

	/* Save the address name */
	sockaddr_to_host_port(listener->factory.pool, 
			      &listener->factory.addr_name, 
			      listener_addr);
    }

    /* If port is zero, get the bound port */
    if (listener->factory.addr_name.port == 0) {
	listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr);
    }

    pj_ansi_snprintf(listener->factory.obj_name, 
		     sizeof(listener->factory.obj_name),
		     "tcplis:%d",  listener->factory.addr_name.port);


    /* Start listening to the address */
    status = pj_sock_listen(sock, PJSIP_TCP_TRANSPORT_BACKLOG);
    if (status != PJ_SUCCESS)
	goto on_error;


    /* Create active socket */
    pj_activesock_cfg_default(&asock_cfg);
    if (cfg->async_cnt > MAX_ASYNC_CNT) 
	asock_cfg.async_cnt = MAX_ASYNC_CNT;
    else
	asock_cfg.async_cnt = cfg->async_cnt;

    pj_bzero(&listener_cb, sizeof(listener_cb));
    listener_cb.on_accept_complete = &on_accept_complete;
    status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), &asock_cfg,
				  pjsip_endpt_get_ioqueue(endpt), 
				  &listener_cb, listener,
				  &listener->asock);

    /* Register to transport manager */
    listener->endpt = endpt;
    listener->tpmgr = pjsip_endpt_get_tpmgr(endpt);
    listener->factory.create_transport = lis_create_transport;
    listener->factory.destroy = lis_destroy;
    listener->is_registered = PJ_TRUE;
    status = pjsip_tpmgr_register_tpfactory(listener->tpmgr,
					    &listener->factory);
    if (status != PJ_SUCCESS) {
	listener->is_registered = PJ_FALSE;
	goto on_error;
    }

    /* Start pending accept() operations */
    status = pj_activesock_start_accept(listener->asock, pool);
    if (status != PJ_SUCCESS)
	goto on_error;

    PJ_LOG(4,(listener->factory.obj_name, 
	     "SIP TCP listener ready for incoming connections at %.*s:%d",
	     (int)listener->factory.addr_name.host.slen,
	     listener->factory.addr_name.host.ptr,
	     listener->factory.addr_name.port));

    /* Return the pointer to user */
    if (p_factory) *p_factory = &listener->factory;

    return PJ_SUCCESS;

on_error:
    if (listener->asock==NULL && sock!=PJ_INVALID_SOCKET)
	pj_sock_close(sock);
    lis_destroy(&listener->factory);
    return status;
}
Beispiel #3
0
/*
 * List the ports in conference bridge
 */
static void conf_list(pjmedia_conf *conf, int detail)
{
    enum { MAX_PORTS = 32 };
    unsigned i, count;
    pjmedia_conf_port_info info[MAX_PORTS];

    printf("Conference ports:\n");

    count = PJ_ARRAY_SIZE(info);
    pjmedia_conf_get_ports_info(conf, &count, info);

    for (i=0; i<count; ++i) {
	char txlist[4*MAX_PORTS];
	unsigned j;
	pjmedia_conf_port_info *port_info = &info[i];	
	
	txlist[0] = '\0';
	for (j=0; j<port_info->listener_cnt; ++j) {
	    char s[10];
	    pj_ansi_sprintf(s, "#%d ", port_info->listener_slots[j]);
	    pj_ansi_strcat(txlist, s);

	}

	if (txlist[0] == '\0') {
	    txlist[0] = '-';
	    txlist[1] = '\0';
	}

	if (!detail) {
	    printf("Port #%02d %-25.*s  transmitting to: %s\n", 
		   port_info->slot, 
		   (int)port_info->name.slen, 
		   port_info->name.ptr,
		   txlist);
	} else {
	    unsigned tx_level, rx_level;

	    pjmedia_conf_get_signal_level(conf, port_info->slot,
					  &tx_level, &rx_level);

	    printf("Port #%02d:\n"
		   "  Name                    : %.*s\n"
		   "  Sampling rate           : %d Hz\n"
		   "  Samples per frame       : %d\n"
		   "  Frame time              : %d ms\n"
		   "  Signal level adjustment : tx=%d, rx=%d\n"
		   "  Current signal level    : tx=%u, rx=%u\n"
		   "  Transmitting to ports   : %s\n\n",
		   port_info->slot,
		   (int)port_info->name.slen,
		   port_info->name.ptr,
		   port_info->clock_rate,
		   port_info->samples_per_frame,
		   port_info->samples_per_frame*1000/port_info->clock_rate,
		   port_info->tx_adj_level,
		   port_info->rx_adj_level,
		   tx_level,
		   rx_level,
		   txlist);
	}

    }
    puts("");
}
PJ_DEF(pj_status_t) pjsip_tls_transport_start2( pjsip_endpoint *endpt,
 					        const pjsip_tls_setting *opt,
					        const pj_sockaddr *local,
					        const pjsip_host_port *a_name,
					        unsigned async_cnt,
					        pjsip_tpfactory **p_factory)
{
    pj_pool_t *pool;
    pj_bool_t is_ipv6;
    int af;
    struct tls_listener *listener;
    pj_ssl_sock_param ssock_param;
    pj_sockaddr *listener_addr;
    pj_bool_t has_listener;
    pj_status_t status;

    /* Sanity check */
    PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL);

    is_ipv6 = (local && local->addr.sa_family == pj_AF_INET6());
    af = is_ipv6 ? pj_AF_INET6() : pj_AF_INET();

    /* Verify that address given in a_name (if any) is valid */
    if (a_name && a_name->host.slen) {
	pj_sockaddr tmp;

	status = pj_sockaddr_init(af, &tmp, &a_name->host,
				  (pj_uint16_t)a_name->port);
	if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) ||
	    (!is_ipv6 && tmp.ipv4.sin_addr.s_addr == PJ_INADDR_NONE))
	{
	    /* Invalid address */
	    return PJ_EINVAL;
	}
    }

    pool = pjsip_endpt_create_pool(endpt, "tlslis", POOL_LIS_INIT, 
				   POOL_LIS_INC);
    PJ_ASSERT_RETURN(pool, PJ_ENOMEM);

    listener = PJ_POOL_ZALLOC_T(pool, struct tls_listener);
    listener->factory.pool = pool;
    if (is_ipv6)
	listener->factory.type = PJSIP_TRANSPORT_TLS6;
    else
	listener->factory.type = PJSIP_TRANSPORT_TLS;
    listener->factory.type_name = (char*)
		pjsip_transport_get_type_name(listener->factory.type);
    listener->factory.flag = 
	pjsip_transport_get_flag_from_type(listener->factory.type);

    pj_ansi_strcpy(listener->factory.obj_name, "tlslis");
    if (is_ipv6)
	pj_ansi_strcat(listener->factory.obj_name, "6");

    if (opt)
	pjsip_tls_setting_copy(pool, &listener->tls_setting, opt);
    else
	pjsip_tls_setting_default(&listener->tls_setting);

    status = pj_lock_create_recursive_mutex(pool, listener->factory.obj_name,
					    &listener->factory.lock);
    if (status != PJ_SUCCESS)
	goto on_error;

    if (async_cnt > MAX_ASYNC_CNT) 
	async_cnt = MAX_ASYNC_CNT;

    /* Build SSL socket param */
    pj_ssl_sock_param_default(&ssock_param);
    ssock_param.sock_af = af;
    ssock_param.cb.on_accept_complete = &on_accept_complete;
    ssock_param.cb.on_data_read = &on_data_read;
    ssock_param.cb.on_data_sent = &on_data_sent;
    ssock_param.async_cnt = async_cnt;
    ssock_param.ioqueue = pjsip_endpt_get_ioqueue(endpt);
    ssock_param.require_client_cert = listener->tls_setting.require_client_cert;
    ssock_param.timeout = listener->tls_setting.timeout;
    ssock_param.user_data = listener;
    ssock_param.verify_peer = PJ_FALSE; /* avoid SSL socket closing the socket
					 * due to verification error */
    if (ssock_param.send_buffer_size < PJSIP_MAX_PKT_LEN)
	ssock_param.send_buffer_size = PJSIP_MAX_PKT_LEN;
    if (ssock_param.read_buffer_size < PJSIP_MAX_PKT_LEN)
	ssock_param.read_buffer_size = PJSIP_MAX_PKT_LEN;
    ssock_param.ciphers_num = listener->tls_setting.ciphers_num;
    ssock_param.ciphers = listener->tls_setting.ciphers;
    ssock_param.reuse_addr = listener->tls_setting.reuse_addr;
    ssock_param.qos_type = listener->tls_setting.qos_type;
    ssock_param.qos_ignore_error = listener->tls_setting.qos_ignore_error;
    pj_memcpy(&ssock_param.qos_params, &listener->tls_setting.qos_params,
	      sizeof(ssock_param.qos_params));

    has_listener = PJ_FALSE;

    switch(listener->tls_setting.method) {
    case PJSIP_TLSV1_METHOD:
	ssock_param.proto = PJ_SSL_SOCK_PROTO_TLS1;
	break;
    case PJSIP_SSLV2_METHOD:
	ssock_param.proto = PJ_SSL_SOCK_PROTO_SSL2;
	break;
    case PJSIP_SSLV3_METHOD:
	ssock_param.proto = PJ_SSL_SOCK_PROTO_SSL3;
	break;
    case PJSIP_SSLV23_METHOD:
	ssock_param.proto = PJ_SSL_SOCK_PROTO_SSL23;
	break;
    default:
	ssock_param.proto = PJ_SSL_SOCK_PROTO_DEFAULT;
	break;
    }

    /* Create SSL socket */
    status = pj_ssl_sock_create(pool, &ssock_param, &listener->ssock);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Bind address may be different than factory.local_addr because
     * factory.local_addr will be resolved below.
     */
    listener_addr = &listener->factory.local_addr;
    if (local) {
	pj_sockaddr_cp((pj_sockaddr_t*)listener_addr, 
		       (const pj_sockaddr_t*)local);
	pj_sockaddr_cp(&listener->bound_addr, local);
    } else {
	pj_sockaddr_init(af, listener_addr, NULL, 0);
	pj_sockaddr_init(af, &listener->bound_addr, NULL, 0);
    }

    /* Check if certificate/CA list for SSL socket is set */
    if (listener->tls_setting.cert_file.slen ||
	listener->tls_setting.ca_list_file.slen) 
    {
	status = pj_ssl_cert_load_from_files(pool,
			&listener->tls_setting.ca_list_file,
			&listener->tls_setting.cert_file,
			&listener->tls_setting.privkey_file,
			&listener->tls_setting.password,
			&listener->cert);
	if (status != PJ_SUCCESS)
	    goto on_error;

	status = pj_ssl_sock_set_certificate(listener->ssock, pool, 
					     listener->cert);
	if (status != PJ_SUCCESS)
	    goto on_error;
    }

    /* Start accepting incoming connections. Note that some TLS/SSL backends
     * may not support for SSL socket server.
     */
    has_listener = PJ_FALSE;

    status = pj_ssl_sock_start_accept(listener->ssock, pool, 
			  (pj_sockaddr_t*)listener_addr, 
			  pj_sockaddr_get_len((pj_sockaddr_t*)listener_addr));
    if (status == PJ_SUCCESS || status == PJ_EPENDING) {
	pj_ssl_sock_info info;
	has_listener = PJ_TRUE;

	/* Retrieve the bound address */
	status = pj_ssl_sock_get_info(listener->ssock, &info);
	if (status == PJ_SUCCESS)
	    pj_sockaddr_cp(listener_addr, (pj_sockaddr_t*)&info.local_addr);
    } else if (status != PJ_ENOTSUP) {
	goto on_error;
    }

    /* If published host/IP is specified, then use that address as the
     * listener advertised address.
     */
    if (a_name && a_name->host.slen) {
	/* Copy the address */
	listener->factory.addr_name = *a_name;
	pj_strdup(listener->factory.pool, &listener->factory.addr_name.host, 
		  &a_name->host);
	listener->factory.addr_name.port = a_name->port;

    } else {
	/* No published address is given, use the bound address */

	/* If the address returns 0.0.0.0, use the default
	 * interface address as the transport's address.
	 */
	if (!pj_sockaddr_has_addr(listener_addr)) {
	    pj_sockaddr hostip;

	    status = pj_gethostip(af, &hostip);
	    if (status != PJ_SUCCESS)
		goto on_error;

	    pj_sockaddr_copy_addr(listener_addr, &hostip);
	}

	/* Save the address name */
	sockaddr_to_host_port(listener->factory.pool, 
			      &listener->factory.addr_name, listener_addr);
    }

    /* If port is zero, get the bound port */
    if (listener->factory.addr_name.port == 0) {
	listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr);
    }

    pj_ansi_snprintf(listener->factory.obj_name, 
		     sizeof(listener->factory.obj_name),
		     "tlslis:%d",  listener->factory.addr_name.port);

    /* Register to transport manager */
    listener->endpt = endpt;
    listener->tpmgr = pjsip_endpt_get_tpmgr(endpt);
    listener->factory.create_transport2 = lis_create_transport;
    listener->factory.destroy = lis_destroy;
    listener->is_registered = PJ_TRUE;
    status = pjsip_tpmgr_register_tpfactory(listener->tpmgr,
					    &listener->factory);
    if (status != PJ_SUCCESS) {
	listener->is_registered = PJ_FALSE;
	goto on_error;
    }

    if (has_listener) {
	PJ_LOG(4,(listener->factory.obj_name, 
		 "SIP TLS listener is ready for incoming connections "
		 "at %.*s:%d",
		 (int)listener->factory.addr_name.host.slen,
		 listener->factory.addr_name.host.ptr,
		 listener->factory.addr_name.port));
    } else {
	PJ_LOG(4,(listener->factory.obj_name, "SIP TLS is ready "
		  "(client only)"));
    }

    /* Return the pointer to user */
    if (p_factory) *p_factory = &listener->factory;

    return PJ_SUCCESS;

on_error:
    lis_destroy(&listener->factory);
    return status;
}
Beispiel #5
0
static int init_options(int argc, char *argv[])
{
    struct pj_getopt_option long_options[] = {
	{ "codec",	    1, 0, OPT_CODEC },
	{ "input",	    1, 0, OPT_INPUT },
	{ "output",	    1, 0, OPT_OUTPUT },
	{ "duration",	    1, 0, OPT_DURATION },
	{ "log-file",	    1, 0, OPT_LOG_FILE},
	{ "loss",	    1, 0, OPT_LOSS },
	{ "min-lost-burst", 1, 0, OPT_MIN_LOST_BURST},
	{ "max-lost-burst", 1, 0, OPT_MAX_LOST_BURST},
	{ "loss-corr",	    1, 0, OPT_LOSS_CORR},
	{ "min-jitter",	    1, 0, OPT_MIN_JITTER },
	{ "max-jitter",	    1, 0, OPT_MAX_JITTER },
	{ "snd-burst",	    1, 0, OPT_SND_BURST },
	{ "tx-ptime",	    1, 0, OPT_TX_PTIME },
	{ "rx-ptime",	    1, 0, OPT_RX_PTIME },
	{ "no-vad",	    0, 0, OPT_NO_VAD },
	{ "no-plc",	    0, 0, OPT_NO_PLC },
	{ "jb-prefetch",    0, 0, OPT_JB_PREFETCH },
	{ "jb-min-pre",     1, 0, OPT_JB_MIN_PRE },
	{ "jb-max-pre",     1, 0, OPT_JB_MAX_PRE },
	{ "jb-max",	    1, 0, OPT_JB_MAX },
	{ "help",	    0, 0, OPT_HELP},
	{ NULL, 0, 0, 0 },
    };
    int c;
    int option_index;
    char format[128];

    /* Init default config */
    g_app.cfg.codec = pj_str(CODEC);
    g_app.cfg.duration_msec = DURATION * 1000;
    g_app.cfg.silent = SILENT;
    g_app.cfg.log_file = LOG_FILE;
    g_app.cfg.tx_wav_in = WAV_REF;
    g_app.cfg.tx_ptime = 0;
    g_app.cfg.tx_min_jitter = 0;
    g_app.cfg.tx_max_jitter = 0;
    g_app.cfg.tx_dtx = DTX;
    g_app.cfg.tx_pct_avg_lost = 0;
    g_app.cfg.tx_min_lost_burst = MIN_LOST_BURST;
    g_app.cfg.tx_max_lost_burst = MAX_LOST_BURST;
    g_app.cfg.tx_pct_loss_corr = LOSS_CORR;

    g_app.cfg.rx_wav_out = WAV_OUT;
    g_app.cfg.rx_ptime = 0;
    g_app.cfg.rx_plc = PLC;
    g_app.cfg.rx_snd_burst = 1;
    g_app.cfg.rx_jb_init = -1;
    g_app.cfg.rx_jb_min_pre = -1;
    g_app.cfg.rx_jb_max_pre = -1;
    g_app.cfg.rx_jb_max = -1;

    /* Build format */
    format[0] = '\0';
    for (c=0; c<PJ_ARRAY_SIZE(long_options)-1; ++c) {
	if (long_options[c].has_arg) {
	    char cmd[10];
	    pj_ansi_snprintf(cmd, sizeof(cmd), "%c:", long_options[c].val);
	    pj_ansi_strcat(format, cmd);
	}
    }
    for (c=0; c<PJ_ARRAY_SIZE(long_options)-1; ++c) {
	if (long_options[c].has_arg == 0) {
	    char cmd[10];
	    pj_ansi_snprintf(cmd, sizeof(cmd), "%c", long_options[c].val);
	    pj_ansi_strcat(format, cmd);
	}
    }

    /* Parse options */
    pj_optind = 0;
    while((c=pj_getopt_long(argc,argv, format, 
			    long_options, &option_index))!=-1) 
    {
	switch (c) {
	case OPT_CODEC:
	    g_app.cfg.codec = pj_str(pj_optarg);
	    break;
	case OPT_INPUT:
	    g_app.cfg.tx_wav_in = pj_optarg;
	    break;
	case OPT_OUTPUT:
	    g_app.cfg.rx_wav_out = pj_optarg;
	    break;
	case OPT_DURATION:
	    g_app.cfg.duration_msec = atoi(pj_optarg) * 1000;
	    break;
	case OPT_LOG_FILE:
	    g_app.cfg.log_file = pj_optarg;
	    break;
	case OPT_LOSS:
	    g_app.cfg.tx_pct_avg_lost = atoi(pj_optarg);
	    if (g_app.cfg.tx_pct_avg_lost > 100) {
		puts("Error: Invalid loss value?");
		return 1;
	    }
	    break;
	case OPT_MIN_LOST_BURST:
	    g_app.cfg.tx_min_lost_burst = atoi(pj_optarg);
	    break;
	case OPT_MAX_LOST_BURST:
	    g_app.cfg.tx_max_lost_burst = atoi(pj_optarg);
	    break;
	case OPT_LOSS_CORR:
	    g_app.cfg.tx_pct_loss_corr = atoi(pj_optarg);
	    if (g_app.cfg.tx_pct_avg_lost > 100) {
		puts("Error: Loss correlation is in percentage, value is not valid?");
		return 1;
	    }
	    break;
	case OPT_MIN_JITTER:
	    g_app.cfg.tx_min_jitter = atoi(pj_optarg);
	    break;
	case OPT_MAX_JITTER:
	    g_app.cfg.tx_max_jitter = atoi(pj_optarg);
	    break;
	case OPT_SND_BURST:
	    g_app.cfg.rx_snd_burst = atoi(pj_optarg);
	    break;
	case OPT_TX_PTIME:
	    g_app.cfg.tx_ptime = atoi(pj_optarg);
	    break;
	case OPT_RX_PTIME:
	    g_app.cfg.rx_ptime = atoi(pj_optarg);
	    break;
	case OPT_NO_VAD:
	    g_app.cfg.tx_dtx = PJ_FALSE;
	    break;
	case OPT_NO_PLC:
	    g_app.cfg.rx_plc = PJ_FALSE;
	    break;
	case OPT_JB_PREFETCH:
	    g_app.cfg.rx_jb_init = 1;
	    break;
	case OPT_JB_MIN_PRE:
	    g_app.cfg.rx_jb_min_pre = atoi(pj_optarg);
	    break;
	case OPT_JB_MAX_PRE:
	    g_app.cfg.rx_jb_max_pre = atoi(pj_optarg);
	    break;
	case OPT_JB_MAX:
	    g_app.cfg.rx_jb_max = atoi(pj_optarg);
	    break;
	case OPT_HELP:
	    usage();
	    return 1;
	default:
	    usage();
	    return 1;
	}
    }

    /* Check for orphaned params */
    if (pj_optind < argc) {
	usage();
	return 1;
    }

    /* Normalize options */
    if (g_app.cfg.rx_jb_init < g_app.cfg.rx_jb_min_pre)
	g_app.cfg.rx_jb_init = g_app.cfg.rx_jb_min_pre;
    else if (g_app.cfg.rx_jb_init > g_app.cfg.rx_jb_max_pre)
	g_app.cfg.rx_jb_init = g_app.cfg.rx_jb_max_pre;

    if (g_app.cfg.tx_max_jitter < g_app.cfg.tx_min_jitter)
	g_app.cfg.tx_max_jitter = g_app.cfg.tx_min_jitter;
    return 0;
}