示例#1
0
static pj_status_t transport_destroy  (pjmedia_transport *tp)
{
    transport_srtp *srtp = (transport_srtp *) tp;
    pj_status_t status;
    unsigned i;

    PJ_ASSERT_RETURN(tp, PJ_EINVAL);

    /* Close keying */
    for (i=0; i < srtp->keying_cnt; i++)
	pjmedia_transport_close(srtp->keying[i]);

    /* Close member if configured */
    if (srtp->setting.close_member_tp && srtp->member_tp) {
	pjmedia_transport_close(srtp->member_tp);
    }

    status = pjmedia_transport_srtp_stop(tp);

    /* In case mutex is being acquired by other thread */
    pj_lock_acquire(srtp->mutex);
    pj_lock_release(srtp->mutex);

    pj_lock_destroy(srtp->mutex);
    pj_pool_release(srtp->pool);

    return status;
}
示例#2
0
文件: pcaputil.c 项目: iamroger/voip
static void cleanup()
{
    if (app.srtp) pjmedia_transport_close(app.srtp);
    if (app.wav) {
        pj_ssize_t pos = pjmedia_wav_writer_port_get_pos(app.wav);
        if (pos >= 0) {
            unsigned msec;
            msec = (unsigned)pos / 2 * 1000 / PJMEDIA_PIA_SRATE(&app.wav->info);
            printf("Written: %dm:%02ds.%03d\n",
                    msec / 1000 / 60,
                    (msec / 1000) % 60,
                    msec % 1000);
        }
	pjmedia_port_destroy(app.wav);
    }
    if (app.pcap) pj_pcap_close(app.pcap);
    if (app.codec) {
	pjmedia_codec_mgr *cmgr;
	pjmedia_codec_close(app.codec);
	cmgr = pjmedia_endpt_get_codec_mgr(app.mept);
	pjmedia_codec_mgr_dealloc_codec(cmgr, app.codec);
    }
    if (app.aud_strm) {
	pjmedia_aud_stream_stop(app.aud_strm);
	pjmedia_aud_stream_destroy(app.aud_strm);
    }
    if (app.mept) pjmedia_endpt_destroy(app.mept);
    if (app.pool) pj_pool_release(app.pool);
    pj_caching_pool_destroy(&app.cp);
    pj_shutdown();
}
示例#3
0
/*
 * destroy() is called when the transport is no longer needed.
 */
static pj_status_t transport_destroy(pjmedia_transport *tp)
{
    struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;

    PJ_ASSERT_RETURN(tp, PJ_EINVAL);

    PJ_LOG(4, (THIS_FILE, "Destroy - encrypted packets: %ld, decrypted packets: %ld",
               zrtp->protect, zrtp->unprotect));

    /* close the slave transport in case */
    if (zrtp->close_slave && zrtp->slave_tp)
    {
        pjmedia_transport_close(zrtp->slave_tp);
    }
    /* Self destruct.. */
    zrtp_DestroyWrapper(zrtp->zrtpCtx);

    /* In case mutex is being acquired by other thread */
    pj_mutex_lock(zrtp->zrtpMutex);
    pj_mutex_unlock(zrtp->zrtpMutex);
    pj_mutex_destroy(zrtp->zrtpMutex);

    pj_pool_release(zrtp->pool);

    return PJ_SUCCESS;
}
示例#4
0
/*****************************************************************************
 * The test session
 */
static void test_destroy(void)
{
    if (g_app.tx)
	stream_destroy(g_app.tx);
    if (g_app.tx_wav)
	pjmedia_port_destroy(g_app.tx_wav);
    if (g_app.rx)
	stream_destroy(g_app.rx);
    if (g_app.rx_wav)
	pjmedia_port_destroy(g_app.rx_wav);
    if (g_app.loop)
	pjmedia_transport_close(g_app.loop);
    if (g_app.endpt)
	pjmedia_endpt_destroy( g_app.endpt );
    if (g_app.log_fd) {
	pj_log_set_log_func(&pj_log_write);
	pj_log_set_decor(pj_log_get_decor() | PJ_LOG_HAS_NEWLINE);
	pj_file_close(g_app.log_fd);
	g_app.log_fd = NULL;
    }
    if (g_app.pool)
	pj_pool_release(g_app.pool);
    pj_caching_pool_destroy( &g_app.cp );
    pj_shutdown();
}
/*
 * destroy() is called when the transport is no longer needed.
 */
static pj_status_t transport_destroy  (pjmedia_transport *tp)
{
    struct tp_adapter *adapter = (struct tp_adapter*)tp;

    /* Close the slave transport */
    if (adapter->del_base) {
        pjmedia_transport_close(adapter->slave_tp);
    }

    /* Self destruct.. */
    pj_pool_release(adapter->pool);

    return PJ_SUCCESS;
}
示例#6
0
static pj_status_t transport_destroy  (pjmedia_transport *tp)
{
    transport_srtp *srtp = (transport_srtp *) tp;
    pj_status_t status;

    PJ_ASSERT_RETURN(tp, PJ_EINVAL);

    pj_lock_acquire(srtp->mutex);

    if (srtp->setting.close_member_tp && srtp->member_tp) {
	pjmedia_transport_close(srtp->member_tp);
    }

    status = pjmedia_transport_srtp_stop(tp);

    pj_lock_release(srtp->mutex);

    pj_lock_destroy(srtp->mutex);
    pj_pool_release(srtp->pool);

    return status;
}
示例#7
0
/*
 * main()
 *
 * If called with argument, treat argument as SIP URL to be called.
 * Otherwise wait for incoming calls.
 */
