⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pjsua_media.c

📁 一个开源的sip源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
    }

    /* Destroy media endpoint. */
    if (pjsua_var.med_endpt) {

	/* Shutdown all codecs: */
#	if PJMEDIA_HAS_SPEEX_CODEC
	    pjmedia_codec_speex_deinit();
#	endif /* PJMEDIA_HAS_SPEEX_CODEC */

#	if PJMEDIA_HAS_GSM_CODEC
	    pjmedia_codec_gsm_deinit();
#	endif /* PJMEDIA_HAS_GSM_CODEC */

#	if PJMEDIA_HAS_G711_CODEC
	    pjmedia_codec_g711_deinit();
#	endif	/* PJMEDIA_HAS_G711_CODEC */

#	if PJMEDIA_HAS_L16_CODEC
	    pjmedia_codec_l16_deinit();
#	endif	/* PJMEDIA_HAS_L16_CODEC */


	pjmedia_endpt_destroy(pjsua_var.med_endpt);
	pjsua_var.med_endpt = NULL;

	/* Deinitialize sound subsystem */
	pjmedia_snd_deinit();
    }

    /* Reset RTP port */
    next_rtp_port = 0;

    return PJ_SUCCESS;
}


/* Create normal UDP media transports */
static pj_status_t create_udp_media_transports(pjsua_transport_config *cfg)
{
    unsigned i;
    pjmedia_sock_info skinfo;
    pj_status_t status;

    /* Create each media transport */
    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {

	status = create_rtp_rtcp_sock(cfg, &skinfo);
	if (status != PJ_SUCCESS) {
	    pjsua_perror(THIS_FILE, "Unable to create RTP/RTCP socket",
		         status);
	    goto on_error;
	}
	status = pjmedia_transport_udp_attach(pjsua_var.med_endpt, NULL,
					      &skinfo, 0,
					      &pjsua_var.calls[i].med_tp);
	if (status != PJ_SUCCESS) {
	    pjsua_perror(THIS_FILE, "Unable to create media transport",
		         status);
	    goto on_error;
	}

	pjmedia_transport_udp_simulate_lost(pjsua_var.calls[i].med_tp,
					    PJMEDIA_DIR_ENCODING,
					    pjsua_var.media_cfg.tx_drop_pct);

	pjmedia_transport_udp_simulate_lost(pjsua_var.calls[i].med_tp,
					    PJMEDIA_DIR_DECODING,
					    pjsua_var.media_cfg.rx_drop_pct);

    }

    return PJ_SUCCESS;

on_error:
    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
	if (pjsua_var.calls[i].med_tp != NULL) {
	    pjmedia_transport_close(pjsua_var.calls[i].med_tp);
	    pjsua_var.calls[i].med_tp = NULL;
	}
    }

    return status;
}


/* Create ICE media transports (when ice is enabled) */
static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg)
{
    unsigned i;
    pj_sockaddr_in addr;
    pj_status_t status;

    /* Make sure STUN server resolution has completed */
    status = pjsua_resolve_stun_server(PJ_TRUE);
    if (status != PJ_SUCCESS) {
	pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
	return status;
    }

    pj_sockaddr_in_init(&addr, 0, (pj_uint16_t)cfg->port);

    /* Create each media transport */
    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
	pj_ice_strans_comp comp;
	int next_port;

	status = pjmedia_ice_create(pjsua_var.med_endpt, NULL, 2,
				    &pjsua_var.stun_cfg, 
				    &pjsua_var.calls[i].med_tp);
	if (status != PJ_SUCCESS) {
	    pjsua_perror(THIS_FILE, "Unable to create ICE media transport",
		         status);
	    goto on_error;
	}

	status = pjmedia_ice_start_init(pjsua_var.calls[i].med_tp, 0, &addr,
				        &pjsua_var.stun_srv.ipv4, NULL);
	if (status != PJ_SUCCESS) {
	    pjsua_perror(THIS_FILE, "Error starting ICE transport",
		         status);
	    goto on_error;
	}

	pjmedia_ice_get_comp(pjsua_var.calls[i].med_tp, 1, &comp);
	next_port = pj_ntohs(comp.local_addr.ipv4.sin_port);
	next_port += 2;
	addr.sin_port = pj_htons((pj_uint16_t)next_port);
    }

    /* Wait until all ICE transports are ready */
    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {

	/* Wait until interface status is PJ_SUCCESS */
	for (;;) {
	    status = pjmedia_ice_get_init_status(pjsua_var.calls[i].med_tp);
	    if (status == PJ_EPENDING)
		pjsua_handle_events(100);
	    else
		break;
	}

	if (status != PJ_SUCCESS) {
	    pjsua_perror(THIS_FILE, 
			 "Error adding STUN address to ICE media transport",
		         status);
	    goto on_error;
	}

    }

    return PJ_SUCCESS;

