Пример #1
0
/*
 * Repeated connect/accept on the same listener socket.
 */
static int compliance_test_2(pj_bool_t allow_concur)
{
#if defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0
    enum { MAX_PAIR = 1, TEST_LOOP = 2 };
#else
    enum { MAX_PAIR = 4, TEST_LOOP = 2 };
#endif

    struct listener
    {
	pj_sock_t	     sock;
	pj_ioqueue_key_t    *key;
	pj_sockaddr_in	     addr;
	int		     addr_len;
    } listener;

    struct server
    {
	pj_sock_t	     sock;
	pj_ioqueue_key_t    *key;
	pj_sockaddr_in	     local_addr;
	pj_sockaddr_in	     rem_addr;
	int		     rem_addr_len;
	pj_ioqueue_op_key_t  accept_op;
    } server[MAX_PAIR];

    struct client
    {
	pj_sock_t	     sock;
	pj_ioqueue_key_t    *key;
    } client[MAX_PAIR];

    pj_pool_t *pool = NULL;
    char *send_buf, *recv_buf;
    pj_ioqueue_t *ioque = NULL;
    int i, bufsize = BUF_MIN_SIZE;
    int status;
    int test_loop, pending_op = 0;
    pj_timestamp t_elapsed;
    pj_str_t s;
    pj_status_t rc;

    listener.sock = PJ_INVALID_SOCKET;
    listener.key = NULL;
    
    for (i=0; i<MAX_PAIR; ++i) {
    	server[i].sock = PJ_INVALID_SOCKET;
    	server[i].key = NULL;
    }
    
    for (i=0; i<MAX_PAIR; ++i) {
    	client[i].sock = PJ_INVALID_SOCKET;
    	client[i].key = NULL;	
    }
    
    // Create pool.
    pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);


    // Create I/O Queue.
    rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
    if (rc != PJ_SUCCESS) {
        app_perror("...ERROR in pj_ioqueue_create()", rc);
	return -10;
    }


    // Concurrency
    rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur);
    if (rc != PJ_SUCCESS) {
        app_perror("...ERROR in pj_ioqueue_set_default_concurrency()", rc);
	return -11;
    }

    // Allocate buffers for send and receive.
    send_buf = (char*)pj_pool_alloc(pool, bufsize);
    recv_buf = (char*)pj_pool_alloc(pool, bufsize);

    // Create listener socket
    rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &listener.sock);
    if (rc != PJ_SUCCESS) {
        app_perror("...error creating socket", rc);
        status=-20; goto on_error;
    }

    // Bind listener socket.
    pj_sockaddr_in_init(&listener.addr, 0, 0);
    if ((rc=pj_sock_bind(listener.sock, &listener.addr, sizeof(listener.addr))) != 0 ) {
        app_perror("...bind error", rc);
	status=-30; goto on_error;
    }

    // Get listener address.
    listener.addr_len = sizeof(listener.addr);
    rc = pj_sock_getsockname(listener.sock, &listener.addr, &listener.addr_len);
    if (rc != PJ_SUCCESS) {
        app_perror("...ERROR in pj_sock_getsockname()", rc);
	status=-40; goto on_error;
    }
    listener.addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));


    // Register listener socket.
    rc = pj_ioqueue_register_sock(pool, ioque, listener.sock, NULL, &test_cb, 
				  &listener.key);
    if (rc != PJ_SUCCESS) {
	app_perror("...ERROR", rc);
	status=-50; goto on_error;
    }


    // Listener socket listen().
    if (pj_sock_listen(listener.sock, 5)) {
        app_perror("...ERROR in pj_sock_listen()", rc);
	status=-60; goto on_error;
    }


    for (test_loop=0; test_loop < TEST_LOOP; ++test_loop) {
	// Client connect and server accept.
	for (i=0; i<MAX_PAIR; ++i) {
	    rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &client[i].sock);
	    if (rc != PJ_SUCCESS) {
		app_perror("...error creating socket", rc);
		status=-70; goto on_error;
	    }

	    rc = pj_ioqueue_register_sock(pool, ioque, client[i].sock, NULL, 
					  &test_cb, &client[i].key);
	    if (rc != PJ_SUCCESS) {
		app_perror("...error ", rc);
		status=-80; goto on_error;
	    }

	    // Server socket accept()
	    pj_ioqueue_op_key_init(&server[i].accept_op, 
				   sizeof(server[i].accept_op));
	    server[i].rem_addr_len = sizeof(pj_sockaddr_in);
	    status = pj_ioqueue_accept(listener.key, &server[i].accept_op, 
				       &server[i].sock, &server[i].local_addr, 
				       &server[i].rem_addr, 
				       &server[i].rem_addr_len);
	    if (status!=PJ_SUCCESS && status != PJ_EPENDING) {
		app_perror("...ERROR in pj_ioqueue_accept()", rc);
		status=-90; goto on_error;
	    }
	    if (status==PJ_EPENDING) {
		++pending_op;
	    }


	    // Client socket connect()
	    status = pj_ioqueue_connect(client[i].key, &listener.addr, 
					sizeof(listener.addr));
	    if (status!=PJ_SUCCESS && status != PJ_EPENDING) {
		app_perror("...ERROR in pj_ioqueue_connect()", rc);
		status=-100; goto on_error;
	    }
	    if (status==PJ_EPENDING) {
		++pending_op;
	    }

	    // Poll until connection of this pair established
	    while (pending_op) {
		pj_time_val timeout = {1, 0};

#ifdef PJ_SYMBIAN
		status = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
#else
		status = pj_ioqueue_poll(ioque, &timeout);
#endif
		if (status > 0) {
		    if (status > pending_op) {
			PJ_LOG(3,(THIS_FILE,
				  "...error: pj_ioqueue_poll() returned %d "
				  "(only expecting %d)",
				  status, pending_op));
			return -110;
		    }
		    pending_op -= status;

		    if (pending_op == 0) {
			status = 0;
		    }
		}
	    }
	}

	// There's no pending operation.
	// When we poll the ioqueue, there must not be events.
	if (pending_op == 0) {
	    pj_time_val timeout = {1, 0};
#ifdef PJ_SYMBIAN
	    status = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
#else
	    status = pj_ioqueue_poll(ioque, &timeout);
#endif
	    if (status != 0) {
		status=-120; goto on_error;
	    }
	}

	for (i=0; i<MAX_PAIR; ++i) {
	    // Check server socket.
	    if (server[i].sock == PJ_INVALID_SOCKET) {
		status = -130;
		app_perror("...accept() error", pj_get_os_error());
		goto on_error;
	    }

	    // Check addresses
	    if (server[i].local_addr.sin_family != pj_AF_INET() ||
		server[i].local_addr.sin_addr.s_addr == 0 ||
		server[i].local_addr.sin_port == 0)
	    {
		app_perror("...ERROR address not set", rc);
		status = -140;
		goto on_error;
	    }

	    if (server[i].rem_addr.sin_family != pj_AF_INET() ||
		server[i].rem_addr.sin_addr.s_addr == 0 ||
		server[i].rem_addr.sin_port == 0)
	    {
		app_perror("...ERROR address not set", rc);
		status = -150;
		goto on_error;
	    }


	    // Register newly accepted socket.
	    rc = pj_ioqueue_register_sock(pool, ioque, server[i].sock, NULL,
					  &test_cb, &server[i].key);
	    if (rc != PJ_SUCCESS) {
		app_perror("...ERROR in pj_ioqueue_register_sock", rc);
		status = -160;
		goto on_error;
	    }

	    // Test send and receive.
	    t_elapsed.u32.lo = 0;
	    status = send_recv_test(ioque, server[i].key, client[i].key, 
				    send_buf, recv_buf, bufsize, &t_elapsed);
	    if (status != 0) {
		goto on_error;
	    }
	}

	// Success
	status = 0;

	for (i=0; i<MAX_PAIR; ++i) {
	    if (server[i].key != NULL) {
		pj_ioqueue_unregister(server[i].key);
		server[i].key = NULL;
		server[i].sock = PJ_INVALID_SOCKET;
	    } else if (server[i].sock != PJ_INVALID_SOCKET) {
		pj_sock_close(server[i].sock);
		server[i].sock = PJ_INVALID_SOCKET;
	    }

	    if (client[i].key != NULL) {
		pj_ioqueue_unregister(client[i].key);
		client[i].key = NULL;
		client[i].sock = PJ_INVALID_SOCKET;
	    } else if (client[i].sock != PJ_INVALID_SOCKET) {
		pj_sock_close(client[i].sock);
		client[i].sock = PJ_INVALID_SOCKET;
	    }
	}
    }

    status = 0;

on_error:
    for (i=0; i<MAX_PAIR; ++i) {
	if (server[i].key != NULL) {
	    pj_ioqueue_unregister(server[i].key);
	    server[i].key = NULL;
	    server[i].sock = PJ_INVALID_SOCKET;
	} else if (server[i].sock != PJ_INVALID_SOCKET) {
	    pj_sock_close(server[i].sock);
	    server[i].sock = PJ_INVALID_SOCKET;
	}

	if (client[i].key != NULL) {
	    pj_ioqueue_unregister(client[i].key);
	    client[i].key = NULL;
	    server[i].sock = PJ_INVALID_SOCKET;
	} else if (client[i].sock != PJ_INVALID_SOCKET) {
	    pj_sock_close(client[i].sock);
	    client[i].sock = PJ_INVALID_SOCKET;
	}
    }

    if (listener.key) {
	pj_ioqueue_unregister(listener.key);
	listener.key = NULL;
    } else if (listener.sock != PJ_INVALID_SOCKET) {
	pj_sock_close(listener.sock);
	listener.sock = PJ_INVALID_SOCKET;
    }

    if (ioque != NULL)
	pj_ioqueue_destroy(ioque);
    pj_pool_release(pool);
    return status;

}
Пример #2
0
/* Set client credentials. */
PJ_DEF(pj_status_t) pjsip_auth_clt_set_credentials( pjsip_auth_clt_sess *sess,
						    int cred_cnt,
						    const pjsip_cred_info *c)
{
    PJ_ASSERT_RETURN(sess && c, PJ_EINVAL);

    if (cred_cnt == 0) {
	sess->cred_cnt = 0;
    } else {
	int i;
	sess->cred_info = (pjsip_cred_info*)
			  pj_pool_alloc(sess->pool, cred_cnt * sizeof(*c));
	for (i=0; i<cred_cnt; ++i) {
	    sess->cred_info[i].data_type = c[i].data_type;

	    /* When data_type is PJSIP_CRED_DATA_EXT_AKA, 
	     * callback must be specified.
	     */
	    if ((c[i].data_type & EXT_MASK) == PJSIP_CRED_DATA_EXT_AKA) {

#if !PJSIP_HAS_DIGEST_AKA_AUTH
		if (!PJSIP_HAS_DIGEST_AKA_AUTH) {
		    pj_assert(!"PJSIP_HAS_DIGEST_AKA_AUTH is not enabled");
		    return PJSIP_EAUTHINAKACRED;
		}
#endif

		/* Callback must be specified */
		PJ_ASSERT_RETURN(c[i].ext.aka.cb != NULL, PJ_EINVAL);

		/* Verify K len */
		PJ_ASSERT_RETURN(c[i].ext.aka.k.slen <= PJSIP_AKA_KLEN, 
				 PJSIP_EAUTHINAKACRED);

		/* Verify OP len */
		PJ_ASSERT_RETURN(c[i].ext.aka.op.slen <= PJSIP_AKA_OPLEN, 
				 PJSIP_EAUTHINAKACRED);

		/* Verify AMF len */
		PJ_ASSERT_RETURN(c[i].ext.aka.amf.slen <= PJSIP_AKA_AMFLEN,
				 PJSIP_EAUTHINAKACRED);

		sess->cred_info[i].ext.aka.cb = c[i].ext.aka.cb;
		pj_strdup(sess->pool, &sess->cred_info[i].ext.aka.k,
			  &c[i].ext.aka.k);
		pj_strdup(sess->pool, &sess->cred_info[i].ext.aka.op,
			  &c[i].ext.aka.op);
		pj_strdup(sess->pool, &sess->cred_info[i].ext.aka.amf,
			  &c[i].ext.aka.amf);
	    }

	    pj_strdup(sess->pool, &sess->cred_info[i].scheme, &c[i].scheme);
	    pj_strdup(sess->pool, &sess->cred_info[i].realm, &c[i].realm);
	    pj_strdup(sess->pool, &sess->cred_info[i].username, &c[i].username);
	    pj_strdup(sess->pool, &sess->cred_info[i].data, &c[i].data);
	}
	sess->cred_cnt = cred_cnt;
    }

    return PJ_SUCCESS;
}
Пример #3
0
/* Initialize outgoing request. */
PJ_DEF(pj_status_t) pjsip_auth_clt_init_req( pjsip_auth_clt_sess *sess,
					     pjsip_tx_data *tdata )
{
    const pjsip_method *method;
    pjsip_cached_auth *auth;
    pjsip_hdr added;

    PJ_ASSERT_RETURN(sess && tdata, PJ_EINVAL);
    PJ_ASSERT_RETURN(sess->pool, PJSIP_ENOTINITIALIZED);
    PJ_ASSERT_RETURN(tdata->msg->type==PJSIP_REQUEST_MSG,
		     PJSIP_ENOTREQUESTMSG);

    /* Init list */
    pj_list_init(&added);

    /* Get the method. */
    method = &tdata->msg->line.req.method;

    auth = sess->cached_auth.next;
    while (auth != &sess->cached_auth) {
	/* Reset stale counter */
	auth->stale_cnt = 0;

	if (auth->qop_value == PJSIP_AUTH_QOP_NONE) {
#	    if defined(PJSIP_AUTH_HEADER_CACHING) && \
	       PJSIP_AUTH_HEADER_CACHING!=0
	    {
		pjsip_cached_auth_hdr *entry = auth->cached_hdr.next;
		while (entry != &auth->cached_hdr) {
		    if (pjsip_method_cmp(&entry->method, method)==0) {
			pjsip_authorization_hdr *hauth;
			hauth = pjsip_hdr_shallow_clone(tdata->pool, entry->hdr);
			//pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth);
			pj_list_push_back(&added, hauth);
			break;
		    }
		    entry = entry->next;
		}

#		if defined(PJSIP_AUTH_AUTO_SEND_NEXT) && \
			   PJSIP_AUTH_AUTO_SEND_NEXT!=0
		{
		    if (entry == &auth->cached_hdr)
			new_auth_for_req( tdata, sess, auth, NULL);
		}
#		endif

	    }
#	    elif defined(PJSIP_AUTH_AUTO_SEND_NEXT) && \
		 PJSIP_AUTH_AUTO_SEND_NEXT!=0
	    {
		new_auth_for_req( tdata, sess, auth, NULL);
	    }
#	    endif

	} 
#	if defined(PJSIP_AUTH_QOP_SUPPORT) && \
	   defined(PJSIP_AUTH_AUTO_SEND_NEXT) && \
	   (PJSIP_AUTH_QOP_SUPPORT && PJSIP_AUTH_AUTO_SEND_NEXT)
	else if (auth->qop_value == PJSIP_AUTH_QOP_AUTH) {
	    /* For qop="auth", we have to re-create the authorization header. 
	     */
	    const pjsip_cred_info *cred;
	    pjsip_authorization_hdr *hauth;
	    pj_status_t status;

	    cred = auth_find_cred(sess, &auth->realm, 
				  &auth->last_chal->scheme);
	    if (!cred) {
		auth = auth->next;
		continue;
	    }

	    status = auth_respond( tdata->pool, auth->last_chal, 
				   tdata->msg->line.req.uri, 
				   cred,
				   &tdata->msg->line.req.method,
				   sess->pool, auth, &hauth);
	    if (status != PJ_SUCCESS)
		return status;
	    
	    //pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth);
	    pj_list_push_back(&added, hauth);
	}
#	endif	/* PJSIP_AUTH_QOP_SUPPORT && PJSIP_AUTH_AUTO_SEND_NEXT */

	auth = auth->next;
    }

    if (sess->pref.initial_auth == PJ_FALSE) {
	pjsip_hdr *h;

	/* Don't want to send initial empty Authorization header, so
	 * just send whatever available in the list (maybe empty).
	 */

	h = added.next;
	while (h != &added) {
	    pjsip_hdr *next = h->next;
	    pjsip_msg_add_hdr(tdata->msg, h);
	    h = next;
	}
    } else {
	/* For each realm, add either the cached authorization header
	 * or add an empty authorization header.
	 */
	unsigned i;
	char *uri_str;
	int len;

	uri_str = (char*)pj_pool_alloc(tdata->pool, PJSIP_MAX_URL_SIZE);
	len = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, tdata->msg->line.req.uri,
			      uri_str, PJSIP_MAX_URL_SIZE);
	if (len < 1 || len >= PJSIP_MAX_URL_SIZE)
	    return PJSIP_EURITOOLONG;

	for (i=0; i<sess->cred_cnt; ++i) {
	    pjsip_cred_info *c = &sess->cred_info[i];
	    pjsip_authorization_hdr *h;

	    h = get_header_for_realm(&added, &c->realm);
	    if (h) {
		pj_list_erase(h);
		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)h);
	    } else {
		pjsip_authorization_hdr *hs;

		hs = pjsip_authorization_hdr_create(tdata->pool);
		pj_strdup(tdata->pool, &hs->scheme, &c->scheme);
		pj_strdup(tdata->pool, &hs->credential.digest.username,
			  &c->username);
		pj_strdup(tdata->pool, &hs->credential.digest.realm,
			  &c->realm);
		pj_strdup2(tdata->pool, &hs->credential.digest.uri,
			   uri_str);
		pj_strdup(tdata->pool, &hs->credential.digest.algorithm,
			  &sess->pref.algorithm);

		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hs);
	    }
	}
    }

    return PJ_SUCCESS;
}
Пример #4
0
static pj_status_t bb10_open_capture (struct bb10_stream *stream,
                                      const pjmedia_aud_param *param)
{
    int ret = 0;
    unsigned int rate;
    unsigned long tmp_buf_size;
    int frame_size;
    snd_pcm_channel_info_t pi;
    snd_mixer_group_t group;
    snd_pcm_channel_params_t pp;
    snd_pcm_channel_setup_t setup;

    if (param->rec_id < 0 || param->rec_id >= stream->af->dev_cnt)
        return PJMEDIA_EAUD_INVDEV;

    PJ_ASSERT_RETURN(param->bits_per_sample == 16, PJMEDIA_EAUD_SAMPFORMAT);

    if ((ret=audio_manager_snd_pcm_open_name(AUDIO_TYPE_VIDEO_CHAT,
                                             &stream->ca_pcm,
                                             &stream->ca_audio_manager_handle,
                                             (char*)"voice",
                                             SND_PCM_OPEN_CAPTURE)) < 0)
    {
	TRACE_((THIS_FILE, "audio_manager_snd_pcm_open_name ret = %d", ret));
	return PJMEDIA_EAUD_SYSERR;
    }
    /* Required call from January 2013 gold OS release */
    snd_pcm_plugin_set_disable (stream->ca_pcm, PLUGIN_DISABLE_MMAP);

    /* Required call from January 2013 gold OS release */
    snd_pcm_plugin_set_enable(stream->ca_pcm, PLUGIN_ROUTING);

    /* sample reads the capabilities of the capture */
    memset (&pi, 0, sizeof (pi));
    pi.channel = SND_PCM_CHANNEL_CAPTURE;
    if ((ret = snd_pcm_plugin_info (stream->ca_pcm, &pi)) < 0) {
        TRACE_((THIS_FILE, "snd_pcm_plugin_info ret = %d", ret));
        return PJMEDIA_EAUD_SYSERR;
    }

    /* Request the VoIP parameters
     * These parameters are different to waverec sample
     */
    memset (&pp, 0, sizeof (pp));
    /* Blocking read */
    pp.mode = SND_PCM_MODE_BLOCK;
    pp.channel = SND_PCM_CHANNEL_CAPTURE;
    pp.start_mode = SND_PCM_START_FULL;
    /* Auto-recover from errors */
    pp.stop_mode = SND_PCM_STOP_ROLLOVER;
    pp.buf.block.frag_size = param->samples_per_frame * param->bits_per_sample / 8;
    /* From January 2013 gold OS release. RIM recommend these for capture */
    pp.buf.block.frags_max = 3;
    pp.buf.block.frags_min = 1;
    pp.format.interleave = 1;
    pp.format.rate = param->clock_rate;
    pp.format.voices = param->channel_count;
    pp.format.format = get_alsa_pcm_fmt(param);

    /* make the request */
    if ((ret = snd_pcm_plugin_params (stream->ca_pcm, &pp)) < 0) {
        TRACE_((THIS_FILE, "snd_pcm_plugin_params ret = %d", ret));
        return PJMEDIA_EAUD_SYSERR;
    }

    /* Again based on the sample */
    memset (&setup, 0, sizeof (setup));
    memset (&group, 0, sizeof (group));
    setup.channel = SND_PCM_CHANNEL_CAPTURE;
    setup.mixer_gid = &group.gid;
    if ((ret = snd_pcm_plugin_setup (stream->ca_pcm, &setup)) < 0) {
        TRACE_((THIS_FILE, "snd_pcm_plugin_setup ret = %d", ret));
        return PJMEDIA_EAUD_SYSERR;
    }

    frame_size = setup.buf.block.frag_size;

    if (group.gid.name[0] == 0) {
    } else {
    }

    frame_size = setup.buf.block.frag_size;
    PJ_UNUSED_ARG(frame_size); /* Warning about unused var */

    /* Set clock rate */
    rate = param->clock_rate;
    stream->ca_frames = (unsigned long) param->samples_per_frame /
			param->channel_count;

    /* Set the sound device buffer size and latency */
    if (param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY) {
        tmp_buf_size = rate * param->input_latency_ms / 1000;
    } else {
        tmp_buf_size = rate * PJMEDIA_SND_DEFAULT_REC_LATENCY / 1000;
    }

    stream->param.input_latency_ms = tmp_buf_size * 1000 / rate;

    /* Set our buffer */
    stream->ca_buf_size = stream->ca_frames * param->channel_count *
			  param->bits_per_sample / 8;
    stream->ca_buf = (char *)pj_pool_alloc (stream->pool, stream->ca_buf_size);

    TRACE_((THIS_FILE, "bb10_open_capture: ca_frames = %d clock = %d",
                       stream->ca_frames, param->clock_rate));

    return PJ_SUCCESS;
}
Пример #5
0
/*
 * Open stream.
 */