int main(int argc, char *argv[])
{
    pj_pool_t *pool = NULL;
    pj_status_t status;
    unsigned i;

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

    pj_log_set_level(5);

    /* Then init PJLIB-UTIL: */
    status = pjlib_util_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);


    /* Create global endpoint: */
    {
	const pj_str_t *hostname;
	const char *endpt_name;

	/* Endpoint MUST be assigned a globally unique name.
	 * The name will be used as the hostname in Warning header.
	 */

	/* For this implementation, we'll use hostname for simplicity */
	hostname = pj_gethostname();
	endpt_name = hostname->ptr;

	/* Create the endpoint: */

	status = pjsip_endpt_create(&cp.factory, endpt_name, 
				    &g_endpt);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    }


    /* 
     * Add UDP transport, with hard-coded port 
     * Alternatively, application can use pjsip_udp_transport_attach() to
     * start UDP transport, if it already has an UDP socket (e.g. after it
     * resolves the address with STUN).
     */
    {
	pj_sockaddr addr;

	pj_sockaddr_init(AF, &addr, NULL, (pj_uint16_t)SIP_PORT);
	
	if (AF == pj_AF_INET()) {
	    status = pjsip_udp_transport_start( g_endpt, &addr.ipv4, NULL, 
						1, NULL);
	} else if (AF == pj_AF_INET6()) {
	    status = pjsip_udp_transport_start6(g_endpt, &addr.ipv6, NULL,
						1, NULL);
	} else {
	    status = PJ_EAFNOTSUP;
	}

	if (status != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to start UDP transport", status);
	    return 1;
	}
    }


    /* 
     * Init transaction layer.
     * This will create/initialize transaction hash tables etc.
     */
    status = pjsip_tsx_layer_init_module(g_endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    /* 
     * Initialize UA layer module.
     * This will create/initialize dialog hash tables etc.
     */
    status = pjsip_ua_init_module( g_endpt, NULL );
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    /* 
     * Init invite session module.
     * The invite session module initialization takes additional argument,
     * i.e. a structure containing callbacks to be called on specific
     * occurence of events.
     *
     * The on_state_changed and on_new_session callbacks are mandatory.
     * Application must supply the callback function.
     *
     * We use on_media_update() callback in this application to start
     * media transmission.
     */
    {
	pjsip_inv_callback inv_cb;

	/* Init the callback for INVITE session: */
	pj_bzero(&inv_cb, sizeof(inv_cb));
	inv_cb.on_state_changed = &call_on_state_changed;
	inv_cb.on_new_session = &call_on_forked;
	inv_cb.on_media_update = &call_on_media_update;

	/* Initialize invite session module:  */
	status = pjsip_inv_usage_init(g_endpt, &inv_cb);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    }

    /* Initialize 100rel support */
    status = pjsip_100rel_init_module(g_endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

    /*
     * Register our module to receive incoming requests.
     */
    status = pjsip_endpt_register_module( g_endpt, &mod_simpleua);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /*
     * Register message logger module.
     */
    status = pjsip_endpt_register_module( g_endpt, &msg_logger);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    /* 
     * Initialize media endpoint.
     * This will implicitly initialize PJMEDIA too.
     */
#if PJ_HAS_THREADS
    status = pjmedia_endpt_create(&cp.factory, NULL, 1, &g_med_endpt);
#else
    status = pjmedia_endpt_create(&cp.factory, 
				  pjsip_endpt_get_ioqueue(g_endpt), 
				  0, &g_med_endpt);
#endif
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /* 
     * Add PCMA/PCMU codec to the media endpoint. 
     */
#if defined(PJMEDIA_HAS_G711_CODEC) && PJMEDIA_HAS_G711_CODEC!=0
    status = pjmedia_codec_g711_init(g_med_endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
#endif


#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
    /* Init video subsystem */
    pool = pjmedia_endpt_create_pool(g_med_endpt, "Video subsystem", 512, 512);
    status = pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    status = pjmedia_converter_mgr_create(pool, NULL);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    status = pjmedia_vid_codec_mgr_create(pool, NULL);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    status = pjmedia_vid_dev_subsys_init(&cp.factory);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

#  if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC!=0
    /* Init ffmpeg video codecs */
    status = pjmedia_codec_ffmpeg_vid_init(NULL, &cp.factory);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
#  endif  /* PJMEDIA_HAS_FFMPEG_VID_CODEC */

#endif	/* PJMEDIA_HAS_VIDEO */
    
    /* 
     * Create media transport used to send/receive RTP/RTCP socket.
     * One media transport is needed for each call. Application may
     * opt to re-use the same media transport for subsequent calls.
     */
    for (i = 0; i < PJ_ARRAY_SIZE(g_med_transport); ++i) {
	status = pjmedia_transport_udp_create3(g_med_endpt, AF, NULL, NULL, 
					       RTP_PORT + i*2, 0, 
					       &g_med_transport[i]);
	if (status != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to create media transport", status);
	    return 1;
	}

	/* 
	 * Get socket info (address, port) of the media transport. We will
	 * need this info to create SDP (i.e. the address and port info in
	 * the SDP).
	 */
	pjmedia_transport_info_init(&g_med_tpinfo[i]);
	pjmedia_transport_get_info(g_med_transport[i], &g_med_tpinfo[i]);

	pj_memcpy(&g_sock_info[i], &g_med_tpinfo[i].sock_info,
		  sizeof(pjmedia_sock_info));
    }

    /*
     * If URL is specified, then make call immediately.
     */
    if (argc > 1) {
	pj_sockaddr hostaddr;
	char hostip[PJ_INET6_ADDRSTRLEN+2];
	char temp[80];
	pj_str_t dst_uri = pj_str(argv[1]);
	pj_str_t local_uri;
	pjsip_dialog *dlg;
	pjmedia_sdp_session *local_sdp;
	pjsip_tx_data *tdata;

	if (pj_gethostip(AF, &hostaddr) != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to retrieve local host IP", status);
	    return 1;
	}
	pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2);

	pj_ansi_sprintf(temp, "<sip:simpleuac@%s:%d>", 
			hostip, SIP_PORT);
	local_uri = pj_str(temp);

	/* Create UAC dialog */
	status = pjsip_dlg_create_uac( pjsip_ua_instance(), 
				       &local_uri,  /* local URI */
				       &local_uri,  /* local Contact */
				       &dst_uri,    /* remote URI */
				       &dst_uri,    /* remote target */
				       &dlg);	    /* dialog */
	if (status != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to create UAC dialog", status);
	    return 1;
	}

	/* If we expect the outgoing INVITE to be challenged, then we should
	 * put the credentials in the dialog here, with something like this:
	 *
	    {
		pjsip_cred_info	cred[1];

		cred[0].realm	  = pj_str("sip.server.realm");
		cred[0].scheme    = pj_str("digest");
		cred[0].username  = pj_str("theuser");
		cred[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
		cred[0].data      = pj_str("thepassword");

		pjsip_auth_clt_set_credentials( &dlg->auth_sess, 1, cred);
	    }
	 *
	 */


	/* Get the SDP body to be put in the outgoing INVITE, by asking
	 * media endpoint to create one for us.
	 */
	status = pjmedia_endpt_create_sdp( g_med_endpt,	    /* the media endpt	*/
					   dlg->pool,	    /* pool.		*/
					   MAX_MEDIA_CNT,   /* # of streams	*/
					   g_sock_info,     /* RTP sock info	*/
					   &local_sdp);	    /* the SDP result	*/
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);



	/* Create the INVITE session, and pass the SDP returned earlier
	 * as the session's initial capability.
	 */
	status = pjsip_inv_create_uac( dlg, local_sdp, 0, &g_inv);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

	/* If we want the initial INVITE to travel to specific SIP proxies,
	 * then we should put the initial dialog's route set here. The final
	 * route set will be updated once a dialog has been established.
	 * To set the dialog's initial route set, we do it with something
	 * like this:
	 *
	    {
		pjsip_route_hdr route_set;
		pjsip_route_hdr *route;
		const pj_str_t hname = { "Route", 5 };
		char *uri = "sip:proxy.server;lr";

		pj_list_init(&route_set);

		route = pjsip_parse_hdr( dlg->pool, &hname, 
					 uri, strlen(uri),
					 NULL);
		PJ_ASSERT_RETURN(route != NULL, 1);
		pj_list_push_back(&route_set, route);

		pjsip_dlg_set_route_set(dlg, &route_set);
	    }
	 *
	 * Note that Route URI SHOULD have an ";lr" parameter!
	 */

	/* Create initial INVITE request.
	 * This INVITE request will contain a perfectly good request and 
	 * an SDP body as well.
	 */
	status = pjsip_inv_invite(g_inv, &tdata);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);



	/* Send initial INVITE request. 
	 * From now on, the invite session's state will be reported to us
	 * via the invite session callbacks.
	 */
	status = pjsip_inv_send_msg(g_inv, tdata);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    } else {

	/* No URL to make call to */

	PJ_LOG(3,(THIS_FILE, "Ready to accept incoming calls..."));
    }


    /* Loop until one call is completed */
    for (;!g_complete;) {
	pj_time_val timeout = {0, 10};
	pjsip_endpt_handle_events(g_endpt, &timeout);
    }

    /* On exit, dump current memory usage: */
    dump_pool_usage(THIS_FILE, &cp);

    /* Destroy audio ports. Destroy the audio port first
     * before the stream since the audio port has threads
     * that get/put frames to the stream.
     */
    if (g_snd_port)
	pjmedia_snd_port_destroy(g_snd_port);

