• ServerMediaSession::generateSDPDescription分析


    //顾名思义,就是用来生成sdp描述信息的。
    char* ServerMediaSession::generateSDPDescription() {
        //获取本地IP地址
        AddressString ipAddressStr(ourIPAddress(envir()));
        unsigned ipAddressStrSize = strlen(ipAddressStr.val());
    
        //不会执行到ssm里面,还不知道SSM是什么
        // For a SSM sessions, we need a "a=source-filter: incl ..." line also:
        char* sourceFilterLine;
        if (fIsSSM) {
            char const* const sourceFilterFmt =
                    "a=source-filter: incl IN IP4 * %s
    "
                    "a=rtcp-unicast: reflection
    ";
            unsigned const sourceFilterFmtSize = strlen(sourceFilterFmt) + ipAddressStrSize + 1;
    
            sourceFilterLine = new char[sourceFilterFmtSize];
            sprintf(sourceFilterLine, sourceFilterFmt, ipAddressStr.val());
        } else {
            sourceFilterLine = strDup("");
        }
    
        char* rangeLine = NULL; // for now
        char* sdp = NULL; // for now
    
        /*
         * 有2种级别的sdp信息,一个叫子媒体级别的sdp,一个叫会话级别的sdp。
         * 先计算保存sdp可能需要的内存空间大小,然后再格式化生成sdp字符串放入内存中保存起来。
         */
        do {
            // Count the lengths of each subsession's media-level SDP lines.
            // (We do this first, because the call to "subsession->sdpLines()"
            // causes correct subsession 'duration()'s to be calculated later.)
            unsigned sdpLength = 0;
            ServerMediaSubsession* subsession;
            for (subsession = fSubsessionsHead; subsession != NULL;
                 subsession = subsession->fNext) {
                //遍历子媒体会话,获取各个子会话的sdp描述信息长度。
                char const* sdpLines = subsession->sdpLines();
                if (sdpLines == NULL) continue; // the media's not available
                sdpLength += strlen(sdpLines);
            }
            if (sdpLength == 0) break; // the session has no usable subsessions
    
            //获取媒体时长的sdp描述
            // Unless subsessions have differing durations, we also have a "a=range:" line:
            float dur = duration();
            if (dur == 0.0) {
                rangeLine = strDup("a=range:npt=0-
    ");
            } else if (dur > 0.0) {
                char buf[100];
                sprintf(buf, "a=range:npt=0-%.3f
    ", dur);
                rangeLine = strDup(buf);
            } else { // subsessions have differing durations, so "a=range:" lines go there
                rangeLine = strDup("");
            }
    
            //根会话级别的sdp固定格式
            char const* const sdpPrefixFmt =
                    "v=0
    "
                    "o=- %ld%06ld %d IN IP4 %s
    "
                    "s=%s
    "
                    "i=%s
    "
                    "t=0 0
    "
                    "a=tool:%s%s
    "
                    "a=type:broadcast
    "
                    "a=control:*
    "
                    "%s"
                    "%s"
                    "a=x-qt-text-nam:%s
    "
                    "a=x-qt-text-inf:%s
    "
                    "%s";
                    
            //计算需要多大的内存空间来存储生成的完整sdp信息。
            sdpLength += strlen(sdpPrefixFmt)
                    + 20 + 6 + 20 + ipAddressStrSize
                    + strlen(fDescriptionSDPString)
                    + strlen(fInfoSDPString)
                    + strlen(libNameStr) + strlen(libVersionStr)
                    + strlen(sourceFilterLine)
                    + strlen(rangeLine)
                    + strlen(fDescriptionSDPString)
                    + strlen(fInfoSDPString)
                    + strlen(fMiscSDPLines);
            //适度地增加一点内存空间,防止后面子会话级别sdp和上面计算的长度不同。
            sdpLength += 1000; // in case the length of the "subsession->sdpLines()" calls below change
            //申请一段内存空间,用来存放后面生成的整个sdp字符串。
            sdp = new char[sdpLength];
            if (sdp == NULL) break;
    
            /*
             * 完整的sdp的组成格式是:一个根会话sdp + 多个子媒体sdp。
             * 
             */
             
            //格式化生成根媒体会话sdp
            // Generate the SDP prefix (session-level lines):
            snprintf(sdp, sdpLength, sdpPrefixFmt,
                     fCreationTime.tv_sec, fCreationTime.tv_usec, // o= <session id>
                     1, // o= <version> // (needs to change if params are modified)
                     ipAddressStr.val(), // o= <address>
                     fDescriptionSDPString, // s= <description>
                     fInfoSDPString, // i= <info>
                     libNameStr, libVersionStr, // a=tool:
                     sourceFilterLine, // a=source-filter: incl (if a SSM session)
                     rangeLine, // a=range: line
                     fDescriptionSDPString, // a=x-qt-text-nam: line
                     fInfoSDPString, // a=x-qt-text-inf: line
                     fMiscSDPLines); // miscellaneous session SDP lines (if any)
    
            //接着,把全部的子媒体级别sdp拼接起来,放到跟会话级别sdp的后面。
            // Then, add the (media-level) lines for each subsession:
            char* mediaSDP = sdp;
            for (subsession = fSubsessionsHead; subsession != NULL;
                 subsession = subsession->fNext) {
                unsigned mediaSDPLength = strlen(mediaSDP);
                mediaSDP += mediaSDPLength;
                sdpLength -= mediaSDPLength;
                if (sdpLength <= 1) break; // the SDP has somehow become too long
    
                //获取子媒体sdp
                char const* sdpLines = subsession->sdpLines();
                if (sdpLines != NULL) snprintf(mediaSDP, sdpLength, "%s", sdpLines);
            }
        } while (0);
    
        delete[] rangeLine; delete[] sourceFilterLine;
        //返回完整sdp信息。
        return sdp;
    }

    完。

  • 相关阅读:
    django系列6--Ajax03 ajax参数
    django系列6--Ajax06 使用插件,Sweet-Alert插件
    django系列6--Ajax05 请求头ContentType, 使用Ajax上传文件
    django系列6--Ajax04 请求设置(设置csrf_token)
    django系列6--Ajax01 特点, 基本格式, 向前端发送数据
    django系列4.2--自定义标签, 自定义过滤器, inclusion_tag, 引入静态文件(css,js等)
    面向对象之封装之如何隐藏属性, 封装的底层原理
    面向对象之------多态与多态性
    在子派生的新方法中重用父类功能的两种方式
    菱形继承
  • 原文地址:https://www.cnblogs.com/liyou-blog/p/5956404.html
Copyright © 2020-2023  润新知