static pj_status_t open_stream( pjmedia_dir dir,
			        int rec_id,
				int play_id,
				unsigned clock_rate,
				unsigned channel_count,
				unsigned samples_per_frame,
				unsigned bits_per_sample,
				pjmedia_snd_rec_cb rec_cb,
				pjmedia_snd_play_cb play_cb,
				void *user_data,
				pjmedia_snd_stream **p_snd_strm)
{
    pj_pool_t *pool;
    pjmedia_snd_stream *strm;
    pj_status_t status;

    /* Make sure sound subsystem has been initialized with
     * pjmedia_snd_init()
     */
    PJ_ASSERT_RETURN( pool_factory != NULL, PJ_EINVALIDOP );


    /* Can only support 16bits per sample */
    PJ_ASSERT_RETURN(bits_per_sample == BITS_PER_SAMPLE, PJ_EINVAL);

    /* Create and Initialize stream descriptor */
    pool = pj_pool_create(pool_factory, "dsound-dev", 1000, 1000, NULL);
    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);

    strm = pj_pool_zalloc(pool, sizeof(pjmedia_snd_stream));
    strm->dir = dir;
    strm->play_id = play_id;
    strm->rec_id = rec_id;
    strm->pool = pool;
    strm->rec_cb = rec_cb;
    strm->play_cb = play_cb;
    strm->user_data = user_data;
    strm->clock_rate = clock_rate;
    strm->samples_per_frame = samples_per_frame;
    strm->bits_per_sample = bits_per_sample;
    strm->channel_count = channel_count;
    strm->buffer = pj_pool_alloc(pool, samples_per_frame * BYTES_PER_SAMPLE);
    if (!strm->buffer) {
	pj_pool_release(pool);
	return PJ_ENOMEM;
    }

    /*
     * Create event for stopping the worker thread.
     */
    strm->thread_quit_event = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (strm->thread_quit_event == NULL) {
	status = pj_get_os_error();
	pj_pool_release(pool);
	return status;
    }

    /* Create player stream */
    if (dir & PJMEDIA_DIR_PLAYBACK) {
	unsigned buffer_count;
	
	/* Calculate buffer count, in frame unit */
	buffer_count = clock_rate * snd_output_latency / samples_per_frame /
		       1000;
	/* There must always be one more buffer than required for the latency */
	buffer_count += 1;
	if (buffer_count < MIN_PACKET_BUFFER_COUNT)
	    buffer_count = MIN_PACKET_BUFFER_COUNT;
	if (buffer_count > MAX_PACKET_BUFFER_COUNT)
	    buffer_count = MAX_PACKET_BUFFER_COUNT;

	status = init_player_stream( &strm->play_strm, play_id, clock_rate,
				     channel_count, samples_per_frame,
				     buffer_count );
	if (status != PJ_SUCCESS) {
	    pjmedia_snd_stream_close(strm);
	    return status;
	}
    }

    /* Create capture stream */
    if (dir & PJMEDIA_DIR_CAPTURE) {
	unsigned buffer_count;
	
	/* Calculate buffer count, in frame unit */
	buffer_count = clock_rate * snd_input_latency / samples_per_frame /
		       1000;
	if (buffer_count < MIN_PACKET_BUFFER_COUNT)
	    buffer_count = MIN_PACKET_BUFFER_COUNT;
	if (buffer_count > MAX_PACKET_BUFFER_COUNT)
	    buffer_count = MAX_PACKET_BUFFER_COUNT;

	status = init_capture_stream( &strm->rec_strm, rec_id, clock_rate,
				      channel_count, samples_per_frame,
				      buffer_count);
	if (status != PJ_SUCCESS) {
	    pjmedia_snd_stream_close(strm);
	    return status;
	}
    }


    /* Create and start the thread */
    status = pj_thread_create(pool, "dsound", &dsound_dev_thread, strm,
			      0, 0, &strm->thread);
    if (status != PJ_SUCCESS) {
	pjmedia_snd_stream_close(strm);
	return status;
    }

    *p_snd_strm = strm;

    return PJ_SUCCESS;
}
Пример #6
0
/*
 * Handler to receive incoming MESSAGE
 */
static pj_bool_t im_on_rx_request(pjsip_rx_data *rdata)
{
    pj_str_t from, to;
    pjsip_accept_hdr *accept_hdr;
    pjsip_msg *msg;
    pj_status_t status;

    msg = rdata->msg_info.msg;

    /* Only want to handle MESSAGE requests. */
    if (pjsip_method_cmp(&msg->line.req.method, &pjsip_message_method) != 0) {
	return PJ_FALSE;
    }


    /* Should not have any transaction attached to rdata. */
    PJ_ASSERT_RETURN(pjsip_rdata_get_tsx(rdata)==NULL, PJ_FALSE);

    /* Should not have any dialog attached to rdata. */
    PJ_ASSERT_RETURN(pjsip_rdata_get_dlg(rdata)==NULL, PJ_FALSE);

    /* Check if we can accept the message. */
    if (!pjsua_im_accept_pager(rdata, &accept_hdr)) {
	pjsip_hdr hdr_list;

	pj_list_init(&hdr_list);
	pj_list_push_back(&hdr_list, accept_hdr);

	pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 
				      PJSIP_SC_NOT_ACCEPTABLE_HERE, NULL, 
				      &hdr_list, NULL);
	return PJ_TRUE;
    }
    
    /* Respond with 200 first, so that remote doesn't retransmit in case
     * the UI takes too long to process the message. 
     */
    status = pjsip_endpt_respond( pjsua_var.endpt, NULL, rdata, 200, NULL,
				  NULL, NULL, NULL);

    /* For the source URI, we use Contact header if present, since
     * Contact header contains the port number information. If this is
     * not available, then use From header.
     */
    from.ptr = (char*)pj_pool_alloc(rdata->tp_info.pool, PJSIP_MAX_URL_SIZE);
    from.slen = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, 
				rdata->msg_info.from->uri,
				from.ptr, PJSIP_MAX_URL_SIZE);

    if (from.slen < 1)
	from = pj_str("<--URI is too long-->");

    /* Build the To text. */
    to.ptr = (char*) pj_pool_alloc(rdata->tp_info.pool, PJSIP_MAX_URL_SIZE);
    to.slen = pjsip_uri_print( PJSIP_URI_IN_FROMTO_HDR, 
			       rdata->msg_info.to->uri,
			       to.ptr, PJSIP_MAX_URL_SIZE);
    if (to.slen < 1)
	to = pj_str("<--URI is too long-->");

    /* Process pager. */
    pjsua_im_process_pager(-1, &from, &to, rdata);

    /* Done. */
    return PJ_TRUE;
}
Пример #7
0
static pj_status_t factory_create_streamBDIMAD(pjmedia_aud_dev_factory *f,
                                    const pjmedia_aud_param *param,
                                    pjmedia_aud_rec_cb rec_cb,
                                    pjmedia_aud_play_cb play_cb,
                                    void *user_data,
                                    pjmedia_aud_stream **p_aud_strm)
{
    struct bd_factory *wf = (struct bd_factory*)f;
    pj_pool_t *pool;
    struct bd_stream *strm;
    pj_uint8_t silence_char;
    pj_status_t status;

    switch (param->ext_fmt.id) {
    case PJMEDIA_FORMAT_L16:
	silence_char = '\0';
	break;
    default:
	return PJMEDIA_EAUD_BADFORMAT;
    }

    /* Create and Initialize stream descriptor */
    pool = pj_pool_create(wf->pf, "BDIMAD_STREAM", 1000, 1000, NULL);
    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);

    strm = PJ_POOL_ZALLOC_T(pool, struct bd_stream);
    pj_memcpy(&strm->param, param, sizeof(*param));
    strm->pool = pool;
    strm->rec_cb = rec_cb;
    strm->play_cb = play_cb;
    strm->user_data = user_data;
    strm->fmt_id = (pjmedia_format_id)param->ext_fmt.id;
    strm->silence_char = silence_char;
    strm->channel_count = param->channel_count;
    strm->samples_per_frame = param->samples_per_frame;

    if (param->dir & PJMEDIA_DIR_CAPTURE_PLAYBACK) {
        status = init_streams(wf, strm, param);

        if (status != PJ_SUCCESS) {
            stream_destroyBDIMAD(&strm->base);
            return status;
        }
    } else {
        stream_destroyBDIMAD(&strm->base);
        return PJMEDIA_EAUD_ERR;
    }

    strm->rec_buf = (pj_int16_t*)pj_pool_alloc(pool, 
		    strm->bytes_per_frame);
    if (!strm->rec_buf) {
        pj_pool_release(pool);
        return PJ_ENOMEM;
    }
    strm->rec_buf_count = 0;

    strm->play_buf = (pj_int16_t*)pj_pool_alloc(pool, 
		     strm->bytes_per_frame);
    if (!strm->play_buf) {
        pj_pool_release(pool);
        return PJ_ENOMEM;
    }
    strm->play_buf_count = 0;

    /* Apply the remaining settings */
    if(param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) {
        stream_set_capBDIMAD(&strm->base, 
			     PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING, 
			     &param->output_vol);
    }
    if(param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING) {
        stream_set_capBDIMAD(&strm->base, 
			     PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING, 
			     &param->input_vol);
    }
    if(param->flags & PJMEDIA_AUD_DEV_CAP_EC) {
        stream_set_capBDIMAD(&strm->base, 
			     PJMEDIA_AUD_DEV_CAP_EC, 
			     &param->ec_enabled);
    }

    strm->base.op = &stream_op;
    *p_aud_strm = &strm->base;

    return PJ_SUCCESS;
}
Пример #8
0
/* Internal: Create both player and recorder stream */
static pj_status_t create_bidir_stream(struct pa_aud_factory *pa,
				       const pjmedia_aud_param *param,
				       pjmedia_aud_rec_cb rec_cb,
				       pjmedia_aud_play_cb play_cb,
				       void *user_data,
				       pjmedia_aud_stream **p_snd_strm)
{
    pj_pool_t *pool;
    pjmedia_aud_dev_index rec_id, play_id;
    struct pa_aud_stream *stream;
    PaStream *paStream = NULL;
    PaStreamParameters inputParam;
    PaStreamParameters outputParam;
    int sampleFormat;
    const PaDeviceInfo *paRecDevInfo = NULL;
    const PaDeviceInfo *paPlayDevInfo = NULL;
    const PaHostApiInfo *paRecHostApiInfo = NULL;
    const PaHostApiInfo *paPlayHostApiInfo = NULL;
    const PaStreamInfo *paSI;
    unsigned paFrames, paRate, paInputLatency, paOutputLatency;
    PaError err;

    PJ_ASSERT_RETURN(play_cb && rec_cb && p_snd_strm, PJ_EINVAL);

    rec_id = param->rec_id;
    if (rec_id < 0) {
	rec_id = pa_get_default_input_dev(param->channel_count);
	if (rec_id < 0) {
	    /* No such device. */
	    return PJMEDIA_EAUD_NODEFDEV;
	}
    }

    paRecDevInfo = Pa_GetDeviceInfo(rec_id);
    if (!paRecDevInfo) {
	/* Assumed it is "No such device" error. */
	return PJMEDIA_EAUD_INVDEV;
    }

    play_id = param->play_id;
    if (play_id < 0) {
	play_id = pa_get_default_output_dev(param->channel_count);
	if (play_id < 0) {
	    /* No such device. */
	    return PJMEDIA_EAUD_NODEFDEV;
	}
    } 

    paPlayDevInfo = Pa_GetDeviceInfo(play_id);
    if (!paPlayDevInfo) {
	/* Assumed it is "No such device" error. */
	return PJMEDIA_EAUD_INVDEV;
    }


    if (param->bits_per_sample == 8)
	sampleFormat = paUInt8;
    else if (param->bits_per_sample == 16)
	sampleFormat = paInt16;
    else if (param->bits_per_sample == 32)
	sampleFormat = paInt32;
    else
	return PJMEDIA_EAUD_SAMPFORMAT;
    
    pool = pj_pool_create(pa->pf, "sndstream", 1024, 1024, NULL);
    if (!pool)
	return PJ_ENOMEM;

    stream = PJ_POOL_ZALLOC_T(pool, struct pa_aud_stream);
    stream->pool = pool;
    pj_strdup2_with_null(pool, &stream->name, paRecDevInfo->name);
    stream->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
    stream->play_id = play_id;
    stream->rec_id = rec_id;
    stream->user_data = user_data;
    stream->samples_per_sec = param->clock_rate;
    stream->samples_per_frame = param->samples_per_frame;
    stream->bytes_per_sample = param->bits_per_sample / 8;
    stream->channel_count = param->channel_count;
    stream->rec_cb = rec_cb;
    stream->play_cb = play_cb;

    stream->rec_buf = (pj_int16_t*)pj_pool_alloc(pool, 
		      stream->samples_per_frame * stream->bytes_per_sample);
    stream->rec_buf_count = 0;

    stream->play_buf = (pj_int16_t*)pj_pool_alloc(pool, 
		       stream->samples_per_frame * stream->bytes_per_sample);
    stream->play_buf_count = 0;

    pj_bzero(&inputParam, sizeof(inputParam));
    inputParam.device = rec_id;
    inputParam.channelCount = param->channel_count;
    inputParam.hostApiSpecificStreamInfo = NULL;
    inputParam.sampleFormat = sampleFormat;
    if (param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY)
	inputParam.suggestedLatency = param->input_latency_ms / 1000.0;
    else
	inputParam.suggestedLatency = PJMEDIA_SND_DEFAULT_REC_LATENCY / 1000.0;

    paRecHostApiInfo = Pa_GetHostApiInfo(paRecDevInfo->hostApi);

    pj_bzero(&outputParam, sizeof(outputParam));
    outputParam.device = play_id;
    outputParam.channelCount = param->channel_count;
    outputParam.hostApiSpecificStreamInfo = NULL;
    outputParam.sampleFormat = sampleFormat;
    if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY)
	outputParam.suggestedLatency=param->output_latency_ms / 1000.0;
    else
	outputParam.suggestedLatency=PJMEDIA_SND_DEFAULT_PLAY_LATENCY/1000.0;

    paPlayHostApiInfo = Pa_GetHostApiInfo(paPlayDevInfo->hostApi);

    /* Frames in PortAudio is number of samples in a single channel */
    paFrames = param->samples_per_frame / param->channel_count;

    /* If both input and output are on the same device, open a single stream
     * for both input and output.
     */
    if (rec_id == play_id) {
	err = Pa_OpenStream( &paStream, &inputParam, &outputParam,
			     param->clock_rate, paFrames, 
			     paClipOff, &PaRecorderPlayerCallback, stream );
	if (err == paNoError) {
	    /* Set play stream and record stream to the same stream */
	    stream->play_strm = stream->rec_strm = paStream;
	}
    } else {
	err = -1;
    }

    /* .. otherwise if input and output are on the same device, OR if we're
     * unable to open a bidirectional stream, then open two separate
     * input and output stream.
     */
    if (paStream == NULL) {
	/* Open input stream */
	err = Pa_OpenStream( &stream->rec_strm, &inputParam, NULL,
			     param->clock_rate, paFrames, 
			     paClipOff, &PaRecorderCallback, stream );
	if (err == paNoError) {
	    /* Open output stream */
	    err = Pa_OpenStream( &stream->play_strm, NULL, &outputParam,
				 param->clock_rate, paFrames, 
				 paClipOff, &PaPlayerCallback, stream );
	    if (err != paNoError)
		Pa_CloseStream(stream->rec_strm);
	}
    }

    if (err != paNoError) {
	pj_pool_release(pool);
	return PJMEDIA_AUDIODEV_ERRNO_FROM_PORTAUDIO(err);
    }

    paSI = Pa_GetStreamInfo(stream->rec_strm);
    paRate = (unsigned)(paSI->sampleRate);
    paInputLatency = (unsigned)(paSI->inputLatency * 1000);
    paSI = Pa_GetStreamInfo(stream->play_strm);
    paOutputLatency = (unsigned)(paSI->outputLatency * 1000);

    PJ_LOG(5,(THIS_FILE, "Opened device %s(%s)/%s(%s) for recording and "
			 "playback, sample rate=%d, ch=%d, "
			 "bits=%d, %d samples per frame, input latency=%d ms, "
			 "output latency=%d ms",
			 paRecDevInfo->name, paRecHostApiInfo->name,
			 paPlayDevInfo->name, paPlayHostApiInfo->name,
			 paRate, param->channel_count,
			 param->bits_per_sample, param->samples_per_frame,
			 paInputLatency, paOutputLatency));

    *p_snd_strm = &stream->base;

    return PJ_SUCCESS;
}
Пример #9
0
static pj_status_t open_capture (struct alsa_stream* stream,
			         const pjmedia_aud_param *param)
{
    snd_pcm_hw_params_t* params;
    snd_pcm_format_t format;
    int result;
    unsigned int rate;
    snd_pcm_uframes_t tmp_buf_size;
    snd_pcm_uframes_t tmp_period_size;

    if (param->rec_id < 0 || param->rec_id >= stream->af->dev_cnt)
	return PJMEDIA_EAUD_INVDEV;

    /* Open PCM for capture */
    PJ_LOG (5,(THIS_FILE, "open_capture: Open capture device '%s'",
	       stream->af->devs[param->rec_id].name));
    result = snd_pcm_open (&stream->ca_pcm,
		            stream->af->devs[param->rec_id].name,
			   SND_PCM_STREAM_CAPTURE,
			   0);
    if (result < 0)
	return PJMEDIA_EAUD_SYSERR;

    /* Allocate a hardware parameters object. */
    snd_pcm_hw_params_alloca (&params);

    /* Fill it in with default values. */
    snd_pcm_hw_params_any (stream->ca_pcm, params);

    /* Set interleaved mode */
    snd_pcm_hw_params_set_access (stream->ca_pcm, params,
				  SND_PCM_ACCESS_RW_INTERLEAVED);

    /* Set format */
    switch (param->bits_per_sample) {
    case 8:
	TRACE_((THIS_FILE, "open_capture: set format SND_PCM_FORMAT_S8"));
	format = SND_PCM_FORMAT_S8;
	break;
    case 16:
	TRACE_((THIS_FILE, "open_capture: set format SND_PCM_FORMAT_S16_LE"));
	format = SND_PCM_FORMAT_S16_LE;
	break;
    case 24:
	TRACE_((THIS_FILE, "open_capture: set format SND_PCM_FORMAT_S24_LE"));
	format = SND_PCM_FORMAT_S24_LE;
	break;
    case 32:
	TRACE_((THIS_FILE, "open_capture: set format SND_PCM_FORMAT_S32_LE"));
	format = SND_PCM_FORMAT_S32_LE;
	break;
    default:
	TRACE_((THIS_FILE, "open_capture: set format SND_PCM_FORMAT_S16_LE"));
	format = SND_PCM_FORMAT_S16_LE;
	break;
    }
    snd_pcm_hw_params_set_format (stream->ca_pcm, params, format);

    /* Set number of channels */
    TRACE_((THIS_FILE, "open_capture: set channels: %d",
	    param->channel_count));
    snd_pcm_hw_params_set_channels (stream->ca_pcm, params,
				    param->channel_count);

    /* Set clock rate */
    rate = param->clock_rate;
    TRACE_((THIS_FILE, "open_capture: set clock rate: %d", rate));
    snd_pcm_hw_params_set_rate_near (stream->ca_pcm, params, &rate, NULL);
    TRACE_((THIS_FILE, "open_capture: clock rate set to: %d", rate));

    /* Set period size to samples_per_frame frames. */
    stream->ca_frames = (snd_pcm_uframes_t) param->samples_per_frame /
					    param->channel_count;
    TRACE_((THIS_FILE, "open_capture: set period size: %d",
	    stream->ca_frames));
    tmp_period_size = stream->ca_frames;
    snd_pcm_hw_params_set_period_size_near (stream->ca_pcm, params,
					    &tmp_period_size, NULL);
    TRACE_((THIS_FILE, "open_capture: period size set to: %d",
	    tmp_period_size));

    /* Set the sound device buffer size and latency */
    if (param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY)
	tmp_buf_size = (rate / 1000) * param->input_latency_ms;
    else
	tmp_buf_size = (rate / 1000) * PJMEDIA_SND_DEFAULT_REC_LATENCY;
    snd_pcm_hw_params_set_buffer_size_near (stream->ca_pcm, params,
					    &tmp_buf_size);
    stream->param.input_latency_ms = tmp_buf_size / (rate / 1000);

    /* Set our buffer */
    stream->ca_buf_size = stream->ca_frames * param->channel_count *
			  (param->bits_per_sample/8);
    stream->ca_buf = (char*) pj_pool_alloc (stream->pool, stream->ca_buf_size);

    TRACE_((THIS_FILE, "open_capture: buffer size set to: %d",
	    (int)tmp_buf_size));
    TRACE_((THIS_FILE, "open_capture: capture_latency set to: %d ms",
	    (int)stream->param.input_latency_ms));

    /* Activate the parameters */
    result = snd_pcm_hw_params (stream->ca_pcm, params);
    if (result < 0) {
	snd_pcm_close (stream->ca_pcm);
	return PJMEDIA_EAUD_SYSERR;
    }

    PJ_LOG (5,(THIS_FILE, "Opened device alsa(%s) for capture, sample rate=%d"
	       ", ch=%d, bits=%d, period size=%d frames, latency=%d ms",
	       stream->af->devs[param->rec_id].name,
	       rate, param->channel_count,
	       param->bits_per_sample, stream->ca_frames,
	       (int)stream->param.input_latency_ms));

    return PJ_SUCCESS;
}
Пример #10
0
/*
 * Create the echo canceller. 
 */
