1/**********
2This library is free software; you can redistribute it and/or modify it under
3the terms of the GNU Lesser General Public License as published by the
4Free Software Foundation; either version 3 of the License, or (at your
5option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
6
7This library is distributed in the hope that it will be useful, but WITHOUT
8ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
10more details.
11
12You should have received a copy of the GNU Lesser General Public License
13along with this library; if not, write to the Free Software Foundation, Inc.,
1451 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
26class VorbisBufferedPacket: public BufferedPacket {
27public:
28 VorbisBufferedPacket();
29 virtual ~VorbisBufferedPacket();
30
31private: // redefined virtual functions
32 virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr,
33 unsigned dataSize);
34};
35
36class VorbisBufferedPacketFactory: public BufferedPacketFactory {
37private: // redefined virtual functions
38 virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource);
39};
40
41
42///////// VorbisAudioRTPSource implementation ////////
43
44VorbisAudioRTPSource*
45VorbisAudioRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs,
46 unsigned char rtpPayloadFormat,
47 unsigned rtpTimestampFrequency) {
48 return new VorbisAudioRTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency);
49}
50
51VorbisAudioRTPSource
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
60VorbisAudioRTPSource::~VorbisAudioRTPSource() {
61}
62
63Boolean VorbisAudioRTPSource
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
86char const* VorbisAudioRTPSource::MIMEtype() const {
87 return "audio/VORBIS";
88}
89
90
91////////// VorbisBufferedPacket and VorbisBufferedPacketFactory implementation //////////
92
93VorbisBufferedPacket::VorbisBufferedPacket() {
94}
95
96VorbisBufferedPacket::~VorbisBufferedPacket() {
97}
98
99unsigned VorbisBufferedPacket
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
113BufferedPacket* VorbisBufferedPacketFactory
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
124void 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