Example #1
0
PJ_DEF(pj_status_t) pjmedia_converter_mgr_create(pj_pool_t *pool,
					         pjmedia_converter_mgr **p_mgr)
{
    pjmedia_converter_mgr *mgr;
    pj_status_t status = PJ_SUCCESS;

    mgr = PJ_POOL_ALLOC_T(pool, pjmedia_converter_mgr);
    pj_list_init(&mgr->factory_list);

    if (!converter_manager_instance)
	converter_manager_instance = mgr;

#if defined(PJMEDIA_HAS_LIBYUV) && PJMEDIA_HAS_LIBYUV != 0
    status = pjmedia_libyuv_converter_init(mgr);
    if (status != PJ_SUCCESS) {
	PJ_PERROR(4,(THIS_FILE, status,
		     "Error initializing libyuv converter"));
    }
#endif

#if PJMEDIA_HAS_LIBSWSCALE && PJMEDIA_HAS_LIBAVUTIL
    status = pjmedia_libswscale_converter_init(mgr);
    if (status != PJ_SUCCESS) {
	PJ_PERROR(4,(THIS_FILE, status,
		     "Error initializing libswscale converter"));
    }
#endif

    if (p_mgr)
	*p_mgr = mgr;

    return status;
}
Example #2
0
/*
 * API: set capability
 * Currently just supporting toggle between speaker and earpiece
 */
static pj_status_t bb10_stream_set_cap(pjmedia_aud_stream *strm,
                                       pjmedia_aud_dev_cap cap,
                                       const void *value)
{

    struct bb10_stream *stream = (struct bb10_stream*)strm;

    if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE &&
        (stream->param.dir & PJMEDIA_DIR_PLAYBACK))
    {
	pjmedia_aud_dev_route route;
	pj_bool_t need_restart;
	pj_status_t ret;

	PJ_ASSERT_RETURN(value, PJ_EINVAL);

	/* OS 10.2.1 requires pausing audio stream */
	need_restart = (stream->pb_thread != NULL);
	if (need_restart) {
	    PJ_LOG(4,(THIS_FILE, "pausing audio stream.."));
	    ret = bb10_stream_stop(strm);
	    if (ret != PJ_SUCCESS) {
		PJ_PERROR(1,(THIS_FILE, ret, "Error pausing stream"));
		return ret;
	    }
	}

    	route = *((pjmedia_aud_dev_route*)value);
    	PJ_LOG(4,(THIS_FILE, "setting audio route to %d..", route));

        /* Use the initialization function which lazy-inits the
         * handle for routing
         */
    	if (route == PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER) {
            ret = bb10_initialize_playback_ctrl(stream,true);
        } else {
            ret = bb10_initialize_playback_ctrl(stream,false);
        }

    	if (need_restart) {
	    PJ_LOG(4,(THIS_FILE, "resuming audio stream.."));
	    ret = bb10_stream_start(strm);
	    if (ret != PJ_SUCCESS) {
		PJ_PERROR(1,(THIS_FILE, ret, "Error resuming stream"));
	    }
    	}

    	return ret;

    } else if (cap==PJMEDIA_AUD_DEV_CAP_EC &&
	       (stream->param.dir & PJMEDIA_DIR_CAPTURE))
    {
	/* EC is always enabled. Silently ignore the request */
	return PJ_SUCCESS;
    }

    TRACE_((THIS_FILE,"bb10_stream_set_cap() = PJMEDIA_EAUD_INVCAP"));
    return PJMEDIA_EAUD_INVCAP;
}
Example #3
0
static int stun_destroy_test_session(struct stun_test_session *test_sess)
{

    unsigned i;
    pj_stun_sock_cb stun_cb;
    pj_status_t status;
    pj_stun_sock *stun_sock[MAX_SOCK_CLIENTS];

    pj_bzero(&stun_cb, sizeof(stun_cb));
    stun_cb.on_status = &stun_sock_on_status;

    pj_event_reset(test_sess->server_event);

    /* Create all clients first */
    for (i=0; i<MAX_SOCK_CLIENTS; ++i) {
	char name[10];
	sprintf(name, "stun%02d", i);
	status = pj_stun_sock_create(&test_sess->stun_cfg, name, pj_AF_INET(),
	                             &stun_cb, NULL, test_sess,
	                             &stun_sock[i]);
	if (status != PJ_SUCCESS) {
	    PJ_PERROR(1,(THIS_FILE, status, "Error creating stun socket"));
	    return -10;
	}
    }

    /* Start resolution */
    for (i=0; i<MAX_SOCK_CLIENTS; ++i) {
	pj_str_t server_ip = pj_str("127.0.0.1");
	status = pj_stun_sock_start(stun_sock[i], &server_ip,
	                            (pj_uint16_t)test_sess->server_port, NULL);
	if (status != PJ_SUCCESS) {
	    PJ_PERROR(1,(THIS_FILE, status, "Error starting stun socket"));
	    return -20;
	}
    }

    /* settle down */
    pj_thread_sleep(test_sess->param.client_sleep_after_start);

    /* Resume server threads */
    pj_event_set(test_sess->server_event);

    pj_thread_sleep(test_sess->param.client_sleep_before_destroy);

    /* Destroy clients */
    for (i=0; i<MAX_SOCK_CLIENTS; ++i) {
	status = pj_stun_sock_destroy(stun_sock[i]);
	if (status != PJ_SUCCESS) {
	    PJ_PERROR(1,(THIS_FILE, status, "Error destroying stun socket"));
	}
    }

    /* Give some time to ioqueue to free sockets */
    pj_thread_sleep(PJ_IOQUEUE_KEY_FREE_DELAY);

    return 0;
}
Example #4
0
/*
 * main()
 */
int main(int argc, char *argv[])
{
    pj_caching_pool cp;
    pj_status_t status;

    if (argc < 2 || argc > 3) {
	puts("Usage: httpdemo URL [output-filename]");
	return 1;
    }

    pj_log_set_level(5);

    pj_init();
    pj_caching_pool_init(&cp, NULL, 0);
    mem = &cp.factory;
    pjlib_util_init();

    if (argc > 2)
	f = fopen(argv[2], "wb");
    else
	f = stdout;

    status = getURL(argv[1]);
    if (status != PJ_SUCCESS) {
        PJ_PERROR(1, (THIS_FILE, status, "Error"));
    }

    if (f != stdout)
	fclose(f);

    pj_caching_pool_destroy(&cp);
    pj_shutdown();
    return 0;
}
Example #5
0
/*
 * udp_on_write_complete()
 *
 * This is callback notification from ioqueue that a pending sendto()
 * operation has completed.
 */
static void udp_on_write_complete( pj_ioqueue_key_t *key, 
				   pj_ioqueue_op_key_t *op_key,
				   pj_ssize_t bytes_sent)
{
    struct udp_transport *tp = (struct udp_transport*) 
    			       pj_ioqueue_get_user_data(key);
    pjsip_tx_data_op_key *tdata_op_key = (pjsip_tx_data_op_key*)op_key;

    tdata_op_key->tdata = NULL;

#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
    	    PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
    if (-bytes_sent == PJ_ESOCKETSTOP) {
	pj_status_t status;
	/* Try to recover by restarting the transport. */
	PJ_LOG(4,(tp->base.obj_name, "Restarting SIP UDP transport"));
	status = pjsip_udp_transport_restart2(
			    &tp->base,
			    PJSIP_UDP_TRANSPORT_DESTROY_SOCKET,
			    PJ_INVALID_SOCKET,
			    &tp->base.local_addr,
			    &tp->base.local_name);

	if (status != PJ_SUCCESS) {
	    PJ_PERROR(1,(THIS_FILE, status,
			 "Error restarting SIP UDP transport"));
	}
        return;
    }
#endif

    if (tdata_op_key->callback) {
	tdata_op_key->callback(&tp->base, tdata_op_key->token, bytes_sent);
    }
}
Example #6
0
static pj_status_t create_converter(pjmedia_vid_port *vp)
{
    if (vp->conv.conv) {
        pjmedia_converter_destroy(vp->conv.conv);
	vp->conv.conv = NULL;
    }

    /* Instantiate converter if necessary */
    if (vp->conv.conv_param.src.id != vp->conv.conv_param.dst.id ||
	(vp->conv.conv_param.src.det.vid.size.w !=
         vp->conv.conv_param.dst.det.vid.size.w) ||
	(vp->conv.conv_param.src.det.vid.size.h !=
         vp->conv.conv_param.dst.det.vid.size.h))
    {
	pj_status_t status;

	/* Yes, we need converter */
	status = pjmedia_converter_create(NULL, vp->pool, &vp->conv.conv_param,
					  &vp->conv.conv);
	if (status != PJ_SUCCESS) {
	    PJ_PERROR(4,(THIS_FILE, status, "Error creating converter"));
	    return status;
	}
    }

    if (vp->conv.conv ||
        (vp->role==ROLE_ACTIVE && (vp->dir & PJMEDIA_DIR_ENCODING)))
    {
	pj_status_t status;
	const pjmedia_video_format_info *vfi;
	pjmedia_video_apply_fmt_param vafp;

	/* Allocate buffer for conversion */
	vfi = pjmedia_get_video_format_info(NULL, vp->conv.conv_param.dst.id);
	if (!vfi)
	    return PJMEDIA_EBADFMT;

	pj_bzero(&vafp, sizeof(vafp));
	vafp.size = vp->conv.conv_param.dst.det.vid.size;
	status = vfi->apply_fmt(vfi, &vafp);
	if (status != PJ_SUCCESS)
	    return PJMEDIA_EBADFMT;

	if (vafp.framebytes > vp->conv.conv_buf_size) {
	    vp->conv.conv_buf = pj_pool_alloc(vp->pool, vafp.framebytes);
	    vp->conv.conv_buf_size = vafp.framebytes;
	}
    }

    vp->conv.usec_ctr = 0;
    vp->conv.usec_src = PJMEDIA_PTIME(&vp->conv.conv_param.src.det.vid.fps);
    vp->conv.usec_dst = PJMEDIA_PTIME(&vp->conv.conv_param.dst.det.vid.fps);

    return PJ_SUCCESS;
}
Example #7
0
/* Notify application that session has failed */
static pj_bool_t sess_fail(pj_stun_sock *stun_sock, 
			   pj_stun_sock_op op,
			   pj_status_t status)
{
    pj_bool_t ret;

    PJ_PERROR(4,(stun_sock->obj_name, status, 
	         "Session failed because %s failed",
		 pj_stun_sock_op_name(op)));

    ret = (*stun_sock->cb.on_status)(stun_sock, op, status);

    return ret;
}
Example #8
0
static void on_complete(pj_http_req *hreq, pj_status_t status,
                        const pj_http_resp *resp)
{
    PJ_UNUSED_ARG(hreq);

    if (status != PJ_SUCCESS) {
        PJ_PERROR(1, (THIS_FILE, status, "HTTP request completed with error"));
        return;
    }
    PJ_LOG(3, (THIS_FILE, "Data completed: %d bytes", resp->size));
    if (resp->size > 0 && resp->data) {
#ifdef VERBOSE
        printf("%.*s\n", (int)resp->size, (char *)resp->data);
#endif
    }
}
Example #9
0
static pj_status_t create_converter(pjmedia_vid_port *vp)
{
    /* Instantiate converter if necessary */
    if (vp->conv_param.src.id != vp->conv_param.dst.id ||
	vp->conv_param.src.det.vid.size.w != vp->conv_param.dst.det.vid.size.w ||
	vp->conv_param.src.det.vid.size.h != vp->conv_param.dst.det.vid.size.h)
    {
	pj_status_t status;

	/* Yes, we need converter */
	const pjmedia_video_format_info *vfi;
	pjmedia_video_apply_fmt_param vafp;

	if (vp->conv) {
	    pjmedia_converter_destroy(vp->conv);
	    vp->conv = NULL;
	}

	status = pjmedia_converter_create(NULL, vp->pool, &vp->conv_param,
					  &vp->conv);
	if (status != PJ_SUCCESS) {
	    PJ_PERROR(4,(THIS_FILE, status, "Error creating converter"));
	    return status;
	}

	/* Allocate buffer for conversion */
	vfi = pjmedia_get_video_format_info(NULL, vp->conv_param.dst.id);
	if (!vfi)
	    return PJMEDIA_EBADFMT;

	pj_bzero(&vafp, sizeof(vafp));
	vafp.size = vp->conv_param.dst.det.vid.size;
	status = vfi->apply_fmt(vfi, &vafp);
	if (status != PJ_SUCCESS)
	    return PJMEDIA_EBADFMT;

	if (vafp.framebytes > vp->conv_buf_size) {
	    vp->conv_buf = pj_pool_alloc(vp->pool, vafp.framebytes);
	    vp->conv_buf_size = vafp.framebytes;
	}
    }

    return PJ_SUCCESS;
}
Example #10
0
/* API: Refresh the list of video devices installed in the system. */
PJ_DEF(pj_status_t) pjmedia_vid_dev_refresh(void)
{
    unsigned i;
    
    vid_subsys.dev_cnt = 0;
    for (i=0; i<vid_subsys.drv_cnt; ++i) {
	pjmedia_vid_driver *drv = &vid_subsys.drv[i];
	
	if (drv->f && drv->f->op->refresh) {
	    pj_status_t status = drv->f->op->refresh(drv->f);
	    if (status != PJ_SUCCESS) {
		PJ_PERROR(4, (THIS_FILE, status, "Unable to refresh device "
						 "list for %s", drv->name));
	    }
	}
	pjmedia_vid_driver_init(i, PJ_TRUE);
    }
    return PJ_SUCCESS;
}
Example #11
0
static pj_status_t openh264_codec_decode( pjmedia_vid_codec *codec,
					pj_size_t pkt_count,
					pjmedia_frame packets[],
					unsigned out_size,
					pjmedia_frame *output)
{
    openh264_private *ff = (openh264_private*)codec->codec_data;
    pj_status_t status;

    PJ_ASSERT_RETURN(codec && pkt_count > 0 && packets && output,
                     PJ_EINVAL);

    if (ff->whole) {
		pj_assert(pkt_count==1);
		return openh264_codec_decode_whole(codec, &packets[0], out_size, output);
    } else {
		pjmedia_frame whole_frm;
		unsigned whole_len = 0;
		unsigned i;

		for (i=0; i<pkt_count; ++i) {
			if (whole_len + packets[i].size > ff->dec_buf_size) {
				PJ_LOG(5,(THIS_FILE, "Decoding buffer overflow"));
				break;
			}

			status = openh264_unpacketize(codec, packets[i].buf, packets[i].size,
										ff->dec_buf, ff->dec_buf_size,
										&whole_len);
			if (status != PJ_SUCCESS) {
				PJ_PERROR(5,(THIS_FILE, status, "Unpacketize error"));
				continue;
			}
		}

		whole_frm.buf = ff->dec_buf;
		whole_frm.size = whole_len;
		whole_frm.timestamp = output->timestamp = packets[i].timestamp;
		whole_frm.bit_info = 0;

		return openh264_codec_decode_whole(codec, &whole_frm, out_size, output);
    }
}
Example #12
0
/*
 * Simple implementation of app_main() for console targets
 */
