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 | // RTP sink for Vorbis audio |
19 | // Implementation |
20 | |
21 | #include "VorbisAudioRTPSink.hh" |
22 | #include "Base64.hh" |
23 | #include "VorbisAudioRTPSource.hh" // for parseVorbisOrTheoraConfigStr() |
24 | |
25 | VorbisAudioRTPSink* VorbisAudioRTPSink |
26 | ::createNew(UsageEnvironment& env, Groupsock* RTPgs, |
27 | u_int8_t rtpPayloadFormat, u_int32_t rtpTimestampFrequency, unsigned numChannels, |
28 | u_int8_t* , unsigned , |
29 | u_int8_t* , unsigned , |
30 | u_int8_t* , unsigned , |
31 | u_int32_t identField) { |
32 | return new VorbisAudioRTPSink(env, RTPgs, |
33 | rtpPayloadFormat, rtpTimestampFrequency, numChannels, |
34 | identificationHeader, identificationHeaderSize, |
35 | commentHeader, commentHeaderSize, |
36 | setupHeader, setupHeaderSize, |
37 | identField); |
38 | } |
39 | |
40 | VorbisAudioRTPSink* VorbisAudioRTPSink |
41 | ::createNew(UsageEnvironment& env, Groupsock* RTPgs,u_int8_t rtpPayloadFormat, |
42 | u_int32_t rtpTimestampFrequency, unsigned numChannels, |
43 | char const* configStr) { |
44 | // Begin by decoding and unpacking the configuration string: |
45 | u_int8_t* ; unsigned ; |
46 | u_int8_t* ; unsigned ; |
47 | u_int8_t* ; unsigned ; |
48 | u_int32_t identField; |
49 | |
50 | parseVorbisOrTheoraConfigStr(configStr, |
51 | identificationHeader, identificationHeaderSize, |
52 | commentHeader, commentHeaderSize, |
53 | setupHeader, setupHeaderSize, |
54 | identField); |
55 | |
56 | VorbisAudioRTPSink* resultSink |
57 | = new VorbisAudioRTPSink(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency, numChannels, |
58 | identificationHeader, identificationHeaderSize, |
59 | commentHeader, commentHeaderSize, |
60 | setupHeader, setupHeaderSize, |
61 | identField); |
62 | delete[] identificationHeader; delete[] commentHeader; delete[] setupHeader; |
63 | |
64 | return resultSink; |
65 | } |
66 | |
67 | VorbisAudioRTPSink |
68 | ::VorbisAudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs, u_int8_t rtpPayloadFormat, |
69 | u_int32_t rtpTimestampFrequency, unsigned numChannels, |
70 | u_int8_t* , unsigned , |
71 | u_int8_t* , unsigned , |
72 | u_int8_t* , unsigned , |
73 | u_int32_t identField) |
74 | : AudioRTPSink(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency, "VORBIS" , numChannels), |
75 | fIdent(identField), fFmtpSDPLine(NULL) { |
76 | if (identificationHeaderSize >= 28) { |
77 | // Get the 'bitrate' values from this header, and use them to set our estimated bitrate: |
78 | u_int32_t val; |
79 | u_int8_t* p; |
80 | |
81 | p = &identificationHeader[16]; |
82 | val = ((p[3]*256 + p[2])*256 + p[1])*256 + p[0]; // i.e., little-endian |
83 | int bitrate_maximum = (int)val; |
84 | if (bitrate_maximum < 0) bitrate_maximum = 0; |
85 | |
86 | p = &identificationHeader[20]; |
87 | val = ((p[3]*256 + p[2])*256 + p[1])*256 + p[0]; // i.e., little-endian |
88 | int bitrate_nominal = (int)val; |
89 | if (bitrate_nominal < 0) bitrate_nominal = 0; |
90 | |
91 | p = &identificationHeader[24]; |
92 | val = ((p[3]*256 + p[2])*256 + p[1])*256 + p[0]; // i.e., little-endian |
93 | int bitrate_minimum = (int)val; |
94 | if (bitrate_minimum < 0) bitrate_minimum = 0; |
95 | |
96 | int bitrate |
97 | = bitrate_nominal > 0 ? bitrate_nominal |
98 | : bitrate_maximum > 0 ? bitrate_maximum |
99 | : bitrate_minimum > 0 ? bitrate_minimum : 0; |
100 | if (bitrate > 0) estimatedBitrate() = ((unsigned)bitrate)/1000; |
101 | } |
102 | |
103 | // Generate a 'config' string from the supplied configuration headers: |
104 | char* |
105 | = generateVorbisOrTheoraConfigStr(identificationHeader, identificationHeaderSize, |
106 | commentHeader, commentHeaderSize, |
107 | setupHeader, setupHeaderSize, |
108 | identField); |
109 | if (base64PackedHeaders == NULL) return; |
110 | |
111 | // Then use this 'config' string to construct our "a=fmtp:" SDP line: |
112 | unsigned fmtpSDPLineMaxSize = 50 + strlen(base64PackedHeaders); // 50 => more than enough space |
113 | fFmtpSDPLine = new char[fmtpSDPLineMaxSize]; |
114 | sprintf(fFmtpSDPLine, "a=fmtp:%d configuration=%s\r\n" , rtpPayloadType(), base64PackedHeaders); |
115 | delete[] base64PackedHeaders; |
116 | } |
117 | |
118 | VorbisAudioRTPSink::~VorbisAudioRTPSink() { |
119 | delete[] fFmtpSDPLine; |
120 | } |
121 | |
122 | char const* VorbisAudioRTPSink::auxSDPLine() { |
123 | return fFmtpSDPLine; |
124 | } |
125 | |
126 | void VorbisAudioRTPSink |
127 | ::doSpecialFrameHandling(unsigned fragmentationOffset, |
128 | unsigned char* frameStart, |
129 | unsigned numBytesInFrame, |
130 | struct timeval framePresentationTime, |
131 | unsigned numRemainingBytes) { |
132 | // Set the 4-byte "payload header", as defined in RFC 5215, section 2.2: |
133 | u_int8_t [4]; |
134 | |
135 | // The first three bytes of the header are our "Ident": |
136 | header[0] = fIdent>>16; header[1] = fIdent>>8; header[2] = fIdent; |
137 | |
138 | // The final byte contains the "F", "VDT", and "numPkts" fields: |
139 | u_int8_t F; // Fragment type |
140 | if (numRemainingBytes > 0) { |
141 | if (fragmentationOffset > 0) { |
142 | F = 2<<6; // continuation fragment |
143 | } else { |
144 | F = 1<<6; // start fragment |
145 | } |
146 | } else { |
147 | if (fragmentationOffset > 0) { |
148 | F = 3<<6; // end fragment |
149 | } else { |
150 | F = 0<<6; // not fragmented |
151 | } |
152 | } |
153 | u_int8_t const VDT = 0<<4; // Vorbis Data Type (always a "Raw Vorbis payload") |
154 | u_int8_t numPkts = F == 0 ? (numFramesUsedSoFar() + 1): 0; // set to 0 when we're a fragment |
155 | header[3] = F|VDT|numPkts; |
156 | |
157 | setSpecialHeaderBytes(header, sizeof header); |
158 | |
159 | // There's also a 2-byte 'frame-specific' header: The length of the Vorbis data: |
160 | u_int8_t [2]; |
161 | frameSpecificHeader[0] = numBytesInFrame>>8; |
162 | frameSpecificHeader[1] = numBytesInFrame; |
163 | setFrameSpecificHeaderBytes(frameSpecificHeader, 2); |
164 | |
165 | // Important: Also call our base class's doSpecialFrameHandling(), |
166 | // to set the packet's timestamp: |
167 | MultiFramedRTPSink::doSpecialFrameHandling(fragmentationOffset, |
168 | frameStart, numBytesInFrame, |
169 | framePresentationTime, |
170 | numRemainingBytes); |
171 | } |
172 | |
173 | Boolean VorbisAudioRTPSink::frameCanAppearAfterPacketStart(unsigned char const* /*frameStart*/, |
174 | unsigned /*numBytesInFrame*/) const { |
175 | // We allow more than one frame to be packed into an outgoing RTP packet, but no more than 15: |
176 | return numFramesUsedSoFar() <= 15; |
177 | } |
178 | |
179 | unsigned VorbisAudioRTPSink::() const { |
180 | return 4; |
181 | } |
182 | |
183 | unsigned VorbisAudioRTPSink::() const { |
184 | return 2; |
185 | } |
186 | |
187 | |
188 | ////////// generateVorbisOrTheoraConfigStr() implementation ////////// |
189 | |
190 | char* generateVorbisOrTheoraConfigStr(u_int8_t* , unsigned , |
191 | u_int8_t* , unsigned , |
192 | u_int8_t* , unsigned , |
193 | u_int32_t identField) { |
194 | // First, count how many headers (<=3) are included, and how many bytes will be used |
195 | // to encode these headers' sizes: |
196 | unsigned = 0; |
197 | unsigned sizeSize[2]; // The number of bytes used to encode the lengths of the first two headers (but not the length of the 3rd) |
198 | sizeSize[0] = sizeSize[1] = 0; |
199 | if (identificationHeaderSize > 0) { |
200 | sizeSize[numHeaders++] = identificationHeaderSize < 128 ? 1 : identificationHeaderSize < 16384 ? 2 : 3; |
201 | } |
202 | if (commentHeaderSize > 0) { |
203 | sizeSize[numHeaders++] = commentHeaderSize < 128 ? 1 : commentHeaderSize < 16384 ? 2 : 3; |
204 | } |
205 | if (setupHeaderSize > 0) { |
206 | ++numHeaders; |
207 | } else { |
208 | sizeSize[1] = 0; // We have at most two headers, so the second one's length isn't encoded |
209 | } |
210 | if (numHeaders == 0) return NULL; // With no headers, we can't set up a configuration |
211 | if (numHeaders == 1) sizeSize[0] = 0; // With only one header, its length isn't encoded |
212 | |
213 | // Then figure out the size of the packed configuration headers, and allocate space for this: |
214 | unsigned length = identificationHeaderSize + commentHeaderSize + setupHeaderSize; |
215 | // The "length" field in the packed headers |
216 | if (length > (unsigned)0xFFFF) return NULL; // too big for a 16-bit field; we can't handle this |
217 | unsigned |
218 | = 4 // "Number of packed headers" field |
219 | + 3 // "ident" field |
220 | + 2 // "length" field |
221 | + 1 // "n. of headers" field |
222 | + sizeSize[0] + sizeSize[1] // "length1" and "length2" (if present) fields |
223 | + length; |
224 | u_int8_t* = new u_int8_t[packedHeadersSize]; |
225 | if (packedHeaders == NULL) return NULL; |
226 | |
227 | // Fill in the 'packed headers': |
228 | u_int8_t* p = packedHeaders; |
229 | *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 1; // "Number of packed headers": 1 |
230 | *p++ = identField>>16; *p++ = identField>>8; *p++ = identField; // "Ident" (24 bits) |
231 | *p++ = length>>8; *p++ = length; // "length" (16 bits) |
232 | *p++ = numHeaders-1; // "n. of headers" |
233 | if (numHeaders > 1) { |
234 | // Fill in the "length1" header: |
235 | unsigned length1 = identificationHeaderSize > 0 ? identificationHeaderSize : commentHeaderSize; |
236 | if (length1 >= 16384) { |
237 | *p++ = 0x80; // flag, but no more, because we know length1 <= 32767 |
238 | } |
239 | if (length1 >= 128) { |
240 | *p++ = 0x80|((length1&0x3F80)>>7); // flag + the second 7 bits |
241 | } |
242 | *p++ = length1&0x7F; // the low 7 bits |
243 | |
244 | if (numHeaders > 2) { // numHeaders == 3 |
245 | // Fill in the "length2" header (for the 'Comment' header): |
246 | unsigned length2 = commentHeaderSize; |
247 | if (length2 >= 16384) { |
248 | *p++ = 0x80; // flag, but no more, because we know length2 <= 32767 |
249 | } |
250 | if (length2 >= 128) { |
251 | *p++ = 0x80|((length2&0x3F80)>>7); // flag + the second 7 bits |
252 | } |
253 | *p++ = length2&0x7F; // the low 7 bits |
254 | } |
255 | } |
256 | // Copy each header: |
257 | if (identificationHeader != NULL) memmove(p, identificationHeader, identificationHeaderSize); p += identificationHeaderSize; |
258 | if (commentHeader != NULL) memmove(p, commentHeader, commentHeaderSize); p += commentHeaderSize; |
259 | if (setupHeader != NULL) memmove(p, setupHeader, setupHeaderSize); |
260 | |
261 | // Having set up the 'packed configuration headers', Base-64-encode this, for our result: |
262 | char* = base64Encode((char const*)packedHeaders, packedHeadersSize); |
263 | delete[] packedHeaders; |
264 | |
265 | return base64PackedHeaders; |
266 | } |
267 | |