PJ_DEF(pj_status_t) pjmedia_echo_create2(pj_pool_t *pool,
					 unsigned clock_rate,
					 unsigned channel_count,
					 unsigned samples_per_frame,
					 unsigned tail_ms,
					 unsigned latency_ms,
					 unsigned options,
					 pjmedia_echo_state **p_echo )
{
    unsigned ptime, lat_cnt;
    unsigned delay_buf_opt = 0;
    pjmedia_echo_state *ec;
    pj_status_t status;

    /* Create new pool and instantiate and init the EC */
    pool = pj_pool_create(pool->factory, "ec%p", 256, 256, NULL);
    ec = PJ_POOL_ZALLOC_T(pool, struct pjmedia_echo_state);
    ec->pool = pool;
    ec->obj_name = pool->obj_name;
    ec->samples_per_frame = samples_per_frame;
    ec->frm_buf = (pj_int16_t*)pj_pool_alloc(pool, samples_per_frame<<1);
    pj_list_init(&ec->lat_buf);
    pj_list_init(&ec->lat_free);

    /* Select the backend algorithm */
    if (0) {
	/* Dummy */
	;
#if defined(PJMEDIA_HAS_SPEEX_AEC) && PJMEDIA_HAS_SPEEX_AEC!=0
    } else if ((options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_SPEEX ||
	       (options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_DEFAULT) 
    {
	ec->op = &speex_aec_op;
#endif

#if defined(PJMEDIA_HAS_INTEL_IPP_AEC) && PJMEDIA_HAS_INTEL_IPP_AEC!=0
    } else if ((options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_IPP ||
	       (options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_DEFAULT)
    {
	ec->op = &ipp_aec_op;

#endif

    } else {
	ec->op = &echo_supp_op;
    }

    /* Completeness check for EC operation playback and capture, they must
     * be implemented both or none.
     */
    pj_assert(!ec->op->ec_capture == !ec->op->ec_playback);

    PJ_LOG(5,(ec->obj_name, "Creating %s", ec->op->name));

    /* Instantiate EC object */
    status = (*ec->op->ec_create)(pool, clock_rate, channel_count, 
				  samples_per_frame, tail_ms, 
				  options, &ec->state);
    if (status != PJ_SUCCESS) {
	pj_pool_release(pool);
	return status;
    }

    /* If EC algo does not have playback and capture callbakcs,
     * create latency buffer and delay buffer to handle drift.
     */
    if (ec->op->ec_playback && ec->op->ec_capture) {
	latency_ms = 0;
    } else {
	/* Create latency buffers */
	ptime = samples_per_frame * 1000 / clock_rate;
	if (latency_ms > ptime) {
	    /* Normalize latency with delaybuf/WSOLA latency */
	    latency_ms -= PJ_MIN(ptime, PJMEDIA_WSOLA_DELAY_MSEC);
	}
	if (latency_ms < ptime) {
	    /* Give at least one frame delay to simplify programming */
	    latency_ms = ptime;
	}
	lat_cnt = latency_ms / ptime;
	while (lat_cnt--)  {
	    struct frame *frm;

	    frm = (struct frame*) pj_pool_alloc(pool, (samples_per_frame<<1) +
						      sizeof(struct frame));
	    pj_list_push_back(&ec->lat_free, frm);
	}

	/* Create delay buffer to compensate drifts */
	if (options & PJMEDIA_ECHO_USE_SIMPLE_FIFO)
	    delay_buf_opt |= PJMEDIA_DELAY_BUF_SIMPLE_FIFO;
	status = pjmedia_delay_buf_create(ec->pool, ec->obj_name, clock_rate, 
					  samples_per_frame, channel_count,
					  (PJMEDIA_SOUND_BUFFER_COUNT+1) * ptime,
					  delay_buf_opt, &ec->delay_buf);
	if (status != PJ_SUCCESS) {
	    pj_pool_release(pool);
	    return status;
	}
    }

    PJ_LOG(4,(ec->obj_name, 
	      "%s created, clock_rate=%d, channel=%d, "
	      "samples per frame=%d, tail length=%d ms, "
	      "latency=%d ms", 
	      ec->op->name, clock_rate, channel_count, samples_per_frame,
	      tail_ms, latency_ms));

    /* Done */
    *p_echo = ec;

    return PJ_SUCCESS;
}
Пример #11
0
/* Internal: create playback stream */
static pj_status_t create_play_stream(struct pa_aud_factory *pa,
				      const pjmedia_aud_param *param,
				      pjmedia_aud_play_cb play_cb,
				      void *user_data,
				      pjmedia_aud_stream **p_snd_strm)
{
    pj_pool_t *pool;
    pjmedia_aud_dev_index play_id;
    struct pa_aud_stream *stream;
    PaStreamParameters outputParam;
    int sampleFormat;
    const PaDeviceInfo *paDevInfo = NULL;
    const PaHostApiInfo *paHostApiInfo = NULL;
    const PaStreamInfo *paSI;
    unsigned paFrames, paRate, paLatency;
    PaError err;

    PJ_ASSERT_RETURN(play_cb && p_snd_strm, PJ_EINVAL);

    play_id = param->play_id;
    if (play_id < 0) {
	play_id = pa_get_default_output_dev(param->channel_count);
	if (play_id < 0) {
	    /* No such device. */
	    return PJMEDIA_EAUD_NODEFDEV;
	}
    } 

    paDevInfo = Pa_GetDeviceInfo(play_id);
    if (!paDevInfo) {
	/* Assumed it is "No such device" error. */
	return PJMEDIA_EAUD_INVDEV;
    }

    if (param->bits_per_sample == 8)
	sampleFormat = paUInt8;
    else if (param->bits_per_sample == 16)
	sampleFormat = paInt16;
    else if (param->bits_per_sample == 32)
	sampleFormat = paInt32;
    else
	return PJMEDIA_EAUD_SAMPFORMAT;
    
    pool = pj_pool_create(pa->pf, "playstrm", 1024, 1024, NULL);
    if (!pool)
	return PJ_ENOMEM;

    stream = PJ_POOL_ZALLOC_T(pool, struct pa_aud_stream);
    stream->pool = pool;
    pj_strdup2_with_null(pool, &stream->name, paDevInfo->name);
    stream->dir = PJMEDIA_DIR_PLAYBACK;
    stream->play_id = play_id;
    stream->rec_id = -1;
    stream->user_data = user_data;
    stream->samples_per_sec = param->clock_rate;
    stream->samples_per_frame = param->samples_per_frame;
    stream->bytes_per_sample = param->bits_per_sample / 8;
    stream->channel_count = param->channel_count;
    stream->play_cb = play_cb;

    stream->play_buf = (pj_int16_t*)pj_pool_alloc(pool, 
					    stream->samples_per_frame * 
					    stream->bytes_per_sample);
    stream->play_buf_count = 0;

    pj_bzero(&outputParam, sizeof(outputParam));
    outputParam.device = play_id;
    outputParam.channelCount = param->channel_count;
    outputParam.hostApiSpecificStreamInfo = NULL;
    outputParam.sampleFormat = sampleFormat;
    if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY)
	outputParam.suggestedLatency=param->output_latency_ms / 1000.0;
    else
	outputParam.suggestedLatency=PJMEDIA_SND_DEFAULT_PLAY_LATENCY/1000.0;

    paHostApiInfo = Pa_GetHostApiInfo(paDevInfo->hostApi);

    /* Frames in PortAudio is number of samples in a single channel */
    paFrames = param->samples_per_frame / param->channel_count;

    err = Pa_OpenStream( &stream->play_strm, NULL, &outputParam,
			 param->clock_rate,  paFrames, 
			 paClipOff, &PaPlayerCallback, stream );
    if (err != paNoError) {
	pj_pool_release(pool);
	return PJMEDIA_AUDIODEV_ERRNO_FROM_PORTAUDIO(err);
    }

    paSI = Pa_GetStreamInfo(stream->play_strm);
    paRate = (unsigned)(paSI->sampleRate);
    paLatency = (unsigned)(paSI->outputLatency * 1000);

    PJ_LOG(5,(THIS_FILE, "Opened device %d: %s(%s) for playing, sample rate=%d"
			 ", ch=%d, "
			 "bits=%d, %d samples per frame, latency=%d ms",
			 play_id, paDevInfo->name, paHostApiInfo->name, 
			 paRate, param->channel_count,
		 	 param->bits_per_sample, param->samples_per_frame, 
			 paLatency));

    *p_snd_strm = &stream->base;

    return PJ_SUCCESS;
}
Пример #12
0
PJ_DEF(pj_status_t) pjmedia_resample_port_create( pj_pool_t *pool,
						  pjmedia_port *dn_port,
						  unsigned clock_rate,
						  unsigned opt,
						  pjmedia_port **p_port  )
{
    const pj_str_t name = pj_str("resample");
    struct resample_port *rport;
    unsigned ptime;
    pj_status_t status;

    /* Validate arguments. */
    PJ_ASSERT_RETURN(pool && dn_port && clock_rate && p_port, PJ_EINVAL);

    /* Only supports 16bit samples per frame */
    PJ_ASSERT_RETURN(dn_port->info.bits_per_sample == 16, PJMEDIA_ENCBITS);

    ptime = dn_port->info.samples_per_frame * 1000 / 
	    dn_port->info.clock_rate;
    
    /* Create and initialize port. */
    rport = PJ_POOL_ZALLOC_T(pool, struct resample_port);
    PJ_ASSERT_RETURN(rport != NULL, PJ_ENOMEM);

    pjmedia_port_info_init(&rport->base.info, &name, SIGNATURE, clock_rate,
			   dn_port->info.channel_count, BYTES_PER_SAMPLE * 8, 
			   clock_rate * ptime / 1000);

    rport->dn_port = dn_port;
    rport->options = opt;


    /* Create buffers. 
     * We need separate buffer for get_frame() and put_frame() since
     * both functions may run simultaneously.
     */
    rport->get_buf = (pj_int16_t*)
		     pj_pool_alloc(pool, dn_port->info.bytes_per_frame);
    PJ_ASSERT_RETURN(rport->get_buf != NULL, PJ_ENOMEM);

    rport->put_buf = (pj_int16_t*)
		     pj_pool_alloc(pool, dn_port->info.bytes_per_frame);
    PJ_ASSERT_RETURN(rport->put_buf != NULL, PJ_ENOMEM);


    /* Create "get_frame" resample */
    status = pjmedia_resample_create(pool, 
				     (opt&PJMEDIA_RESAMPLE_USE_LINEAR)==0,
				     (opt&PJMEDIA_RESAMPLE_USE_SMALL_FILTER)==0,
				     dn_port->info.channel_count,
				     dn_port->info.clock_rate, 
				     rport->base.info.clock_rate,
				     dn_port->info.samples_per_frame, 
				     &rport->resample_get);
    if (status != PJ_SUCCESS)
	return status;

    /* Create "put_frame" resample */
    status = pjmedia_resample_create(pool, 
				     (opt&PJMEDIA_RESAMPLE_USE_LINEAR)==0, 
				     (opt&PJMEDIA_RESAMPLE_USE_SMALL_FILTER)==0,
				     dn_port->info.channel_count,
				     rport->base.info.clock_rate, 
				     dn_port->info.clock_rate,
				     rport->base.info.samples_per_frame,
				     &rport->resample_put);

    /* Media port interface */
    rport->base.get_frame = &resample_get_frame;
    rport->base.put_frame = &resample_put_frame;
    rport->base.on_destroy = &resample_destroy;


    /* Done */
    *p_port = &rport->base;

    return PJ_SUCCESS;
}
Пример #13
0
static pj_status_t test_init(void)
{
    struct stream_cfg strm_cfg;
    pj_status_t status;

    /* Must init PJLIB first: */
    status = pj_init();
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

    /* Must create a pool factory before we can allocate any memory. */
    pj_caching_pool_init(&g_app.cp, &pj_pool_factory_default_policy, 0);

    /* Pool */
    g_app.pool = pj_pool_create(&g_app.cp.factory, "g_app", 512, 512, NULL);

    /* Log file */
    if (g_app.cfg.log_file) {
	status = pj_file_open(g_app.pool, g_app.cfg.log_file, 
			      PJ_O_WRONLY,
			      &g_app.log_fd);
	if (status != PJ_SUCCESS) {
	    jbsim_perror("Error writing output file", status);
	    goto on_error;
	}

	pj_log_set_decor(PJ_LOG_HAS_SENDER | PJ_LOG_HAS_COLOR | PJ_LOG_HAS_LEVEL_TEXT);
	pj_log_set_log_func(&log_cb);
    }

    /* 
     * Initialize media endpoint.
     * This will implicitly initialize PJMEDIA too.
     */
    status = pjmedia_endpt_create(&g_app.cp.factory, NULL, 0, &g_app.endpt);
    if (status != PJ_SUCCESS) {
	jbsim_perror("Error creating media endpoint", status);
	goto on_error;
    }

    /* Register codecs */
    pjmedia_codec_register_audio_codecs(g_app.endpt, NULL);

    /* Create the loop transport */
    status = pjmedia_transport_loop_create(g_app.endpt, &g_app.loop);
    if (status != PJ_SUCCESS) {
	jbsim_perror("Error creating loop transport", status);
	goto on_error;
    }

    /* Create transmitter stream */
    pj_bzero(&strm_cfg, sizeof(strm_cfg));
    strm_cfg.name = "tx";
    strm_cfg.dir = PJMEDIA_DIR_ENCODING;
    strm_cfg.codec = g_app.cfg.codec;
    strm_cfg.ptime = g_app.cfg.tx_ptime;
    strm_cfg.dtx = g_app.cfg.tx_dtx;
    strm_cfg.plc = PJ_TRUE;
    status = stream_init(&strm_cfg, &g_app.tx);
    if (status != PJ_SUCCESS) 
	goto on_error;

    /* Create transmitter WAV */
    status = pjmedia_wav_player_port_create(g_app.pool, 
					    g_app.cfg.tx_wav_in,
					    g_app.cfg.tx_ptime,
					    0,
					    0,
					    &g_app.tx_wav);
    if (status != PJ_SUCCESS) {
	jbsim_perror("Error reading input WAV file", status);
	goto on_error;
    }

    /* Make sure stream and WAV parameters match */
    if (PJMEDIA_PIA_SRATE(&g_app.tx_wav->info) != PJMEDIA_PIA_SRATE(&g_app.tx->port->info) ||
	PJMEDIA_PIA_CCNT(&g_app.tx_wav->info) != PJMEDIA_PIA_CCNT(&g_app.tx->port->info))
    {
	jbsim_perror("Error: Input WAV file has different clock rate "
		     "or number of channels than the codec", PJ_SUCCESS);
	goto on_error;
    }


    /* Create receiver */
    pj_bzero(&strm_cfg, sizeof(strm_cfg));
    strm_cfg.name = "rx";
    strm_cfg.dir = PJMEDIA_DIR_DECODING;
    strm_cfg.codec = g_app.cfg.codec;
    strm_cfg.ptime = g_app.cfg.rx_ptime;
    strm_cfg.dtx = PJ_TRUE;
    strm_cfg.plc = g_app.cfg.rx_plc;
    status = stream_init(&strm_cfg, &g_app.rx);
    if (status != PJ_SUCCESS) 
	goto on_error;

    /* Create receiver WAV */
    status = pjmedia_wav_writer_port_create(g_app.pool, 
					    g_app.cfg.rx_wav_out,
					    PJMEDIA_PIA_SRATE(&g_app.rx->port->info),
					    PJMEDIA_PIA_CCNT(&g_app.rx->port->info),
					    PJMEDIA_PIA_SPF(&g_app.rx->port->info),
					    PJMEDIA_PIA_BITS(&g_app.rx->port->info),
					    0,
					    0,
					    &g_app.rx_wav);
    if (status != PJ_SUCCESS) {
	jbsim_perror("Error creating output WAV file", status);
	goto on_error;
    }


    /* Frame buffer */
    g_app.framebuf = (pj_int16_t*)
		     pj_pool_alloc(g_app.pool,
				   MAX(PJMEDIA_PIA_SPF(&g_app.rx->port->info),
				       PJMEDIA_PIA_SPF(&g_app.tx->port->info)) * sizeof(pj_int16_t));


    /* Set the receiver in the loop transport */
    pjmedia_transport_loop_disable_rx(g_app.loop, g_app.tx->strm, PJ_TRUE);

    /* Done */
    return PJ_SUCCESS;

on_error:
    test_destroy();
    return status;
}
Пример #14
0
static pj_status_t test_init(void)
{
    struct stream_cfg strm_cfg;
    pj_status_t status;

    /* Must init PJLIB first: */
    status = pj_init();
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

    /* Must create a pool factory before we can allocate any memory. */
    pj_caching_pool_init(&g_app.cp, &pj_pool_factory_default_policy, 0);

    /* Pool */
    g_app.pool = pj_pool_create(&g_app.cp.factory, "g_app", 512, 512, NULL);

    /* Log file */
    if (g_app.cfg.log_file) {
	status = pj_file_open(g_app.pool, g_app.cfg.log_file, 
			      PJ_O_WRONLY,
			      &g_app.log_fd);
	if (status != PJ_SUCCESS) {
	    jbsim_perror("Error writing output file", status);
	    goto on_error;
	}

	pj_log_set_decor(PJ_LOG_HAS_SENDER | PJ_LOG_HAS_COLOR | PJ_LOG_HAS_LEVEL_TEXT);
	pj_log_set_log_func(&log_cb);
    }

    /* 
     * Initialize media endpoint.
     * This will implicitly initialize PJMEDIA too.
     */
    status = pjmedia_endpt_create(&g_app.cp.factory, NULL, 0, &g_app.endpt);
    if (status != PJ_SUCCESS) {
	jbsim_perror("Error creating media endpoint", status);
	goto on_error;
    }

    /* Register codecs */
#if defined(PJMEDIA_HAS_GSM_CODEC) && PJMEDIA_HAS_GSM_CODEC != 0
    pjmedia_codec_gsm_init(g_app.endpt);
#endif
#if defined(PJMEDIA_HAS_G711_CODEC) && PJMEDIA_HAS_G711_CODEC!=0
    pjmedia_codec_g711_init(g_app.endpt);
#endif
#if defined(PJMEDIA_HAS_SPEEX_CODEC) && PJMEDIA_HAS_SPEEX_CODEC!=0
    pjmedia_codec_speex_init(g_app.endpt, 0, PJMEDIA_CODEC_SPEEX_DEFAULT_QUALITY,
			     PJMEDIA_CODEC_SPEEX_DEFAULT_COMPLEXITY);
#endif
#if defined(PJMEDIA_HAS_G722_CODEC) && (PJMEDIA_HAS_G722_CODEC != 0)
    pjmedia_codec_g722_init(g_app.endpt);
#endif
#if defined(PJMEDIA_HAS_ILBC_CODEC) && PJMEDIA_HAS_ILBC_CODEC != 0
    /* Init ILBC with mode=20 to make the losts occur at the same
     * places as other codecs.
     */
    pjmedia_codec_ilbc_init(g_app.endpt, 20);
#endif
#if defined(PJMEDIA_HAS_INTEL_IPP) && PJMEDIA_HAS_INTEL_IPP != 0
    pjmedia_codec_ipp_init(g_app.endpt);
#endif
#if defined(PJMEDIA_HAS_OPENCORE_AMRNB_CODEC) && (PJMEDIA_HAS_OPENCORE_AMRNB_CODEC != 0)
    pjmedia_codec_opencore_amrnb_init(g_app.endpt);
#endif
#if defined(PJMEDIA_HAS_L16_CODEC) && PJMEDIA_HAS_L16_CODEC != 0
    pjmedia_codec_l16_init(g_app.endpt, 0);
#endif

    /* Create the loop transport */
    status = pjmedia_transport_loop_create(g_app.endpt, &g_app.loop);
    if (status != PJ_SUCCESS) {
	jbsim_perror("Error creating loop transport", status);
	goto on_error;
    }

    /* Create transmitter stream */
    pj_bzero(&strm_cfg, sizeof(strm_cfg));
    strm_cfg.name = "tx";
    strm_cfg.dir = PJMEDIA_DIR_ENCODING;
    strm_cfg.codec = g_app.cfg.codec;
    strm_cfg.ptime = g_app.cfg.tx_ptime;
    strm_cfg.dtx = g_app.cfg.tx_dtx;
    strm_cfg.plc = PJ_TRUE;
    status = stream_init(&strm_cfg, &g_app.tx);
    if (status != PJ_SUCCESS) 
	goto on_error;

    /* Create transmitter WAV */
    status = pjmedia_wav_player_port_create(g_app.pool, 
					    g_app.cfg.tx_wav_in,
					    g_app.cfg.tx_ptime,
					    0,
					    0,
					    &g_app.tx_wav);
    if (status != PJ_SUCCESS) {
	jbsim_perror("Error reading input WAV file", status);
	goto on_error;
    }

    /* Make sure stream and WAV parameters match */
    if (g_app.tx_wav->info.clock_rate != g_app.tx->port->info.clock_rate ||
	g_app.tx_wav->info.channel_count != g_app.tx->port->info.channel_count)
    {
	jbsim_perror("Error: Input WAV file has different clock rate "
		     "or number of channels than the codec", PJ_SUCCESS);
	goto on_error;
    }


    /* Create receiver */
    pj_bzero(&strm_cfg, sizeof(strm_cfg));
    strm_cfg.name = "rx";
    strm_cfg.dir = PJMEDIA_DIR_DECODING;
    strm_cfg.codec = g_app.cfg.codec;
    strm_cfg.ptime = g_app.cfg.rx_ptime;
    strm_cfg.dtx = PJ_TRUE;
    strm_cfg.plc = g_app.cfg.rx_plc;
    status = stream_init(&strm_cfg, &g_app.rx);
    if (status != PJ_SUCCESS) 
	goto on_error;

    /* Create receiver WAV */
    status = pjmedia_wav_writer_port_create(g_app.pool, 
					    g_app.cfg.rx_wav_out,
					    g_app.rx->port->info.clock_rate,
					    g_app.rx->port->info.channel_count,
					    g_app.rx->port->info.samples_per_frame,
					    g_app.rx->port->info.bits_per_sample,
					    0,
					    0,
					    &g_app.rx_wav);
    if (status != PJ_SUCCESS) {
	jbsim_perror("Error creating output WAV file", status);
	goto on_error;
    }


    /* Frame buffer */
    g_app.framebuf = (pj_int16_t*)
		     pj_pool_alloc(g_app.pool,
				   MAX(g_app.rx->port->info.samples_per_frame,
				       g_app.tx->port->info.samples_per_frame) * sizeof(pj_int16_t));


    /* Set the receiver in the loop transport */
    pjmedia_transport_loop_disable_rx(g_app.loop, g_app.tx->strm, PJ_TRUE);

    /* Done */
    return PJ_SUCCESS;

on_error:
    test_destroy();
    return status;
}
Пример #15
0
/* Public function to parse multipart message bodies into its parts */
PJ_DEF(pjsip_msg_body*) pjsip_multipart_parse(pj_pool_t *pool,
					      char *buf, pj_size_t len,
					      const pjsip_media_type *ctype,
					      unsigned options)
{
    pj_str_t boundary, delim;
    char *curptr, *endptr;
    const pjsip_param *ctype_param;
    const pj_str_t STR_BOUNDARY = { "boundary", 8 };
    pjsip_msg_body *body = NULL;

    PJ_ASSERT_RETURN(pool && buf && len && ctype && !options, NULL);

    TRACE_((THIS_FILE, "Started parsing multipart body"));

    /* Get the boundary value in the ctype */
    boundary.ptr = NULL;
    boundary.slen = 0;
    ctype_param = pjsip_param_find(&ctype->param, &STR_BOUNDARY);
    if (ctype_param) {
	boundary = ctype_param->value;
	if (boundary.slen>2 && *boundary.ptr=='"') {
	    /* Remove quote */
	    boundary.ptr++;
	    boundary.slen -= 2;
	}
	TRACE_((THIS_FILE, "Boundary is specified: '%.*s'", (int)boundary.slen,
		boundary.ptr));
    }

    if (!boundary.slen) {
	/* Boundary not found or not specified. Try to be clever, get
	 * the boundary from the body.
	 */
	char *p=buf, *end=buf+len;

	PJ_LOG(4,(THIS_FILE, "Warning: boundary parameter not found or "
			     "not specified when parsing multipart body"));

	/* Find the first "--". This "--" must be right after a CRLF, unless
	 * it really appears at the start of the buffer.
	 */
	for (;;) {
	    while (p!=end && *p!='-') ++p;
	    if (p!=end && *(p+1)=='-' &&
		((p>buf && *(p-1)=='\n') || (p==buf)))
	    {
		p+=2;
		break;
	    } else {
		++p;
	    }
	}

	if (p==end) {
	    /* Unable to determine boundary. Maybe this is not a multipart
	     * message?
	     */
	    PJ_LOG(4,(THIS_FILE, "Error: multipart boundary not specified and"
				 " unable to calculate from the body"));
	    return NULL;
	}

	boundary.ptr = p;
	while (p!=end && !pj_isspace(*p)) ++p;
	boundary.slen = p - boundary.ptr;

	TRACE_((THIS_FILE, "Boundary is calculated: '%.*s'",
		(int)boundary.slen, boundary.ptr));
    }

    /* Build the delimiter:
     *   delimiter = "--" boundary
     */
    delim.slen = boundary.slen+2;
    delim.ptr = (char*)pj_pool_alloc(pool, (int)delim.slen);
    delim.ptr[0] = '-';
    delim.ptr[1] = '-';
    pj_memcpy(delim.ptr+2, boundary.ptr, boundary.slen);

    /* Start parsing the body, skip until the first delimiter. */
    curptr = buf;
    endptr = buf + len;
    {
	pj_str_t body;

	body.ptr = buf; body.slen = len;
	curptr = pj_strstr(&body, &delim);
	if (!curptr)
	    return NULL;
    }

    body = pjsip_multipart_create(pool, ctype, &boundary);

    for (;;) {
	char *start_body, *end_body;
	pjsip_multipart_part *part;

	/* Eat the boundary */
	curptr += delim.slen;
	if (*curptr=='-' && curptr<endptr-1 && *(curptr+1)=='-') {
	    /* Found the closing delimiter */
	    curptr += 2;
	    break;
	}
	/* Optional whitespace after delimiter */
	while (curptr!=endptr && IS_SPACE(*curptr)) ++curptr;
	/* Mandatory CRLF */
	if (*curptr=='\r') ++curptr;
	if (*curptr!='\n') {
	    /* Expecting a newline here */
	    return NULL;
	}
	++curptr;

	/* We now in the start of the body */
	start_body = curptr;

	/* Find the next delimiter */
	{
	    pj_str_t subbody;

	    subbody.ptr = curptr; subbody.slen = endptr - curptr;
	    curptr = pj_strstr(&subbody, &delim);
	    if (!curptr) {
		/* We're really expecting end delimiter to be found. */
		return NULL;
	    }
	}

	end_body = curptr;

	/* The newline preceeding the delimiter is conceptually part of
	 * the delimiter, so trim it from the body.
	 */
	if (*(end_body-1) == '\n')
	    --end_body;
	if (*(end_body-1) == '\r')
	    --end_body;

	/* Now that we have determined the part's boundary, parse it
	 * to get the header and body part of the part.
	 */
	part = parse_multipart_part(pool, start_body, end_body - start_body,
				    ctype);
	if (part) {
	    pjsip_multipart_add_part(pool, body, part);
	}
    }

    return body;
}
/*
 * Common function to create TLS transport, called when pending accept() and
 * pending connect() complete.
 */
static pj_status_t tls_create( struct tls_listener *listener,
			       pj_pool_t *pool,
			       pj_ssl_sock_t *ssock,
			       pj_bool_t is_server,
			       const pj_sockaddr_in *local,
			       const pj_sockaddr_in *remote,
			       const pj_str_t *remote_name,
			       struct tls_transport **p_tls)
{
    struct tls_transport *tls;
    const pj_str_t ka_pkt = PJSIP_TLS_KEEP_ALIVE_DATA;
    pj_status_t status;
    

    PJ_ASSERT_RETURN(listener && ssock && local && remote && p_tls, PJ_EINVAL);


    if (pool == NULL) {
	pool = pjsip_endpt_create_pool(listener->endpt, "tls",
				       POOL_TP_INIT, POOL_TP_INC);
	PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
    }    

    /*
     * Create and initialize basic transport structure.
     */
    tls = PJ_POOL_ZALLOC_T(pool, struct tls_transport);
    tls->is_server = is_server;
    tls->verify_server = listener->tls_setting.verify_server;
    pj_list_init(&tls->delayed_list);
    tls->base.pool = pool;

    pj_ansi_snprintf(tls->base.obj_name, PJ_MAX_OBJ_NAME, 
		     (is_server ? "tlss%p" :"tlsc%p"), tls);

    status = pj_atomic_create(pool, 0, &tls->base.ref_cnt);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    status = pj_lock_create_recursive_mutex(pool, "tls", &tls->base.lock);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    if (remote_name)
	pj_strdup(pool, &tls->remote_name, remote_name);

    tls->base.key.type = PJSIP_TRANSPORT_TLS;
    pj_memcpy(&tls->base.key.rem_addr, remote, sizeof(pj_sockaddr_in));
    tls->base.type_name = "tls";
    tls->base.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TLS);

    tls->base.info = (char*) pj_pool_alloc(pool, 64);
    pj_ansi_snprintf(tls->base.info, 64, "TLS to %s:%d",
		     pj_inet_ntoa(remote->sin_addr), 
		     (int)pj_ntohs(remote->sin_port));

    tls->base.addr_len = sizeof(pj_sockaddr_in);
    tls->base.dir = is_server? PJSIP_TP_DIR_INCOMING : PJSIP_TP_DIR_OUTGOING;
    
    /* Set initial local address */
    if (!pj_sockaddr_has_addr(local)) {
        pj_sockaddr_cp(&tls->base.local_addr,
                       &listener->factory.local_addr);
    } else {
	pj_sockaddr_cp(&tls->base.local_addr, local);
    }
    
    sockaddr_to_host_port(pool, &tls->base.local_name, 
			  (pj_sockaddr_in*)&tls->base.local_addr);
    if (tls->remote_name.slen) {
	tls->base.remote_name.host = tls->remote_name;
	tls->base.remote_name.port = pj_sockaddr_in_get_port(remote);
    } else {
	sockaddr_to_host_port(pool, &tls->base.remote_name, remote);
    }

    tls->base.endpt = listener->endpt;
    tls->base.tpmgr = listener->tpmgr;
    tls->base.send_msg = &tls_send_msg;
    tls->base.do_shutdown = &tls_shutdown;
    tls->base.destroy = &tls_destroy_transport;

    tls->ssock = ssock;

    /* Register transport to transport manager */
    status = pjsip_transport_register(listener->tpmgr, &tls->base);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    tls->is_registered = PJ_TRUE;

    /* Initialize keep-alive timer */
    tls->ka_timer.user_data = (void*)tls;
    tls->ka_timer.cb = &tls_keep_alive_timer;
    pj_ioqueue_op_key_init(&tls->ka_op_key.key, sizeof(pj_ioqueue_op_key_t));
    pj_strdup(tls->base.pool, &tls->ka_pkt, &ka_pkt);
    
    /* Done setting up basic transport. */
    *p_tls = tls;

    PJ_LOG(4,(tls->base.obj_name, "TLS %s transport created",
	      (tls->is_server ? "server" : "client")));

    return PJ_SUCCESS;

on_error:
    tls_destroy(&tls->base, status);
    return status;
}
Пример #17
0
/**
 * Private: process pager message.
 *	    This may trigger pjsua_ui_on_pager() or pjsua_ui_on_typing().
 */
void pjsua_im_process_pager(int call_id, const pj_str_t *from,
			    const pj_str_t *to, pjsip_rx_data *rdata)
{
    pjsip_contact_hdr *contact_hdr;
    pj_str_t contact;
    pjsip_msg_body *body = rdata->msg_info.msg->body;

#if 0
    /* Ticket #693: allow incoming MESSAGE without message body */
    /* Body MUST have been checked before */
    pj_assert(body != NULL);
#endif


    /* Build remote contact */
    contact_hdr = (pjsip_contact_hdr*)
		  pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT,
				     NULL);
    if (contact_hdr && contact_hdr->uri) {
	contact.ptr = (char*) pj_pool_alloc(rdata->tp_info.pool, 
				    	    PJSIP_MAX_URL_SIZE);
	contact.slen = pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR,
				       contact_hdr->uri, contact.ptr,
				       PJSIP_MAX_URL_SIZE);
    } else {
	contact.slen = 0;
    }

    if (body && pj_stricmp(&body->content_type.type, &STR_MIME_APP)==0 &&
	pj_stricmp(&body->content_type.subtype, &STR_MIME_ISCOMPOSING)==0)
    {
	/* Expecting typing indication */
	pj_status_t status;
	pj_bool_t is_typing;

	status = pjsip_iscomposing_parse(rdata->tp_info.pool, (char*)body->data,
					 body->len, &is_typing, NULL, NULL,
					 NULL );
	if (status != PJ_SUCCESS) {
	    pjsua_perror(THIS_FILE, "Invalid MESSAGE body", status);
	    return;
	}

	if (pjsua_var.ua_cfg.cb.on_typing) {
	    (*pjsua_var.ua_cfg.cb.on_typing)(call_id, from, to, &contact,
					     is_typing);
	}

	if (pjsua_var.ua_cfg.cb.on_typing2) {
	    pjsua_acc_id acc_id;

	    if (call_id == PJSUA_INVALID_ID) {
		acc_id = pjsua_acc_find_for_incoming(rdata);
	    } else {
		pjsua_call *call = &pjsua_var.calls[call_id];
		acc_id = call->acc_id;
	    }


	    (*pjsua_var.ua_cfg.cb.on_typing2)(call_id, from, to, &contact,
					      is_typing, rdata, acc_id);
	}

    } else {
	pj_str_t mime_type;
	char buf[256];
	pjsip_media_type *m;
	pj_str_t text_body;
	
	/* Save text body */
	if (body) {
	    text_body.ptr = (char*)rdata->msg_info.msg->body->data;
	    text_body.slen = rdata->msg_info.msg->body->len;

	    /* Get mime type */
	    m = &rdata->msg_info.msg->body->content_type;
	    mime_type.ptr = buf;
	    mime_type.slen = pj_ansi_snprintf(buf, sizeof(buf),
					      "%.*s/%.*s",
					      (int)m->type.slen,
					      m->type.ptr,
					      (int)m->subtype.slen,
					      m->subtype.ptr);
	    if (mime_type.slen < 1)
		mime_type.slen = 0;


	} else {
	    text_body.ptr = mime_type.ptr = "";
	    text_body.slen = mime_type.slen = 0;
	}

	if (pjsua_var.ua_cfg.cb.on_pager) {
	    (*pjsua_var.ua_cfg.cb.on_pager)(call_id, from, to, &contact, 
					    &mime_type, &text_body);
	}

	if (pjsua_var.ua_cfg.cb.on_pager2) {
	    pjsua_acc_id acc_id;

	    if (call_id == PJSUA_INVALID_ID) {
		acc_id = pjsua_acc_find_for_incoming(rdata);
	    } else {
		pjsua_call *call = &pjsua_var.calls[call_id];
		acc_id = call->acc_id;
	    }

	    (*pjsua_var.ua_cfg.cb.on_pager2)(call_id, from, to, &contact, 
					     &mime_type, &text_body, rdata,
					     acc_id);
	}
    }
}
Пример #18
0
/*
 * compliance_test()
 * To test that the basic IOQueue functionality works. It will just exchange
 * data between two sockets.
 */ 