pj_status_t app_main(pj_cli_t *cli) {
    print_msg(("", "APP STARTED \n \n \n"));
    print_msg(("", "======================================================================\n"));
    pj_status_t status;
    pj_cli_sess *sess;
    pj_cli_console_cfg console_cfg;

    pj_cli_console_cfg_default(&console_cfg);
    console_cfg.prompt_str = pj_str("CMD> ");

    /*
     * Create the console front end
     */
    status = pj_cli_console_create(cli, &console_cfg, &sess, NULL);
    if (status != PJ_SUCCESS)
        return status;

    pj_log_set_log_func(&log_writer);

    /*
     * Main loop.
     */
    for (;;) {
        char cmdline[PJ_CLI_MAX_CMDBUF];
        pj_status_t status;

        status = pj_cli_console_process(sess, &cmdline[0], sizeof(cmdline));
        if (status != PJ_SUCCESS)
            break;

        // pj_ansi_strcpy(cmdline, "sayhello {Teluu Inc.}");
        if (status == PJ_CLI_EEXIT) {
            /* exit is called */
            break;
        } else if (status != PJ_SUCCESS) {
            /* Something wrong with the cmdline */
            PJ_PERROR(1, (THIS_FILE, status, "Exec error"));
        }
    }

    return PJ_SUCCESS;
}
Example #13
0
PJ_DEF(pj_ioqueue_key_t*) pj_ioqueue_register( pj_pool_t *pool,
					       pj_ioqueue_t *ioque,
					       pj_oshandle_t sock,
					       void *user_data,
					       const pj_ioqueue_callback *cb)
{
    pj_ioqueue_key_t *key = NULL;
    pj_uint32_t value;
    
    pj_mutex_lock(ioque->mutex);

    if (ioque->count >= ioque->max)
	goto on_return;

    /* Set socket to nonblocking. */
    value = 1;
    if (pj_sock_ioctl((pj_sock_t)sock, PJ_FIONBIO, &value)) {
	PJ_PERROR(("ioqueue", "Error setting FIONBIO"));
	goto on_return;
    }

    /* Create key. */
    key = (pj_ioqueue_key_t*)pj_pool_calloc(pool, 1, sizeof(pj_ioqueue_key_t));
    key->fd = (pj_sock_t)sock;
    key->user_data = user_data;

    /* Save callback. */
    pj_memcpy(&key->cb, cb, sizeof(pj_ioqueue_callback));

    /* Register */
    pj_list_insert_before(&ioque->hlist, key);
    ++ioque->count;

on_return:
    pj_mutex_unlock(ioque->mutex);
    return key;
}
Example #14
0
/*
 * Set socket option.
 */
PJ_DEF(pj_status_t) pj_sock_setsockopt_params( pj_sock_t sockfd,
					       const pj_sockopt_params *params)
{
    unsigned int i = 0;
    pj_status_t retval = PJ_SUCCESS;
    PJ_CHECK_STACK();
    PJ_ASSERT_RETURN(params, PJ_EINVAL);
    
    for (;i<params->cnt && i<PJ_MAX_SOCKOPT_PARAMS;++i) {
	pj_status_t status = pj_sock_setsockopt(sockfd, 
					(pj_uint16_t)params->options[i].level,
					(pj_uint16_t)params->options[i].optname,
					params->options[i].optval, 
					params->options[i].optlen);
	if (status != PJ_SUCCESS) {
	    retval = status;
	    PJ_PERROR(4,(THIS_FILE, status,
			 "Warning: error applying sock opt %d",
			 params->options[i].optname));
	}
    }

    return retval;
}
Example #15
0
static int server_thread_proc(void *p)
{
    struct stun_test_session *test_sess = (struct stun_test_session*)p;
    pj_pool_t *pool;
    pj_status_t status;

    PJ_LOG(4,(THIS_FILE, "Server thread running"));

    pool = pj_pool_create(test_sess->stun_cfg.pf, "server", 512, 512, NULL);

    while (!test_sess->thread_quit_flag) {
	pj_time_val timeout = {0, 10};
	pj_fd_set_t rdset;
	int n;

	/* Serve client */
	PJ_FD_ZERO(&rdset);
	PJ_FD_SET(test_sess->server_sock, &rdset);
	n = pj_sock_select(test_sess->server_sock+1, &rdset,
	                   NULL, NULL, &timeout);
	if (n==1 && PJ_FD_ISSET(test_sess->server_sock, &rdset)) {
	    pj_uint8_t pkt[512];
	    pj_ssize_t pkt_len;
	    pj_size_t res_len;
	    pj_sockaddr client_addr;
	    int addr_len;

	    pj_stun_msg	*stun_req, *stun_res;

	    pj_pool_reset(pool);

	    /* Got query */
	    pkt_len = sizeof(pkt);
	    addr_len = sizeof(client_addr);
	    status = pj_sock_recvfrom(test_sess->server_sock, pkt, &pkt_len,
	                              0, &client_addr, &addr_len);
	    if (status != PJ_SUCCESS) {
		continue;
	    }

	    status = pj_stun_msg_decode(pool, pkt, pkt_len,
	                                PJ_STUN_IS_DATAGRAM,
	                                &stun_req, NULL, NULL);
	    if (status != PJ_SUCCESS) {
		PJ_PERROR(1,(THIS_FILE, status, "STUN request decode error"));
		continue;
	    }

	    status = pj_stun_msg_create_response(pool, stun_req,
	                                         PJ_STUN_SC_BAD_REQUEST, NULL,
	                                         &stun_res);
	    if (status != PJ_SUCCESS) {
		PJ_PERROR(1,(THIS_FILE, status, "STUN create response error"));
		continue;
	    }

	    status = pj_stun_msg_encode(stun_res, pkt, sizeof(pkt), 0,
	                                NULL, &res_len);
	    if (status != PJ_SUCCESS) {
		PJ_PERROR(1,(THIS_FILE, status, "STUN encode error"));
		continue;
	    }

	    /* Ignore request */
	    if (test_sess->param.server_drop_request)
		continue;

	    /* Wait for signal to continue */
	    if (test_sess->param.server_wait_for_event)
		pj_event_wait(test_sess->server_event);

	    pkt_len = res_len;
	    pj_sock_sendto(test_sess->server_sock, pkt, &pkt_len, 0,
	                   &client_addr, pj_sockaddr_get_len(&client_addr));
	}
    }

    pj_pool_release(pool);

    PJ_LOG(4,(THIS_FILE, "Server thread quitting"));
    return 0;
}
Example #16
0
/*
 * pj_ioqueue_sendto()
 *
 * Start asynchronous write() to the descriptor.
 */
PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
                                       pj_ioqueue_op_key_t *op_key,
			               const void *data,
			               pj_ssize_t *length,
                                       pj_uint32_t flags,
			               const pj_sockaddr_t *addr,
			               int addrlen)
{
    struct write_operation *write_op;
    unsigned retry;
    pj_bool_t restart_retry = PJ_FALSE;
    pj_status_t status;
    pj_ssize_t sent;

    PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);
    PJ_CHECK_STACK();

#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
	    PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
retry_on_restart:
#else
    PJ_UNUSED_ARG(restart_retry);
