1 /**********
2 This library is free software; you can redistribute it and/or modify it under
3 the terms of the GNU Lesser General Public License as published by the
4 Free Software Foundation; either version 3 of the License, or (at your
5 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
6 
7 This library is distributed in the hope that it will be useful, but WITHOUT
8 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
10 more details.
11 
12 You should have received a copy of the GNU Lesser General Public License
13 along with this library; if not, write to the Free Software Foundation, Inc.,
14 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
15 **********/
16 // "liveMedia"
17 // Copyright (c) 1996-2020 Live Networks, Inc.  All rights reserved.
18 // Vorbis Audio RTP Sources
19 // Implementation
20 
21 #include "VorbisAudioRTPSource.hh"
22 #include "Base64.hh"
23 
24 ////////// VorbisBufferedPacket and VorbisBufferedPacketFactory //////////
25 
26 class VorbisBufferedPacket: public BufferedPacket {
27 public:
28   VorbisBufferedPacket();
29   virtual ~VorbisBufferedPacket();
30 
31 private: // redefined virtual functions
32   virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr,
33 					 unsigned dataSize);
34 };
35 
36 class VorbisBufferedPacketFactory: public BufferedPacketFactory {
37 private: // redefined virtual functions
38   virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource);
39 };
40 
41 
42 ///////// VorbisAudioRTPSource implementation ////////
43 
44 VorbisAudioRTPSource*
createNew(UsageEnvironment & env,Groupsock * RTPgs,unsigned char rtpPayloadFormat,unsigned rtpTimestampFrequency)45 VorbisAudioRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs,
46 				unsigned char rtpPayloadFormat,
47 				unsigned rtpTimestampFrequency) {
48   return new VorbisAudioRTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency);
49 }
50 
51 VorbisAudioRTPSource
VorbisAudioRTPSource(UsageEnvironment & env,Groupsock * RTPgs,unsigned char rtpPayloadFormat,unsigned rtpTimestampFrequency)52 ::VorbisAudioRTPSource(UsageEnvironment& env, Groupsock* RTPgs,
53 		     unsigned char rtpPayloadFormat,
54 		     unsigned rtpTimestampFrequency)
55   : MultiFramedRTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency,
56 			 new VorbisBufferedPacketFactory),
57     fCurPacketIdent(0) {
58 }
59 
~VorbisAudioRTPSource()60 VorbisAudioRTPSource::~VorbisAudioRTPSource() {
61 }
62 
63 Boolean VorbisAudioRTPSource
processSpecialHeader(BufferedPacket * packet,unsigned & resultSpecialHeaderSize)64 ::processSpecialHeader(BufferedPacket* packet,
65                        unsigned& resultSpecialHeaderSize) {
66   unsigned char* headerStart = packet->data();
67   unsigned packetSize = packet->dataSize();
68 
69   resultSpecialHeaderSize = 4;
70   if (packetSize < resultSpecialHeaderSize) return False; // packet was too small
71 
72   // The first 3 bytes of the header are the "Ident" field:
73   fCurPacketIdent = (headerStart[0]<<16) | (headerStart[1]<<8) | headerStart[2];
74 
75   // The 4th byte is F|VDT|numPkts.
76   // Reject any packet with VDT == 3:
77   if ((headerStart[3]&0x30) == 0x30) return False;
78 
79   u_int8_t F = headerStart[3]>>6;
80   fCurrentPacketBeginsFrame = F <= 1; // "Not Fragmented" or "Start Fragment"
81   fCurrentPacketCompletesFrame = F == 0 || F == 3; // "Not Fragmented" or "End Fragment"
82 
83   return True;
84 }
85 
MIMEtype() const86 char const* VorbisAudioRTPSource::MIMEtype() const {
87   return "audio/VORBIS";
88 }
89 
90 
91 ////////// VorbisBufferedPacket and VorbisBufferedPacketFactory implementation //////////
92 
VorbisBufferedPacket()93 VorbisBufferedPacket::VorbisBufferedPacket() {
94 }
95 
~VorbisBufferedPacket()96 VorbisBufferedPacket::~VorbisBufferedPacket() {
97 }
98 
99 unsigned VorbisBufferedPacket
nextEnclosedFrameSize(unsigned char * & framePtr,unsigned dataSize)100 ::nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) {
101   if (dataSize < 2) {
102     // There's not enough space for a 2-byte header.  TARFU!  Just return the data that's left:
103     return dataSize;
104   }
105 
106   unsigned frameSize = (framePtr[0]<<8) | framePtr[1];
107   framePtr += 2;
108   if (frameSize > dataSize - 2) return dataSize - 2; // inconsistent frame size => just return all the data that's left
109 
110   return frameSize;
111 }
112 
113 BufferedPacket* VorbisBufferedPacketFactory
createNewPacket(MultiFramedRTPSource *)114 ::createNewPacket(MultiFramedRTPSource* /*ourSource*/) {
115   return new VorbisBufferedPacket();
116 }
117 
118 
119 ////////// parseVorbisOrTheoraConfigStr() implementation //////////
120 
121 #define ADVANCE(n) do { p += (n); rem -= (n); } while (0)
122 #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
123 
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)124 void parseVorbisOrTheoraConfigStr(char const* configStr,
125                                   u_int8_t*& identificationHdr, unsigned& identificationHdrSize,
126                                   u_int8_t*& commentHdr, unsigned& commentHdrSize,
127                                   u_int8_t*& setupHdr, unsigned& setupHdrSize,
128 				  u_int32_t& identField) {
129   identificationHdr = commentHdr = setupHdr = NULL; // default values, if an error occur
130   identificationHdrSize = commentHdrSize = setupHdrSize = 0; // ditto
131   identField = 0; // ditto
132 
133   // Begin by Base64-decoding the configuration string:
134   unsigned configDataSize;
135   u_int8_t* configData = base64Decode(configStr, configDataSize);
136   u_int8_t* p = configData;
137   unsigned rem = configDataSize;
138 
139   do {
140     if (rem < 4) break;
141     u_int32_t numPackedHeaders = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3]; ADVANCE(4);
142     if (numPackedHeaders == 0) break;
143 
144     // Use the first 'packed header' only.
145     if (rem < 3) break;
146     identField = (p[0]<<16)|(p[1]<<8)|p[2]; ADVANCE(3);
147 
148     if (rem < 2) break;
149     u_int16_t length = (p[0]<<8)|p[1]; ADVANCE(2);
150 
151     unsigned numHeaders;
152     GET_ENCODED_VAL(numHeaders);
153 
154     Boolean success = False;
155     for (unsigned i = 0; i < numHeaders+1 && i < 3; ++i) {
156       success = False;
157       unsigned headerSize;
158       if (i < numHeaders) {
159         // The header size is encoded:
160 	GET_ENCODED_VAL(headerSize);
161         if (headerSize > length) break;
162         length -= headerSize;
163       } else {
164 	// The last header is implicit:
165         headerSize = length;
166       }
167 
168       // Allocate space for the header bytes; we'll fill it in later
169       if (i == 0) {
170 	identificationHdrSize = headerSize;
171         identificationHdr = new u_int8_t[identificationHdrSize];
172       } else if (i == 1) {
173         commentHdrSize = headerSize;
174 	commentHdr = new u_int8_t[commentHdrSize];
175       } else { // i == 2
176         setupHdrSize = headerSize;
177         setupHdr = new u_int8_t[setupHdrSize];
178       }
179 
180       success = True;
181     }
182     if (!success) break;
183 
184     // Copy the remaining config bytes into the appropriate 'header' buffers:
185     if (identificationHdr != NULL) {
186       memmove(identificationHdr, p, identificationHdrSize); ADVANCE(identificationHdrSize);
187       if (commentHdr != NULL) {
188         memmove(commentHdr, p, commentHdrSize); ADVANCE(commentHdrSize);
189 	if (setupHdr != NULL) {
190           memmove(setupHdr, p, setupHdrSize); ADVANCE(setupHdrSize);
191         }
192       }
193     }
194   } while (0);
195 
196   delete[] configData;
197 }
198