static int compliance_test(pj_bool_t allow_concur)
{
    pj_sock_t ssock=-1, csock=-1;
    pj_sockaddr_in addr, dst_addr;
    int addrlen;
    pj_pool_t *pool = NULL;
    char *send_buf, *recv_buf;
    pj_ioqueue_t *ioque = NULL;
    pj_ioqueue_key_t *skey = NULL, *ckey = NULL;
    pj_ioqueue_op_key_t read_op, write_op;
    int bufsize = BUF_MIN_SIZE;
    pj_ssize_t bytes, status = -1;
    pj_str_t temp;
    pj_bool_t send_pending, recv_pending;
    pj_status_t rc;

    pj_set_os_error(PJ_SUCCESS);

    // Create pool.
    pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);

    // Allocate buffers for send and receive.
    send_buf = (char*)pj_pool_alloc(pool, bufsize);
    recv_buf = (char*)pj_pool_alloc(pool, bufsize);

    // Allocate sockets for sending and receiving.
    TRACE_("creating sockets...");
    rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &ssock);
    if (rc==PJ_SUCCESS)
        rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &csock);
    else
        csock = PJ_INVALID_SOCKET;
    if (rc != PJ_SUCCESS) {
        app_perror("...ERROR in pj_sock_socket()", rc);
	status=-1; goto on_error;
    }

    // Bind server socket.
    TRACE_("bind socket...");
    pj_bzero(&addr, sizeof(addr));
    addr.sin_family = pj_AF_INET();
    addr.sin_port = pj_htons(PORT);
    if (pj_sock_bind(ssock, &addr, sizeof(addr))) {
	status=-10; goto on_error;
    }

    // Create I/O Queue.
    TRACE_("create ioqueue...");
    rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
    if (rc != PJ_SUCCESS) {
	status=-20; goto on_error;
    }

    // Set concurrency
    TRACE_("set concurrency...");
    rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur);
    if (rc != PJ_SUCCESS) {
	status=-21; goto on_error;
    }

    // Register server and client socket.
    // We put this after inactivity socket, hopefully this can represent the
    // worst waiting time.
    TRACE_("registering first sockets...");
    rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, 
			          &test_cb, &skey);
    if (rc != PJ_SUCCESS) {
	app_perror("...error(10): ioqueue_register error", rc);
	status=-25; goto on_error;
    }
    TRACE_("registering second sockets...");
    rc = pj_ioqueue_register_sock( pool, ioque, csock, NULL, 
			           &test_cb, &ckey);
    if (rc != PJ_SUCCESS) {
	app_perror("...error(11): ioqueue_register error", rc);
	status=-26; goto on_error;
    }

    // Randomize send_buf.
    pj_create_random_string(send_buf, bufsize);

    // Register reading from ioqueue.
    TRACE_("start recvfrom...");
    pj_bzero(&addr, sizeof(addr));
    addrlen = sizeof(addr);
    bytes = bufsize;
    rc = pj_ioqueue_recvfrom(skey, &read_op, recv_buf, &bytes, 0,
			     &addr, &addrlen);
    if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
        app_perror("...error: pj_ioqueue_recvfrom", rc);
	status=-28; goto on_error;
    } else if (rc == PJ_EPENDING) {
	recv_pending = 1;
	PJ_LOG(3, (THIS_FILE, 
		   "......ok: recvfrom returned pending"));
    } else {
	PJ_LOG(3, (THIS_FILE, 
		   "......error: recvfrom returned immediate ok!"));
	status=-29; goto on_error;
    }

    // Set destination address to send the packet.
    TRACE_("set destination address...");
    temp = pj_str("127.0.0.1");
    if ((rc=pj_sockaddr_in_init(&dst_addr, &temp, PORT)) != 0) {
	app_perror("...error: unable to resolve 127.0.0.1", rc);
	status=-290; goto on_error;
    }

    // Write must return the number of bytes.
    TRACE_("start sendto...");
    bytes = bufsize;
    rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0, &dst_addr, 
			   sizeof(dst_addr));
    if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
        app_perror("...error: pj_ioqueue_sendto", rc);
	status=-30; goto on_error;
    } else if (rc == PJ_EPENDING) {
	send_pending = 1;
	PJ_LOG(3, (THIS_FILE, 
		   "......ok: sendto returned pending"));
    } else {
	send_pending = 0;
	PJ_LOG(3, (THIS_FILE, 
		   "......ok: sendto returned immediate success"));
    }

    // reset callback variables.
    callback_read_size = callback_write_size = 0;
    callback_accept_status = callback_connect_status = -2;
    callback_read_key = callback_write_key = 
        callback_accept_key = callback_connect_key = NULL;
    callback_read_op = callback_write_op = NULL;

    // Poll if pending.
    while (send_pending || recv_pending) {
	int rc;
	pj_time_val timeout = { 5, 0 };

	TRACE_("poll...");
#ifdef PJ_SYMBIAN
	rc = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
#else
	rc = pj_ioqueue_poll(ioque, &timeout);
#endif

	if (rc == 0) {
	    PJ_LOG(1,(THIS_FILE, "...ERROR: timed out..."));
	    status=-45; goto on_error;
        } else if (rc < 0) {
            app_perror("...ERROR in ioqueue_poll()", -rc);
	    status=-50; goto on_error;
	}

	if (callback_read_key != NULL) {
            if (callback_read_size != bufsize) {
                status=-61; goto on_error;
            }
            if (callback_read_key != skey) {
                status=-65; goto on_error;
            }
            if (callback_read_op != &read_op) {
                status=-66; goto on_error;
            }

	    if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) {
		status=-67; goto on_error;
	    }
	    if (addrlen != sizeof(pj_sockaddr_in)) {
		status=-68; goto on_error;
	    }
	    if (addr.sin_family != pj_AF_INET()) {
		status=-69; goto on_error;
	    }


	    recv_pending = 0;
	} 

        if (callback_write_key != NULL) {
            if (callback_write_size != bufsize) {
                status=-73; goto on_error;
            }
            if (callback_write_key != ckey) {
                status=-75; goto on_error;
            }
            if (callback_write_op != &write_op) {
                status=-76; goto on_error;
            }

            send_pending = 0;
	}
    } 
    
    // Success
    status = 0;

