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/engine_configurations.h"
22 #include "webrtc/modules/include/module_common_types.h"
23 #include "webrtc/system_wrappers/include/file_wrapper.h"
24 #include "webrtc/system_wrappers/include/trace.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;
304 codec_info_.plfreq = 11000;
305 }
306 else if(samplesPerSec == 22050)
307 {
308 strcpy(codec_info_.plname, "L16");
309 _codecId = kCodecL16_16kHz;
310 codec_info_.pacsize = 220;
311 codec_info_.plfreq = 22000;
312 }
313 else if(samplesPerSec == 44100)
314 {
315 strcpy(codec_info_.plname, "L16");
316 _codecId = kCodecL16_16kHz;
317 codec_info_.pacsize = 440;
318 codec_info_.plfreq = 44000;
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 // TODO (hellner): 44.1 kHz has 440 samples frame size. Doesn't seem to
740 // be taken into consideration here!
741 const size_t frameSize = (freq / 100) * channels;
742
743 // Calculate the number of full frames that the wave file contain.
744 const size_t dataLengthInBytes = frameSize * (lengthInBytes / frameSize);
745
746 uint8_t buf[kWavHeaderSize];
747 webrtc::WriteWavHeader(buf, channels, freq, static_cast<WavFormat>(format),
748 bytesPerSample, dataLengthInBytes / bytesPerSample);
749 wav.Write(buf, kWavHeaderSize);
750 return 0;
751 }
752
UpdateWavHeader(OutStream & wav)753 int32_t ModuleFileUtility::UpdateWavHeader(OutStream& wav)
754 {
755 int32_t res = -1;
756 if(wav.Rewind() == -1)
757 {
758 return -1;
759 }
760 size_t channels = (codec_info_.channels == 0) ? 1 : codec_info_.channels;
761
762 if(STR_CASE_CMP(codec_info_.plname, "L16") == 0)
763 {
764 res = WriteWavHeader(wav, codec_info_.plfreq, 2, channels,
765 kWavFormatPcm, _bytesWritten);
766 } else if(STR_CASE_CMP(codec_info_.plname, "PCMU") == 0) {
767 res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatMuLaw,
768 _bytesWritten);
769 } else if(STR_CASE_CMP(codec_info_.plname, "PCMA") == 0) {
770 res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatALaw,
771 _bytesWritten);
772 } else {
773 // Allow calling this API even if not writing to a WAVE file.
774 // TODO (hellner): why?!
775 return 0;
776 }
777 return res;
778 }
779
780
InitPreEncodedReading(InStream & in,const CodecInst & cinst)781 int32_t ModuleFileUtility::InitPreEncodedReading(InStream& in,
782 const CodecInst& cinst)
783 {
784
785 uint8_t preEncodedID;
786 in.Read(&preEncodedID, 1);
787
788 MediaFileUtility_CodecType codecType =
789 (MediaFileUtility_CodecType)preEncodedID;
790
791 if(set_codec_info(cinst) != 0)
792 {
793 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
794 "Pre-encoded file send codec mismatch!");
795 return -1;
796 }
797 if(codecType != _codecId)
798 {
799 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
800 "Pre-encoded file format codec mismatch!");
801 return -1;
802 }
803 memcpy(&codec_info_,&cinst,sizeof(CodecInst));
804 _reading = true;
805 return 0;
806 }
807
ReadPreEncodedData(InStream & in,int8_t * outData,const size_t bufferSize)808 int32_t ModuleFileUtility::ReadPreEncodedData(
809 InStream& in,
810 int8_t* outData,
811 const size_t bufferSize)
812 {
813 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
814 "ModuleFileUtility::ReadPreEncodedData(in= 0x%x, "
815 "outData= 0x%x, bufferSize= %" PRIuS ")", &in, outData,
816 bufferSize);
817
818 if(outData == NULL)
819 {
820 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "output buffer NULL");
821 }
822
823 size_t frameLen;
824 uint8_t buf[64];
825 // Each frame has a two byte header containing the frame length.
826 int32_t res = in.Read(buf, 2);
827 if(res != 2)
828 {
829 if(!in.Rewind())
830 {
831 // The first byte is the codec identifier.
832 in.Read(buf, 1);
833 res = in.Read(buf, 2);
834 }
835 else
836 {
837 return -1;
838 }
839 }
840 frameLen = buf[0] + buf[1] * 256;
841 if(bufferSize < frameLen)
842 {
843 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
844 "buffer not large enough to read %" PRIuS " bytes of "
845 "pre-encoded data!", frameLen);
846 return -1;
847 }
848 return in.Read(outData, frameLen);
849 }
850
InitPreEncodedWriting(OutStream & out,const CodecInst & codecInst)851 int32_t ModuleFileUtility::InitPreEncodedWriting(
852 OutStream& out,
853 const CodecInst& codecInst)
854 {
855
856 if(set_codec_info(codecInst) != 0)
857 {
858 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "CodecInst not recognized!");
859 return -1;
860 }
861 _writing = true;
862 _bytesWritten = 1;
863 out.Write(&_codecId, 1);
864 return 0;
865 }
866
WritePreEncodedData(OutStream & out,const int8_t * buffer,const size_t dataLength)867 int32_t ModuleFileUtility::WritePreEncodedData(
868 OutStream& out,
869 const int8_t* buffer,
870 const size_t dataLength)
871 {
872 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
873 "ModuleFileUtility::WritePreEncodedData(out= 0x%x, "
874 "inData= 0x%x, dataLen= %" PRIuS ")", &out, buffer,
875 dataLength);
876
877 if(buffer == NULL)
878 {
879 WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL");
880 }
881
882 size_t bytesWritten = 0;
883 // The first two bytes is the size of the frame.
884 int16_t lengthBuf;
885 lengthBuf = (int16_t)dataLength;
886 if(dataLength > static_cast<size_t>(std::numeric_limits<int16_t>::max()) ||
887 !out.Write(&lengthBuf, 2))
888 {
889 return -1;
890 }
891 bytesWritten = 2;
892
893 if(!out.Write(buffer, dataLength))
894 {
895 return -1;
896 }
897 bytesWritten += dataLength;
898 return static_cast<int32_t>(bytesWritten);
899 }
900
InitCompressedReading(InStream & in,const uint32_t start,const uint32_t stop)901 int32_t ModuleFileUtility::InitCompressedReading(
902 InStream& in,
903 const uint32_t start,
904 const uint32_t stop)
905 {
906 WEBRTC_TRACE(kTraceDebug, kTraceFile, _id,
907 "ModuleFileUtility::InitCompressedReading(in= 0x%x, "
908 "start= %d, stop= %d)", &in, start, stop);
909
910 #if defined(WEBRTC_CODEC_ILBC)
911 int16_t read_len = 0;
912 #endif
913 _codecId = kCodecNoCodec;
914 _playoutPositionMs = 0;
915 _reading = false;
916
917 _startPointInMs = start;
918 _stopPointInMs = stop;
919
920 // Read the codec name
921 int32_t cnt = 0;
922 char buf[64];
923 do
924 {
925 in.Read(&buf[cnt++], 1);
926 } while ((buf[cnt-1] != '\n') && (64 > cnt));
927
928 if(cnt==64)
929 {
930 return -1;
931 }
932 buf[cnt]=0;
933
934 #ifdef WEBRTC_CODEC_ILBC
935 if(!strcmp("#!iLBC20\n", buf))
936 {
937 codec_info_.pltype = 102;
938 strcpy(codec_info_.plname, "ilbc");
939 codec_info_.plfreq = 8000;
940 codec_info_.pacsize = 160;
941 codec_info_.channels = 1;
942 codec_info_.rate = 13300;
943 _codecId = kCodecIlbc20Ms;
944
945 if(_startPointInMs > 0)
946 {
947 while (_playoutPositionMs <= _startPointInMs)
948 {
949 read_len = in.Read(buf, 38);
950 if(read_len != 38)
951 {
952 return -1;
953 }
954 _playoutPositionMs += 20;
955 }
956 }
957 }
958
959 if(!strcmp("#!iLBC30\n", buf))
960 {
961 codec_info_.pltype = 102;
962 strcpy(codec_info_.plname, "ilbc");
963 codec_info_.plfreq = 8000;
964 codec_info_.pacsize = 240;
965 codec_info_.channels = 1;
966 codec_info_.rate = 13300;
967 _codecId = kCodecIlbc30Ms;
968
969 if(_startPointInMs > 0)
970 {
971 while (_playoutPositionMs <= _startPointInMs)
972 {
973 read_len = in.Read(buf, 50);
974 if(read_len != 50)
975 {
976 return -1;
977 }
978 _playoutPositionMs += 20;
979 }
980 }
981 }
982 #endif
983 if(_codecId == kCodecNoCodec)
984 {
985 return -1;
986 }
987 _reading = true;
988 return 0;
989 }
990
ReadCompressedData(InStream & in,int8_t * outData,size_t bufferSize)991 int32_t ModuleFileUtility::ReadCompressedData(InStream& in,
992 int8_t* outData,
993 size_t bufferSize)
994 {
995 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
996 "ModuleFileUtility::ReadCompressedData(in=0x%x, outData=0x%x, "
997 "bytes=%" PRIuS ")", &in, outData, bufferSize);
998
999 int bytesRead = 0;
1000
1001 if(! _reading)
1002 {
1003 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "not currently reading!");
1004 return -1;
1005 }
1006
1007 #ifdef WEBRTC_CODEC_ILBC
1008 if((_codecId == kCodecIlbc20Ms) ||
1009 (_codecId == kCodecIlbc30Ms))
1010 {
1011 size_t byteSize = 0;
1012 if(_codecId == kCodecIlbc30Ms)
1013 {
1014 byteSize = 50;
1015 }
1016 if(_codecId == kCodecIlbc20Ms)
1017 {
1018 byteSize = 38;
1019 }
1020 if(bufferSize < byteSize)
1021 {
1022 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1023 "output buffer is too short to read ILBC compressed "
1024 "data.");
1025 assert(false);
1026 return -1;
1027 }
1028
1029 bytesRead = in.Read(outData, byteSize);
1030 if(bytesRead != static_cast<int>(byteSize))
1031 {
1032 if(!in.Rewind())
1033 {
1034 InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1035 bytesRead = in.Read(outData, byteSize);
1036 if(bytesRead != static_cast<int>(byteSize))
1037 {
1038 _reading = false;
1039 return -1;
1040 }
1041 }
1042 else
1043 {
1044 _reading = false;
1045 return -1;
1046 }
1047 }
1048 }
1049 #endif
1050 if(bytesRead == 0)
1051 {
1052 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1053 "ReadCompressedData() no bytes read, codec not supported");
1054 return -1;
1055 }
1056
1057 _playoutPositionMs += 20;
1058 if((_stopPointInMs > 0) &&
1059 (_playoutPositionMs >= _stopPointInMs))
1060 {
1061 if(!in.Rewind())
1062 {
1063 InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1064 }
1065 else
1066 {
1067 _reading = false;
1068 }
1069 }
1070 return bytesRead;
1071 }
1072
InitCompressedWriting(OutStream & out,const CodecInst & codecInst)1073 int32_t ModuleFileUtility::InitCompressedWriting(
1074 OutStream& out,
1075 const CodecInst& codecInst)
1076 {
1077 WEBRTC_TRACE(kTraceDebug, kTraceFile, _id,
1078 "ModuleFileUtility::InitCompressedWriting(out= 0x%x, "
1079 "codecName= %s)", &out, codecInst.plname);
1080
1081 _writing = false;
1082
1083 #ifdef WEBRTC_CODEC_ILBC
1084 if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0)
1085 {
1086 if(codecInst.pacsize == 160)
1087 {
1088 _codecId = kCodecIlbc20Ms;
1089 out.Write("#!iLBC20\n",9);
1090 }
1091 else if(codecInst.pacsize == 240)
1092 {
1093 _codecId = kCodecIlbc30Ms;
1094 out.Write("#!iLBC30\n",9);
1095 }
1096 else
1097 {
1098 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1099 "codecInst defines unsupported compression codec!");
1100 return -1;
1101 }
1102 memcpy(&codec_info_,&codecInst,sizeof(CodecInst));
1103 _writing = true;
1104 return 0;
1105 }
1106 #endif
1107
1108 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1109 "codecInst defines unsupported compression codec!");
1110 return -1;
1111 }
1112
WriteCompressedData(OutStream & out,const int8_t * buffer,const size_t dataLength)1113 int32_t ModuleFileUtility::WriteCompressedData(
1114 OutStream& out,
1115 const int8_t* buffer,
1116 const size_t dataLength)
1117 {
1118 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1119 "ModuleFileUtility::WriteCompressedData(out= 0x%x, buf= 0x%x, "
1120 "dataLen= %" PRIuS ")", &out, buffer, dataLength);
1121
1122 if(buffer == NULL)
1123 {
1124 WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL");
1125 }
1126
1127 if(!out.Write(buffer, dataLength))
1128 {
1129 return -1;
1130 }
1131 return static_cast<int32_t>(dataLength);
1132 }
1133
InitPCMReading(InStream & pcm,const uint32_t start,const uint32_t stop,uint32_t freq)1134 int32_t ModuleFileUtility::InitPCMReading(InStream& pcm,
1135 const uint32_t start,
1136 const uint32_t stop,
1137 uint32_t freq)
1138 {
1139 WEBRTC_TRACE(kTraceInfo, kTraceFile, _id,
1140 "ModuleFileUtility::InitPCMReading(pcm= 0x%x, start=%d, "
1141 "stop=%d, freq=%d)", &pcm, start, stop, freq);
1142
1143 int8_t dummy[320];
1144 int read_len;
1145
1146 _playoutPositionMs = 0;
1147 _startPointInMs = start;
1148 _stopPointInMs = stop;
1149 _reading = false;
1150
1151 if(freq == 8000)
1152 {
1153 strcpy(codec_info_.plname, "L16");
1154 codec_info_.pltype = -1;
1155 codec_info_.plfreq = 8000;
1156 codec_info_.pacsize = 160;
1157 codec_info_.channels = 1;
1158 codec_info_.rate = 128000;
1159 _codecId = kCodecL16_8Khz;
1160 }
1161 else if(freq == 16000)
1162 {
1163 strcpy(codec_info_.plname, "L16");
1164 codec_info_.pltype = -1;
1165 codec_info_.plfreq = 16000;
1166 codec_info_.pacsize = 320;
1167 codec_info_.channels = 1;
1168 codec_info_.rate = 256000;
1169 _codecId = kCodecL16_16kHz;
1170 }
1171 else if(freq == 32000)
1172 {
1173 strcpy(codec_info_.plname, "L16");
1174 codec_info_.pltype = -1;
1175 codec_info_.plfreq = 32000;
1176 codec_info_.pacsize = 320;
1177 codec_info_.channels = 1;
1178 codec_info_.rate = 512000;
1179 _codecId = kCodecL16_32Khz;
1180 }
1181
1182 // Readsize for 10ms of audio data (2 bytes per sample).
1183 _readSizeBytes = 2 * codec_info_. plfreq / 100;
1184 if(_startPointInMs > 0)
1185 {
1186 while (_playoutPositionMs < _startPointInMs)
1187 {
1188 read_len = pcm.Read(dummy, _readSizeBytes);
1189 if(read_len != static_cast<int>(_readSizeBytes))
1190 {
1191 return -1; // Must have reached EOF before start position!
1192 }
1193 _playoutPositionMs += 10;
1194 }
1195 }
1196 _reading = true;
1197 return 0;
1198 }
1199
ReadPCMData(InStream & pcm,int8_t * outData,size_t bufferSize)1200 int32_t ModuleFileUtility::ReadPCMData(InStream& pcm,
1201 int8_t* outData,
1202 size_t bufferSize)
1203 {
1204 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1205 "ModuleFileUtility::ReadPCMData(pcm= 0x%x, outData= 0x%x, "
1206 "bufSize= %" PRIuS ")", &pcm, outData, bufferSize);
1207
1208 if(outData == NULL)
1209 {
1210 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "buffer NULL");
1211 }
1212
1213 // Readsize for 10ms of audio data (2 bytes per sample).
1214 size_t bytesRequested = static_cast<size_t>(2 * codec_info_.plfreq / 100);
1215 if(bufferSize < bytesRequested)
1216 {
1217 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1218 "ReadPCMData: buffer not long enough for a 10ms frame.");
1219 assert(false);
1220 return -1;
1221 }
1222
1223 int bytesRead = pcm.Read(outData, bytesRequested);
1224 if(bytesRead < static_cast<int>(bytesRequested))
1225 {
1226 if(pcm.Rewind() == -1)
1227 {
1228 _reading = false;
1229 }
1230 else
1231 {
1232 if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
1233 codec_info_.plfreq) == -1)
1234 {
1235 _reading = false;
1236 }
1237 else
1238 {
1239 size_t rest = bytesRequested - bytesRead;
1240 int len = pcm.Read(&(outData[bytesRead]), rest);
1241 if(len == static_cast<int>(rest))
1242 {
1243 bytesRead += len;
1244 }
1245 else
1246 {
1247 _reading = false;
1248 }
1249 }
1250 if(bytesRead <= 0)
1251 {
1252 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1253 "ReadPCMData: Failed to rewind audio file.");
1254 return -1;
1255 }
1256 }
1257 }
1258
1259 if(bytesRead <= 0)
1260 {
1261 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1262 "ReadPCMData: end of file");
1263 return -1;
1264 }
1265 _playoutPositionMs += 10;
1266 if(_stopPointInMs && _playoutPositionMs >= _stopPointInMs)
1267 {
1268 if(!pcm.Rewind())
1269 {
1270 if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
1271 codec_info_.plfreq) == -1)
1272 {
1273 _reading = false;
1274 }
1275 }
1276 }
1277 return bytesRead;
1278 }
1279
InitPCMWriting(OutStream & out,uint32_t freq)1280 int32_t ModuleFileUtility::InitPCMWriting(OutStream& out, uint32_t freq)
1281 {
1282
1283 if(freq == 8000)
1284 {
1285 strcpy(codec_info_.plname, "L16");
1286 codec_info_.pltype = -1;
1287 codec_info_.plfreq = 8000;
1288 codec_info_.pacsize = 160;
1289 codec_info_.channels = 1;
1290 codec_info_.rate = 128000;
1291
1292 _codecId = kCodecL16_8Khz;
1293 }
1294 else if(freq == 16000)
1295 {
1296 strcpy(codec_info_.plname, "L16");
1297 codec_info_.pltype = -1;
1298 codec_info_.plfreq = 16000;
1299 codec_info_.pacsize = 320;
1300 codec_info_.channels = 1;
1301 codec_info_.rate = 256000;
1302
1303 _codecId = kCodecL16_16kHz;
1304 }
1305 else if(freq == 32000)
1306 {
1307 strcpy(codec_info_.plname, "L16");
1308 codec_info_.pltype = -1;
1309 codec_info_.plfreq = 32000;
1310 codec_info_.pacsize = 320;
1311 codec_info_.channels = 1;
1312 codec_info_.rate = 512000;
1313
1314 _codecId = kCodecL16_32Khz;
1315 }
1316 if((_codecId != kCodecL16_8Khz) &&
1317 (_codecId != kCodecL16_16kHz) &&
1318 (_codecId != kCodecL16_32Khz))
1319 {
1320 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1321 "CodecInst is not 8KHz PCM or 16KHz PCM!");
1322 return -1;
1323 }
1324 _writing = true;
1325 _bytesWritten = 0;
1326 return 0;
1327 }
1328
WritePCMData(OutStream & out,const int8_t * buffer,const size_t dataLength)1329 int32_t ModuleFileUtility::WritePCMData(OutStream& out,
1330 const int8_t* buffer,
1331 const size_t dataLength)
1332 {
1333 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1334 "ModuleFileUtility::WritePCMData(out= 0x%x, buf= 0x%x, "
1335 "dataLen= %" PRIuS ")", &out, buffer, dataLength);
1336
1337 if(buffer == NULL)
1338 {
1339 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "buffer NULL");
1340 }
1341
1342 if(!out.Write(buffer, dataLength))
1343 {
1344 return -1;
1345 }
1346
1347 _bytesWritten += dataLength;
1348 return static_cast<int32_t>(dataLength);
1349 }
1350
codec_info(CodecInst & codecInst)1351 int32_t ModuleFileUtility::codec_info(CodecInst& codecInst)
1352 {
1353 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1354 "ModuleFileUtility::codec_info(codecInst= 0x%x)", &codecInst);
1355
1356 if(!_reading && !_writing)
1357 {
1358 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1359 "CodecInst: not currently reading audio file!");
1360 return -1;
1361 }
1362 memcpy(&codecInst,&codec_info_,sizeof(CodecInst));
1363 return 0;
1364 }
1365
set_codec_info(const CodecInst & codecInst)1366 int32_t ModuleFileUtility::set_codec_info(const CodecInst& codecInst)
1367 {
1368
1369 _codecId = kCodecNoCodec;
1370 if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0)
1371 {
1372 _codecId = kCodecPcmu;
1373 }
1374 else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0)
1375 {
1376 _codecId = kCodecPcma;
1377 }
1378 else if(STR_CASE_CMP(codecInst.plname, "L16") == 0)
1379 {
1380 if(codecInst.plfreq == 8000)
1381 {
1382 _codecId = kCodecL16_8Khz;
1383 }
1384 else if(codecInst.plfreq == 16000)
1385 {
1386 _codecId = kCodecL16_16kHz;
1387 }
1388 else if(codecInst.plfreq == 32000)
1389 {
1390 _codecId = kCodecL16_32Khz;
1391 }
1392 }
1393 #ifdef WEBRTC_CODEC_ILBC
1394 else if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0)
1395 {
1396 if(codecInst.pacsize == 160)
1397 {
1398 _codecId = kCodecIlbc20Ms;
1399 }
1400 else if(codecInst.pacsize == 240)
1401 {
1402 _codecId = kCodecIlbc30Ms;
1403 }
1404 }
1405 #endif
1406 #if(defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
1407 else if(STR_CASE_CMP(codecInst.plname, "isac") == 0)
1408 {
1409 if(codecInst.plfreq == 16000)
1410 {
1411 _codecId = kCodecIsac;
1412 }
1413 else if(codecInst.plfreq == 32000)
1414 {
1415 _codecId = kCodecIsacSwb;
1416 }
1417 }
1418 #endif
1419 #ifdef WEBRTC_CODEC_G722
1420 else if(STR_CASE_CMP(codecInst.plname, "G722") == 0)
1421 {
1422 _codecId = kCodecG722;
1423 }
1424 #endif
1425 if(_codecId == kCodecNoCodec)
1426 {
1427 return -1;
1428 }
1429 memcpy(&codec_info_, &codecInst, sizeof(CodecInst));
1430 return 0;
1431 }
1432
FileDurationMs(const char * fileName,const FileFormats fileFormat,const uint32_t freqInHz)1433 int32_t ModuleFileUtility::FileDurationMs(const char* fileName,
1434 const FileFormats fileFormat,
1435 const uint32_t freqInHz)
1436 {
1437
1438 if(fileName == NULL)
1439 {
1440 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "filename NULL");
1441 return -1;
1442 }
1443
1444 int32_t time_in_ms = -1;
1445 struct stat file_size;
1446 if(stat(fileName,&file_size) == -1)
1447 {
1448 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1449 "failed to retrieve file size with stat!");
1450 return -1;
1451 }
1452 FileWrapper* inStreamObj = FileWrapper::Create();
1453 if(inStreamObj == NULL)
1454 {
1455 WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
1456 "failed to create InStream object!");
1457 return -1;
1458 }
1459 if(inStreamObj->OpenFile(fileName, true) == -1)
1460 {
1461 delete inStreamObj;
1462 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1463 "failed to open file %s!", fileName);
1464 return -1;
1465 }
1466
1467 switch (fileFormat)
1468 {
1469 case kFileFormatWavFile:
1470 {
1471 if(ReadWavHeader(*inStreamObj) == -1)
1472 {
1473 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1474 "failed to read WAV file header!");
1475 return -1;
1476 }
1477 time_in_ms = ((file_size.st_size - 44) /
1478 (_wavFormatObj.nAvgBytesPerSec/1000));
1479 break;
1480 }
1481 case kFileFormatPcm16kHzFile:
1482 {
1483 // 16 samples per ms. 2 bytes per sample.
1484 int32_t denominator = 16*2;
1485 time_in_ms = (file_size.st_size)/denominator;
1486 break;
1487 }
1488 case kFileFormatPcm8kHzFile:
1489 {
1490 // 8 samples per ms. 2 bytes per sample.
1491 int32_t denominator = 8*2;
1492 time_in_ms = (file_size.st_size)/denominator;
1493 break;
1494 }
1495 case kFileFormatCompressedFile:
1496 {
1497 int32_t cnt = 0;
1498 int read_len = 0;
1499 char buf[64];
1500 do
1501 {
1502 read_len = inStreamObj->Read(&buf[cnt++], 1);
1503 if(read_len != 1)
1504 {
1505 return -1;
1506 }
1507 } while ((buf[cnt-1] != '\n') && (64 > cnt));
1508
1509 if(cnt == 64)
1510 {
1511 return -1;
1512 }
1513 else
1514 {
1515 buf[cnt] = 0;
1516 }
1517 #ifdef WEBRTC_CODEC_ILBC
1518 if(!strcmp("#!iLBC20\n", buf))
1519 {
1520 // 20 ms is 304 bits
1521 time_in_ms = ((file_size.st_size)*160)/304;
1522 break;
1523 }
1524 if(!strcmp("#!iLBC30\n", buf))
1525 {
1526 // 30 ms takes 400 bits.
1527 // file size in bytes * 8 / 400 is the number of
1528 // 30 ms frames in the file ->
1529 // time_in_ms = file size * 8 / 400 * 30
1530 time_in_ms = ((file_size.st_size)*240)/400;
1531 break;
1532 }
1533 #endif
1534 break;
1535 }
1536 case kFileFormatPreencodedFile:
1537 {
1538 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1539 "cannot determine duration of Pre-Encoded file!");
1540 break;
1541 }
1542 default:
1543 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1544 "unsupported file format %d!", fileFormat);
1545 break;
1546 }
1547 inStreamObj->CloseFile();
1548 delete inStreamObj;
1549 return time_in_ms;
1550 }
1551
PlayoutPositionMs()1552 uint32_t ModuleFileUtility::PlayoutPositionMs()
1553 {
1554 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1555 "ModuleFileUtility::PlayoutPosition()");
1556
1557 return _reading ? _playoutPositionMs : 0;
1558 }
1559 } // namespace webrtc
1560