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// Qualcomm "PureVoice" (aka. "QCELP") Audio RTP Sources
19// Implementation
20
21#include "QCELPAudioRTPSource.hh"
22#include "MultiFramedRTPSource.hh"
23#include "FramedFilter.hh"
24#include <string.h>
25#include <stdlib.h>
26
27// This source is implemented internally by two separate sources:
28// (i) a RTP source for the raw (interleaved) QCELP frames, and
29// (ii) a deinterleaving filter that reads from this.
30// Define these two new classes here:
31
32class RawQCELPRTPSource: public MultiFramedRTPSource {
33public:
34 static RawQCELPRTPSource* createNew(UsageEnvironment& env,
35 Groupsock* RTPgs,
36 unsigned char rtpPayloadFormat,
37 unsigned rtpTimestampFrequency);
38
39 unsigned char interleaveL() const { return fInterleaveL; }
40 unsigned char interleaveN() const { return fInterleaveN; }
41 unsigned char& frameIndex() { return fFrameIndex; } // index within pkt
42
43private:
44 RawQCELPRTPSource(UsageEnvironment& env, Groupsock* RTPgs,
45 unsigned char rtpPayloadFormat,
46 unsigned rtpTimestampFrequency);
47 // called only by createNew()
48
49 virtual ~RawQCELPRTPSource();
50
51private:
52 // redefined virtual functions:
53 virtual Boolean processSpecialHeader(BufferedPacket* packet,
54 unsigned& resultSpecialHeaderSize);
55 virtual char const* MIMEtype() const;
56
57 virtual Boolean hasBeenSynchronizedUsingRTCP();
58
59private:
60 unsigned char fInterleaveL, fInterleaveN, fFrameIndex;
61 unsigned fNumSuccessiveSyncedPackets;
62};
63
64class QCELPDeinterleaver: public FramedFilter {
65public:
66 static QCELPDeinterleaver* createNew(UsageEnvironment& env,
67 RawQCELPRTPSource* inputSource);
68
69private:
70 QCELPDeinterleaver(UsageEnvironment& env,
71 RawQCELPRTPSource* inputSource);
72 // called only by "createNew()"
73
74 virtual ~QCELPDeinterleaver();
75
76 static void afterGettingFrame(void* clientData, unsigned frameSize,
77 unsigned numTruncatedBytes,
78 struct timeval presentationTime,
79 unsigned durationInMicroseconds);
80 void afterGettingFrame1(unsigned frameSize, struct timeval presentationTime);
81
82private:
83 // Redefined virtual functions:
84 void doGetNextFrame();
85 virtual void doStopGettingFrames();
86
87private:
88 class QCELPDeinterleavingBuffer* fDeinterleavingBuffer;
89 Boolean fNeedAFrame;
90};
91
92
93////////// QCELPAudioRTPSource implementation //////////
94
95FramedSource*
96QCELPAudioRTPSource::createNew(UsageEnvironment& env,
97 Groupsock* RTPgs,
98 RTPSource*& resultRTPSource,
99 unsigned char rtpPayloadFormat,
100 unsigned rtpTimestampFrequency) {
101 RawQCELPRTPSource* rawRTPSource;
102 resultRTPSource = rawRTPSource
103 = RawQCELPRTPSource::createNew(env, RTPgs, rtpPayloadFormat,
104 rtpTimestampFrequency);
105 if (resultRTPSource == NULL) return NULL;
106
107 QCELPDeinterleaver* deinterleaver
108 = QCELPDeinterleaver::createNew(env, rawRTPSource);
109 if (deinterleaver == NULL) {
110 Medium::close(resultRTPSource);
111 resultRTPSource = NULL;
112 }
113
114 return deinterleaver;
115}
116
117
118////////// QCELPBufferedPacket and QCELPBufferedPacketFactory //////////
119
120// A subclass of BufferedPacket, used to separate out QCELP frames.
121
122class QCELPBufferedPacket: public BufferedPacket {
123public:
124 QCELPBufferedPacket(RawQCELPRTPSource& ourSource);
125 virtual ~QCELPBufferedPacket();
126
127private: // redefined virtual functions
128 virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr,
129 unsigned dataSize);
130private:
131 RawQCELPRTPSource& fOurSource;
132};
133
134class QCELPBufferedPacketFactory: public BufferedPacketFactory {
135private: // redefined virtual functions
136 virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource);
137};
138
139
140///////// RawQCELPRTPSource implementation ////////
141
142RawQCELPRTPSource*
143RawQCELPRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs,
144 unsigned char rtpPayloadFormat,
145 unsigned rtpTimestampFrequency) {
146 return new RawQCELPRTPSource(env, RTPgs, rtpPayloadFormat,
147 rtpTimestampFrequency);
148}
149
150RawQCELPRTPSource::RawQCELPRTPSource(UsageEnvironment& env,
151 Groupsock* RTPgs,
152 unsigned char rtpPayloadFormat,
153 unsigned rtpTimestampFrequency)
154 : MultiFramedRTPSource(env, RTPgs, rtpPayloadFormat,
155 rtpTimestampFrequency,
156 new QCELPBufferedPacketFactory),
157 fInterleaveL(0), fInterleaveN(0), fFrameIndex(0),
158 fNumSuccessiveSyncedPackets(0) {
159}
160
161RawQCELPRTPSource::~RawQCELPRTPSource() {
162}
163
164Boolean RawQCELPRTPSource
165::processSpecialHeader(BufferedPacket* packet,
166 unsigned& resultSpecialHeaderSize) {
167 unsigned char* headerStart = packet->data();
168 unsigned packetSize = packet->dataSize();
169
170 // First, check whether this packet's RTP timestamp is synchronized:
171 if (RTPSource::hasBeenSynchronizedUsingRTCP()) {
172 ++fNumSuccessiveSyncedPackets;
173 } else {
174 fNumSuccessiveSyncedPackets = 0;
175 }
176
177 // There's a 1-byte header indicating the interleave parameters
178 if (packetSize < 1) return False;
179
180 // Get the interleaving parameters from the 1-byte header,
181 // and check them for validity:
182 unsigned char const firstByte = headerStart[0];
183 unsigned char const interleaveL = (firstByte&0x38)>>3;
184 unsigned char const interleaveN = firstByte&0x07;
185#ifdef DEBUG
186 fprintf(stderr, "packetSize: %d, interleaveL: %d, interleaveN: %d\n", packetSize, interleaveL, interleaveN);
187#endif
188 if (interleaveL > 5 || interleaveN > interleaveL) return False; //invalid
189
190 fInterleaveL = interleaveL;
191 fInterleaveN = interleaveN;
192 fFrameIndex = 0; // initially
193
194 resultSpecialHeaderSize = 1;
195 return True;
196}
197
198char const* RawQCELPRTPSource::MIMEtype() const {
199 return "audio/QCELP";
200}
201
202Boolean RawQCELPRTPSource::hasBeenSynchronizedUsingRTCP() {
203 // Don't report ourselves as being synchronized until we've received
204 // at least a complete interleave cycle of synchronized packets.
205 // This ensures that the receiver is currently getting a frame from
206 // a packet that was synchronized.
207 if (fNumSuccessiveSyncedPackets > (unsigned)(fInterleaveL+1)) {
208 fNumSuccessiveSyncedPackets = fInterleaveL+2; // prevents overflow
209 return True;
210 }
211 return False;
212}
213
214
215///// QCELPBufferedPacket and QCELPBufferedPacketFactory implementation
216
217QCELPBufferedPacket::QCELPBufferedPacket(RawQCELPRTPSource& ourSource)
218 : fOurSource(ourSource) {
219}
220
221QCELPBufferedPacket::~QCELPBufferedPacket() {
222}
223
224unsigned QCELPBufferedPacket::
225 nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) {
226 // The size of the QCELP frame is determined by the first byte:
227 if (dataSize == 0) return 0; // sanity check
228 unsigned char const firstByte = framePtr[0];
229
230 unsigned frameSize;
231 switch (firstByte) {
232 case 0: { frameSize = 1; break; }
233 case 1: { frameSize = 4; break; }
234 case 2: { frameSize = 8; break; }
235 case 3: { frameSize = 17; break; }
236 case 4: { frameSize = 35; break; }
237 default: { frameSize = 0; break; }
238 }
239
240#ifdef DEBUG
241 fprintf(stderr, "QCELPBufferedPacket::nextEnclosedFrameSize(): frameSize: %d, dataSize: %d\n", frameSize, dataSize);
242#endif
243 if (dataSize < frameSize) return 0;
244
245 ++fOurSource.frameIndex();
246 return frameSize;
247}
248
249BufferedPacket* QCELPBufferedPacketFactory
250::createNewPacket(MultiFramedRTPSource* ourSource) {
251 return new QCELPBufferedPacket((RawQCELPRTPSource&)(*ourSource));
252}
253
254///////// QCELPDeinterleavingBuffer /////////
255// (used to implement QCELPDeinterleaver)
256
257#define QCELP_MAX_FRAME_SIZE 35
258#define QCELP_MAX_INTERLEAVE_L 5
259#define QCELP_MAX_FRAMES_PER_PACKET 10
260#define QCELP_MAX_INTERLEAVE_GROUP_SIZE \
261 ((QCELP_MAX_INTERLEAVE_L+1)*QCELP_MAX_FRAMES_PER_PACKET)
262
263class QCELPDeinterleavingBuffer {
264public:
265 QCELPDeinterleavingBuffer();
266 virtual ~QCELPDeinterleavingBuffer();
267
268 void deliverIncomingFrame(unsigned frameSize,
269 unsigned char interleaveL,
270 unsigned char interleaveN,
271 unsigned char frameIndex,
272 unsigned short packetSeqNum,
273 struct timeval presentationTime);
274 Boolean retrieveFrame(unsigned char* to, unsigned maxSize,
275 unsigned& resultFrameSize, unsigned& resultNumTruncatedBytes,
276 struct timeval& resultPresentationTime);
277
278 unsigned char* inputBuffer() { return fInputBuffer; }
279 unsigned inputBufferSize() const { return QCELP_MAX_FRAME_SIZE; }
280
281private:
282 class FrameDescriptor {
283 public:
284 FrameDescriptor();
285 virtual ~FrameDescriptor();
286
287 unsigned frameSize;
288 unsigned char* frameData;
289 struct timeval presentationTime;
290 };
291
292 // Use two banks of descriptors - one for incoming, one for outgoing
293 FrameDescriptor fFrames[QCELP_MAX_INTERLEAVE_GROUP_SIZE][2];
294 unsigned char fIncomingBankId; // toggles between 0 and 1
295 unsigned char fIncomingBinMax; // in the incoming bank
296 unsigned char fOutgoingBinMax; // in the outgoing bank
297 unsigned char fNextOutgoingBin;
298 Boolean fHaveSeenPackets;
299 u_int16_t fLastPacketSeqNumForGroup;
300 unsigned char* fInputBuffer;
301 struct timeval fLastRetrievedPresentationTime;
302};
303
304
305////////// QCELPDeinterleaver implementation /////////
306
307QCELPDeinterleaver*
308QCELPDeinterleaver::createNew(UsageEnvironment& env,
309 RawQCELPRTPSource* inputSource) {
310 return new QCELPDeinterleaver(env, inputSource);
311}
312
313QCELPDeinterleaver::QCELPDeinterleaver(UsageEnvironment& env,
314 RawQCELPRTPSource* inputSource)
315 : FramedFilter(env, inputSource),
316 fNeedAFrame(False) {
317 fDeinterleavingBuffer = new QCELPDeinterleavingBuffer();
318}
319
320QCELPDeinterleaver::~QCELPDeinterleaver() {
321 delete fDeinterleavingBuffer;
322}
323
324static unsigned const uSecsPerFrame = 20000; // 20 ms
325
326void QCELPDeinterleaver::doGetNextFrame() {
327 // First, try getting a frame from the deinterleaving buffer:
328 if (fDeinterleavingBuffer->retrieveFrame(fTo, fMaxSize,
329 fFrameSize, fNumTruncatedBytes,
330 fPresentationTime)) {
331 // Success!
332 fNeedAFrame = False;
333
334 fDurationInMicroseconds = uSecsPerFrame;
335
336 // Call our own 'after getting' function. Because we're not a 'leaf'
337 // source, we can call this directly, without risking
338 // infinite recursion
339 afterGetting(this);
340 return;
341 }
342
343 // No luck, so ask our source for help:
344 fNeedAFrame = True;
345 if (!fInputSource->isCurrentlyAwaitingData()) {
346 fInputSource->getNextFrame(fDeinterleavingBuffer->inputBuffer(),
347 fDeinterleavingBuffer->inputBufferSize(),
348 afterGettingFrame, this,
349 FramedSource::handleClosure, this);
350 }
351}
352
353void QCELPDeinterleaver::doStopGettingFrames() {
354 fNeedAFrame = False;
355 fInputSource->stopGettingFrames();
356}
357
358void QCELPDeinterleaver
359::afterGettingFrame(void* clientData, unsigned frameSize,
360 unsigned /*numTruncatedBytes*/,
361 struct timeval presentationTime,
362 unsigned /*durationInMicroseconds*/) {
363 QCELPDeinterleaver* deinterleaver = (QCELPDeinterleaver*)clientData;
364 deinterleaver->afterGettingFrame1(frameSize, presentationTime);
365}
366
367void QCELPDeinterleaver
368::afterGettingFrame1(unsigned frameSize, struct timeval presentationTime) {
369 RawQCELPRTPSource* source = (RawQCELPRTPSource*)fInputSource;
370
371 // First, put the frame into our deinterleaving buffer:
372 fDeinterleavingBuffer
373 ->deliverIncomingFrame(frameSize, source->interleaveL(),
374 source->interleaveN(), source->frameIndex(),
375 source->curPacketRTPSeqNum(),
376 presentationTime);
377
378 // Then, try delivering a frame to the client (if he wants one):
379 if (fNeedAFrame) doGetNextFrame();
380}
381
382
383////////// QCELPDeinterleavingBuffer implementation /////////
384
385QCELPDeinterleavingBuffer::QCELPDeinterleavingBuffer()
386 : fIncomingBankId(0), fIncomingBinMax(0),
387 fOutgoingBinMax(0), fNextOutgoingBin(0),
388 fHaveSeenPackets(False) {
389 fInputBuffer = new unsigned char[QCELP_MAX_FRAME_SIZE];
390}
391
392QCELPDeinterleavingBuffer::~QCELPDeinterleavingBuffer() {
393 delete[] fInputBuffer;
394}
395
396void QCELPDeinterleavingBuffer
397::deliverIncomingFrame(unsigned frameSize,
398 unsigned char interleaveL,
399 unsigned char interleaveN,
400 unsigned char frameIndex,
401 unsigned short packetSeqNum,
402 struct timeval presentationTime) {
403 // First perform a sanity check on the parameters:
404 // (This is overkill, as the source should have already done this.)
405 if (frameSize > QCELP_MAX_FRAME_SIZE
406 || interleaveL > QCELP_MAX_INTERLEAVE_L || interleaveN > interleaveL
407 || frameIndex == 0 || frameIndex > QCELP_MAX_FRAMES_PER_PACKET) {
408#ifdef DEBUG
409 fprintf(stderr, "QCELPDeinterleavingBuffer::deliverIncomingFrame() param sanity check failed (%d,%d,%d,%d)\n", frameSize, interleaveL, interleaveN, frameIndex);
410#endif
411 return;
412 }
413
414 // The input "presentationTime" was that of the first frame in this
415 // packet. Update it for the current frame:
416 unsigned uSecIncrement = (frameIndex-1)*(interleaveL+1)*uSecsPerFrame;
417 presentationTime.tv_usec += uSecIncrement;
418 presentationTime.tv_sec += presentationTime.tv_usec/1000000;
419 presentationTime.tv_usec = presentationTime.tv_usec%1000000;
420
421 // Next, check whether this packet is part of a new interleave group
422 if (!fHaveSeenPackets
423 || seqNumLT(fLastPacketSeqNumForGroup, packetSeqNum)) {
424 // We've moved to a new interleave group
425 fHaveSeenPackets = True;
426 fLastPacketSeqNumForGroup = packetSeqNum + interleaveL - interleaveN;
427
428 // Switch the incoming and outgoing banks:
429 fIncomingBankId ^= 1;
430 unsigned char tmp = fIncomingBinMax;
431 fIncomingBinMax = fOutgoingBinMax;
432 fOutgoingBinMax = tmp;
433 fNextOutgoingBin = 0;
434 }
435
436 // Now move the incoming frame into the appropriate bin:
437 unsigned const binNumber
438 = interleaveN + (frameIndex-1)*(interleaveL+1);
439 FrameDescriptor& inBin = fFrames[binNumber][fIncomingBankId];
440 unsigned char* curBuffer = inBin.frameData;
441 inBin.frameData = fInputBuffer;
442 inBin.frameSize = frameSize;
443 inBin.presentationTime = presentationTime;
444
445 if (curBuffer == NULL) curBuffer = new unsigned char[QCELP_MAX_FRAME_SIZE];
446 fInputBuffer = curBuffer;
447
448 if (binNumber >= fIncomingBinMax) {
449 fIncomingBinMax = binNumber + 1;
450 }
451}
452
453Boolean QCELPDeinterleavingBuffer
454::retrieveFrame(unsigned char* to, unsigned maxSize,
455 unsigned& resultFrameSize, unsigned& resultNumTruncatedBytes,
456 struct timeval& resultPresentationTime) {
457 if (fNextOutgoingBin >= fOutgoingBinMax) return False; // none left
458
459 FrameDescriptor& outBin = fFrames[fNextOutgoingBin][fIncomingBankId^1];
460 unsigned char* fromPtr;
461 unsigned char fromSize = outBin.frameSize;
462 outBin.frameSize = 0; // for the next time this bin is used
463
464 // Check whether this frame is missing; if so, return an 'erasure' frame:
465 unsigned char erasure = 14;
466 if (fromSize == 0) {
467 fromPtr = &erasure;
468 fromSize = 1;
469
470 // Compute this erasure frame's presentation time via extrapolation:
471 resultPresentationTime = fLastRetrievedPresentationTime;
472 resultPresentationTime.tv_usec += uSecsPerFrame;
473 if (resultPresentationTime.tv_usec >= 1000000) {
474 ++resultPresentationTime.tv_sec;
475 resultPresentationTime.tv_usec -= 1000000;
476 }
477 } else {
478 // Normal case - a frame exists:
479 fromPtr = outBin.frameData;
480 resultPresentationTime = outBin.presentationTime;
481 }
482
483 fLastRetrievedPresentationTime = resultPresentationTime;
484
485 if (fromSize > maxSize) {
486 resultNumTruncatedBytes = fromSize - maxSize;
487 resultFrameSize = maxSize;
488 } else {
489 resultNumTruncatedBytes = 0;
490 resultFrameSize = fromSize;
491 }
492 memmove(to, fromPtr, resultFrameSize);
493
494 ++fNextOutgoingBin;
495 return True;
496}
497
498QCELPDeinterleavingBuffer::FrameDescriptor::FrameDescriptor()
499 : frameSize(0), frameData(NULL) {
500}
501
502QCELPDeinterleavingBuffer::FrameDescriptor::~FrameDescriptor() {
503 delete[] frameData;
504}
505