on_error:
    if (skey)
    	pj_ioqueue_unregister(skey);
    else if (ssock != -1)
	pj_sock_close(ssock);
    
    if (ckey)
    	pj_ioqueue_unregister(ckey);
    else if (csock != -1)
	pj_sock_close(csock);
    
    if (ioque != NULL)
	pj_ioqueue_destroy(ioque);
    pj_pool_release(pool);
    return status;

}
Пример #19
0
/*
 * Common function to create TCP transport, called when pending accept() and
 * pending connect() complete.
 */
static pj_status_t tcp_create( struct tcp_listener *listener,
			       pj_pool_t *pool,
			       pj_sock_t sock, pj_bool_t is_server,
			       const pj_sockaddr *local,
			       const pj_sockaddr *remote,
			       struct tcp_transport **p_tcp)
{
    struct tcp_transport *tcp;
    pj_ioqueue_t *ioqueue;
    pj_activesock_cfg asock_cfg;
    pj_activesock_cb tcp_callback;
    const pj_str_t ka_pkt = PJSIP_TCP_KEEP_ALIVE_DATA;
    char print_addr[PJ_INET6_ADDRSTRLEN+10];
    pj_status_t status;


    PJ_ASSERT_RETURN(sock != PJ_INVALID_SOCKET, PJ_EINVAL);


    if (pool == NULL) {
	pool = pjsip_endpt_create_pool(listener->endpt, "tcp",
				       POOL_TP_INIT, POOL_TP_INC);
	PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
    }

    /*
     * Create and initialize basic transport structure.
     */
    tcp = PJ_POOL_ZALLOC_T(pool, struct tcp_transport);
    tcp->is_server = is_server;
    tcp->sock = sock;
    /*tcp->listener = listener;*/
    pj_list_init(&tcp->delayed_list);
    tcp->base.pool = pool;

    pj_ansi_snprintf(tcp->base.obj_name, PJ_MAX_OBJ_NAME,
		     (is_server ? "tcps%p" :"tcpc%p"), tcp);

    status = pj_atomic_create(pool, 0, &tcp->base.ref_cnt);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    status = pj_lock_create_recursive_mutex(pool, "tcp", &tcp->base.lock);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    tcp->base.key.type = listener->factory.type;
    pj_sockaddr_cp(&tcp->base.key.rem_addr, remote);
    tcp->base.type_name = (char*)pjsip_transport_get_type_name(
				(pjsip_transport_type_e)tcp->base.key.type);
    tcp->base.flag = pjsip_transport_get_flag_from_type(
				(pjsip_transport_type_e)tcp->base.key.type);

    tcp->base.info = (char*) pj_pool_alloc(pool, 64);
    pj_ansi_snprintf(tcp->base.info, 64, "%s to %s",
                     tcp->base.type_name,
                     pj_sockaddr_print(remote, print_addr,
                                       sizeof(print_addr), 3));

    tcp->base.addr_len = pj_sockaddr_get_len(remote);
    pj_sockaddr_cp(&tcp->base.local_addr, local);
    sockaddr_to_host_port(pool, &tcp->base.local_name, local);
    sockaddr_to_host_port(pool, &tcp->base.remote_name, remote);
    tcp->base.dir = is_server? PJSIP_TP_DIR_INCOMING : PJSIP_TP_DIR_OUTGOING;

    tcp->base.endpt = listener->endpt;
    tcp->base.tpmgr = listener->tpmgr;
    tcp->base.send_msg = &tcp_send_msg;
    tcp->base.do_shutdown = &tcp_shutdown;
    tcp->base.destroy = &tcp_destroy_transport;

    /* Create active socket */
    pj_activesock_cfg_default(&asock_cfg);
    asock_cfg.async_cnt = 1;

    pj_bzero(&tcp_callback, sizeof(tcp_callback));
    tcp_callback.on_data_read = &on_data_read;
    tcp_callback.on_data_sent = &on_data_sent;
    tcp_callback.on_connect_complete = &on_connect_complete;

    ioqueue = pjsip_endpt_get_ioqueue(listener->endpt);
    status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), &asock_cfg,
				  ioqueue, &tcp_callback, tcp, &tcp->asock);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    /* Register transport to transport manager */
    status = pjsip_transport_register(listener->tpmgr, &tcp->base);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    tcp->is_registered = PJ_TRUE;

    /* Initialize keep-alive timer */
    tcp->ka_timer.user_data = (void*)tcp;
    tcp->ka_timer.cb = &tcp_keep_alive_timer;
    pj_ioqueue_op_key_init(&tcp->ka_op_key.key, sizeof(pj_ioqueue_op_key_t));
    pj_strdup(tcp->base.pool, &tcp->ka_pkt, &ka_pkt);

    /* Done setting up basic transport. */
    *p_tcp = tcp;

    PJ_LOG(4,(tcp->base.obj_name, "TCP %s transport created",
	      (tcp->is_server ? "server" : "client")));

    return PJ_SUCCESS;

on_error:
    tcp_destroy(&tcp->base, status);
    return status;
}
Пример #20
0
/*
 * Testing with many handles.
 * This will just test registering PJ_IOQUEUE_MAX_HANDLES count
 * of sockets to the ioqueue.
 */