on_error:
    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
	if (pjsua_var.calls[i].med_tp != NULL) {
	    pjmedia_transport_close(pjsua_var.calls[i].med_tp);
	    pjsua_var.calls[i].med_tp = NULL;
	}
    }

    return status;
}


/*
 * Create UDP media transports for all the calls. This function creates
 * one UDP media transport for each call.
 */
PJ_DEF(pj_status_t) 
pjsua_media_transports_create(const pjsua_transport_config *app_cfg)
{
    pjsua_transport_config cfg;
    unsigned i;
    pj_status_t status;


    /* Make sure pjsua_init() has been called */
    PJ_ASSERT_RETURN(pjsua_var.ua_cfg.max_calls>0, PJ_EINVALIDOP);

    PJSUA_LOCK();

    /* Delete existing media transports */
    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
	if (pjsua_var.calls[i].med_tp != NULL) {
	    pjmedia_transport_close(pjsua_var.calls[i].med_tp);
	    pjsua_var.calls[i].med_tp = NULL;
	}
    }

    /* Copy config */
    pjsua_transport_config_dup(pjsua_var.pool, &cfg, app_cfg);

    if (pjsua_var.media_cfg.enable_ice) {
	status = create_ice_media_transports(&cfg);
    } else {
	status = create_udp_media_transports(&cfg);
    }


    PJSUA_UNLOCK();

    return status;
}


pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
				     pjsip_role_e role)
{
    pjsua_call *call = &pjsua_var.calls[call_id];

    if (pjsua_var.media_cfg.enable_ice) {
	pj_ice_sess_role ice_role;
	pj_status_t status;

	ice_role = (role==PJSIP_ROLE_UAC ? PJ_ICE_SESS_ROLE_CONTROLLING : 
				           PJ_ICE_SESS_ROLE_CONTROLLED);

	/* Restart ICE */
	pjmedia_ice_stop_ice(call->med_tp);

	status = pjmedia_ice_init_ice(call->med_tp, ice_role, NULL, NULL);
	if (status != PJ_SUCCESS)
	    return status;
    }

    return PJ_SUCCESS;
}

pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id, 
					   pj_pool_t *pool,
					   pjmedia_sdp_session **p_sdp)
{
    pjmedia_sdp_session *sdp;
    pjmedia_sock_info skinfo;
    pjsua_call *call = &pjsua_var.calls[call_id];
    pj_status_t status;

    /* Return error if media transport has not been created yet
     * (e.g. application is starting)
     */
    if (call->med_tp == NULL) {
	return PJ_EBUSY;
    }

    /* Get media socket info */
    pjmedia_transport_get_info(call->med_tp, &skinfo);

    /* Create SDP */
    status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, pool, 1,
				      &skinfo, &sdp);
    if (status != PJ_SUCCESS)
	goto on_error;

    if (pjsua_var.media_cfg.enable_ice) {
	status = pjmedia_ice_modify_sdp(call->med_tp, pool, sdp);
	if (status != PJ_SUCCESS)
	    goto on_error;
    }

    *p_sdp = sdp;
    return PJ_SUCCESS;

on_error:
    pjsua_media_channel_deinit(call_id);
    return status;

}


static void stop_media_session(pjsua_call_id call_id)
{
    pjsua_call *call = &pjsua_var.calls[call_id];

    if (call->conf_slot != PJSUA_INVALID_ID) {
	pjmedia_conf_remove_port(pjsua_var.mconf, call->conf_slot);
	call->conf_slot = PJSUA_INVALID_ID;
    }

    if (call->session) {
	pjmedia_session_destroy(call->session);
	call->session = NULL;

	PJ_LOG(4,(THIS_FILE, "Media session for call %d is destroyed", 
			     call_id));

    }

    call->media_st = PJSUA_CALL_MEDIA_NONE;
}

pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id)
{
    pjsua_call *call = &pjsua_var.calls[call_id];

    stop_media_session(call_id);

    if (pjsua_var.media_cfg.enable_ice) {
	pjmedia_ice_stop_ice(call->med_tp);
    }

    return PJ_SUCCESS;
}


/*
 * DTMF callback from the stream.
 */
static void dtmf_callback(pjmedia_stream *strm, void *user_data,
			  int digit)
{
    PJ_UNUSED_ARG(strm);

    if (pjsua_var.ua_cfg.cb.on_dtmf_digit) {
	pjsua_call_id call_id;

	call_id = (pjsua_call_id)user_data;
	pjsua_var.ua_cfg.cb.on_dtmf_digit(call_id, digit);
    }
}


pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
				       const pjmedia_sdp_session *local_sdp,
				       const pjmedia_sdp_session *remote_sdp)
{
    int prev_media_st = 0;
    pjsua_call *call = &pjsua_var.calls[call_id];
    pjmedia_session_info sess_info;
    pjmedia_port *media_port;
    pj_str_t port_name;
    char tmp[PJSIP_MAX_URL_SIZE];
    pj_status_t status;

    /* Destroy existing media session, if any. */
    prev_media_st = call->media_st;
    stop_media_session(call->index);

    /* Create media session info based on SDP parameters. 
     * We only support one stream per session at the moment
     */    
    status = pjmedia_session_info_from_sdp( call->inv->dlg->pool, 
					    pjsua_var.med_endpt, 
					    1,&sess_info, 
					    local_sdp, remote_sdp);
    if (status != PJ_SUCCESS)
	return status;


    /* Check if media is put on-hold */
    if (sess_info.stream_cnt == 0 || 
	sess_info.stream_info[0].dir == PJMEDIA_DIR_NONE)
    {

	/* Determine who puts the call on-hold */
	if (prev_media_st == PJSUA_CALL_MEDIA_ACTIVE) {
	    if (pjmedia_sdp_neg_was_answer_remote(call->inv->neg)) {
		/* It was local who offer hold */
		call->media_st = PJSUA_CALL_MEDIA_LOCAL_HOLD;
	    } else {
		call->media_st = PJSUA_CALL_MEDIA_REMOTE_HOLD;
	    }
	}

	call->media_dir = PJMEDIA_DIR_NONE;

	/* Shutdown ICE session */
	if (pjsua_var.media_cfg.enable_ice) {
	    pjmedia_ice_stop_ice(call->med_tp);
	}

	/* No need because we need keepalive? */

    } else {

	/* Start ICE */
	if (pjsua_var.media_cfg.enable_ice) {
	    status = pjmedia_ice_start_ice(call->med_tp, call->inv->pool, 
					   remote_sdp, 0);
	    if (status != PJ_SUCCESS)
		return status;
	}

	/* Override ptime, if this option is specified. */
	if (pjsua_var.media_cfg.ptime != 0) {
	    sess_info.stream_info[0].param->setting.frm_per_pkt = (pj_uint8_t)
		(pjsua_var.media_cfg.ptime / sess_info.stream_info[0].param->info.frm_ptime);
	    if (sess_info.stream_info[0].param->setting.frm_per_pkt == 0)
		sess_info.stream_info[0].param->setting.frm_per_pkt = 1;
	}

	/* Disable VAD, if this option is specified. */
	if (pjsua_var.media_cfg.no_vad) {
	    sess_info.stream_info[0].param->setting.vad = 0;
	}


	/* Optionally, application may modify other stream settings here
	 * (such as jitter buffer parameters, codec ptime, etc.)
	 */
	sess_info.stream_info[0].jb_init = pjsua_var.media_cfg.jb_init;
	sess_info.stream_info[0].jb_min_pre = pjsua_var.media_cfg.jb_min_pre;
	sess_info.stream_info[0].jb_max_pre = pjsua_var.media_cfg.jb_max_pre;
	sess_info.stream_info[0].jb_max = pjsua_var.media_cfg.jb_max;

	/* Create session based on session info. */
	status = pjmedia_session_create( pjsua_var.med_endpt, &sess_info,
					 &call->med_tp,
					 call, &call->session );
	if (status != PJ_SUCCESS) {
	    return status;
	}

	/* If DTMF callback is installed by application, install our
	 * callback to the session.
	 */
	if (pjsua_var.ua_cfg.cb.on_dtmf_digit) {
	    pjmedia_session_set_dtmf_callback(call->session, 0, 
					      &dtmf_callback, 
					      (void*)(call->index));
	}

	/* Get the port interface of the first stream in the session.
	 * We need the port interface to add to the conference bridge.
	 */
	pjmedia_session_get_port(call->session, 0, &media_port);


	/*
	 * Add the call to conference bridge.
	 */
	port_name.ptr = tmp;
	port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,
					 call->inv->dlg->remote.info->uri,
					 tmp, sizeof(tmp));
	if (port_name.slen < 1) {
	    port_name = pj_str("call");
	}
	status = pjmedia_conf_add_port( pjsua_var.mconf, call->inv->pool,
					media_port, 
					&port_name,
					(unsigned*)&call->conf_slot);
	if (status != PJ_SUCCESS) {
	    return status;
	}

	/* Call's media state is active */
	call->media_st = PJSUA_CALL_MEDIA_ACTIVE;
	call->media_dir = sess_info.stream_info[0].dir;
    }

    /* Print info. */
    {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -