Загрузка данных
pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id, pj_pool_t *pool, const pjmedia_sdp_session *rem_sdp,pjmedia_sdp_session **p_sdp, int *sip_err_code)
{
enum { MAX_MEDIA = PJSUA_MAX_CALL_MEDIA };
pjmedia_sdp_session *sdp;
pj_sockaddr origin;
pjsua_call *call = &pjsua_var.calls[call_id];
pjsua_acc *acc = &pjsua_var.acc[call->acc_id];
pjmedia_sdp_neg_state sdp_neg_state = PJMEDIA_SDP_NEG_STATE_NULL;
unsigned mi;
unsigned tot_bandw_tias = 0;
pj_status_t status;
if (pjsua_get_state() != PJSUA_STATE_RUNNING) {
status = PJ_EBUSY;
goto on_error;
}
#if 0
// This function should not really change the media channel.
if (rem_sdp) {
/* If this is a re-offer, let's re-initialize media as remote may
* add or remove media
*/
if (call->inv && call->inv->state == PJSIP_INV_STATE_CONFIRMED) {
status = pjsua_media_channel_init(call_id, PJSIP_ROLE_UAS,
call->secure_level, pool,
rem_sdp, sip_err_code,
PJ_FALSE, NULL);
if (status != PJ_SUCCESS)
return status;
}
} else {
/* Audio is first in our offer, by convention */
// The audio_idx should not be changed here, as this function may be
// called in generating re-offer and the current active audio index
// can be anywhere.
//call->audio_idx = 0;
}
#endif
#if 0
// Since r3512, old-style hold should have got transport, created by
// pjsua_media_channel_init() in initial offer/answer or remote reoffer.
/* Create media if it's not created. This could happen when call is
* currently on-hold (with the old style hold)
*/
if (call->media[call->audio_idx].tp == NULL) {
pjsip_role_e role;
role = (rem_sdp ? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC);
status = pjsua_media_channel_init(call_id, role, call->secure_level,
pool, rem_sdp, sip_err_code);
if (status != PJ_SUCCESS)
return status;
}
#endif
/* Get SDP negotiator state */
if (call->inv && call->inv->neg)
sdp_neg_state = pjmedia_sdp_neg_get_state(call->inv->neg);
PJ_UNUSED_ARG(sdp_neg_state);
/* Get one address to use in the origin field */
pj_bzero(&origin, sizeof(origin));
for (mi=0; mi<call->med_prov_cnt; ++mi) {
pjmedia_transport_info tpinfo;
if (call->media_prov[mi].tp == NULL)
continue;
pjmedia_transport_info_init(&tpinfo);
pjmedia_transport_get_info(call->media_prov[mi].tp, &tpinfo);
pj_sockaddr_cp(&origin, &tpinfo.sock_info.rtp_addr_name);
break;
}
/* Create the base (blank) SDP */
status = pjmedia_endpt_create_base_sdp(pjsua_var.med_endpt, pool, NULL,
&origin, &sdp);
if (status != PJ_SUCCESS)
goto on_error;
/* Process each media line */
for (mi=0; mi<call->med_prov_cnt; ++mi) {
pjsua_call_media *call_med = &call->media_prov[mi];
pjmedia_sdp_media *m = NULL;
pjmedia_transport_info tpinfo;
pjmedia_endpt_create_sdp_param param;
unsigned i;
if (rem_sdp && mi >= rem_sdp->media_count) {
/* Remote might have removed some media lines. */
/* Note that we must not modify the current active media
* (e.g: stop stream, close/cleanup media transport), as if
* SDP nego fails, the current active media should be maintained.
* Also note that our media count should never decrease, even when
* remote removed some media lines.
*/
break;
}
if (call_med->tp == NULL || call_med->tp_st == PJSUA_MED_TP_DISABLED)
{
/*
* This media is disabled. Just create a valid SDP with zero
* port.
*/
if (rem_sdp) {
/* Just clone the remote media and deactivate it */
m = pjmedia_sdp_media_clone_deactivate(pool,
rem_sdp->media[mi]);
} else {
m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
m->desc.transport = pj_str("RTP/AVP");
m->desc.fmt_count = 1;
switch (call_med->type) {
case PJMEDIA_TYPE_AUDIO:
m->desc.media = pj_str("audio");
m->desc.fmt[0] = pj_str("0");
break;
case PJMEDIA_TYPE_VIDEO:
m->desc.media = pj_str("video");
m->desc.fmt[0] = pj_str("31");
break;
case PJMEDIA_TYPE_TEXT:
m->desc.media = pj_str("text");
m->desc.fmt[0] = pj_str("0");
break;
default:
/* This must be us generating re-offer, and some unknown
* media may exist, so just clone from active local SDP
* (and it should have been deactivated already).
*/
pj_assert(call->inv && call->inv->neg &&
sdp_neg_state == PJMEDIA_SDP_NEG_STATE_DONE);
{
const pjmedia_sdp_session *s_;
pjmedia_sdp_neg_get_active_local(call->inv->neg, &s_);
if (mi < s_->media_count) {
m = pjmedia_sdp_media_clone(pool, s_->media[mi]);
m->desc.port = 0;
} else {
/* Remote may have removed some media lines in
* previous negotiations. However, since our
* media count may never decrease (as per
* the RFC), we'll just offer unknown media here.
*/
m->desc.media = pj_str("unknown");
m->desc.fmt[0] = pj_str("0");
}
}
break;
}
}
/* Add connection line, if none */
if (m->conn == NULL && sdp->conn == NULL) {
pj_bool_t use_ipv6;
pj_bool_t use_nat64;
if (rem_sdp) {
use_ipv6 = (get_media_ip_version(call_med, rem_sdp,
PJ_FALSE, PJ_FALSE) == 6);
} else {
//use_ipv6 = PJ_HAS_IPV6 &&
// (pjsua_var.acc[call->acc_id].cfg.ipv6_media_use !=
// PJSUA_IPV6_DISABLED);
use_ipv6 = (get_media_ip_version(call_med, rem_sdp,
PJ_FALSE, PJ_FALSE) == 6);
}
use_nat64 = PJ_HAS_IPV6 &&
(pjsua_var.acc[call->acc_id].cfg.nat64_opt !=
PJSUA_NAT64_DISABLED);
m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
m->conn->net_type = pj_str("IN");
if (use_ipv6 && !use_nat64) {
m->conn->addr_type = pj_str("IP6");
m->conn->addr = pj_str("::1");
} else {
m->conn->addr_type = pj_str("IP4");
m->conn->addr = pj_str("127.0.0.1");
}
}
sdp->media[sdp->media_count++] = m;
continue;
}
/* Get transport address info */
pjmedia_transport_info_init(&tpinfo);
pjmedia_transport_get_info(call_med->tp, &tpinfo);
/* Ask pjmedia endpoint to create SDP media line */
pjmedia_endpt_create_sdp_param_default(¶m);
param.dir = call_med->def_dir;
switch (call_med->type) {
case PJMEDIA_TYPE_AUDIO:
status = pjmedia_endpt_create_audio_sdp(pjsua_var.med_endpt, pool,
&tpinfo.sock_info,
¶m, &m);
break;
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
case PJMEDIA_TYPE_VIDEO:
status = pjmedia_endpt_create_video_sdp(pjsua_var.med_endpt, pool,
&tpinfo.sock_info,
¶m, &m);
break;
#endif
case PJMEDIA_TYPE_TEXT:
param.red_level = acc->cfg.txt_red_level;
status = pjmedia_endpt_create_text_sdp(pjsua_var.med_endpt, pool,
&tpinfo.sock_info,
¶m, &m);
break;
default:
pj_assert(!"Invalid call_med media type");
status = PJ_EBUG;
}
if (status != PJ_SUCCESS)
goto on_error;
/* Add generated media to SDP session */
sdp->media[sdp->media_count++] = m;
/* Disable media if it has zero format/codec */
if (m->desc.fmt_count == 0) {
m->desc.fmt[m->desc.fmt_count++] = pj_str("0");
pjmedia_sdp_media_deactivate(pool, m);
PJ_LOG(3,(THIS_FILE,
"Call %d media %d: Disabled due to no active codec",
call_id, mi));
continue;
}
/* Check if request supports PJSIP_INV_REQUIRE_SIPREC. If so Get label
* attribute in SDP offer and add label attribute to SDP answer
*/
if (call->inv && (call->inv->options & PJSIP_INV_REQUIRE_SIPREC) &&
rem_sdp)
{
pjmedia_sdp_attr *label_attr;
const pj_str_t STR_LABEL_ATTR = {"label", 5};
label_attr = pjmedia_sdp_media_find_attr(
rem_sdp->media[mi], &STR_LABEL_ATTR, NULL);
m->attr[m->attr_count++] = pjmedia_sdp_attr_create_label(pool,
&label_attr->value);
}