RSS订阅优然探索
你的位置:首页 » 未分类 » 正文

创建基于现有SDP媒体频道

选择字号: 超大 标准 发布时间:2016-2-14 10:31:48 | 作者:admin | 0个评论 | 人浏览

 

/* Create SDP based on the current media channel. Note that, this function
 * will not modify the media channel, so when receiving new offer or
 * updating media count (via call setting), media channel must be reinit'd
 * (using pjsua_media_channel_init()) first before calling this function.

创建基于现有SDP媒体频道。请注意,此功能
*不会修改媒体频道,所以在接受新的报价或
*更新媒体计数(通过调用设置),媒体必须勒会
*(用pjsua_media_channel_init())第一次调用这个函数之前。 */
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];
    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)
 return PJ_EBUSY;

#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);

    /* 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)
 return status;

    /* 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;
 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;
  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_);

   pj_assert(mi < s_->media_count);
   m = pjmedia_sdp_media_clone(pool, s_->media[mi]);
   m->desc.port = 0;
      }
      break;
  }
     }

     /* Add connection line, if none */
     if (m->conn == NULL && sdp->conn == NULL) {
  pj_bool_t use_ipv6;

  use_ipv6 = (pjsua_var.acc[call->acc_id].cfg.ipv6_media_use !=
       PJSUA_IPV6_DISABLED);

  m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
  m->conn->net_type = pj_str("IN");
  if (use_ipv6) {
      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 */
 switch (call_med->type) {
 case PJMEDIA_TYPE_AUDIO:
     status = pjmedia_endpt_create_audio_sdp(pjsua_var.med_endpt, pool,
                                                    &tpinfo.sock_info, 0, &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, 0, &m);
     break;
#endif
 default:
     pj_assert(!"Invalid call_med media type");
     return PJ_EBUG;
 }

 if (status != PJ_SUCCESS)
     return status;

 sdp->media[sdp->media_count++] = m;

 /* Give to transport */
 status = pjmedia_transport_encode_sdp(call_med->tp, pool,
           sdp, rem_sdp, mi);
 if (status != PJ_SUCCESS) {
     if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE;
     return status;
 }

#if PJSUA_SDP_SESS_HAS_CONN
 /* Copy c= line of the first media to session level,
  * if there's none.
  */
 if (sdp->conn == NULL) {
     sdp->conn = pjmedia_sdp_conn_clone(pool, m->conn);
 }
#endif

 
 /* Find media bandwidth info */
 for (i = 0; i < m->bandw_count; ++i) {
     const pj_str_t STR_BANDW_MODIFIER_TIAS = { "TIAS", 4 };
     if (!pj_stricmp(&m->bandw[i]->modifier, &STR_BANDW_MODIFIER_TIAS))
     {
  tot_bandw_tias += m->bandw[i]->value;
  break;
     }
 }
    }

    /* Add NAT info in the SDP */
    if (pjsua_var.ua_cfg.nat_type_in_sdp) {
 pjmedia_sdp_attr *a;
 pj_str_t value;
 char nat_info[80];

 value.ptr = nat_info;
 if (pjsua_var.ua_cfg.nat_type_in_sdp == 1) {
     value.slen = pj_ansi_snprintf(nat_info, sizeof(nat_info),
       "%d", pjsua_var.nat_type);
 } else {
     const char *type_name = pj_stun_get_nat_name(pjsua_var.nat_type);
     value.slen = pj_ansi_snprintf(nat_info, sizeof(nat_info),
       "%d %s",
       pjsua_var.nat_type,
       type_name);
 }

 a = pjmedia_sdp_attr_create(pool, "X-nat", &value);

 pjmedia_sdp_attr_add(&sdp->attr_count, sdp->attr, a);

    }


    /* Add bandwidth info in session level using bandwidth modifier "AS". */
    if (tot_bandw_tias) {
 unsigned bandw;
 const pj_str_t STR_BANDW_MODIFIER_AS = { "AS", 2 };
 pjmedia_sdp_bandw *b;

 /* AS bandwidth = RTP bitrate + RTCP bitrate.
  * RTP bitrate  = payload bitrate (total TIAS) + overheads (~16kbps).
  * RTCP bitrate = est. 5% of RTP bitrate.
  * Note that AS bandwidth is in kbps.
  */
 bandw = tot_bandw_tias + 16000;
 bandw += bandw * 5 / 100;
 b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
 b->modifier = STR_BANDW_MODIFIER_AS;
 b->value = bandw / 1000;
 sdp->bandw[sdp->bandw_count++] = b;
    }


#if DISABLED_FOR_TICKET_1185 && defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
    /* Check if SRTP is in optional mode and configured to use duplicated
     * media, i.e: secured and unsecured version, in the SDP offer.
     */
    if (!rem_sdp &&
 pjsua_var.acc[call->acc_id].cfg.use_srtp == PJMEDIA_SRTP_OPTIONAL &&
 pjsua_var.acc[call->acc_id].cfg.srtp_optional_dup_offer)
    {
 unsigned i;

 for (i = 0; i < sdp->media_count; ++i) {
     pjmedia_sdp_media *m = sdp->media[i];

     /* Check if this media is unsecured but has SDP "crypto"
      * attribute.
      */
     if (pj_stricmp2(&m->desc.transport, "RTP/AVP") == 0 &&
  pjmedia_sdp_media_find_attr2(m, "crypto", NULL) != NULL)
     {
  if (i == (unsigned)call->audio_idx &&
      sdp_neg_state == PJMEDIA_SDP_NEG_STATE_DONE)
  {
      /* This is a session update, and peer has chosen the
       * unsecured version, so let's make this unsecured too.
       */
      pjmedia_sdp_media_remove_all_attr(m, "crypto");
  } else {
      /* This is new offer, duplicate media so we'll have
       * secured (with "RTP/SAVP" transport) and and unsecured
       * versions.
       */
      pjmedia_sdp_media *new_m;

      /* Duplicate this media and apply secured transport */
      new_m = pjmedia_sdp_media_clone(pool, m);
      pj_strdup2(pool, &new_m->desc.transport, "RTP/SAVP");

      /* Remove the "crypto" attribute in the unsecured media */
      pjmedia_sdp_media_remove_all_attr(m, "crypto");

      /* Insert the new media before the unsecured media */
      if (sdp->media_count < PJMEDIA_MAX_SDP_MEDIA) {
   pj_array_insert(sdp->media, sizeof(new_m),
     sdp->media_count, i, &new_m);
   ++sdp->media_count;
   ++i;
      }
  }
     }
 }
    }
#endif

    call->rem_offerer = (rem_sdp != NULL);

    /* Notify application */
    if (pjsua_var.ua_cfg.cb.on_call_sdp_created) {
 (*pjsua_var.ua_cfg.cb.on_call_sdp_created)(call_id, sdp,
         pool, rem_sdp);
    }

    *p_sdp = sdp;
    return PJ_SUCCESS;
}

标签:

猜你喜欢

发表评论

必填

选填

选填

必填,不填不让过哦,嘻嘻。

记住我,下次回复时不用重新输入个人信息

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。