static int many_handles_test(pj_bool_t allow_concur)
{
    enum { MAX = PJ_IOQUEUE_MAX_HANDLES };
    pj_pool_t *pool;
    pj_ioqueue_t *ioqueue;
    pj_sock_t *sock;
    pj_ioqueue_key_t **key;
    pj_status_t rc;
    int count, i; /* must be signed */

    PJ_LOG(3,(THIS_FILE,"...testing with so many handles"));

    pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
    if (!pool)
	return PJ_ENOMEM;

    key = (pj_ioqueue_key_t**) 
    	  pj_pool_alloc(pool, MAX*sizeof(pj_ioqueue_key_t*));
    sock = (pj_sock_t*) pj_pool_alloc(pool, MAX*sizeof(pj_sock_t));
    
    /* Create IOQueue */
    rc = pj_ioqueue_create(pool, MAX, &ioqueue);
    if (rc != PJ_SUCCESS || ioqueue == NULL) {
	app_perror("...error in pj_ioqueue_create", rc);
	return -10;
    }

    // Set concurrency
    rc = pj_ioqueue_set_default_concurrency(ioqueue, allow_concur);
    if (rc != PJ_SUCCESS) {
	return -11;
    }

    /* Register as many sockets. */
    for (count=0; count<MAX; ++count) {
	sock[count] = PJ_INVALID_SOCKET;
	rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[count]);
	if (rc != PJ_SUCCESS || sock[count] == PJ_INVALID_SOCKET) {
	    PJ_LOG(3,(THIS_FILE, "....unable to create %d-th socket, rc=%d", 
				 count, rc));
	    break;
	}
	key[count] = NULL;
	rc = pj_ioqueue_register_sock(pool, ioqueue, sock[count],
				      NULL, &test_cb, &key[count]);
	if (rc != PJ_SUCCESS || key[count] == NULL) {
	    PJ_LOG(3,(THIS_FILE, "....unable to register %d-th socket, rc=%d", 
				 count, rc));
	    return -30;
	}
    }

    /* Test complete. */

    /* Now deregister and close all handles. */ 

    /* NOTE for RTEMS:
     *  It seems that the order of close(sock) is pretty important here.
     *  If we close the sockets with the same order as when they were created,
     *  RTEMS doesn't seem to reuse the sockets, thus next socket created
     *  will have descriptor higher than the last socket created.
     *  If we close the sockets in the reverse order, then the descriptor will
     *  get reused.
     *  This used to cause problem with select ioqueue, since the ioqueue
     *  always gives FD_SETSIZE for the first select() argument. This ioqueue
     *  behavior can be changed with setting PJ_SELECT_NEEDS_NFDS macro.
     */
    for (i=count-1; i>=0; --i) {
    ///for (i=0; i<count; ++i) {
	rc = pj_ioqueue_unregister(key[i]);
	if (rc != PJ_SUCCESS) {
	    app_perror("...error in pj_ioqueue_unregister", rc);
	}
    }

    rc = pj_ioqueue_destroy(ioqueue);
    if (rc != PJ_SUCCESS) {
	app_perror("...error in pj_ioqueue_destroy", rc);
    }
    
    pj_pool_release(pool);

    PJ_LOG(3,(THIS_FILE,"....many_handles_test() ok"));

    return 0;
}
Пример #21
0
static pj_status_t bb10_open_playback (struct bb10_stream *stream,
                                       const pjmedia_aud_param *param)
{
    int ret = 0;
    snd_pcm_channel_info_t pi;
    snd_pcm_channel_setup_t setup;
    snd_mixer_group_t group;
    snd_pcm_channel_params_t pp;
    unsigned int rate;
    unsigned long tmp_buf_size;

    if (param->play_id < 0 || param->play_id >= stream->af->dev_cnt) {
        return PJMEDIA_EAUD_INVDEV;
    }

    PJ_ASSERT_RETURN(param->bits_per_sample == 16, PJMEDIA_EAUD_SAMPFORMAT);

    /* Use the bb10 audio manager API to open as opposed to QNX core audio
     * Echo cancellation built in
     */
    if ((ret = audio_manager_snd_pcm_open_name(
	    AUDIO_TYPE_VIDEO_CHAT,
            &stream->pb_pcm, &stream->pb_audio_manager_handle,
            (char*)"voice",
            SND_PCM_OPEN_PLAYBACK)) < 0)
    {
        TRACE_((THIS_FILE, "audio_manager_snd_pcm_open_name ret = %d", ret));
        return PJMEDIA_EAUD_SYSERR;
    }

    /* Required call from January 2013 gold OS release */
    snd_pcm_plugin_set_disable(stream->pb_pcm, PLUGIN_DISABLE_MMAP);

    /* Required call from January 2013 gold OS release */
    snd_pcm_plugin_set_enable(stream->pb_pcm, PLUGIN_ROUTING);

    memset (&pi, 0, sizeof (pi));
    pi.channel = SND_PCM_CHANNEL_PLAYBACK;
    if ((ret = snd_pcm_plugin_info (stream->pb_pcm, &pi)) < 0) {
	TRACE_((THIS_FILE, "snd_pcm_plugin_info ret = %d", ret));
	return PJMEDIA_EAUD_SYSERR;
    }

    memset (&pp, 0, sizeof (pp));

    /* Request VoIP compatible capabilities */
    pp.mode = SND_PCM_MODE_BLOCK;
    pp.channel = SND_PCM_CHANNEL_PLAYBACK;
    pp.start_mode = SND_PCM_START_FULL;
    pp.stop_mode = SND_PCM_STOP_ROLLOVER;
    pp.buf.block.frag_size = param->samples_per_frame * param->bits_per_sample / 8;
    /* RIM recommends maximum of 5 */
    pp.buf.block.frags_max = 5;
    pp.buf.block.frags_min = 1;
    pp.format.interleave = 1;
    pp.format.rate = param->clock_rate;
    pp.format.voices = param->channel_count;
    pp.format.format = get_alsa_pcm_fmt(param);

    /* Make the calls as per the wave sample */
    if ((ret = snd_pcm_plugin_params (stream->pb_pcm, &pp)) < 0) {
        TRACE_((THIS_FILE, "snd_pcm_plugin_params ret = %d", ret));
        return PJMEDIA_EAUD_SYSERR;
    }

    memset (&setup, 0, sizeof (setup));
    memset (&group, 0, sizeof (group));
    setup.channel = SND_PCM_CHANNEL_PLAYBACK;
    setup.mixer_gid = &group.gid;

    if ((ret = snd_pcm_plugin_setup (stream->pb_pcm, &setup)) < 0) {
        TRACE_((THIS_FILE, "snd_pcm_plugin_setup ret = %d", ret));
        return PJMEDIA_EAUD_SYSERR;
    }

    if (group.gid.name[0] == 0) {
        return PJMEDIA_EAUD_SYSERR;
    }

    rate = param->clock_rate;
    /* Set the sound device buffer size and latency */
    if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY) {
        tmp_buf_size = rate * param->output_latency_ms / 1000;
    } else {
	tmp_buf_size = rate * PJMEDIA_SND_DEFAULT_PLAY_LATENCY / 1000;
    }
    /* Set period size to samples_per_frame frames. */
    stream->pb_frames = param->samples_per_frame / param->channel_count;
    stream->param.output_latency_ms = tmp_buf_size * 1000 / rate;

    /* Set our buffer */
    stream->pb_buf_size = stream->pb_frames * param->channel_count *
                          param->bits_per_sample / 8;
    stream->pb_buf = (char *) pj_pool_alloc(stream->pool, stream->pb_buf_size);

    TRACE_((THIS_FILE, "bb10_open_playback: pb_frames = %d clock = %d",
                       stream->pb_frames, param->clock_rate));

    return PJ_SUCCESS;
}
Пример #22
0
/*
 * Benchmarking IOQueue
 */
static int bench_test(pj_bool_t allow_concur, int bufsize, 
		      int inactive_sock_count)
{
    pj_sock_t ssock=-1, csock=-1;
    pj_sockaddr_in addr;
    pj_pool_t *pool = NULL;
    pj_sock_t *inactive_sock=NULL;
    pj_ioqueue_op_key_t *inactive_read_op;
    char *send_buf, *recv_buf;
    pj_ioqueue_t *ioque = NULL;
    pj_ioqueue_key_t *skey, *ckey, *keys[SOCK_INACTIVE_MAX+2];
    pj_timestamp t1, t2, t_elapsed;
    int rc=0, i;    /* i must be signed */
    pj_str_t temp;
    char errbuf[PJ_ERR_MSG_SIZE];

    TRACE__((THIS_FILE, "   bench test %d", inactive_sock_count));

    // Create pool.
    pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);

    // Allocate buffers for send and receive.
    send_buf = (char*)pj_pool_alloc(pool, bufsize);
    recv_buf = (char*)pj_pool_alloc(pool, bufsize);

    // Allocate sockets for sending and receiving.
    rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &ssock);
    if (rc == PJ_SUCCESS) {
        rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &csock);
    } else
        csock = PJ_INVALID_SOCKET;
    if (rc != PJ_SUCCESS) {
	app_perror("...error: pj_sock_socket()", rc);
	goto on_error;
    }

    // Bind server socket.
    pj_bzero(&addr, sizeof(addr));
    addr.sin_family = pj_AF_INET();
    addr.sin_port = pj_htons(PORT);
    if (pj_sock_bind(ssock, &addr, sizeof(addr)))
	goto on_error;

    pj_assert(inactive_sock_count+2 <= PJ_IOQUEUE_MAX_HANDLES);

    // Create I/O Queue.
    rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: pj_ioqueue_create()", rc);
	goto on_error;
    }

    // Set concurrency
    rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: pj_ioqueue_set_default_concurrency()", rc);
	goto on_error;
    }

    // Allocate inactive sockets, and bind them to some arbitrary address.
    // Then register them to the I/O queue, and start a read operation.
    inactive_sock = (pj_sock_t*)pj_pool_alloc(pool, 
				    inactive_sock_count*sizeof(pj_sock_t));
    inactive_read_op = (pj_ioqueue_op_key_t*)pj_pool_alloc(pool,
                              inactive_sock_count*sizeof(pj_ioqueue_op_key_t));
    pj_bzero(&addr, sizeof(addr));
    addr.sin_family = pj_AF_INET();
    for (i=0; i<inactive_sock_count; ++i) {
        pj_ssize_t bytes;

	rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &inactive_sock[i]);
	if (rc != PJ_SUCCESS || inactive_sock[i] < 0) {
	    app_perror("...error: pj_sock_socket()", rc);
	    goto on_error;
	}
	if ((rc=pj_sock_bind(inactive_sock[i], &addr, sizeof(addr))) != 0) {
	    pj_sock_close(inactive_sock[i]);
	    inactive_sock[i] = PJ_INVALID_SOCKET;
	    app_perror("...error: pj_sock_bind()", rc);
	    goto on_error;
	}
	rc = pj_ioqueue_register_sock(pool, ioque, inactive_sock[i], 
			              NULL, &test_cb, &keys[i]);
	if (rc != PJ_SUCCESS) {
	    pj_sock_close(inactive_sock[i]);
	    inactive_sock[i] = PJ_INVALID_SOCKET;
	    app_perror("...error(1): pj_ioqueue_register_sock()", rc);
	    PJ_LOG(3,(THIS_FILE, "....i=%d", i));
	    goto on_error;
	}
        bytes = bufsize;
	rc = pj_ioqueue_recv(keys[i], &inactive_read_op[i], recv_buf, &bytes, 0);
	if (rc != PJ_EPENDING) {
	    pj_sock_close(inactive_sock[i]);
	    inactive_sock[i] = PJ_INVALID_SOCKET;
	    app_perror("...error: pj_ioqueue_read()", rc);
	    goto on_error;
	}
    }

    // Register server and client socket.
    // We put this after inactivity socket, hopefully this can represent the
    // worst waiting time.
    rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, 
			          &test_cb, &skey);
    if (rc != PJ_SUCCESS) {
	app_perror("...error(2): pj_ioqueue_register_sock()", rc);
	goto on_error;
    }

    rc = pj_ioqueue_register_sock(pool, ioque, csock, NULL, 
			          &test_cb, &ckey);
    if (rc != PJ_SUCCESS) {
	app_perror("...error(3): pj_ioqueue_register_sock()", rc);
	goto on_error;
    }

    // Set destination address to send the packet.
    pj_sockaddr_in_init(&addr, pj_cstr(&temp, "127.0.0.1"), PORT);

    // Test loop.
    t_elapsed.u64 = 0;
    for (i=0; i<LOOP; ++i) {
	pj_ssize_t bytes;
        pj_ioqueue_op_key_t read_op, write_op;

	// Randomize send buffer.
	pj_create_random_string(send_buf, bufsize);

	// Start reading on the server side.
        bytes = bufsize;
	rc = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);
	if (rc != PJ_EPENDING) {
	    app_perror("...error: pj_ioqueue_read()", rc);
	    break;
	}

	// Starts send on the client side.
        bytes = bufsize;
	rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0,
			       &addr, sizeof(addr));
	if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
	    app_perror("...error: pj_ioqueue_write()", rc);
	    break;
	}
	if (rc == PJ_SUCCESS) {
	    if (bytes < 0) {
		app_perror("...error: pj_ioqueue_sendto()", -bytes);
		break;
	    }
	}

	// Begin time.
	pj_get_timestamp(&t1);

	// Poll the queue until we've got completion event in the server side.
        callback_read_key = NULL;
        callback_read_size = 0;
	TRACE__((THIS_FILE, "     waiting for key = %p", skey));
	do {
	    pj_time_val timeout = { 1, 0 };
#ifdef PJ_SYMBIAN
	    rc = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
#else
	    rc = pj_ioqueue_poll(ioque, &timeout);
#endif
	    TRACE__((THIS_FILE, "     poll rc=%d", rc));
	} while (rc >= 0 && callback_read_key != skey);

	// End time.
	pj_get_timestamp(&t2);
	t_elapsed.u64 += (t2.u64 - t1.u64);

	if (rc < 0) {
	    app_perror("   error: pj_ioqueue_poll", -rc);
	    break;
	}

	// Compare recv buffer with send buffer.
	if (callback_read_size != bufsize || 
	    pj_memcmp(send_buf, recv_buf, bufsize)) 
	{
	    rc = -10;
	    PJ_LOG(3,(THIS_FILE, "   error: size/buffer mismatch"));
	    break;
	}

	// Poll until all events are exhausted, before we start the next loop.
	do {
	    pj_time_val timeout = { 0, 10 };
#ifdef PJ_SYMBIAN
	    PJ_UNUSED_ARG(timeout);
	    rc = pj_symbianos_poll(-1, 100);
#else	    
	    rc = pj_ioqueue_poll(ioque, &timeout);
#endif
	} while (rc>0);

	rc = 0;
    }

    // Print results
    if (rc == 0) {
	pj_timestamp tzero;
	pj_uint32_t usec_delay;

	tzero.u32.hi = tzero.u32.lo = 0;
	usec_delay = pj_elapsed_usec( &tzero, &t_elapsed);

	PJ_LOG(3, (THIS_FILE, "...%10d %15d  % 9d", 
	           bufsize, inactive_sock_count, usec_delay));

    } else {
	PJ_LOG(2, (THIS_FILE, "...ERROR rc=%d (buf:%d, fds:%d)", 
			      rc, bufsize, inactive_sock_count+2));
    }

    // Cleaning up.
    for (i=inactive_sock_count-1; i>=0; --i) {
	pj_ioqueue_unregister(keys[i]);
    }

    pj_ioqueue_unregister(skey);
    pj_ioqueue_unregister(ckey);


    pj_ioqueue_destroy(ioque);
    pj_pool_release( pool);
    return rc;

on_error:
    PJ_LOG(1,(THIS_FILE, "...ERROR: %s", 
	      pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf))));
    if (ssock)
	pj_sock_close(ssock);
    if (csock)
	pj_sock_close(csock);
    for (i=0; i<inactive_sock_count && inactive_sock && 
	      inactive_sock[i]!=PJ_INVALID_SOCKET; ++i) 
    {
	pj_sock_close(inactive_sock[i]);
    }
    if (ioque != NULL)
	pj_ioqueue_destroy(ioque);
    pj_pool_release( pool);
    return -1;
}
Пример #23
0
/*
 * pj_ioqueue_create()
 *
 * Create select ioqueue.
 */
PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 
                                       pj_size_t max_fd,
                                       pj_ioqueue_t **p_ioqueue)
{
    pj_ioqueue_t *ioqueue;
    pj_status_t rc;
    pj_lock_t *lock;
    int i;

    /* Check that arguments are valid. */
    PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL && 
                     max_fd > 0, PJ_EINVAL);

    /* Check that size of pj_ioqueue_op_key_t is sufficient */
    PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=
                     sizeof(union operation_key), PJ_EBUG);

    ioqueue = pj_pool_alloc(pool, sizeof(pj_ioqueue_t));

    ioqueue_init(ioqueue);

    ioqueue->max = max_fd;
    ioqueue->count = 0;
    pj_list_init(&ioqueue->active_list);

#if PJ_IOQUEUE_HAS_SAFE_UNREG
    /* When safe unregistration is used (the default), we pre-create
     * all keys and put them in the free list.
     */

    /* Mutex to protect key's reference counter 
     * We don't want to use key's mutex or ioqueue's mutex because
     * that would create deadlock situation in some cases.
     */
    rc = pj_mutex_create_simple(pool, NULL, &ioqueue->ref_cnt_mutex);
    if (rc != PJ_SUCCESS)
	return rc;


    /* Init key list */
    pj_list_init(&ioqueue->free_list);
    pj_list_init(&ioqueue->closing_list);


    /* Pre-create all keys according to max_fd */
    for ( i=0; i<max_fd; ++i) {
	pj_ioqueue_key_t *key;

	key = PJ_POOL_ALLOC_T(pool, pj_ioqueue_key_t);
	key->ref_count = 0;
	rc = pj_mutex_create_recursive(pool, NULL, &key->mutex);
	if (rc != PJ_SUCCESS) {
	    key = ioqueue->free_list.next;
	    while (key != &ioqueue->free_list) {
		pj_mutex_destroy(key->mutex);
		key = key->next;
	    }
	    pj_mutex_destroy(ioqueue->ref_cnt_mutex);
	    return rc;
	}

	pj_list_push_back(&ioqueue->free_list, key);
    }