#endif
    /* Check if key is closing. */
    if (IS_CLOSING(key))
	return PJ_ECANCELLED;

    /* We can not use PJ_IOQUEUE_ALWAYS_ASYNC for socket write */
    flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);

    /* Fast track:
     *   Try to send data immediately, only if there's no pending write!
     * Note:
     *  We are speculating that the list is empty here without properly
     *  acquiring ioqueue's mutex first. This is intentional, to maximize
     *  performance via parallelism.
     *
     *  This should be safe, because:
     *      - by convention, we require caller to make sure that the
     *        key is not unregistered while other threads are invoking
     *        an operation on the same key.
     *      - pj_list_empty() is safe to be invoked by multiple threads,
     *        even when other threads are modifying the list.
     */
    if (pj_list_empty(&key->write_list)) {
        /*
         * See if data can be sent immediately.
         */
        sent = *length;
        status = pj_sock_sendto(key->fd, data, &sent, flags, addr, addrlen);
        if (status == PJ_SUCCESS) {
            /* Success! */
            *length = sent;
            return PJ_SUCCESS;
        } else {
            /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
             * the error to caller.
             */
            if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
	    PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
		/* Special treatment for dead UDP sockets here, see ticket #1107 */
		if (status==PJ_STATUS_FROM_OS(EPIPE) && !IS_CLOSING(key) &&
		    key->fd_type==pj_SOCK_DGRAM() && !restart_retry)
		{
		    PJ_PERROR(4,(THIS_FILE, status,
				 "Send error for socket %d, retrying",
				 key->fd));
		    replace_udp_sock(key);
		    restart_retry = PJ_TRUE;
		    goto retry_on_restart;
		}
#endif

                return status;
            }
        }
    }

    /*
     * Check that address storage can hold the address parameter.
     */
    PJ_ASSERT_RETURN(addrlen <= (int)sizeof(pj_sockaddr_in), PJ_EBUG);

    /*
     * Schedule asynchronous send.
     */
    write_op = (struct write_operation*)op_key;
    
    /* Spin if write_op has pending operation */
    for (retry=0; write_op->op != 0 && retry<PENDING_RETRY; ++retry)
	pj_thread_sleep(0);

    /* Last chance */
    if (write_op->op) {
	/* Unable to send packet because there is already pending write on the
	 * write_op. We could not put the operation into the write_op
	 * because write_op already contains a pending operation! And
	 * we could not send the packet directly with sendto() either,
	 * because that will break the order of the packet. So we can
	 * only return error here.
	 *
	 * This could happen for example in multithreads program,
	 * where polling is done by one thread, while other threads are doing
	 * the sending only. If the polling thread runs on lower priority
	 * than the sending thread, then it's possible that the pending
	 * write flag is not cleared in-time because clearing is only done
	 * during polling. 
	 *
	 * Aplication should specify multiple write operation keys on
	 * situation like this.
	 */
	//pj_assert(!"ioqueue: there is pending operation on this key!");
	return PJ_EBUSY;
    }

    write_op->op = PJ_IOQUEUE_OP_SEND_TO;
    write_op->buf = (char*)data;
    write_op->size = *length;
    write_op->written = 0;
    write_op->flags = flags;
    pj_memcpy(&write_op->rmt_addr, addr, addrlen);
    write_op->rmt_addrlen = addrlen;
    
    pj_ioqueue_lock_key(key);
    /* Check again. Handle may have been closed after the previous check
     * in multithreaded app. If we add bad handle to the set it will
     * corrupt the ioqueue set. See #913
     */
    if (IS_CLOSING(key)) {
	pj_ioqueue_unlock_key(key);
	return PJ_ECANCELLED;
    }
    pj_list_insert_before(&key->write_list, write_op);
    ioqueue_add_to_set(key->ioqueue, key, WRITEABLE_EVENT);
    pj_ioqueue_unlock_key(key);

    return PJ_EPENDING;
}
Example #17
0
/* Display error */
static void show_err(pj_turn_sock *turn_sock, const char *title,
		     pj_status_t status)
{
    PJ_PERROR(4,(turn_sock->obj_name, status, title));
}
/*
 * This is the public API to create, initialize, register, and start the
 * TCP listener.
 */
PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
					pjsip_endpoint *endpt,
					const pjsip_tcp_transport_cfg *cfg,
					pjsip_tpfactory **p_factory
					)
{
    pj_pool_t *pool;
    pj_sock_t sock = PJ_INVALID_SOCKET;
    struct tcp_listener *listener;
    pj_activesock_cfg asock_cfg;
    pj_activesock_cb listener_cb;
    pj_sockaddr *listener_addr;
    int addr_len;
    pj_status_t status;

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

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

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

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


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

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

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


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

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

    /* Apply SO_REUSEADDR */
    if (cfg->reuse_addr) {
	int enabled = 1;
	status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_REUSEADDR(),
				    &enabled, sizeof(enabled));
	if (status != PJ_SUCCESS) {
	    PJ_PERROR(4,(listener->factory.obj_name, status,
		         "Warning: error applying SO_REUSEADDR"));
	}
    }

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

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

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

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

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

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

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

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

	    pj_sockaddr_copy_addr(listener_addr, &hostip);
	}

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

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

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


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


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

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

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

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

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

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

    return PJ_SUCCESS;

on_error:
    if (listener->asock==NULL && sock!=PJ_INVALID_SOCKET)
	pj_sock_close(sock);
    lis_destroy(&listener->factory);
    return status;
}
Example #19
0
static void parse_media(pj_scanner *scanner, pjmedia_sdp_media *med,
			parse_context *ctx)
{
    pj_str_t str;

    ctx->last_error = PJMEDIA_SDP_EINMEDIA;

    /* check the equal sign */
    if (*(scanner->curptr+1) != '=') {
	on_scanner_error(scanner);
	return;
    }

    /* m= */
    pj_scan_advance_n(scanner, 2, SKIP_WS);

    /* type */
    pj_scan_get_until_ch(scanner, ' ', &med->desc.media);
    pj_scan_get_char(scanner);

    /* port */
    pj_scan_get(scanner, &cs_token, &str);
    med->desc.port = (unsigned short)pj_strtoul(&str);
    if (*scanner->curptr == '/') {
	/* port count */
	pj_scan_get_char(scanner);
	pj_scan_get(scanner, &cs_token, &str);
	med->desc.port_count = pj_strtoul(&str);

    } else {
	med->desc.port_count = 0;
    }

    if (pj_scan_get_char(scanner) != ' ') {
	PJ_THROW(SYNTAX_ERROR);
    }

    /* transport */
    pj_scan_get_until_chr(scanner, " \t\r\n", &med->desc.transport);

    /* format list */
    med->desc.fmt_count = 0;
    while (*scanner->curptr == ' ') {
	pj_str_t fmt;

	pj_scan_get_char(scanner);

	/* Check again for the end of the line */
	if ((*scanner->curptr == '\r') || (*scanner->curptr == '\n'))
		break;

	pj_scan_get(scanner, &cs_token, &fmt);
	if (med->desc.fmt_count < PJMEDIA_MAX_SDP_FMT)
	    med->desc.fmt[med->desc.fmt_count++] = fmt;
	else
	    PJ_PERROR(2,(THIS_FILE, PJ_ETOOMANY, 
		         "Error adding SDP media format %.*s, "
			 "format is ignored",
			 (int)fmt.slen, fmt.ptr));
    }

    /* We've got what we're looking for, skip anything until newline */
    pj_scan_skip_line(scanner);
}
Example #20
0
static int encode_decode_test(pj_pool_t *pool, const char *codec_id,
                              pjmedia_vid_packing packing)
{
    const pj_str_t port_name = {"codec", 5};

    pjmedia_vid_codec *codec=NULL;
    pjmedia_port codec_port;
    codec_port_data_t codec_port_data;
    pjmedia_vid_codec_param codec_param;
    const pjmedia_vid_codec_info *codec_info;
    const char *packing_name;
    pjmedia_vid_dev_index cap_idx, rdr_idx;
    pjmedia_vid_port *capture=NULL, *renderer=NULL;
    pjmedia_vid_port_param vport_param;
    pjmedia_video_format_detail *vfd;
    char codec_name[5];
    pj_status_t status;
    int rc = 0;

    switch (packing) {
    case PJMEDIA_VID_PACKING_PACKETS:
        packing_name = "framed";
        break;
    case PJMEDIA_VID_PACKING_WHOLE:
        packing_name = "whole";
        break;
    default:
        packing_name = "unknown";
        break;
    }

    PJ_LOG(3, (THIS_FILE, "  encode decode test: codec=%s, packing=%s",
               codec_id, packing_name));

    /* Lookup codec */
    {
        pj_str_t codec_id_st;
        unsigned info_cnt = 1;

        /* Lookup codec */
        pj_cstr(&codec_id_st, codec_id);
        status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st,
                 &info_cnt,
                 &codec_info, NULL);
        if (status != PJ_SUCCESS) {
            rc = 205;
            goto on_return;
        }
    }


#if CAPTURE_DEV == -1
    /* Lookup colorbar source */
    status = pjmedia_vid_dev_lookup("Colorbar", "Colorbar generator", &cap_idx);
    if (status != PJ_SUCCESS) {
        rc = 206;
        goto on_return;
    }
#elif CAPTURE_DEV == -2
    /* Lookup any first non-colorbar source */
    {
        unsigned i, cnt;
        pjmedia_vid_dev_info info;

        cap_idx = -1;
        cnt = pjmedia_vid_dev_count();
        for (i = 0; i < cnt; ++i) {
            status = pjmedia_vid_dev_get_info(i, &info);
            if (status != PJ_SUCCESS) {
                rc = 206;
                goto on_return;
            }
            if (info.dir & PJMEDIA_DIR_CAPTURE &&
                    pj_ansi_stricmp(info.driver, "Colorbar"))
            {
                cap_idx = i;
                break;
            }
        }

        if (cap_idx == -1) {
            status = PJ_ENOTFOUND;
            rc = 206;
            goto on_return;
        }
    }
#else
    cap_idx = CAPTURE_DEV;
