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\r\n"
                "a=rtcp-unicast: reflection\r\n";
        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-\r\n");
        } else if (dur > 0.0) {
            char buf[100];
            sprintf(buf, "a=range:npt=0-%.3f\r\n", dur);
            rangeLine = strDup(buf);
        } else { // subsessions have differing durations, so "a=range:" lines go there
            rangeLine = strDup("");
        }

        //根会话级别的sdp固定格式
        char const* const sdpPrefixFmt =
                "v=0\r\n"
                "o=- %ld%06ld %d IN IP4 %s\r\n"
                "s=%s\r\n"
                "i=%s\r\n"
                "t=0 0\r\n"
                "a=tool:%s%s\r\n"
                "a=type:broadcast\r\n"
                "a=control:*\r\n"
                "%s"
                "%s"
                "a=x-qt-text-nam:%s\r\n"
                "a=x-qt-text-inf:%s\r\n"
                "%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;
}

 

完。

posted @ 2016-10-13 14:33  liyou  阅读(572)  评论(0编辑  收藏  举报