//顾名思义,就是用来生成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; }
完。