#endif

    /* Lookup SDL renderer */
    status = pjmedia_vid_dev_lookup("SDL", "SDL renderer", &rdr_idx);
    if (status != PJ_SUCCESS) {
        rc = 207;
        goto on_return;
    }

    /* Prepare codec */
    {
        pj_str_t codec_id_st;
        unsigned info_cnt = 1;
        const pjmedia_vid_codec_info *codec_info;

        /* Lookup codec */
        pj_cstr(&codec_id_st, codec_id);
        status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st,
                 &info_cnt,
                 &codec_info, NULL);
        if (status != PJ_SUCCESS) {
            rc = 245;
            goto on_return;
        }
        status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
                 &codec_param);
        if (status != PJ_SUCCESS) {
            rc = 246;
            goto on_return;
        }

        codec_param.packing = packing;

        /* Open codec */
        status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
                 &codec);
        if (status != PJ_SUCCESS) {
            rc = 250;
            goto on_return;
        }

        status = pjmedia_vid_codec_init(codec, pool);
        if (status != PJ_SUCCESS) {
            rc = 251;
            goto on_return;
        }

        status = pjmedia_vid_codec_open(codec, &codec_param);
        if (status != PJ_SUCCESS) {
            rc = 252;
            goto on_return;
        }

        /* After opened, codec will update the param, let's sync encoder &
         * decoder format detail.
         */
        codec_param.dec_fmt.det = codec_param.enc_fmt.det;

        /* Subscribe to codec events */
        pjmedia_event_subscribe(NULL, &codec_on_event, &codec_port_data,
                                codec);
    }

    pjmedia_vid_port_param_default(&vport_param);

    /* Create capture, set it to active (master) */
    status = pjmedia_vid_dev_default_param(pool, cap_idx,
                                           &vport_param.vidparam);
    if (status != PJ_SUCCESS) {
        rc = 220;
        goto on_return;
    }
    pjmedia_format_copy(&vport_param.vidparam.fmt, &codec_param.dec_fmt);
    vport_param.vidparam.dir = PJMEDIA_DIR_CAPTURE;
    vport_param.active = PJ_TRUE;

    if (vport_param.vidparam.fmt.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO) {
        rc = 221;
        goto on_return;
    }

    vfd = pjmedia_format_get_video_format_detail(&vport_param.vidparam.fmt,
            PJ_TRUE);
    if (vfd == NULL) {
        rc = 225;
        goto on_return;
    }

    status = pjmedia_vid_port_create(pool, &vport_param, &capture);
    if (status != PJ_SUCCESS) {
        rc = 226;
        goto on_return;
    }

    /* Create renderer, set it to passive (slave)  */
    vport_param.active = PJ_FALSE;
    vport_param.vidparam.dir = PJMEDIA_DIR_RENDER;
    vport_param.vidparam.rend_id = rdr_idx;
    vport_param.vidparam.disp_size = vfd->size;

    status = pjmedia_vid_port_create(pool, &vport_param, &renderer);
    if (status != PJ_SUCCESS) {
        rc = 230;
        goto on_return;
    }

    /* Init codec port */
    pj_bzero(&codec_port, sizeof(codec_port));
    status = pjmedia_port_info_init2(&codec_port.info, &port_name, 0x1234,
                                     PJMEDIA_DIR_ENCODING,
                                     &codec_param.dec_fmt);
    if (status != PJ_SUCCESS) {
        rc = 260;
        goto on_return;
    }

    codec_port_data.codec = codec;
    codec_port_data.rdr_port = renderer;
    codec_port_data.enc_buf_size = codec_param.dec_fmt.det.vid.size.w *
                                   codec_param.dec_fmt.det.vid.size.h * 4;
    codec_port_data.enc_buf = pj_pool_alloc(pool,
                                            codec_port_data.enc_buf_size);
    codec_port_data.pack_buf_size = codec_port_data.enc_buf_size;
    codec_port_data.pack_buf = pj_pool_alloc(pool,
                               codec_port_data.pack_buf_size);

    codec_port.put_frame = &codec_put_frame;
    codec_port.port_data.pdata = &codec_port_data;

    /* Connect capture to codec port */
    status = pjmedia_vid_port_connect(capture,
                                      &codec_port,
                                      PJ_FALSE);
    if (status != PJ_SUCCESS) {
        rc = 270;
        goto on_return;
    }

    PJ_LOG(3, (THIS_FILE, "    starting codec test: %s<->%.*s %dx%d",
               pjmedia_fourcc_name(codec_param.dec_fmt.id, codec_name),
               codec_info->encoding_name.slen,
               codec_info->encoding_name.ptr,
               codec_param.dec_fmt.det.vid.size.w,
               codec_param.dec_fmt.det.vid.size.h
              ));

    /* Start streaming.. */
    status = pjmedia_vid_port_start(renderer);
    if (status != PJ_SUCCESS) {
        rc = 275;
        goto on_return;
    }
    status = pjmedia_vid_port_start(capture);
    if (status != PJ_SUCCESS) {
        rc = 280;
        goto on_return;
    }

    /* Sleep while the video is being displayed... */
    pj_thread_sleep(10000);

on_return:
    if (status != PJ_SUCCESS) {
        PJ_PERROR(3, (THIS_FILE, status, "  error"));
    }
    if (capture)
        pjmedia_vid_port_stop(capture);
    if (renderer)
        pjmedia_vid_port_stop(renderer);
    if (capture)
        pjmedia_vid_port_destroy(capture);
    if (renderer)
        pjmedia_vid_port_destroy(renderer);
    if (codec) {
        pjmedia_event_unsubscribe(NULL, &codec_on_event, &codec_port_data,
                                  codec);
        pjmedia_vid_codec_close(codec);
        pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
    }

    return rc;
}
Example #21
0
/*
 * main()
 */
int main(int argc, char *argv[])
{
    pj_caching_pool cp;
    pjmedia_endpt *med_endpt;
    pj_pool_t *pool;
    pj_status_t status; 

    /* Codec */
    char *codec_id = (char*)"H264";
    const pjmedia_vid_codec_info *codec_info;
    pjmedia_vid_codec_param codec_param;
    pjmedia_vid_codec *codec = NULL;

    //const char *save_filename =
    //	"/home/bennylp/Desktop/opt/src/openh264-svn/testbin/test.264";
    const char *save_filename = NULL;

    /* File */
    enum
    {
	WIDTH = 320,
	HEIGHT = 192,
	FPS = 12,
	YUV_SIZE = WIDTH * HEIGHT * 3 >> 1,
	YUV_BUF_SIZE = YUV_SIZE + WIDTH,
	MAX_FRAMES = 32,
	MTU = 1500
    };
    FILE *fyuv = NULL;
    FILE *f264 = NULL;
    typedef pj_uint8_t enc_buf_type[MTU];
    pj_uint8_t yuv_frame[YUV_BUF_SIZE];
    enc_buf_type enc_buf[MAX_FRAMES];
    unsigned read_cnt = 0,
	     pkt_cnt = 0,
	     dec_cnt = 0,
	     enc_cnt;

    if (0) {
	diff_file();
	return 1;
    }

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

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

    /* Initialize media endpoint. */
    status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /* Create memory pool for application purpose */
    pool = pj_pool_create( &cp.factory,	    /* pool factory	    */
			   "app",	    /* pool name.	    */
			   4000,	    /* init size	    */
			   4000,	    /* increment size	    */
			   NULL		    /* callback on error    */
			   );

    /* Init video format manager */
    pjmedia_video_format_mgr_create(pool, 64, 0, NULL);

    /* Init video converter manager */
    pjmedia_converter_mgr_create(pool, NULL);

    /* Init event manager */
    pjmedia_event_mgr_create(pool, 0, NULL);

    /* Init video codec manager */
    pjmedia_vid_codec_mgr_create(pool, NULL);

    /* Register all supported codecs */
    status = init_codecs(&cp.factory);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /* Open YUV file */
    fyuv = fopen("pjsip-apps/bin/CiscoVT2people_320x192_12fps.yuv", "rb");
    if (!fyuv) {
	puts("Unable to open ../CiscoVT2people_320x192_12fps.yuv");
	status = -1;
	goto on_exit;
    }

    /* Write 264 file if wanted */
    if (save_filename) {
	f264 = fopen(save_filename, "wb");
    }

    /* Find which codec to use. */
    if (codec_id) {
	unsigned count = 1;
	pj_str_t str_codec_id = pj_str(codec_id);

        status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL,
						         &str_codec_id, &count,
						         &codec_info, NULL);
	if (status != PJ_SUCCESS) {
	    printf("Error: unable to find codec %s\n", codec_id);
	    return 1;
	}
    } else {
        static pjmedia_vid_codec_info info[1];
        unsigned count = PJ_ARRAY_SIZE(info);

	/* Default to first codec */
	pjmedia_vid_codec_mgr_enum_codecs(NULL, &count, info, NULL);
        codec_info = &info[0];
    }

    /* Get codec default param for info */
    status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info, 
				                     &codec_param);
    pj_assert(status == PJ_SUCCESS);
    
    /* Alloc encoder */
    status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info, &codec);
    if (status != PJ_SUCCESS) {
	PJ_PERROR(3,(THIS_FILE, status, "Error allocating codec"));
	goto on_exit;
    }

    codec_param.dir = PJMEDIA_DIR_ENCODING_DECODING;
    codec_param.packing = PJMEDIA_VID_PACKING_PACKETS;
    codec_param.enc_mtu = MTU;
    codec_param.enc_fmt.det.vid.size.w = WIDTH;
    codec_param.enc_fmt.det.vid.size.h = HEIGHT;
    codec_param.enc_fmt.det.vid.fps.num = FPS;
    codec_param.enc_fmt.det.vid.avg_bps = WIDTH * HEIGHT * FPS;

    status = pjmedia_vid_codec_init(codec, pool);
    if (status != PJ_SUCCESS) {
	PJ_PERROR(3,(THIS_FILE, status, "Error initializing codec"));
	goto on_exit;
    }

    status = pjmedia_vid_codec_open(codec, &codec_param);
    if (status != PJ_SUCCESS) {
	PJ_PERROR(3,(THIS_FILE, status, "Error opening codec"));
	goto on_exit;
    }

    while (fread(yuv_frame, 1, YUV_SIZE, fyuv) == YUV_SIZE) {
	pjmedia_frame frm_yuv, frm_enc[MAX_FRAMES];
	pj_bool_t has_more = PJ_FALSE;
	const pj_uint8_t start_nal[] = { 0, 0, 1 };
	unsigned i;

	++ read_cnt;

	pj_bzero(&frm_enc, sizeof(frm_enc));
	pj_bzero(&frm_yuv, sizeof(frm_yuv));

	frm_yuv.buf = yuv_frame;
	frm_yuv.size = YUV_SIZE;

	enc_cnt = 0;
	frm_enc[enc_cnt].buf = enc_buf[enc_cnt];
	frm_enc[enc_cnt].size = MTU;

	status = pjmedia_vid_codec_encode_begin(codec, NULL, &frm_yuv,
	                                        MTU, &frm_enc[enc_cnt],
	                                        &has_more);
	if (status != PJ_SUCCESS) {
	    PJ_PERROR(3,(THIS_FILE, status, "Codec encode error"));
	    goto on_exit;
	}
	if (frm_enc[enc_cnt].size) {
	    if (f264) {
		fwrite(start_nal, 1, sizeof(start_nal), f264);
		fwrite(frm_enc[enc_cnt].buf, 1, frm_enc[enc_cnt].size, f264);
	    }
	    ++pkt_cnt;
	    ++enc_cnt;
	}

	while (has_more) {

	    if (enc_cnt >= MAX_FRAMES) {
		status = -1;
		puts("Error: too many encoded frames");
		goto on_exit;
	    }

	    has_more = PJ_FALSE;
	    frm_enc[enc_cnt].buf = enc_buf[enc_cnt];
	    frm_enc[enc_cnt].size = MTU;

	    status = pjmedia_vid_codec_encode_more(codec, MTU,
	                                           &frm_enc[enc_cnt],
	                                           &has_more);
	    if (status != PJ_SUCCESS) {
		PJ_PERROR(3,(THIS_FILE, status, "Codec encode error"));
		goto on_exit;
	    }

	    if (frm_enc[enc_cnt].size) {
		if (f264) {
		    fwrite(start_nal, 1, sizeof(start_nal), f264);
		    fwrite(frm_enc[enc_cnt].buf, 1, frm_enc[enc_cnt].size,
		           f264);
		}
		++pkt_cnt;
		++enc_cnt;
	    }
	}

	if (enc_cnt) {
	    frm_yuv.buf = yuv_frame;
	    frm_yuv.size = YUV_BUF_SIZE;
	    status = pjmedia_vid_codec_decode(codec, enc_cnt,
					      frm_enc,
					      YUV_BUF_SIZE,
					      &frm_yuv);
	    if (status != PJ_SUCCESS) {
		PJ_PERROR(3,(THIS_FILE, status, "Codec decode error"));
		goto on_exit;
	    }

	    if (frm_yuv.size != 0) {
		++dec_cnt;
	    }
	}
    }

    printf("Done.\n"
	   " Read YUV frames:    %d\n"
	   " Encoded packets:    %d\n"
	   " Decoded YUV frames: %d\n",
	   read_cnt, pkt_cnt, dec_cnt);

    /* Start deinitialization: */
