liveMedia/AMRAudioRTPSource.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-2013 Live Networks, Inc.  All rights reserved.
00018 // AMR Audio RTP Sources (RFC 4867)
00019 // Implementation
00020 
00021 #include "AMRAudioRTPSource.hh"
00022 #include "MultiFramedRTPSource.hh"
00023 #include "BitVector.hh"
00024 #include <string.h>
00025 #include <stdlib.h>
00026 
00027 // This source is implemented internally by two separate sources:
00028 // (i) a RTP source for the raw (and possibly interleaved) AMR frames, and
00029 // (ii) a deinterleaving filter that reads from this.
00030 // Define these two new classes here:
00031 
00032 class RawAMRRTPSource: public MultiFramedRTPSource {
00033 public:
00034   static RawAMRRTPSource*
00035   createNew(UsageEnvironment& env,
00036             Groupsock* RTPgs, unsigned char rtpPayloadFormat,
00037             Boolean isWideband, Boolean isOctetAligned,
00038             Boolean isInterleaved, Boolean CRCsArePresent);
00039 
00040   Boolean isWideband() const { return fIsWideband; }
00041   unsigned char ILL() const { return fILL; }
00042   unsigned char ILP() const { return fILP; }
00043   unsigned TOCSize() const { return fTOCSize; } // total # of frames in the last pkt
00044   unsigned char* TOC() const { return fTOC; } // FT+Q value for each TOC entry
00045   unsigned& frameIndex() { return fFrameIndex; } // index of frame-block within pkt
00046   Boolean& isSynchronized() { return fIsSynchronized; }
00047 
00048 private:
00049   RawAMRRTPSource(UsageEnvironment& env, Groupsock* RTPgs,
00050                   unsigned char rtpPayloadFormat,
00051                   Boolean isWideband, Boolean isOctetAligned,
00052                   Boolean isInterleaved, Boolean CRCsArePresent);
00053       // called only by createNew()
00054 
00055   virtual ~RawAMRRTPSource();
00056 
00057 private:
00058   // redefined virtual functions:
00059   virtual Boolean hasBeenSynchronizedUsingRTCP();
00060 
00061   virtual Boolean processSpecialHeader(BufferedPacket* packet,
00062                                        unsigned& resultSpecialHeaderSize);
00063   virtual char const* MIMEtype() const;
00064 
00065 private:
00066   Boolean fIsWideband, fIsOctetAligned, fIsInterleaved, fCRCsArePresent;
00067   unsigned char fILL, fILP;
00068   unsigned fTOCSize;
00069   unsigned char* fTOC;
00070   unsigned fFrameIndex;
00071   Boolean fIsSynchronized;
00072 };
00073 
00074 class AMRDeinterleaver: public AMRAudioSource {
00075 public:
00076   static AMRDeinterleaver*
00077   createNew(UsageEnvironment& env,
00078             Boolean isWideband, unsigned numChannels, unsigned maxInterleaveGroupSize,
00079             RawAMRRTPSource* inputSource);
00080 
00081 private:
00082   AMRDeinterleaver(UsageEnvironment& env,
00083                    Boolean isWideband, unsigned numChannels,
00084                    unsigned maxInterleaveGroupSize, RawAMRRTPSource* inputSource);
00085       // called only by "createNew()"
00086 
00087   virtual ~AMRDeinterleaver();
00088 
00089   static void afterGettingFrame(void* clientData, unsigned frameSize,
00090                                 unsigned numTruncatedBytes,
00091                                 struct timeval presentationTime,
00092                                 unsigned durationInMicroseconds);
00093   void afterGettingFrame1(unsigned frameSize, struct timeval presentationTime);
00094 
00095 private:
00096   // Redefined virtual functions:
00097   void doGetNextFrame();
00098   virtual void doStopGettingFrames();
00099 
00100 private:
00101   RawAMRRTPSource* fInputSource;
00102   class AMRDeinterleavingBuffer* fDeinterleavingBuffer;
00103   Boolean fNeedAFrame;
00104 };
00105 
00106 
00108 
00109 #define MAX_NUM_CHANNELS 20 // far larger than ever expected...
00110 #define MAX_INTERLEAVING_GROUP_SIZE 1000 // far larger than ever expected...
00111 
00112 AMRAudioSource*
00113 AMRAudioRTPSource::createNew(UsageEnvironment& env,
00114                              Groupsock* RTPgs,
00115                              RTPSource*& resultRTPSource,
00116                              unsigned char rtpPayloadFormat,
00117                              Boolean isWideband,
00118                              unsigned numChannels,
00119                              Boolean isOctetAligned,
00120                              unsigned interleaving,
00121                              Boolean robustSortingOrder,
00122                              Boolean CRCsArePresent) {
00123   // Perform sanity checks on the input parameters:
00124   if (robustSortingOrder) {
00125     env << "AMRAudioRTPSource::createNew(): 'Robust sorting order' was specified, but we don't yet support this!\n";
00126     return NULL;
00127   } else if (numChannels > MAX_NUM_CHANNELS) {
00128     env << "AMRAudioRTPSource::createNew(): The \"number of channels\" parameter ("
00129         << numChannels << ") is much too large!\n";
00130     return NULL;
00131   } else if (interleaving > MAX_INTERLEAVING_GROUP_SIZE) {
00132     env << "AMRAudioRTPSource::createNew(): The \"interleaving\" parameter ("
00133         << interleaving << ") is much too large!\n";
00134     return NULL;
00135   }
00136 
00137   // 'Bandwidth-efficient mode' precludes some other options:
00138   if (!isOctetAligned) {
00139     if (interleaving > 0 || robustSortingOrder || CRCsArePresent) {
00140       env << "AMRAudioRTPSource::createNew(): 'Bandwidth-efficient mode' was specified, along with interleaving, 'robust sorting order', and/or CRCs, so we assume 'octet-aligned mode' instead.\n";
00141       isOctetAligned = True;
00142     }
00143   }
00144 
00145   Boolean isInterleaved;
00146   unsigned maxInterleaveGroupSize; // in frames (not frame-blocks)
00147   if (interleaving > 0) {
00148     isInterleaved = True;
00149     maxInterleaveGroupSize = interleaving*numChannels;
00150   } else {
00151     isInterleaved = False;
00152     maxInterleaveGroupSize = numChannels;
00153   }
00154 
00155   RawAMRRTPSource* rawRTPSource;
00156   resultRTPSource = rawRTPSource
00157     = RawAMRRTPSource::createNew(env, RTPgs, rtpPayloadFormat,
00158                                  isWideband, isOctetAligned,
00159                                  isInterleaved, CRCsArePresent);
00160   if (resultRTPSource == NULL) return NULL;
00161 
00162   AMRDeinterleaver* deinterleaver
00163     = AMRDeinterleaver::createNew(env, isWideband, numChannels,
00164                                   maxInterleaveGroupSize, rawRTPSource);
00165   if (deinterleaver == NULL) {
00166     Medium::close(resultRTPSource);
00167     resultRTPSource = NULL;
00168   }
00169 
00170   return deinterleaver;
00171 }
00172 
00173 
00175 
00176 // A subclass of BufferedPacket, used to separate out AMR frames.
00177 
00178 class AMRBufferedPacket: public BufferedPacket {
00179 public:
00180   AMRBufferedPacket(RawAMRRTPSource& ourSource);
00181   virtual ~AMRBufferedPacket();
00182 
00183 private: // redefined virtual functions
00184   virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr,
00185                                          unsigned dataSize);
00186 private:
00187   RawAMRRTPSource& fOurSource;
00188 };
00189 
00190 class AMRBufferedPacketFactory: public BufferedPacketFactory {
00191 private: // redefined virtual functions
00192   virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource);
00193 };
00194 
00195 
00197 
00198 RawAMRRTPSource*
00199 RawAMRRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs,
00200                            unsigned char rtpPayloadFormat,
00201                            Boolean isWideband, Boolean isOctetAligned,
00202                            Boolean isInterleaved, Boolean CRCsArePresent) {
00203   return new RawAMRRTPSource(env, RTPgs, rtpPayloadFormat,
00204                              isWideband, isOctetAligned,
00205                              isInterleaved, CRCsArePresent);
00206 }
00207 
00208 RawAMRRTPSource
00209 ::RawAMRRTPSource(UsageEnvironment& env,
00210                   Groupsock* RTPgs, unsigned char rtpPayloadFormat,
00211                   Boolean isWideband, Boolean isOctetAligned,
00212                   Boolean isInterleaved, Boolean CRCsArePresent)
00213   : MultiFramedRTPSource(env, RTPgs, rtpPayloadFormat,
00214                          isWideband ? 16000 : 8000,
00215                          new AMRBufferedPacketFactory),
00216   fIsWideband(isWideband), fIsOctetAligned(isOctetAligned),
00217   fIsInterleaved(isInterleaved), fCRCsArePresent(CRCsArePresent),
00218   fILL(0), fILP(0), fTOCSize(0), fTOC(NULL), fFrameIndex(0), fIsSynchronized(False) {
00219 }
00220 
00221 RawAMRRTPSource::~RawAMRRTPSource() {
00222   delete[] fTOC;
00223 }
00224 
00225 #define FT_SPEECH_LOST 14
00226 #define FT_NO_DATA 15
00227 
00228 static void unpackBandwidthEfficientData(BufferedPacket* packet,
00229                                          Boolean isWideband); // forward
00230 
00231 Boolean RawAMRRTPSource
00232 ::processSpecialHeader(BufferedPacket* packet,
00233                        unsigned& resultSpecialHeaderSize) {
00234   // If the data is 'bandwidth-efficient', first unpack it so that it's
00235   // 'octet-aligned':
00236   if (!fIsOctetAligned) unpackBandwidthEfficientData(packet, fIsWideband);
00237 
00238   unsigned char* headerStart = packet->data();
00239   unsigned packetSize = packet->dataSize();
00240 
00241   // There's at least a 1-byte header, containing the CMR:
00242   if (packetSize < 1) return False;
00243   resultSpecialHeaderSize = 1;
00244 
00245   if (fIsInterleaved) {
00246     // There's an extra byte, containing the interleave parameters:
00247     if (packetSize < 2) return False;
00248 
00249     // Get the interleaving parameters, and check them for validity:
00250     unsigned char const secondByte = headerStart[1];
00251     fILL = (secondByte&0xF0)>>4;
00252     fILP = secondByte&0x0F;
00253     if (fILP > fILL) return False; // invalid
00254     ++resultSpecialHeaderSize;
00255   }
00256 #ifdef DEBUG
00257   fprintf(stderr, "packetSize: %d, ILL: %d, ILP: %d\n", packetSize, fILL, fILP);
00258 #endif
00259   fFrameIndex = 0; // initially
00260 
00261   // Next, there's a "Payload Table of Contents" (one byte per entry):
00262   unsigned numFramesPresent = 0, numNonEmptyFramesPresent = 0;
00263   unsigned tocStartIndex = resultSpecialHeaderSize;
00264   Boolean F;
00265   do {
00266     if (resultSpecialHeaderSize >= packetSize) return False;
00267     unsigned char const tocByte = headerStart[resultSpecialHeaderSize++];
00268     F = (tocByte&0x80) != 0;
00269     unsigned char const FT = (tocByte&0x78) >> 3;
00270 #ifdef DEBUG
00271     unsigned char Q = (tocByte&0x04)>>2;
00272     fprintf(stderr, "\tTOC entry: F %d, FT %d, Q %d\n", F, FT, Q);
00273 #endif
00274     ++numFramesPresent;
00275     if (FT != FT_SPEECH_LOST && FT != FT_NO_DATA) ++numNonEmptyFramesPresent;
00276   } while (F);
00277 #ifdef DEBUG
00278   fprintf(stderr, "TOC contains %d entries (%d non-empty)\n", numFramesPresent, numNonEmptyFramesPresent);
00279 #endif
00280 
00281   // Now that we know the size of the TOC, fill in our copy:
00282   if (numFramesPresent > fTOCSize) {
00283     delete[] fTOC;
00284     fTOC = new unsigned char[numFramesPresent];
00285   }
00286   fTOCSize = numFramesPresent;
00287   for (unsigned i = 0; i < fTOCSize; ++i) {
00288     unsigned char const tocByte = headerStart[tocStartIndex + i];
00289     fTOC[i] = tocByte&0x7C; // clear everything except the F and Q fields
00290   }
00291 
00292   if (fCRCsArePresent) {
00293     // 'numNonEmptyFramesPresent' CRC bytes will follow.
00294     // Note: we currently don't check the CRCs for validity #####
00295     resultSpecialHeaderSize += numNonEmptyFramesPresent;
00296 #ifdef DEBUG
00297     fprintf(stderr, "Ignoring %d following CRC bytes\n", numNonEmptyFramesPresent);
00298 #endif
00299     if (resultSpecialHeaderSize > packetSize) return False;
00300   }
00301 #ifdef DEBUG
00302   fprintf(stderr, "Total special header size: %d\n", resultSpecialHeaderSize);
00303 #endif
00304 
00305   return True;
00306 }
00307 
00308 char const* RawAMRRTPSource::MIMEtype() const {
00309   return fIsWideband ? "audio/AMR-WB" : "audio/AMR";
00310 }
00311 
00312 Boolean RawAMRRTPSource::hasBeenSynchronizedUsingRTCP() {
00313   return fIsSynchronized;
00314 }
00315 
00316 
00318 
00319 AMRBufferedPacket::AMRBufferedPacket(RawAMRRTPSource& ourSource)
00320   : fOurSource(ourSource) {
00321 }
00322 
00323 AMRBufferedPacket::~AMRBufferedPacket() {
00324 }
00325 
00326 // The mapping from the "FT" field to frame size.
00327 // Values of 65535 are invalid.
00328 #define FT_INVALID 65535
00329 static unsigned short const frameBytesFromFT[16] = {
00330   12, 13, 15, 17,
00331   19, 20, 26, 31,
00332   5, FT_INVALID, FT_INVALID, FT_INVALID,
00333   FT_INVALID, FT_INVALID, FT_INVALID, 0
00334 };
00335 static unsigned short const frameBytesFromFTWideband[16] = {
00336   17, 23, 32, 36,
00337   40, 46, 50, 58,
00338   60, 5, FT_INVALID, FT_INVALID,
00339   FT_INVALID, FT_INVALID, 0, 0
00340 };
00341 
00342 unsigned AMRBufferedPacket::
00343   nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) {
00344   if (dataSize == 0) return 0; // sanity check
00345 
00346   // The size of the AMR frame is determined by the corresponding 'FT' value
00347   // in the packet's Table of Contents.
00348   unsigned const tocIndex = fOurSource.frameIndex();
00349   if (tocIndex >= fOurSource.TOCSize()) return 0; // sanity check
00350 
00351   unsigned char const tocByte = fOurSource.TOC()[tocIndex];
00352   unsigned char const FT = (tocByte&0x78) >> 3;
00353   // ASSERT: FT < 16
00354   unsigned short frameSize
00355     = fOurSource.isWideband() ? frameBytesFromFTWideband[FT] : frameBytesFromFT[FT];
00356   if (frameSize == FT_INVALID) {
00357     // Strange TOC entry!
00358     fOurSource.envir() << "AMRBufferedPacket::nextEnclosedFrameSize(): invalid FT: " << FT << "\n";
00359     frameSize = 0; // This probably messes up the rest of this packet, but...
00360   }
00361 #ifdef DEBUG
00362   fprintf(stderr, "AMRBufferedPacket::nextEnclosedFrameSize(): frame #: %d, FT: %d, isWideband: %d => frameSize: %d (dataSize: %d)\n", tocIndex, FT, fOurSource.isWideband(), frameSize, dataSize);
00363 #endif
00364   ++fOurSource.frameIndex();
00365 
00366   if (dataSize < frameSize) return 0;
00367   return frameSize;
00368 }
00369 
00370 BufferedPacket* AMRBufferedPacketFactory
00371 ::createNewPacket(MultiFramedRTPSource* ourSource) {
00372   return new AMRBufferedPacket((RawAMRRTPSource&)(*ourSource));
00373 }
00374 
00376 // (used to implement AMRDeinterleaver)
00377 
00378 #define AMR_MAX_FRAME_SIZE 60
00379 
00380 class AMRDeinterleavingBuffer {
00381 public:
00382   AMRDeinterleavingBuffer(unsigned numChannels, unsigned maxInterleaveGroupSize);
00383   virtual ~AMRDeinterleavingBuffer();
00384 
00385   void deliverIncomingFrame(unsigned frameSize, RawAMRRTPSource* source,
00386                             struct timeval presentationTime);
00387   Boolean retrieveFrame(unsigned char* to, unsigned maxSize,
00388                         unsigned& resultFrameSize, unsigned& resultNumTruncatedBytes,
00389                         u_int8_t& resultFrameHeader,
00390                         struct timeval& resultPresentationTime,
00391                         Boolean& resultIsSynchronized);
00392 
00393   unsigned char* inputBuffer() { return fInputBuffer; }
00394   unsigned inputBufferSize() const { return AMR_MAX_FRAME_SIZE; }
00395 
00396 private:
00397   unsigned char* createNewBuffer();
00398 
00399   class FrameDescriptor {
00400   public:
00401     FrameDescriptor();
00402     virtual ~FrameDescriptor();
00403 
00404     unsigned frameSize;
00405     unsigned char* frameData;
00406     u_int8_t frameHeader;
00407     struct timeval presentationTime;
00408     Boolean fIsSynchronized;
00409   };
00410 
00411   unsigned fNumChannels, fMaxInterleaveGroupSize;
00412   FrameDescriptor* fFrames[2];
00413   unsigned char fIncomingBankId; // toggles between 0 and 1
00414   unsigned char fIncomingBinMax; // in the incoming bank
00415   unsigned char fOutgoingBinMax; // in the outgoing bank
00416   unsigned char fNextOutgoingBin;
00417   Boolean fHaveSeenPackets;
00418   u_int16_t fLastPacketSeqNumForGroup;
00419   unsigned char* fInputBuffer;
00420   struct timeval fLastRetrievedPresentationTime;
00421   unsigned fNumSuccessiveSyncedFrames;
00422   unsigned char fILL;
00423 };
00424 
00425 
00427 
00428 AMRDeinterleaver* AMRDeinterleaver
00429 ::createNew(UsageEnvironment& env,
00430             Boolean isWideband, unsigned numChannels, unsigned maxInterleaveGroupSize,
00431             RawAMRRTPSource* inputSource) {
00432   return new AMRDeinterleaver(env, isWideband, numChannels, maxInterleaveGroupSize, inputSource);
00433 }
00434 
00435 AMRDeinterleaver::AMRDeinterleaver(UsageEnvironment& env,
00436                                    Boolean isWideband, unsigned numChannels,
00437                                    unsigned maxInterleaveGroupSize,
00438                                    RawAMRRTPSource* inputSource)
00439   : AMRAudioSource(env, isWideband, numChannels),
00440     fInputSource(inputSource), fNeedAFrame(False) {
00441   fDeinterleavingBuffer
00442     = new AMRDeinterleavingBuffer(numChannels, maxInterleaveGroupSize);
00443 }
00444 
00445 AMRDeinterleaver::~AMRDeinterleaver() {
00446   delete fDeinterleavingBuffer;
00447   Medium::close(fInputSource);
00448 }
00449 
00450 static unsigned const uSecsPerFrame = 20000; // 20 ms
00451 
00452 void AMRDeinterleaver::doGetNextFrame() {
00453   // First, try getting a frame from the deinterleaving buffer:
00454   if (fDeinterleavingBuffer->retrieveFrame(fTo, fMaxSize,
00455                                            fFrameSize, fNumTruncatedBytes,
00456                                            fLastFrameHeader, fPresentationTime,
00457                                            fInputSource->isSynchronized())) {
00458 
00459     // Success!
00460     fNeedAFrame = False;
00461 
00462     fDurationInMicroseconds = uSecsPerFrame;
00463 
00464     // Call our own 'after getting' function.  Because we're not a 'leaf'
00465     // source, we can call this directly, without risking
00466     // infinite recursion
00467     afterGetting(this);
00468     return;
00469   }
00470 
00471   // No luck, so ask our source for help:
00472   fNeedAFrame = True;
00473   if (!fInputSource->isCurrentlyAwaitingData()) {
00474     fInputSource->getNextFrame(fDeinterleavingBuffer->inputBuffer(),
00475                                fDeinterleavingBuffer->inputBufferSize(),
00476                                afterGettingFrame, this,
00477                                FramedSource::handleClosure, this);
00478   }
00479 }
00480 
00481 void AMRDeinterleaver::doStopGettingFrames() {
00482   fNeedAFrame = False;
00483   fInputSource->stopGettingFrames();
00484 }
00485 
00486 void AMRDeinterleaver
00487 ::afterGettingFrame(void* clientData, unsigned frameSize,
00488                     unsigned /*numTruncatedBytes*/,
00489                     struct timeval presentationTime,
00490                     unsigned /*durationInMicroseconds*/) {
00491   AMRDeinterleaver* deinterleaver = (AMRDeinterleaver*)clientData;
00492   deinterleaver->afterGettingFrame1(frameSize, presentationTime);
00493 }
00494 
00495 void AMRDeinterleaver
00496 ::afterGettingFrame1(unsigned frameSize, struct timeval presentationTime) {
00497   RawAMRRTPSource* source = (RawAMRRTPSource*)fInputSource;
00498 
00499   // First, put the frame into our deinterleaving buffer:
00500   fDeinterleavingBuffer->deliverIncomingFrame(frameSize, source, presentationTime);
00501 
00502   // Then, try delivering a frame to the client (if he wants one):
00503   if (fNeedAFrame) doGetNextFrame();
00504 }
00505 
00506 
00508 
00509 AMRDeinterleavingBuffer
00510 ::AMRDeinterleavingBuffer(unsigned numChannels, unsigned maxInterleaveGroupSize)
00511   : fNumChannels(numChannels), fMaxInterleaveGroupSize(maxInterleaveGroupSize),
00512     fIncomingBankId(0), fIncomingBinMax(0),
00513     fOutgoingBinMax(0), fNextOutgoingBin(0),
00514     fHaveSeenPackets(False), fNumSuccessiveSyncedFrames(0), fILL(0) {
00515   // Use two banks of descriptors - one for incoming, one for outgoing
00516   fFrames[0] = new FrameDescriptor[fMaxInterleaveGroupSize];
00517   fFrames[1] = new FrameDescriptor[fMaxInterleaveGroupSize];
00518   fInputBuffer = createNewBuffer();
00519 }
00520 
00521 AMRDeinterleavingBuffer::~AMRDeinterleavingBuffer() {
00522   delete[] fInputBuffer;
00523   delete[] fFrames[0]; delete[] fFrames[1];
00524 }
00525 
00526 void AMRDeinterleavingBuffer
00527 ::deliverIncomingFrame(unsigned frameSize, RawAMRRTPSource* source,
00528                        struct timeval presentationTime) {
00529   fILL = source->ILL();
00530   unsigned char const ILP = source->ILP();
00531   unsigned frameIndex = source->frameIndex();
00532   unsigned short packetSeqNum = source->curPacketRTPSeqNum();
00533 
00534   // First perform a sanity check on the parameters:
00535   // (This is overkill, as the source should have already done this.)
00536   if (ILP > fILL || frameIndex == 0) {
00537 #ifdef DEBUG
00538     fprintf(stderr, "AMRDeinterleavingBuffer::deliverIncomingFrame() param sanity check failed (%d,%d,%d,%d)\n", frameSize, fILL, ILP, frameIndex);
00539 #endif
00540     source->envir().internalError();
00541   }
00542 
00543   --frameIndex; // because it was incremented by the source when this frame was read
00544   u_int8_t frameHeader;
00545   if (frameIndex >= source->TOCSize()) { // sanity check
00546     frameHeader = FT_NO_DATA<<3;
00547   } else {
00548     frameHeader = source->TOC()[frameIndex];
00549   }
00550 
00551   unsigned frameBlockIndex = frameIndex/fNumChannels;
00552   unsigned frameWithinFrameBlock = frameIndex%fNumChannels;
00553 
00554   // The input "presentationTime" was that of the first frame-block in this
00555   // packet.  Update it for the current frame:
00556   unsigned uSecIncrement = frameBlockIndex*(fILL+1)*uSecsPerFrame;
00557   presentationTime.tv_usec += uSecIncrement;
00558   presentationTime.tv_sec += presentationTime.tv_usec/1000000;
00559   presentationTime.tv_usec = presentationTime.tv_usec%1000000;
00560 
00561   // Next, check whether this packet is part of a new interleave group
00562   if (!fHaveSeenPackets
00563       || seqNumLT(fLastPacketSeqNumForGroup, packetSeqNum + frameBlockIndex)) {
00564     // We've moved to a new interleave group
00565 #ifdef DEBUG
00566     fprintf(stderr, "AMRDeinterleavingBuffer::deliverIncomingFrame(): new interleave group\n");
00567 #endif
00568     fHaveSeenPackets = True;
00569     fLastPacketSeqNumForGroup = packetSeqNum + fILL - ILP;
00570 
00571     // Switch the incoming and outgoing banks:
00572     fIncomingBankId ^= 1;
00573     unsigned char tmp = fIncomingBinMax;
00574     fIncomingBinMax = fOutgoingBinMax;
00575     fOutgoingBinMax = tmp;
00576     fNextOutgoingBin = 0;
00577   }
00578 
00579   // Now move the incoming frame into the appropriate bin:
00580   unsigned const binNumber
00581     = ((ILP + frameBlockIndex*(fILL+1))*fNumChannels + frameWithinFrameBlock)
00582       % fMaxInterleaveGroupSize; // the % is for sanity
00583 #ifdef DEBUG
00584   fprintf(stderr, "AMRDeinterleavingBuffer::deliverIncomingFrame(): frameIndex %d (%d,%d) put in bank %d, bin %d (%d): size %d, header 0x%02x, presentationTime %lu.%06ld\n", frameIndex, frameBlockIndex, frameWithinFrameBlock, fIncomingBankId, binNumber, fMaxInterleaveGroupSize, frameSize, frameHeader, presentationTime.tv_sec, presentationTime.tv_usec);
00585 #endif
00586   FrameDescriptor& inBin = fFrames[fIncomingBankId][binNumber];
00587   unsigned char* curBuffer = inBin.frameData;
00588   inBin.frameData = fInputBuffer;
00589   inBin.frameSize = frameSize;
00590   inBin.frameHeader = frameHeader;
00591   inBin.presentationTime = presentationTime;
00592   inBin.fIsSynchronized = ((RTPSource*)source)->RTPSource::hasBeenSynchronizedUsingRTCP();
00593 
00594   if (curBuffer == NULL) curBuffer = createNewBuffer();
00595   fInputBuffer = curBuffer;
00596 
00597   if (binNumber >= fIncomingBinMax) {
00598     fIncomingBinMax = binNumber + 1;
00599   }
00600 }
00601 
00602 Boolean AMRDeinterleavingBuffer
00603 ::retrieveFrame(unsigned char* to, unsigned maxSize,
00604                 unsigned& resultFrameSize, unsigned& resultNumTruncatedBytes,
00605                 u_int8_t& resultFrameHeader,
00606                 struct timeval& resultPresentationTime,
00607                 Boolean& resultIsSynchronized) {
00608 
00609   if (fNextOutgoingBin >= fOutgoingBinMax) return False; // none left
00610 
00611   FrameDescriptor& outBin = fFrames[fIncomingBankId^1][fNextOutgoingBin];
00612   unsigned char* fromPtr = outBin.frameData;
00613   unsigned char fromSize = outBin.frameSize;
00614   outBin.frameSize = 0; // for the next time this bin is used
00615   resultIsSynchronized = False; // by default; can be changed by:
00616   if (outBin.fIsSynchronized) {
00617     // Don't consider the outgoing frame to be synchronized until we've received at least a complete interleave cycle of
00618     // synchronized frames.  This ensures that the receiver will be getting all synchronized frames from now on.
00619     if (++fNumSuccessiveSyncedFrames > fILL) {
00620       resultIsSynchronized = True;
00621       fNumSuccessiveSyncedFrames = fILL+1; // prevents overflow
00622     }
00623   } else {
00624     fNumSuccessiveSyncedFrames = 0;
00625   } 
00626 
00627   // Check whether this frame is missing; if so, return a FT_NO_DATA frame:
00628   if (fromSize == 0) {
00629     resultFrameHeader = FT_NO_DATA<<3;
00630 
00631     // Compute this erasure frame's presentation time via extrapolation:
00632     resultPresentationTime = fLastRetrievedPresentationTime;
00633     resultPresentationTime.tv_usec += uSecsPerFrame;
00634     if (resultPresentationTime.tv_usec >= 1000000) {
00635       ++resultPresentationTime.tv_sec;
00636       resultPresentationTime.tv_usec -= 1000000;
00637     }
00638   } else {
00639     // Normal case - a frame exists:
00640     resultFrameHeader = outBin.frameHeader;
00641     resultPresentationTime = outBin.presentationTime;
00642   }
00643 
00644   fLastRetrievedPresentationTime = resultPresentationTime;
00645 
00646   if (fromSize > maxSize) {
00647     resultNumTruncatedBytes = fromSize - maxSize;
00648     resultFrameSize = maxSize;
00649   } else {
00650     resultNumTruncatedBytes = 0;
00651     resultFrameSize = fromSize;
00652   }
00653   memmove(to, fromPtr, resultFrameSize);
00654 #ifdef DEBUG
00655   fprintf(stderr, "AMRDeinterleavingBuffer::retrieveFrame(): from bank %d, bin %d: size %d, header 0x%02x, presentationTime %lu.%06ld\n", fIncomingBankId^1, fNextOutgoingBin, resultFrameSize, resultFrameHeader, resultPresentationTime.tv_sec, resultPresentationTime.tv_usec);
00656 #endif
00657 
00658   ++fNextOutgoingBin;
00659   return True;
00660 }
00661 
00662 unsigned char* AMRDeinterleavingBuffer::createNewBuffer() {
00663   return new unsigned char[inputBufferSize()];
00664 }
00665 
00666 AMRDeinterleavingBuffer::FrameDescriptor::FrameDescriptor()
00667   : frameSize(0), frameData(NULL) {
00668 }
00669 
00670 AMRDeinterleavingBuffer::FrameDescriptor::~FrameDescriptor() {
00671   delete[] frameData;
00672 }
00673 
00674 // Unpack bandwidth-aligned data to octet-aligned:
00675 static unsigned short const frameBitsFromFT[16] = {
00676   95, 103, 118, 134,
00677   148, 159, 204, 244,
00678   39, 0, 0, 0,
00679   0, 0, 0, 0
00680 };
00681 static unsigned short const frameBitsFromFTWideband[16] = {
00682   132, 177, 253, 285,
00683   317, 365, 397, 461,
00684   477, 40, 0, 0,
00685   0, 0, 0, 0
00686 };
00687 
00688 static void unpackBandwidthEfficientData(BufferedPacket* packet,
00689                                          Boolean isWideband) {
00690 #ifdef DEBUG
00691   fprintf(stderr, "Unpacking 'bandwidth-efficient' payload (%d bytes):\n", packet->dataSize());
00692   for (unsigned j = 0; j < packet->dataSize(); ++j) {
00693     fprintf(stderr, "%02x:", (packet->data())[j]);
00694   }
00695   fprintf(stderr, "\n");
00696 #endif
00697   BitVector fromBV(packet->data(), 0, 8*packet->dataSize());
00698 
00699   unsigned const toBufferSize = 2*packet->dataSize(); // conservatively large
00700   unsigned char* toBuffer = new unsigned char[toBufferSize];
00701   unsigned toCount = 0;
00702 
00703   // Begin with the payload header:
00704   unsigned CMR = fromBV.getBits(4);
00705   toBuffer[toCount++] = CMR << 4;
00706 
00707   // Then, run through and unpack the TOC entries:
00708   while (1) {
00709     unsigned toc = fromBV.getBits(6);
00710     toBuffer[toCount++] = toc << 2;
00711 
00712     if ((toc&0x20) == 0) break; // the F bit is 0
00713   }
00714 
00715   // Then, using the TOC data, unpack each frame payload:
00716   unsigned const tocSize = toCount - 1;
00717   for (unsigned i = 1; i <= tocSize; ++i) {
00718     unsigned char tocByte = toBuffer[i];
00719     unsigned char const FT = (tocByte&0x78) >> 3;
00720     unsigned short frameSizeBits
00721       = isWideband ? frameBitsFromFTWideband[FT] : frameBitsFromFT[FT];
00722     unsigned short frameSizeBytes = (frameSizeBits+7)/8;
00723 
00724     shiftBits(&toBuffer[toCount], 0, // to
00725               packet->data(), fromBV.curBitIndex(), // from
00726               frameSizeBits // num bits
00727               );
00728 #ifdef DEBUG
00729     if (frameSizeBits > fromBV.numBitsRemaining()) {
00730       fprintf(stderr, "\tWarning: Unpacking frame %d of %d: want %d bits, but only %d are available!\n", i, tocSize, frameSizeBits, fromBV.numBitsRemaining());
00731     }
00732 #endif
00733     fromBV.skipBits(frameSizeBits);
00734     toCount += frameSizeBytes;
00735   }
00736 
00737 #ifdef DEBUG
00738   if (fromBV.numBitsRemaining() > 7) {
00739     fprintf(stderr, "\tWarning: %d bits remain unused!\n", fromBV.numBitsRemaining());
00740   }
00741 #endif
00742 
00743   // Finally, replace the current packet data with the unpacked data:
00744   packet->removePadding(packet->dataSize()); // throws away current packet data
00745   packet->appendData(toBuffer, toCount);
00746   delete[] toBuffer;
00747 }

Generated on Mon Apr 29 13:28:01 2013 for live by  doxygen 1.5.2