#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
    /* Destroy video ports */
    if (g_vid_capturer)
	pjmedia_vid_port_destroy(g_vid_capturer);
    if (g_vid_renderer)
	pjmedia_vid_port_destroy(g_vid_renderer);
#endif

    /* Destroy streams */
    if (g_med_stream)
	pjmedia_stream_destroy(g_med_stream);
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
    if (g_med_vstream)
	pjmedia_vid_stream_destroy(g_med_vstream);

    /* Deinit ffmpeg codec */
#   if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC!=0
    pjmedia_codec_ffmpeg_vid_deinit();
#   endif

#endif

    /* Destroy media transports */
    for (i = 0; i < MAX_MEDIA_CNT; ++i) {
	if (g_med_transport[i])
	    pjmedia_transport_close(g_med_transport[i]);
    }

    /* Deinit pjmedia endpoint */
    if (g_med_endpt)
	pjmedia_endpt_destroy(g_med_endpt);

    /* Deinit pjsip endpoint */
    if (g_endpt)
	pjsip_endpt_destroy(g_endpt);

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

    return 0;
}
示例#8
0
/*
 * main()
 */
int main(int argc, char *argv[])
{
    pj_caching_pool cp;
    pjmedia_endpt *med_endpt;
    pj_pool_t *pool;
    pjmedia_vid_stream *stream = NULL;
    pjmedia_port *enc_port, *dec_port;
    pj_status_t status; 

    pjmedia_vid_port *capture=NULL, *renderer=NULL;
    pjmedia_vid_port_param vpp;

#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
    /* SRTP variables */
    pj_bool_t use_srtp = PJ_FALSE;
    char tmp_tx_key[64];
    char tmp_rx_key[64];
    pj_str_t  srtp_tx_key = {NULL, 0};
    pj_str_t  srtp_rx_key = {NULL, 0};
    pj_str_t  srtp_crypto_suite = {NULL, 0};
    int	tmp_key_len;
#endif

    /* Default values */
    const pjmedia_vid_codec_info *codec_info;
    pjmedia_vid_codec_param codec_param;
    pjmedia_dir dir = PJMEDIA_DIR_DECODING;
    pj_sockaddr_in remote_addr;
    pj_uint16_t local_port = 4000;
    char *codec_id = NULL;
    pjmedia_rect_size tx_size = {0};
    pj_int8_t rx_pt = -1, tx_pt = -1;

    play_file_data play_file = { NULL };
    pjmedia_port *play_port = NULL;
    pjmedia_vid_codec *play_decoder = NULL;
    pjmedia_clock *play_clock = NULL;

    enum {
	OPT_CODEC	= 'c',
	OPT_LOCAL_PORT	= 'p',
	OPT_REMOTE	= 'r',
	OPT_PLAY_FILE	= 'f',
	OPT_SEND_RECV	= 'b',
	OPT_SEND_ONLY	= 's',
	OPT_RECV_ONLY	= 'i',
	OPT_SEND_WIDTH	= 'W',
	OPT_SEND_HEIGHT	= 'H',
	OPT_RECV_PT	= 't',
	OPT_SEND_PT	= 'T',
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
	OPT_USE_SRTP	= 'S',
#endif
	OPT_SRTP_TX_KEY	= 'x',
	OPT_SRTP_RX_KEY	= 'y',
	OPT_HELP	= 'h',
    };

    struct pj_getopt_option long_options[] = {
	{ "codec",	    1, 0, OPT_CODEC },
	{ "local-port",	    1, 0, OPT_LOCAL_PORT },
	{ "remote",	    1, 0, OPT_REMOTE },
	{ "play-file",	    1, 0, OPT_PLAY_FILE },
	{ "send-recv",      0, 0, OPT_SEND_RECV },
	{ "send-only",      0, 0, OPT_SEND_ONLY },
	{ "recv-only",      0, 0, OPT_RECV_ONLY },
	{ "send-width",     1, 0, OPT_SEND_WIDTH },
	{ "send-height",    1, 0, OPT_SEND_HEIGHT },
	{ "recv-pt",        1, 0, OPT_RECV_PT },
	{ "send-pt",        1, 0, OPT_SEND_PT },
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
	{ "use-srtp",	    2, 0, OPT_USE_SRTP },
	{ "srtp-tx-key",    1, 0, OPT_SRTP_TX_KEY },
	{ "srtp-rx-key",    1, 0, OPT_SRTP_RX_KEY },
#endif
	{ "help",	    0, 0, OPT_HELP },
	{ NULL, 0, 0, 0 },
    };

    int c;
    int option_index;


    pj_bzero(&remote_addr, sizeof(remote_addr));


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


    /* Parse arguments */
    pj_optind = 0;
    while((c=pj_getopt_long(argc,argv, "h", long_options, &option_index))!=-1)
    {
	switch (c) {
	case OPT_CODEC:
	    codec_id = pj_optarg;
	    break;

	case OPT_LOCAL_PORT:
	    local_port = (pj_uint16_t) atoi(pj_optarg);
	    if (local_port < 1) {
		printf("Error: invalid local port %s\n", pj_optarg);
		return 1;
	    }
	    break;

	case OPT_REMOTE:
	    {
		pj_str_t ip = pj_str(strtok(pj_optarg, ":"));
		pj_uint16_t port = (pj_uint16_t) atoi(strtok(NULL, ":"));

		status = pj_sockaddr_in_init(&remote_addr, &ip, port);
		if (status != PJ_SUCCESS) {
		    app_perror(THIS_FILE, "Invalid remote address", status);
		    return 1;
		}
	    }
	    break;

	case OPT_PLAY_FILE:
	    play_file.file_name = pj_optarg;
	    break;

	case OPT_SEND_RECV:
	    dir = PJMEDIA_DIR_ENCODING_DECODING;
	    break;

	case OPT_SEND_ONLY:
	    dir = PJMEDIA_DIR_ENCODING;
	    break;

	case OPT_RECV_ONLY:
	    dir = PJMEDIA_DIR_DECODING;
	    break;

	case OPT_SEND_WIDTH:
	    tx_size.w = (unsigned)atoi(pj_optarg);
	    break;

	case OPT_SEND_HEIGHT:
	    tx_size.h = (unsigned)atoi(pj_optarg);
	    break;

	case OPT_RECV_PT:
	    rx_pt = (pj_int8_t)atoi(pj_optarg);
	    break;

	case OPT_SEND_PT:
	    tx_pt = (pj_int8_t)atoi(pj_optarg);
	    break;

#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
	case OPT_USE_SRTP:
	    use_srtp = PJ_TRUE;
	    if (pj_optarg) {
		pj_strset(&srtp_crypto_suite, pj_optarg, strlen(pj_optarg));
	    } else {
		srtp_crypto_suite = pj_str("AES_CM_128_HMAC_SHA1_80");
	    }
	    break;

	case OPT_SRTP_TX_KEY:
	    tmp_key_len = hex_string_to_octet_string(tmp_tx_key, pj_optarg, 
						     strlen(pj_optarg));
	    pj_strset(&srtp_tx_key, tmp_tx_key, tmp_key_len/2);
	    break;

	case OPT_SRTP_RX_KEY:
	    tmp_key_len = hex_string_to_octet_string(tmp_rx_key, pj_optarg,
						     strlen(pj_optarg));
	    pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2);
	    break;
#endif

	case OPT_HELP:
	    usage();
	    return 1;

	default:
	    printf("Invalid options %s\n", argv[pj_optind]);
	    return 1;
	}

    }


    /* Verify arguments. */
    if (dir & PJMEDIA_DIR_ENCODING) {
	if (remote_addr.sin_addr.s_addr == 0) {
	    printf("Error: remote address must be set\n");
	    return 1;
	}
    }

    if (play_file.file_name != NULL && dir != PJMEDIA_DIR_ENCODING) {
	printf("Direction is set to --send-only because of --play-file\n");
	dir = PJMEDIA_DIR_ENCODING;
    }

