Загрузка данных


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(&param);
        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,
                                                    &param, &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,
                                                    &param, &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,
                                                    &param, &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);
        }