📄 mediasession.cpp
字号:
// Look up the codec name and timestamp frequency for known (static) // RTP payload formats. char const* temp = NULL; switch (rtpPayloadType) { case 0: {temp = "PCMU"; freq = 8000; nCh = 1; break;} case 2: {temp = "G726-32"; freq = 8000; nCh = 1; break;} case 3: {temp = "GSM"; freq = 8000; nCh = 1; break;} case 4: {temp = "G723"; freq = 8000; nCh = 1; break;} case 5: {temp = "DVI4"; freq = 8000; nCh = 1; break;} case 6: {temp = "DVI4"; freq = 16000; nCh = 1; break;} case 7: {temp = "LPC"; freq = 8000; nCh = 1; break;} case 8: {temp = "PCMA"; freq = 8000; nCh = 1; break;} case 9: {temp = "G722"; freq = 8000; nCh = 1; break;} case 10: {temp = "L16"; freq = 44100; nCh = 2; break;} case 11: {temp = "L16"; freq = 44100; nCh = 1; break;} case 12: {temp = "QCELP"; freq = 8000; nCh = 1; break;} case 14: {temp = "MPA"; freq = 90000; nCh = 1; break;} // 'number of channels' is actually encoded in the media stream case 15: {temp = "G728"; freq = 8000; nCh = 1; break;} case 16: {temp = "DVI4"; freq = 11025; nCh = 1; break;} case 17: {temp = "DVI4"; freq = 22050; nCh = 1; break;} case 18: {temp = "G729"; freq = 8000; nCh = 1; break;} case 25: {temp = "CELB"; freq = 90000; nCh = 1; break;} case 26: {temp = "JPEG"; freq = 90000; nCh = 1; break;} case 28: {temp = "NV"; freq = 90000; nCh = 1; break;} case 31: {temp = "H261"; freq = 90000; nCh = 1; break;} case 32: {temp = "MPV"; freq = 90000; nCh = 1; break;} case 33: {temp = "MP2T"; freq = 90000; nCh = 1; break;} case 34: {temp = "H263"; freq = 90000; nCh = 1; break;} }; return strDup(temp);}unsigned MediaSession::guessRTPTimestampFrequency(char const* mediumName, char const* codecName) { // By default, we assume that audio sessions use a frequency of 8000, // video sessions use a frequency of 90000, // and text sessions use a frequency of 1000. // Begin by checking for known exceptions to this rule // (where the frequency is known unambiguously (e.g., not like "DVI4")) if (strcmp(codecName, "L16") == 0) return 44100; if (strcmp(codecName, "MPA") == 0 || strcmp(codecName, "MPA-ROBUST") == 0 || strcmp(codecName, "X-MP3-DRAFT-00")) return 90000; // Now, guess default values: if (strcmp(mediumName, "video") == 0) return 90000; else if (strcmp(mediumName, "text") == 0) return 1000; return 8000; // for "audio", and any other medium}Boolean MediaSession::initiateByMediaType(char const* mimeType, MediaSubsession*& resultSubsession, int useSpecialRTPoffset) { // Look through this session's subsessions for media that match "mimeType" resultSubsession = NULL; MediaSubsessionIterator iter(*this); MediaSubsession* subsession; while ((subsession = iter.next()) != NULL) { Boolean wasAlreadyInitiated = subsession->readSource() != NULL; if (!wasAlreadyInitiated) { // Try to create a source for this subsession: if (!subsession->initiate(useSpecialRTPoffset)) return False; } // Make sure the source's MIME type is one that we handle: if (strcmp(subsession->readSource()->MIMEtype(), mimeType) != 0) { if (!wasAlreadyInitiated) subsession->deInitiate(); continue; } resultSubsession = subsession; break; // use this } if (resultSubsession == NULL) { envir().setResultMsg("Session has no usable media subsession"); return False; } return True;}////////// MediaSubsessionIterator //////////MediaSubsessionIterator::MediaSubsessionIterator(MediaSession& session) : fOurSession(session) { reset();}MediaSubsessionIterator::~MediaSubsessionIterator() {}MediaSubsession* MediaSubsessionIterator::next() { MediaSubsession* result = fNextPtr; if (fNextPtr != NULL) fNextPtr = fNextPtr->fNext; return result;}void MediaSubsessionIterator::reset() { fNextPtr = fOurSession.fSubsessionsHead;}////////// MediaSubsession //////////MediaSubsession::MediaSubsession(MediaSession& parent) : sessionId(NULL), serverPortNum(0), sink(NULL), miscPtr(NULL), fParent(parent), fNext(NULL), fConnectionEndpointName(NULL), fClientPortNum(0), fRTPPayloadFormat(0xFF), fSavedSDPLines(NULL), fMediumName(NULL), fCodecName(NULL), fProtocolName(NULL), fRTPTimestampFrequency(0), fControlPath(NULL), fSourceFilterAddr(parent.sourceFilterAddr()), fBandwidth(0), fAuxiliarydatasizelength(0), fConstantduration(0), fConstantsize(0), fCRC(0), fCtsdeltalength(0), fDe_interleavebuffersize(0), fDtsdeltalength(0), fIndexdeltalength(0), fIndexlength(0), fInterleaving(0), fMaxdisplacement(0), fObjecttype(0), fOctetalign(0), fProfile_level_id(0), fRobustsorting(0), fSizelength(0), fStreamstateindication(0), fStreamtype(0), fCpresent(False), fRandomaccessindication(False), fConfig(NULL), fMode(NULL), fSpropParameterSets(NULL), fPlayStartTime(0.0), fPlayEndTime(0.0), fVideoWidth(0), fVideoHeight(0), fVideoFPS(0), fNumChannels(1), fScale(1.0f), fNPT_PTS_Offset(0.0f), fRTPSocket(NULL), fRTCPSocket(NULL), fRTPSource(NULL), fRTCPInstance(NULL), fReadSource(NULL) { rtpInfo.seqNum = 0; rtpInfo.timestamp = 0; rtpInfo.infoIsNew = False;}MediaSubsession::~MediaSubsession() { deInitiate(); delete[] fConnectionEndpointName; delete[] fSavedSDPLines; delete[] fMediumName; delete[] fCodecName; delete[] fProtocolName; delete[] fControlPath; delete[] fConfig; delete[] fMode; delete[] fSpropParameterSets; delete fNext;}double MediaSubsession::playStartTime() const { if (fPlayStartTime > 0) return fPlayStartTime; return fParent.playStartTime();}double MediaSubsession::playEndTime() const { if (fPlayEndTime > 0) return fPlayEndTime; return fParent.playEndTime();}Boolean MediaSubsession::initiate(int useSpecialRTPoffset) { if (fReadSource != NULL) return True; // has already been initiated do { if (fCodecName == NULL) { env().setResultMsg("Codec is unspecified"); break; } // Create RTP and RTCP 'Groupsocks' on which to receive incoming data. // (Groupsocks will work even for unicast addresses) struct in_addr tempAddr; tempAddr.s_addr = connectionEndpointAddress(); // This could get changed later, as a result of a RTSP "SETUP" if (fClientPortNum != 0) { // The sockets' port numbers were specified for us. Use these: fClientPortNum = fClientPortNum&~1; // even if (isSSM()) { fRTPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, fClientPortNum); } else { fRTPSocket = new Groupsock(env(), tempAddr, fClientPortNum, 255); } if (fRTPSocket == NULL) { env().setResultMsg("Failed to create RTP socket"); break; } // Set our RTCP port to be the RTP port +1 portNumBits const rtcpPortNum = fClientPortNum|1; if (isSSM()) { fRTCPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, rtcpPortNum); } else { fRTCPSocket = new Groupsock(env(), tempAddr, rtcpPortNum, 255); } if (fRTCPSocket == NULL) { char tmpBuf[100]; sprintf(tmpBuf, "Failed to create RTCP socket (port %d)", rtcpPortNum); env().setResultMsg(tmpBuf); break; } } else { // Port numbers were not specified in advance, so we use ephemeral port numbers. // Create sockets until we get a port-number pair (even: RTP; even+1: RTCP). // We need to make sure that we don't keep trying to use the same bad port numbers over and over again. // so we store bad sockets in a table, and delete them all when we're done. HashTable* socketHashTable = HashTable::create(ONE_WORD_HASH_KEYS); if (socketHashTable == NULL) break; Boolean success = False; NoReuse dummy; // ensures that our new ephemeral port number won't be one that's already in use while (1) { // Create a new socket: if (isSSM()) { fRTPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, 0); } else { fRTPSocket = new Groupsock(env(), tempAddr, 0, 255); } if (fRTPSocket == NULL) { env().setResultMsg("MediaSession::initiate(): unable to create RTP and RTCP sockets"); break; } // Get the client port number, and check whether it's even (for RTP): Port clientPort(0); if (!getSourcePort(env(), fRTPSocket->socketNum(), clientPort)) { break; } fClientPortNum = ntohs(clientPort.num()); if ((fClientPortNum&1) != 0) { // it's odd // Record this socket in our table, and keep trying: unsigned key = (unsigned)fClientPortNum; Groupsock* existing = (Groupsock*)socketHashTable->Add((char const*)key, fRTPSocket); delete existing; // in case it wasn't NULL continue; } // Make sure we can use the next (i.e., odd) port number, for RTCP: portNumBits rtcpPortNum = fClientPortNum|1; if (isSSM()) { fRTCPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, rtcpPortNum); } else { fRTCPSocket = new Groupsock(env(), tempAddr, rtcpPortNum, 255); } if (fRTCPSocket != NULL) { // Success! Use these two sockets. success = True; break; } else { // We couldn't create the RTCP socket (perhaps that port number's already in use elsewhere?). // Record the first socket in our table, and keep trying: unsigned key = (unsigned)fClientPortNum; Groupsock* existing = (Groupsock*)socketHashTable->Add((char const*)key, fRTPSocket); delete existing; // in case it wasn't NULL continue; } } // Clean up the socket hash table (and contents): Groupsock* oldGS; while ((oldGS = (Groupsock*)socketHashTable->RemoveNext()) != NULL) { delete oldGS; } delete socketHashTable; if (!success) break; // a fatal error occurred trying to create the RTP and RTCP sockets; we can't continue } // Try to use a big receive buffer for RTP - at least 0.1 second of // specified bandwidth and at least 50 KB unsigned rtpBufSize = fBandwidth * 25 / 2; // 1 kbps * 0.1 s = 12.5 bytes if (rtpBufSize < 50 * 1024) rtpBufSize = 50 * 1024; increaseReceiveBufferTo(env(), fRTPSocket->socketNum(), rtpBufSize); // ASSERT: fRTPSocket != NULL && fRTCPSocket != NULL if (isSSM()) { // Special case for RTCP SSM: Send RTCP packets back to the source via unicast: fRTCPSocket->changeDestinationParameters(fSourceFilterAddr,0,~0); } // Check "fProtocolName" if (strcmp(fProtocolName, "UDP") == 0) { // A UDP-packetized stream (*not* a RTP stream) fReadSource = BasicUDPSource::createNew(env(), fRTPSocket); fRTPSource = NULL; // Note! if (strcmp(fCodecName, "MP2T") == 0) { // MPEG-2 Transport Stream fReadSource = MPEG2TransportStreamFramer::createNew(env(), fReadSource); // this sets "durationInMicroseconds" correctly, based on the PCR values } } else { // Check "fCodecName" against the set of codecs that we support, // and create our RTP source accordingly // (Later make this code more efficient, as this set grows #####) // (Also, add more fmts that can be implemented by SimpleRTPSource#####) Boolean createSimpleRTPSource = False; // by default; can be changed below Boolean doNormalMBitRule = False; // default behavior if "createSimpleRTPSource" is True if (strcmp(fCodecName, "QCELP") == 0) { // QCELP audio fReadSource = QCELPAudioRTPSource::createNew(env(), fRTPSocket, fRTPSource, fRTPPayloadFormat, fRTPTimestampFrequency); // Note that fReadSource will differ from fRTPSource in this case } else if (strcmp(fCodecName, "AMR") == 0) { // AMR audio (narrowband) fReadSource = AMRAudioRTPSource::createNew(env(), fRTPSocket, fRTPSource, fRTPPayloadFormat, 0 /*isWideband*/, fNumChannels, fOctetalign, fInterleaving, fRobustsorting, fCRC); // Note that fReadSource will differ from fRTPSource in this case } else if (strcmp(fCodecName, "AMR-WB") == 0) { // AMR audio (wideband) fReadSource = AMRAudioRTPSource::createNew(env(), fRTPSocket, fRTPSource, fRTPPayloadFormat, 1 /*isWideband*/, fNumChannels, fOctetalign, fInterleaving, fRobustsorting, fCRC); // Note that fReadSource will differ from fRTPSource in this case } else if (strcmp(fCodecName, "MPA") == 0) { // MPEG-1 or 2 audio fReadSource = fRTPSource = MPEG1or2AudioRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, fRTPTimestampFrequency); } else if (strcmp(fCodecName, "MPA-ROBUST") == 0) { // robust MP3 audio fRTPSource = MP3ADURTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, fRTPTimestampFrequency); if (fRTPSource == NULL) break; // Add a filter that deinterleaves the ADUs after depacketizing them: MP3ADUdeinterleaver* deinterleaver = MP3ADUdeinterleaver::createNew(env(), fRTPSource); if (deinterleaver == NULL) break; // Add another filter that converts these ADUs to MP3 frames: fReadSource = MP3FromADUSource::createNew(env(), deinterleaver); } else if (strcmp(fCodecName, "X-MP3-DRAFT-00") == 0) { // a non-standard variant of "MPA-ROBUST" used by RealNetworks // (one 'ADU'ized MP3 frame per packet; no headers) fRTPSource = SimpleRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, fRTPTimestampFrequency, "audio/MPA-ROBUST" /*hack*/); if (fRTPSource == NULL) break; // Add a filter that converts these ADUs to MP3 frames: fReadSource = MP3FromADUSource::createNew(env(), fRTPSource, False /*no ADU header*/); } else if (strcmp(fCodecName, "MP4A-LATM") == 0) { // MPEG-4 LATM audio fReadSource = fRTPSource = MPEG4LATMAudioRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, fRTPTimestampFrequency); } else if (strcmp(fCodecName, "AC3") == 0) { // AC3 audio fReadSource = fRTPSource = AC3AudioRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, fRTPTimestampFrequency); } else if (strcmp(fCodecName, "MP4V-ES") == 0) { // MPEG-4 Elem Str vid fReadSource = fRTPSource = MPEG4ESVideoRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, fRTPTimestampFrequency); } else if (strcmp(fCodecName, "MPEG4-GENERIC") == 0) { fReadSource = fRTPSource = MPEG4GenericRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, fRTPTimestampFrequency, fMediumName, fMode, fSizelength, fIndexlength, fIndexdeltalength); } else if (strcmp(fCodecName, "MPV") == 0) { // MPEG-1 or 2 video fReadSource = fRTPSource = MPEG1or2VideoRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, fRTPTimestampFrequency); } else if (strcmp(fCodecName, "MP2T") == 0) { // MPEG-2 Transport Stream fRTPSource = SimpleRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, fRTPTimestampFrequency, "video/MP2T", 0, False); fReadSource = MPEG2TransportStreamFramer::createNew(env(), fRTPSource); // this sets "durationInMicroseconds" correctly, based on the PCR values } else if (strcmp(fCodecName, "H261") == 0) { // H.261 fReadSource = fRTPSource = H261VideoRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, fRTPTimestampFrequency); } else if (strcmp(fCodecName, "H263-1998") == 0 || strcmp(fCodecName, "H263-2000") == 0) { // H.263+ fReadSource = fRTPSource = H263plusVideoRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, fRTPTimestampFrequency); } else if (strcmp(fCodecName, "H264") == 0) { fReadSource = fRTPSource = H264VideoRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, fRTPTimestampFrequency); } else if (strcmp(fCodecName, "DV") == 0) { fReadSource = fRTPSource = DVVideoRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, fRTPTimestampFrequency); } else if (strcmp(fCodecName, "JPEG") == 0) { // motion JPEG fReadSource = fRTPSource = JPEGVideoRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, fRTPTimestampFrequency, videoWidth(), videoHeight()); } else if (strcmp(fCodecName, "X-QT") == 0 || strcmp(fCodecName, "X-QUICKTIME") == 0) { // Generic QuickTime streams, as defined in // <http://developer.apple.com/quicktime/icefloe/dispatch026.html> char* mimeType = new char[strlen(mediumName()) + strlen(codecName()) + 2] ; sprintf(mimeType, "%s/%s", mediumName(), codecName()); fReadSource = fRTPSource = QuickTimeGenericRTPSource::createNew(env(), fRTPSocket,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -