/********** 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 3 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-2020 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; }