#endif

    rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock);
    if (rc != PJ_SUCCESS)
	return rc;

    rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE);
    if (rc != PJ_SUCCESS)
        return rc;

    ioqueue->epfd = os_epoll_create(max_fd);
    if (ioqueue->epfd < 0) {
	ioqueue_destroy(ioqueue);
	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
    }
    
    /*ioqueue->events = pj_pool_calloc(pool, max_fd, sizeof(struct epoll_event));
    PJ_ASSERT_RETURN(ioqueue->events != NULL, PJ_ENOMEM);

    ioqueue->queue = pj_pool_calloc(pool, max_fd, sizeof(struct queue));
    PJ_ASSERT_RETURN(ioqueue->queue != NULL, PJ_ENOMEM);
   */
    PJ_LOG(4, ("pjlib", "epoll I/O Queue created (%p)", ioqueue));

    *p_ioqueue = ioqueue;
    return PJ_SUCCESS;
}
Пример #24
0
/* Encode ICE information in SDP */
static pj_status_t encode_session_in_sdp(struct transport_ice *tp_ice,
					 pj_pool_t *sdp_pool,
					 pjmedia_sdp_session *sdp_local,
					 unsigned media_index,
					 unsigned comp_cnt,
					 pj_bool_t restart_session)
{
    enum { 
	ATTR_BUF_LEN = 160,	/* Max len of a=candidate attr */
	RATTR_BUF_LEN= 160	/* Max len of a=remote-candidates attr */
    };
    pjmedia_sdp_media *m = sdp_local->media[media_index];
    pj_str_t local_ufrag, local_pwd;
    pjmedia_sdp_attr *attr;
    pj_status_t status;

    /* Must have a session */
    PJ_ASSERT_RETURN(pj_ice_strans_has_sess(tp_ice->ice_st), PJ_EBUG);

    /* Get ufrag and pwd from current session */
    pj_ice_strans_get_ufrag_pwd(tp_ice->ice_st, &local_ufrag, &local_pwd,
				NULL, NULL);

    /* The listing of candidates depends on whether ICE has completed
     * or not. When ICE has completed:
     *
     * 9.1.2.2: Existing Media Streams with ICE Completed
     *   The agent MUST include a candidate attributes for candidates
     *   matching the default destination for each component of the 
     *   media stream, and MUST NOT include any other candidates.
     *
     * When ICE has not completed, we shall include all candidates.
     *
     * Except when we have detected that remote is offering to restart
     * the session, in this case we will answer with full ICE SDP and
     * new ufrag/pwd pair.
     */
    if (!restart_session && pj_ice_strans_sess_is_complete(tp_ice->ice_st)) {
	const pj_ice_sess_check *check;
	char *attr_buf;
	pjmedia_sdp_conn *conn;
	pjmedia_sdp_attr *a_rtcp;
	pj_str_t rem_cand;
	unsigned comp;

	/* Encode ice-ufrag attribute */
	attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_UFRAG.ptr,
				       &local_ufrag);
	pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);

	/* Encode ice-pwd attribute */
	attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_PWD.ptr, 
				       &local_pwd);
	pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);

	/* Prepare buffer */
	attr_buf = (char*) pj_pool_alloc(sdp_pool, ATTR_BUF_LEN);
	rem_cand.ptr = (char*) pj_pool_alloc(sdp_pool, RATTR_BUF_LEN);
	rem_cand.slen = 0;

	/* 9.1.2.2: Existing Media Streams with ICE Completed
	 *   The default destination for media (i.e., the values of 
	 *   the IP addresses and ports in the m and c line used for
	 *   that media stream) MUST be the local candidate from the
	 *   highest priority nominated pair in the valid list for each
	 *   component.
	 */
	check = pj_ice_strans_get_valid_pair(tp_ice->ice_st, 1);
	if (check == NULL) {
	    pj_assert(!"Shouldn't happen");
	    return PJ_EBUG;
	}

	/* Override connection line address and media port number */
	conn = m->conn;
	if (conn == NULL)
	    conn = sdp_local->conn;

	conn->addr.ptr = (char*) pj_pool_alloc(sdp_pool, 
					       PJ_INET6_ADDRSTRLEN);
	pj_sockaddr_print(&check->lcand->addr, conn->addr.ptr, 
			  PJ_INET6_ADDRSTRLEN, 0);
	conn->addr.slen = pj_ansi_strlen(conn->addr.ptr);
	m->desc.port = pj_sockaddr_get_port(&check->lcand->addr);

	/* Override address RTCP attribute if it's present */
	if (comp_cnt == 2 &&
	    (check = pj_ice_strans_get_valid_pair(tp_ice->ice_st, 
						  COMP_RTCP)) != NULL &&
	    (a_rtcp = pjmedia_sdp_attr_find(m->attr_count, m->attr, 
					    &STR_RTCP, 0)) != NULL) 
	{
	    pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a_rtcp);

	    a_rtcp = pjmedia_sdp_attr_create_rtcp(sdp_pool, 
						  &check->lcand->addr);
	    if (a_rtcp)
		pjmedia_sdp_attr_add(&m->attr_count, m->attr, a_rtcp);
	}

	/* Encode only candidates matching the default destination 
	 * for each component 
	 */
	for (comp=0; comp < comp_cnt; ++comp) {
	    int len;
	    pj_str_t value;

	    /* Get valid pair for this component */
	    check = pj_ice_strans_get_valid_pair(tp_ice->ice_st, comp+1);
	    if (check == NULL)
		continue;

	    /* Print and add local candidate in the pair */
	    value.ptr = attr_buf;
	    value.slen = print_sdp_cand_attr(attr_buf, ATTR_BUF_LEN, 
					     check->lcand);
	    if (value.slen < 0) {
		pj_assert(!"Not enough attr_buf to print candidate");
		return PJ_EBUG;
	    }

	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_CANDIDATE.ptr,
					   &value);
	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);

	    /* Append to a=remote-candidates attribute */
	    if (pj_ice_strans_get_role(tp_ice->ice_st) == 
				    PJ_ICE_SESS_ROLE_CONTROLLING) 
	    {
		char rem_addr[PJ_INET6_ADDRSTRLEN];

		pj_sockaddr_print(&check->rcand->addr, rem_addr, 
				  sizeof(rem_addr), 0);
		len = pj_ansi_snprintf(
			   rem_cand.ptr + rem_cand.slen,
			   RATTR_BUF_LEN - rem_cand.slen,
			   "%s%u %s %u", 
			   (rem_cand.slen==0? "" : " "),
			   comp+1, rem_addr,
			   pj_sockaddr_get_port(&check->rcand->addr)
			   );
		if (len < 1 || len >= RATTR_BUF_LEN) {
		    pj_assert(!"Not enough buffer to print "
			       "remote-candidates");
		    return PJ_EBUG;
		}

		rem_cand.slen += len;
	    }
	}

	/* 9.1.2.2: Existing Media Streams with ICE Completed
	 *   In addition, if the agent is controlling, it MUST include
	 *   the a=remote-candidates attribute for each media stream 
	 *   whose check list is in the Completed state.  The attribute
	 *   contains the remote candidates from the highest priority 
	 *   nominated pair in the valid list for each component of that
	 *   media stream.
	 */
	if (pj_ice_strans_get_role(tp_ice->ice_st) == 
				    PJ_ICE_SESS_ROLE_CONTROLLING) 
	{
	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_REM_CAND.ptr, 
					   &rem_cand);
	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
	}

    } else if (pj_ice_strans_has_sess(tp_ice->ice_st)) {
	/* Encode all candidates to SDP media */
	char *attr_buf;
	unsigned comp;

	/* If ICE is not restarted, encode current ICE ufrag/pwd.
	 * Otherwise generate new one.
	 */
	if (!restart_session) {
	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_UFRAG.ptr,
					   &local_ufrag);
	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);

	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_PWD.ptr, 
					   &local_pwd);
	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);

	} else {
	    pj_str_t str;

	    str.slen = PJ_ICE_UFRAG_LEN;
	    str.ptr = (char*) pj_pool_alloc(sdp_pool, str.slen);
	    pj_create_random_string(str.ptr, str.slen);
	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_UFRAG.ptr, &str);
	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);

	    str.ptr = (char*) pj_pool_alloc(sdp_pool, str.slen);
	    pj_create_random_string(str.ptr, str.slen);
	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_PWD.ptr, &str);
	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
	}

	/* Create buffer to encode candidates as SDP attribute */
	attr_buf = (char*) pj_pool_alloc(sdp_pool, ATTR_BUF_LEN);

	for (comp=0; comp < comp_cnt; ++comp) {
	    unsigned cand_cnt;
	    pj_ice_sess_cand cand[PJ_ICE_ST_MAX_CAND];
	    unsigned i;

	    cand_cnt = PJ_ARRAY_SIZE(cand);
	    status = pj_ice_strans_enum_cands(tp_ice->ice_st, comp+1,
					      &cand_cnt, cand);
	    if (status != PJ_SUCCESS)
		return status;

	    for (i=0; i<cand_cnt; ++i) {
		pj_str_t value;

		value.slen = print_sdp_cand_attr(attr_buf, ATTR_BUF_LEN, 
						 &cand[i]);
		if (value.slen < 0) {
		    pj_assert(!"Not enough attr_buf to print candidate");
		    return PJ_EBUG;
		}

		value.ptr = attr_buf;
		attr = pjmedia_sdp_attr_create(sdp_pool, 
					       STR_CANDIDATE.ptr,
					       &value);
		pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
	    }
	}
    } else {
	/* ICE has failed, application should have terminated this call */
    }

    /* Removing a=rtcp line when there is only one component. */
    if (comp_cnt == 1) {
	attr = pjmedia_sdp_attr_find(m->attr_count, m->attr, &STR_RTCP, NULL);
	if (attr)
	    pjmedia_sdp_attr_remove(&m->attr_count, m->attr, attr);
    }
    

    return PJ_SUCCESS;
}
Пример #25
0
/*
 * Generate response digest. 
 * Most of the parameters to generate the digest (i.e. username, realm, uri,
 * and nonce) are expected to be in the credential. Additional parameters (i.e.
 * password and method param) should be supplied in the argument.
 *
 * The resulting digest will be stored in cred->response.
 * The pool is used to allocate 32 bytes to store the digest in cred->response.
 */
static pj_status_t respond_digest( pj_pool_t *pool,
				   pjsip_digest_credential *cred,
				   const pjsip_digest_challenge *chal,
				   const pj_str_t *uri,
				   const pjsip_cred_info *cred_info,
				   const pj_str_t *cnonce,
				   pj_uint32_t nc,
				   const pj_str_t *method)
{
    const pj_str_t pjsip_AKAv1_MD5_STR = { "AKAv1-MD5", 9 };

    /* Check algorithm is supported. We support MD5 and AKAv1-MD5. */
    if (chal->algorithm.slen==0 ||
	(pj_stricmp(&chal->algorithm, &pjsip_MD5_STR) ||
	 pj_stricmp(&chal->algorithm, &pjsip_AKAv1_MD5_STR)))
    {
	;
    }
    else {
	PJ_LOG(4,(THIS_FILE, "Unsupported digest algorithm \"%.*s\"",
		  chal->algorithm.slen, chal->algorithm.ptr));
	return PJSIP_EINVALIDALGORITHM;
    }

    /* Build digest credential from arguments. */
    pj_strdup(pool, &cred->username, &cred_info->username);
    pj_strdup(pool, &cred->realm, &chal->realm);
    pj_strdup(pool, &cred->nonce, &chal->nonce);
    pj_strdup(pool, &cred->uri, uri);
    pj_strdup(pool, &cred->algorithm, &chal->algorithm);
    pj_strdup(pool, &cred->opaque, &chal->opaque);

    /* Allocate memory. */
    cred->response.ptr = (char*) pj_pool_alloc(pool, PJSIP_MD5STRLEN);
    cred->response.slen = PJSIP_MD5STRLEN;

    if (chal->qop.slen == 0) {
	/* Server doesn't require quality of protection. */

	if ((cred_info->data_type & EXT_MASK) == PJSIP_CRED_DATA_EXT_AKA) {
	    /* Call application callback to create the response digest */
	    return (*cred_info->ext.aka.cb)(pool, chal, cred_info, 
					    method, cred);
	} 
	else {
	    /* Convert digest to string and store in chal->response. */
	    pjsip_auth_create_digest( &cred->response, &cred->nonce, NULL, 
				      NULL,  NULL, uri, &chal->realm, 
				      cred_info, method);
	}

    } else if (has_auth_qop(pool, &chal->qop)) {
	/* Server requires quality of protection. 
	 * We respond with selecting "qop=auth" protection.
	 */
	cred->qop = pjsip_AUTH_STR;
	cred->nc.ptr = (char*) pj_pool_alloc(pool, 16);
	cred->nc.slen = pj_ansi_snprintf(cred->nc.ptr, 16, "%08u", nc);

	if (cnonce && cnonce->slen) {
	    pj_strdup(pool, &cred->cnonce, cnonce);
	} else {
	    pj_str_t dummy_cnonce = { "b39971", 6};
	    pj_strdup(pool, &cred->cnonce, &dummy_cnonce);
	}

	if ((cred_info->data_type & EXT_MASK) == PJSIP_CRED_DATA_EXT_AKA) {
	    /* Call application callback to create the response digest */
	    return (*cred_info->ext.aka.cb)(pool, chal, cred_info, 
					    method, cred);
	}
	else {
	    pjsip_auth_create_digest( &cred->response, &cred->nonce, 
				      &cred->nc, cnonce, &pjsip_AUTH_STR, 
				      uri, &chal->realm, cred_info, method );
	}

    } else {
	/* Server requires quality protection that we don't support. */
	PJ_LOG(4,(THIS_FILE, "Unsupported qop offer %.*s", 
		  chal->qop.slen, chal->qop.ptr));
	return PJSIP_EINVALIDQOP;
    }

    return PJ_SUCCESS;
}
Пример #26
0
/* Calculate the bandwidth for the specific test configuration.
 * The test is simple:
 *  - create sockpair_cnt number of producer-consumer socket pair.
 *  - create thread_cnt number of worker threads.
 *  - each producer will send buffer_size bytes data as fast and
 *    as soon as it can.
 *  - each consumer will read buffer_size bytes of data as fast 
 *    as it could.
 *  - measure the total bytes received by all consumers during a
 *    period of time.
 */
static int perform_test(pj_bool_t allow_concur,
			int sock_type, const char *type_name,
                        unsigned thread_cnt, unsigned sockpair_cnt,
                        pj_size_t buffer_size, 
                        pj_size_t *p_bandwidth)
{
    enum { MSEC_DURATION = 5000 };
    pj_pool_t *pool;
    test_item *items;
    pj_thread_t **thread;
    pj_ioqueue_t *ioqueue;
    pj_status_t rc;
    pj_ioqueue_callback ioqueue_callback;
    pj_uint32_t total_elapsed_usec, total_received;
    pj_highprec_t bandwidth;
    pj_timestamp start, stop;
    unsigned i;

    TRACE_((THIS_FILE, "    starting test.."));

    ioqueue_callback.on_read_complete = &on_read_complete;
    ioqueue_callback.on_write_complete = &on_write_complete;

    thread_quit_flag = 0;

    pool = pj_pool_create(mem, NULL, 4096, 4096, NULL);
    if (!pool)
        return -10;

    items = (test_item*) pj_pool_alloc(pool, sockpair_cnt*sizeof(test_item));
    thread = (pj_thread_t**)
    	     pj_pool_alloc(pool, thread_cnt*sizeof(pj_thread_t*));

    TRACE_((THIS_FILE, "     creating ioqueue.."));
    rc = pj_ioqueue_create(pool, sockpair_cnt*2, &ioqueue);
    if (rc != PJ_SUCCESS) {
        app_perror("...error: unable to create ioqueue", rc);
        return -15;
    }

    rc = pj_ioqueue_set_default_concurrency(ioqueue, allow_concur);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: pj_ioqueue_set_default_concurrency()", rc);
        return -16;
    }

    /* Initialize each producer-consumer pair. */
    for (i=0; i<sockpair_cnt; ++i) {
        pj_ssize_t bytes;

        items[i].ioqueue = ioqueue;
        items[i].buffer_size = buffer_size;
        items[i].outgoing_buffer = (char*) pj_pool_alloc(pool, buffer_size);
        items[i].incoming_buffer = (char*) pj_pool_alloc(pool, buffer_size);
        items[i].bytes_recv = items[i].bytes_sent = 0;

        /* randomize outgoing buffer. */
        pj_create_random_string(items[i].outgoing_buffer, buffer_size);

        /* Create socket pair. */
	TRACE_((THIS_FILE, "      calling socketpair.."));
        rc = app_socketpair(pj_AF_INET(), sock_type, 0, 
                            &items[i].server_fd, &items[i].client_fd);
        if (rc != PJ_SUCCESS) {
            app_perror("...error: unable to create socket pair", rc);
            return -20;
        }

        /* Register server socket to ioqueue. */
	TRACE_((THIS_FILE, "      register(1).."));
        rc = pj_ioqueue_register_sock(pool, ioqueue, 
                                      items[i].server_fd,
                                      &items[i], &ioqueue_callback,
                                      &items[i].server_key);
        if (rc != PJ_SUCCESS) {
            app_perror("...error: registering server socket to ioqueue", rc);
            return -60;
        }

        /* Register client socket to ioqueue. */
	TRACE_((THIS_FILE, "      register(2).."));
        rc = pj_ioqueue_register_sock(pool, ioqueue, 
                                      items[i].client_fd,
                                      &items[i],  &ioqueue_callback,
                                      &items[i].client_key);
        if (rc != PJ_SUCCESS) {
            app_perror("...error: registering server socket to ioqueue", rc);
            return -70;
        }

        /* Start reading. */
	TRACE_((THIS_FILE, "      pj_ioqueue_recv.."));
        bytes = items[i].buffer_size;
        rc = pj_ioqueue_recv(items[i].server_key, &items[i].recv_op,
                             items[i].incoming_buffer, &bytes,
			     0);
        if (rc != PJ_EPENDING) {
            app_perror("...error: pj_ioqueue_recv", rc);
            return -73;
        }

        /* Start writing. */
	TRACE_((THIS_FILE, "      pj_ioqueue_write.."));
        bytes = items[i].buffer_size;
        rc = pj_ioqueue_send(items[i].client_key, &items[i].send_op,
                             items[i].outgoing_buffer, &bytes, 0);
        if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
            app_perror("...error: pj_ioqueue_write", rc);
            return -76;
        }

        items[i].has_pending_send = (rc==PJ_EPENDING);
    }

    /* Create the threads. */
    for (i=0; i<thread_cnt; ++i) {
	struct thread_arg *arg;

	arg = (struct thread_arg*) pj_pool_zalloc(pool, sizeof(*arg));
	arg->id = i;
	arg->ioqueue = ioqueue;
	arg->counter = 0;

        rc = pj_thread_create( pool, NULL, 
                               &worker_thread, 
                               arg, 
                               PJ_THREAD_DEFAULT_STACK_SIZE, 
                               PJ_THREAD_SUSPENDED, &thread[i] );
        if (rc != PJ_SUCCESS) {
            app_perror("...error: unable to create thread", rc);
            return -80;
        }
    }

    /* Mark start time. */
    rc = pj_get_timestamp(&start);
    if (rc != PJ_SUCCESS)
        return -90;

    /* Start the thread. */
    TRACE_((THIS_FILE, "     resuming all threads.."));
    for (i=0; i<thread_cnt; ++i) {
        rc = pj_thread_resume(thread[i]);
        if (rc != 0)
            return -100;
    }

    /* Wait for MSEC_DURATION seconds. 
     * This should be as simple as pj_thread_sleep(MSEC_DURATION) actually,
     * but unfortunately it doesn't work when system doesn't employ
     * timeslicing for threads.
     */
    TRACE_((THIS_FILE, "     wait for few seconds.."));
    do {
	pj_thread_sleep(1);

	/* Mark end time. */
	rc = pj_get_timestamp(&stop);

	if (thread_quit_flag) {
	    TRACE_((THIS_FILE, "      transfer limit reached.."));
	    break;
	}

	if (pj_elapsed_usec(&start,&stop)<MSEC_DURATION * 1000) {
	    TRACE_((THIS_FILE, "      time limit reached.."));
	    break;
	}

    } while (1);

    /* Terminate all threads. */
    TRACE_((THIS_FILE, "     terminating all threads.."));
    thread_quit_flag = 1;

    for (i=0; i<thread_cnt; ++i) {
	TRACE_((THIS_FILE, "      join thread %d..", i));
        pj_thread_join(thread[i]);
    }

    /* Close all sockets. */
    TRACE_((THIS_FILE, "     closing all sockets.."));
    for (i=0; i<sockpair_cnt; ++i) {
        pj_ioqueue_unregister(items[i].server_key);
        pj_ioqueue_unregister(items[i].client_key);
    }

    /* Destroy threads */
    for (i=0; i<thread_cnt; ++i) {
        pj_thread_destroy(thread[i]);
    }

    /* Destroy ioqueue. */
    TRACE_((THIS_FILE, "     destroying ioqueue.."));
    pj_ioqueue_destroy(ioqueue);

    /* Calculate actual time in usec. */
    total_elapsed_usec = pj_elapsed_usec(&start, &stop);

    /* Calculate total bytes received. */
    total_received = 0;
    for (i=0; i<sockpair_cnt; ++i) {
        total_received = items[i].bytes_recv;
    }

    /* bandwidth = total_received*1000/total_elapsed_usec */
    bandwidth = total_received;
    pj_highprec_mul(bandwidth, 1000);
    pj_highprec_div(bandwidth, total_elapsed_usec);
    
    *p_bandwidth = (pj_uint32_t)bandwidth;

    PJ_LOG(3,(THIS_FILE, "   %.4s    %2d        %2d       %8d KB/s",
              type_name, thread_cnt, sockpair_cnt,
              *p_bandwidth));

    /* Done. */
    pj_pool_release(pool);

    TRACE_((THIS_FILE, "    done.."));
    return 0;
}
Пример #27
0
/* 
 * Create Authorization/Proxy-Authorization response header based on the challege
 * in WWW-Authenticate/Proxy-Authenticate header.
 */
static pj_status_t auth_respond( pj_pool_t *req_pool,
				 const pjsip_www_authenticate_hdr *hdr,
				 const pjsip_uri *uri,
				 const pjsip_cred_info *cred_info,
				 const pjsip_method *method,
				 pj_pool_t *sess_pool,
				 pjsip_cached_auth *cached_auth,
				 pjsip_authorization_hdr **p_h_auth)
{
    pjsip_authorization_hdr *hauth;
    char tmp[PJSIP_MAX_URL_SIZE];
    pj_str_t uri_str;
    pj_pool_t *pool;
    pj_status_t status;

    /* Verify arguments. */
    PJ_ASSERT_RETURN(req_pool && hdr && uri && cred_info && method &&
		     sess_pool && cached_auth && p_h_auth, PJ_EINVAL);

    /* Print URL in the original request. */
    uri_str.ptr = tmp;
    uri_str.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, tmp,sizeof(tmp));
    if (uri_str.slen < 1) {
	pj_assert(!"URL is too long!");
	return PJSIP_EURITOOLONG;
    }

#   if (PJSIP_AUTH_HEADER_CACHING)
    {
	pool = sess_pool;
	PJ_UNUSED_ARG(req_pool);
    }
#   else
    {
	pool = req_pool;
	PJ_UNUSED_ARG(sess_pool);
    }
