/********** 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. // Vorbis Audio RTP Sources // Implementation #include "VorbisAudioRTPSource.hh" #include "Base64.hh" ////////// VorbisBufferedPacket and VorbisBufferedPacketFactory ////////// class VorbisBufferedPacket: public BufferedPacket { public: VorbisBufferedPacket(); virtual ~VorbisBufferedPacket(); private: // redefined virtual functions virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize); }; class VorbisBufferedPacketFactory: public BufferedPacketFactory { private: // redefined virtual functions virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); }; ///////// VorbisAudioRTPSource implementation //////// VorbisAudioRTPSource* VorbisAudioRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat, unsigned rtpTimestampFrequency) { return new VorbisAudioRTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency); } VorbisAudioRTPSource ::VorbisAudioRTPSource(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat, unsigned rtpTimestampFrequency) : MultiFramedRTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency, new VorbisBufferedPacketFactory), fCurPacketIdent(0) { } VorbisAudioRTPSource::~VorbisAudioRTPSource() { } Boolean VorbisAudioRTPSource ::processSpecialHeader(BufferedPacket* packet, unsigned& resultSpecialHeaderSize) { unsigned char* headerStart = packet->data(); unsigned packetSize = packet->dataSize(); resultSpecialHeaderSize = 4; if (packetSize < resultSpecialHeaderSize) return False; // packet was too small // The first 3 bytes of the header are the "Ident" field: fCurPacketIdent = (headerStart[0]<<16) | (headerStart[1]<<8) | headerStart[2]; // The 4th byte is F|VDT|numPkts. // Reject any packet with VDT == 3: if ((headerStart[3]&0x30) == 0x30) return False; u_int8_t F = headerStart[3]>>6; fCurrentPacketBeginsFrame = F <= 1; // "Not Fragmented" or "Start Fragment" fCurrentPacketCompletesFrame = F == 0 || F == 3; // "Not Fragmented" or "End Fragment" return True; } char const* VorbisAudioRTPSource::MIMEtype() const { return "audio/VORBIS"; } ////////// VorbisBufferedPacket and VorbisBufferedPacketFactory implementation ////////// VorbisBufferedPacket::VorbisBufferedPacket() { } VorbisBufferedPacket::~VorbisBufferedPacket() { } unsigned VorbisBufferedPacket ::nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) { if (dataSize < 2) { // There's not enough space for a 2-byte header. TARFU! Just return the data that's left: return dataSize; } unsigned frameSize = (framePtr[0]<<8) | framePtr[1]; framePtr += 2; if (frameSize > dataSize - 2) return dataSize - 2; // inconsistent frame size => just return all the data that's left return frameSize; } BufferedPacket* VorbisBufferedPacketFactory ::createNewPacket(MultiFramedRTPSource* /*ourSource*/) { return new VorbisBufferedPacket(); } ////////// parseVorbisOrTheoraConfigStr() implementation ////////// #define ADVANCE(n) do { p += (n); rem -= (n); } while (0) #define GET_ENCODED_VAL(n) do { u_int8_t byte; n = 0; do { if (rem == 0) break; byte = *p; n = (n*128) + (byte&0x7F); ADVANCE(1); } while (byte&0x80); } while (0); if (rem == 0) break void parseVorbisOrTheoraConfigStr(char const* configStr, u_int8_t*& identificationHdr, unsigned& identificationHdrSize, u_int8_t*& commentHdr, unsigned& commentHdrSize, u_int8_t*& setupHdr, unsigned& setupHdrSize, u_int32_t& identField) { identificationHdr = commentHdr = setupHdr = NULL; // default values, if an error occur identificationHdrSize = commentHdrSize = setupHdrSize = 0; // ditto identField = 0; // ditto // Begin by Base64-decoding the configuration string: unsigned configDataSize; u_int8_t* configData = base64Decode(configStr, configDataSize); u_int8_t* p = configData; unsigned rem = configDataSize; do { if (rem < 4) break; u_int32_t numPackedHeaders = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3]; ADVANCE(4); if (numPackedHeaders == 0) break; // Use the first 'packed header' only. if (rem < 3) break; identField = (p[0]<<16)|(p[1]<<8)|p[2]; ADVANCE(3); if (rem < 2) break; u_int16_t length = (p[0]<<8)|p[1]; ADVANCE(2); unsigned numHeaders; GET_ENCODED_VAL(numHeaders); Boolean success = False; for (unsigned i = 0; i < numHeaders+1 && i < 3; ++i) { success = False; unsigned headerSize; if (i < numHeaders) { // The header size is encoded: GET_ENCODED_VAL(headerSize); if (headerSize > length) break; length -= headerSize; } else { // The last header is implicit: headerSize = length; } // Allocate space for the header bytes; we'll fill it in later if (i == 0) { identificationHdrSize = headerSize; identificationHdr = new u_int8_t[identificationHdrSize]; } else if (i == 1) { commentHdrSize = headerSize; commentHdr = new u_int8_t[commentHdrSize]; } else { // i == 2 setupHdrSize = headerSize; setupHdr = new u_int8_t[setupHdrSize]; } success = True; } if (!success) break; // Copy the remaining config bytes into the appropriate 'header' buffers: if (identificationHdr != NULL) { memmove(identificationHdr, p, identificationHdrSize); ADVANCE(identificationHdrSize); if (commentHdr != NULL) { memmove(commentHdr, p, commentHdrSize); ADVANCE(commentHdrSize); if (setupHdr != NULL) { memmove(setupHdr, p, setupHdrSize); ADVANCE(setupHdrSize); } } } } while (0); delete[] configData; }