/********** This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. (See .) This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********/ // "liveMedia" // Copyright (c) 1996-2016 Live Networks, Inc. All rights reserved. // Qualcomm "PureVoice" (aka. "QCELP") Audio RTP Sources // Implementation #include "QCELPAudioRTPSource.hh" #include "MultiFramedRTPSource.hh" #include "FramedFilter.hh" #include #include // This source is implemented internally by two separate sources: // (i) a RTP source for the raw (interleaved) QCELP frames, and // (ii) a deinterleaving filter that reads from this. // Define these two new classes here: class RawQCELPRTPSource: public MultiFramedRTPSource { public: static RawQCELPRTPSource* createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat, unsigned rtpTimestampFrequency); unsigned char interleaveL() const { return fInterleaveL; } unsigned char interleaveN() const { return fInterleaveN; } unsigned char& frameIndex() { return fFrameIndex; } // index within pkt private: RawQCELPRTPSource(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat, unsigned rtpTimestampFrequency); // called only by createNew() virtual ~RawQCELPRTPSource(); private: // redefined virtual functions: virtual Boolean processSpecialHeader(BufferedPacket* packet, unsigned& resultSpecialHeaderSize); virtual char const* MIMEtype() const; virtual Boolean hasBeenSynchronizedUsingRTCP(); private: unsigned char fInterleaveL, fInterleaveN, fFrameIndex; unsigned fNumSuccessiveSyncedPackets; }; class QCELPDeinterleaver: public FramedFilter { public: static QCELPDeinterleaver* createNew(UsageEnvironment& env, RawQCELPRTPSource* inputSource); private: QCELPDeinterleaver(UsageEnvironment& env, RawQCELPRTPSource* inputSource); // called only by "createNew()" virtual ~QCELPDeinterleaver(); static void afterGettingFrame(void* clientData, unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime, unsigned durationInMicroseconds); void afterGettingFrame1(unsigned frameSize, struct timeval presentationTime); private: // Redefined virtual functions: void doGetNextFrame(); virtual void doStopGettingFrames(); private: class QCELPDeinterleavingBuffer* fDeinterleavingBuffer; Boolean fNeedAFrame; }; ////////// QCELPAudioRTPSource implementation ////////// FramedSource* QCELPAudioRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, RTPSource*& resultRTPSource, unsigned char rtpPayloadFormat, unsigned rtpTimestampFrequency) { RawQCELPRTPSource* rawRTPSource; resultRTPSource = rawRTPSource = RawQCELPRTPSource::createNew(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency); if (resultRTPSource == NULL) return NULL; QCELPDeinterleaver* deinterleaver = QCELPDeinterleaver::createNew(env, rawRTPSource); if (deinterleaver == NULL) { Medium::close(resultRTPSource); resultRTPSource = NULL; } return deinterleaver; } ////////// QCELPBufferedPacket and QCELPBufferedPacketFactory ////////// // A subclass of BufferedPacket, used to separate out QCELP frames. class QCELPBufferedPacket: public BufferedPacket { public: QCELPBufferedPacket(RawQCELPRTPSource& ourSource); virtual ~QCELPBufferedPacket(); private: // redefined virtual functions virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize); private: RawQCELPRTPSource& fOurSource; }; class QCELPBufferedPacketFactory: public BufferedPacketFactory { private: // redefined virtual functions virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); }; ///////// RawQCELPRTPSource implementation //////// RawQCELPRTPSource* RawQCELPRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat, unsigned rtpTimestampFrequency) { return new RawQCELPRTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency); } RawQCELPRTPSource::RawQCELPRTPSource(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat, unsigned rtpTimestampFrequency) : MultiFramedRTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency, new QCELPBufferedPacketFactory), fInterleaveL(0), fInterleaveN(0), fFrameIndex(0), fNumSuccessiveSyncedPackets(0) { } RawQCELPRTPSource::~RawQCELPRTPSource() { } Boolean RawQCELPRTPSource ::processSpecialHeader(BufferedPacket* packet, unsigned& resultSpecialHeaderSize) { unsigned char* headerStart = packet->data(); unsigned packetSize = packet->dataSize(); // First, check whether this packet's RTP timestamp is synchronized: if (RTPSource::hasBeenSynchronizedUsingRTCP()) { ++fNumSuccessiveSyncedPackets; } else { fNumSuccessiveSyncedPackets = 0; } // There's a 1-byte header indicating the interleave parameters if (packetSize < 1) return False; // Get the interleaving parameters from the 1-byte header, // and check them for validity: unsigned char const firstByte = headerStart[0]; unsigned char const interleaveL = (firstByte&0x38)>>3; unsigned char const interleaveN = firstByte&0x07; #ifdef DEBUG fprintf(stderr, "packetSize: %d, interleaveL: %d, interleaveN: %d\n", packetSize, interleaveL, interleaveN); #endif if (interleaveL > 5 || interleaveN > interleaveL) return False; //invalid fInterleaveL = interleaveL; fInterleaveN = interleaveN; fFrameIndex = 0; // initially resultSpecialHeaderSize = 1; return True; } char const* RawQCELPRTPSource::MIMEtype() const { return "audio/QCELP"; } Boolean RawQCELPRTPSource::hasBeenSynchronizedUsingRTCP() { // Don't report ourselves as being synchronized until we've received // at least a complete interleave cycle of synchronized packets. // This ensures that the receiver is currently getting a frame from // a packet that was synchronized. if (fNumSuccessiveSyncedPackets > (unsigned)(fInterleaveL+1)) { fNumSuccessiveSyncedPackets = fInterleaveL+2; // prevents overflow return True; } return False; } ///// QCELPBufferedPacket and QCELPBufferedPacketFactory implementation QCELPBufferedPacket::QCELPBufferedPacket(RawQCELPRTPSource& ourSource) : fOurSource(ourSource) { } QCELPBufferedPacket::~QCELPBufferedPacket() { } unsigned QCELPBufferedPacket:: nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) { // The size of the QCELP frame is determined by the first byte: if (dataSize == 0) return 0; // sanity check unsigned char const firstByte = framePtr[0]; unsigned frameSize; switch (firstByte) { case 0: { frameSize = 1; break; } case 1: { frameSize = 4; break; } case 2: { frameSize = 8; break; } case 3: { frameSize = 17; break; } case 4: { frameSize = 35; break; } default: { frameSize = 0; break; } } #ifdef DEBUG fprintf(stderr, "QCELPBufferedPacket::nextEnclosedFrameSize(): frameSize: %d, dataSize: %d\n", frameSize, dataSize); #endif if (dataSize < frameSize) return 0; ++fOurSource.frameIndex(); return frameSize; } BufferedPacket* QCELPBufferedPacketFactory ::createNewPacket(MultiFramedRTPSource* ourSource) { return new QCELPBufferedPacket((RawQCELPRTPSource&)(*ourSource)); } ///////// QCELPDeinterleavingBuffer ///////// // (used to implement QCELPDeinterleaver) #define QCELP_MAX_FRAME_SIZE 35 #define QCELP_MAX_INTERLEAVE_L 5 #define QCELP_MAX_FRAMES_PER_PACKET 10 #define QCELP_MAX_INTERLEAVE_GROUP_SIZE \ ((QCELP_MAX_INTERLEAVE_L+1)*QCELP_MAX_FRAMES_PER_PACKET) class QCELPDeinterleavingBuffer { public: QCELPDeinterleavingBuffer(); virtual ~QCELPDeinterleavingBuffer(); void deliverIncomingFrame(unsigned frameSize, unsigned char interleaveL, unsigned char interleaveN, unsigned char frameIndex, unsigned short packetSeqNum, struct timeval presentationTime); Boolean retrieveFrame(unsigned char* to, unsigned maxSize, unsigned& resultFrameSize, unsigned& resultNumTruncatedBytes, struct timeval& resultPresentationTime); unsigned char* inputBuffer() { return fInputBuffer; } unsigned inputBufferSize() const { return QCELP_MAX_FRAME_SIZE; } private: class FrameDescriptor { public: FrameDescriptor(); virtual ~FrameDescriptor(); unsigned frameSize; unsigned char* frameData; struct timeval presentationTime; }; // Use two banks of descriptors - one for incoming, one for outgoing FrameDescriptor fFrames[QCELP_MAX_INTERLEAVE_GROUP_SIZE][2]; unsigned char fIncomingBankId; // toggles between 0 and 1 unsigned char fIncomingBinMax; // in the incoming bank unsigned char fOutgoingBinMax; // in the outgoing bank unsigned char fNextOutgoingBin; Boolean fHaveSeenPackets; u_int16_t fLastPacketSeqNumForGroup; unsigned char* fInputBuffer; struct timeval fLastRetrievedPresentationTime; }; ////////// QCELPDeinterleaver implementation ///////// QCELPDeinterleaver* QCELPDeinterleaver::createNew(UsageEnvironment& env, RawQCELPRTPSource* inputSource) { return new QCELPDeinterleaver(env, inputSource); } QCELPDeinterleaver::QCELPDeinterleaver(UsageEnvironment& env, RawQCELPRTPSource* inputSource) : FramedFilter(env, inputSource), fNeedAFrame(False) { fDeinterleavingBuffer = new QCELPDeinterleavingBuffer(); } QCELPDeinterleaver::~QCELPDeinterleaver() { delete fDeinterleavingBuffer; } static unsigned const uSecsPerFrame = 20000; // 20 ms void QCELPDeinterleaver::doGetNextFrame() { // First, try getting a frame from the deinterleaving buffer: if (fDeinterleavingBuffer->retrieveFrame(fTo, fMaxSize, fFrameSize, fNumTruncatedBytes, fPresentationTime)) { // Success! fNeedAFrame = False; fDurationInMicroseconds = uSecsPerFrame; // Call our own 'after getting' function. Because we're not a 'leaf' // source, we can call this directly, without risking // infinite recursion afterGetting(this); return; } // No luck, so ask our source for help: fNeedAFrame = True; if (!fInputSource->isCurrentlyAwaitingData()) { fInputSource->getNextFrame(fDeinterleavingBuffer->inputBuffer(), fDeinterleavingBuffer->inputBufferSize(), afterGettingFrame, this, FramedSource::handleClosure, this); } } void QCELPDeinterleaver::doStopGettingFrames() { fNeedAFrame = False; fInputSource->stopGettingFrames(); } void QCELPDeinterleaver ::afterGettingFrame(void* clientData, unsigned frameSize, unsigned /*numTruncatedBytes*/, struct timeval presentationTime, unsigned /*durationInMicroseconds*/) { QCELPDeinterleaver* deinterleaver = (QCELPDeinterleaver*)clientData; deinterleaver->afterGettingFrame1(frameSize, presentationTime); } void QCELPDeinterleaver ::afterGettingFrame1(unsigned frameSize, struct timeval presentationTime) { RawQCELPRTPSource* source = (RawQCELPRTPSource*)fInputSource; // First, put the frame into our deinterleaving buffer: fDeinterleavingBuffer ->deliverIncomingFrame(frameSize, source->interleaveL(), source->interleaveN(), source->frameIndex(), source->curPacketRTPSeqNum(), presentationTime); // Then, try delivering a frame to the client (if he wants one): if (fNeedAFrame) doGetNextFrame(); } ////////// QCELPDeinterleavingBuffer implementation ///////// QCELPDeinterleavingBuffer::QCELPDeinterleavingBuffer() : fIncomingBankId(0), fIncomingBinMax(0), fOutgoingBinMax(0), fNextOutgoingBin(0), fHaveSeenPackets(False) { fInputBuffer = new unsigned char[QCELP_MAX_FRAME_SIZE]; } QCELPDeinterleavingBuffer::~QCELPDeinterleavingBuffer() { delete[] fInputBuffer; } void QCELPDeinterleavingBuffer ::deliverIncomingFrame(unsigned frameSize, unsigned char interleaveL, unsigned char interleaveN, unsigned char frameIndex, unsigned short packetSeqNum, struct timeval presentationTime) { // First perform a sanity check on the parameters: // (This is overkill, as the source should have already done this.) if (frameSize > QCELP_MAX_FRAME_SIZE || interleaveL > QCELP_MAX_INTERLEAVE_L || interleaveN > interleaveL || frameIndex == 0 || frameIndex > QCELP_MAX_FRAMES_PER_PACKET) { #ifdef DEBUG fprintf(stderr, "QCELPDeinterleavingBuffer::deliverIncomingFrame() param sanity check failed (%d,%d,%d,%d)\n", frameSize, interleaveL, interleaveN, frameIndex); #endif return; } // The input "presentationTime" was that of the first frame in this // packet. Update it for the current frame: unsigned uSecIncrement = (frameIndex-1)*(interleaveL+1)*uSecsPerFrame; presentationTime.tv_usec += uSecIncrement; presentationTime.tv_sec += presentationTime.tv_usec/1000000; presentationTime.tv_usec = presentationTime.tv_usec%1000000; // Next, check whether this packet is part of a new interleave group if (!fHaveSeenPackets || seqNumLT(fLastPacketSeqNumForGroup, packetSeqNum)) { // We've moved to a new interleave group fHaveSeenPackets = True; fLastPacketSeqNumForGroup = packetSeqNum + interleaveL - interleaveN; // Switch the incoming and outgoing banks: fIncomingBankId ^= 1; unsigned char tmp = fIncomingBinMax; fIncomingBinMax = fOutgoingBinMax; fOutgoingBinMax = tmp; fNextOutgoingBin = 0; } // Now move the incoming frame into the appropriate bin: unsigned const binNumber = interleaveN + (frameIndex-1)*(interleaveL+1); FrameDescriptor& inBin = fFrames[binNumber][fIncomingBankId]; unsigned char* curBuffer = inBin.frameData; inBin.frameData = fInputBuffer; inBin.frameSize = frameSize; inBin.presentationTime = presentationTime; if (curBuffer == NULL) curBuffer = new unsigned char[QCELP_MAX_FRAME_SIZE]; fInputBuffer = curBuffer; if (binNumber >= fIncomingBinMax) { fIncomingBinMax = binNumber + 1; } } Boolean QCELPDeinterleavingBuffer ::retrieveFrame(unsigned char* to, unsigned maxSize, unsigned& resultFrameSize, unsigned& resultNumTruncatedBytes, struct timeval& resultPresentationTime) { if (fNextOutgoingBin >= fOutgoingBinMax) return False; // none left FrameDescriptor& outBin = fFrames[fNextOutgoingBin][fIncomingBankId^1]; unsigned char* fromPtr; unsigned char fromSize = outBin.frameSize; outBin.frameSize = 0; // for the next time this bin is used // Check whether this frame is missing; if so, return an 'erasure' frame: unsigned char erasure = 14; if (fromSize == 0) { fromPtr = &erasure; fromSize = 1; // Compute this erasure frame's presentation time via extrapolation: resultPresentationTime = fLastRetrievedPresentationTime; resultPresentationTime.tv_usec += uSecsPerFrame; if (resultPresentationTime.tv_usec >= 1000000) { ++resultPresentationTime.tv_sec; resultPresentationTime.tv_usec -= 1000000; } } else { // Normal case - a frame exists: fromPtr = outBin.frameData; resultPresentationTime = outBin.presentationTime; } fLastRetrievedPresentationTime = resultPresentationTime; if (fromSize > maxSize) { resultNumTruncatedBytes = fromSize - maxSize; resultFrameSize = maxSize; } else { resultNumTruncatedBytes = 0; resultFrameSize = fromSize; } memmove(to, fromPtr, resultFrameSize); ++fNextOutgoingBin; return True; } QCELPDeinterleavingBuffer::FrameDescriptor::FrameDescriptor() : frameSize(0), frameData(NULL) { } QCELPDeinterleavingBuffer::FrameDescriptor::~FrameDescriptor() { delete[] frameData; }