on_exit:
    if (codec) {
	pjmedia_vid_codec_close(codec);
	pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
    }

    if (f264)
	fclose(f264);

    if (fyuv)
	fclose(fyuv);

    /* Deinit codecs */
    deinit_codecs();

    /* Destroy event manager */
    pjmedia_event_mgr_destroy(NULL);

    /* Release application pool */
    pj_pool_release( pool );

    /* Destroy media endpoint. */
    pjmedia_endpt_destroy( med_endpt );

    /* Destroy pool factory */
    pj_caching_pool_destroy( &cp );

    /* Shutdown PJLIB */
    pj_shutdown();

    return (status == PJ_SUCCESS) ? 0 : 1;
}


#else

int main(int argc, char *argv[])
{
    PJ_UNUSED_ARG(argc);
    PJ_UNUSED_ARG(argv);
    puts("Error: this sample requires video capability "
	    "(PJMEDIA_HAS_VIDEO == 1)");
    return -1;
}
Example #22
0
/*
 * Parse SDP message.
 */
PJ_DEF(pj_status_t) pjmedia_sdp_parse( pj_pool_t *pool,
				       char *buf, pj_size_t len, 
				       pjmedia_sdp_session **p_sdp)
{
    pj_scanner scanner;
    pjmedia_sdp_session *session;
    pjmedia_sdp_media *media = NULL;
    pjmedia_sdp_attr *attr;
    pjmedia_sdp_conn *conn;
    pjmedia_sdp_bandw *bandw;
    pj_str_t dummy;
    int cur_name = 254;
    parse_context ctx;
    PJ_USE_EXCEPTION;

    ctx.last_error = PJ_SUCCESS;

    init_sdp_parser();

    pj_scan_init(&scanner, buf, len, 0, &on_scanner_error);
    session = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session);
    PJ_ASSERT_RETURN(session != NULL, PJ_ENOMEM);

    /* Ignore leading newlines */
    while (*scanner.curptr=='\r' || *scanner.curptr=='\n')
	pj_scan_get_char(&scanner);

    PJ_TRY {
	while (!pj_scan_is_eof(&scanner)) {
		cur_name = *scanner.curptr;
		switch (cur_name) {
		case 'a':
		    attr = parse_attr(pool, &scanner, &ctx);
		    if (attr) {
			if (media) {
			    if (media->attr_count < PJMEDIA_MAX_SDP_ATTR)
				pjmedia_sdp_media_add_attr(media, attr);
			    else
				PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY,
					      "Error adding media attribute, "
					      "attribute is ignored"));
			} else {
			    if (session->attr_count < PJMEDIA_MAX_SDP_ATTR)
				pjmedia_sdp_session_add_attr(session, attr);
			    else
				PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY,
					      "Error adding session attribute"
					      ", attribute is ignored"));
			}
		    }
		    break;
		case 'o':
		    parse_origin(&scanner, session, &ctx);
		    break;
		case 's':
		    parse_generic_line(&scanner, &session->name, &ctx);
		    break;
		case 'c':
		    conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
		    parse_connection_info(&scanner, conn, &ctx);
		    if (media) {
			media->conn = conn;
		    } else {
			session->conn = conn;
		    }
		    break;
		case 't':
		    parse_time(&scanner, session, &ctx);
		    break;
		case 'm':
		    media = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
		    parse_media(&scanner, media, &ctx);
		    if (session->media_count < PJMEDIA_MAX_SDP_MEDIA)
			session->media[ session->media_count++ ] = media;
		    else
			PJ_PERROR(2,(THIS_FILE, PJ_ETOOMANY,
				     "Error adding media, media is ignored"));
		    break;
		case 'v':
		    parse_version(&scanner, &ctx);
		    break;
		case 13:
		case 10:
		    pj_scan_get_char(&scanner);
		    /* Allow empty newlines at the end of the message */
		    while (!pj_scan_is_eof(&scanner)) {
			if (*scanner.curptr != 13 && *scanner.curptr != 10) {
			    ctx.last_error = PJMEDIA_SDP_EINSDP;
			    on_scanner_error(&scanner);
			}
			pj_scan_get_char(&scanner);
		    }
		    break;
		case 'b':
		    bandw = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_bandw);
		    parse_bandwidth_info(&scanner, bandw, &ctx);
		    if (media) {
			if (media->bandw_count < PJMEDIA_MAX_SDP_BANDW)
			    media->bandw[media->bandw_count++] = bandw;
			else
			    PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY,
					  "Error adding media bandwidth "
					  "info, info is ignored"));
		    } else {
			if (session->bandw_count < PJMEDIA_MAX_SDP_BANDW)
			    session->bandw[session->bandw_count++] = bandw;
			else
			    PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY,
					  "Error adding session bandwidth "
					  "info, info is ignored"));
		    }
		    break;
		default:
		    if (cur_name >= 'a' && cur_name <= 'z')
			parse_generic_line(&scanner, &dummy, &ctx);
		    else  {
			ctx.last_error = PJMEDIA_SDP_EINSDP;
			on_scanner_error(&scanner);
		    }
		    break;
		}
	}

	ctx.last_error = PJ_SUCCESS;

    }
    PJ_CATCH_ANY {
	
	char errmsg[PJ_ERR_MSG_SIZE];
	pj_strerror(ctx.last_error, errmsg, sizeof(errmsg));

	PJ_LOG(4, (THIS_FILE, "Error parsing SDP in line %d col %d: %s",
		   scanner.line, pj_scan_get_col(&scanner),
		   errmsg));

	session = NULL;

	pj_assert(ctx.last_error != PJ_SUCCESS);
    }
    PJ_END;

    pj_scan_fini(&scanner);

    if (session)
	apply_media_direction(session);

    *p_sdp = session;
    return ctx.last_error;
}
/* Scan V4L2 devices */
static pj_status_t v4l2_scan_devs(vid4lin_factory *f)
{
    vid4lin_dev_info vdi[V4L2_MAX_DEVS];
    char dev_name[32];
    unsigned i, old_count;
    pj_status_t status;

    if (f->dev_pool) {
        pj_pool_release(f->dev_pool);
        f->dev_pool = NULL;
    }

    pj_bzero(vdi, sizeof(vdi));
    old_count = f->dev_count;
    f->dev_count = 0;
    f->dev_pool = pj_pool_create(f->pf, DRIVER_NAME, 500, 500, NULL);

    for (i=0; i<V4L2_MAX_DEVS && f->dev_count < V4L2_MAX_DEVS; ++i) {
	int fd;
	vid4lin_dev_info *pdi;
	pj_uint32_t fmt_cap[8];
	int j, fmt_cnt=0;

	pdi = &vdi[f->dev_count];

	snprintf(dev_name, sizeof(dev_name), "/dev/video%d", i);
	if (!pj_file_exists(dev_name))
	    continue;

	fd = v4l2_open(dev_name, O_RDWR, 0);
	if (fd == -1)
	    continue;

	status = xioctl(fd, VIDIOC_QUERYCAP, &pdi->v4l2_cap);
	if (status != PJ_SUCCESS) {
	    PJ_PERROR(4,(THIS_FILE, status, "Error querying %s", dev_name));
	    v4l2_close(fd);
	    continue;
	}

	if ((pdi->v4l2_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
	    v4l2_close(fd);
	    continue;
	}

	PJ_LOG(5,(THIS_FILE, "Found capture device %s", pdi->v4l2_cap.card));
	PJ_LOG(5,(THIS_FILE, "  Enumerating formats:"));
	for (j=0; fmt_cnt<PJ_ARRAY_SIZE(fmt_cap); ++j) {
	    struct v4l2_fmtdesc fdesc;
	    unsigned k;

	    pj_bzero(&fdesc, sizeof(fdesc));
	    fdesc.index = j;
	    fdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

	    status = xioctl(fd, VIDIOC_ENUM_FMT, &fdesc);
	    if (status != PJ_SUCCESS)
		break;

	    for (k=0; k<PJ_ARRAY_SIZE(v4l2_fmt_maps); ++k) {
		if (v4l2_fmt_maps[k].v4l2_fmt_id == fdesc.pixelformat) {
		    fmt_cap[fmt_cnt++] = v4l2_fmt_maps[k].pjmedia_fmt_id;
		    PJ_LOG(5,(THIS_FILE, "   Supported: %s",
			      fdesc.description));
		    break;
		}
	    }
	    if (k==PJ_ARRAY_SIZE(v4l2_fmt_maps)) {
		PJ_LOG(5,(THIS_FILE, "   Unsupported: %s", fdesc.description));
	    }
	}

	v4l2_close(fd);

	if (fmt_cnt==0) {
	    PJ_LOG(5,(THIS_FILE, "    Found no common format"));
	    continue;
	}

	strncpy(pdi->dev_name, dev_name, sizeof(pdi->dev_name));
	pdi->dev_name[sizeof(pdi->dev_name)-1] = '\0';
	strncpy(pdi->info.name, (char*)pdi->v4l2_cap.card,
		sizeof(pdi->info.name));
	pdi->info.name[sizeof(pdi->info.name)-1] = '\0';
	strncpy(pdi->info.driver, DRIVER_NAME, sizeof(pdi->info.driver));
	pdi->info.driver[sizeof(pdi->info.driver)-1] = '\0';
	pdi->info.dir = PJMEDIA_DIR_CAPTURE;
	pdi->info.has_callback = PJ_FALSE;
	pdi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT;

	pdi->info.fmt_cnt = fmt_cnt;
	for (j=0; j<fmt_cnt; ++j) {
	    pjmedia_format_init_video(&pdi->info.fmt[j],
				      fmt_cap[j],
				      DEFAULT_WIDTH,
				      DEFAULT_HEIGHT,
				      DEFAULT_FPS, 1);
	}
	if (j < fmt_cnt)
	    continue;

	f->dev_count++;
    }

    if (f->dev_count == 0)
	return PJ_SUCCESS;

    if (f->dev_count > old_count || f->dev_info == NULL) {
	f->dev_info = (vid4lin_dev_info*)
		      pj_pool_calloc(f->dev_pool,
				     f->dev_count,
				     sizeof(vid4lin_dev_info));
    }
    pj_memcpy(f->dev_info, vdi, f->dev_count * sizeof(vid4lin_dev_info));

    return PJ_SUCCESS;
}
Example #24
0
static void systest_aec_test(void)
{
    const char *ref_wav_paths[] = { add_path(res_path, WAV_PLAYBACK_PATH),
				    ALT_PATH1 WAV_PLAYBACK_PATH };
    pjsua_player_id player_id = PJSUA_INVALID_ID;
    pjsua_recorder_id writer_id = PJSUA_INVALID_ID;
    enum gui_key key;
    test_item_t *ti;
    const char *title = "AEC/AES Test";
    unsigned last_ec_tail = 0;
    pj_status_t status;
    pj_str_t tmp;

    ti = systest_alloc_test_item(title);
    if (!ti)
	return;

    key = gui_msgbox(title,
		     "This test will try to find whether the AEC/AES "
		     "works good on this system. Test will play a file "
		     "while recording from mic. The recording will be "
		     "played back later so you can check if echo is there. "
		     "Press OK to start.",
		     WITH_OKCANCEL);
    if (key != KEY_OK) {
	ti->skipped = PJ_TRUE;
	return;
    }

    /* Save current EC tail */
    status = pjsua_get_ec_tail(&last_ec_tail);
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Set EC tail setting to default */
    status = pjsua_set_ec(PJSUA_DEFAULT_EC_TAIL_LEN, 0);
    if (status != PJ_SUCCESS)
	goto on_return;

    /*
     * Create player and recorder
     */
    status = create_player(PJ_ARRAY_SIZE(ref_wav_paths), ref_wav_paths,
			   &player_id);
    if (status != PJ_SUCCESS) {
	PJ_PERROR(1,(THIS_FILE, status, "Error opening WAV file %s",
		     WAV_PLAYBACK_PATH));
	goto on_return;
    }

    status = pjsua_recorder_create(
                 pj_cstr(&tmp, add_path(doc_path, AEC_REC_PATH)), 0, 0, -1,
                 0, &writer_id);
    if (status != PJ_SUCCESS) {
	PJ_PERROR(1,(THIS_FILE, status, "Error writing WAV file %s",
		     AEC_REC_PATH));
	goto on_return;
    }

    /*
     * Start playback and recording.
     */
    pjsua_conf_connect(pjsua_player_get_conf_port(player_id), 0);
    pj_thread_sleep(100);
    pjsua_conf_connect(0, pjsua_recorder_get_conf_port(writer_id));

    /* Wait user signal */
    gui_msgbox(title, "AEC/AES test is running. Press OK to stop this test.",
	       WITH_OK);

    /*
     * Stop and close playback and recorder
     */
    pjsua_conf_disconnect(0, pjsua_recorder_get_conf_port(writer_id));
    pjsua_conf_disconnect(pjsua_player_get_conf_port(player_id), 0);
    pjsua_recorder_destroy(writer_id);
    pjsua_player_destroy(player_id);
    player_id = PJSUA_INVALID_ID;
    writer_id = PJSUA_INVALID_ID;

    /*
     * Play the result.
     */
    status = pjsua_player_create(
                 pj_cstr(&tmp, add_path(doc_path, AEC_REC_PATH)),
                 0, &player_id);
    if (status != PJ_SUCCESS) {
	PJ_PERROR(1,(THIS_FILE, status, "Error opening WAV file %s", AEC_REC_PATH));
	goto on_return;
    }
    pjsua_conf_connect(pjsua_player_get_conf_port(player_id), 0);

    /* Wait user signal */
    gui_msgbox(title, "We are now playing the captured audio from the mic. "
		      "Check if echo (of the audio played back previously) is "
		      "present in the audio. The recording is stored in "
		      AEC_REC_PATH " for offline analysis. "
		      "Press OK to stop.",
		      WITH_OK);

    pjsua_conf_disconnect(pjsua_player_get_conf_port(player_id), 0);

    key = gui_msgbox(title,
		     "Did you notice any echo in the recording?",
		     WITH_YESNO);


on_return:
    if (player_id != PJSUA_INVALID_ID)
	pjsua_player_destroy(player_id);
    if (writer_id != PJSUA_INVALID_ID)
	pjsua_recorder_destroy(writer_id);

    /* Wait until sound device closed before restoring back EC tail setting */
    while (pjsua_snd_is_active())
	pj_thread_sleep(10);
    pjsua_set_ec(last_ec_tail, 0);


    if (status != PJ_SUCCESS) {
	systest_perror("Sorry we encountered an error: ", status);
	ti->success = PJ_FALSE;
	pj_strerror(status, ti->reason, sizeof(ti->reason));
    } else if (key == KEY_YES) {
	ti->success = PJ_FALSE;
	if (!ti->success) {
	    pj_ansi_strcpy(ti->reason, USER_ERROR);
	}
    } else {
	char msg[200];

	pj_ansi_snprintf(msg, sizeof(msg), "Test succeeded.\r\n");

	ti->success = PJ_TRUE;
	pj_ansi_strncpy(ti->reason, msg, sizeof(ti->reason));
	ti->reason[sizeof(ti->reason)-1] = '\0';
    }
}
Example #25
0
/*
 * Transmit message.
 */
static pj_status_t tsx_transmit_msg(pj_stun_client_tsx *tsx,
                                    pj_bool_t mod_count)
{
    pj_status_t status;

    PJ_ASSERT_RETURN(tsx->retransmit_timer.id == TIMER_INACTIVE ||
		     !tsx->require_retransmit, PJ_EBUSY);

    if (tsx->require_retransmit && mod_count) {
	/* Calculate retransmit/timeout delay */
	if (tsx->transmit_count == 0) {
	    tsx->retransmit_time.sec = 0;
	    tsx->retransmit_time.msec = tsx->rto_msec;

	} else if (tsx->transmit_count < PJ_STUN_MAX_TRANSMIT_COUNT-1) {
	    unsigned msec;

	    msec = PJ_TIME_VAL_MSEC(tsx->retransmit_time);
	    msec <<= 1;
	    tsx->retransmit_time.sec = msec / 1000;
	    tsx->retransmit_time.msec = msec % 1000;

	} else {
	    tsx->retransmit_time.sec = PJ_STUN_TIMEOUT_VALUE / 1000;
	    tsx->retransmit_time.msec = PJ_STUN_TIMEOUT_VALUE % 1000;
	}

	/* Schedule timer first because when send_msg() failed we can
	 * cancel it (as opposed to when schedule_timer() failed we cannot
	 * cancel transmission).
	 */;
	status = pj_timer_heap_schedule_w_grp_lock(tsx->timer_heap,
						   &tsx->retransmit_timer,
						   &tsx->retransmit_time,
						   TIMER_ACTIVE,
						   tsx->grp_lock);
	if (status != PJ_SUCCESS) {
	    tsx->retransmit_timer.id = TIMER_INACTIVE;
	    return status;
	}
    }


    if (mod_count)
        tsx->transmit_count++;

    PJ_LOG(5,(tsx->obj_name, "STUN sending message (transmit count=%d)",
	      tsx->transmit_count));
    pj_log_push_indent();

    /* Send message */
    status = tsx->cb.on_send_msg(tsx, tsx->last_pkt, tsx->last_pkt_size);

    if (status == PJNATH_ESTUNDESTROYED) {
	/* We've been destroyed, don't access the object. */
    } else if (status != PJ_SUCCESS) {
	if (mod_count) {
		pj_timer_heap_cancel_if_active( tsx->timer_heap,
	                               		&tsx->retransmit_timer,
	                               		TIMER_INACTIVE);
	}
	PJ_PERROR(4, (tsx->obj_name, status, "STUN error sending message"));
    }

    pj_log_pop_indent();
    return status;
}
Example #26
0
static int aviplay(pj_pool_t *pool, const char *fname)
{
    pjmedia_vid_port *renderer=NULL;
    pjmedia_vid_port_param param;
    const pjmedia_video_format_info *vfi;
    pjmedia_video_format_detail *vfd;
    pjmedia_snd_port *snd_port = NULL;
    pj_status_t status;
    int rc = 0;
    pjmedia_avi_streams *avi_streams;
    pjmedia_avi_stream *vid_stream, *aud_stream;
    pjmedia_port *vid_port = NULL, *aud_port = NULL;
    pjmedia_vid_codec *codec=NULL;
    avi_port_t avi_port;

    pj_bzero(&avi_port, sizeof(avi_port));

    status = pjmedia_avi_player_create_streams(pool, fname, 0, &avi_streams);
    if (status != PJ_SUCCESS) {
        PJ_PERROR(2,("", status, "    Error playing %s", fname));
        rc = 210;
        goto on_return;
    }

    vid_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
                 0,
                 PJMEDIA_TYPE_VIDEO);
    vid_port = pjmedia_avi_stream_get_port(vid_stream);

    if (vid_port) {
        pjmedia_vid_port_param_default(&param);

        status = pjmedia_vid_dev_default_param(pool,
                                               PJMEDIA_VID_DEFAULT_RENDER_DEV,
                                               &param.vidparam);
        if (status != PJ_SUCCESS) {
            rc = 220;
            goto on_return;
        }

        /* Create renderer, set it to active  */
        param.active = PJ_TRUE;
        param.vidparam.dir = PJMEDIA_DIR_RENDER;
        vfd = pjmedia_format_get_video_format_detail(&vid_port->info.fmt,
                PJ_TRUE);
        pjmedia_format_init_video(&param.vidparam.fmt,
                                  vid_port->info.fmt.id,
                                  vfd->size.w, vfd->size.h,
                                  vfd->fps.num, vfd->fps.denum);

        vfi = pjmedia_get_video_format_info(
                  pjmedia_video_format_mgr_instance(),
                  vid_port->info.fmt.id);
        /* Check whether the frame is encoded */
        if (!vfi || vfi->bpp == 0) {
            /* Yes, prepare codec */
            pj_str_t codec_id_st;
            unsigned info_cnt = 1, i, k;
            const pjmedia_vid_codec_info *codec_info;
            pj_str_t port_name = {"codec", 5};
            pj_uint8_t *enc_buf = NULL;
            pj_size_t enc_buf_size = 0;
            pjmedia_vid_dev_info rdr_info;
            pjmedia_port codec_port;
            codec_port_data_t codec_port_data;
            pjmedia_vid_codec_param codec_param;
            struct codec_fmt *codecp = NULL;

            /* Lookup codec */
            for (i = 0; i < sizeof(codec_fmts)/sizeof(codec_fmts[0]); i++) {
                if (vid_port->info.fmt.id == codec_fmts[i].pjmedia_id) {
                    codecp = &codec_fmts[i];
                    break;
                }
            }
            if (!codecp) {
                rc = 242;
                goto on_return;
            }
            pj_cstr(&codec_id_st, codecp->codec_id);
            status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL,
                     &codec_id_st,
                     &info_cnt,
                     &codec_info,
                     NULL);
            if (status != PJ_SUCCESS) {
                rc = 245;
                goto on_return;
            }
            status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
                     &codec_param);
            if (status != PJ_SUCCESS) {
                rc = 246;
                goto on_return;
            }

            pjmedia_format_copy(&codec_param.enc_fmt, &param.vidparam.fmt);

            pjmedia_vid_dev_get_info(param.vidparam.rend_id, &rdr_info);
            for (i=0; i<codec_info->dec_fmt_id_cnt; ++i) {
                for (k=0; k<rdr_info.fmt_cnt; ++k) {
                    if (codec_info->dec_fmt_id[i]==(int)rdr_info.fmt[k].id)
                    {
                        param.vidparam.fmt.id = codec_info->dec_fmt_id[i];
                        i = codec_info->dec_fmt_id_cnt;
                        break;
                    }
                }
            }

            /* Open codec */
            status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
                     &codec);
            if (status != PJ_SUCCESS) {
                rc = 250;
                goto on_return;
            }

            status = pjmedia_vid_codec_init(codec, pool);
            if (status != PJ_SUCCESS) {
                rc = 251;
                goto on_return;
            }

            pjmedia_format_copy(&codec_param.dec_fmt, &param.vidparam.fmt);
            codec_param.dir = PJMEDIA_DIR_DECODING;
            codec_param.packing = PJMEDIA_VID_PACKING_WHOLE;
            status = pjmedia_vid_codec_open(codec, &codec_param);
            if (status != PJ_SUCCESS) {
                rc = 252;
                goto on_return;
            }

            /* Alloc encoding buffer */
            enc_buf_size =  codec_param.dec_fmt.det.vid.size.w *
                            codec_param.dec_fmt.det.vid.size.h * 4
                            + 16; /*< padding, just in case */
            enc_buf = pj_pool_alloc(pool,enc_buf_size);

            /* Init codec port */
            pj_bzero(&codec_port, sizeof(codec_port));
            status = pjmedia_port_info_init2(&codec_port.info, &port_name,
                                             0x1234,
                                             PJMEDIA_DIR_ENCODING,
                                             &codec_param.dec_fmt);
            if (status != PJ_SUCCESS) {
                rc = 260;
                goto on_return;
            }
            pj_bzero(&codec_port_data, sizeof(codec_port_data));
            codec_port_data.codec = codec;
            codec_port_data.src_port = vid_port;
            codec_port_data.enc_buf = enc_buf;
            codec_port_data.enc_buf_size = enc_buf_size;

            codec_port.get_frame = &codec_get_frame;
            codec_port.port_data.pdata = &codec_port_data;

            /* Check whether we need to convert the decoded frame */
            if (codecp->need_conversion) {
                pjmedia_conversion_param conv_param;

                pjmedia_format_copy(&conv_param.src, &param.vidparam.fmt);
                pjmedia_format_copy(&conv_param.dst, &param.vidparam.fmt);
                conv_param.dst.id = codecp->dst_fmt;
                param.vidparam.fmt.id = conv_param.dst.id;

                status = pjmedia_converter_create(NULL, pool, &conv_param,
                                                  &codec_port_data.conv);
                if (status != PJ_SUCCESS) {
                    rc = 270;
                    goto on_return;
                }
            }

            status = pjmedia_vid_port_create(pool, &param, &renderer);
            if (status != PJ_SUCCESS) {
                rc = 230;
                goto on_return;
            }

            status = pjmedia_vid_port_connect(renderer, &codec_port,
                                              PJ_FALSE);
        } else {
            status = pjmedia_vid_port_create(pool, &param, &renderer);
            if (status != PJ_SUCCESS) {
                rc = 230;
                goto on_return;
            }

            /* Connect avi port to renderer */
            status = pjmedia_vid_port_connect(renderer, vid_port,
                                              PJ_FALSE);
        }

        if (status != PJ_SUCCESS) {
            rc = 240;
            goto on_return;
        }
    }

    aud_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
                 0,
                 PJMEDIA_TYPE_AUDIO);
    aud_port = pjmedia_avi_stream_get_port(aud_stream);

    if (aud_port) {
        /* Create sound player port. */
        status = pjmedia_snd_port_create_player(
                     pool,				    /* pool		    */
                     -1,				    /* use default dev.	    */
                     PJMEDIA_PIA_SRATE(&aud_port->info),/* clock rate.	    */
                     PJMEDIA_PIA_CCNT(&aud_port->info), /* # of channels.	    */
                     PJMEDIA_PIA_SPF(&aud_port->info),  /* samples per frame.   */
                     PJMEDIA_PIA_BITS(&aud_port->info), /* bits per sample.	    */
                     0,				    /* options		    */
                     &snd_port			    /* returned port	    */
                 );
        if (status != PJ_SUCCESS) {
            rc = 310;
            goto on_return;
        }

        /* Connect file port to the sound player.
         * Stream playing will commence immediately.
         */
        status = pjmedia_snd_port_connect(snd_port, aud_port);
        if (status != PJ_SUCCESS) {
            rc = 330;
            goto on_return;
        }
    }

    if (vid_port) {
        pjmedia_vid_dev_cb cb;

        pj_bzero(&cb, sizeof(cb));
        avi_port.snd_port = snd_port;
        avi_port.vid_port = renderer;
        avi_port.is_running = PJ_TRUE;
        pjmedia_vid_port_set_cb(renderer, &cb, &avi_port);

        /* subscribe events */
        pjmedia_event_subscribe(NULL, &avi_event_cb, &avi_port,
                                renderer);

        if (snd_port) {
            /* Synchronize video rendering and audio playback */
            pjmedia_vid_port_set_clock_src(
                renderer,
                pjmedia_snd_port_get_clock_src(
                    snd_port, PJMEDIA_DIR_PLAYBACK));
        }


        /* Start video streaming.. */
        status = pjmedia_vid_port_start(renderer);
        if (status != PJ_SUCCESS) {
            rc = 270;
            goto on_return;
        }
    }

    while (!avi_port.is_quitting) {
        pj_thread_sleep(100);
    }

on_return:
    if (snd_port) {
        pjmedia_snd_port_disconnect(snd_port);
        /* Without this sleep, Windows/DirectSound will repeteadly
         * play the last frame during destroy.
         */
        pj_thread_sleep(100);
        pjmedia_snd_port_destroy(snd_port);
    }
    if (renderer) {
        pjmedia_event_unsubscribe(NULL, &avi_event_cb, &avi_port,
                                  renderer);
        pjmedia_vid_port_destroy(renderer);
    }
    if (aud_port)
        pjmedia_port_destroy(aud_port);
    if (vid_port)
        pjmedia_port_destroy(vid_port);
    if (codec) {
        pjmedia_vid_codec_close(codec);
        pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
    }

    return rc;
}
Example #27
0
/* Parse a multipart part. "pct" is parent content-type  */
static pjsip_multipart_part *parse_multipart_part(pj_pool_t *pool,
						  char *start,
						  pj_size_t len,
						  const pjsip_media_type *pct)
{
    pjsip_multipart_part *part = pjsip_multipart_create_part(pool);
    char *p = start, *end = start+len, *end_hdr = NULL, *start_body = NULL;
    pjsip_ctype_hdr *ctype_hdr = NULL;

    TRACE_((THIS_FILE, "Parsing part: begin--\n%.*s\n--end",
	    (int)len, start));

    /* Find the end of header area, by looking at an empty line */
    for (;;) {
	while (p!=end && *p!='\n') ++p;
	if (p==end) {
	    start_body = end;
	    break;
	}
	if ((p==start) || (p==start+1 && *(p-1)=='\r')) {
	    /* Empty header section */
	    end_hdr = start;
	    start_body = ++p;
	    break;
	} else if (p==end-1) {
	    /* Empty body section */
	    end_hdr = end;
	    start_body = ++p;
	} else if ((p>=start+1 && *(p-1)=='\n') ||
	           (p>=start+2 && *(p-1)=='\r' && *(p-2)=='\n'))
	{
	    /* Found it */
	    end_hdr = (*(p-1)=='\r') ? (p-1) : p;
	    start_body = ++p;
	    break;
	} else {
	    ++p;
	}
    }

    /* Parse the headers */
    if (end_hdr-start > 0) {
	pjsip_hdr *hdr;
	pj_status_t status;

	status = pjsip_parse_headers(pool, start, end_hdr-start, 
				     &part->hdr, 0);
	if (status != PJ_SUCCESS) {
	    PJ_PERROR(2,(THIS_FILE, status, "Warning: error parsing multipart"
					    " header"));
	}

	/* Find Content-Type header */
	hdr = part->hdr.next;
	while (hdr != &part->hdr) {
	    TRACE_((THIS_FILE, "Header parsed: %.*s", (int)hdr->name.slen,
		    hdr->name.ptr));
	    if (hdr->type == PJSIP_H_CONTENT_TYPE) {
		ctype_hdr = (pjsip_ctype_hdr*)hdr;
	    }
	    hdr = hdr->next;
	}
    }

    /* Assign the body */
    part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
    if (ctype_hdr) {
	pjsip_media_type_cp(pool, &part->body->content_type, &ctype_hdr->media);
    } else if (pct && pj_stricmp2(&pct->subtype, "digest")==0) {
	part->body->content_type.type = pj_str("message");
	part->body->content_type.subtype = pj_str("rfc822");
    } else {
	part->body->content_type.type = pj_str("text");
	part->body->content_type.subtype = pj_str("plain");
    }

    if (start_body < end) {
	part->body->data = start_body;
	part->body->len = (unsigned)(end - start_body);
    } else {
	part->body->data = (void*)"";
	part->body->len = 0;
    }
    TRACE_((THIS_FILE, "Body parsed: \"%.*s\"", (int)part->body->len,
	    part->body->data));
    part->body->print_body = &pjsip_print_text_body;
    part->body->clone_data = &pjsip_clone_text_data;

    return part;
}
Example #28
0
/* Create m=video SDP media line */
PJ_DEF(pj_status_t) pjmedia_endpt_create_video_sdp(pjmedia_endpt *endpt,
																									 pj_pool_t *pool,
																									 const pjmedia_sock_info *si,
																									 unsigned options,
																									 pjmedia_sdp_media **p_m)
{


	const pj_str_t STR_VIDEO = { "video", 5 };
	pjmedia_sdp_media *m;
	pjmedia_vid_codec_info codec_info[PJMEDIA_VID_CODEC_MGR_MAX_CODECS];
	unsigned codec_prio[PJMEDIA_VID_CODEC_MGR_MAX_CODECS];
	pjmedia_sdp_attr *attr;
	unsigned cnt, i;
	unsigned max_bitrate = 0;
	pj_status_t status;

	PJ_UNUSED_ARG(options);

	/* Make sure video codec manager is instantiated */
	if (!pjmedia_vid_codec_mgr_instance())
		pjmedia_vid_codec_mgr_create(endpt->pool, NULL);

	/* Create and init basic SDP media */
	m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
	status = init_sdp_media(m, pool, &STR_VIDEO, si);
	if (status != PJ_SUCCESS)
		return status;

	cnt = PJ_ARRAY_SIZE(codec_info);
	status = pjmedia_vid_codec_mgr_enum_codecs(NULL, &cnt, 
		codec_info, codec_prio);

	/* Check that there are not too many codecs */
	PJ_ASSERT_RETURN(0 <= PJMEDIA_MAX_SDP_FMT,
		PJ_ETOOMANY);

	/* Add format, rtpmap, and fmtp (when applicable) for each codec */
	for (i=0; i<cnt; ++i) {
		pjmedia_sdp_rtpmap rtpmap;
		pjmedia_vid_codec_param codec_param;
		pj_str_t *fmt;
		pjmedia_video_format_detail *vfd;

		pj_bzero(&rtpmap, sizeof(rtpmap));

		if (codec_prio[i] == PJMEDIA_CODEC_PRIO_DISABLED)
			break;

		if (i > PJMEDIA_MAX_SDP_FMT) {
			/* Too many codecs, perhaps it is better to tell application by
			* returning appropriate status code.
			*/
			PJ_PERROR(3,(THIS_FILE, PJ_ETOOMANY,
				"Skipping some video codecs"));
			break;
		}

		/* Must support RTP packetization and bidirectional */
		if ((codec_info[i].packings & PJMEDIA_VID_PACKING_PACKETS) == 0 ||
			codec_info[i].dir != PJMEDIA_DIR_ENCODING_DECODING)
		{
			continue;
		}

		pjmedia_vid_codec_mgr_get_default_param(NULL, &codec_info[i],
			&codec_param);

		fmt = &m->desc.fmt[m->desc.fmt_count++];
		fmt->ptr = (char*) pj_pool_alloc(pool, 8);
		fmt->slen = pj_utoa(codec_info[i].pt, fmt->ptr);
		rtpmap.pt = *fmt;

		/* Encoding name */
		rtpmap.enc_name = codec_info[i].encoding_name;

		/* Clock rate */
		rtpmap.clock_rate = codec_info[i].clock_rate;

		if (codec_info[i].pt >= 96 || pjmedia_add_rtpmap_for_static_pt) {
			pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
			m->attr[m->attr_count++] = attr;
		}

		/* Add fmtp params */
		if (codec_param.dec_fmtp.cnt > 0) {
			enum { MAX_FMTP_STR_LEN = 160 };
			char buf[MAX_FMTP_STR_LEN];
			unsigned buf_len = 0, j;
			pjmedia_codec_fmtp *dec_fmtp = &codec_param.dec_fmtp;

			/* Print codec PT */
			buf_len += pj_ansi_snprintf(buf, 
				MAX_FMTP_STR_LEN - buf_len, 
				"%d", 
				codec_info[i].pt);

			for (j = 0; j < dec_fmtp->cnt; ++j) {
				unsigned test_len = 2;

				/* Check if buf still available */
				test_len = dec_fmtp->param[j].val.slen + 
					dec_fmtp->param[j].name.slen;
				if (test_len + buf_len >= MAX_FMTP_STR_LEN)
					return PJ_ETOOBIG;

				/* Print delimiter */
				buf_len += pj_ansi_snprintf(&buf[buf_len], 
					MAX_FMTP_STR_LEN - buf_len,
					(j == 0?" ":";"));

				/* Print an fmtp param */
				if (dec_fmtp->param[j].name.slen)
					buf_len += pj_ansi_snprintf(
					&buf[buf_len],
					MAX_FMTP_STR_LEN - buf_len,
					"%.*s=%.*s",
					(int)dec_fmtp->param[j].name.slen,
					dec_fmtp->param[j].name.ptr,
					(int)dec_fmtp->param[j].val.slen,
					dec_fmtp->param[j].val.ptr);
				else
					buf_len += pj_ansi_snprintf(&buf[buf_len], 
					MAX_FMTP_STR_LEN - buf_len,
					"%.*s", 
					(int)dec_fmtp->param[j].val.slen,
					dec_fmtp->param[j].val.ptr);
			}

			attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);

			attr->name = pj_str("fmtp");
			attr->value = pj_strdup3(pool, buf);
			m->attr[m->attr_count++] = attr;
		}

		/* Find maximum bitrate in this media */
		vfd = pjmedia_format_get_video_format_detail(&codec_param.enc_fmt,
			PJ_TRUE);
		if (vfd && max_bitrate < vfd->max_bps)
			max_bitrate = vfd->max_bps;
	}

	/* Put bandwidth info in media level using bandwidth modifier "TIAS"
	* (RFC3890).
	*/
	if (max_bitrate) {
		const pj_str_t STR_BANDW_MODIFIER = { "TIAS", 4 };
		pjmedia_sdp_bandw *b;

		b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
		b->modifier = STR_BANDW_MODIFIER;
		b->value = max_bitrate;
		m->bandw[m->bandw_count++] = b;
	}

	*p_m = m;
	return PJ_SUCCESS;
}
Example #29
0
int errno_test(void)
{
    enum { CUT = 6 };
    pj_status_t rc = 0;
    char errbuf[256];

    PJ_LOG(3,(THIS_FILE, "...errno test: check the msg carefully"));

    PJ_UNUSED_ARG(rc);
    
    /* 
     * Windows platform error. 
     */
#   ifdef ERROR_INVALID_DATA
    rc = PJ_STATUS_FROM_OS(ERROR_INVALID_DATA);
    pj_set_os_error(rc);

    /* Whole */
    pj_strerror(rc, errbuf, sizeof(errbuf));
    trim_newlines(errbuf);
    PJ_LOG(3,(THIS_FILE, "...msg for rc=ERROR_INVALID_DATA: '%s'", errbuf));
    if (my_stristr(errbuf, "invalid") == NULL) {
        PJ_LOG(3, (THIS_FILE, 
                   "...error: expecting \"invalid\" string in the msg"));
#ifndef PJ_WIN32_WINCE
        return -20;
#endif
    }

    /* Cut version. */
    pj_strerror(rc, errbuf, CUT);
    PJ_LOG(3,(THIS_FILE, "...msg for rc=ERROR_INVALID_DATA (cut): '%s'", errbuf));
#   endif

    /*
     * Unix errors
     */
#   if defined(EINVAL) && !defined(PJ_SYMBIAN)
    rc = PJ_STATUS_FROM_OS(EINVAL);
    pj_set_os_error(rc);

    /* Whole */
    pj_strerror(rc, errbuf, sizeof(errbuf));
    trim_newlines(errbuf);
    PJ_LOG(3,(THIS_FILE, "...msg for rc=EINVAL: '%s'", errbuf));
    if (my_stristr(errbuf, "invalid") == NULL) {
        PJ_LOG(3, (THIS_FILE, 
                   "...error: expecting \"invalid\" string in the msg"));
        return -30;
    }

    /* Cut */
    pj_strerror(rc, errbuf, CUT);
    PJ_LOG(3,(THIS_FILE, "...msg for rc=EINVAL (cut): '%s'", errbuf));
#   endif

    /* 
     * Windows WSA errors
     */
#   ifdef WSAEINVAL
    rc = PJ_STATUS_FROM_OS(WSAEINVAL);
    pj_set_os_error(rc);

    /* Whole */
    pj_strerror(rc, errbuf, sizeof(errbuf));
    trim_newlines(errbuf);
    PJ_LOG(3,(THIS_FILE, "...msg for rc=WSAEINVAL: '%s'", errbuf));
    if (my_stristr(errbuf, "invalid") == NULL) {
        PJ_LOG(3, (THIS_FILE, 
                   "...error: expecting \"invalid\" string in the msg"));
        return -40;
    }

    /* Cut */
    pj_strerror(rc, errbuf, CUT);
    PJ_LOG(3,(THIS_FILE, "...msg for rc=WSAEINVAL (cut): '%s'", errbuf));
#   endif

    pj_strerror(PJ_EBUG, errbuf, sizeof(errbuf));
    PJ_LOG(3,(THIS_FILE, "...msg for rc=PJ_EBUG: '%s'", errbuf));
    if (my_stristr(errbuf, "BUG") == NULL) {
        PJ_LOG(3, (THIS_FILE, 
                   "...error: expecting \"BUG\" string in the msg"));
        return -20;
    }

    pj_strerror(PJ_EBUG, errbuf, CUT);
    PJ_LOG(3,(THIS_FILE, "...msg for rc=PJ_EBUG, cut at %d chars: '%s'", 
              CUT, errbuf));

    /* Perror */
    pj_perror(3, THIS_FILE, PJ_SUCCESS, "...testing %s", "pj_perror");
    PJ_PERROR(3,(THIS_FILE, PJ_SUCCESS, "...testing %s", "PJ_PERROR"));

    return 0;
}
Example #30
0
static int capture_render_loopback(pj_bool_t active,
				   int cap_dev_id, int rend_dev_id,
                                   const pjmedia_format *fmt)
{
    pj_pool_t *pool;
    pjmedia_vid_port *capture=NULL, *renderer=NULL;
    pjmedia_vid_dev_info cdi, rdi;
    pjmedia_vid_port_param param;
    pjmedia_video_format_detail *vfd;
    pj_status_t status;
    int rc = 0, i;

    pool = pj_pool_create(mem, "vidportloop", 1000, 1000, NULL);

    status = pjmedia_vid_dev_get_info(cap_dev_id, &cdi);
    if (status != PJ_SUCCESS)
	goto on_return;

    status = pjmedia_vid_dev_get_info(rend_dev_id, &rdi);
    if (status != PJ_SUCCESS)
	goto on_return;

    PJ_LOG(3,(THIS_FILE,
	      "  %s (%s) ===> %s (%s)\t%s\t%dx%d\t@%d:%d fps",
	      cdi.name, cdi.driver, rdi.name, rdi.driver,
	      pjmedia_get_video_format_info(NULL, fmt->id)->name,
	      fmt->det.vid.size.w, fmt->det.vid.size.h,
	      fmt->det.vid.fps.num, fmt->det.vid.fps.denum));

    pjmedia_vid_port_param_default(&param);

    /* Create capture, set it to active (master) */
    status = pjmedia_vid_dev_default_param(pool, cap_dev_id,
					   &param.vidparam);
    if (status != PJ_SUCCESS) {
	rc = 100; goto on_return;
    }
    param.vidparam.dir = PJMEDIA_DIR_CAPTURE;
    param.vidparam.fmt = *fmt;
    param.active = (active? PJ_TRUE: PJ_FALSE);

    if (param.vidparam.fmt.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO) {
	rc = 103; goto on_return;
    }

    vfd = pjmedia_format_get_video_format_detail(&param.vidparam.fmt, PJ_TRUE);
    if (vfd == NULL) {
	rc = 105; goto on_return;
    }

    status = pjmedia_vid_port_create(pool, &param, &capture);
    if (status != PJ_SUCCESS) {
	rc = 110; goto on_return;
    }

    /* Create renderer, set it to passive (slave)  */
    status = pjmedia_vid_dev_default_param(pool, rend_dev_id,
					   &param.vidparam);
    if (status != PJ_SUCCESS) {
	rc = 120; goto on_return;
    }

    param.active = (active? PJ_FALSE: PJ_TRUE);
    param.vidparam.dir = PJMEDIA_DIR_RENDER;
    param.vidparam.rend_id = rend_dev_id;
    param.vidparam.fmt = *fmt;
    param.vidparam.disp_size = vfd->size;

    status = pjmedia_vid_port_create(pool, &param, &renderer);
    if (status != PJ_SUCCESS) {
	rc = 130; goto on_return;
    }

    /* Set event handler */
    pjmedia_event_subscribe(NULL, &vid_event_cb, NULL, renderer);

    /* Connect capture to renderer */
    status = pjmedia_vid_port_connect(
	         (active? capture: renderer),
		 pjmedia_vid_port_get_passive_port(active? renderer: capture),
		 PJ_FALSE);
    if (status != PJ_SUCCESS) {
	rc = 140; goto on_return;
    }

    /* Start streaming.. */
    status = pjmedia_vid_port_start(renderer);
    if (status != PJ_SUCCESS) {
	rc = 150; goto on_return;
    }
    status = pjmedia_vid_port_start(capture);
    if (status != PJ_SUCCESS) {
	rc = 160; goto on_return;
    }

    /* Sleep while the webcam is being displayed... */
    for (i = 0; i < LOOP_DURATION*10 && (!is_quitting); i++) {
        pj_thread_sleep(100);
    }

on_return:
    if (status != PJ_SUCCESS)
	PJ_PERROR(3, (THIS_FILE, status, "   error"));

    if (capture)
        pjmedia_vid_port_stop(capture);
    if (renderer)
        pjmedia_vid_port_stop(renderer);
    if (capture)
	pjmedia_vid_port_destroy(capture);
    if (renderer) {
        pjmedia_event_unsubscribe(NULL, &vid_event_cb, NULL, renderer);
	pjmedia_vid_port_destroy(renderer);
    }

    pj_pool_release(pool);
    return rc;
}