#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
    /* SRTP validation */
    if (use_srtp) {
	if (!srtp_tx_key.slen || !srtp_rx_key.slen)
	{
	    printf("Error: Key for each SRTP stream direction must be set\n");
	    return 1;
	}
    }
#endif

    /* 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.
     * This will implicitly initialize PJMEDIA too.
     */
    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);

    /* Init video subsystem */
    pjmedia_vid_dev_subsys_init(&cp.factory);

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


    /* 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);
    
    /* Set outgoing video size */
    if (tx_size.w && tx_size.h)
        codec_param.enc_fmt.det.vid.size = tx_size;

#if DEF_RENDERER_WIDTH && DEF_RENDERER_HEIGHT
    /* Set incoming video size */
    if (DEF_RENDERER_WIDTH > codec_param.dec_fmt.det.vid.size.w)
	codec_param.dec_fmt.det.vid.size.w = DEF_RENDERER_WIDTH;
    if (DEF_RENDERER_HEIGHT > codec_param.dec_fmt.det.vid.size.h)
	codec_param.dec_fmt.det.vid.size.h = DEF_RENDERER_HEIGHT;
#endif

    if (play_file.file_name) {
	pjmedia_video_format_detail *file_vfd;
        pjmedia_clock_param clock_param;
        char fmt_name[5];

	/* Create file player */
	status = create_file_player(pool, play_file.file_name, &play_port);
	if (status != PJ_SUCCESS)
	    goto on_exit;

	/* Collect format info */
	file_vfd = pjmedia_format_get_video_format_detail(&play_port->info.fmt,
							  PJ_TRUE);
	PJ_LOG(2, (THIS_FILE, "Reading video stream %dx%d %s @%.2ffps",
		   file_vfd->size.w, file_vfd->size.h,
		   pjmedia_fourcc_name(play_port->info.fmt.id, fmt_name),
		   (1.0*file_vfd->fps.num/file_vfd->fps.denum)));

	/* Allocate file read buffer */
	play_file.read_buf_size = PJMEDIA_MAX_VIDEO_ENC_FRAME_SIZE;
	play_file.read_buf = pj_pool_zalloc(pool, play_file.read_buf_size);

	/* Create decoder, if the file and the stream uses different codec */
	if (codec_info->fmt_id != (pjmedia_format_id)play_port->info.fmt.id) {
	    const pjmedia_video_format_info *dec_vfi;
	    pjmedia_video_apply_fmt_param dec_vafp = {0};
	    const pjmedia_vid_codec_info *codec_info2;
	    pjmedia_vid_codec_param codec_param2;

	    /* Find decoder */
	    status = pjmedia_vid_codec_mgr_get_codec_info2(NULL,
							   play_port->info.fmt.id,
							   &codec_info2);
	    if (status != PJ_SUCCESS)
		goto on_exit;

	    /* Init decoder */
	    status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info2,
						       &play_decoder);
	    if (status != PJ_SUCCESS)
		goto on_exit;

	    status = play_decoder->op->init(play_decoder, pool);
	    if (status != PJ_SUCCESS)
		goto on_exit;

	    /* Open decoder */
	    status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info2,
							     &codec_param2);
	    if (status != PJ_SUCCESS)
		goto on_exit;

	    codec_param2.dir = PJMEDIA_DIR_DECODING;
	    status = play_decoder->op->open(play_decoder, &codec_param2);
	    if (status != PJ_SUCCESS)
		goto on_exit;

	    /* Get decoder format info and apply param */
	    dec_vfi = pjmedia_get_video_format_info(NULL,
						    codec_info2->dec_fmt_id[0]);
	    if (!dec_vfi || !dec_vfi->apply_fmt) {
		status = PJ_ENOTSUP;
		goto on_exit;
	    }
	    dec_vafp.size = file_vfd->size;
	    (*dec_vfi->apply_fmt)(dec_vfi, &dec_vafp);

	    /* Allocate buffer to receive decoder output */
	    play_file.dec_buf_size = dec_vafp.framebytes;
	    play_file.dec_buf = pj_pool_zalloc(pool, play_file.dec_buf_size);
	}

	/* Create player clock */
        clock_param.usec_interval = PJMEDIA_PTIME(&file_vfd->fps);
        clock_param.clock_rate = codec_info->clock_rate;
	status = pjmedia_clock_create2(pool, &clock_param,
				       PJMEDIA_CLOCK_NO_HIGHEST_PRIO,
				       &clock_cb, &play_file, &play_clock);
	if (status != PJ_SUCCESS)
	    goto on_exit;

	/* Override stream codec param for encoding direction */
	codec_param.enc_fmt.det.vid.size = file_vfd->size;
	codec_param.enc_fmt.det.vid.fps  = file_vfd->fps;

    } else {
        pjmedia_vid_port_param_default(&vpp);

        /* Set as active for all video devices */
        vpp.active = PJ_TRUE;

	/* Create video device port. */
        if (dir & PJMEDIA_DIR_ENCODING) {
            /* Create capture */
            status = pjmedia_vid_dev_default_param(
					pool,
					PJMEDIA_VID_DEFAULT_CAPTURE_DEV,
					&vpp.vidparam);
            if (status != PJ_SUCCESS)
	        goto on_exit;

            pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.enc_fmt);
	    vpp.vidparam.fmt.id = codec_param.dec_fmt.id;
            vpp.vidparam.dir = PJMEDIA_DIR_CAPTURE;
            
            status = pjmedia_vid_port_create(pool, &vpp, &capture);
            if (status != PJ_SUCCESS)
	        goto on_exit;
        }
	
        if (dir & PJMEDIA_DIR_DECODING) {
            /* Create renderer */
            status = pjmedia_vid_dev_default_param(
					pool,
					PJMEDIA_VID_DEFAULT_RENDER_DEV,
					&vpp.vidparam);
            if (status != PJ_SUCCESS)
	        goto on_exit;

            pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.dec_fmt);
            vpp.vidparam.dir = PJMEDIA_DIR_RENDER;
            vpp.vidparam.disp_size = vpp.vidparam.fmt.det.vid.size;
	    vpp.vidparam.flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS;
	    vpp.vidparam.window_flags = PJMEDIA_VID_DEV_WND_BORDER |
					PJMEDIA_VID_DEV_WND_RESIZABLE;

            status = pjmedia_vid_port_create(pool, &vpp, &renderer);
            if (status != PJ_SUCCESS)
	        goto on_exit;
        }
    }

    /* Set to ignore fmtp */
    codec_param.ignore_fmtp = PJ_TRUE;

    /* Create stream based on program arguments */
    status = create_stream(pool, med_endpt, codec_info, &codec_param,
                           dir, rx_pt, tx_pt, local_port, &remote_addr, 
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
			   use_srtp, &srtp_crypto_suite, 
			   &srtp_tx_key, &srtp_rx_key,
#endif
			   &stream);
    if (status != PJ_SUCCESS)
	goto on_exit;

    /* Get the port interface of the stream */
    status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_ENCODING,
				         &enc_port);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_DECODING,
				         &dec_port);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /* Start streaming */
    status = pjmedia_vid_stream_start(stream);
    if (status != PJ_SUCCESS)
        goto on_exit;

    /* Start renderer */
    if (renderer) {
        status = pjmedia_vid_port_connect(renderer, dec_port, PJ_FALSE);
        if (status != PJ_SUCCESS)
	    goto on_exit;
        status = pjmedia_vid_port_start(renderer);
        if (status != PJ_SUCCESS)
            goto on_exit;
    }

    /* Start capture */
    if (capture) {
        status = pjmedia_vid_port_connect(capture, enc_port, PJ_FALSE);
        if (status != PJ_SUCCESS)
	    goto on_exit;
        status = pjmedia_vid_port_start(capture);
        if (status != PJ_SUCCESS)
            goto on_exit;
    }

    /* Start playing file */
    if (play_file.file_name) {

#if HAS_LOCAL_RENDERER_FOR_PLAY_FILE
        /* Create local renderer */
        pjmedia_vid_port_param_default(&vpp);
        vpp.active = PJ_FALSE;
        status = pjmedia_vid_dev_default_param(
				pool,
				PJMEDIA_VID_DEFAULT_RENDER_DEV,
				&vpp.vidparam);
        if (status != PJ_SUCCESS)
	    goto on_exit;

        vpp.vidparam.dir = PJMEDIA_DIR_RENDER;
        pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.dec_fmt);
	vpp.vidparam.fmt.det.vid.size = play_port->info.fmt.det.vid.size;
	vpp.vidparam.fmt.det.vid.fps = play_port->info.fmt.det.vid.fps;
        vpp.vidparam.disp_size = vpp.vidparam.fmt.det.vid.size;

	status = pjmedia_vid_port_create(pool, &vpp, &renderer);
        if (status != PJ_SUCCESS)
	    goto on_exit;
        status = pjmedia_vid_port_start(renderer);
        if (status != PJ_SUCCESS)
            goto on_exit;
