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

Generated on Tue Oct 7 15:38:08 2008 for live by  doxygen 1.5.2