liveMedia/MultiFramedRTPSink.cpp

Go to the documentation of this file.
00001 /**********
00002 This library is free software; you can redistribute it and/or modify it under
00003 the terms of the GNU Lesser General Public License as published by the
00004 Free Software Foundation; either version 2.1 of the License, or (at your
00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
00006 
00007 This library is distributed in the hope that it will be useful, but WITHOUT
00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00009 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
00010 more details.
00011 
00012 You should have received a copy of the GNU Lesser General Public License
00013 along with this library; if not, write to the Free Software Foundation, Inc.,
00014 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
00015 **********/
00016 // "liveMedia"
00017 // Copyright (c) 1996-2012 Live Networks, Inc.  All rights reserved.
00018 // RTP sink for a common kind of payload format: Those which pack multiple,
00019 // complete codec frames (as many as possible) into each RTP packet.
00020 // Implementation
00021 
00022 #include "MultiFramedRTPSink.hh"
00023 #include "GroupsockHelper.hh"
00024 
00026 
00027 void MultiFramedRTPSink::setPacketSizes(unsigned preferredPacketSize,
00028                                         unsigned maxPacketSize) {
00029   if (preferredPacketSize > maxPacketSize || preferredPacketSize == 0) return;
00030       // sanity check
00031 
00032   delete fOutBuf;
00033   fOutBuf = new OutPacketBuffer(preferredPacketSize, maxPacketSize);
00034   fOurMaxPacketSize = maxPacketSize; // save value, in case subclasses need it
00035 }
00036 
00037 MultiFramedRTPSink::MultiFramedRTPSink(UsageEnvironment& env,
00038                                        Groupsock* rtpGS,
00039                                        unsigned char rtpPayloadType,
00040                                        unsigned rtpTimestampFrequency,
00041                                        char const* rtpPayloadFormatName,
00042                                        unsigned numChannels)
00043   : RTPSink(env, rtpGS, rtpPayloadType, rtpTimestampFrequency,
00044             rtpPayloadFormatName, numChannels),
00045     fOutBuf(NULL), fCurFragmentationOffset(0), fPreviousFrameEndedFragmentation(False),
00046     fOnSendErrorFunc(NULL), fOnSendErrorData(NULL) {
00047   setPacketSizes(1000, 1448);
00048       // Default max packet size (1500, minus allowance for IP, UDP, UMTP headers)
00049       // (Also, make it a multiple of 4 bytes, just in case that matters.)
00050 }
00051 
00052 MultiFramedRTPSink::~MultiFramedRTPSink() {
00053   delete fOutBuf;
00054 }
00055 
00056 void MultiFramedRTPSink
00057 ::doSpecialFrameHandling(unsigned /*fragmentationOffset*/,
00058                          unsigned char* /*frameStart*/,
00059                          unsigned /*numBytesInFrame*/,
00060                          struct timeval framePresentationTime,
00061                          unsigned /*numRemainingBytes*/) {
00062   // default implementation: If this is the first frame in the packet,
00063   // use its presentationTime for the RTP timestamp:
00064   if (isFirstFrameInPacket()) {
00065     setTimestamp(framePresentationTime);
00066   }
00067 }
00068 
00069 Boolean MultiFramedRTPSink::allowFragmentationAfterStart() const {
00070   return False; // by default
00071 }
00072 
00073 Boolean MultiFramedRTPSink::allowOtherFramesAfterLastFragment() const {
00074   return False; // by default
00075 }
00076 
00077 Boolean MultiFramedRTPSink
00078 ::frameCanAppearAfterPacketStart(unsigned char const* /*frameStart*/,
00079                                  unsigned /*numBytesInFrame*/) const {
00080   return True; // by default
00081 }
00082 
00083 unsigned MultiFramedRTPSink::specialHeaderSize() const {
00084   // default implementation: Assume no special header:
00085   return 0;
00086 }
00087 
00088 unsigned MultiFramedRTPSink::frameSpecificHeaderSize() const {
00089   // default implementation: Assume no frame-specific header:
00090   return 0;
00091 }
00092 
00093 unsigned MultiFramedRTPSink::computeOverflowForNewFrame(unsigned newFrameSize) const {
00094   // default implementation: Just call numOverflowBytes()
00095   return fOutBuf->numOverflowBytes(newFrameSize);
00096 }
00097 
00098 void MultiFramedRTPSink::setMarkerBit() {
00099   unsigned rtpHdr = fOutBuf->extractWord(0);
00100   rtpHdr |= 0x00800000;
00101   fOutBuf->insertWord(rtpHdr, 0);
00102 }
00103 
00104 void MultiFramedRTPSink::setTimestamp(struct timeval framePresentationTime) {
00105   // First, convert the presentatoin time to a 32-bit RTP timestamp:
00106   fCurrentTimestamp = convertToRTPTimestamp(framePresentationTime);
00107 
00108   // Then, insert it into the RTP packet:
00109   fOutBuf->insertWord(fCurrentTimestamp, fTimestampPosition);
00110 }
00111 
00112 void MultiFramedRTPSink::setSpecialHeaderWord(unsigned word,
00113                                               unsigned wordPosition) {
00114   fOutBuf->insertWord(word, fSpecialHeaderPosition + 4*wordPosition);
00115 }
00116 
00117 void MultiFramedRTPSink::setSpecialHeaderBytes(unsigned char const* bytes,
00118                                                unsigned numBytes,
00119                                                unsigned bytePosition) {
00120   fOutBuf->insert(bytes, numBytes, fSpecialHeaderPosition + bytePosition);
00121 }
00122 
00123 void MultiFramedRTPSink::setFrameSpecificHeaderWord(unsigned word,
00124                                                     unsigned wordPosition) {
00125   fOutBuf->insertWord(word, fCurFrameSpecificHeaderPosition + 4*wordPosition);
00126 }
00127 
00128 void MultiFramedRTPSink::setFrameSpecificHeaderBytes(unsigned char const* bytes,
00129                                                      unsigned numBytes,
00130                                                      unsigned bytePosition) {
00131   fOutBuf->insert(bytes, numBytes, fCurFrameSpecificHeaderPosition + bytePosition);
00132 }
00133 
00134 void MultiFramedRTPSink::setFramePadding(unsigned numPaddingBytes) {
00135   if (numPaddingBytes > 0) {
00136     // Add the padding bytes (with the last one being the padding size):
00137     unsigned char paddingBuffer[255]; //max padding
00138     memset(paddingBuffer, 0, numPaddingBytes);
00139     paddingBuffer[numPaddingBytes-1] = numPaddingBytes;
00140     fOutBuf->enqueue(paddingBuffer, numPaddingBytes);
00141 
00142     // Set the RTP padding bit:
00143     unsigned rtpHdr = fOutBuf->extractWord(0);
00144     rtpHdr |= 0x20000000;
00145     fOutBuf->insertWord(rtpHdr, 0);
00146   }
00147 }
00148 
00149 Boolean MultiFramedRTPSink::continuePlaying() {
00150   // Send the first packet.
00151   // (This will also schedule any future sends.)
00152   buildAndSendPacket(True);
00153   return True;
00154 }
00155 
00156 void MultiFramedRTPSink::stopPlaying() {
00157   fOutBuf->resetPacketStart();
00158   fOutBuf->resetOffset();
00159   fOutBuf->resetOverflowData();
00160 
00161   // Then call the default "stopPlaying()" function:
00162   MediaSink::stopPlaying();
00163 }
00164 
00165 void MultiFramedRTPSink::buildAndSendPacket(Boolean isFirstPacket) {
00166   fIsFirstPacket = isFirstPacket;
00167 
00168   // Set up the RTP header:
00169   unsigned rtpHdr = 0x80000000; // RTP version 2; marker ('M') bit not set (by default; it can be set later)
00170   rtpHdr |= (fRTPPayloadType<<16);
00171   rtpHdr |= fSeqNo; // sequence number
00172   fOutBuf->enqueueWord(rtpHdr);
00173 
00174   // Note where the RTP timestamp will go.
00175   // (We can't fill this in until we start packing payload frames.)
00176   fTimestampPosition = fOutBuf->curPacketSize();
00177   fOutBuf->skipBytes(4); // leave a hole for the timestamp
00178 
00179   fOutBuf->enqueueWord(SSRC());
00180 
00181   // Allow for a special, payload-format-specific header following the
00182   // RTP header:
00183   fSpecialHeaderPosition = fOutBuf->curPacketSize();
00184   fSpecialHeaderSize = specialHeaderSize();
00185   fOutBuf->skipBytes(fSpecialHeaderSize);
00186 
00187   // Begin packing as many (complete) frames into the packet as we can:
00188   fTotalFrameSpecificHeaderSizes = 0;
00189   fNoFramesLeft = False;
00190   fNumFramesUsedSoFar = 0;
00191   packFrame();
00192 }
00193 
00194 void MultiFramedRTPSink::packFrame() {
00195   // Get the next frame.
00196 
00197   // First, see if we have an overflow frame that was too big for the last pkt
00198   if (fOutBuf->haveOverflowData()) {
00199     // Use this frame before reading a new one from the source
00200     unsigned frameSize = fOutBuf->overflowDataSize();
00201     struct timeval presentationTime = fOutBuf->overflowPresentationTime();
00202     unsigned durationInMicroseconds = fOutBuf->overflowDurationInMicroseconds();
00203     fOutBuf->useOverflowData();
00204 
00205     afterGettingFrame1(frameSize, 0, presentationTime, durationInMicroseconds);
00206   } else {
00207     // Normal case: we need to read a new frame from the source
00208     if (fSource == NULL) return;
00209 
00210     fCurFrameSpecificHeaderPosition = fOutBuf->curPacketSize();
00211     fCurFrameSpecificHeaderSize = frameSpecificHeaderSize();
00212     fOutBuf->skipBytes(fCurFrameSpecificHeaderSize);
00213     fTotalFrameSpecificHeaderSizes += fCurFrameSpecificHeaderSize;
00214 
00215     fSource->getNextFrame(fOutBuf->curPtr(), fOutBuf->totalBytesAvailable(),
00216                           afterGettingFrame, this, ourHandleClosure, this);
00217   }
00218 }
00219 
00220 void MultiFramedRTPSink
00221 ::afterGettingFrame(void* clientData, unsigned numBytesRead,
00222                     unsigned numTruncatedBytes,
00223                     struct timeval presentationTime,
00224                     unsigned durationInMicroseconds) {
00225   MultiFramedRTPSink* sink = (MultiFramedRTPSink*)clientData;
00226   sink->afterGettingFrame1(numBytesRead, numTruncatedBytes,
00227                            presentationTime, durationInMicroseconds);
00228 }
00229 
00230 void MultiFramedRTPSink
00231 ::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes,
00232                      struct timeval presentationTime,
00233                      unsigned durationInMicroseconds) {
00234   if (fIsFirstPacket) {
00235     // Record the fact that we're starting to play now:
00236     gettimeofday(&fNextSendTime, NULL);
00237   }
00238 
00239   if (numTruncatedBytes > 0) {
00240     unsigned const bufferSize = fOutBuf->totalBytesAvailable();
00241     envir() << "MultiFramedRTPSink::afterGettingFrame1(): The input frame data was too large for our buffer size ("
00242             << bufferSize << ").  "
00243             << numTruncatedBytes << " bytes of trailing data was dropped!  Correct this by increasing \"OutPacketBuffer::maxSize\" to at least "
00244             << OutPacketBuffer::maxSize + numTruncatedBytes << ", *before* creating this 'RTPSink'.  (Current value is "
00245             << OutPacketBuffer::maxSize << ".)\n";
00246   }
00247   unsigned curFragmentationOffset = fCurFragmentationOffset;
00248   unsigned numFrameBytesToUse = frameSize;
00249   unsigned overflowBytes = 0;
00250 
00251   // If we have already packed one or more frames into this packet,
00252   // check whether this new frame is eligible to be packed after them.
00253   // (This is independent of whether the packet has enough room for this
00254   // new frame; that check comes later.)
00255   if (fNumFramesUsedSoFar > 0) {
00256     if ((fPreviousFrameEndedFragmentation
00257          && !allowOtherFramesAfterLastFragment())
00258         || !frameCanAppearAfterPacketStart(fOutBuf->curPtr(), frameSize)) {
00259       // Save away this frame for next time:
00260       numFrameBytesToUse = 0;
00261       fOutBuf->setOverflowData(fOutBuf->curPacketSize(), frameSize,
00262                                presentationTime, durationInMicroseconds);
00263     }
00264   }
00265   fPreviousFrameEndedFragmentation = False;
00266 
00267   if (numFrameBytesToUse > 0) {
00268     // Check whether this frame overflows the packet
00269     if (fOutBuf->wouldOverflow(frameSize)) {
00270       // Don't use this frame now; instead, save it as overflow data, and
00271       // send it in the next packet instead.  However, if the frame is too
00272       // big to fit in a packet by itself, then we need to fragment it (and
00273       // use some of it in this packet, if the payload format permits this.)
00274       if (isTooBigForAPacket(frameSize)
00275           && (fNumFramesUsedSoFar == 0 || allowFragmentationAfterStart())) {
00276         // We need to fragment this frame, and use some of it now:
00277         overflowBytes = computeOverflowForNewFrame(frameSize);
00278         numFrameBytesToUse -= overflowBytes;
00279         fCurFragmentationOffset += numFrameBytesToUse;
00280       } else {
00281         // We don't use any of this frame now:
00282         overflowBytes = frameSize;
00283         numFrameBytesToUse = 0;
00284       }
00285       fOutBuf->setOverflowData(fOutBuf->curPacketSize() + numFrameBytesToUse,
00286                                overflowBytes, presentationTime, durationInMicroseconds);
00287     } else if (fCurFragmentationOffset > 0) {
00288       // This is the last fragment of a frame that was fragmented over
00289       // more than one packet.  Do any special handling for this case:
00290       fCurFragmentationOffset = 0;
00291       fPreviousFrameEndedFragmentation = True;
00292     }
00293   }
00294 
00295   if (numFrameBytesToUse == 0 && frameSize > 0) {
00296     // Send our packet now, because we have filled it up:
00297     sendPacketIfNecessary();
00298   } else {
00299     // Use this frame in our outgoing packet:
00300     unsigned char* frameStart = fOutBuf->curPtr();
00301     fOutBuf->increment(numFrameBytesToUse);
00302         // do this now, in case "doSpecialFrameHandling()" calls "setFramePadding()" to append padding bytes
00303 
00304     // Here's where any payload format specific processing gets done:
00305     doSpecialFrameHandling(curFragmentationOffset, frameStart,
00306                            numFrameBytesToUse, presentationTime,
00307                            overflowBytes);
00308 
00309     ++fNumFramesUsedSoFar;
00310 
00311     // Update the time at which the next packet should be sent, based
00312     // on the duration of the frame that we just packed into it.
00313     // However, if this frame has overflow data remaining, then don't
00314     // count its duration yet.
00315     if (overflowBytes == 0) {
00316       fNextSendTime.tv_usec += durationInMicroseconds;
00317       fNextSendTime.tv_sec += fNextSendTime.tv_usec/1000000;
00318       fNextSendTime.tv_usec %= 1000000;
00319     }
00320 
00321     // Send our packet now if (i) it's already at our preferred size, or
00322     // (ii) (heuristic) another frame of the same size as the one we just
00323     //      read would overflow the packet, or
00324     // (iii) it contains the last fragment of a fragmented frame, and we
00325     //      don't allow anything else to follow this or
00326     // (iv) one frame per packet is allowed:
00327     if (fOutBuf->isPreferredSize()
00328         || fOutBuf->wouldOverflow(numFrameBytesToUse)
00329         || (fPreviousFrameEndedFragmentation &&
00330             !allowOtherFramesAfterLastFragment())
00331         || !frameCanAppearAfterPacketStart(fOutBuf->curPtr() - frameSize,
00332                                            frameSize) ) {
00333       // The packet is ready to be sent now
00334       sendPacketIfNecessary();
00335     } else {
00336       // There's room for more frames; try getting another:
00337       packFrame();
00338     }
00339   }
00340 }
00341 
00342 static unsigned const rtpHeaderSize = 12;
00343 
00344 Boolean MultiFramedRTPSink::isTooBigForAPacket(unsigned numBytes) const {
00345   // Check whether a 'numBytes'-byte frame - together with a RTP header and
00346   // (possible) special headers - would be too big for an output packet:
00347   // (Later allow for RTP extension header!) #####
00348   numBytes += rtpHeaderSize + specialHeaderSize() + frameSpecificHeaderSize();
00349   return fOutBuf->isTooBigForAPacket(numBytes);
00350 }
00351 
00352 void MultiFramedRTPSink::sendPacketIfNecessary() {
00353   if (fNumFramesUsedSoFar > 0) {
00354     // Send the packet:
00355 #ifdef TEST_LOSS
00356     if ((our_random()%10) != 0) // simulate 10% packet loss #####
00357 #endif
00358       if (!fRTPInterface.sendPacket(fOutBuf->packet(), fOutBuf->curPacketSize())) {
00359         // if failure handler has been specified, call it
00360         if (fOnSendErrorFunc != NULL) (*fOnSendErrorFunc)(fOnSendErrorData);
00361       }
00362     ++fPacketCount;
00363     fTotalOctetCount += fOutBuf->curPacketSize();
00364     fOctetCount += fOutBuf->curPacketSize()
00365       - rtpHeaderSize - fSpecialHeaderSize - fTotalFrameSpecificHeaderSizes;
00366 
00367     ++fSeqNo; // for next time
00368   }
00369 
00370   if (fOutBuf->haveOverflowData()
00371       && fOutBuf->totalBytesAvailable() > fOutBuf->totalBufferSize()/2) {
00372     // Efficiency hack: Reset the packet start pointer to just in front of
00373     // the overflow data (allowing for the RTP header and special headers),
00374     // so that we probably don't have to "memmove()" the overflow data
00375     // into place when building the next packet:
00376     unsigned newPacketStart = fOutBuf->curPacketSize()
00377       - (rtpHeaderSize + fSpecialHeaderSize + frameSpecificHeaderSize());
00378     fOutBuf->adjustPacketStart(newPacketStart);
00379   } else {
00380     // Normal case: Reset the packet start pointer back to the start:
00381     fOutBuf->resetPacketStart();
00382   }
00383   fOutBuf->resetOffset();
00384   fNumFramesUsedSoFar = 0;
00385 
00386   if (fNoFramesLeft) {
00387     // We're done:
00388     onSourceClosure(this);
00389   } else {
00390     // We have more frames left to send.  Figure out when the next frame
00391     // is due to start playing, then make sure that we wait this long before
00392     // sending the next packet.
00393     struct timeval timeNow;
00394     gettimeofday(&timeNow, NULL);
00395     int secsDiff = fNextSendTime.tv_sec - timeNow.tv_sec;
00396     int64_t uSecondsToGo = secsDiff*1000000 + (fNextSendTime.tv_usec - timeNow.tv_usec);
00397     if (uSecondsToGo < 0 || secsDiff < 0) { // sanity check: Make sure that the time-to-delay is non-negative:
00398       uSecondsToGo = 0;
00399     }
00400 
00401     // Delay this amount of time:
00402     nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecondsToGo, (TaskFunc*)sendNext, this);
00403   }
00404 }
00405 
00406 // The following is called after each delay between packet sends:
00407 void MultiFramedRTPSink::sendNext(void* firstArg) {
00408   MultiFramedRTPSink* sink = (MultiFramedRTPSink*)firstArg;
00409   sink->buildAndSendPacket(False);
00410 }
00411 
00412 void MultiFramedRTPSink::ourHandleClosure(void* clientData) {
00413   MultiFramedRTPSink* sink = (MultiFramedRTPSink*)clientData;
00414   // There are no frames left, but we may have a partially built packet
00415   //  to send
00416   sink->fNoFramesLeft = True;
00417   sink->sendPacketIfNecessary();
00418 }

Generated on Thu May 17 07:11:47 2012 for live by  doxygen 1.5.2