#endif

	/* Init play file data */
	play_file.play_port = play_port;
	play_file.stream_port = enc_port;
	play_file.decoder = play_decoder;
	if (renderer) {
	    play_file.renderer = pjmedia_vid_port_get_passive_port(renderer);
	}

	status = pjmedia_clock_start(play_clock);
	if (status != PJ_SUCCESS)
	    goto on_exit;
    }

    /* Done */

    if (dir == PJMEDIA_DIR_DECODING)
	printf("Stream is active, dir is recv-only, local port is %d\n",
	       local_port);
    else if (dir == PJMEDIA_DIR_ENCODING)
	printf("Stream is active, dir is send-only, sending to %s:%d\n",
	       pj_inet_ntoa(remote_addr.sin_addr),
	       pj_ntohs(remote_addr.sin_port));
    else
	printf("Stream is active, send/recv, local port is %d, "
	       "sending to %s:%d\n",
	       local_port,
	       pj_inet_ntoa(remote_addr.sin_addr),
	       pj_ntohs(remote_addr.sin_port));

    if (dir & PJMEDIA_DIR_ENCODING)
	PJ_LOG(2, (THIS_FILE, "Sending %dx%d %.*s @%.2ffps",
		   codec_param.enc_fmt.det.vid.size.w,
		   codec_param.enc_fmt.det.vid.size.h,
		   codec_info->encoding_name.slen,
		   codec_info->encoding_name.ptr,
		   (1.0*codec_param.enc_fmt.det.vid.fps.num/
		    codec_param.enc_fmt.det.vid.fps.denum)));

    for (;;) {
	char tmp[10];

	puts("");
	puts("Commands:");
	puts("  q     Quit");
	puts("");

	printf("Command: "); fflush(stdout);

	if (fgets(tmp, sizeof(tmp), stdin) == NULL) {
	    puts("EOF while reading stdin, will quit now..");
	    break;
	}

	if (tmp[0] == 'q')
	    break;

    }



    /* Start deinitialization: */
on_exit:

    /* Stop and destroy file clock */
    if (play_clock) {
	pjmedia_clock_stop(play_clock);
	pjmedia_clock_destroy(play_clock);
    }

    /* Destroy file reader/player */
    if (play_port)
	pjmedia_port_destroy(play_port);

    /* Destroy file decoder */
    if (play_decoder) {
	play_decoder->op->close(play_decoder);
	pjmedia_vid_codec_mgr_dealloc_codec(NULL, play_decoder);
    }

    /* Destroy video devices */
    if (capture)
	pjmedia_vid_port_destroy(capture);
    if (renderer)
	pjmedia_vid_port_destroy(renderer);

    /* Destroy stream */
    if (stream) {
	pjmedia_transport *tp;

	tp = pjmedia_vid_stream_get_transport(stream);
	pjmedia_vid_stream_destroy(stream);
	
	pjmedia_transport_close(tp);
    }

    /* Deinit codecs */
    deinit_codecs();

    /* Shutdown video subsystem */
    pjmedia_vid_dev_subsys_shutdown();

    /* 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;
}
示例#9
0
/* 
 * Create stream based on the codec, dir, remote address, etc. 
 */
static pj_status_t create_stream( pj_pool_t *pool,
				  pjmedia_endpt *med_endpt,
				  const pjmedia_vid_codec_info *codec_info,
                                  pjmedia_vid_codec_param *codec_param,
				  pjmedia_dir dir,
				  pj_int8_t rx_pt,
				  pj_int8_t tx_pt,
				  pj_uint16_t local_port,
				  const pj_sockaddr_in *rem_addr,
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
				  pj_bool_t use_srtp,
				  const pj_str_t *crypto_suite,
				  const pj_str_t *srtp_tx_key,
				  const pj_str_t *srtp_rx_key,
#endif
				  pjmedia_vid_stream **p_stream )
{
    pjmedia_vid_stream_info info;
    pjmedia_transport *transport = NULL;
    pj_status_t status;
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
    pjmedia_transport *srtp_tp = NULL;
#endif

    /* Reset stream info. */
    pj_bzero(&info, sizeof(info));

    /* Initialize stream info formats */
    info.type = PJMEDIA_TYPE_VIDEO;
    info.dir = dir;
    info.codec_info = *codec_info;
    info.tx_pt = (tx_pt == -1)? codec_info->pt : tx_pt;
    info.rx_pt = (rx_pt == -1)? codec_info->pt : rx_pt;
    info.ssrc = pj_rand();
    if (codec_param)
        info.codec_param = codec_param;
    
    /* Copy remote address */
    pj_memcpy(&info.rem_addr, rem_addr, sizeof(pj_sockaddr_in));

    /* If remote address is not set, set to an arbitrary address
     * (otherwise stream will assert).
     */
    if (info.rem_addr.addr.sa_family == 0) {
	const pj_str_t addr = pj_str("127.0.0.1");
	pj_sockaddr_in_init(&info.rem_addr.ipv4, &addr, 0);
    }

    /* Create media transport */
    status = pjmedia_transport_udp_create(med_endpt, NULL, local_port,
					  0, &transport);
    if (status != PJ_SUCCESS)
	return status;

#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
    /* Check if SRTP enabled */
    if (use_srtp) {
	pjmedia_srtp_crypto tx_plc, rx_plc;

	status = pjmedia_transport_srtp_create(med_endpt, transport, 
					       NULL, &srtp_tp);
	if (status != PJ_SUCCESS)
	    return status;

	pj_bzero(&tx_plc, sizeof(pjmedia_srtp_crypto));
	pj_bzero(&rx_plc, sizeof(pjmedia_srtp_crypto));

	tx_plc.key = *srtp_tx_key;
	tx_plc.name = *crypto_suite;
	rx_plc.key = *srtp_rx_key;
	rx_plc.name = *crypto_suite;
	
	status = pjmedia_transport_srtp_start(srtp_tp, &tx_plc, &rx_plc);
	if (status != PJ_SUCCESS)
	    return status;

	transport = srtp_tp;
    }
#endif

    /* Now that the stream info is initialized, we can create the 
     * stream.
     */

    status = pjmedia_vid_stream_create( med_endpt, pool, &info, 
					transport, 
					NULL, p_stream);

    if (status != PJ_SUCCESS) {
	app_perror(THIS_FILE, "Error creating stream", status);
	pjmedia_transport_close(transport);
	return status;
    }


    return PJ_SUCCESS;
}
示例#10
0
/*
 * main()
 */
int main(int argc, char *argv[])
{
    pj_caching_pool cp;
    pjmedia_endpt *med_endpt;
    pj_pool_t *pool;
    pjmedia_port *rec_file_port = NULL, *play_file_port = NULL;
    pjmedia_master_port *master_port = NULL;
    pjmedia_snd_port *snd_port = NULL;
    pjmedia_stream *stream = NULL;
    pjmedia_port *stream_port;
    char tmp[10];
    pj_status_t status; 

#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
    /* SRTP variables */
    pj_bool_t use_srtp = PJ_FALSE;
    char tmp_tx_key[64];
    char tmp_rx_key[64];
    pj_str_t  srtp_tx_key = {NULL, 0};
    pj_str_t  srtp_rx_key = {NULL, 0};
    pj_str_t  srtp_crypto_suite = {NULL, 0};
    int	tmp_key_len;
#endif

    /* Default values */
    const pjmedia_codec_info *codec_info;
    pjmedia_codec_param codec_param;
    pjmedia_dir dir = PJMEDIA_DIR_DECODING;
    pj_sockaddr_in remote_addr;
    pj_uint16_t local_port = 4000;
    char *codec_id = NULL;
    char *rec_file = NULL;
    char *play_file = NULL;

    enum {
	OPT_CODEC	= 'c',
	OPT_LOCAL_PORT	= 'p',
	OPT_REMOTE	= 'r',
	OPT_PLAY_FILE	= 'w',
	OPT_RECORD_FILE	= 'R',
	OPT_SEND_RECV	= 'b',
	OPT_SEND_ONLY	= 's',
	OPT_RECV_ONLY	= 'i',
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
	OPT_USE_SRTP	= 'S',
#endif
	OPT_SRTP_TX_KEY	= 'x',
	OPT_SRTP_RX_KEY	= 'y',
	OPT_HELP	= 'h',
    };

    struct pj_getopt_option long_options[] = {
	{ "codec",	    1, 0, OPT_CODEC },
	{ "local-port",	    1, 0, OPT_LOCAL_PORT },
	{ "remote",	    1, 0, OPT_REMOTE },
	{ "play-file",	    1, 0, OPT_PLAY_FILE },
	{ "record-file",    1, 0, OPT_RECORD_FILE },
	{ "send-recv",      0, 0, OPT_SEND_RECV },
	{ "send-only",      0, 0, OPT_SEND_ONLY },
	{ "recv-only",      0, 0, OPT_RECV_ONLY },
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
	{ "use-srtp",	    2, 0, OPT_USE_SRTP },
	{ "srtp-tx-key",    1, 0, OPT_SRTP_TX_KEY },
	{ "srtp-rx-key",    1, 0, OPT_SRTP_RX_KEY },
#endif
	{ "help",	    0, 0, OPT_HELP },
	{ NULL, 0, 0, 0 },
    };

    int c;
    int option_index;


    pj_bzero(&remote_addr, sizeof(remote_addr));


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


    /* Parse arguments */
    pj_optind = 0;
    while((c=pj_getopt_long(argc,argv, "h", long_options, &option_index))!=-1) {

	switch (c) {
	case OPT_CODEC:
	    codec_id = pj_optarg;
	    break;

	case OPT_LOCAL_PORT:
	    local_port = (pj_uint16_t) atoi(pj_optarg);
	    if (local_port < 1) {
		printf("Error: invalid local port %s\n", pj_optarg);
		return 1;
	    }
	    break;

	case OPT_REMOTE:
	    {
		pj_str_t ip = pj_str(strtok(pj_optarg, ":"));
		pj_uint16_t port = (pj_uint16_t) atoi(strtok(NULL, ":"));

		status = pj_sockaddr_in_init(&remote_addr, &ip, port);
		if (status != PJ_SUCCESS) {
		    app_perror(THIS_FILE, "Invalid remote address", status);
		    return 1;
		}
	    }
	    break;

	case OPT_PLAY_FILE:
	    play_file = pj_optarg;
	    break;

	case OPT_RECORD_FILE:
	    rec_file = pj_optarg;
	    break;

	case OPT_SEND_RECV:
	    dir = PJMEDIA_DIR_ENCODING_DECODING;
	    break;

	case OPT_SEND_ONLY:
	    dir = PJMEDIA_DIR_ENCODING;
	    break;

	case OPT_RECV_ONLY:
	    dir = PJMEDIA_DIR_DECODING;
	    break;

#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
	case OPT_USE_SRTP:
	    use_srtp = PJ_TRUE;
	    if (pj_optarg) {
		pj_strset(&srtp_crypto_suite, pj_optarg, strlen(pj_optarg));
	    } else {
		srtp_crypto_suite = pj_str("AES_CM_128_HMAC_SHA1_80");
	    }
	    break;

	case OPT_SRTP_TX_KEY:
	    tmp_key_len = hex_string_to_octet_string(tmp_tx_key, pj_optarg, 
						     (int)strlen(pj_optarg));
	    pj_strset(&srtp_tx_key, tmp_tx_key, tmp_key_len/2);
	    break;

	case OPT_SRTP_RX_KEY:
	    tmp_key_len = hex_string_to_octet_string(tmp_rx_key, pj_optarg, 
						     (int)strlen(pj_optarg));
	    pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2);
	    break;
#endif

	case OPT_HELP:
	    usage();
	    return 1;

	default:
	    printf("Invalid options %s\n", argv[pj_optind]);
	    return 1;
	}

    }


    /* Verify arguments. */
    if (dir & PJMEDIA_DIR_ENCODING) {
	if (remote_addr.sin_addr.s_addr == 0) {
	    printf("Error: remote address must be set\n");
	    return 1;
	}
    }

    if (play_file != NULL && dir != PJMEDIA_DIR_ENCODING) {
	printf("Direction is set to --send-only because of --play-file\n");
	dir = PJMEDIA_DIR_ENCODING;
    }

