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// A WAV audio file source
19// Implementation
20
21#include "WAVAudioFileSource.hh"
22#include "InputFile.hh"
23#include "GroupsockHelper.hh"
24
25////////// WAVAudioFileSource //////////
26
27WAVAudioFileSource*
28WAVAudioFileSource::createNew(UsageEnvironment& env, char const* fileName) {
29 do {
30 FILE* fid = OpenInputFile(env, fileName);
31 if (fid == NULL) break;
32
33 WAVAudioFileSource* newSource = new WAVAudioFileSource(env, fid);
34 if (newSource != NULL && newSource->bitsPerSample() == 0) {
35 // The WAV file header was apparently invalid.
36 Medium::close(newSource);
37 break;
38 }
39
40 newSource->fFileSize = (unsigned)GetFileSize(fileName, fid);
41
42 return newSource;
43 } while (0);
44
45 return NULL;
46}
47
48unsigned WAVAudioFileSource::numPCMBytes() const {
49 if (fFileSize < fWAVHeaderSize) return 0;
50 return fFileSize - fWAVHeaderSize;
51}
52
53void WAVAudioFileSource::setScaleFactor(int scale) {
54 if (!fFidIsSeekable) return; // we can't do 'trick play' operations on non-seekable files
55
56 fScaleFactor = scale;
57
58 if (fScaleFactor < 0 && TellFile64(fFid) > 0) {
59 // Because we're reading backwards, seek back one sample, to ensure that
60 // (i) we start reading the last sample before the start point, and
61 // (ii) we don't hit end-of-file on the first read.
62 int bytesPerSample = (fNumChannels*fBitsPerSample)/8;
63 if (bytesPerSample == 0) bytesPerSample = 1;
64 SeekFile64(fFid, -bytesPerSample, SEEK_CUR);
65 }
66}
67
68void WAVAudioFileSource::seekToPCMByte(unsigned byteNumber) {
69 byteNumber += fWAVHeaderSize;
70 if (byteNumber > fFileSize) byteNumber = fFileSize;
71
72 SeekFile64(fFid, byteNumber, SEEK_SET);
73}
74
75void WAVAudioFileSource::limitNumBytesToStream(unsigned numBytesToStream) {
76 fNumBytesToStream = numBytesToStream;
77 fLimitNumBytesToStream = fNumBytesToStream > 0;
78}
79
80unsigned char WAVAudioFileSource::getAudioFormat() {
81 return fAudioFormat;
82}
83
84
85#define nextc fgetc(fid)
86
87static Boolean get4Bytes(FILE* fid, u_int32_t& result) { // little-endian
88 int c0, c1, c2, c3;
89 if ((c0 = nextc) == EOF || (c1 = nextc) == EOF ||
90 (c2 = nextc) == EOF || (c3 = nextc) == EOF) return False;
91 result = (c3<<24)|(c2<<16)|(c1<<8)|c0;
92 return True;
93}
94
95static Boolean get2Bytes(FILE* fid, u_int16_t& result) {//little-endian
96 int c0, c1;
97 if ((c0 = nextc) == EOF || (c1 = nextc) == EOF) return False;
98 result = (c1<<8)|c0;
99 return True;
100}
101
102static Boolean skipBytes(FILE* fid, int num) {
103 while (num-- > 0) {
104 if (nextc == EOF) return False;
105 }
106 return True;
107}
108
109WAVAudioFileSource::WAVAudioFileSource(UsageEnvironment& env, FILE* fid)
110 : AudioInputDevice(env, 0, 0, 0, 0)/* set the real parameters later */,
111 fFid(fid), fFidIsSeekable(False), fLastPlayTime(0), fHaveStartedReading(False), fWAVHeaderSize(0), fFileSize(0),
112 fScaleFactor(1), fLimitNumBytesToStream(False), fNumBytesToStream(0), fAudioFormat(WA_UNKNOWN) {
113 // Check the WAV file header for validity.
114 // Note: The following web pages contain info about the WAV format:
115 // http://www.ringthis.com/dev/wave_format.htm
116 // http://www.lightlink.com/tjweber/StripWav/Canon.html
117 // http://www.onicos.com/staff/iz/formats/wav.html
118
119 Boolean success = False; // until we learn otherwise
120 do {
121 // RIFF Chunk:
122 if (nextc != 'R' || nextc != 'I' || nextc != 'F' || nextc != 'F') break;
123 if (!skipBytes(fid, 4)) break;
124 if (nextc != 'W' || nextc != 'A' || nextc != 'V' || nextc != 'E') break;
125
126 // Skip over any chunk that's not a FORMAT ('fmt ') chunk:
127 u_int32_t tmp;
128 if (!get4Bytes(fid, tmp)) break;
129 while (tmp != 0x20746d66/*'fmt ', little-endian*/) {
130 // Skip this chunk:
131 u_int32_t chunkLength;
132 if (!get4Bytes(fid, chunkLength)) break;
133 if (!skipBytes(fid, chunkLength)) break;
134 if (!get4Bytes(fid, tmp)) break;
135 }
136
137 // FORMAT Chunk (the 4-byte header code has already been parsed):
138 unsigned formatLength;
139 if (!get4Bytes(fid, formatLength)) break;
140 unsigned short audioFormat;
141 if (!get2Bytes(fid, audioFormat)) break;
142
143 fAudioFormat = (unsigned char)audioFormat;
144 if (fAudioFormat != WA_PCM && fAudioFormat != WA_PCMA && fAudioFormat != WA_PCMU && fAudioFormat != WA_IMA_ADPCM) {
145 // It's a format that we don't (yet) understand
146 env.setResultMsg("Audio format is not one that we handle (PCM/PCMU/PCMA or IMA ADPCM)");
147 break;
148 }
149 unsigned short numChannels;
150 if (!get2Bytes(fid, numChannels)) break;
151 fNumChannels = (unsigned char)numChannels;
152 if (fNumChannels < 1 || fNumChannels > 2) { // invalid # channels
153 char errMsg[100];
154 sprintf(errMsg, "Bad # channels: %d", fNumChannels);
155 env.setResultMsg(errMsg);
156 break;
157 }
158 if (!get4Bytes(fid, fSamplingFrequency)) break;
159 if (fSamplingFrequency == 0) {
160 env.setResultMsg("Bad sampling frequency: 0");
161 break;
162 }
163 if (!skipBytes(fid, 6)) break; // "nAvgBytesPerSec" (4 bytes) + "nBlockAlign" (2 bytes)
164 unsigned short bitsPerSample;
165 if (!get2Bytes(fid, bitsPerSample)) break;
166 fBitsPerSample = (unsigned char)bitsPerSample;
167 if (fBitsPerSample == 0) {
168 env.setResultMsg("Bad bits-per-sample: 0");
169 break;
170 }
171 if (!skipBytes(fid, formatLength - 16)) break;
172
173 // FACT chunk (optional):
174 int c = nextc;
175 if (c == 'f') {
176 if (nextc != 'a' || nextc != 'c' || nextc != 't') break;
177 unsigned factLength;
178 if (!get4Bytes(fid, factLength)) break;
179 if (!skipBytes(fid, factLength)) break;
180 c = nextc;
181 }
182
183 // EYRE chunk (optional):
184 if (c == 'e') {
185 if (nextc != 'y' || nextc != 'r' || nextc != 'e') break;
186 unsigned eyreLength;
187 if (!get4Bytes(fid, eyreLength)) break;
188 if (!skipBytes(fid, eyreLength)) break;
189 c = nextc;
190 }
191
192 // DATA Chunk:
193 if (c != 'd' || nextc != 'a' || nextc != 't' || nextc != 'a') break;
194 if (!skipBytes(fid, 4)) break;
195
196 // The header is good; the remaining data are the sample bytes.
197 fWAVHeaderSize = (unsigned)TellFile64(fid);
198 success = True;
199 } while (0);
200
201 if (!success) {
202 env.setResultMsg("Bad WAV file format");
203 // Set "fBitsPerSample" to zero, to indicate failure:
204 fBitsPerSample = 0;
205 return;
206 }
207
208 fPlayTimePerSample = 1e6/(double)fSamplingFrequency;
209
210 // Although PCM is a sample-based format, we group samples into
211 // 'frames' for efficient delivery to clients. Set up our preferred
212 // frame size to be close to 20 ms, if possible, but always no greater
213 // than 1400 bytes (to ensure that it will fit in a single RTP packet)
214 unsigned maxSamplesPerFrame = (1400*8)/(fNumChannels*fBitsPerSample);
215 unsigned desiredSamplesPerFrame = (unsigned)(0.02*fSamplingFrequency);
216 unsigned samplesPerFrame = desiredSamplesPerFrame < maxSamplesPerFrame ? desiredSamplesPerFrame : maxSamplesPerFrame;
217 fPreferredFrameSize = (samplesPerFrame*fNumChannels*fBitsPerSample)/8;
218
219 fFidIsSeekable = FileIsSeekable(fFid);
220#ifndef READ_FROM_FILES_SYNCHRONOUSLY
221 // Now that we've finished reading the WAV header, all future reads (of audio samples) from the file will be asynchronous:
222 makeSocketNonBlocking(fileno(fFid));
223#endif
224}
225
226WAVAudioFileSource::~WAVAudioFileSource() {
227 if (fFid == NULL) return;
228
229#ifndef READ_FROM_FILES_SYNCHRONOUSLY
230 envir().taskScheduler().turnOffBackgroundReadHandling(fileno(fFid));
231#endif
232
233 CloseInputFile(fFid);
234}
235
236void WAVAudioFileSource::doGetNextFrame() {
237 if (feof(fFid) || ferror(fFid) || (fLimitNumBytesToStream && fNumBytesToStream == 0)) {
238 handleClosure();
239 return;
240 }
241
242 fFrameSize = 0; // until it's set later
243#ifdef READ_FROM_FILES_SYNCHRONOUSLY
244 doReadFromFile();
245#else
246 if (!fHaveStartedReading) {
247 // Await readable data from the file:
248 envir().taskScheduler().turnOnBackgroundReadHandling(fileno(fFid),
249 (TaskScheduler::BackgroundHandlerProc*)&fileReadableHandler, this);
250 fHaveStartedReading = True;
251 }
252#endif
253}
254
255void WAVAudioFileSource::doStopGettingFrames() {
256 envir().taskScheduler().unscheduleDelayedTask(nextTask());
257#ifndef READ_FROM_FILES_SYNCHRONOUSLY
258 envir().taskScheduler().turnOffBackgroundReadHandling(fileno(fFid));
259 fHaveStartedReading = False;
260#endif
261}
262
263void WAVAudioFileSource::fileReadableHandler(WAVAudioFileSource* source, int /*mask*/) {
264 if (!source->isCurrentlyAwaitingData()) {
265 source->doStopGettingFrames(); // we're not ready for the data yet
266 return;
267 }
268 source->doReadFromFile();
269}
270
271void WAVAudioFileSource::doReadFromFile() {
272 // Try to read as many bytes as will fit in the buffer provided (or "fPreferredFrameSize" if less)
273 if (fLimitNumBytesToStream && fNumBytesToStream < fMaxSize) {
274 fMaxSize = fNumBytesToStream;
275 }
276 if (fPreferredFrameSize < fMaxSize) {
277 fMaxSize = fPreferredFrameSize;
278 }
279 unsigned bytesPerSample = (fNumChannels*fBitsPerSample)/8;
280 if (bytesPerSample == 0) bytesPerSample = 1; // because we can't read less than a byte at a time
281
282 // For 'trick play', read one sample at a time; otherwise (normal case) read samples in bulk:
283 unsigned bytesToRead = fScaleFactor == 1 ? fMaxSize - fMaxSize%bytesPerSample : bytesPerSample;
284 unsigned numBytesRead;
285 while (1) { // loop for 'trick play' only
286#ifdef READ_FROM_FILES_SYNCHRONOUSLY
287 numBytesRead = fread(fTo, 1, bytesToRead, fFid);
288#else
289 if (fFidIsSeekable) {
290 numBytesRead = fread(fTo, 1, bytesToRead, fFid);
291 } else {
292 // For non-seekable files (e.g., pipes), call "read()" rather than "fread()", to ensure that the read doesn't block:
293 numBytesRead = read(fileno(fFid), fTo, bytesToRead);
294 }
295#endif
296 if (numBytesRead == 0) {
297 handleClosure();
298 return;
299 }
300 fFrameSize += numBytesRead;
301 fTo += numBytesRead;
302 fMaxSize -= numBytesRead;
303 fNumBytesToStream -= numBytesRead;
304
305 // If we did an asynchronous read, and didn't read an integral number of samples, then we need to wait for another read:
306#ifndef READ_FROM_FILES_SYNCHRONOUSLY
307 if (fFrameSize%bytesPerSample > 0) return;
308#endif
309
310 // If we're doing 'trick play', then seek to the appropriate place for reading the next sample,
311 // and keep reading until we fill the provided buffer:
312 if (fScaleFactor != 1) {
313 SeekFile64(fFid, (fScaleFactor-1)*bytesPerSample, SEEK_CUR);
314 if (fMaxSize < bytesPerSample) break;
315 } else {
316 break; // from the loop (normal case)
317 }
318 }
319
320 // Set the 'presentation time' and 'duration' of this frame:
321 if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) {
322 // This is the first frame, so use the current time:
323 gettimeofday(&fPresentationTime, NULL);
324 } else {
325 // Increment by the play time of the previous data:
326 unsigned uSeconds = fPresentationTime.tv_usec + fLastPlayTime;
327 fPresentationTime.tv_sec += uSeconds/1000000;
328 fPresentationTime.tv_usec = uSeconds%1000000;
329 }
330
331 // Remember the play time of this data:
332 fDurationInMicroseconds = fLastPlayTime
333 = (unsigned)((fPlayTimePerSample*fFrameSize)/bytesPerSample);
334
335 // Inform the reader that he has data:
336#ifdef READ_FROM_FILES_SYNCHRONOUSLY
337 // To avoid possible infinite recursion, we need to return to the event loop to do this:
338 nextTask() = envir().taskScheduler().scheduleDelayedTask(0,
339 (TaskFunc*)FramedSource::afterGetting, this);
340#else
341 // Because the file read was done from the event loop, we can call the
342 // 'after getting' function directly, without risk of infinite recursion:
343 FramedSource::afterGetting(this);
344#endif
345}
346
347Boolean WAVAudioFileSource::setInputPort(int /*portIndex*/) {
348 return True;
349}
350
351double WAVAudioFileSource::getAverageLevel() const {
352 return 0.0;//##### fix this later
353}
354