blob: 1c2f7fd4c559f3a31d6cf49a9191553577314c02 [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"
21#include "webrtc/engine_configurations.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010022#include "webrtc/modules/include/module_common_types.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010023#include "webrtc/system_wrappers/include/file_wrapper.h"
24#include "webrtc/system_wrappers/include/trace.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,
256 uint32_t channels,
257 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;
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000666 uint32_t channels = (codecInst.channels == 0) ?
niklase@google.com470e71d2011-07-07 08:21:25 +0000667 1 : codecInst.channels;
668
669 if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0)
670 {
671 _bytesPerSample = 1;
672 if(WriteWavHeader(wav, 8000, _bytesPerSample, channels,
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000673 kWavFormatMuLaw, 0) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000674 {
675 return -1;
676 }
pkasting25702cb2016-01-08 13:50:27 -0800677 }
678 else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000679 {
680 _bytesPerSample = 1;
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000681 if(WriteWavHeader(wav, 8000, _bytesPerSample, channels, kWavFormatALaw,
niklase@google.com470e71d2011-07-07 08:21:25 +0000682 0) == -1)
683 {
684 return -1;
685 }
686 }
687 else if(STR_CASE_CMP(codecInst.plname, "L16") == 0)
688 {
689 _bytesPerSample = 2;
690 if(WriteWavHeader(wav, codecInst.plfreq, _bytesPerSample, channels,
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000691 kWavFormatPcm, 0) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000692 {
693 return -1;
694 }
695 }
696 else
697 {
698 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
699 "codecInst identifies unsupported codec for WAV file!");
700 return -1;
701 }
702 _writing = true;
703 _bytesWritten = 0;
704 return 0;
705}
706
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000707int32_t ModuleFileUtility::WriteWavData(OutStream& out,
708 const int8_t* buffer,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000709 const size_t dataLength)
niklase@google.com470e71d2011-07-07 08:21:25 +0000710{
pkasting25702cb2016-01-08 13:50:27 -0800711 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
712 "ModuleFileUtility::WriteWavData(out= 0x%x, buf= 0x%x, "
713 "dataLen= %" PRIuS ")", &out, buffer, dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +0000714
715 if(buffer == NULL)
716 {
717 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
718 "WriteWavData: input buffer NULL!");
719 return -1;
720 }
721
722 if(!out.Write(buffer, dataLength))
723 {
724 return -1;
725 }
726 _bytesWritten += dataLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000727 return static_cast<int32_t>(dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +0000728}
729
730
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000731int32_t ModuleFileUtility::WriteWavHeader(
niklase@google.com470e71d2011-07-07 08:21:25 +0000732 OutStream& wav,
pkasting25702cb2016-01-08 13:50:27 -0800733 uint32_t freq,
734 size_t bytesPerSample,
735 uint32_t channels,
736 uint32_t format,
737 size_t lengthInBytes)
niklase@google.com470e71d2011-07-07 08:21:25 +0000738{
niklase@google.com470e71d2011-07-07 08:21:25 +0000739 // Frame size in bytes for 10 ms of audio.
740 // TODO (hellner): 44.1 kHz has 440 samples frame size. Doesn't seem to
741 // be taken into consideration here!
pkasting25702cb2016-01-08 13:50:27 -0800742 const size_t frameSize = (freq / 100) * channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000743
744 // Calculate the number of full frames that the wave file contain.
pkasting25702cb2016-01-08 13:50:27 -0800745 const size_t dataLengthInBytes = frameSize * (lengthInBytes / frameSize);
niklase@google.com470e71d2011-07-07 08:21:25 +0000746
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000747 uint8_t buf[kWavHeaderSize];
748 webrtc::WriteWavHeader(buf, channels, freq, static_cast<WavFormat>(format),
749 bytesPerSample, dataLengthInBytes / bytesPerSample);
750 wav.Write(buf, kWavHeaderSize);
niklase@google.com470e71d2011-07-07 08:21:25 +0000751 return 0;
752}
753
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000754int32_t ModuleFileUtility::UpdateWavHeader(OutStream& wav)
niklase@google.com470e71d2011-07-07 08:21:25 +0000755{
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000756 int32_t res = -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000757 if(wav.Rewind() == -1)
758 {
759 return -1;
760 }
pkasting25702cb2016-01-08 13:50:27 -0800761 uint32_t channels = (codec_info_.channels == 0) ? 1 : codec_info_.channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000762
763 if(STR_CASE_CMP(codec_info_.plname, "L16") == 0)
764 {
765 res = WriteWavHeader(wav, codec_info_.plfreq, 2, channels,
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000766 kWavFormatPcm, _bytesWritten);
niklase@google.com470e71d2011-07-07 08:21:25 +0000767 } else if(STR_CASE_CMP(codec_info_.plname, "PCMU") == 0) {
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000768 res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatMuLaw,
niklase@google.com470e71d2011-07-07 08:21:25 +0000769 _bytesWritten);
henrike@webrtc.org4df8c9a2011-10-19 18:30:25 +0000770 } else if(STR_CASE_CMP(codec_info_.plname, "PCMA") == 0) {
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000771 res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatALaw,
niklase@google.com470e71d2011-07-07 08:21:25 +0000772 _bytesWritten);
773 } else {
774 // Allow calling this API even if not writing to a WAVE file.
775 // TODO (hellner): why?!
776 return 0;
777 }
778 return res;
779}
780
781
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000782int32_t ModuleFileUtility::InitPreEncodedReading(InStream& in,
783 const CodecInst& cinst)
niklase@google.com470e71d2011-07-07 08:21:25 +0000784{
niklase@google.com470e71d2011-07-07 08:21:25 +0000785
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000786 uint8_t preEncodedID;
niklase@google.com470e71d2011-07-07 08:21:25 +0000787 in.Read(&preEncodedID, 1);
788
789 MediaFileUtility_CodecType codecType =
790 (MediaFileUtility_CodecType)preEncodedID;
791
792 if(set_codec_info(cinst) != 0)
793 {
794 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
795 "Pre-encoded file send codec mismatch!");
796 return -1;
797 }
798 if(codecType != _codecId)
799 {
800 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
801 "Pre-encoded file format codec mismatch!");
802 return -1;
803 }
804 memcpy(&codec_info_,&cinst,sizeof(CodecInst));
805 _reading = true;
806 return 0;
807}
808
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000809int32_t ModuleFileUtility::ReadPreEncodedData(
niklase@google.com470e71d2011-07-07 08:21:25 +0000810 InStream& in,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000811 int8_t* outData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000812 const size_t bufferSize)
niklase@google.com470e71d2011-07-07 08:21:25 +0000813{
pkasting25702cb2016-01-08 13:50:27 -0800814 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
815 "ModuleFileUtility::ReadPreEncodedData(in= 0x%x, "
816 "outData= 0x%x, bufferSize= %" PRIuS ")", &in, outData,
817 bufferSize);
niklase@google.com470e71d2011-07-07 08:21:25 +0000818
819 if(outData == NULL)
820 {
821 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "output buffer NULL");
822 }
823
pkasting25702cb2016-01-08 13:50:27 -0800824 size_t frameLen;
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000825 uint8_t buf[64];
niklase@google.com470e71d2011-07-07 08:21:25 +0000826 // Each frame has a two byte header containing the frame length.
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000827 int32_t res = in.Read(buf, 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000828 if(res != 2)
829 {
830 if(!in.Rewind())
831 {
832 // The first byte is the codec identifier.
833 in.Read(buf, 1);
834 res = in.Read(buf, 2);
835 }
836 else
837 {
838 return -1;
839 }
840 }
841 frameLen = buf[0] + buf[1] * 256;
842 if(bufferSize < frameLen)
843 {
pkasting25702cb2016-01-08 13:50:27 -0800844 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
845 "buffer not large enough to read %" PRIuS " bytes of "
846 "pre-encoded data!", frameLen);
niklase@google.com470e71d2011-07-07 08:21:25 +0000847 return -1;
848 }
849 return in.Read(outData, frameLen);
850}
851
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000852int32_t ModuleFileUtility::InitPreEncodedWriting(
niklase@google.com470e71d2011-07-07 08:21:25 +0000853 OutStream& out,
854 const CodecInst& codecInst)
855{
niklase@google.com470e71d2011-07-07 08:21:25 +0000856
857 if(set_codec_info(codecInst) != 0)
858 {
859 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "CodecInst not recognized!");
860 return -1;
861 }
862 _writing = true;
863 _bytesWritten = 1;
864 out.Write(&_codecId, 1);
865 return 0;
866}
867
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000868int32_t ModuleFileUtility::WritePreEncodedData(
niklase@google.com470e71d2011-07-07 08:21:25 +0000869 OutStream& out,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000870 const int8_t* buffer,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000871 const size_t dataLength)
niklase@google.com470e71d2011-07-07 08:21:25 +0000872{
pkasting25702cb2016-01-08 13:50:27 -0800873 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
874 "ModuleFileUtility::WritePreEncodedData(out= 0x%x, "
875 "inData= 0x%x, dataLen= %" PRIuS ")", &out, buffer,
876 dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +0000877
878 if(buffer == NULL)
879 {
880 WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL");
881 }
882
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000883 size_t bytesWritten = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000884 // The first two bytes is the size of the frame.
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000885 int16_t lengthBuf;
886 lengthBuf = (int16_t)dataLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000887 if(dataLength > static_cast<size_t>(std::numeric_limits<int16_t>::max()) ||
888 !out.Write(&lengthBuf, 2))
niklase@google.com470e71d2011-07-07 08:21:25 +0000889 {
890 return -1;
891 }
892 bytesWritten = 2;
893
894 if(!out.Write(buffer, dataLength))
895 {
896 return -1;
897 }
898 bytesWritten += dataLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000899 return static_cast<int32_t>(bytesWritten);
niklase@google.com470e71d2011-07-07 08:21:25 +0000900}
901
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000902int32_t ModuleFileUtility::InitCompressedReading(
niklase@google.com470e71d2011-07-07 08:21:25 +0000903 InStream& in,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000904 const uint32_t start,
905 const uint32_t stop)
niklase@google.com470e71d2011-07-07 08:21:25 +0000906{
pkasting25702cb2016-01-08 13:50:27 -0800907 WEBRTC_TRACE(kTraceDebug, kTraceFile, _id,
908 "ModuleFileUtility::InitCompressedReading(in= 0x%x, "
909 "start= %d, stop= %d)", &in, start, stop);
niklase@google.com470e71d2011-07-07 08:21:25 +0000910
henrik.lundin@webrtc.orgfa587452015-02-23 09:25:40 +0000911#if defined(WEBRTC_CODEC_ILBC)
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000912 int16_t read_len = 0;
henrikg@webrtc.orgaf225d62011-12-09 09:58:39 +0000913#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000914 _codecId = kCodecNoCodec;
915 _playoutPositionMs = 0;
916 _reading = false;
917
918 _startPointInMs = start;
919 _stopPointInMs = stop;
920
niklase@google.com470e71d2011-07-07 08:21:25 +0000921 // Read the codec name
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000922 int32_t cnt = 0;
leozwang@webrtc.org09e77192012-03-01 18:35:54 +0000923 char buf[64];
niklase@google.com470e71d2011-07-07 08:21:25 +0000924 do
925 {
926 in.Read(&buf[cnt++], 1);
927 } while ((buf[cnt-1] != '\n') && (64 > cnt));
928
929 if(cnt==64)
930 {
931 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000932 }
pkasting25702cb2016-01-08 13:50:27 -0800933 buf[cnt]=0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000934
niklase@google.com470e71d2011-07-07 08:21:25 +0000935#ifdef WEBRTC_CODEC_ILBC
936 if(!strcmp("#!iLBC20\n", buf))
937 {
938 codec_info_.pltype = 102;
939 strcpy(codec_info_.plname, "ilbc");
940 codec_info_.plfreq = 8000;
941 codec_info_.pacsize = 160;
942 codec_info_.channels = 1;
943 codec_info_.rate = 13300;
944 _codecId = kCodecIlbc20Ms;
945
946 if(_startPointInMs > 0)
947 {
948 while (_playoutPositionMs <= _startPointInMs)
949 {
950 read_len = in.Read(buf, 38);
pkasting25702cb2016-01-08 13:50:27 -0800951 if(read_len != 38)
niklase@google.com470e71d2011-07-07 08:21:25 +0000952 {
953 return -1;
954 }
pkasting25702cb2016-01-08 13:50:27 -0800955 _playoutPositionMs += 20;
niklase@google.com470e71d2011-07-07 08:21:25 +0000956 }
957 }
958 }
959
960 if(!strcmp("#!iLBC30\n", buf))
961 {
962 codec_info_.pltype = 102;
963 strcpy(codec_info_.plname, "ilbc");
964 codec_info_.plfreq = 8000;
965 codec_info_.pacsize = 240;
966 codec_info_.channels = 1;
967 codec_info_.rate = 13300;
968 _codecId = kCodecIlbc30Ms;
969
970 if(_startPointInMs > 0)
971 {
972 while (_playoutPositionMs <= _startPointInMs)
973 {
974 read_len = in.Read(buf, 50);
pkasting25702cb2016-01-08 13:50:27 -0800975 if(read_len != 50)
niklase@google.com470e71d2011-07-07 08:21:25 +0000976 {
977 return -1;
978 }
pkasting25702cb2016-01-08 13:50:27 -0800979 _playoutPositionMs += 20;
niklase@google.com470e71d2011-07-07 08:21:25 +0000980 }
981 }
982 }
983#endif
984 if(_codecId == kCodecNoCodec)
985 {
986 return -1;
987 }
988 _reading = true;
989 return 0;
990}
991
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000992int32_t ModuleFileUtility::ReadCompressedData(InStream& in,
993 int8_t* outData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000994 size_t bufferSize)
niklase@google.com470e71d2011-07-07 08:21:25 +0000995{
pkasting25702cb2016-01-08 13:50:27 -0800996 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
997 "ModuleFileUtility::ReadCompressedData(in=0x%x, outData=0x%x, "
998 "bytes=%" PRIuS ")", &in, outData, bufferSize);
niklase@google.com470e71d2011-07-07 08:21:25 +0000999
pkasting25702cb2016-01-08 13:50:27 -08001000 int bytesRead = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001001
1002 if(! _reading)
1003 {
1004 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "not currently reading!");
1005 return -1;
1006 }
1007
niklase@google.com470e71d2011-07-07 08:21:25 +00001008#ifdef WEBRTC_CODEC_ILBC
1009 if((_codecId == kCodecIlbc20Ms) ||
1010 (_codecId == kCodecIlbc30Ms))
1011 {
pkasting25702cb2016-01-08 13:50:27 -08001012 size_t byteSize = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001013 if(_codecId == kCodecIlbc30Ms)
1014 {
1015 byteSize = 50;
1016 }
1017 if(_codecId == kCodecIlbc20Ms)
1018 {
1019 byteSize = 38;
1020 }
1021 if(bufferSize < byteSize)
1022 {
1023 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
pkasting25702cb2016-01-08 13:50:27 -08001024 "output buffer is too short to read ILBC compressed "
1025 "data.");
niklase@google.com470e71d2011-07-07 08:21:25 +00001026 assert(false);
1027 return -1;
1028 }
1029
1030 bytesRead = in.Read(outData, byteSize);
pkasting25702cb2016-01-08 13:50:27 -08001031 if(bytesRead != static_cast<int>(byteSize))
niklase@google.com470e71d2011-07-07 08:21:25 +00001032 {
1033 if(!in.Rewind())
1034 {
1035 InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1036 bytesRead = in.Read(outData, byteSize);
pkasting25702cb2016-01-08 13:50:27 -08001037 if(bytesRead != static_cast<int>(byteSize))
niklase@google.com470e71d2011-07-07 08:21:25 +00001038 {
1039 _reading = false;
1040 return -1;
1041 }
1042 }
1043 else
1044 {
1045 _reading = false;
1046 return -1;
1047 }
1048 }
1049 }
1050#endif
1051 if(bytesRead == 0)
1052 {
1053 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1054 "ReadCompressedData() no bytes read, codec not supported");
1055 return -1;
1056 }
1057
1058 _playoutPositionMs += 20;
1059 if((_stopPointInMs > 0) &&
1060 (_playoutPositionMs >= _stopPointInMs))
1061 {
1062 if(!in.Rewind())
1063 {
1064 InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1065 }
1066 else
1067 {
1068 _reading = false;
1069 }
1070 }
1071 return bytesRead;
1072}
1073
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001074int32_t ModuleFileUtility::InitCompressedWriting(
niklase@google.com470e71d2011-07-07 08:21:25 +00001075 OutStream& out,
1076 const CodecInst& codecInst)
1077{
1078 WEBRTC_TRACE(kTraceDebug, kTraceFile, _id,
pkasting25702cb2016-01-08 13:50:27 -08001079 "ModuleFileUtility::InitCompressedWriting(out= 0x%x, "
1080 "codecName= %s)", &out, codecInst.plname);
niklase@google.com470e71d2011-07-07 08:21:25 +00001081
1082 _writing = false;
1083
niklase@google.com470e71d2011-07-07 08:21:25 +00001084#ifdef WEBRTC_CODEC_ILBC
1085 if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0)
1086 {
1087 if(codecInst.pacsize == 160)
1088 {
1089 _codecId = kCodecIlbc20Ms;
1090 out.Write("#!iLBC20\n",9);
1091 }
1092 else if(codecInst.pacsize == 240)
1093 {
1094 _codecId = kCodecIlbc30Ms;
1095 out.Write("#!iLBC30\n",9);
1096 }
1097 else
1098 {
1099 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1100 "codecInst defines unsupported compression codec!");
1101 return -1;
1102 }
1103 memcpy(&codec_info_,&codecInst,sizeof(CodecInst));
1104 _writing = true;
1105 return 0;
1106 }
1107#endif
1108
1109 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1110 "codecInst defines unsupported compression codec!");
1111 return -1;
1112}
1113
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001114int32_t ModuleFileUtility::WriteCompressedData(
niklase@google.com470e71d2011-07-07 08:21:25 +00001115 OutStream& out,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001116 const int8_t* buffer,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001117 const size_t dataLength)
niklase@google.com470e71d2011-07-07 08:21:25 +00001118{
pkasting25702cb2016-01-08 13:50:27 -08001119 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1120 "ModuleFileUtility::WriteCompressedData(out= 0x%x, buf= 0x%x, "
1121 "dataLen= %" PRIuS ")", &out, buffer, dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +00001122
1123 if(buffer == NULL)
1124 {
1125 WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL");
1126 }
1127
1128 if(!out.Write(buffer, dataLength))
1129 {
1130 return -1;
1131 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001132 return static_cast<int32_t>(dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +00001133}
1134
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001135int32_t ModuleFileUtility::InitPCMReading(InStream& pcm,
1136 const uint32_t start,
1137 const uint32_t stop,
1138 uint32_t freq)
niklase@google.com470e71d2011-07-07 08:21:25 +00001139{
pkasting25702cb2016-01-08 13:50:27 -08001140 WEBRTC_TRACE(kTraceInfo, kTraceFile, _id,
1141 "ModuleFileUtility::InitPCMReading(pcm= 0x%x, start=%d, "
1142 "stop=%d, freq=%d)", &pcm, start, stop, freq);
niklase@google.com470e71d2011-07-07 08:21:25 +00001143
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001144 int8_t dummy[320];
pkasting25702cb2016-01-08 13:50:27 -08001145 int read_len;
niklase@google.com470e71d2011-07-07 08:21:25 +00001146
1147 _playoutPositionMs = 0;
1148 _startPointInMs = start;
1149 _stopPointInMs = stop;
1150 _reading = false;
1151
1152 if(freq == 8000)
1153 {
1154 strcpy(codec_info_.plname, "L16");
1155 codec_info_.pltype = -1;
1156 codec_info_.plfreq = 8000;
1157 codec_info_.pacsize = 160;
1158 codec_info_.channels = 1;
1159 codec_info_.rate = 128000;
1160 _codecId = kCodecL16_8Khz;
1161 }
1162 else if(freq == 16000)
1163 {
1164 strcpy(codec_info_.plname, "L16");
1165 codec_info_.pltype = -1;
1166 codec_info_.plfreq = 16000;
1167 codec_info_.pacsize = 320;
1168 codec_info_.channels = 1;
1169 codec_info_.rate = 256000;
1170 _codecId = kCodecL16_16kHz;
1171 }
1172 else if(freq == 32000)
1173 {
1174 strcpy(codec_info_.plname, "L16");
1175 codec_info_.pltype = -1;
1176 codec_info_.plfreq = 32000;
1177 codec_info_.pacsize = 320;
1178 codec_info_.channels = 1;
1179 codec_info_.rate = 512000;
1180 _codecId = kCodecL16_32Khz;
1181 }
1182
1183 // Readsize for 10ms of audio data (2 bytes per sample).
1184 _readSizeBytes = 2 * codec_info_. plfreq / 100;
1185 if(_startPointInMs > 0)
1186 {
1187 while (_playoutPositionMs < _startPointInMs)
1188 {
1189 read_len = pcm.Read(dummy, _readSizeBytes);
pkasting25702cb2016-01-08 13:50:27 -08001190 if(read_len != static_cast<int>(_readSizeBytes))
niklase@google.com470e71d2011-07-07 08:21:25 +00001191 {
pkasting25702cb2016-01-08 13:50:27 -08001192 return -1; // Must have reached EOF before start position!
niklase@google.com470e71d2011-07-07 08:21:25 +00001193 }
pkasting25702cb2016-01-08 13:50:27 -08001194 _playoutPositionMs += 10;
niklase@google.com470e71d2011-07-07 08:21:25 +00001195 }
1196 }
1197 _reading = true;
1198 return 0;
1199}
1200
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001201int32_t ModuleFileUtility::ReadPCMData(InStream& pcm,
1202 int8_t* outData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001203 size_t bufferSize)
niklase@google.com470e71d2011-07-07 08:21:25 +00001204{
pkasting25702cb2016-01-08 13:50:27 -08001205 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1206 "ModuleFileUtility::ReadPCMData(pcm= 0x%x, outData= 0x%x, "
1207 "bufSize= %" PRIuS ")", &pcm, outData, bufferSize);
niklase@google.com470e71d2011-07-07 08:21:25 +00001208
1209 if(outData == NULL)
1210 {
pkasting25702cb2016-01-08 13:50:27 -08001211 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "buffer NULL");
niklase@google.com470e71d2011-07-07 08:21:25 +00001212 }
1213
1214 // Readsize for 10ms of audio data (2 bytes per sample).
pkasting25702cb2016-01-08 13:50:27 -08001215 size_t bytesRequested = static_cast<size_t>(2 * codec_info_.plfreq / 100);
niklase@google.com470e71d2011-07-07 08:21:25 +00001216 if(bufferSize < bytesRequested)
1217 {
1218 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1219 "ReadPCMData: buffer not long enough for a 10ms frame.");
1220 assert(false);
1221 return -1;
1222 }
1223
pkasting25702cb2016-01-08 13:50:27 -08001224 int bytesRead = pcm.Read(outData, bytesRequested);
1225 if(bytesRead < static_cast<int>(bytesRequested))
niklase@google.com470e71d2011-07-07 08:21:25 +00001226 {
1227 if(pcm.Rewind() == -1)
1228 {
1229 _reading = false;
1230 }
1231 else
1232 {
1233 if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
1234 codec_info_.plfreq) == -1)
1235 {
1236 _reading = false;
1237 }
1238 else
1239 {
pkasting25702cb2016-01-08 13:50:27 -08001240 size_t rest = bytesRequested - bytesRead;
1241 int len = pcm.Read(&(outData[bytesRead]), rest);
1242 if(len == static_cast<int>(rest))
niklase@google.com470e71d2011-07-07 08:21:25 +00001243 {
1244 bytesRead += len;
1245 }
1246 else
1247 {
1248 _reading = false;
1249 }
1250 }
1251 if(bytesRead <= 0)
1252 {
1253 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
pkasting25702cb2016-01-08 13:50:27 -08001254 "ReadPCMData: Failed to rewind audio file.");
niklase@google.com470e71d2011-07-07 08:21:25 +00001255 return -1;
1256 }
1257 }
1258 }
1259
1260 if(bytesRead <= 0)
1261 {
1262 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
pkasting25702cb2016-01-08 13:50:27 -08001263 "ReadPCMData: end of file");
niklase@google.com470e71d2011-07-07 08:21:25 +00001264 return -1;
1265 }
1266 _playoutPositionMs += 10;
1267 if(_stopPointInMs && _playoutPositionMs >= _stopPointInMs)
1268 {
1269 if(!pcm.Rewind())
1270 {
1271 if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
1272 codec_info_.plfreq) == -1)
1273 {
1274 _reading = false;
1275 }
1276 }
1277 }
1278 return bytesRead;
1279}
1280
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001281int32_t ModuleFileUtility::InitPCMWriting(OutStream& out, uint32_t freq)
niklase@google.com470e71d2011-07-07 08:21:25 +00001282{
niklase@google.com470e71d2011-07-07 08:21:25 +00001283
1284 if(freq == 8000)
1285 {
1286 strcpy(codec_info_.plname, "L16");
1287 codec_info_.pltype = -1;
1288 codec_info_.plfreq = 8000;
1289 codec_info_.pacsize = 160;
1290 codec_info_.channels = 1;
1291 codec_info_.rate = 128000;
1292
1293 _codecId = kCodecL16_8Khz;
1294 }
1295 else if(freq == 16000)
1296 {
1297 strcpy(codec_info_.plname, "L16");
1298 codec_info_.pltype = -1;
1299 codec_info_.plfreq = 16000;
1300 codec_info_.pacsize = 320;
1301 codec_info_.channels = 1;
1302 codec_info_.rate = 256000;
1303
1304 _codecId = kCodecL16_16kHz;
1305 }
1306 else if(freq == 32000)
1307 {
1308 strcpy(codec_info_.plname, "L16");
1309 codec_info_.pltype = -1;
1310 codec_info_.plfreq = 32000;
1311 codec_info_.pacsize = 320;
1312 codec_info_.channels = 1;
1313 codec_info_.rate = 512000;
1314
1315 _codecId = kCodecL16_32Khz;
1316 }
1317 if((_codecId != kCodecL16_8Khz) &&
1318 (_codecId != kCodecL16_16kHz) &&
1319 (_codecId != kCodecL16_32Khz))
1320 {
1321 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1322 "CodecInst is not 8KHz PCM or 16KHz PCM!");
1323 return -1;
1324 }
1325 _writing = true;
1326 _bytesWritten = 0;
1327 return 0;
1328}
1329
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001330int32_t ModuleFileUtility::WritePCMData(OutStream& out,
1331 const int8_t* buffer,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001332 const size_t dataLength)
niklase@google.com470e71d2011-07-07 08:21:25 +00001333{
pkasting25702cb2016-01-08 13:50:27 -08001334 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1335 "ModuleFileUtility::WritePCMData(out= 0x%x, buf= 0x%x, "
1336 "dataLen= %" PRIuS ")", &out, buffer, dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +00001337
1338 if(buffer == NULL)
1339 {
1340 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "buffer NULL");
1341 }
1342
1343 if(!out.Write(buffer, dataLength))
1344 {
1345 return -1;
1346 }
1347
1348 _bytesWritten += dataLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001349 return static_cast<int32_t>(dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +00001350}
1351
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001352int32_t ModuleFileUtility::codec_info(CodecInst& codecInst)
niklase@google.com470e71d2011-07-07 08:21:25 +00001353{
1354 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1355 "ModuleFileUtility::codec_info(codecInst= 0x%x)", &codecInst);
1356
1357 if(!_reading && !_writing)
1358 {
1359 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1360 "CodecInst: not currently reading audio file!");
1361 return -1;
1362 }
1363 memcpy(&codecInst,&codec_info_,sizeof(CodecInst));
1364 return 0;
1365}
1366
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001367int32_t ModuleFileUtility::set_codec_info(const CodecInst& codecInst)
niklase@google.com470e71d2011-07-07 08:21:25 +00001368{
niklase@google.com470e71d2011-07-07 08:21:25 +00001369
1370 _codecId = kCodecNoCodec;
1371 if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0)
1372 {
1373 _codecId = kCodecPcmu;
1374 }
1375 else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0)
1376 {
1377 _codecId = kCodecPcma;
1378 }
1379 else if(STR_CASE_CMP(codecInst.plname, "L16") == 0)
1380 {
1381 if(codecInst.plfreq == 8000)
1382 {
1383 _codecId = kCodecL16_8Khz;
1384 }
1385 else if(codecInst.plfreq == 16000)
1386 {
1387 _codecId = kCodecL16_16kHz;
1388 }
1389 else if(codecInst.plfreq == 32000)
1390 {
1391 _codecId = kCodecL16_32Khz;
1392 }
1393 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001394#ifdef WEBRTC_CODEC_ILBC
1395 else if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0)
1396 {
1397 if(codecInst.pacsize == 160)
1398 {
1399 _codecId = kCodecIlbc20Ms;
1400 }
1401 else if(codecInst.pacsize == 240)
1402 {
1403 _codecId = kCodecIlbc30Ms;
1404 }
1405 }
1406#endif
1407#if(defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
1408 else if(STR_CASE_CMP(codecInst.plname, "isac") == 0)
1409 {
1410 if(codecInst.plfreq == 16000)
1411 {
1412 _codecId = kCodecIsac;
1413 }
1414 else if(codecInst.plfreq == 32000)
1415 {
1416 _codecId = kCodecIsacSwb;
1417 }
1418 }
1419#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001420#ifdef WEBRTC_CODEC_G722
1421 else if(STR_CASE_CMP(codecInst.plname, "G722") == 0)
1422 {
1423 _codecId = kCodecG722;
1424 }
1425#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001426 if(_codecId == kCodecNoCodec)
1427 {
1428 return -1;
1429 }
1430 memcpy(&codec_info_, &codecInst, sizeof(CodecInst));
1431 return 0;
1432}
1433
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001434int32_t ModuleFileUtility::FileDurationMs(const char* fileName,
1435 const FileFormats fileFormat,
1436 const uint32_t freqInHz)
niklase@google.com470e71d2011-07-07 08:21:25 +00001437{
niklase@google.com470e71d2011-07-07 08:21:25 +00001438
1439 if(fileName == NULL)
1440 {
1441 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "filename NULL");
henrike@webrtc.org26085e12012-02-27 21:50:40 +00001442 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001443 }
1444
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001445 int32_t time_in_ms = -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001446 struct stat file_size;
1447 if(stat(fileName,&file_size) == -1)
1448 {
1449 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1450 "failed to retrieve file size with stat!");
1451 return -1;
1452 }
1453 FileWrapper* inStreamObj = FileWrapper::Create();
1454 if(inStreamObj == NULL)
1455 {
1456 WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
1457 "failed to create InStream object!");
1458 return -1;
1459 }
1460 if(inStreamObj->OpenFile(fileName, true) == -1)
1461 {
1462 delete inStreamObj;
1463 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1464 "failed to open file %s!", fileName);
1465 return -1;
1466 }
1467
1468 switch (fileFormat)
1469 {
1470 case kFileFormatWavFile:
1471 {
1472 if(ReadWavHeader(*inStreamObj) == -1)
1473 {
1474 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1475 "failed to read WAV file header!");
1476 return -1;
1477 }
1478 time_in_ms = ((file_size.st_size - 44) /
1479 (_wavFormatObj.nAvgBytesPerSec/1000));
1480 break;
1481 }
1482 case kFileFormatPcm16kHzFile:
1483 {
1484 // 16 samples per ms. 2 bytes per sample.
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001485 int32_t denominator = 16*2;
niklase@google.com470e71d2011-07-07 08:21:25 +00001486 time_in_ms = (file_size.st_size)/denominator;
1487 break;
1488 }
1489 case kFileFormatPcm8kHzFile:
1490 {
1491 // 8 samples per ms. 2 bytes per sample.
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001492 int32_t denominator = 8*2;
niklase@google.com470e71d2011-07-07 08:21:25 +00001493 time_in_ms = (file_size.st_size)/denominator;
1494 break;
1495 }
1496 case kFileFormatCompressedFile:
1497 {
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001498 int32_t cnt = 0;
pkasting25702cb2016-01-08 13:50:27 -08001499 int read_len = 0;
leozwang@webrtc.org09e77192012-03-01 18:35:54 +00001500 char buf[64];
niklase@google.com470e71d2011-07-07 08:21:25 +00001501 do
1502 {
1503 read_len = inStreamObj->Read(&buf[cnt++], 1);
1504 if(read_len != 1)
1505 {
1506 return -1;
1507 }
1508 } while ((buf[cnt-1] != '\n') && (64 > cnt));
1509
1510 if(cnt == 64)
1511 {
1512 return -1;
1513 }
1514 else
1515 {
1516 buf[cnt] = 0;
1517 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001518#ifdef WEBRTC_CODEC_ILBC
1519 if(!strcmp("#!iLBC20\n", buf))
1520 {
1521 // 20 ms is 304 bits
1522 time_in_ms = ((file_size.st_size)*160)/304;
1523 break;
1524 }
1525 if(!strcmp("#!iLBC30\n", buf))
1526 {
1527 // 30 ms takes 400 bits.
1528 // file size in bytes * 8 / 400 is the number of
1529 // 30 ms frames in the file ->
1530 // time_in_ms = file size * 8 / 400 * 30
1531 time_in_ms = ((file_size.st_size)*240)/400;
1532 break;
1533 }
1534#endif
mflodman@webrtc.org19fc09e2014-06-04 05:21:56 +00001535 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001536 }
1537 case kFileFormatPreencodedFile:
1538 {
1539 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1540 "cannot determine duration of Pre-Encoded file!");
1541 break;
1542 }
1543 default:
1544 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1545 "unsupported file format %d!", fileFormat);
1546 break;
1547 }
1548 inStreamObj->CloseFile();
1549 delete inStreamObj;
1550 return time_in_ms;
1551}
1552
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001553uint32_t ModuleFileUtility::PlayoutPositionMs()
niklase@google.com470e71d2011-07-07 08:21:25 +00001554{
1555 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
pkasting25702cb2016-01-08 13:50:27 -08001556 "ModuleFileUtility::PlayoutPosition()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001557
pkasting25702cb2016-01-08 13:50:27 -08001558 return _reading ? _playoutPositionMs : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001559}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001560} // namespace webrtc