#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
    /* SRTP validation */
    if (use_srtp) {
	if (!srtp_tx_key.slen || !srtp_rx_key.slen)
	{
	    printf("Error: Key for each SRTP stream direction must be set\n");
	    return 1;
	}
    }
#endif

    /* 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.
     * This will implicitly initialize PJMEDIA too.
     */
    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    */
			   );


    /* Register all supported codecs */
    status = init_codecs(med_endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    /* Find which codec to use. */
    if (codec_id) {
	unsigned count = 1;
	pj_str_t str_codec_id = pj_str(codec_id);
	pjmedia_codec_mgr *codec_mgr = pjmedia_endpt_get_codec_mgr(med_endpt);
	status = pjmedia_codec_mgr_find_codecs_by_id( codec_mgr,
						      &str_codec_id, &count,
						      &codec_info, NULL);
	if (status != PJ_SUCCESS) {
	    printf("Error: unable to find codec %s\n", codec_id);
	    return 1;
	}
    } else {
	/* Default to pcmu */
	pjmedia_codec_mgr_get_codec_info( pjmedia_endpt_get_codec_mgr(med_endpt),
					  0, &codec_info);
    }

    /* Create stream based on program arguments */
    status = create_stream(pool, med_endpt, codec_info, dir, local_port, 
			   &remote_addr, 
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
			   use_srtp, &srtp_crypto_suite, 
			   &srtp_tx_key, &srtp_rx_key,
#endif
			   &stream);
    if (status != PJ_SUCCESS)
	goto on_exit;

    /* Get codec default param for info */
    status = pjmedia_codec_mgr_get_default_param(
				    pjmedia_endpt_get_codec_mgr(med_endpt), 
				    codec_info, 
				    &codec_param);
    /* Should be ok, as create_stream() above succeeded */
    pj_assert(status == PJ_SUCCESS);

    /* Get the port interface of the stream */
    status = pjmedia_stream_get_port( stream, &stream_port);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    if (play_file) {
	unsigned wav_ptime;

	wav_ptime = PJMEDIA_PIA_PTIME(&stream_port->info);
	status = pjmedia_wav_player_port_create(pool, play_file, wav_ptime,
						0, -1, &play_file_port);
	if (status != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to use file", status);
	    goto on_exit;
	}

	status = pjmedia_master_port_create(pool, play_file_port, stream_port,
					    0, &master_port);
	if (status != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to create master port", status);
	    goto on_exit;
	}

	status = pjmedia_master_port_start(master_port);
	if (status != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Error starting master port", status);
	    goto on_exit;
	}

	printf("Playing from WAV file %s..\n", play_file);

    } else if (rec_file) {

	status = pjmedia_wav_writer_port_create(pool, rec_file,
					        PJMEDIA_PIA_SRATE(&stream_port->info),
					        PJMEDIA_PIA_CCNT(&stream_port->info),
					        PJMEDIA_PIA_SPF(&stream_port->info),
					        PJMEDIA_PIA_BITS(&stream_port->info),
						0, 0, &rec_file_port);
	if (status != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to use file", status);
	    goto on_exit;
	}

	status = pjmedia_master_port_create(pool, stream_port, rec_file_port, 
					    0, &master_port);
	if (status != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to create master port", status);
	    goto on_exit;
	}

	status = pjmedia_master_port_start(master_port);
	if (status != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Error starting master port", status);
	    goto on_exit;
	}

	printf("Recording to WAV file %s..\n", rec_file);
	
    } else {

	/* Create sound device port. */
	if (dir == PJMEDIA_DIR_ENCODING_DECODING)
	    status = pjmedia_snd_port_create(pool, -1, -1, 
					PJMEDIA_PIA_SRATE(&stream_port->info),
					PJMEDIA_PIA_CCNT(&stream_port->info),
					PJMEDIA_PIA_SPF(&stream_port->info),
					PJMEDIA_PIA_BITS(&stream_port->info),
					0, &snd_port);
	else if (dir == PJMEDIA_DIR_ENCODING)
	    status = pjmedia_snd_port_create_rec(pool, -1, 
					PJMEDIA_PIA_SRATE(&stream_port->info),
					PJMEDIA_PIA_CCNT(&stream_port->info),
					PJMEDIA_PIA_SPF(&stream_port->info),
					PJMEDIA_PIA_BITS(&stream_port->info),
					0, &snd_port);
	else
	    status = pjmedia_snd_port_create_player(pool, -1, 
					PJMEDIA_PIA_SRATE(&stream_port->info),
					PJMEDIA_PIA_CCNT(&stream_port->info),
					PJMEDIA_PIA_SPF(&stream_port->info),
					PJMEDIA_PIA_BITS(&stream_port->info),
					0, &snd_port);


	if (status != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to create sound port", status);
	    goto on_exit;
	}

	/* Connect sound port to stream */
	status = pjmedia_snd_port_connect( snd_port, stream_port );
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    }

    /* Start streaming */
    pjmedia_stream_start(stream);


    /* Done */

    if (dir == PJMEDIA_DIR_DECODING)
	printf("Stream is active, dir is recv-only, local port is %d\n",
	       local_port);
    else if (dir == PJMEDIA_DIR_ENCODING)
	printf("Stream is active, dir is send-only, sending to %s:%d\n",
	       pj_inet_ntoa(remote_addr.sin_addr),
	       pj_ntohs(remote_addr.sin_port));
    else
	printf("Stream is active, send/recv, local port is %d, "
	       "sending to %s:%d\n",
	       local_port,
	       pj_inet_ntoa(remote_addr.sin_addr),
	       pj_ntohs(remote_addr.sin_port));


    for (;;) {

	puts("");
	puts("Commands:");
	puts("  s     Display media statistics");
	puts("  q     Quit");
	puts("");

	printf("Command: "); fflush(stdout);

	if (fgets(tmp, sizeof(tmp), stdin) == NULL) {
	    puts("EOF while reading stdin, will quit now..");
	    break;
	}

	if (tmp[0] == 's')
	    print_stream_stat(stream, &codec_param);
	else if (tmp[0] == 'q')
	    break;

    }



    /* Start deinitialization: */
on_exit:

    /* Destroy sound device */
    if (snd_port) {
	pjmedia_snd_port_destroy( snd_port );
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    }

    /* If there is master port, then we just need to destroy master port
     * (it will recursively destroy upstream and downstream ports, which
     * in this case are file_port and stream_port).
     */
    if (master_port) {
	pjmedia_master_port_destroy(master_port, PJ_TRUE);
	play_file_port = NULL;
	stream = NULL;
    }

    /* Destroy stream */
    if (stream) {
	pjmedia_transport *tp;

	tp = pjmedia_stream_get_transport(stream);
	pjmedia_stream_destroy(stream);
	
	pjmedia_transport_close(tp);
    }

    /* Destroy file ports */
    if (play_file_port)
	pjmedia_port_destroy( play_file_port );
    if (rec_file_port)
	pjmedia_port_destroy( rec_file_port );


    /* 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;
}
示例#11
0
/**
 * Create ipv6 transport
 */
PJ_DECL(pj_status_t) media_transports_create_ipv6(pjsua_transport_config rtp_cfg) {
    pjsua_media_transport tp[PJSUA_MAX_CALLS];
    pj_status_t status;
    int port = rtp_cfg.port;
    unsigned i;

    //TODO : here should be get from config
    for (i=0; i<PJSUA_MAX_CALLS; ++i) {
	enum { MAX_RETRY = 10 };
	pj_sock_t sock[2];
	pjmedia_sock_info si;
	unsigned j;

	/* Get rid of uninitialized var compiler warning with MSVC */
	status = PJ_SUCCESS;

	for (j=0; j<MAX_RETRY; ++j) {
	    unsigned k;

	    for (k=0; k<2; ++k) {
		pj_sockaddr bound_addr;

		status = pj_sock_socket(pj_AF_INET6(), pj_SOCK_DGRAM(), 0, &sock[k]);
		if (status != PJ_SUCCESS)
		    break;

		status = pj_sockaddr_init(pj_AF_INET6(), &bound_addr,
					  &rtp_cfg.bound_addr,
					  (unsigned short)(port+k));
		if (status != PJ_SUCCESS)
		    break;

		status = pj_sock_bind(sock[k], &bound_addr,
				      pj_sockaddr_get_len(&bound_addr));
		if (status != PJ_SUCCESS)
		    break;
	    }
	    if (status != PJ_SUCCESS) {
		if (k==1)
		    pj_sock_close(sock[0]);

		if (port != 0)
		    port += 10;
		else
		    break;

		continue;
	    }

	    pj_bzero(&si, sizeof(si));
	    si.rtp_sock = sock[0];
	    si.rtcp_sock = sock[1];

	    pj_sockaddr_init(pj_AF_INET6(), &si.rtp_addr_name,
			     &rtp_cfg.public_addr,
			     (unsigned short)(port));
	    pj_sockaddr_init(pj_AF_INET6(), &si.rtcp_addr_name,
			     &rtp_cfg.public_addr,
			     (unsigned short)(port+1));

	    status = pjmedia_transport_udp_attach(pjsua_get_pjmedia_endpt(),
						  NULL,
						  &si,
						  0,
						  &tp[i].transport);
	    if (port != 0)
		port += 10;
	    else
		break;

	    if (status == PJ_SUCCESS)
		break;
	}

	if (status != PJ_SUCCESS) {
	    pjsua_perror(THIS_FILE, "Error creating IPv6 UDP media transport",
			 status);
	    for (j=0; j<i; ++j) {
		pjmedia_transport_close(tp[j].transport);
	    }
	    return status;
	}
    }

    return pjsua_media_transports_attach(tp, i, PJ_TRUE);
}
示例#12
0
static pj_status_t transport_media_start(pjmedia_transport *tp,
				         pj_pool_t *pool,
				         const pjmedia_sdp_session *sdp_local,
				         const pjmedia_sdp_session *sdp_remote,
				         unsigned media_index)
{
    struct transport_srtp *srtp = (struct transport_srtp*) tp;
    pj_status_t last_err_st = PJ_EBUG;
    pj_status_t status;
    unsigned i;

    PJ_ASSERT_RETURN(tp && pool && sdp_local && sdp_remote, PJ_EINVAL);

    status = pjmedia_transport_media_start(srtp->member_tp, pool,
					   sdp_local, sdp_remote,
				           media_index);
    if (status != PJ_SUCCESS || srtp->bypass_srtp)
	return status;

    /* Invoke media_start() of all keying methods */
    for (i=0; i < srtp->keying_cnt; ) {
	status = pjmedia_transport_media_start(srtp->keying[i], pool,
					       sdp_local, sdp_remote,
					       media_index);
	if (status != PJ_SUCCESS) {
	    /* This keying method returns error, remove it */
	    pj_array_erase(srtp->keying, sizeof(srtp->keying[0]),
			   srtp->keying_cnt, i);
	    srtp->keying_cnt--;
	    last_err_st = status;
	    continue;
	}

	if (!srtp_crypto_empty(&srtp->tx_policy_neg) &&
	    !srtp_crypto_empty(&srtp->rx_policy_neg))
	{
	    /* SRTP nego is done, let's destroy any other keying. */
	    unsigned j;
	    for (j = 0; j < srtp->keying_cnt; ++j) {
		if (j != i)
		    pjmedia_transport_close(srtp->keying[j]);
	    }
	    srtp->keying_cnt = 1;
	    srtp->keying[0] = srtp->keying[i];
	    srtp->keying_pending_cnt = 0;
	    break;
	}

	i++;
    }

    /* All keying method failed to process remote SDP? */
    if (srtp->keying_cnt == 0)
	return last_err_st;

    /* If SRTP key is being negotiated, just return now.
     * The keying method should start the SRTP once keying nego is done.
     */
    if (srtp->keying_pending_cnt)
	return PJ_SUCCESS;

    /* Start SRTP */
    status = start_srtp(srtp);

    return status;
}
示例#13
0
static pj_status_t transport_encode_sdp(pjmedia_transport *tp,
					pj_pool_t *sdp_pool,
					pjmedia_sdp_session *sdp_local,
					const pjmedia_sdp_session *sdp_remote,
					unsigned media_index)
{
    struct transport_srtp *srtp = (struct transport_srtp*) tp;
    pj_status_t last_err_st = PJ_EBUG;
    pj_status_t status;
    unsigned i;

    PJ_ASSERT_RETURN(tp && sdp_pool && sdp_local, PJ_EINVAL);

    pj_bzero(&srtp->rx_policy_neg, sizeof(srtp->rx_policy_neg));
    pj_bzero(&srtp->tx_policy_neg, sizeof(srtp->tx_policy_neg));

    srtp->offerer_side = (sdp_remote == NULL);

    status = pjmedia_transport_encode_sdp(srtp->member_tp, sdp_pool,
					  sdp_local, sdp_remote, media_index);
    if (status != PJ_SUCCESS || srtp->bypass_srtp)
	return status;

    /* Invoke encode_sdp() of all keying methods */
    for (i=0; i < srtp->keying_cnt; ) {
	pj_status_t st;
	st = pjmedia_transport_encode_sdp(srtp->keying[i], sdp_pool,
					  sdp_local, sdp_remote,
					  media_index);
	if (st != PJ_SUCCESS) {
	    /* This keying method returns error, remove it */
	    pj_array_erase(srtp->keying, sizeof(srtp->keying[0]),
			   srtp->keying_cnt, i);
	    srtp->keying_cnt--;
	    last_err_st = st;
	    continue;
	}

	if (!srtp_crypto_empty(&srtp->tx_policy_neg) &&
	    !srtp_crypto_empty(&srtp->rx_policy_neg))
	{
	    /* SRTP nego is done, let's destroy any other keying. */
	    unsigned j;
	    for (j = 0; j < srtp->keying_cnt; ++j) {
		if (j != i)
		    pjmedia_transport_close(srtp->keying[j]);
	    }
	    srtp->keying_cnt = 1;
	    srtp->keying[0] = srtp->keying[i];
	    srtp->keying_pending_cnt = 0;
	    break;
	}

	i++;
    }

    /* All keying method failed to process remote SDP? */
    if (srtp->keying_cnt == 0)
	return last_err_st;

    return PJ_SUCCESS;
}