#   endif

    if (hdr->type == PJSIP_H_WWW_AUTHENTICATE)
	hauth = pjsip_authorization_hdr_create(pool);
    else if (hdr->type == PJSIP_H_PROXY_AUTHENTICATE)
	hauth = pjsip_proxy_authorization_hdr_create(pool);
    else {
	pj_assert(!"Invalid response header!");
	return PJSIP_EINVALIDHDR;
    }

    /* Only support digest scheme at the moment. */
    if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) {
	pj_str_t *cnonce = NULL;
	pj_uint32_t nc = 1;

	/* Update the session (nonce-count etc) if required. */
#	if PJSIP_AUTH_QOP_SUPPORT
	{
	    if (cached_auth) {
		update_digest_session( sess_pool, cached_auth, hdr );

		cnonce = &cached_auth->cnonce;
		nc = cached_auth->nc;
	    }
	}
#	endif	/* PJSIP_AUTH_QOP_SUPPORT */

	hauth->scheme = pjsip_DIGEST_STR;
	status = respond_digest( pool, &hauth->credential.digest,
				 &hdr->challenge.digest, &uri_str, cred_info,
				 cnonce, nc, &method->name);
	if (status != PJ_SUCCESS)
	    return status;

	/* Set qop type in auth session the first time only. */
	if (hdr->challenge.digest.qop.slen != 0 && cached_auth) {
	    if (cached_auth->qop_value == PJSIP_AUTH_QOP_NONE) {
		pj_str_t *qop_val = &hauth->credential.digest.qop;
		if (!pj_strcmp(qop_val, &pjsip_AUTH_STR)) {
		    cached_auth->qop_value = PJSIP_AUTH_QOP_AUTH;
		} else {
		    cached_auth->qop_value = PJSIP_AUTH_QOP_UNKNOWN;
		}
	    }
	}
    } else {
	return PJSIP_EINVALIDAUTHSCHEME;
    }

    /* Keep the new authorization header in the cache, only
     * if no qop is not present.
     */
#   if PJSIP_AUTH_HEADER_CACHING
    {
	if (hauth && cached_auth && cached_auth->qop_value == PJSIP_AUTH_QOP_NONE) {
	    pjsip_cached_auth_hdr *cached_hdr;

	    /* Delete old header with the same method. */
	    cached_hdr = cached_auth->cached_hdr.next;
	    while (cached_hdr != &cached_auth->cached_hdr) {
		if (pjsip_method_cmp(method, &cached_hdr->method)==0)
		    break;
		cached_hdr = cached_hdr->next;
	    }

	    /* Save the header to the list. */
	    if (cached_hdr != &cached_auth->cached_hdr) {
		cached_hdr->hdr = hauth;
	    } else {
		cached_hdr = pj_pool_alloc(pool, sizeof(*cached_hdr));
		pjsip_method_copy( pool, &cached_hdr->method, method);
		cached_hdr->hdr = hauth;
		pj_list_insert_before( &cached_auth->cached_hdr, cached_hdr );
	    }
	}

#	if defined(PJSIP_AUTH_AUTO_SEND_NEXT) && PJSIP_AUTH_AUTO_SEND_NEXT!=0
	    if (hdr != cached_auth->last_chal) {
		cached_auth->last_chal = pjsip_hdr_clone(sess_pool, hdr);
	    }
#	endif
    }
#   endif

    *p_h_auth = hauth;
    return PJ_SUCCESS;

}
Пример #28
0
/* API: configure the AVI */
PJ_DEF(pj_status_t) pjmedia_avi_dev_alloc( pjmedia_vid_dev_factory *f,
                                           pjmedia_avi_dev_param *p,
                                           pjmedia_vid_dev_index *p_id)
{
    pjmedia_vid_dev_index id;
    struct avi_factory *cf = (struct avi_factory*)f;
    unsigned local_idx;
    struct avi_dev_info *adi = NULL;
    pjmedia_format avi_fmt;
    const pjmedia_video_format_info *vfi;
    pj_status_t status;

    PJ_ASSERT_RETURN(f && p && p_id, PJ_EINVAL);

    if (p_id)
	*p_id = PJMEDIA_VID_INVALID_DEV;

    /* Get a free dev */
    for (local_idx=0; local_idx<cf->dev_count; ++local_idx) {
	if (cf->dev_info[local_idx].avi == NULL) {
	    adi = &cf->dev_info[local_idx];
	    break;
	}
    }

    if (!adi)
	return PJ_ETOOMANY;

    /* Convert local ID to global id */
    status = pjmedia_vid_dev_get_global_index(&cf->base, local_idx, &id);
    if (status != PJ_SUCCESS)
	return status;

    /* Reset */
    if (adi->pool) {
	pj_pool_release(adi->pool);
    }
    pj_bzero(adi, sizeof(*adi));

    /* Reinit */
    PJ_ASSERT_RETURN(p->path.slen, PJ_EINVAL);
    adi->pool = pj_pool_create(cf->pf, "avidi%p", 512, 512, NULL);


    /* Open the AVI */
    pj_strdup_with_null(adi->pool, &adi->fpath, &p->path);
    status = pjmedia_avi_player_create_streams(adi->pool, adi->fpath.ptr, 0,
                                               &adi->avi);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    adi->vid = pjmedia_avi_streams_get_stream_by_media(adi->avi, 0,
                                                       PJMEDIA_TYPE_VIDEO);
    if (!adi->vid) {
	status = PJMEDIA_EVID_BADFORMAT;
	PJ_LOG(4,(THIS_FILE, "Error: cannot find video in AVI %s",
		adi->fpath.ptr));
	goto on_error;
    }

    pjmedia_format_copy(&avi_fmt, &adi->vid->info.fmt);
    vfi = pjmedia_get_video_format_info(NULL, avi_fmt.id);
    /* Check whether the frame is encoded. */
    if (!vfi || vfi->bpp == 0) {
        /* Yes, prepare codec */
        const pjmedia_vid_codec_info *codec_info;
        pjmedia_vid_codec_param codec_param;
	pjmedia_video_apply_fmt_param vafp;

        /* Lookup codec */
        status = pjmedia_vid_codec_mgr_get_codec_info2(NULL,
                                                       avi_fmt.id,
                                                       &codec_info);
        if (status != PJ_SUCCESS || !codec_info)
            goto on_error;

        status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
                                                         &codec_param);
        if (status != PJ_SUCCESS)
            goto on_error;

        /* Open codec */
        status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
                                                   &adi->codec);
        if (status != PJ_SUCCESS)
            goto on_error;

        status = pjmedia_vid_codec_init(adi->codec, adi->pool);
        if (status != PJ_SUCCESS)
            goto on_error;

        codec_param.dir = PJMEDIA_DIR_DECODING;
        codec_param.packing = PJMEDIA_VID_PACKING_WHOLE;
        status = pjmedia_vid_codec_open(adi->codec, &codec_param);
        if (status != PJ_SUCCESS)
            goto on_error;

	/* Allocate buffer */
        avi_fmt.id = codec_info->dec_fmt_id[0];
        vfi = pjmedia_get_video_format_info(NULL, avi_fmt.id);
	pj_bzero(&vafp, sizeof(vafp));
	vafp.size = avi_fmt.det.vid.size;
	status = vfi->apply_fmt(vfi, &vafp);
	if (status != PJ_SUCCESS)
	    goto on_error;

	adi->enc_buf = pj_pool_alloc(adi->pool, vafp.framebytes);
	adi->enc_buf_size = vafp.framebytes;
    }

    /* Calculate title */
    if (p->title.slen) {
	pj_strdup_with_null(adi->pool, &adi->title, &p->title);
    } else {
	char *start = p->path.ptr + p->path.slen;
	pj_str_t tmp;

	while (start >= p->path.ptr) {
	    if (*start == '/' || *start == '\\')
		break;
	    --start;
	}
	tmp.ptr = start + 1;
	tmp.slen = p->path.ptr + p->path.slen - tmp.ptr;
	pj_strdup_with_null(adi->pool, &adi->title, &tmp);
    }

    /* Init device info */
    pj_ansi_strncpy(adi->info.name, adi->title.ptr, sizeof(adi->info.name)-1);
    pj_ansi_strncpy(adi->info.driver, DRIVER_NAME, sizeof(adi->info.driver)-1);
    adi->info.dir = PJMEDIA_DIR_CAPTURE;
    adi->info.has_callback = PJ_FALSE;

    adi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT;
    adi->info.fmt_cnt = 1;
    pjmedia_format_copy(&adi->info.fmt[0], &avi_fmt);

    /* Set out vars */
    if (p_id)
	*p_id = id;
    p->avi_streams = adi->avi;
    if (p->title.slen == 0)
	p->title = adi->title;

    return PJ_SUCCESS;

on_error:
    if (adi->codec) {
        pjmedia_vid_codec_close(adi->codec);
        adi->codec = NULL;
    }
    if (adi->pool) {
	pj_pool_release(adi->pool);
	adi->pool = NULL;
    }
    pjmedia_avi_dev_free(id);
    return status;
}
Пример #29
0
/*
 * PUT request scenario 1: sending the whole data at once
 */
int http_client_test_put1()
{
    pj_str_t url;
    pj_http_req_callback hcb;
    pj_http_req_param param;
    char *data;
    int length = 3875;
    char urlbuf[80];

    pj_bzero(&hcb, sizeof(hcb));
    hcb.on_complete = &on_complete;
    hcb.on_data_read = &on_data_read;
    hcb.on_response = &on_response;

    /* Create pool, timer, and ioqueue */
    pool = pj_pool_create(mem, NULL, 8192, 4096, NULL);
    if (pj_timer_heap_create(pool, 16, &timer_heap))
        return -51;
    if (pj_ioqueue_create(pool, 16, &ioqueue))
        return -52;

#ifdef USE_LOCAL_SERVER
    thread_quit = PJ_FALSE;
    g_server.action = ACTION_REPLY;
    g_server.send_content_length = PJ_TRUE;
    g_server.data_size = 0;
    g_server.buf_size = 4096;

    sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, 
                             &g_server.sock);
    if (sstatus != PJ_SUCCESS)
        return -41;

    pj_sockaddr_in_init(&addr, NULL, 0);

    sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr));
    if (sstatus != PJ_SUCCESS)
        return -43;

    {
	pj_sockaddr_in addr;
	int addr_len = sizeof(addr);
	sstatus = pj_sock_getsockname(g_server.sock, &addr, &addr_len);
	if (sstatus != PJ_SUCCESS)
	    return -44;
	g_server.port = pj_sockaddr_in_get_port(&addr);
	pj_ansi_snprintf(urlbuf, sizeof(urlbuf),
			 "http://127.0.0.1:%d/test/test.txt",
			 g_server.port);
	url = pj_str(urlbuf);
    }

    sstatus = pj_sock_listen(g_server.sock, 8);
    if (sstatus != PJ_SUCCESS)
        return -45;

    sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server,
                               0, 0, &g_server.thread);
    if (sstatus != PJ_SUCCESS)
        return -47;

#else
    pj_cstr(&url, "http://127.0.0.1:280/test/test.txt");

#endif

    pj_http_req_param_default(&param);
    pj_strset2(&param.method, (char*)"PUT");
    data = (char*)pj_pool_alloc(pool, length);
    pj_create_random_string(data, length);
    pj_ansi_sprintf(data, "PUT test\n");
    param.reqdata.data = data;
    param.reqdata.size = length;
    if (pj_http_req_create(pool, &url, timer_heap, ioqueue, 
                           &param, &hcb, &http_req))
        return -53;

    if (pj_http_req_start(http_req))
        return -55;

    while (pj_http_req_is_running(http_req)) {
        pj_time_val delay = {0, 50};
	pj_ioqueue_poll(ioqueue, &delay);
	pj_timer_heap_poll(timer_heap, NULL);
    }

#ifdef USE_LOCAL_SERVER
    thread_quit = PJ_TRUE;
    pj_thread_join(g_server.thread);
    pj_sock_close(g_server.sock);
#endif

    pj_http_req_destroy(http_req);
    pj_ioqueue_destroy(ioqueue);
    pj_timer_heap_destroy(timer_heap);
    pj_pool_release(pool);

    return PJ_SUCCESS;
}
Пример #30
0
/*
 * Compliance test for success scenario.
 */
static int compliance_test_0(pj_bool_t allow_concur)
{
    pj_sock_t ssock=-1, csock0=-1, csock1=-1;
    pj_sockaddr_in addr, client_addr, rmt_addr;
    int client_addr_len;
    pj_pool_t *pool = NULL;
    char *send_buf, *recv_buf;
    pj_ioqueue_t *ioque = NULL;
    pj_ioqueue_key_t *skey=NULL, *ckey0=NULL, *ckey1=NULL;
    pj_ioqueue_op_key_t accept_op;
    int bufsize = BUF_MIN_SIZE;
    int status = -1;
    int pending_op = 0;
    pj_timestamp t_elapsed;
    pj_str_t s;
    pj_status_t rc;

    // Create pool.
    pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);

    // Allocate buffers for send and receive.
    send_buf = (char*)pj_pool_alloc(pool, bufsize);
    recv_buf = (char*)pj_pool_alloc(pool, bufsize);

    // Create server socket and client socket for connecting
    rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &ssock);
    if (rc != PJ_SUCCESS) {
        app_perror("...error creating socket", rc);
        status=-1; goto on_error;
    }

    rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &csock1);
    if (rc != PJ_SUCCESS) {
        app_perror("...error creating socket", rc);
	status=-1; goto on_error;
    }

    // Bind server socket.
    pj_sockaddr_in_init(&addr, 0, 0);
    if ((rc=pj_sock_bind(ssock, &addr, sizeof(addr))) != 0 ) {
        app_perror("...bind error", rc);
	status=-10; goto on_error;
    }

    // Get server address.
    client_addr_len = sizeof(addr);
    rc = pj_sock_getsockname(ssock, &addr, &client_addr_len);
    if (rc != PJ_SUCCESS) {
        app_perror("...ERROR in pj_sock_getsockname()", rc);
	status=-15; goto on_error;
    }
    addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));

    // Create I/O Queue.
    rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
    if (rc != PJ_SUCCESS) {
        app_perror("...ERROR in pj_ioqueue_create()", rc);
	status=-20; goto on_error;
    }

    // Concurrency
    rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur);
    if (rc != PJ_SUCCESS) {
        app_perror("...ERROR in pj_ioqueue_set_default_concurrency()", rc);
	status=-21; goto on_error;
    }

    // Register server socket and client socket.
    rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, &test_cb, &skey);
    if (rc == PJ_SUCCESS)
        rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL, &test_cb, 
                                      &ckey1);
    else
        ckey1 = NULL;
    if (rc != PJ_SUCCESS) {
        app_perror("...ERROR in pj_ioqueue_register_sock()", rc);
	status=-23; goto on_error;
    }

    // Server socket listen().
    if (pj_sock_listen(ssock, 5)) {
        app_perror("...ERROR in pj_sock_listen()", rc);
	status=-25; goto on_error;
    }

    // Server socket accept()
    client_addr_len = sizeof(pj_sockaddr_in);
    status = pj_ioqueue_accept(skey, &accept_op, &csock0, 
                               &client_addr, &rmt_addr, &client_addr_len);
    if (status != PJ_EPENDING) {
        app_perror("...ERROR in pj_ioqueue_accept()", rc);
	status=-30; goto on_error;
    }
    if (status==PJ_EPENDING) {
	++pending_op;
    }

    // Client socket connect()
    status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr));
    if (status!=PJ_SUCCESS && status != PJ_EPENDING) {
        app_perror("...ERROR in pj_ioqueue_connect()", rc);
	status=-40; goto on_error;
    }
    if (status==PJ_EPENDING) {
	++pending_op;
    }

    // Poll until connected
    callback_read_size = callback_write_size = 0;
    callback_accept_status = callback_connect_status = -2;
    callback_call_count = 0;

    callback_read_key = callback_write_key = 
        callback_accept_key = callback_connect_key = NULL;
    callback_accept_op = callback_read_op = callback_write_op = NULL;

    while (pending_op) {
	pj_time_val timeout = {1, 0};

#ifdef PJ_SYMBIAN
	callback_call_count = 0;
	pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
	status = callback_call_count;
#else
	status = pj_ioqueue_poll(ioque, &timeout);
#endif
	if (status > 0) {
            if (callback_accept_status != -2) {
                if (callback_accept_status != 0) {
                    status=-41; goto on_error;
                }
                if (callback_accept_key != skey) {
                    status=-42; goto on_error;
                }
                if (callback_accept_op != &accept_op) {
                    status=-43; goto on_error;
                }
                callback_accept_status = -2;
            }

            if (callback_connect_status != -2) {
                if (callback_connect_status != 0) {
                    status=-50; goto on_error;
                }
                if (callback_connect_key != ckey1) {
                    status=-51; goto on_error;
                }
                callback_connect_status = -2;
            }

	    if (status > pending_op) {
		PJ_LOG(3,(THIS_FILE,
			  "...error: pj_ioqueue_poll() returned %d "
			  "(only expecting %d)",
			  status, pending_op));
		return -52;
	    }
	    pending_op -= status;

	    if (pending_op == 0) {
		status = 0;
	    }
	}
    }

    // There's no pending operation.
    // When we poll the ioqueue, there must not be events.
    if (pending_op == 0) {
        pj_time_val timeout = {1, 0};
#ifdef PJ_SYMBIAN
	status = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
#else
        status = pj_ioqueue_poll(ioque, &timeout);
#endif
        if (status != 0) {
            status=-60; goto on_error;
        }
    }

    // Check accepted socket.
    if (csock0 == PJ_INVALID_SOCKET) {
	status = -69;
        app_perror("...accept() error", pj_get_os_error());
	goto on_error;
    }

    // Register newly accepted socket.
    rc = pj_ioqueue_register_sock(pool, ioque, csock0, NULL, 
                                  &test_cb, &ckey0);
    if (rc != PJ_SUCCESS) {
        app_perror("...ERROR in pj_ioqueue_register_sock", rc);
	status = -70;
	goto on_error;
    }

    // Test send and receive.
    t_elapsed.u32.lo = 0;
    status = send_recv_test(ioque, ckey0, ckey1, send_buf, 
                            recv_buf, bufsize, &t_elapsed);
    if (status != 0) {
	goto on_error;
    }

    // Success
    status = 0;

on_error:
    if (skey != NULL)
    	pj_ioqueue_unregister(skey);
    else if (ssock != PJ_INVALID_SOCKET)
	pj_sock_close(ssock);
    
    if (ckey1 != NULL)
    	pj_ioqueue_unregister(ckey1);
    else if (csock1 != PJ_INVALID_SOCKET)
	pj_sock_close(csock1);
    
    if (ckey0 != NULL)
    	pj_ioqueue_unregister(ckey0);
    else if (csock0 != PJ_INVALID_SOCKET)
	pj_sock_close(csock0);
    
    if (ioque != NULL)
	pj_ioqueue_destroy(ioque);
    pj_pool_release(pool);
    return status;

}