Line data Source code
1 : /*
2 : * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 : *
4 : * Use of this source code is governed by a BSD-style license
5 : * that can be found in the LICENSE file in the root of the source
6 : * tree. An additional intellectual property rights grant can be found
7 : * in the file PATENTS. All contributing project authors may
8 : * be found in the AUTHORS file in the root of the source tree.
9 : */
10 :
11 : #include "webrtc/modules/media_file/media_file_utility.h"
12 :
13 : #include <assert.h>
14 : #include <sys/stat.h>
15 : #include <sys/types.h>
16 : #include <limits>
17 :
18 : #include "webrtc/base/format_macros.h"
19 : #include "webrtc/common_audio/wav_header.h"
20 : #include "webrtc/common_types.h"
21 : #include "webrtc/modules/include/module_common_types.h"
22 : #include "webrtc/system_wrappers/include/file_wrapper.h"
23 : #include "webrtc/system_wrappers/include/trace.h"
24 : #include "webrtc/typedefs.h"
25 :
26 : namespace {
27 :
28 : // First 16 bytes the WAVE header. ckID should be "RIFF", wave_ckID should be
29 : // "WAVE" and ckSize is the chunk size (4 + n)
30 : struct WAVE_RIFF_header
31 : {
32 : int8_t ckID[4];
33 : int32_t ckSize;
34 : int8_t wave_ckID[4];
35 : };
36 :
37 : // First 8 byte of the format chunk. fmt_ckID should be "fmt ". fmt_ckSize is
38 : // the chunk size (16, 18 or 40 byte)
39 : struct WAVE_CHUNK_header
40 : {
41 : int8_t fmt_ckID[4];
42 : uint32_t fmt_ckSize;
43 : };
44 : } // unnamed namespace
45 :
46 : namespace webrtc {
47 0 : ModuleFileUtility::ModuleFileUtility(const int32_t id)
48 : : _wavFormatObj(),
49 : _dataSize(0),
50 : _readSizeBytes(0),
51 : _id(id),
52 : _stopPointInMs(0),
53 : _startPointInMs(0),
54 : _playoutPositionMs(0),
55 : _bytesWritten(0),
56 : codec_info_(),
57 : _codecId(kCodecNoCodec),
58 : _bytesPerSample(0),
59 : _readPos(0),
60 : _reading(false),
61 : _writing(false),
62 0 : _tempData() {
63 : WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
64 : "ModuleFileUtility::ModuleFileUtility()");
65 0 : memset(&codec_info_,0,sizeof(CodecInst));
66 0 : codec_info_.pltype = -1;
67 0 : }
68 :
69 0 : ModuleFileUtility::~ModuleFileUtility()
70 : {
71 : WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
72 : "ModuleFileUtility::~ModuleFileUtility()");
73 0 : }
74 :
75 0 : int32_t ModuleFileUtility::ReadWavHeader(InStream& wav)
76 : {
77 : WAVE_RIFF_header RIFFheaderObj;
78 : WAVE_CHUNK_header CHUNKheaderObj;
79 : // TODO (hellner): tmpStr and tmpStr2 seems unnecessary here.
80 0 : char tmpStr[6] = "FOUR";
81 : unsigned char tmpStr2[4];
82 : size_t i;
83 0 : bool dataFound = false;
84 0 : bool fmtFound = false;
85 : int8_t dummyRead;
86 :
87 :
88 0 : _dataSize = 0;
89 0 : int len = wav.Read(&RIFFheaderObj, sizeof(WAVE_RIFF_header));
90 0 : if (len != static_cast<int>(sizeof(WAVE_RIFF_header)))
91 : {
92 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
93 : "Not a wave file (too short)");
94 0 : return -1;
95 : }
96 :
97 0 : for (i = 0; i < 4; i++)
98 : {
99 0 : tmpStr[i] = RIFFheaderObj.ckID[i];
100 : }
101 0 : if(strcmp(tmpStr, "RIFF") != 0)
102 : {
103 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
104 : "Not a wave file (does not have RIFF)");
105 0 : return -1;
106 : }
107 0 : for (i = 0; i < 4; i++)
108 : {
109 0 : tmpStr[i] = RIFFheaderObj.wave_ckID[i];
110 : }
111 0 : if(strcmp(tmpStr, "WAVE") != 0)
112 : {
113 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
114 : "Not a wave file (does not have WAVE)");
115 0 : return -1;
116 : }
117 :
118 0 : len = wav.Read(&CHUNKheaderObj, sizeof(WAVE_CHUNK_header));
119 :
120 : // WAVE files are stored in little endian byte order. Make sure that the
121 : // data can be read on big endian as well.
122 : // TODO (hellner): little endian to system byte order should be done in
123 : // in a subroutine.
124 0 : memcpy(tmpStr2, &CHUNKheaderObj.fmt_ckSize, 4);
125 0 : CHUNKheaderObj.fmt_ckSize =
126 0 : (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8) +
127 0 : (((uint32_t)tmpStr2[2]) << 16) + (((uint32_t)tmpStr2[3]) << 24);
128 :
129 0 : memcpy(tmpStr, CHUNKheaderObj.fmt_ckID, 4);
130 :
131 0 : while ((len == static_cast<int>(sizeof(WAVE_CHUNK_header))) &&
132 0 : (!fmtFound || !dataFound))
133 : {
134 0 : if(strcmp(tmpStr, "fmt ") == 0)
135 : {
136 0 : len = wav.Read(&_wavFormatObj, sizeof(WAVE_FMTINFO_header));
137 :
138 0 : memcpy(tmpStr2, &_wavFormatObj.formatTag, 2);
139 0 : _wavFormatObj.formatTag =
140 0 : (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1])<<8);
141 0 : memcpy(tmpStr2, &_wavFormatObj.nChannels, 2);
142 0 : _wavFormatObj.nChannels =
143 0 : (int16_t) ((uint32_t)tmpStr2[0] +
144 0 : (((uint32_t)tmpStr2[1])<<8));
145 0 : memcpy(tmpStr2, &_wavFormatObj.nSamplesPerSec, 4);
146 0 : _wavFormatObj.nSamplesPerSec =
147 0 : (int32_t) ((uint32_t)tmpStr2[0] +
148 0 : (((uint32_t)tmpStr2[1])<<8) +
149 0 : (((uint32_t)tmpStr2[2])<<16) +
150 0 : (((uint32_t)tmpStr2[3])<<24));
151 0 : memcpy(tmpStr2, &_wavFormatObj.nAvgBytesPerSec, 4);
152 0 : _wavFormatObj.nAvgBytesPerSec =
153 0 : (int32_t) ((uint32_t)tmpStr2[0] +
154 0 : (((uint32_t)tmpStr2[1])<<8) +
155 0 : (((uint32_t)tmpStr2[2])<<16) +
156 0 : (((uint32_t)tmpStr2[3])<<24));
157 0 : memcpy(tmpStr2, &_wavFormatObj.nBlockAlign, 2);
158 0 : _wavFormatObj.nBlockAlign =
159 0 : (int16_t) ((uint32_t)tmpStr2[0] +
160 0 : (((uint32_t)tmpStr2[1])<<8));
161 0 : memcpy(tmpStr2, &_wavFormatObj.nBitsPerSample, 2);
162 0 : _wavFormatObj.nBitsPerSample =
163 0 : (int16_t) ((uint32_t)tmpStr2[0] +
164 0 : (((uint32_t)tmpStr2[1])<<8));
165 :
166 0 : if (CHUNKheaderObj.fmt_ckSize < sizeof(WAVE_FMTINFO_header))
167 : {
168 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
169 : "Chunk size is too small");
170 0 : return -1;
171 : }
172 0 : for (i = 0;
173 0 : i < CHUNKheaderObj.fmt_ckSize - sizeof(WAVE_FMTINFO_header);
174 : i++)
175 : {
176 0 : len = wav.Read(&dummyRead, 1);
177 0 : if(len != 1)
178 : {
179 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
180 : "File corrupted, reached EOF (reading fmt)");
181 0 : return -1;
182 : }
183 : }
184 0 : fmtFound = true;
185 : }
186 0 : else if(strcmp(tmpStr, "data") == 0)
187 : {
188 0 : _dataSize = CHUNKheaderObj.fmt_ckSize;
189 0 : dataFound = true;
190 0 : break;
191 : }
192 : else
193 : {
194 0 : for (i = 0; i < CHUNKheaderObj.fmt_ckSize; i++)
195 : {
196 0 : len = wav.Read(&dummyRead, 1);
197 0 : if(len != 1)
198 : {
199 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
200 : "File corrupted, reached EOF (reading other)");
201 0 : return -1;
202 : }
203 : }
204 : }
205 :
206 0 : len = wav.Read(&CHUNKheaderObj, sizeof(WAVE_CHUNK_header));
207 :
208 0 : memcpy(tmpStr2, &CHUNKheaderObj.fmt_ckSize, 4);
209 0 : CHUNKheaderObj.fmt_ckSize =
210 0 : (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8) +
211 0 : (((uint32_t)tmpStr2[2]) << 16) + (((uint32_t)tmpStr2[3]) << 24);
212 :
213 0 : memcpy(tmpStr, CHUNKheaderObj.fmt_ckID, 4);
214 : }
215 :
216 : // Either a proper format chunk has been read or a data chunk was come
217 : // across.
218 0 : if( (_wavFormatObj.formatTag != kWavFormatPcm) &&
219 0 : (_wavFormatObj.formatTag != kWavFormatALaw) &&
220 0 : (_wavFormatObj.formatTag != kWavFormatMuLaw))
221 : {
222 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
223 : "Coding formatTag value=%d not supported!",
224 : _wavFormatObj.formatTag);
225 0 : return -1;
226 : }
227 0 : if((_wavFormatObj.nChannels < 1) ||
228 0 : (_wavFormatObj.nChannels > 2))
229 : {
230 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
231 : "nChannels value=%d not supported!",
232 : _wavFormatObj.nChannels);
233 0 : return -1;
234 : }
235 :
236 0 : if((_wavFormatObj.nBitsPerSample != 8) &&
237 0 : (_wavFormatObj.nBitsPerSample != 16))
238 : {
239 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
240 : "nBitsPerSample value=%d not supported!",
241 : _wavFormatObj.nBitsPerSample);
242 0 : return -1;
243 : }
244 :
245 : // Calculate the number of bytes that 10 ms of audio data correspond to.
246 : size_t samples_per_10ms =
247 0 : ((_wavFormatObj.formatTag == kWavFormatPcm) &&
248 0 : (_wavFormatObj.nSamplesPerSec == 44100)) ?
249 0 : 440 : static_cast<size_t>(_wavFormatObj.nSamplesPerSec / 100);
250 0 : _readSizeBytes = samples_per_10ms * _wavFormatObj.nChannels *
251 0 : (_wavFormatObj.nBitsPerSample / 8);
252 0 : return 0;
253 : }
254 :
255 0 : int32_t ModuleFileUtility::InitWavCodec(uint32_t samplesPerSec,
256 : size_t channels,
257 : uint32_t bitsPerSample,
258 : uint32_t formatTag)
259 : {
260 0 : codec_info_.pltype = -1;
261 0 : codec_info_.plfreq = samplesPerSec;
262 0 : codec_info_.channels = channels;
263 0 : codec_info_.rate = bitsPerSample * samplesPerSec;
264 :
265 : // Calculate the packet size for 10ms frames
266 0 : switch(formatTag)
267 : {
268 : case kWavFormatALaw:
269 0 : strcpy(codec_info_.plname, "PCMA");
270 0 : _codecId = kCodecPcma;
271 0 : codec_info_.pltype = 8;
272 0 : codec_info_.pacsize = codec_info_.plfreq / 100;
273 0 : break;
274 : case kWavFormatMuLaw:
275 0 : strcpy(codec_info_.plname, "PCMU");
276 0 : _codecId = kCodecPcmu;
277 0 : codec_info_.pltype = 0;
278 0 : codec_info_.pacsize = codec_info_.plfreq / 100;
279 0 : break;
280 : case kWavFormatPcm:
281 0 : codec_info_.pacsize = (bitsPerSample * (codec_info_.plfreq / 100)) / 8;
282 0 : if(samplesPerSec == 8000)
283 : {
284 0 : strcpy(codec_info_.plname, "L16");
285 0 : _codecId = kCodecL16_8Khz;
286 : }
287 0 : else if(samplesPerSec == 16000)
288 : {
289 0 : strcpy(codec_info_.plname, "L16");
290 0 : _codecId = kCodecL16_16kHz;
291 : }
292 0 : else if(samplesPerSec == 32000)
293 : {
294 0 : strcpy(codec_info_.plname, "L16");
295 0 : _codecId = kCodecL16_32Khz;
296 : }
297 : // Set the packet size for "odd" sampling frequencies so that it
298 : // properly corresponds to _readSizeBytes.
299 0 : else if(samplesPerSec == 11025)
300 : {
301 0 : strcpy(codec_info_.plname, "L16");
302 0 : _codecId = kCodecL16_16kHz;
303 0 : codec_info_.pacsize = 110; // XXX inexact!
304 0 : codec_info_.plfreq = 11000; // XXX inexact!
305 : }
306 0 : else if(samplesPerSec == 22050)
307 : {
308 0 : strcpy(codec_info_.plname, "L16");
309 0 : _codecId = kCodecL16_16kHz;
310 0 : codec_info_.pacsize = 220; // XXX inexact!
311 0 : codec_info_.plfreq = 22000; // XXX inexact!
312 : }
313 0 : else if(samplesPerSec == 44100)
314 : {
315 0 : strcpy(codec_info_.plname, "L16");
316 0 : _codecId = kCodecL16_16kHz;
317 0 : codec_info_.pacsize = 441;
318 0 : codec_info_.plfreq = 44100;
319 : }
320 0 : else if(samplesPerSec == 48000)
321 : {
322 0 : strcpy(codec_info_.plname, "L16");
323 0 : _codecId = kCodecL16_16kHz;
324 0 : codec_info_.pacsize = 480;
325 0 : codec_info_.plfreq = 48000;
326 : }
327 : else
328 : {
329 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
330 : "Unsupported PCM frequency!");
331 0 : return -1;
332 : }
333 0 : break;
334 : default:
335 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
336 : "unknown WAV format TAG!");
337 0 : return -1;
338 : break;
339 : }
340 0 : return 0;
341 : }
342 :
343 0 : int32_t ModuleFileUtility::InitWavReading(InStream& wav,
344 : const uint32_t start,
345 : const uint32_t stop)
346 : {
347 :
348 0 : _reading = false;
349 :
350 0 : if(ReadWavHeader(wav) == -1)
351 : {
352 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
353 : "failed to read WAV header!");
354 0 : return -1;
355 : }
356 :
357 0 : _playoutPositionMs = 0;
358 0 : _readPos = 0;
359 :
360 0 : if(start > 0)
361 : {
362 : uint8_t dummy[WAV_MAX_BUFFER_SIZE];
363 : int readLength;
364 0 : if(_readSizeBytes <= WAV_MAX_BUFFER_SIZE)
365 : {
366 0 : while (_playoutPositionMs < start)
367 : {
368 0 : readLength = wav.Read(dummy, _readSizeBytes);
369 0 : if(readLength == static_cast<int>(_readSizeBytes))
370 : {
371 0 : _readPos += _readSizeBytes;
372 0 : _playoutPositionMs += 10;
373 : }
374 : else // Must have reached EOF before start position!
375 : {
376 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
377 : "InitWavReading(), EOF before start position");
378 0 : return -1;
379 : }
380 : }
381 : }
382 : else
383 : {
384 0 : return -1;
385 : }
386 : }
387 0 : if( InitWavCodec(_wavFormatObj.nSamplesPerSec, _wavFormatObj.nChannels,
388 0 : _wavFormatObj.nBitsPerSample,
389 0 : _wavFormatObj.formatTag) != 0)
390 : {
391 0 : return -1;
392 : }
393 0 : _bytesPerSample = static_cast<size_t>(_wavFormatObj.nBitsPerSample / 8);
394 :
395 :
396 0 : _startPointInMs = start;
397 0 : _stopPointInMs = stop;
398 0 : _reading = true;
399 0 : return 0;
400 : }
401 :
402 0 : int32_t ModuleFileUtility::ReadWavDataAsMono(
403 : InStream& wav,
404 : int8_t* outData,
405 : const size_t bufferSize)
406 : {
407 : WEBRTC_TRACE(
408 : kTraceStream,
409 : kTraceFile,
410 : _id,
411 : "ModuleFileUtility::ReadWavDataAsMono(wav= 0x%x, outData= 0x%d, "
412 : "bufSize= %" PRIuS ")",
413 : &wav,
414 : outData,
415 : bufferSize);
416 :
417 : // The number of bytes that should be read from file.
418 0 : const size_t totalBytesNeeded = _readSizeBytes;
419 : // The number of bytes that will be written to outData.
420 0 : const size_t bytesRequested = (codec_info_.channels == 2) ?
421 0 : totalBytesNeeded >> 1 : totalBytesNeeded;
422 0 : if(bufferSize < bytesRequested)
423 : {
424 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
425 : "ReadWavDataAsMono: output buffer is too short!");
426 0 : return -1;
427 : }
428 0 : if(outData == NULL)
429 : {
430 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
431 : "ReadWavDataAsMono: output buffer NULL!");
432 0 : return -1;
433 : }
434 :
435 0 : if(!_reading)
436 : {
437 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
438 : "ReadWavDataAsMono: no longer reading file.");
439 0 : return -1;
440 : }
441 :
442 0 : int32_t bytesRead = ReadWavData(
443 : wav,
444 0 : (codec_info_.channels == 2) ? _tempData : (uint8_t*)outData,
445 0 : totalBytesNeeded);
446 0 : if(bytesRead == 0)
447 : {
448 0 : return 0;
449 : }
450 0 : if(bytesRead < 0)
451 : {
452 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
453 : "ReadWavDataAsMono: failed to read data from WAV file.");
454 0 : return -1;
455 : }
456 : // Output data is should be mono.
457 0 : if(codec_info_.channels == 2)
458 : {
459 0 : for (size_t i = 0; i < bytesRequested / _bytesPerSample; i++)
460 : {
461 : // Sample value is the average of left and right buffer rounded to
462 : // closest integer value. Note samples can be either 1 or 2 byte.
463 0 : if(_bytesPerSample == 1)
464 : {
465 0 : _tempData[i] = ((_tempData[2 * i] + _tempData[(2 * i) + 1] +
466 0 : 1) >> 1);
467 : }
468 : else
469 : {
470 0 : int16_t* sampleData = (int16_t*) _tempData;
471 0 : sampleData[i] = ((sampleData[2 * i] + sampleData[(2 * i) + 1] +
472 0 : 1) >> 1);
473 : }
474 : }
475 0 : memcpy(outData, _tempData, bytesRequested);
476 : }
477 0 : return static_cast<int32_t>(bytesRequested);
478 : }
479 :
480 0 : int32_t ModuleFileUtility::ReadWavDataAsStereo(
481 : InStream& wav,
482 : int8_t* outDataLeft,
483 : int8_t* outDataRight,
484 : const size_t bufferSize)
485 : {
486 : WEBRTC_TRACE(
487 : kTraceStream,
488 : kTraceFile,
489 : _id,
490 : "ModuleFileUtility::ReadWavDataAsStereo(wav= 0x%x, outLeft= 0x%x, "
491 : "outRight= 0x%x, bufSize= %" PRIuS ")",
492 : &wav,
493 : outDataLeft,
494 : outDataRight,
495 : bufferSize);
496 :
497 0 : if((outDataLeft == NULL) ||
498 : (outDataRight == NULL))
499 : {
500 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
501 : "ReadWavDataAsMono: an input buffer is NULL!");
502 0 : return -1;
503 : }
504 0 : if(codec_info_.channels != 2)
505 : {
506 : WEBRTC_TRACE(
507 : kTraceError,
508 : kTraceFile,
509 : _id,
510 : "ReadWavDataAsStereo: WAV file does not contain stereo data!");
511 0 : return -1;
512 : }
513 0 : if(! _reading)
514 : {
515 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
516 : "ReadWavDataAsStereo: no longer reading file.");
517 0 : return -1;
518 : }
519 :
520 : // The number of bytes that should be read from file.
521 0 : const size_t totalBytesNeeded = _readSizeBytes;
522 : // The number of bytes that will be written to the left and the right
523 : // buffers.
524 0 : const size_t bytesRequested = totalBytesNeeded >> 1;
525 0 : if(bufferSize < bytesRequested)
526 : {
527 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
528 : "ReadWavData: Output buffers are too short!");
529 0 : assert(false);
530 : return -1;
531 : }
532 :
533 0 : int32_t bytesRead = ReadWavData(wav, _tempData, totalBytesNeeded);
534 0 : if(bytesRead <= 0)
535 : {
536 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
537 : "ReadWavDataAsStereo: failed to read data from WAV file.");
538 0 : return -1;
539 : }
540 :
541 : // Turn interleaved audio to left and right buffer. Note samples can be
542 : // either 1 or 2 bytes
543 0 : if(_bytesPerSample == 1)
544 : {
545 0 : for (size_t i = 0; i < bytesRequested; i++)
546 : {
547 0 : outDataLeft[i] = _tempData[2 * i];
548 0 : outDataRight[i] = _tempData[(2 * i) + 1];
549 : }
550 : }
551 0 : else if(_bytesPerSample == 2)
552 : {
553 0 : int16_t* sampleData = reinterpret_cast<int16_t*>(_tempData);
554 0 : int16_t* outLeft = reinterpret_cast<int16_t*>(outDataLeft);
555 : int16_t* outRight = reinterpret_cast<int16_t*>(
556 0 : outDataRight);
557 :
558 : // Bytes requested to samples requested.
559 0 : size_t sampleCount = bytesRequested >> 1;
560 0 : for (size_t i = 0; i < sampleCount; i++)
561 : {
562 0 : outLeft[i] = sampleData[2 * i];
563 0 : outRight[i] = sampleData[(2 * i) + 1];
564 : }
565 : } else {
566 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
567 : "ReadWavStereoData: unsupported sample size %" PRIuS "!",
568 : _bytesPerSample);
569 0 : assert(false);
570 : return -1;
571 : }
572 0 : return static_cast<int32_t>(bytesRequested);
573 : }
574 :
575 0 : int32_t ModuleFileUtility::ReadWavData(InStream& wav,
576 : uint8_t* buffer,
577 : size_t dataLengthInBytes)
578 : {
579 : WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
580 : "ModuleFileUtility::ReadWavData(wav= 0x%x, buffer= 0x%x, "
581 : "dataLen= %" PRIuS ")", &wav, buffer, dataLengthInBytes);
582 :
583 :
584 0 : if(buffer == NULL)
585 : {
586 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
587 : "ReadWavDataAsMono: output buffer NULL!");
588 0 : return -1;
589 : }
590 :
591 : // Make sure that a read won't return too few samples.
592 : // TODO (hellner): why not read the remaining bytes needed from the start
593 : // of the file?
594 0 : if(_dataSize < (_readPos + dataLengthInBytes))
595 : {
596 : // Rewind() being -1 may be due to the file not supposed to be looped.
597 0 : if(wav.Rewind() == -1)
598 : {
599 0 : _reading = false;
600 0 : return 0;
601 : }
602 0 : if(InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1)
603 : {
604 0 : _reading = false;
605 0 : return -1;
606 : }
607 : }
608 :
609 0 : int32_t bytesRead = wav.Read(buffer, dataLengthInBytes);
610 0 : if(bytesRead < 0)
611 : {
612 0 : _reading = false;
613 0 : return -1;
614 : }
615 :
616 : // This should never happen due to earlier sanity checks.
617 : // TODO (hellner): change to an assert and fail here since this should
618 : // never happen...
619 0 : if(bytesRead < (int32_t)dataLengthInBytes)
620 : {
621 0 : if((wav.Rewind() == -1) ||
622 0 : (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1))
623 : {
624 0 : _reading = false;
625 0 : return -1;
626 : }
627 : else
628 : {
629 0 : bytesRead = wav.Read(buffer, dataLengthInBytes);
630 0 : if(bytesRead < (int32_t)dataLengthInBytes)
631 : {
632 0 : _reading = false;
633 0 : return -1;
634 : }
635 : }
636 : }
637 :
638 0 : _readPos += bytesRead;
639 :
640 : // TODO (hellner): Why is dataLengthInBytes let dictate the number of bytes
641 : // to read when exactly 10ms should be read?!
642 0 : _playoutPositionMs += 10;
643 0 : if((_stopPointInMs > 0) &&
644 0 : (_playoutPositionMs >= _stopPointInMs))
645 : {
646 0 : if((wav.Rewind() == -1) ||
647 0 : (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1))
648 : {
649 0 : _reading = false;
650 : }
651 : }
652 0 : return bytesRead;
653 : }
654 :
655 0 : int32_t ModuleFileUtility::InitWavWriting(OutStream& wav,
656 : const CodecInst& codecInst)
657 : {
658 :
659 0 : if(set_codec_info(codecInst) != 0)
660 : {
661 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
662 : "codecInst identifies unsupported codec!");
663 0 : return -1;
664 : }
665 0 : _writing = false;
666 0 : size_t channels = (codecInst.channels == 0) ? 1 : codecInst.channels;
667 :
668 0 : if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0)
669 : {
670 0 : _bytesPerSample = 1;
671 0 : if(WriteWavHeader(wav, 8000, _bytesPerSample, channels,
672 : kWavFormatMuLaw, 0) == -1)
673 : {
674 0 : return -1;
675 : }
676 : }
677 0 : else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0)
678 : {
679 0 : _bytesPerSample = 1;
680 0 : if(WriteWavHeader(wav, 8000, _bytesPerSample, channels, kWavFormatALaw,
681 : 0) == -1)
682 : {
683 0 : return -1;
684 : }
685 : }
686 0 : else if(STR_CASE_CMP(codecInst.plname, "L16") == 0)
687 : {
688 0 : _bytesPerSample = 2;
689 0 : if(WriteWavHeader(wav, codecInst.plfreq, _bytesPerSample, channels,
690 : kWavFormatPcm, 0) == -1)
691 : {
692 0 : return -1;
693 : }
694 : }
695 : else
696 : {
697 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
698 : "codecInst identifies unsupported codec for WAV file!");
699 0 : return -1;
700 : }
701 0 : _writing = true;
702 0 : _bytesWritten = 0;
703 0 : return 0;
704 : }
705 :
706 0 : int32_t ModuleFileUtility::WriteWavData(OutStream& out,
707 : const int8_t* buffer,
708 : const size_t dataLength)
709 : {
710 : WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
711 : "ModuleFileUtility::WriteWavData(out= 0x%x, buf= 0x%x, "
712 : "dataLen= %" PRIuS ")", &out, buffer, dataLength);
713 :
714 0 : if(buffer == NULL)
715 : {
716 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
717 : "WriteWavData: input buffer NULL!");
718 0 : return -1;
719 : }
720 :
721 0 : if(!out.Write(buffer, dataLength))
722 : {
723 0 : return -1;
724 : }
725 0 : _bytesWritten += dataLength;
726 0 : return static_cast<int32_t>(dataLength);
727 : }
728 :
729 :
730 0 : int32_t ModuleFileUtility::WriteWavHeader(
731 : OutStream& wav,
732 : uint32_t freq,
733 : size_t bytesPerSample,
734 : size_t channels,
735 : uint32_t format,
736 : size_t lengthInBytes)
737 : {
738 : // Frame size in bytes for 10 ms of audio.
739 0 : const size_t frameSize = (freq / 100) * channels;
740 :
741 : // Calculate the number of full frames that the wave file contain.
742 0 : const size_t dataLengthInBytes = frameSize * (lengthInBytes / frameSize);
743 :
744 : uint8_t buf[kWavHeaderSize];
745 0 : webrtc::WriteWavHeader(buf, channels, freq, static_cast<WavFormat>(format),
746 0 : bytesPerSample, dataLengthInBytes / bytesPerSample);
747 0 : wav.Write(buf, kWavHeaderSize);
748 0 : return 0;
749 : }
750 :
751 0 : int32_t ModuleFileUtility::UpdateWavHeader(OutStream& wav)
752 : {
753 0 : int32_t res = -1;
754 0 : if(wav.Rewind() == -1)
755 : {
756 0 : return -1;
757 : }
758 0 : size_t channels = (codec_info_.channels == 0) ? 1 : codec_info_.channels;
759 :
760 0 : if(STR_CASE_CMP(codec_info_.plname, "L16") == 0)
761 : {
762 0 : res = WriteWavHeader(wav, codec_info_.plfreq, 2, channels,
763 0 : kWavFormatPcm, _bytesWritten);
764 0 : } else if(STR_CASE_CMP(codec_info_.plname, "PCMU") == 0) {
765 0 : res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatMuLaw,
766 0 : _bytesWritten);
767 0 : } else if(STR_CASE_CMP(codec_info_.plname, "PCMA") == 0) {
768 0 : res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatALaw,
769 0 : _bytesWritten);
770 : } else {
771 : // Allow calling this API even if not writing to a WAVE file.
772 : // TODO (hellner): why?!
773 0 : return 0;
774 : }
775 0 : return res;
776 : }
777 :
778 :
779 0 : int32_t ModuleFileUtility::InitPreEncodedReading(InStream& in,
780 : const CodecInst& cinst)
781 : {
782 :
783 : uint8_t preEncodedID;
784 0 : in.Read(&preEncodedID, 1);
785 :
786 : MediaFileUtility_CodecType codecType =
787 0 : (MediaFileUtility_CodecType)preEncodedID;
788 :
789 0 : if(set_codec_info(cinst) != 0)
790 : {
791 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
792 : "Pre-encoded file send codec mismatch!");
793 0 : return -1;
794 : }
795 0 : if(codecType != _codecId)
796 : {
797 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
798 : "Pre-encoded file format codec mismatch!");
799 0 : return -1;
800 : }
801 0 : memcpy(&codec_info_,&cinst,sizeof(CodecInst));
802 0 : _reading = true;
803 0 : return 0;
804 : }
805 :
806 0 : int32_t ModuleFileUtility::ReadPreEncodedData(
807 : InStream& in,
808 : int8_t* outData,
809 : const size_t bufferSize)
810 : {
811 : WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
812 : "ModuleFileUtility::ReadPreEncodedData(in= 0x%x, "
813 : "outData= 0x%x, bufferSize= %" PRIuS ")", &in, outData,
814 : bufferSize);
815 :
816 : if(outData == NULL)
817 : {
818 : WEBRTC_TRACE(kTraceError, kTraceFile, _id, "output buffer NULL");
819 : }
820 :
821 : size_t frameLen;
822 : uint8_t buf[64];
823 : // Each frame has a two byte header containing the frame length.
824 0 : int32_t res = in.Read(buf, 2);
825 0 : if(res != 2)
826 : {
827 0 : if(!in.Rewind())
828 : {
829 : // The first byte is the codec identifier.
830 0 : in.Read(buf, 1);
831 0 : res = in.Read(buf, 2);
832 : }
833 : else
834 : {
835 0 : return -1;
836 : }
837 : }
838 0 : frameLen = buf[0] + buf[1] * 256;
839 0 : if(bufferSize < frameLen)
840 : {
841 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
842 : "buffer not large enough to read %" PRIuS " bytes of "
843 : "pre-encoded data!", frameLen);
844 0 : return -1;
845 : }
846 0 : return in.Read(outData, frameLen);
847 : }
848 :
849 0 : int32_t ModuleFileUtility::InitPreEncodedWriting(
850 : OutStream& out,
851 : const CodecInst& codecInst)
852 : {
853 :
854 0 : if(set_codec_info(codecInst) != 0)
855 : {
856 : WEBRTC_TRACE(kTraceError, kTraceFile, _id, "CodecInst not recognized!");
857 0 : return -1;
858 : }
859 0 : _writing = true;
860 0 : _bytesWritten = 1;
861 0 : out.Write(&_codecId, 1);
862 0 : return 0;
863 : }
864 :
865 0 : int32_t ModuleFileUtility::WritePreEncodedData(
866 : OutStream& out,
867 : const int8_t* buffer,
868 : const size_t dataLength)
869 : {
870 : WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
871 : "ModuleFileUtility::WritePreEncodedData(out= 0x%x, "
872 : "inData= 0x%x, dataLen= %" PRIuS ")", &out, buffer,
873 : dataLength);
874 :
875 : if(buffer == NULL)
876 : {
877 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL");
878 : }
879 :
880 0 : size_t bytesWritten = 0;
881 : // The first two bytes is the size of the frame.
882 : int16_t lengthBuf;
883 0 : lengthBuf = (int16_t)dataLength;
884 0 : if(dataLength > static_cast<size_t>(std::numeric_limits<int16_t>::max()) ||
885 0 : !out.Write(&lengthBuf, 2))
886 : {
887 0 : return -1;
888 : }
889 0 : bytesWritten = 2;
890 :
891 0 : if(!out.Write(buffer, dataLength))
892 : {
893 0 : return -1;
894 : }
895 0 : bytesWritten += dataLength;
896 0 : return static_cast<int32_t>(bytesWritten);
897 : }
898 :
899 0 : int32_t ModuleFileUtility::InitCompressedReading(
900 : InStream& in,
901 : const uint32_t start,
902 : const uint32_t stop)
903 : {
904 : WEBRTC_TRACE(kTraceDebug, kTraceFile, _id,
905 : "ModuleFileUtility::InitCompressedReading(in= 0x%x, "
906 : "start= %d, stop= %d)", &in, start, stop);
907 :
908 : #if defined(WEBRTC_CODEC_ILBC)
909 : int16_t read_len = 0;
910 : #endif
911 0 : _codecId = kCodecNoCodec;
912 0 : _playoutPositionMs = 0;
913 0 : _reading = false;
914 :
915 0 : _startPointInMs = start;
916 0 : _stopPointInMs = stop;
917 :
918 : // Read the codec name
919 0 : int32_t cnt = 0;
920 : char buf[64];
921 0 : do
922 : {
923 0 : in.Read(&buf[cnt++], 1);
924 0 : } while ((buf[cnt-1] != '\n') && (64 > cnt));
925 :
926 0 : if(cnt==64)
927 : {
928 0 : return -1;
929 : }
930 0 : buf[cnt]=0;
931 :
932 : #ifdef WEBRTC_CODEC_ILBC
933 : if(!strcmp("#!iLBC20\n", buf))
934 : {
935 : codec_info_.pltype = 102;
936 : strcpy(codec_info_.plname, "ilbc");
937 : codec_info_.plfreq = 8000;
938 : codec_info_.pacsize = 160;
939 : codec_info_.channels = 1;
940 : codec_info_.rate = 13300;
941 : _codecId = kCodecIlbc20Ms;
942 :
943 : if(_startPointInMs > 0)
944 : {
945 : while (_playoutPositionMs <= _startPointInMs)
946 : {
947 : read_len = in.Read(buf, 38);
948 : if(read_len != 38)
949 : {
950 : return -1;
951 : }
952 : _playoutPositionMs += 20;
953 : }
954 : }
955 : }
956 :
957 : if(!strcmp("#!iLBC30\n", buf))
958 : {
959 : codec_info_.pltype = 102;
960 : strcpy(codec_info_.plname, "ilbc");
961 : codec_info_.plfreq = 8000;
962 : codec_info_.pacsize = 240;
963 : codec_info_.channels = 1;
964 : codec_info_.rate = 13300;
965 : _codecId = kCodecIlbc30Ms;
966 :
967 : if(_startPointInMs > 0)
968 : {
969 : while (_playoutPositionMs <= _startPointInMs)
970 : {
971 : read_len = in.Read(buf, 50);
972 : if(read_len != 50)
973 : {
974 : return -1;
975 : }
976 : _playoutPositionMs += 20;
977 : }
978 : }
979 : }
980 : #endif
981 0 : if(_codecId == kCodecNoCodec)
982 : {
983 0 : return -1;
984 : }
985 0 : _reading = true;
986 0 : return 0;
987 : }
988 :
989 0 : int32_t ModuleFileUtility::ReadCompressedData(InStream& in,
990 : int8_t* outData,
991 : size_t bufferSize)
992 : {
993 : WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
994 : "ModuleFileUtility::ReadCompressedData(in=0x%x, outData=0x%x, "
995 : "bytes=%" PRIuS ")", &in, outData, bufferSize);
996 :
997 0 : int bytesRead = 0;
998 :
999 0 : if(! _reading)
1000 : {
1001 : WEBRTC_TRACE(kTraceError, kTraceFile, _id, "not currently reading!");
1002 0 : return -1;
1003 : }
1004 :
1005 : #ifdef WEBRTC_CODEC_ILBC
1006 : if((_codecId == kCodecIlbc20Ms) ||
1007 : (_codecId == kCodecIlbc30Ms))
1008 : {
1009 : size_t byteSize = 0;
1010 : if(_codecId == kCodecIlbc30Ms)
1011 : {
1012 : byteSize = 50;
1013 : }
1014 : if(_codecId == kCodecIlbc20Ms)
1015 : {
1016 : byteSize = 38;
1017 : }
1018 : if(bufferSize < byteSize)
1019 : {
1020 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1021 : "output buffer is too short to read ILBC compressed "
1022 : "data.");
1023 : assert(false);
1024 : return -1;
1025 : }
1026 :
1027 : bytesRead = in.Read(outData, byteSize);
1028 : if(bytesRead != static_cast<int>(byteSize))
1029 : {
1030 : if(!in.Rewind())
1031 : {
1032 : InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1033 : bytesRead = in.Read(outData, byteSize);
1034 : if(bytesRead != static_cast<int>(byteSize))
1035 : {
1036 : _reading = false;
1037 : return -1;
1038 : }
1039 : }
1040 : else
1041 : {
1042 : _reading = false;
1043 : return -1;
1044 : }
1045 : }
1046 : }
1047 : #endif
1048 0 : if(bytesRead == 0)
1049 : {
1050 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1051 : "ReadCompressedData() no bytes read, codec not supported");
1052 0 : return -1;
1053 : }
1054 :
1055 0 : _playoutPositionMs += 20;
1056 0 : if((_stopPointInMs > 0) &&
1057 0 : (_playoutPositionMs >= _stopPointInMs))
1058 : {
1059 0 : if(!in.Rewind())
1060 : {
1061 0 : InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1062 : }
1063 : else
1064 : {
1065 0 : _reading = false;
1066 : }
1067 : }
1068 0 : return bytesRead;
1069 : }
1070 :
1071 0 : int32_t ModuleFileUtility::InitCompressedWriting(
1072 : OutStream& out,
1073 : const CodecInst& codecInst)
1074 : {
1075 : WEBRTC_TRACE(kTraceDebug, kTraceFile, _id,
1076 : "ModuleFileUtility::InitCompressedWriting(out= 0x%x, "
1077 : "codecName= %s)", &out, codecInst.plname);
1078 :
1079 0 : _writing = false;
1080 :
1081 : #ifdef WEBRTC_CODEC_ILBC
1082 : if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0)
1083 : {
1084 : if(codecInst.pacsize == 160)
1085 : {
1086 : _codecId = kCodecIlbc20Ms;
1087 : out.Write("#!iLBC20\n",9);
1088 : }
1089 : else if(codecInst.pacsize == 240)
1090 : {
1091 : _codecId = kCodecIlbc30Ms;
1092 : out.Write("#!iLBC30\n",9);
1093 : }
1094 : else
1095 : {
1096 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1097 : "codecInst defines unsupported compression codec!");
1098 : return -1;
1099 : }
1100 : memcpy(&codec_info_,&codecInst,sizeof(CodecInst));
1101 : _writing = true;
1102 : return 0;
1103 : }
1104 : #endif
1105 :
1106 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1107 : "codecInst defines unsupported compression codec!");
1108 0 : return -1;
1109 : }
1110 :
1111 0 : int32_t ModuleFileUtility::WriteCompressedData(
1112 : OutStream& out,
1113 : const int8_t* buffer,
1114 : const size_t dataLength)
1115 : {
1116 : WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1117 : "ModuleFileUtility::WriteCompressedData(out= 0x%x, buf= 0x%x, "
1118 : "dataLen= %" PRIuS ")", &out, buffer, dataLength);
1119 :
1120 : if(buffer == NULL)
1121 : {
1122 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL");
1123 : }
1124 :
1125 0 : if(!out.Write(buffer, dataLength))
1126 : {
1127 0 : return -1;
1128 : }
1129 0 : return static_cast<int32_t>(dataLength);
1130 : }
1131 :
1132 0 : int32_t ModuleFileUtility::InitPCMReading(InStream& pcm,
1133 : const uint32_t start,
1134 : const uint32_t stop,
1135 : uint32_t freq)
1136 : {
1137 : WEBRTC_TRACE(kTraceInfo, kTraceFile, _id,
1138 : "ModuleFileUtility::InitPCMReading(pcm= 0x%x, start=%d, "
1139 : "stop=%d, freq=%d)", &pcm, start, stop, freq);
1140 :
1141 : int8_t dummy[320];
1142 : int read_len;
1143 :
1144 0 : _playoutPositionMs = 0;
1145 0 : _startPointInMs = start;
1146 0 : _stopPointInMs = stop;
1147 0 : _reading = false;
1148 :
1149 0 : if(freq == 8000)
1150 : {
1151 0 : strcpy(codec_info_.plname, "L16");
1152 0 : codec_info_.pltype = -1;
1153 0 : codec_info_.plfreq = 8000;
1154 0 : codec_info_.pacsize = 160;
1155 0 : codec_info_.channels = 1;
1156 0 : codec_info_.rate = 128000;
1157 0 : _codecId = kCodecL16_8Khz;
1158 : }
1159 0 : else if(freq == 16000)
1160 : {
1161 0 : strcpy(codec_info_.plname, "L16");
1162 0 : codec_info_.pltype = -1;
1163 0 : codec_info_.plfreq = 16000;
1164 0 : codec_info_.pacsize = 320;
1165 0 : codec_info_.channels = 1;
1166 0 : codec_info_.rate = 256000;
1167 0 : _codecId = kCodecL16_16kHz;
1168 : }
1169 0 : else if(freq == 32000)
1170 : {
1171 0 : strcpy(codec_info_.plname, "L16");
1172 0 : codec_info_.pltype = -1;
1173 0 : codec_info_.plfreq = 32000;
1174 0 : codec_info_.pacsize = 320;
1175 0 : codec_info_.channels = 1;
1176 0 : codec_info_.rate = 512000;
1177 0 : _codecId = kCodecL16_32Khz;
1178 : }
1179 :
1180 : // Readsize for 10ms of audio data (2 bytes per sample).
1181 0 : _readSizeBytes = 2 * codec_info_. plfreq / 100;
1182 0 : if(_startPointInMs > 0)
1183 : {
1184 0 : while (_playoutPositionMs < _startPointInMs)
1185 : {
1186 0 : read_len = pcm.Read(dummy, _readSizeBytes);
1187 0 : if(read_len != static_cast<int>(_readSizeBytes))
1188 : {
1189 0 : return -1; // Must have reached EOF before start position!
1190 : }
1191 0 : _playoutPositionMs += 10;
1192 : }
1193 : }
1194 0 : _reading = true;
1195 0 : return 0;
1196 : }
1197 :
1198 0 : int32_t ModuleFileUtility::ReadPCMData(InStream& pcm,
1199 : int8_t* outData,
1200 : size_t bufferSize)
1201 : {
1202 : WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1203 : "ModuleFileUtility::ReadPCMData(pcm= 0x%x, outData= 0x%x, "
1204 : "bufSize= %" PRIuS ")", &pcm, outData, bufferSize);
1205 :
1206 : if(outData == NULL)
1207 : {
1208 : WEBRTC_TRACE(kTraceError, kTraceFile, _id, "buffer NULL");
1209 : }
1210 :
1211 : // Readsize for 10ms of audio data (2 bytes per sample).
1212 0 : size_t bytesRequested = static_cast<size_t>(2 * codec_info_.plfreq / 100);
1213 0 : if(bufferSize < bytesRequested)
1214 : {
1215 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1216 : "ReadPCMData: buffer not long enough for a 10ms frame.");
1217 0 : assert(false);
1218 : return -1;
1219 : }
1220 :
1221 0 : int bytesRead = pcm.Read(outData, bytesRequested);
1222 0 : if(bytesRead < static_cast<int>(bytesRequested))
1223 : {
1224 0 : if(pcm.Rewind() == -1)
1225 : {
1226 0 : _reading = false;
1227 : }
1228 : else
1229 : {
1230 0 : if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
1231 0 : codec_info_.plfreq) == -1)
1232 : {
1233 0 : _reading = false;
1234 : }
1235 : else
1236 : {
1237 0 : size_t rest = bytesRequested - bytesRead;
1238 0 : int len = pcm.Read(&(outData[bytesRead]), rest);
1239 0 : if(len == static_cast<int>(rest))
1240 : {
1241 0 : bytesRead += len;
1242 : }
1243 : else
1244 : {
1245 0 : _reading = false;
1246 : }
1247 : }
1248 0 : if(bytesRead <= 0)
1249 : {
1250 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1251 : "ReadPCMData: Failed to rewind audio file.");
1252 0 : return -1;
1253 : }
1254 : }
1255 : }
1256 :
1257 0 : if(bytesRead <= 0)
1258 : {
1259 : WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1260 : "ReadPCMData: end of file");
1261 0 : return -1;
1262 : }
1263 0 : _playoutPositionMs += 10;
1264 0 : if(_stopPointInMs && _playoutPositionMs >= _stopPointInMs)
1265 : {
1266 0 : if(!pcm.Rewind())
1267 : {
1268 0 : if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
1269 0 : codec_info_.plfreq) == -1)
1270 : {
1271 0 : _reading = false;
1272 : }
1273 : }
1274 : }
1275 0 : return bytesRead;
1276 : }
1277 :
1278 0 : int32_t ModuleFileUtility::InitPCMWriting(OutStream& out, uint32_t freq)
1279 : {
1280 :
1281 0 : if(freq == 8000)
1282 : {
1283 0 : strcpy(codec_info_.plname, "L16");
1284 0 : codec_info_.pltype = -1;
1285 0 : codec_info_.plfreq = 8000;
1286 0 : codec_info_.pacsize = 160;
1287 0 : codec_info_.channels = 1;
1288 0 : codec_info_.rate = 128000;
1289 :
1290 0 : _codecId = kCodecL16_8Khz;
1291 : }
1292 0 : else if(freq == 16000)
1293 : {
1294 0 : strcpy(codec_info_.plname, "L16");
1295 0 : codec_info_.pltype = -1;
1296 0 : codec_info_.plfreq = 16000;
1297 0 : codec_info_.pacsize = 320;
1298 0 : codec_info_.channels = 1;
1299 0 : codec_info_.rate = 256000;
1300 :
1301 0 : _codecId = kCodecL16_16kHz;
1302 : }
1303 0 : else if(freq == 32000)
1304 : {
1305 0 : strcpy(codec_info_.plname, "L16");
1306 0 : codec_info_.pltype = -1;
1307 0 : codec_info_.plfreq = 32000;
1308 0 : codec_info_.pacsize = 320;
1309 0 : codec_info_.channels = 1;
1310 0 : codec_info_.rate = 512000;
1311 :
1312 0 : _codecId = kCodecL16_32Khz;
1313 : }
1314 0 : if((_codecId != kCodecL16_8Khz) &&
1315 0 : (_codecId != kCodecL16_16kHz) &&
1316 0 : (_codecId != kCodecL16_32Khz))
1317 : {
1318 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1319 : "CodecInst is not 8KHz PCM or 16KHz PCM!");
1320 0 : return -1;
1321 : }
1322 0 : _writing = true;
1323 0 : _bytesWritten = 0;
1324 0 : return 0;
1325 : }
1326 :
1327 0 : int32_t ModuleFileUtility::WritePCMData(OutStream& out,
1328 : const int8_t* buffer,
1329 : const size_t dataLength)
1330 : {
1331 : WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1332 : "ModuleFileUtility::WritePCMData(out= 0x%x, buf= 0x%x, "
1333 : "dataLen= %" PRIuS ")", &out, buffer, dataLength);
1334 :
1335 : if(buffer == NULL)
1336 : {
1337 : WEBRTC_TRACE(kTraceError, kTraceFile, _id, "buffer NULL");
1338 : }
1339 :
1340 0 : if(!out.Write(buffer, dataLength))
1341 : {
1342 0 : return -1;
1343 : }
1344 :
1345 0 : _bytesWritten += dataLength;
1346 0 : return static_cast<int32_t>(dataLength);
1347 : }
1348 :
1349 0 : int32_t ModuleFileUtility::codec_info(CodecInst& codecInst)
1350 : {
1351 : WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1352 : "ModuleFileUtility::codec_info(codecInst= 0x%x)", &codecInst);
1353 :
1354 0 : if(!_reading && !_writing)
1355 : {
1356 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1357 : "CodecInst: not currently reading audio file!");
1358 0 : return -1;
1359 : }
1360 0 : memcpy(&codecInst,&codec_info_,sizeof(CodecInst));
1361 0 : return 0;
1362 : }
1363 :
1364 0 : int32_t ModuleFileUtility::set_codec_info(const CodecInst& codecInst)
1365 : {
1366 :
1367 0 : _codecId = kCodecNoCodec;
1368 0 : if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0)
1369 : {
1370 0 : _codecId = kCodecPcmu;
1371 : }
1372 0 : else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0)
1373 : {
1374 0 : _codecId = kCodecPcma;
1375 : }
1376 0 : else if(STR_CASE_CMP(codecInst.plname, "L16") == 0)
1377 : {
1378 0 : if(codecInst.plfreq == 8000)
1379 : {
1380 0 : _codecId = kCodecL16_8Khz;
1381 : }
1382 0 : else if(codecInst.plfreq == 16000)
1383 : {
1384 0 : _codecId = kCodecL16_16kHz;
1385 : }
1386 0 : else if(codecInst.plfreq == 32000)
1387 : {
1388 0 : _codecId = kCodecL16_32Khz;
1389 : }
1390 : }
1391 : #ifdef WEBRTC_CODEC_ILBC
1392 : else if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0)
1393 : {
1394 : if(codecInst.pacsize == 160)
1395 : {
1396 : _codecId = kCodecIlbc20Ms;
1397 : }
1398 : else if(codecInst.pacsize == 240)
1399 : {
1400 : _codecId = kCodecIlbc30Ms;
1401 : }
1402 : }
1403 : #endif
1404 : #if(defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
1405 : else if(STR_CASE_CMP(codecInst.plname, "isac") == 0)
1406 : {
1407 : if(codecInst.plfreq == 16000)
1408 : {
1409 : _codecId = kCodecIsac;
1410 : }
1411 : else if(codecInst.plfreq == 32000)
1412 : {
1413 : _codecId = kCodecIsacSwb;
1414 : }
1415 : }
1416 : #endif
1417 : #ifdef WEBRTC_CODEC_G722
1418 : else if(STR_CASE_CMP(codecInst.plname, "G722") == 0)
1419 : {
1420 : _codecId = kCodecG722;
1421 : }
1422 : #endif
1423 0 : if(_codecId == kCodecNoCodec)
1424 : {
1425 0 : return -1;
1426 : }
1427 0 : memcpy(&codec_info_, &codecInst, sizeof(CodecInst));
1428 0 : return 0;
1429 : }
1430 :
1431 0 : int32_t ModuleFileUtility::FileDurationMs(const char* fileName,
1432 : const FileFormats fileFormat,
1433 : const uint32_t freqInHz)
1434 : {
1435 :
1436 0 : if(fileName == NULL)
1437 : {
1438 : WEBRTC_TRACE(kTraceError, kTraceFile, _id, "filename NULL");
1439 0 : return -1;
1440 : }
1441 :
1442 0 : int32_t time_in_ms = -1;
1443 : struct stat file_size;
1444 0 : if(stat(fileName,&file_size) == -1)
1445 : {
1446 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1447 : "failed to retrieve file size with stat!");
1448 0 : return -1;
1449 : }
1450 0 : FileWrapper* inStreamObj = FileWrapper::Create();
1451 0 : if(inStreamObj == NULL)
1452 : {
1453 : WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
1454 : "failed to create InStream object!");
1455 0 : return -1;
1456 : }
1457 0 : if (!inStreamObj->OpenFile(fileName, true)) {
1458 0 : delete inStreamObj;
1459 : WEBRTC_TRACE(kTraceError, kTraceFile, _id, "failed to open file %s!",
1460 : fileName);
1461 0 : return -1;
1462 : }
1463 :
1464 0 : switch (fileFormat)
1465 : {
1466 : case kFileFormatWavFile:
1467 : {
1468 0 : if(ReadWavHeader(*inStreamObj) == -1)
1469 : {
1470 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1471 : "failed to read WAV file header!");
1472 0 : return -1;
1473 : }
1474 0 : time_in_ms = ((file_size.st_size - 44) /
1475 0 : (_wavFormatObj.nAvgBytesPerSec/1000));
1476 0 : break;
1477 : }
1478 : case kFileFormatPcm16kHzFile:
1479 : {
1480 : // 16 samples per ms. 2 bytes per sample.
1481 0 : int32_t denominator = 16*2;
1482 0 : time_in_ms = (file_size.st_size)/denominator;
1483 0 : break;
1484 : }
1485 : case kFileFormatPcm8kHzFile:
1486 : {
1487 : // 8 samples per ms. 2 bytes per sample.
1488 0 : int32_t denominator = 8*2;
1489 0 : time_in_ms = (file_size.st_size)/denominator;
1490 0 : break;
1491 : }
1492 : case kFileFormatCompressedFile:
1493 : {
1494 0 : int32_t cnt = 0;
1495 0 : int read_len = 0;
1496 : char buf[64];
1497 0 : do
1498 : {
1499 0 : read_len = inStreamObj->Read(&buf[cnt++], 1);
1500 0 : if(read_len != 1)
1501 : {
1502 0 : return -1;
1503 : }
1504 0 : } while ((buf[cnt-1] != '\n') && (64 > cnt));
1505 :
1506 0 : if(cnt == 64)
1507 : {
1508 0 : return -1;
1509 : }
1510 : else
1511 : {
1512 0 : buf[cnt] = 0;
1513 : }
1514 : #ifdef WEBRTC_CODEC_ILBC
1515 : if(!strcmp("#!iLBC20\n", buf))
1516 : {
1517 : // 20 ms is 304 bits
1518 : time_in_ms = ((file_size.st_size)*160)/304;
1519 : break;
1520 : }
1521 : if(!strcmp("#!iLBC30\n", buf))
1522 : {
1523 : // 30 ms takes 400 bits.
1524 : // file size in bytes * 8 / 400 is the number of
1525 : // 30 ms frames in the file ->
1526 : // time_in_ms = file size * 8 / 400 * 30
1527 : time_in_ms = ((file_size.st_size)*240)/400;
1528 : break;
1529 : }
1530 : #endif
1531 0 : break;
1532 : }
1533 : case kFileFormatPreencodedFile:
1534 : {
1535 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1536 : "cannot determine duration of Pre-Encoded file!");
1537 0 : break;
1538 : }
1539 : default:
1540 : WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1541 : "unsupported file format %d!", fileFormat);
1542 0 : break;
1543 : }
1544 0 : inStreamObj->CloseFile();
1545 0 : delete inStreamObj;
1546 0 : return time_in_ms;
1547 : }
1548 :
1549 0 : uint32_t ModuleFileUtility::PlayoutPositionMs()
1550 : {
1551 : WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1552 : "ModuleFileUtility::PlayoutPosition()");
1553 :
1554 0 : return _reading ? _playoutPositionMs : 0;
1555 : }
1556 : } // namespace webrtc
|