void OnDemandServerMediaSubsession ::setSDPLinesFromRTPSink(RTPSink* rtpSink, FramedSource* inputSource, unsigned estBitrate) { if (rtpSink == NULL) return; liveLogInfo(" OnDemandServerMediaSubsession::setSDPLinesFromRTPSink \n"); char const* mediaType = rtpSink->sdpMediaType(); unsigned char rtpPayloadType = rtpSink->rtpPayloadType(); AddressString ipAddressStr(fServerAddressForSDP); char* rtpmapLine = rtpSink->rtpmapLine(); char const* rtcpmuxLine = fMultiplexRTCPWithRTP ? "a=rtcp-mux\r\n" : ""; char const* rangeLine = rangeSDPLine(); char const* auxSDPLine = getAuxSDPLine(rtpSink, inputSource); if (auxSDPLine == NULL) auxSDPLine = ""; char const* const sdpFmt = "m=%s %u RTP/AVP %d\r\n" "c=IN IP4 %s\r\n" "b=AS:%u\r\n" "%s" "%s" "%s" "%s" "a=control:%s\r\n"; unsigned sdpFmtSize = strlen(sdpFmt) + strlen(mediaType) + 5 /* max short len */ + 3 /* max char len */ + strlen(ipAddressStr.val()) + 20 /* max int len */ + strlen(rtpmapLine) + strlen(rtcpmuxLine) + strlen(rangeLine) + strlen(auxSDPLine) + strlen(trackId()); char* sdpLines = new char[sdpFmtSize]; sprintf(sdpLines, sdpFmt, mediaType, // m= <media> fPortNumForSDP, // m= <port> rtpPayloadType, // m= <fmt list> ipAddressStr.val(), // c= address estBitrate, // b=AS:<bandwidth> rtpmapLine, // a=rtpmap:... (if present) rtcpmuxLine, // a=rtcp-mux:... (if present) rangeLine, // a=range:... (if present) auxSDPLine, // optional extra SDP line trackId()); // a=control:<track-id> delete[] (char*)rangeLine; delete[] rtpmapLine; fSDPLines = strDup(sdpLines); delete[] sdpLines; }
char const* H264MediaSubsession::sdpLines() { if (fSDPLines == NULL) { AddressString ipAddressStr(fServerAddressForSDP); const char* rtpmapLine = "a=rtpmap:96 H264/90000\r\n"; char const* rangeLine = rangeSDPLine(); char const* const sdpFmt = "m=%s %u RTP/AVP %d\r\n" "c=IN IP4 %s\r\n" "b=AS:%u\r\n" "%s" "%s" "%s" "a=control:%s\r\n"; unsigned sdpFmtSize = strlen(sdpFmt) + strlen(mediaType) + 5 /* max short len */ + 3 /* max char len */ + strlen(ipAddressStr.val()) + 20 /* max int len */ + strlen(rtpmapLine) + strlen(rangeLine) + strlen(auxSDPLine()) + strlen(trackId()); char* sdpLines = new char[sdpFmtSize]; sprintf(sdpLines, sdpFmt, mediaType, // m= <media> fPortNumForSDP, // m= <port> rtpPayloadType, // m= <fmt list> ipAddressStr.val(), // c= address m_Watcher->GetVideoBitrate(), // b=AS:<bandwidth> rtpmapLine, // a=rtpmap:... (if present) rangeLine, // a=range:... (if present) auxSDPLine(), // optional extra SDP line trackId()); // a=control:<track-id> delete[] (char*)rangeLine; fSDPLines = strDup(sdpLines); delete[] sdpLines; } return fSDPLines; }
void BasicRTSPOnlySubsession ::setSDPLines() { //TODO: should be more dynamic unsigned estBitrate = 5000; char const* mediaType = "video"; uint8_t rtpPayloadType = 96; AddressString ipAddressStr(fServerAddressForSDP); char* rtpmapLine = strdup("a=rtpmap:96 H264/90000\n"); char const* auxSDPLine = ""; char const* const sdpFmt = "m=%s %u RTP/AVP %u\r\n" "c=IN IP4 %s\r\n" "b=AS:%u\r\n" "%s" "a=control:%s\r\n"; unsigned sdpFmtSize = strlen(sdpFmt) + strlen(mediaType) + 5 /* max short len */ + 3 /* max char len */ + strlen(ipAddressStr.val()) + 20 /* max int len */ + strlen(rtpmapLine) + strlen(trackId()); char* sdpLines = new char[sdpFmtSize]; sprintf(sdpLines, sdpFmt, mediaType, // m= <media> fPortNumForSDP, // m= <port> rtpPayloadType, // m= <fmt list> ipAddressStr.val(), // c= address estBitrate, // b=AS:<bandwidth> rtpmapLine, // a=rtpmap:... (if present) trackId()); // a=control:<track-id> fSDPLines = sdpLines; }
char* ServerMediaSession::generateSDPDescription() { AddressString ipAddressStr(ourIPAddress(envir())); unsigned ipAddressStrSize = strlen(ipAddressStr.val()); // 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 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) { 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 // 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(""); } 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"; 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 = new char[sdpLength]; if (sdp == NULL) break; // Generate the SDP prefix (session-level lines): sprintf(sdp, 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) // Then, add the (media-level) lines for each subsession: char* mediaSDP = sdp; for (subsession = fSubsessionsHead; subsession != NULL; subsession = subsession->fNext) { mediaSDP += strlen(mediaSDP); char const* sdpLines = subsession->sdpLines(); if (sdpLines != NULL) sprintf(mediaSDP, "%s", sdpLines); } } while (0); delete[] rangeLine; delete[] sourceFilterLine; return sdp; }