blob: ae8d06f634054ef7738167840c6e9a2c45e33a7d [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
xians@webrtc.org03039d52012-02-20 08:37:49 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
Henrik Kjellander0b9e29c2015-11-16 11:12:24 +010011#include "webrtc/modules/media_file/media_file_utility.h"
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +000012
niklase@google.com470e71d2011-07-07 08:21:25 +000013#include <assert.h>
14#include <sys/stat.h>
15#include <sys/types.h>
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000016#include <limits>
niklase@google.com470e71d2011-07-07 08:21:25 +000017
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000018#include "webrtc/base/format_macros.h"
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +000019#include "webrtc/common_audio/wav_header.h"
pbos@webrtc.org0c4e05a2013-07-16 13:05:40 +000020#include "webrtc/common_types.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010021#include "webrtc/modules/include/module_common_types.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010022#include "webrtc/system_wrappers/include/file_wrapper.h"
23#include "webrtc/system_wrappers/include/trace.h"
henrik.lundina9a6d4b2016-12-12 05:03:02 -080024#include "webrtc/typedefs.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000025
niklase@google.com470e71d2011-07-07 08:21:25 +000026namespace {
niklase@google.com470e71d2011-07-07 08:21:25 +000027
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)
30struct WAVE_RIFF_header
31{
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +000032 int8_t ckID[4];
33 int32_t ckSize;
34 int8_t wave_ckID[4];
niklase@google.com470e71d2011-07-07 08:21:25 +000035};
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)
39struct WAVE_CHUNK_header
40{
pkasting25702cb2016-01-08 13:50:27 -080041 int8_t fmt_ckID[4];
42 uint32_t fmt_ckSize;
niklase@google.com470e71d2011-07-07 08:21:25 +000043};
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +000044} // unnamed namespace
niklase@google.com470e71d2011-07-07 08:21:25 +000045
46namespace webrtc {
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +000047ModuleFileUtility::ModuleFileUtility(const int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +000048 : _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),
andresp@webrtc.orge8f50df2015-03-02 13:07:02 +000062 _tempData() {
niklase@google.com470e71d2011-07-07 08:21:25 +000063 WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
64 "ModuleFileUtility::ModuleFileUtility()");
65 memset(&codec_info_,0,sizeof(CodecInst));
66 codec_info_.pltype = -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000067}
68
69ModuleFileUtility::~ModuleFileUtility()
70{
71 WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
72 "ModuleFileUtility::~ModuleFileUtility()");
niklase@google.com470e71d2011-07-07 08:21:25 +000073}
74
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +000075int32_t ModuleFileUtility::ReadWavHeader(InStream& wav)
niklase@google.com470e71d2011-07-07 08:21:25 +000076{
77 WAVE_RIFF_header RIFFheaderObj;
78 WAVE_CHUNK_header CHUNKheaderObj;
79 // TODO (hellner): tmpStr and tmpStr2 seems unnecessary here.
leozwang@webrtc.org09e77192012-03-01 18:35:54 +000080 char tmpStr[6] = "FOUR";
leozwang@webrtc.org0dc8efe2012-04-03 15:11:01 +000081 unsigned char tmpStr2[4];
pkasting25702cb2016-01-08 13:50:27 -080082 size_t i;
niklase@google.com470e71d2011-07-07 08:21:25 +000083 bool dataFound = false;
84 bool fmtFound = false;
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +000085 int8_t dummyRead;
niklase@google.com470e71d2011-07-07 08:21:25 +000086
niklase@google.com470e71d2011-07-07 08:21:25 +000087
88 _dataSize = 0;
pkasting25702cb2016-01-08 13:50:27 -080089 int len = wav.Read(&RIFFheaderObj, sizeof(WAVE_RIFF_header));
90 if (len != static_cast<int>(sizeof(WAVE_RIFF_header)))
niklase@google.com470e71d2011-07-07 08:21:25 +000091 {
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 =
pkasting25702cb2016-01-08 13:50:27 -0800126 (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8) +
127 (((uint32_t)tmpStr2[2]) << 16) + (((uint32_t)tmpStr2[3]) << 24);
niklase@google.com470e71d2011-07-07 08:21:25 +0000128
129 memcpy(tmpStr, CHUNKheaderObj.fmt_ckID, 4);
130
pkasting25702cb2016-01-08 13:50:27 -0800131 while ((len == static_cast<int>(sizeof(WAVE_CHUNK_header))) &&
132 (!fmtFound || !dataFound))
niklase@google.com470e71d2011-07-07 08:21:25 +0000133 {
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 =
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000140 (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1])<<8);
niklase@google.com470e71d2011-07-07 08:21:25 +0000141 memcpy(tmpStr2, &_wavFormatObj.nChannels, 2);
142 _wavFormatObj.nChannels =
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000143 (int16_t) ((uint32_t)tmpStr2[0] +
144 (((uint32_t)tmpStr2[1])<<8));
niklase@google.com470e71d2011-07-07 08:21:25 +0000145 memcpy(tmpStr2, &_wavFormatObj.nSamplesPerSec, 4);
146 _wavFormatObj.nSamplesPerSec =
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000147 (int32_t) ((uint32_t)tmpStr2[0] +
148 (((uint32_t)tmpStr2[1])<<8) +
149 (((uint32_t)tmpStr2[2])<<16) +
150 (((uint32_t)tmpStr2[3])<<24));
niklase@google.com470e71d2011-07-07 08:21:25 +0000151 memcpy(tmpStr2, &_wavFormatObj.nAvgBytesPerSec, 4);
152 _wavFormatObj.nAvgBytesPerSec =
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000153 (int32_t) ((uint32_t)tmpStr2[0] +
154 (((uint32_t)tmpStr2[1])<<8) +
155 (((uint32_t)tmpStr2[2])<<16) +
156 (((uint32_t)tmpStr2[3])<<24));
niklase@google.com470e71d2011-07-07 08:21:25 +0000157 memcpy(tmpStr2, &_wavFormatObj.nBlockAlign, 2);
158 _wavFormatObj.nBlockAlign =
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000159 (int16_t) ((uint32_t)tmpStr2[0] +
160 (((uint32_t)tmpStr2[1])<<8));
niklase@google.com470e71d2011-07-07 08:21:25 +0000161 memcpy(tmpStr2, &_wavFormatObj.nBitsPerSample, 2);
162 _wavFormatObj.nBitsPerSample =
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000163 (int16_t) ((uint32_t)tmpStr2[0] +
164 (((uint32_t)tmpStr2[1])<<8));
niklase@google.com470e71d2011-07-07 08:21:25 +0000165
pkasting25702cb2016-01-08 13:50:27 -0800166 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 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000172 for (i = 0;
pkasting25702cb2016-01-08 13:50:27 -0800173 i < CHUNKheaderObj.fmt_ckSize - sizeof(WAVE_FMTINFO_header);
niklase@google.com470e71d2011-07-07 08:21:25 +0000174 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 {
pkasting25702cb2016-01-08 13:50:27 -0800194 for (i = 0; i < CHUNKheaderObj.fmt_ckSize; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000195 {
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 =
pkasting25702cb2016-01-08 13:50:27 -0800210 (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8) +
211 (((uint32_t)tmpStr2[2]) << 16) + (((uint32_t)tmpStr2[3]) << 24);
niklase@google.com470e71d2011-07-07 08:21:25 +0000212
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.
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000218 if( (_wavFormatObj.formatTag != kWavFormatPcm) &&
219 (_wavFormatObj.formatTag != kWavFormatALaw) &&
220 (_wavFormatObj.formatTag != kWavFormatMuLaw))
niklase@google.com470e71d2011-07-07 08:21:25 +0000221 {
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.
pkasting25702cb2016-01-08 13:50:27 -0800246 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);
niklase@google.com470e71d2011-07-07 08:21:25 +0000252 return 0;
253}
254
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000255int32_t ModuleFileUtility::InitWavCodec(uint32_t samplesPerSec,
Peter Kasting69558702016-01-12 16:26:35 -0800256 size_t channels,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000257 uint32_t bitsPerSample,
258 uint32_t formatTag)
niklase@google.com470e71d2011-07-07 08:21:25 +0000259{
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 {
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000268 case kWavFormatALaw:
niklase@google.com470e71d2011-07-07 08:21:25 +0000269 strcpy(codec_info_.plname, "PCMA");
270 _codecId = kCodecPcma;
271 codec_info_.pltype = 8;
272 codec_info_.pacsize = codec_info_.plfreq / 100;
273 break;
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000274 case kWavFormatMuLaw:
niklase@google.com470e71d2011-07-07 08:21:25 +0000275 strcpy(codec_info_.plname, "PCMU");
276 _codecId = kCodecPcmu;
277 codec_info_.pltype = 0;
278 codec_info_.pacsize = codec_info_.plfreq / 100;
279 break;
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000280 case kWavFormatPcm:
niklase@google.com470e71d2011-07-07 08:21:25 +0000281 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
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000343int32_t ModuleFileUtility::InitWavReading(InStream& wav,
344 const uint32_t start,
345 const uint32_t stop)
niklase@google.com470e71d2011-07-07 08:21:25 +0000346{
niklase@google.com470e71d2011-07-07 08:21:25 +0000347
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 {
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000362 uint8_t dummy[WAV_MAX_BUFFER_SIZE];
pkasting25702cb2016-01-08 13:50:27 -0800363 int readLength;
niklase@google.com470e71d2011-07-07 08:21:25 +0000364 if(_readSizeBytes <= WAV_MAX_BUFFER_SIZE)
365 {
366 while (_playoutPositionMs < start)
367 {
368 readLength = wav.Read(dummy, _readSizeBytes);
pkasting25702cb2016-01-08 13:50:27 -0800369 if(readLength == static_cast<int>(_readSizeBytes))
niklase@google.com470e71d2011-07-07 08:21:25 +0000370 {
pkasting25702cb2016-01-08 13:50:27 -0800371 _readPos += _readSizeBytes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000372 _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 }
pkasting25702cb2016-01-08 13:50:27 -0800393 _bytesPerSample = static_cast<size_t>(_wavFormatObj.nBitsPerSample / 8);
niklase@google.com470e71d2011-07-07 08:21:25 +0000394
niklase@google.com470e71d2011-07-07 08:21:25 +0000395
396 _startPointInMs = start;
397 _stopPointInMs = stop;
398 _reading = true;
399 return 0;
400}
401
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000402int32_t ModuleFileUtility::ReadWavDataAsMono(
niklase@google.com470e71d2011-07-07 08:21:25 +0000403 InStream& wav,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000404 int8_t* outData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000405 const size_t bufferSize)
niklase@google.com470e71d2011-07-07 08:21:25 +0000406{
407 WEBRTC_TRACE(
408 kTraceStream,
409 kTraceFile,
410 _id,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000411 "ModuleFileUtility::ReadWavDataAsMono(wav= 0x%x, outData= 0x%d, "
412 "bufSize= %" PRIuS ")",
niklase@google.com470e71d2011-07-07 08:21:25 +0000413 &wav,
414 outData,
415 bufferSize);
416
417 // The number of bytes that should be read from file.
pkasting25702cb2016-01-08 13:50:27 -0800418 const size_t totalBytesNeeded = _readSizeBytes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000419 // The number of bytes that will be written to outData.
pkasting25702cb2016-01-08 13:50:27 -0800420 const size_t bytesRequested = (codec_info_.channels == 2) ?
niklase@google.com470e71d2011-07-07 08:21:25 +0000421 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
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000442 int32_t bytesRead = ReadWavData(
niklase@google.com470e71d2011-07-07 08:21:25 +0000443 wav,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000444 (codec_info_.channels == 2) ? _tempData : (uint8_t*)outData,
niklase@google.com470e71d2011-07-07 08:21:25 +0000445 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 {
pkasting25702cb2016-01-08 13:50:27 -0800459 for (size_t i = 0; i < bytesRequested / _bytesPerSample; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000460 {
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 {
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000470 int16_t* sampleData = (int16_t*) _tempData;
niklase@google.com470e71d2011-07-07 08:21:25 +0000471 sampleData[i] = ((sampleData[2 * i] + sampleData[(2 * i) + 1] +
472 1) >> 1);
473 }
474 }
475 memcpy(outData, _tempData, bytesRequested);
476 }
pkasting25702cb2016-01-08 13:50:27 -0800477 return static_cast<int32_t>(bytesRequested);
niklase@google.com470e71d2011-07-07 08:21:25 +0000478}
479
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000480int32_t ModuleFileUtility::ReadWavDataAsStereo(
niklase@google.com470e71d2011-07-07 08:21:25 +0000481 InStream& wav,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000482 int8_t* outDataLeft,
483 int8_t* outDataRight,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000484 const size_t bufferSize)
niklase@google.com470e71d2011-07-07 08:21:25 +0000485{
486 WEBRTC_TRACE(
487 kTraceStream,
488 kTraceFile,
489 _id,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000490 "ModuleFileUtility::ReadWavDataAsStereo(wav= 0x%x, outLeft= 0x%x, "
491 "outRight= 0x%x, bufSize= %" PRIuS ")",
niklase@google.com470e71d2011-07-07 08:21:25 +0000492 &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.
pkasting25702cb2016-01-08 13:50:27 -0800521 const size_t totalBytesNeeded = _readSizeBytes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000522 // The number of bytes that will be written to the left and the right
523 // buffers.
pkasting25702cb2016-01-08 13:50:27 -0800524 const size_t bytesRequested = totalBytesNeeded >> 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000525 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
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000533 int32_t bytesRead = ReadWavData(wav, _tempData, totalBytesNeeded);
niklase@google.com470e71d2011-07-07 08:21:25 +0000534 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 {
pkasting25702cb2016-01-08 13:50:27 -0800545 for (size_t i = 0; i < bytesRequested; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000546 {
547 outDataLeft[i] = _tempData[2 * i];
548 outDataRight[i] = _tempData[(2 * i) + 1];
549 }
550 }
551 else if(_bytesPerSample == 2)
552 {
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000553 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*>(
niklase@google.com470e71d2011-07-07 08:21:25 +0000556 outDataRight);
557
558 // Bytes requested to samples requested.
pkasting25702cb2016-01-08 13:50:27 -0800559 size_t sampleCount = bytesRequested >> 1;
560 for (size_t i = 0; i < sampleCount; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000561 {
562 outLeft[i] = sampleData[2 * i];
563 outRight[i] = sampleData[(2 * i) + 1];
564 }
565 } else {
566 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
pkasting25702cb2016-01-08 13:50:27 -0800567 "ReadWavStereoData: unsupported sample size %" PRIuS "!",
niklase@google.com470e71d2011-07-07 08:21:25 +0000568 _bytesPerSample);
569 assert(false);
570 return -1;
571 }
pkasting25702cb2016-01-08 13:50:27 -0800572 return static_cast<int32_t>(bytesRequested);
niklase@google.com470e71d2011-07-07 08:21:25 +0000573}
574
pkasting25702cb2016-01-08 13:50:27 -0800575int32_t ModuleFileUtility::ReadWavData(InStream& wav,
576 uint8_t* buffer,
577 size_t dataLengthInBytes)
niklase@google.com470e71d2011-07-07 08:21:25 +0000578{
pkasting25702cb2016-01-08 13:50:27 -0800579 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
580 "ModuleFileUtility::ReadWavData(wav= 0x%x, buffer= 0x%x, "
581 "dataLen= %" PRIuS ")", &wav, buffer, dataLengthInBytes);
niklase@google.com470e71d2011-07-07 08:21:25 +0000582
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?
pkasting25702cb2016-01-08 13:50:27 -0800594 if(_dataSize < (_readPos + dataLengthInBytes))
niklase@google.com470e71d2011-07-07 08:21:25 +0000595 {
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
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000609 int32_t bytesRead = wav.Read(buffer, dataLengthInBytes);
niklase@google.com470e71d2011-07-07 08:21:25 +0000610 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...
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000619 if(bytesRead < (int32_t)dataLengthInBytes)
niklase@google.com470e71d2011-07-07 08:21:25 +0000620 {
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);
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000630 if(bytesRead < (int32_t)dataLengthInBytes)
niklase@google.com470e71d2011-07-07 08:21:25 +0000631 {
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
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000655int32_t ModuleFileUtility::InitWavWriting(OutStream& wav,
656 const CodecInst& codecInst)
niklase@google.com470e71d2011-07-07 08:21:25 +0000657{
niklase@google.com470e71d2011-07-07 08:21:25 +0000658
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;
Peter Kasting69558702016-01-12 16:26:35 -0800666 size_t channels = (codecInst.channels == 0) ? 1 : codecInst.channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000667
668 if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0)
669 {
670 _bytesPerSample = 1;
671 if(WriteWavHeader(wav, 8000, _bytesPerSample, channels,
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000672 kWavFormatMuLaw, 0) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000673 {
674 return -1;
675 }
pkasting25702cb2016-01-08 13:50:27 -0800676 }
677 else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000678 {
679 _bytesPerSample = 1;
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000680 if(WriteWavHeader(wav, 8000, _bytesPerSample, channels, kWavFormatALaw,
niklase@google.com470e71d2011-07-07 08:21:25 +0000681 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,
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000690 kWavFormatPcm, 0) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000691 {
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
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000706int32_t ModuleFileUtility::WriteWavData(OutStream& out,
707 const int8_t* buffer,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000708 const size_t dataLength)
niklase@google.com470e71d2011-07-07 08:21:25 +0000709{
pkasting25702cb2016-01-08 13:50:27 -0800710 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
711 "ModuleFileUtility::WriteWavData(out= 0x%x, buf= 0x%x, "
712 "dataLen= %" PRIuS ")", &out, buffer, dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +0000713
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;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000726 return static_cast<int32_t>(dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +0000727}
728
729
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000730int32_t ModuleFileUtility::WriteWavHeader(
niklase@google.com470e71d2011-07-07 08:21:25 +0000731 OutStream& wav,
pkasting25702cb2016-01-08 13:50:27 -0800732 uint32_t freq,
733 size_t bytesPerSample,
Peter Kasting69558702016-01-12 16:26:35 -0800734 size_t channels,
pkasting25702cb2016-01-08 13:50:27 -0800735 uint32_t format,
736 size_t lengthInBytes)
niklase@google.com470e71d2011-07-07 08:21:25 +0000737{
niklase@google.com470e71d2011-07-07 08:21:25 +0000738 // 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!
pkasting25702cb2016-01-08 13:50:27 -0800741 const size_t frameSize = (freq / 100) * channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000742
743 // Calculate the number of full frames that the wave file contain.
pkasting25702cb2016-01-08 13:50:27 -0800744 const size_t dataLengthInBytes = frameSize * (lengthInBytes / frameSize);
niklase@google.com470e71d2011-07-07 08:21:25 +0000745
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000746 uint8_t buf[kWavHeaderSize];
747 webrtc::WriteWavHeader(buf, channels, freq, static_cast<WavFormat>(format),
748 bytesPerSample, dataLengthInBytes / bytesPerSample);
749 wav.Write(buf, kWavHeaderSize);
niklase@google.com470e71d2011-07-07 08:21:25 +0000750 return 0;
751}
752
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000753int32_t ModuleFileUtility::UpdateWavHeader(OutStream& wav)
niklase@google.com470e71d2011-07-07 08:21:25 +0000754{
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000755 int32_t res = -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000756 if(wav.Rewind() == -1)
757 {
758 return -1;
759 }
Peter Kasting69558702016-01-12 16:26:35 -0800760 size_t channels = (codec_info_.channels == 0) ? 1 : codec_info_.channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000761
762 if(STR_CASE_CMP(codec_info_.plname, "L16") == 0)
763 {
764 res = WriteWavHeader(wav, codec_info_.plfreq, 2, channels,
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000765 kWavFormatPcm, _bytesWritten);
niklase@google.com470e71d2011-07-07 08:21:25 +0000766 } else if(STR_CASE_CMP(codec_info_.plname, "PCMU") == 0) {
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000767 res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatMuLaw,
niklase@google.com470e71d2011-07-07 08:21:25 +0000768 _bytesWritten);
henrike@webrtc.org4df8c9a2011-10-19 18:30:25 +0000769 } else if(STR_CASE_CMP(codec_info_.plname, "PCMA") == 0) {
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000770 res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatALaw,
niklase@google.com470e71d2011-07-07 08:21:25 +0000771 _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
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000781int32_t ModuleFileUtility::InitPreEncodedReading(InStream& in,
782 const CodecInst& cinst)
niklase@google.com470e71d2011-07-07 08:21:25 +0000783{
niklase@google.com470e71d2011-07-07 08:21:25 +0000784
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000785 uint8_t preEncodedID;
niklase@google.com470e71d2011-07-07 08:21:25 +0000786 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
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000808int32_t ModuleFileUtility::ReadPreEncodedData(
niklase@google.com470e71d2011-07-07 08:21:25 +0000809 InStream& in,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000810 int8_t* outData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000811 const size_t bufferSize)
niklase@google.com470e71d2011-07-07 08:21:25 +0000812{
pkasting25702cb2016-01-08 13:50:27 -0800813 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
814 "ModuleFileUtility::ReadPreEncodedData(in= 0x%x, "
815 "outData= 0x%x, bufferSize= %" PRIuS ")", &in, outData,
816 bufferSize);
niklase@google.com470e71d2011-07-07 08:21:25 +0000817
818 if(outData == NULL)
819 {
820 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "output buffer NULL");
821 }
822
pkasting25702cb2016-01-08 13:50:27 -0800823 size_t frameLen;
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000824 uint8_t buf[64];
niklase@google.com470e71d2011-07-07 08:21:25 +0000825 // Each frame has a two byte header containing the frame length.
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000826 int32_t res = in.Read(buf, 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000827 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 {
pkasting25702cb2016-01-08 13:50:27 -0800843 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
844 "buffer not large enough to read %" PRIuS " bytes of "
845 "pre-encoded data!", frameLen);
niklase@google.com470e71d2011-07-07 08:21:25 +0000846 return -1;
847 }
848 return in.Read(outData, frameLen);
849}
850
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000851int32_t ModuleFileUtility::InitPreEncodedWriting(
niklase@google.com470e71d2011-07-07 08:21:25 +0000852 OutStream& out,
853 const CodecInst& codecInst)
854{
niklase@google.com470e71d2011-07-07 08:21:25 +0000855
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;
Peter Kasting69558702016-01-12 16:26:35 -0800863 out.Write(&_codecId, 1);
864 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000865}
866
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000867int32_t ModuleFileUtility::WritePreEncodedData(
niklase@google.com470e71d2011-07-07 08:21:25 +0000868 OutStream& out,
Peter Kasting69558702016-01-12 16:26:35 -0800869 const int8_t* buffer,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000870 const size_t dataLength)
niklase@google.com470e71d2011-07-07 08:21:25 +0000871{
pkasting25702cb2016-01-08 13:50:27 -0800872 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
873 "ModuleFileUtility::WritePreEncodedData(out= 0x%x, "
874 "inData= 0x%x, dataLen= %" PRIuS ")", &out, buffer,
875 dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +0000876
877 if(buffer == NULL)
878 {
879 WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL");
880 }
881
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000882 size_t bytesWritten = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000883 // The first two bytes is the size of the frame.
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000884 int16_t lengthBuf;
885 lengthBuf = (int16_t)dataLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000886 if(dataLength > static_cast<size_t>(std::numeric_limits<int16_t>::max()) ||
887 !out.Write(&lengthBuf, 2))
niklase@google.com470e71d2011-07-07 08:21:25 +0000888 {
889 return -1;
890 }
891 bytesWritten = 2;
892
893 if(!out.Write(buffer, dataLength))
894 {
895 return -1;
896 }
897 bytesWritten += dataLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000898 return static_cast<int32_t>(bytesWritten);
niklase@google.com470e71d2011-07-07 08:21:25 +0000899}
900
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000901int32_t ModuleFileUtility::InitCompressedReading(
niklase@google.com470e71d2011-07-07 08:21:25 +0000902 InStream& in,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000903 const uint32_t start,
904 const uint32_t stop)
niklase@google.com470e71d2011-07-07 08:21:25 +0000905{
pkasting25702cb2016-01-08 13:50:27 -0800906 WEBRTC_TRACE(kTraceDebug, kTraceFile, _id,
907 "ModuleFileUtility::InitCompressedReading(in= 0x%x, "
908 "start= %d, stop= %d)", &in, start, stop);
niklase@google.com470e71d2011-07-07 08:21:25 +0000909
henrik.lundin@webrtc.orgfa587452015-02-23 09:25:40 +0000910#if defined(WEBRTC_CODEC_ILBC)
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000911 int16_t read_len = 0;
henrikg@webrtc.orgaf225d62011-12-09 09:58:39 +0000912#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000913 _codecId = kCodecNoCodec;
914 _playoutPositionMs = 0;
915 _reading = false;
916
917 _startPointInMs = start;
918 _stopPointInMs = stop;
919
niklase@google.com470e71d2011-07-07 08:21:25 +0000920 // Read the codec name
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000921 int32_t cnt = 0;
leozwang@webrtc.org09e77192012-03-01 18:35:54 +0000922 char buf[64];
niklase@google.com470e71d2011-07-07 08:21:25 +0000923 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;
niklase@google.com470e71d2011-07-07 08:21:25 +0000931 }
pkasting25702cb2016-01-08 13:50:27 -0800932 buf[cnt]=0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000933
niklase@google.com470e71d2011-07-07 08:21:25 +0000934#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);
pkasting25702cb2016-01-08 13:50:27 -0800950 if(read_len != 38)
niklase@google.com470e71d2011-07-07 08:21:25 +0000951 {
952 return -1;
953 }
pkasting25702cb2016-01-08 13:50:27 -0800954 _playoutPositionMs += 20;
niklase@google.com470e71d2011-07-07 08:21:25 +0000955 }
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);
pkasting25702cb2016-01-08 13:50:27 -0800974 if(read_len != 50)
niklase@google.com470e71d2011-07-07 08:21:25 +0000975 {
976 return -1;
977 }
pkasting25702cb2016-01-08 13:50:27 -0800978 _playoutPositionMs += 20;
niklase@google.com470e71d2011-07-07 08:21:25 +0000979 }
980 }
981 }
982#endif
983 if(_codecId == kCodecNoCodec)
984 {
985 return -1;
986 }
987 _reading = true;
988 return 0;
989}
990
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000991int32_t ModuleFileUtility::ReadCompressedData(InStream& in,
992 int8_t* outData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000993 size_t bufferSize)
niklase@google.com470e71d2011-07-07 08:21:25 +0000994{
pkasting25702cb2016-01-08 13:50:27 -0800995 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
996 "ModuleFileUtility::ReadCompressedData(in=0x%x, outData=0x%x, "
997 "bytes=%" PRIuS ")", &in, outData, bufferSize);
niklase@google.com470e71d2011-07-07 08:21:25 +0000998
pkasting25702cb2016-01-08 13:50:27 -0800999 int bytesRead = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001000
1001 if(! _reading)
1002 {
1003 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "not currently reading!");
1004 return -1;
1005 }
1006
niklase@google.com470e71d2011-07-07 08:21:25 +00001007#ifdef WEBRTC_CODEC_ILBC
1008 if((_codecId == kCodecIlbc20Ms) ||
1009 (_codecId == kCodecIlbc30Ms))
1010 {
pkasting25702cb2016-01-08 13:50:27 -08001011 size_t byteSize = 0;
Peter Kasting69558702016-01-12 16:26:35 -08001012 if(_codecId == kCodecIlbc30Ms)
niklase@google.com470e71d2011-07-07 08:21:25 +00001013 {
1014 byteSize = 50;
1015 }
1016 if(_codecId == kCodecIlbc20Ms)
1017 {
1018 byteSize = 38;
1019 }
1020 if(bufferSize < byteSize)
1021 {
1022 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
pkasting25702cb2016-01-08 13:50:27 -08001023 "output buffer is too short to read ILBC compressed "
1024 "data.");
niklase@google.com470e71d2011-07-07 08:21:25 +00001025 assert(false);
1026 return -1;
1027 }
1028
1029 bytesRead = in.Read(outData, byteSize);
pkasting25702cb2016-01-08 13:50:27 -08001030 if(bytesRead != static_cast<int>(byteSize))
niklase@google.com470e71d2011-07-07 08:21:25 +00001031 {
1032 if(!in.Rewind())
1033 {
1034 InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1035 bytesRead = in.Read(outData, byteSize);
pkasting25702cb2016-01-08 13:50:27 -08001036 if(bytesRead != static_cast<int>(byteSize))
niklase@google.com470e71d2011-07-07 08:21:25 +00001037 {
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
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001073int32_t ModuleFileUtility::InitCompressedWriting(
niklase@google.com470e71d2011-07-07 08:21:25 +00001074 OutStream& out,
1075 const CodecInst& codecInst)
1076{
1077 WEBRTC_TRACE(kTraceDebug, kTraceFile, _id,
pkasting25702cb2016-01-08 13:50:27 -08001078 "ModuleFileUtility::InitCompressedWriting(out= 0x%x, "
1079 "codecName= %s)", &out, codecInst.plname);
niklase@google.com470e71d2011-07-07 08:21:25 +00001080
1081 _writing = false;
1082
niklase@google.com470e71d2011-07-07 08:21:25 +00001083#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
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001113int32_t ModuleFileUtility::WriteCompressedData(
niklase@google.com470e71d2011-07-07 08:21:25 +00001114 OutStream& out,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001115 const int8_t* buffer,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001116 const size_t dataLength)
niklase@google.com470e71d2011-07-07 08:21:25 +00001117{
pkasting25702cb2016-01-08 13:50:27 -08001118 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1119 "ModuleFileUtility::WriteCompressedData(out= 0x%x, buf= 0x%x, "
1120 "dataLen= %" PRIuS ")", &out, buffer, dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +00001121
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 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001131 return static_cast<int32_t>(dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +00001132}
1133
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001134int32_t ModuleFileUtility::InitPCMReading(InStream& pcm,
1135 const uint32_t start,
1136 const uint32_t stop,
1137 uint32_t freq)
niklase@google.com470e71d2011-07-07 08:21:25 +00001138{
pkasting25702cb2016-01-08 13:50:27 -08001139 WEBRTC_TRACE(kTraceInfo, kTraceFile, _id,
1140 "ModuleFileUtility::InitPCMReading(pcm= 0x%x, start=%d, "
1141 "stop=%d, freq=%d)", &pcm, start, stop, freq);
niklase@google.com470e71d2011-07-07 08:21:25 +00001142
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001143 int8_t dummy[320];
pkasting25702cb2016-01-08 13:50:27 -08001144 int read_len;
niklase@google.com470e71d2011-07-07 08:21:25 +00001145
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);
pkasting25702cb2016-01-08 13:50:27 -08001189 if(read_len != static_cast<int>(_readSizeBytes))
niklase@google.com470e71d2011-07-07 08:21:25 +00001190 {
pkasting25702cb2016-01-08 13:50:27 -08001191 return -1; // Must have reached EOF before start position!
niklase@google.com470e71d2011-07-07 08:21:25 +00001192 }
pkasting25702cb2016-01-08 13:50:27 -08001193 _playoutPositionMs += 10;
niklase@google.com470e71d2011-07-07 08:21:25 +00001194 }
1195 }
1196 _reading = true;
1197 return 0;
1198}
1199
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001200int32_t ModuleFileUtility::ReadPCMData(InStream& pcm,
1201 int8_t* outData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001202 size_t bufferSize)
niklase@google.com470e71d2011-07-07 08:21:25 +00001203{
pkasting25702cb2016-01-08 13:50:27 -08001204 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1205 "ModuleFileUtility::ReadPCMData(pcm= 0x%x, outData= 0x%x, "
1206 "bufSize= %" PRIuS ")", &pcm, outData, bufferSize);
niklase@google.com470e71d2011-07-07 08:21:25 +00001207
1208 if(outData == NULL)
1209 {
pkasting25702cb2016-01-08 13:50:27 -08001210 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "buffer NULL");
niklase@google.com470e71d2011-07-07 08:21:25 +00001211 }
1212
1213 // Readsize for 10ms of audio data (2 bytes per sample).
pkasting25702cb2016-01-08 13:50:27 -08001214 size_t bytesRequested = static_cast<size_t>(2 * codec_info_.plfreq / 100);
niklase@google.com470e71d2011-07-07 08:21:25 +00001215 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
pkasting25702cb2016-01-08 13:50:27 -08001223 int bytesRead = pcm.Read(outData, bytesRequested);
1224 if(bytesRead < static_cast<int>(bytesRequested))
niklase@google.com470e71d2011-07-07 08:21:25 +00001225 {
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 {
pkasting25702cb2016-01-08 13:50:27 -08001239 size_t rest = bytesRequested - bytesRead;
1240 int len = pcm.Read(&(outData[bytesRead]), rest);
1241 if(len == static_cast<int>(rest))
niklase@google.com470e71d2011-07-07 08:21:25 +00001242 {
1243 bytesRead += len;
1244 }
1245 else
1246 {
1247 _reading = false;
1248 }
1249 }
1250 if(bytesRead <= 0)
1251 {
1252 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
pkasting25702cb2016-01-08 13:50:27 -08001253 "ReadPCMData: Failed to rewind audio file.");
niklase@google.com470e71d2011-07-07 08:21:25 +00001254 return -1;
1255 }
1256 }
1257 }
1258
1259 if(bytesRead <= 0)
1260 {
1261 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
pkasting25702cb2016-01-08 13:50:27 -08001262 "ReadPCMData: end of file");
niklase@google.com470e71d2011-07-07 08:21:25 +00001263 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
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001280int32_t ModuleFileUtility::InitPCMWriting(OutStream& out, uint32_t freq)
niklase@google.com470e71d2011-07-07 08:21:25 +00001281{
niklase@google.com470e71d2011-07-07 08:21:25 +00001282
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
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001329int32_t ModuleFileUtility::WritePCMData(OutStream& out,
1330 const int8_t* buffer,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001331 const size_t dataLength)
niklase@google.com470e71d2011-07-07 08:21:25 +00001332{
pkasting25702cb2016-01-08 13:50:27 -08001333 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1334 "ModuleFileUtility::WritePCMData(out= 0x%x, buf= 0x%x, "
1335 "dataLen= %" PRIuS ")", &out, buffer, dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +00001336
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;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001348 return static_cast<int32_t>(dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +00001349}
1350
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001351int32_t ModuleFileUtility::codec_info(CodecInst& codecInst)
niklase@google.com470e71d2011-07-07 08:21:25 +00001352{
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
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001366int32_t ModuleFileUtility::set_codec_info(const CodecInst& codecInst)
niklase@google.com470e71d2011-07-07 08:21:25 +00001367{
niklase@google.com470e71d2011-07-07 08:21:25 +00001368
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 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001393#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
niklase@google.com470e71d2011-07-07 08:21:25 +00001419#ifdef WEBRTC_CODEC_G722
1420 else if(STR_CASE_CMP(codecInst.plname, "G722") == 0)
1421 {
1422 _codecId = kCodecG722;
1423 }
1424#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001425 if(_codecId == kCodecNoCodec)
1426 {
1427 return -1;
1428 }
1429 memcpy(&codec_info_, &codecInst, sizeof(CodecInst));
1430 return 0;
1431}
1432
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001433int32_t ModuleFileUtility::FileDurationMs(const char* fileName,
1434 const FileFormats fileFormat,
1435 const uint32_t freqInHz)
niklase@google.com470e71d2011-07-07 08:21:25 +00001436{
niklase@google.com470e71d2011-07-07 08:21:25 +00001437
1438 if(fileName == NULL)
1439 {
1440 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "filename NULL");
henrike@webrtc.org26085e12012-02-27 21:50:40 +00001441 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001442 }
1443
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001444 int32_t time_in_ms = -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001445 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 }
tommia6219cc2016-06-15 10:30:14 -07001459 if (!inStreamObj->OpenFile(fileName, true)) {
1460 delete inStreamObj;
1461 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "failed to open file %s!",
1462 fileName);
1463 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001464 }
1465
1466 switch (fileFormat)
1467 {
1468 case kFileFormatWavFile:
1469 {
1470 if(ReadWavHeader(*inStreamObj) == -1)
1471 {
1472 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1473 "failed to read WAV file header!");
1474 return -1;
1475 }
1476 time_in_ms = ((file_size.st_size - 44) /
1477 (_wavFormatObj.nAvgBytesPerSec/1000));
1478 break;
1479 }
1480 case kFileFormatPcm16kHzFile:
1481 {
1482 // 16 samples per ms. 2 bytes per sample.
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001483 int32_t denominator = 16*2;
niklase@google.com470e71d2011-07-07 08:21:25 +00001484 time_in_ms = (file_size.st_size)/denominator;
1485 break;
1486 }
1487 case kFileFormatPcm8kHzFile:
1488 {
1489 // 8 samples per ms. 2 bytes per sample.
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001490 int32_t denominator = 8*2;
niklase@google.com470e71d2011-07-07 08:21:25 +00001491 time_in_ms = (file_size.st_size)/denominator;
1492 break;
1493 }
1494 case kFileFormatCompressedFile:
1495 {
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001496 int32_t cnt = 0;
pkasting25702cb2016-01-08 13:50:27 -08001497 int read_len = 0;
leozwang@webrtc.org09e77192012-03-01 18:35:54 +00001498 char buf[64];
niklase@google.com470e71d2011-07-07 08:21:25 +00001499 do
1500 {
1501 read_len = inStreamObj->Read(&buf[cnt++], 1);
1502 if(read_len != 1)
1503 {
1504 return -1;
1505 }
1506 } while ((buf[cnt-1] != '\n') && (64 > cnt));
1507
1508 if(cnt == 64)
1509 {
1510 return -1;
1511 }
1512 else
1513 {
1514 buf[cnt] = 0;
1515 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001516#ifdef WEBRTC_CODEC_ILBC
1517 if(!strcmp("#!iLBC20\n", buf))
1518 {
1519 // 20 ms is 304 bits
1520 time_in_ms = ((file_size.st_size)*160)/304;
1521 break;
1522 }
1523 if(!strcmp("#!iLBC30\n", buf))
1524 {
1525 // 30 ms takes 400 bits.
1526 // file size in bytes * 8 / 400 is the number of
1527 // 30 ms frames in the file ->
1528 // time_in_ms = file size * 8 / 400 * 30
1529 time_in_ms = ((file_size.st_size)*240)/400;
1530 break;
1531 }
1532#endif
mflodman@webrtc.org19fc09e2014-06-04 05:21:56 +00001533 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001534 }
1535 case kFileFormatPreencodedFile:
1536 {
1537 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1538 "cannot determine duration of Pre-Encoded file!");
1539 break;
1540 }
1541 default:
1542 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1543 "unsupported file format %d!", fileFormat);
1544 break;
1545 }
1546 inStreamObj->CloseFile();
1547 delete inStreamObj;
1548 return time_in_ms;
1549}
1550
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001551uint32_t ModuleFileUtility::PlayoutPositionMs()
niklase@google.com470e71d2011-07-07 08:21:25 +00001552{
1553 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
pkasting25702cb2016-01-08 13:50:27 -08001554 "ModuleFileUtility::PlayoutPosition()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001555
pkasting25702cb2016-01-08 13:50:27 -08001556 return _reading ? _playoutPositionMs : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001557}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001558} // namespace webrtc