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 {
ModuleFileUtility(const int32_t id)47 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 _tempData() {
63 WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
64 "ModuleFileUtility::ModuleFileUtility()");
65 memset(&codec_info_,0,sizeof(CodecInst));
66 codec_info_.pltype = -1;
67 }
68
~ModuleFileUtility()69 ModuleFileUtility::~ModuleFileUtility()
70 {
71 WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
72 "ModuleFileUtility::~ModuleFileUtility()");
73 }
74
ReadWavHeader(InStream & wav)75 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 char tmpStr[6] = "FOUR";
81 unsigned char tmpStr2[4];
82 size_t i;
83 bool dataFound = false;
84 bool fmtFound = false;
85 int8_t dummyRead;
86
87
88 _dataSize = 0;
89 int len = wav.Read(&RIFFheaderObj, sizeof(WAVE_RIFF_header));
90 if (len != static_cast<int>(sizeof(WAVE_RIFF_header)))
91 {
92 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
93 "Not a wave file (too short)");
94 return -1;
95 }
96
97 for (i = 0; i < 4; i++)
98 {
99 tmpStr[i] = RIFFheaderObj.ckID[i];
100 }
101 if(strcmp(tmpStr, "RIFF") != 0)
102 {
103 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
104 "Not a wave file (does not have RIFF)");
105 return -1;
106 }
107 for (i = 0; i < 4; i++)
108 {
109 tmpStr[i] = RIFFheaderObj.wave_ckID[i];
110 }
111 if(strcmp(tmpStr, "WAVE") != 0)
112 {
113 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
114 "Not a wave file (does not have WAVE)");
115 return -1;
116 }
117
118 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 memcpy(tmpStr2, &CHUNKheaderObj.fmt_ckSize, 4);
125 CHUNKheaderObj.fmt_ckSize =
126 (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8) +
127 (((uint32_t)tmpStr2[2]) << 16) + (((uint32_t)tmpStr2[3]) << 24);
128
129 memcpy(tmpStr, CHUNKheaderObj.fmt_ckID, 4);
130
131 while ((len == static_cast<int>(sizeof(WAVE_CHUNK_header))) &&
132 (!fmtFound || !dataFound))
133 {
134 if(strcmp(tmpStr, "fmt ") == 0)
135 {
136 len = wav.Read(&_wavFormatObj, sizeof(WAVE_FMTINFO_header));
137
138 memcpy(tmpStr2, &_wavFormatObj.formatTag, 2);
139 _wavFormatObj.formatTag =
140 (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1])<<8);
141 memcpy(tmpStr2, &_wavFormatObj.nChannels, 2);
142 _wavFormatObj.nChannels =
143 (int16_t) ((uint32_t)tmpStr2[0] +
144 (((uint32_t)tmpStr2[1])<<8));
145 memcpy(tmpStr2, &_wavFormatObj.nSamplesPerSec, 4);
146 _wavFormatObj.nSamplesPerSec =
147 (int32_t) ((uint32_t)tmpStr2[0] +
148 (((uint32_t)tmpStr2[1])<<8) +
149 (((uint32_t)tmpStr2[2])<<16) +
150 (((uint32_t)tmpStr2[3])<<24));
151 memcpy(tmpStr2, &_wavFormatObj.nAvgBytesPerSec, 4);
152 _wavFormatObj.nAvgBytesPerSec =
153 (int32_t) ((uint32_t)tmpStr2[0] +
154 (((uint32_t)tmpStr2[1])<<8) +
155 (((uint32_t)tmpStr2[2])<<16) +
156 (((uint32_t)tmpStr2[3])<<24));
157 memcpy(tmpStr2, &_wavFormatObj.nBlockAlign, 2);
158 _wavFormatObj.nBlockAlign =
159 (int16_t) ((uint32_t)tmpStr2[0] +
160 (((uint32_t)tmpStr2[1])<<8));
161 memcpy(tmpStr2, &_wavFormatObj.nBitsPerSample, 2);
162 _wavFormatObj.nBitsPerSample =
163 (int16_t) ((uint32_t)tmpStr2[0] +
164 (((uint32_t)tmpStr2[1])<<8));
165
166 if (CHUNKheaderObj.fmt_ckSize < sizeof(WAVE_FMTINFO_header))
167 {
168 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
169 "Chunk size is too small");
170 return -1;
171 }
172 for (i = 0;
173 i < CHUNKheaderObj.fmt_ckSize - sizeof(WAVE_FMTINFO_header);
174 i++)
175 {
176 len = wav.Read(&dummyRead, 1);
177 if(len != 1)
178 {
179 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
180 "File corrupted, reached EOF (reading fmt)");
181 return -1;
182 }
183 }
184 fmtFound = true;
185 }
186 else if(strcmp(tmpStr, "data") == 0)
187 {
188 _dataSize = CHUNKheaderObj.fmt_ckSize;
189 dataFound = true;
190 break;
191 }
192 else
193 {
194 for (i = 0; i < CHUNKheaderObj.fmt_ckSize; i++)
195 {
196 len = wav.Read(&dummyRead, 1);
197 if(len != 1)
198 {
199 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
200 "File corrupted, reached EOF (reading other)");
201 return -1;
202 }
203 }
204 }
205
206 len = wav.Read(&CHUNKheaderObj, sizeof(WAVE_CHUNK_header));
207
208 memcpy(tmpStr2, &CHUNKheaderObj.fmt_ckSize, 4);
209 CHUNKheaderObj.fmt_ckSize =
210 (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8) +
211 (((uint32_t)tmpStr2[2]) << 16) + (((uint32_t)tmpStr2[3]) << 24);
212
213 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 if( (_wavFormatObj.formatTag != kWavFormatPcm) &&
219 (_wavFormatObj.formatTag != kWavFormatALaw) &&
220 (_wavFormatObj.formatTag != kWavFormatMuLaw))
221 {
222 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
223 "Coding formatTag value=%d not supported!",
224 _wavFormatObj.formatTag);
225 return -1;
226 }
227 if((_wavFormatObj.nChannels < 1) ||
228 (_wavFormatObj.nChannels > 2))
229 {
230 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
231 "nChannels value=%d not supported!",
232 _wavFormatObj.nChannels);
233 return -1;
234 }
235
236 if((_wavFormatObj.nBitsPerSample != 8) &&
237 (_wavFormatObj.nBitsPerSample != 16))
238 {
239 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
240 "nBitsPerSample value=%d not supported!",
241 _wavFormatObj.nBitsPerSample);
242 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 ((_wavFormatObj.formatTag == kWavFormatPcm) &&
248 (_wavFormatObj.nSamplesPerSec == 44100)) ?
249 440 : static_cast<size_t>(_wavFormatObj.nSamplesPerSec / 100);
250 _readSizeBytes = samples_per_10ms * _wavFormatObj.nChannels *
251 (_wavFormatObj.nBitsPerSample / 8);
252 return 0;
253 }
254
InitWavCodec(uint32_t samplesPerSec,size_t channels,uint32_t bitsPerSample,uint32_t formatTag)255 int32_t ModuleFileUtility::InitWavCodec(uint32_t samplesPerSec,
256 size_t channels,
257 uint32_t bitsPerSample,
258 uint32_t formatTag)
259 {
260 codec_info_.pltype = -1;
261 codec_info_.plfreq = samplesPerSec;
262 codec_info_.channels = channels;
263 codec_info_.rate = bitsPerSample * samplesPerSec;
264
265 // Calculate the packet size for 10ms frames
266 switch(formatTag)
267 {
268 case kWavFormatALaw:
269 strcpy(codec_info_.plname, "PCMA");
270 _codecId = kCodecPcma;
271 codec_info_.pltype = 8;
272 codec_info_.pacsize = codec_info_.plfreq / 100;
273 break;
274 case kWavFormatMuLaw:
275 strcpy(codec_info_.plname, "PCMU");
276 _codecId = kCodecPcmu;
277 codec_info_.pltype = 0;
278 codec_info_.pacsize = codec_info_.plfreq / 100;
279 break;
280 case kWavFormatPcm:
281 codec_info_.pacsize = (bitsPerSample * (codec_info_.plfreq / 100)) / 8;
282 if(samplesPerSec == 8000)
283 {
284 strcpy(codec_info_.plname, "L16");
285 _codecId = kCodecL16_8Khz;
286 }
287 else if(samplesPerSec == 16000)
288 {
289 strcpy(codec_info_.plname, "L16");
290 _codecId = kCodecL16_16kHz;
291 }
292 else if(samplesPerSec == 32000)
293 {
294 strcpy(codec_info_.plname, "L16");
295 _codecId = kCodecL16_32Khz;
296 }
297 // Set the packet size for "odd" sampling frequencies so that it
298 // properly corresponds to _readSizeBytes.
299 else if(samplesPerSec == 11025)
300 {
301 strcpy(codec_info_.plname, "L16");
302 _codecId = kCodecL16_16kHz;
303 codec_info_.pacsize = 110; // XXX inexact!
304 codec_info_.plfreq = 11000; // XXX inexact!
305 }
306 else if(samplesPerSec == 22050)
307 {
308 strcpy(codec_info_.plname, "L16");
309 _codecId = kCodecL16_16kHz;
310 codec_info_.pacsize = 220; // XXX inexact!
311 codec_info_.plfreq = 22000; // XXX inexact!
312 }
313 else if(samplesPerSec == 44100)
314 {
315 strcpy(codec_info_.plname, "L16");
316 _codecId = kCodecL16_16kHz;
317 codec_info_.pacsize = 441;
318 codec_info_.plfreq = 44100;
319 }
320 else if(samplesPerSec == 48000)
321 {
322 strcpy(codec_info_.plname, "L16");
323 _codecId = kCodecL16_16kHz;
324 codec_info_.pacsize = 480;
325 codec_info_.plfreq = 48000;
326 }
327 else
328 {
329 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
330 "Unsupported PCM frequency!");
331 return -1;
332 }
333 break;
334 default:
335 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
336 "unknown WAV format TAG!");
337 return -1;
338 break;
339 }
340 return 0;
341 }
342
InitWavReading(InStream & wav,const uint32_t start,const uint32_t stop)343 int32_t ModuleFileUtility::InitWavReading(InStream& wav,
344 const uint32_t start,
345 const uint32_t stop)
346 {
347
348 _reading = false;
349
350 if(ReadWavHeader(wav) == -1)
351 {
352 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
353 "failed to read WAV header!");
354 return -1;
355 }
356
357 _playoutPositionMs = 0;
358 _readPos = 0;
359
360 if(start > 0)
361 {
362 uint8_t dummy[WAV_MAX_BUFFER_SIZE];
363 int readLength;
364 if(_readSizeBytes <= WAV_MAX_BUFFER_SIZE)
365 {
366 while (_playoutPositionMs < start)
367 {
368 readLength = wav.Read(dummy, _readSizeBytes);
369 if(readLength == static_cast<int>(_readSizeBytes))
370 {
371 _readPos += _readSizeBytes;
372 _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 return -1;
379 }
380 }
381 }
382 else
383 {
384 return -1;
385 }
386 }
387 if( InitWavCodec(_wavFormatObj.nSamplesPerSec, _wavFormatObj.nChannels,
388 _wavFormatObj.nBitsPerSample,
389 _wavFormatObj.formatTag) != 0)
390 {
391 return -1;
392 }
393 _bytesPerSample = static_cast<size_t>(_wavFormatObj.nBitsPerSample / 8);
394
395
396 _startPointInMs = start;
397 _stopPointInMs = stop;
398 _reading = true;
399 return 0;
400 }
401
ReadWavDataAsMono(InStream & wav,int8_t * outData,const size_t bufferSize)402 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 const size_t totalBytesNeeded = _readSizeBytes;
419 // The number of bytes that will be written to outData.
420 const size_t bytesRequested = (codec_info_.channels == 2) ?
421 totalBytesNeeded >> 1 : totalBytesNeeded;
422 if(bufferSize < bytesRequested)
423 {
424 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
425 "ReadWavDataAsMono: output buffer is too short!");
426 return -1;
427 }
428 if(outData == NULL)
429 {
430 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
431 "ReadWavDataAsMono: output buffer NULL!");
432 return -1;
433 }
434
435 if(!_reading)
436 {
437 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
438 "ReadWavDataAsMono: no longer reading file.");
439 return -1;
440 }
441
442 int32_t bytesRead = ReadWavData(
443 wav,
444 (codec_info_.channels == 2) ? _tempData : (uint8_t*)outData,
445 totalBytesNeeded);
446 if(bytesRead == 0)
447 {
448 return 0;
449 }
450 if(bytesRead < 0)
451 {
452 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
453 "ReadWavDataAsMono: failed to read data from WAV file.");
454 return -1;
455 }
456 // Output data is should be mono.
457 if(codec_info_.channels == 2)
458 {
459 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 if(_bytesPerSample == 1)
464 {
465 _tempData[i] = ((_tempData[2 * i] + _tempData[(2 * i) + 1] +
466 1) >> 1);
467 }
468 else
469 {
470 int16_t* sampleData = (int16_t*) _tempData;
471 sampleData[i] = ((sampleData[2 * i] + sampleData[(2 * i) + 1] +
472 1) >> 1);
473 }
474 }
475 memcpy(outData, _tempData, bytesRequested);
476 }
477 return static_cast<int32_t>(bytesRequested);
478 }
479
ReadWavDataAsStereo(InStream & wav,int8_t * outDataLeft,int8_t * outDataRight,const size_t bufferSize)480 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 if((outDataLeft == NULL) ||
498 (outDataRight == NULL))
499 {
500 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
501 "ReadWavDataAsMono: an input buffer is NULL!");
502 return -1;
503 }
504 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 return -1;
512 }
513 if(! _reading)
514 {
515 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
516 "ReadWavDataAsStereo: no longer reading file.");
517 return -1;
518 }
519
520 // The number of bytes that should be read from file.
521 const size_t totalBytesNeeded = _readSizeBytes;
522 // The number of bytes that will be written to the left and the right
523 // buffers.
524 const size_t bytesRequested = totalBytesNeeded >> 1;
525 if(bufferSize < bytesRequested)
526 {
527 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
528 "ReadWavData: Output buffers are too short!");
529 assert(false);
530 return -1;
531 }
532
533 int32_t bytesRead = ReadWavData(wav, _tempData, totalBytesNeeded);
534 if(bytesRead <= 0)
535 {
536 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
537 "ReadWavDataAsStereo: failed to read data from WAV file.");
538 return -1;
539 }
540
541 // Turn interleaved audio to left and right buffer. Note samples can be
542 // either 1 or 2 bytes
543 if(_bytesPerSample == 1)
544 {
545 for (size_t i = 0; i < bytesRequested; i++)
546 {
547 outDataLeft[i] = _tempData[2 * i];
548 outDataRight[i] = _tempData[(2 * i) + 1];
549 }
550 }
551 else if(_bytesPerSample == 2)
552 {
553 int16_t* sampleData = reinterpret_cast<int16_t*>(_tempData);
554 int16_t* outLeft = reinterpret_cast<int16_t*>(outDataLeft);
555 int16_t* outRight = reinterpret_cast<int16_t*>(
556 outDataRight);
557
558 // Bytes requested to samples requested.
559 size_t sampleCount = bytesRequested >> 1;
560 for (size_t i = 0; i < sampleCount; i++)
561 {
562 outLeft[i] = sampleData[2 * i];
563 outRight[i] = sampleData[(2 * i) + 1];
564 }
565 } else {
566 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
567 "ReadWavStereoData: unsupported sample size %" PRIuS "!",
568 _bytesPerSample);
569 assert(false);
570 return -1;
571 }
572 return static_cast<int32_t>(bytesRequested);
573 }
574
ReadWavData(InStream & wav,uint8_t * buffer,size_t dataLengthInBytes)575 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 if(buffer == NULL)
585 {
586 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
587 "ReadWavDataAsMono: output buffer NULL!");
588 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 if(_dataSize < (_readPos + dataLengthInBytes))
595 {
596 // Rewind() being -1 may be due to the file not supposed to be looped.
597 if(wav.Rewind() == -1)
598 {
599 _reading = false;
600 return 0;
601 }
602 if(InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1)
603 {
604 _reading = false;
605 return -1;
606 }
607 }
608
609 int32_t bytesRead = wav.Read(buffer, dataLengthInBytes);
610 if(bytesRead < 0)
611 {
612 _reading = false;
613 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 if(bytesRead < (int32_t)dataLengthInBytes)
620 {
621 if((wav.Rewind() == -1) ||
622 (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1))
623 {
624 _reading = false;
625 return -1;
626 }
627 else
628 {
629 bytesRead = wav.Read(buffer, dataLengthInBytes);
630 if(bytesRead < (int32_t)dataLengthInBytes)
631 {
632 _reading = false;
633 return -1;
634 }
635 }
636 }
637
638 _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 _playoutPositionMs += 10;
643 if((_stopPointInMs > 0) &&
644 (_playoutPositionMs >= _stopPointInMs))
645 {
646 if((wav.Rewind() == -1) ||
647 (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1))
648 {
649 _reading = false;
650 }
651 }
652 return bytesRead;
653 }
654
InitWavWriting(OutStream & wav,const CodecInst & codecInst)655 int32_t ModuleFileUtility::InitWavWriting(OutStream& wav,
656 const CodecInst& codecInst)
657 {
658
659 if(set_codec_info(codecInst) != 0)
660 {
661 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
662 "codecInst identifies unsupported codec!");
663 return -1;
664 }
665 _writing = false;
666 size_t channels = (codecInst.channels == 0) ? 1 : codecInst.channels;
667
668 if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0)
669 {
670 _bytesPerSample = 1;
671 if(WriteWavHeader(wav, 8000, _bytesPerSample, channels,
672 kWavFormatMuLaw, 0) == -1)
673 {
674 return -1;
675 }
676 }
677 else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0)
678 {
679 _bytesPerSample = 1;
680 if(WriteWavHeader(wav, 8000, _bytesPerSample, channels, kWavFormatALaw,
681 0) == -1)
682 {
683 return -1;
684 }
685 }
686 else if(STR_CASE_CMP(codecInst.plname, "L16") == 0)
687 {
688 _bytesPerSample = 2;
689 if(WriteWavHeader(wav, codecInst.plfreq, _bytesPerSample, channels,
690 kWavFormatPcm, 0) == -1)
691 {
692 return -1;
693 }
694 }
695 else
696 {
697 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
698 "codecInst identifies unsupported codec for WAV file!");
699 return -1;
700 }
701 _writing = true;
702 _bytesWritten = 0;
703 return 0;
704 }
705
WriteWavData(OutStream & out,const int8_t * buffer,const size_t dataLength)706 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 if(buffer == NULL)
715 {
716 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
717 "WriteWavData: input buffer NULL!");
718 return -1;
719 }
720
721 if(!out.Write(buffer, dataLength))
722 {
723 return -1;
724 }
725 _bytesWritten += dataLength;
726 return static_cast<int32_t>(dataLength);
727 }
728
729
WriteWavHeader(OutStream & wav,uint32_t freq,size_t bytesPerSample,size_t channels,uint32_t format,size_t lengthInBytes)730 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 const size_t frameSize = (freq / 100) * channels;
740
741 // Calculate the number of full frames that the wave file contain.
742 const size_t dataLengthInBytes = frameSize * (lengthInBytes / frameSize);
743
744 uint8_t buf[kWavHeaderSize];
745 webrtc::WriteWavHeader(buf, channels, freq, static_cast<WavFormat>(format),
746 bytesPerSample, dataLengthInBytes / bytesPerSample);
747 wav.Write(buf, kWavHeaderSize);
748 return 0;
749 }
750
UpdateWavHeader(OutStream & wav)751 int32_t ModuleFileUtility::UpdateWavHeader(OutStream& wav)
752 {
753 int32_t res = -1;
754 if(wav.Rewind() == -1)
755 {
756 return -1;
757 }
758 size_t channels = (codec_info_.channels == 0) ? 1 : codec_info_.channels;
759
760 if(STR_CASE_CMP(codec_info_.plname, "L16") == 0)
761 {
762 res = WriteWavHeader(wav, codec_info_.plfreq, 2, channels,
763 kWavFormatPcm, _bytesWritten);
764 } else if(STR_CASE_CMP(codec_info_.plname, "PCMU") == 0) {
765 res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatMuLaw,
766 _bytesWritten);
767 } else if(STR_CASE_CMP(codec_info_.plname, "PCMA") == 0) {
768 res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatALaw,
769 _bytesWritten);
770 } else {
771 // Allow calling this API even if not writing to a WAVE file.
772 // TODO (hellner): why?!
773 return 0;
774 }
775 return res;
776 }
777
778
InitPreEncodedReading(InStream & in,const CodecInst & cinst)779 int32_t ModuleFileUtility::InitPreEncodedReading(InStream& in,
780 const CodecInst& cinst)
781 {
782
783 uint8_t preEncodedID;
784 in.Read(&preEncodedID, 1);
785
786 MediaFileUtility_CodecType codecType =
787 (MediaFileUtility_CodecType)preEncodedID;
788
789 if(set_codec_info(cinst) != 0)
790 {
791 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
792 "Pre-encoded file send codec mismatch!");
793 return -1;
794 }
795 if(codecType != _codecId)
796 {
797 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
798 "Pre-encoded file format codec mismatch!");
799 return -1;
800 }
801 memcpy(&codec_info_,&cinst,sizeof(CodecInst));
802 _reading = true;
803 return 0;
804 }
805
ReadPreEncodedData(InStream & in,int8_t * outData,const size_t bufferSize)806 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 int32_t res = in.Read(buf, 2);
825 if(res != 2)
826 {
827 if(!in.Rewind())
828 {
829 // The first byte is the codec identifier.
830 in.Read(buf, 1);
831 res = in.Read(buf, 2);
832 }
833 else
834 {
835 return -1;
836 }
837 }
838 frameLen = buf[0] + buf[1] * 256;
839 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 return -1;
845 }
846 return in.Read(outData, frameLen);
847 }
848
InitPreEncodedWriting(OutStream & out,const CodecInst & codecInst)849 int32_t ModuleFileUtility::InitPreEncodedWriting(
850 OutStream& out,
851 const CodecInst& codecInst)
852 {
853
854 if(set_codec_info(codecInst) != 0)
855 {
856 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "CodecInst not recognized!");
857 return -1;
858 }
859 _writing = true;
860 _bytesWritten = 1;
861 out.Write(&_codecId, 1);
862 return 0;
863 }
864
WritePreEncodedData(OutStream & out,const int8_t * buffer,const size_t dataLength)865 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 size_t bytesWritten = 0;
881 // The first two bytes is the size of the frame.
882 int16_t lengthBuf;
883 lengthBuf = (int16_t)dataLength;
884 if(dataLength > static_cast<size_t>(std::numeric_limits<int16_t>::max()) ||
885 !out.Write(&lengthBuf, 2))
886 {
887 return -1;
888 }
889 bytesWritten = 2;
890
891 if(!out.Write(buffer, dataLength))
892 {
893 return -1;
894 }
895 bytesWritten += dataLength;
896 return static_cast<int32_t>(bytesWritten);
897 }
898
InitCompressedReading(InStream & in,const uint32_t start,const uint32_t stop)899 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 _codecId = kCodecNoCodec;
912 _playoutPositionMs = 0;
913 _reading = false;
914
915 _startPointInMs = start;
916 _stopPointInMs = stop;
917
918 // Read the codec name
919 int32_t cnt = 0;
920 char buf[64];
921 do
922 {
923 in.Read(&buf[cnt++], 1);
924 } while ((buf[cnt-1] != '\n') && (64 > cnt));
925
926 if(cnt==64)
927 {
928 return -1;
929 }
930 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 if(_codecId == kCodecNoCodec)
982 {
983 return -1;
984 }
985 _reading = true;
986 return 0;
987 }
988
ReadCompressedData(InStream & in,int8_t * outData,size_t bufferSize)989 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 int bytesRead = 0;
998
999 if(! _reading)
1000 {
1001 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "not currently reading!");
1002 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 if(bytesRead == 0)
1049 {
1050 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1051 "ReadCompressedData() no bytes read, codec not supported");
1052 return -1;
1053 }
1054
1055 _playoutPositionMs += 20;
1056 if((_stopPointInMs > 0) &&
1057 (_playoutPositionMs >= _stopPointInMs))
1058 {
1059 if(!in.Rewind())
1060 {
1061 InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1062 }
1063 else
1064 {
1065 _reading = false;
1066 }
1067 }
1068 return bytesRead;
1069 }
1070
InitCompressedWriting(OutStream & out,const CodecInst & codecInst)1071 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 _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 return -1;
1109 }
1110
WriteCompressedData(OutStream & out,const int8_t * buffer,const size_t dataLength)1111 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 if(!out.Write(buffer, dataLength))
1126 {
1127 return -1;
1128 }
1129 return static_cast<int32_t>(dataLength);
1130 }
1131
InitPCMReading(InStream & pcm,const uint32_t start,const uint32_t stop,uint32_t freq)1132 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 _playoutPositionMs = 0;
1145 _startPointInMs = start;
1146 _stopPointInMs = stop;
1147 _reading = false;
1148
1149 if(freq == 8000)
1150 {
1151 strcpy(codec_info_.plname, "L16");
1152 codec_info_.pltype = -1;
1153 codec_info_.plfreq = 8000;
1154 codec_info_.pacsize = 160;
1155 codec_info_.channels = 1;
1156 codec_info_.rate = 128000;
1157 _codecId = kCodecL16_8Khz;
1158 }
1159 else if(freq == 16000)
1160 {
1161 strcpy(codec_info_.plname, "L16");
1162 codec_info_.pltype = -1;
1163 codec_info_.plfreq = 16000;
1164 codec_info_.pacsize = 320;
1165 codec_info_.channels = 1;
1166 codec_info_.rate = 256000;
1167 _codecId = kCodecL16_16kHz;
1168 }
1169 else if(freq == 32000)
1170 {
1171 strcpy(codec_info_.plname, "L16");
1172 codec_info_.pltype = -1;
1173 codec_info_.plfreq = 32000;
1174 codec_info_.pacsize = 320;
1175 codec_info_.channels = 1;
1176 codec_info_.rate = 512000;
1177 _codecId = kCodecL16_32Khz;
1178 }
1179
1180 // Readsize for 10ms of audio data (2 bytes per sample).
1181 _readSizeBytes = 2 * codec_info_. plfreq / 100;
1182 if(_startPointInMs > 0)
1183 {
1184 while (_playoutPositionMs < _startPointInMs)
1185 {
1186 read_len = pcm.Read(dummy, _readSizeBytes);
1187 if(read_len != static_cast<int>(_readSizeBytes))
1188 {
1189 return -1; // Must have reached EOF before start position!
1190 }
1191 _playoutPositionMs += 10;
1192 }
1193 }
1194 _reading = true;
1195 return 0;
1196 }
1197
ReadPCMData(InStream & pcm,int8_t * outData,size_t bufferSize)1198 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 size_t bytesRequested = static_cast<size_t>(2 * codec_info_.plfreq / 100);
1213 if(bufferSize < bytesRequested)
1214 {
1215 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1216 "ReadPCMData: buffer not long enough for a 10ms frame.");
1217 assert(false);
1218 return -1;
1219 }
1220
1221 int bytesRead = pcm.Read(outData, bytesRequested);
1222 if(bytesRead < static_cast<int>(bytesRequested))
1223 {
1224 if(pcm.Rewind() == -1)
1225 {
1226 _reading = false;
1227 }
1228 else
1229 {
1230 if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
1231 codec_info_.plfreq) == -1)
1232 {
1233 _reading = false;
1234 }
1235 else
1236 {
1237 size_t rest = bytesRequested - bytesRead;
1238 int len = pcm.Read(&(outData[bytesRead]), rest);
1239 if(len == static_cast<int>(rest))
1240 {
1241 bytesRead += len;
1242 }
1243 else
1244 {
1245 _reading = false;
1246 }
1247 }
1248 if(bytesRead <= 0)
1249 {
1250 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1251 "ReadPCMData: Failed to rewind audio file.");
1252 return -1;
1253 }
1254 }
1255 }
1256
1257 if(bytesRead <= 0)
1258 {
1259 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1260 "ReadPCMData: end of file");
1261 return -1;
1262 }
1263 _playoutPositionMs += 10;
1264 if(_stopPointInMs && _playoutPositionMs >= _stopPointInMs)
1265 {
1266 if(!pcm.Rewind())
1267 {
1268 if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
1269 codec_info_.plfreq) == -1)
1270 {
1271 _reading = false;
1272 }
1273 }
1274 }
1275 return bytesRead;
1276 }
1277
InitPCMWriting(OutStream & out,uint32_t freq)1278 int32_t ModuleFileUtility::InitPCMWriting(OutStream& out, uint32_t freq)
1279 {
1280
1281 if(freq == 8000)
1282 {
1283 strcpy(codec_info_.plname, "L16");
1284 codec_info_.pltype = -1;
1285 codec_info_.plfreq = 8000;
1286 codec_info_.pacsize = 160;
1287 codec_info_.channels = 1;
1288 codec_info_.rate = 128000;
1289
1290 _codecId = kCodecL16_8Khz;
1291 }
1292 else if(freq == 16000)
1293 {
1294 strcpy(codec_info_.plname, "L16");
1295 codec_info_.pltype = -1;
1296 codec_info_.plfreq = 16000;
1297 codec_info_.pacsize = 320;
1298 codec_info_.channels = 1;
1299 codec_info_.rate = 256000;
1300
1301 _codecId = kCodecL16_16kHz;
1302 }
1303 else if(freq == 32000)
1304 {
1305 strcpy(codec_info_.plname, "L16");
1306 codec_info_.pltype = -1;
1307 codec_info_.plfreq = 32000;
1308 codec_info_.pacsize = 320;
1309 codec_info_.channels = 1;
1310 codec_info_.rate = 512000;
1311
1312 _codecId = kCodecL16_32Khz;
1313 }
1314 if((_codecId != kCodecL16_8Khz) &&
1315 (_codecId != kCodecL16_16kHz) &&
1316 (_codecId != kCodecL16_32Khz))
1317 {
1318 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1319 "CodecInst is not 8KHz PCM or 16KHz PCM!");
1320 return -1;
1321 }
1322 _writing = true;
1323 _bytesWritten = 0;
1324 return 0;
1325 }
1326
WritePCMData(OutStream & out,const int8_t * buffer,const size_t dataLength)1327 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 if(!out.Write(buffer, dataLength))
1341 {
1342 return -1;
1343 }
1344
1345 _bytesWritten += dataLength;
1346 return static_cast<int32_t>(dataLength);
1347 }
1348
codec_info(CodecInst & codecInst)1349 int32_t ModuleFileUtility::codec_info(CodecInst& codecInst)
1350 {
1351 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1352 "ModuleFileUtility::codec_info(codecInst= 0x%x)", &codecInst);
1353
1354 if(!_reading && !_writing)
1355 {
1356 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1357 "CodecInst: not currently reading audio file!");
1358 return -1;
1359 }
1360 memcpy(&codecInst,&codec_info_,sizeof(CodecInst));
1361 return 0;
1362 }
1363
set_codec_info(const CodecInst & codecInst)1364 int32_t ModuleFileUtility::set_codec_info(const CodecInst& codecInst)
1365 {
1366
1367 _codecId = kCodecNoCodec;
1368 if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0)
1369 {
1370 _codecId = kCodecPcmu;
1371 }
1372 else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0)
1373 {
1374 _codecId = kCodecPcma;
1375 }
1376 else if(STR_CASE_CMP(codecInst.plname, "L16") == 0)
1377 {
1378 if(codecInst.plfreq == 8000)
1379 {
1380 _codecId = kCodecL16_8Khz;
1381 }
1382 else if(codecInst.plfreq == 16000)
1383 {
1384 _codecId = kCodecL16_16kHz;
1385 }
1386 else if(codecInst.plfreq == 32000)
1387 {
1388 _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 if(_codecId == kCodecNoCodec)
1424 {
1425 return -1;
1426 }
1427 memcpy(&codec_info_, &codecInst, sizeof(CodecInst));
1428 return 0;
1429 }
1430
FileDurationMs(const char * fileName,const FileFormats fileFormat,const uint32_t freqInHz)1431 int32_t ModuleFileUtility::FileDurationMs(const char* fileName,
1432 const FileFormats fileFormat,
1433 const uint32_t freqInHz)
1434 {
1435
1436 if(fileName == NULL)
1437 {
1438 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "filename NULL");
1439 return -1;
1440 }
1441
1442 int32_t time_in_ms = -1;
1443 struct stat file_size;
1444 if(stat(fileName,&file_size) == -1)
1445 {
1446 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1447 "failed to retrieve file size with stat!");
1448 return -1;
1449 }
1450 FileWrapper* inStreamObj = FileWrapper::Create();
1451 if(inStreamObj == NULL)
1452 {
1453 WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
1454 "failed to create InStream object!");
1455 return -1;
1456 }
1457 if (!inStreamObj->OpenFile(fileName, true)) {
1458 delete inStreamObj;
1459 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "failed to open file %s!",
1460 fileName);
1461 return -1;
1462 }
1463
1464 switch (fileFormat)
1465 {
1466 case kFileFormatWavFile:
1467 {
1468 if(ReadWavHeader(*inStreamObj) == -1)
1469 {
1470 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1471 "failed to read WAV file header!");
1472 return -1;
1473 }
1474 time_in_ms = ((file_size.st_size - 44) /
1475 (_wavFormatObj.nAvgBytesPerSec/1000));
1476 break;
1477 }
1478 case kFileFormatPcm16kHzFile:
1479 {
1480 // 16 samples per ms. 2 bytes per sample.
1481 int32_t denominator = 16*2;
1482 time_in_ms = (file_size.st_size)/denominator;
1483 break;
1484 }
1485 case kFileFormatPcm8kHzFile:
1486 {
1487 // 8 samples per ms. 2 bytes per sample.
1488 int32_t denominator = 8*2;
1489 time_in_ms = (file_size.st_size)/denominator;
1490 break;
1491 }
1492 case kFileFormatCompressedFile:
1493 {
1494 int32_t cnt = 0;
1495 int read_len = 0;
1496 char buf[64];
1497 do
1498 {
1499 read_len = inStreamObj->Read(&buf[cnt++], 1);
1500 if(read_len != 1)
1501 {
1502 return -1;
1503 }
1504 } while ((buf[cnt-1] != '\n') && (64 > cnt));
1505
1506 if(cnt == 64)
1507 {
1508 return -1;
1509 }
1510 else
1511 {
1512 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 break;
1532 }
1533 case kFileFormatPreencodedFile:
1534 {
1535 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1536 "cannot determine duration of Pre-Encoded file!");
1537 break;
1538 }
1539 default:
1540 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1541 "unsupported file format %d!", fileFormat);
1542 break;
1543 }
1544 inStreamObj->CloseFile();
1545 delete inStreamObj;
1546 return time_in_ms;
1547 }
1548
PlayoutPositionMs()1549 uint32_t ModuleFileUtility::PlayoutPositionMs()
1550 {
1551 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1552 "ModuleFileUtility::PlayoutPosition()");
1553
1554 return _reading ? _playoutPositionMs : 0;
1555 }
1556 } // namespace webrtc
1557