blob: 8b0f22d9b7c39dffdec5b8aaaaab8e8e81dc2c34 [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
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +000018#include "webrtc/common_audio/wav_header.h"
pbos@webrtc.org0c4e05a2013-07-16 13:05:40 +000019#include "webrtc/common_types.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010020#include "webrtc/modules/include/module_common_types.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020021#include "webrtc/rtc_base/format_macros.h"
Sam Zackrisson45ca37c2017-08-22 13:44:09 +020022#include "webrtc/rtc_base/logging.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010023#include "webrtc/system_wrappers/include/file_wrapper.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 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +020047ModuleFileUtility::ModuleFileUtility()
niklase@google.com470e71d2011-07-07 08:21:25 +000048 : _wavFormatObj(),
49 _dataSize(0),
50 _readSizeBytes(0),
niklase@google.com470e71d2011-07-07 08:21:25 +000051 _stopPointInMs(0),
52 _startPointInMs(0),
53 _playoutPositionMs(0),
54 _bytesWritten(0),
55 codec_info_(),
56 _codecId(kCodecNoCodec),
57 _bytesPerSample(0),
58 _readPos(0),
59 _reading(false),
60 _writing(false),
andresp@webrtc.orge8f50df2015-03-02 13:07:02 +000061 _tempData() {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +020062 LOG(LS_INFO) << "ModuleFileUtility::ModuleFileUtility()";
niklase@google.com470e71d2011-07-07 08:21:25 +000063 memset(&codec_info_,0,sizeof(CodecInst));
64 codec_info_.pltype = -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000065}
66
67ModuleFileUtility::~ModuleFileUtility()
68{
Sam Zackrisson45ca37c2017-08-22 13:44:09 +020069 LOG(LS_INFO) << "ModuleFileUtility::~ModuleFileUtility()";
niklase@google.com470e71d2011-07-07 08:21:25 +000070}
71
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +000072int32_t ModuleFileUtility::ReadWavHeader(InStream& wav)
niklase@google.com470e71d2011-07-07 08:21:25 +000073{
74 WAVE_RIFF_header RIFFheaderObj;
75 WAVE_CHUNK_header CHUNKheaderObj;
76 // TODO (hellner): tmpStr and tmpStr2 seems unnecessary here.
leozwang@webrtc.org09e77192012-03-01 18:35:54 +000077 char tmpStr[6] = "FOUR";
leozwang@webrtc.org0dc8efe2012-04-03 15:11:01 +000078 unsigned char tmpStr2[4];
pkasting25702cb2016-01-08 13:50:27 -080079 size_t i;
niklase@google.com470e71d2011-07-07 08:21:25 +000080 bool dataFound = false;
81 bool fmtFound = false;
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +000082 int8_t dummyRead;
niklase@google.com470e71d2011-07-07 08:21:25 +000083
niklase@google.com470e71d2011-07-07 08:21:25 +000084
85 _dataSize = 0;
pkasting25702cb2016-01-08 13:50:27 -080086 int len = wav.Read(&RIFFheaderObj, sizeof(WAVE_RIFF_header));
87 if (len != static_cast<int>(sizeof(WAVE_RIFF_header)))
niklase@google.com470e71d2011-07-07 08:21:25 +000088 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +020089 LOG(LS_ERROR) << "Not a wave file (too short)";
niklase@google.com470e71d2011-07-07 08:21:25 +000090 return -1;
91 }
92
93 for (i = 0; i < 4; i++)
94 {
95 tmpStr[i] = RIFFheaderObj.ckID[i];
96 }
97 if(strcmp(tmpStr, "RIFF") != 0)
98 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +020099 LOG(LS_ERROR) << "Not a wave file (does not have RIFF)";
niklase@google.com470e71d2011-07-07 08:21:25 +0000100 return -1;
101 }
102 for (i = 0; i < 4; i++)
103 {
104 tmpStr[i] = RIFFheaderObj.wave_ckID[i];
105 }
106 if(strcmp(tmpStr, "WAVE") != 0)
107 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200108 LOG(LS_ERROR) << "Not a wave file (does not have WAVE)";
niklase@google.com470e71d2011-07-07 08:21:25 +0000109 return -1;
110 }
111
112 len = wav.Read(&CHUNKheaderObj, sizeof(WAVE_CHUNK_header));
113
114 // WAVE files are stored in little endian byte order. Make sure that the
115 // data can be read on big endian as well.
116 // TODO (hellner): little endian to system byte order should be done in
117 // in a subroutine.
118 memcpy(tmpStr2, &CHUNKheaderObj.fmt_ckSize, 4);
119 CHUNKheaderObj.fmt_ckSize =
pkasting25702cb2016-01-08 13:50:27 -0800120 (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8) +
121 (((uint32_t)tmpStr2[2]) << 16) + (((uint32_t)tmpStr2[3]) << 24);
niklase@google.com470e71d2011-07-07 08:21:25 +0000122
123 memcpy(tmpStr, CHUNKheaderObj.fmt_ckID, 4);
124
pkasting25702cb2016-01-08 13:50:27 -0800125 while ((len == static_cast<int>(sizeof(WAVE_CHUNK_header))) &&
126 (!fmtFound || !dataFound))
niklase@google.com470e71d2011-07-07 08:21:25 +0000127 {
128 if(strcmp(tmpStr, "fmt ") == 0)
129 {
130 len = wav.Read(&_wavFormatObj, sizeof(WAVE_FMTINFO_header));
131
132 memcpy(tmpStr2, &_wavFormatObj.formatTag, 2);
133 _wavFormatObj.formatTag =
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000134 (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1])<<8);
niklase@google.com470e71d2011-07-07 08:21:25 +0000135 memcpy(tmpStr2, &_wavFormatObj.nChannels, 2);
136 _wavFormatObj.nChannels =
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000137 (int16_t) ((uint32_t)tmpStr2[0] +
138 (((uint32_t)tmpStr2[1])<<8));
niklase@google.com470e71d2011-07-07 08:21:25 +0000139 memcpy(tmpStr2, &_wavFormatObj.nSamplesPerSec, 4);
140 _wavFormatObj.nSamplesPerSec =
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000141 (int32_t) ((uint32_t)tmpStr2[0] +
142 (((uint32_t)tmpStr2[1])<<8) +
143 (((uint32_t)tmpStr2[2])<<16) +
144 (((uint32_t)tmpStr2[3])<<24));
niklase@google.com470e71d2011-07-07 08:21:25 +0000145 memcpy(tmpStr2, &_wavFormatObj.nAvgBytesPerSec, 4);
146 _wavFormatObj.nAvgBytesPerSec =
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.nBlockAlign, 2);
152 _wavFormatObj.nBlockAlign =
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000153 (int16_t) ((uint32_t)tmpStr2[0] +
154 (((uint32_t)tmpStr2[1])<<8));
niklase@google.com470e71d2011-07-07 08:21:25 +0000155 memcpy(tmpStr2, &_wavFormatObj.nBitsPerSample, 2);
156 _wavFormatObj.nBitsPerSample =
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000157 (int16_t) ((uint32_t)tmpStr2[0] +
158 (((uint32_t)tmpStr2[1])<<8));
niklase@google.com470e71d2011-07-07 08:21:25 +0000159
pkasting25702cb2016-01-08 13:50:27 -0800160 if (CHUNKheaderObj.fmt_ckSize < sizeof(WAVE_FMTINFO_header))
161 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200162 LOG(LS_ERROR) << "Chunk size is too small";
pkasting25702cb2016-01-08 13:50:27 -0800163 return -1;
164 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000165 for (i = 0;
pkasting25702cb2016-01-08 13:50:27 -0800166 i < CHUNKheaderObj.fmt_ckSize - sizeof(WAVE_FMTINFO_header);
niklase@google.com470e71d2011-07-07 08:21:25 +0000167 i++)
168 {
169 len = wav.Read(&dummyRead, 1);
170 if(len != 1)
171 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200172 LOG(LS_ERROR)
173 << "File corrupted, reached EOF (reading fmt)";
niklase@google.com470e71d2011-07-07 08:21:25 +0000174 return -1;
175 }
176 }
177 fmtFound = true;
178 }
179 else if(strcmp(tmpStr, "data") == 0)
180 {
181 _dataSize = CHUNKheaderObj.fmt_ckSize;
182 dataFound = true;
183 break;
184 }
185 else
186 {
pkasting25702cb2016-01-08 13:50:27 -0800187 for (i = 0; i < CHUNKheaderObj.fmt_ckSize; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000188 {
189 len = wav.Read(&dummyRead, 1);
190 if(len != 1)
191 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200192 LOG(LS_ERROR)
193 << "File corrupted, reached EOF (reading other)";
niklase@google.com470e71d2011-07-07 08:21:25 +0000194 return -1;
195 }
196 }
197 }
198
199 len = wav.Read(&CHUNKheaderObj, sizeof(WAVE_CHUNK_header));
200
201 memcpy(tmpStr2, &CHUNKheaderObj.fmt_ckSize, 4);
202 CHUNKheaderObj.fmt_ckSize =
pkasting25702cb2016-01-08 13:50:27 -0800203 (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8) +
204 (((uint32_t)tmpStr2[2]) << 16) + (((uint32_t)tmpStr2[3]) << 24);
niklase@google.com470e71d2011-07-07 08:21:25 +0000205
206 memcpy(tmpStr, CHUNKheaderObj.fmt_ckID, 4);
207 }
208
209 // Either a proper format chunk has been read or a data chunk was come
210 // across.
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000211 if( (_wavFormatObj.formatTag != kWavFormatPcm) &&
212 (_wavFormatObj.formatTag != kWavFormatALaw) &&
213 (_wavFormatObj.formatTag != kWavFormatMuLaw))
niklase@google.com470e71d2011-07-07 08:21:25 +0000214 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200215 LOG(LS_ERROR) << "Coding formatTag value=" << _wavFormatObj.formatTag
216 << " not supported!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000217 return -1;
218 }
219 if((_wavFormatObj.nChannels < 1) ||
220 (_wavFormatObj.nChannels > 2))
221 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200222 LOG(LS_ERROR) << "nChannels value=" << _wavFormatObj.nChannels
223 << " not supported!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000224 return -1;
225 }
226
227 if((_wavFormatObj.nBitsPerSample != 8) &&
228 (_wavFormatObj.nBitsPerSample != 16))
229 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200230 LOG(LS_ERROR) << "nBitsPerSample value=" << _wavFormatObj.nBitsPerSample
231 << " not supported!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000232 return -1;
233 }
234
235 // Calculate the number of bytes that 10 ms of audio data correspond to.
pkasting25702cb2016-01-08 13:50:27 -0800236 size_t samples_per_10ms =
237 ((_wavFormatObj.formatTag == kWavFormatPcm) &&
238 (_wavFormatObj.nSamplesPerSec == 44100)) ?
239 440 : static_cast<size_t>(_wavFormatObj.nSamplesPerSec / 100);
240 _readSizeBytes = samples_per_10ms * _wavFormatObj.nChannels *
241 (_wavFormatObj.nBitsPerSample / 8);
niklase@google.com470e71d2011-07-07 08:21:25 +0000242 return 0;
243}
244
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000245int32_t ModuleFileUtility::InitWavCodec(uint32_t samplesPerSec,
Peter Kasting69558702016-01-12 16:26:35 -0800246 size_t channels,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000247 uint32_t bitsPerSample,
248 uint32_t formatTag)
niklase@google.com470e71d2011-07-07 08:21:25 +0000249{
250 codec_info_.pltype = -1;
251 codec_info_.plfreq = samplesPerSec;
252 codec_info_.channels = channels;
253 codec_info_.rate = bitsPerSample * samplesPerSec;
254
255 // Calculate the packet size for 10ms frames
256 switch(formatTag)
257 {
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000258 case kWavFormatALaw:
niklase@google.com470e71d2011-07-07 08:21:25 +0000259 strcpy(codec_info_.plname, "PCMA");
260 _codecId = kCodecPcma;
261 codec_info_.pltype = 8;
262 codec_info_.pacsize = codec_info_.plfreq / 100;
263 break;
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000264 case kWavFormatMuLaw:
niklase@google.com470e71d2011-07-07 08:21:25 +0000265 strcpy(codec_info_.plname, "PCMU");
266 _codecId = kCodecPcmu;
267 codec_info_.pltype = 0;
268 codec_info_.pacsize = codec_info_.plfreq / 100;
269 break;
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000270 case kWavFormatPcm:
niklase@google.com470e71d2011-07-07 08:21:25 +0000271 codec_info_.pacsize = (bitsPerSample * (codec_info_.plfreq / 100)) / 8;
272 if(samplesPerSec == 8000)
273 {
274 strcpy(codec_info_.plname, "L16");
275 _codecId = kCodecL16_8Khz;
276 }
277 else if(samplesPerSec == 16000)
278 {
279 strcpy(codec_info_.plname, "L16");
280 _codecId = kCodecL16_16kHz;
281 }
282 else if(samplesPerSec == 32000)
283 {
284 strcpy(codec_info_.plname, "L16");
285 _codecId = kCodecL16_32Khz;
286 }
287 // Set the packet size for "odd" sampling frequencies so that it
288 // properly corresponds to _readSizeBytes.
289 else if(samplesPerSec == 11025)
290 {
291 strcpy(codec_info_.plname, "L16");
292 _codecId = kCodecL16_16kHz;
293 codec_info_.pacsize = 110;
294 codec_info_.plfreq = 11000;
295 }
296 else if(samplesPerSec == 22050)
297 {
298 strcpy(codec_info_.plname, "L16");
299 _codecId = kCodecL16_16kHz;
300 codec_info_.pacsize = 220;
301 codec_info_.plfreq = 22000;
302 }
303 else if(samplesPerSec == 44100)
304 {
305 strcpy(codec_info_.plname, "L16");
306 _codecId = kCodecL16_16kHz;
307 codec_info_.pacsize = 440;
308 codec_info_.plfreq = 44000;
309 }
310 else if(samplesPerSec == 48000)
311 {
312 strcpy(codec_info_.plname, "L16");
313 _codecId = kCodecL16_16kHz;
314 codec_info_.pacsize = 480;
315 codec_info_.plfreq = 48000;
316 }
317 else
318 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200319 LOG(LS_ERROR) << "Unsupported PCM frequency!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000320 return -1;
321 }
322 break;
323 default:
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200324 LOG(LS_ERROR) << "unknown WAV format TAG!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000325 return -1;
326 break;
327 }
328 return 0;
329}
330
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000331int32_t ModuleFileUtility::InitWavReading(InStream& wav,
332 const uint32_t start,
333 const uint32_t stop)
niklase@google.com470e71d2011-07-07 08:21:25 +0000334{
niklase@google.com470e71d2011-07-07 08:21:25 +0000335
336 _reading = false;
337
338 if(ReadWavHeader(wav) == -1)
339 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200340 LOG(LS_ERROR) << "failed to read WAV header!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000341 return -1;
342 }
343
344 _playoutPositionMs = 0;
345 _readPos = 0;
346
347 if(start > 0)
348 {
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000349 uint8_t dummy[WAV_MAX_BUFFER_SIZE];
pkasting25702cb2016-01-08 13:50:27 -0800350 int readLength;
niklase@google.com470e71d2011-07-07 08:21:25 +0000351 if(_readSizeBytes <= WAV_MAX_BUFFER_SIZE)
352 {
353 while (_playoutPositionMs < start)
354 {
355 readLength = wav.Read(dummy, _readSizeBytes);
pkasting25702cb2016-01-08 13:50:27 -0800356 if(readLength == static_cast<int>(_readSizeBytes))
niklase@google.com470e71d2011-07-07 08:21:25 +0000357 {
pkasting25702cb2016-01-08 13:50:27 -0800358 _readPos += _readSizeBytes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000359 _playoutPositionMs += 10;
360 }
361 else // Must have reached EOF before start position!
362 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200363 LOG(LS_ERROR)
364 << "InitWavReading(), EOF before start position";
niklase@google.com470e71d2011-07-07 08:21:25 +0000365 return -1;
366 }
367 }
368 }
369 else
370 {
371 return -1;
372 }
373 }
374 if( InitWavCodec(_wavFormatObj.nSamplesPerSec, _wavFormatObj.nChannels,
375 _wavFormatObj.nBitsPerSample,
376 _wavFormatObj.formatTag) != 0)
377 {
378 return -1;
379 }
pkasting25702cb2016-01-08 13:50:27 -0800380 _bytesPerSample = static_cast<size_t>(_wavFormatObj.nBitsPerSample / 8);
niklase@google.com470e71d2011-07-07 08:21:25 +0000381
niklase@google.com470e71d2011-07-07 08:21:25 +0000382
383 _startPointInMs = start;
384 _stopPointInMs = stop;
385 _reading = true;
386 return 0;
387}
388
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000389int32_t ModuleFileUtility::ReadWavDataAsMono(
niklase@google.com470e71d2011-07-07 08:21:25 +0000390 InStream& wav,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000391 int8_t* outData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000392 const size_t bufferSize)
niklase@google.com470e71d2011-07-07 08:21:25 +0000393{
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200394 LOG(LS_VERBOSE) << "ModuleFileUtility::ReadWavDataAsMono(wav= " << &wav
395 << ", outData= " << static_cast<void*>(outData)
396 << ", bufSize= " << bufferSize << ")";
niklase@google.com470e71d2011-07-07 08:21:25 +0000397
398 // The number of bytes that should be read from file.
pkasting25702cb2016-01-08 13:50:27 -0800399 const size_t totalBytesNeeded = _readSizeBytes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000400 // The number of bytes that will be written to outData.
pkasting25702cb2016-01-08 13:50:27 -0800401 const size_t bytesRequested = (codec_info_.channels == 2) ?
niklase@google.com470e71d2011-07-07 08:21:25 +0000402 totalBytesNeeded >> 1 : totalBytesNeeded;
403 if(bufferSize < bytesRequested)
404 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200405 LOG(LS_ERROR) << "ReadWavDataAsMono: output buffer is too short!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000406 return -1;
407 }
408 if(outData == NULL)
409 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200410 LOG(LS_ERROR) << "ReadWavDataAsMono: output buffer NULL!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000411 return -1;
412 }
413
414 if(!_reading)
415 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200416 LOG(LS_ERROR) << "ReadWavDataAsMono: no longer reading file.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000417 return -1;
418 }
419
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000420 int32_t bytesRead = ReadWavData(
niklase@google.com470e71d2011-07-07 08:21:25 +0000421 wav,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000422 (codec_info_.channels == 2) ? _tempData : (uint8_t*)outData,
niklase@google.com470e71d2011-07-07 08:21:25 +0000423 totalBytesNeeded);
424 if(bytesRead == 0)
425 {
426 return 0;
427 }
428 if(bytesRead < 0)
429 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200430 LOG(LS_ERROR)
431 << "ReadWavDataAsMono: failed to read data from WAV file.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000432 return -1;
433 }
434 // Output data is should be mono.
435 if(codec_info_.channels == 2)
436 {
pkasting25702cb2016-01-08 13:50:27 -0800437 for (size_t i = 0; i < bytesRequested / _bytesPerSample; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000438 {
439 // Sample value is the average of left and right buffer rounded to
440 // closest integer value. Note samples can be either 1 or 2 byte.
441 if(_bytesPerSample == 1)
442 {
443 _tempData[i] = ((_tempData[2 * i] + _tempData[(2 * i) + 1] +
444 1) >> 1);
445 }
446 else
447 {
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000448 int16_t* sampleData = (int16_t*) _tempData;
niklase@google.com470e71d2011-07-07 08:21:25 +0000449 sampleData[i] = ((sampleData[2 * i] + sampleData[(2 * i) + 1] +
450 1) >> 1);
451 }
452 }
453 memcpy(outData, _tempData, bytesRequested);
454 }
pkasting25702cb2016-01-08 13:50:27 -0800455 return static_cast<int32_t>(bytesRequested);
niklase@google.com470e71d2011-07-07 08:21:25 +0000456}
457
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000458int32_t ModuleFileUtility::ReadWavDataAsStereo(
niklase@google.com470e71d2011-07-07 08:21:25 +0000459 InStream& wav,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000460 int8_t* outDataLeft,
461 int8_t* outDataRight,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000462 const size_t bufferSize)
niklase@google.com470e71d2011-07-07 08:21:25 +0000463{
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200464 LOG(LS_VERBOSE) << "ModuleFileUtility::ReadWavDataAsStereo(wav= " << &wav
465 << ", outLeft= " << static_cast<void*>(outDataLeft)
466 << ", outRight= " << static_cast<void*>(outDataRight)
467 << ", bufSize= " << bufferSize << ")";
niklase@google.com470e71d2011-07-07 08:21:25 +0000468
469 if((outDataLeft == NULL) ||
470 (outDataRight == NULL))
471 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200472 LOG(LS_ERROR) << "ReadWavDataAsStereo: an input buffer is NULL!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000473 return -1;
474 }
475 if(codec_info_.channels != 2)
476 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200477 LOG(LS_ERROR)
478 << "ReadWavDataAsStereo: WAV file does not contain stereo data!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000479 return -1;
480 }
481 if(! _reading)
482 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200483 LOG(LS_ERROR) << "ReadWavDataAsStereo: no longer reading file.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000484 return -1;
485 }
486
487 // The number of bytes that should be read from file.
pkasting25702cb2016-01-08 13:50:27 -0800488 const size_t totalBytesNeeded = _readSizeBytes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000489 // The number of bytes that will be written to the left and the right
490 // buffers.
pkasting25702cb2016-01-08 13:50:27 -0800491 const size_t bytesRequested = totalBytesNeeded >> 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000492 if(bufferSize < bytesRequested)
493 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200494 LOG(LS_ERROR) << "ReadWavDataAsStereo: Output buffers are too short!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000495 assert(false);
496 return -1;
497 }
498
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000499 int32_t bytesRead = ReadWavData(wav, _tempData, totalBytesNeeded);
niklase@google.com470e71d2011-07-07 08:21:25 +0000500 if(bytesRead <= 0)
501 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200502 LOG(LS_ERROR)
503 << "ReadWavDataAsStereo: failed to read data from WAV file.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000504 return -1;
505 }
506
507 // Turn interleaved audio to left and right buffer. Note samples can be
508 // either 1 or 2 bytes
509 if(_bytesPerSample == 1)
510 {
pkasting25702cb2016-01-08 13:50:27 -0800511 for (size_t i = 0; i < bytesRequested; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000512 {
513 outDataLeft[i] = _tempData[2 * i];
514 outDataRight[i] = _tempData[(2 * i) + 1];
515 }
516 }
517 else if(_bytesPerSample == 2)
518 {
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000519 int16_t* sampleData = reinterpret_cast<int16_t*>(_tempData);
520 int16_t* outLeft = reinterpret_cast<int16_t*>(outDataLeft);
521 int16_t* outRight = reinterpret_cast<int16_t*>(
niklase@google.com470e71d2011-07-07 08:21:25 +0000522 outDataRight);
523
524 // Bytes requested to samples requested.
pkasting25702cb2016-01-08 13:50:27 -0800525 size_t sampleCount = bytesRequested >> 1;
526 for (size_t i = 0; i < sampleCount; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000527 {
528 outLeft[i] = sampleData[2 * i];
529 outRight[i] = sampleData[(2 * i) + 1];
530 }
531 } else {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200532 LOG(LS_ERROR) << "ReadWavStereoData: unsupported sample size "
533 << _bytesPerSample << "!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000534 assert(false);
535 return -1;
536 }
pkasting25702cb2016-01-08 13:50:27 -0800537 return static_cast<int32_t>(bytesRequested);
niklase@google.com470e71d2011-07-07 08:21:25 +0000538}
539
pkasting25702cb2016-01-08 13:50:27 -0800540int32_t ModuleFileUtility::ReadWavData(InStream& wav,
541 uint8_t* buffer,
542 size_t dataLengthInBytes)
niklase@google.com470e71d2011-07-07 08:21:25 +0000543{
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200544 LOG(LS_VERBOSE) << "ModuleFileUtility::ReadWavData(wav= " << &wav
545 << ", buffer= " << static_cast<void*>(buffer)
546 << ", dataLen= " << dataLengthInBytes << ")";
niklase@google.com470e71d2011-07-07 08:21:25 +0000547
548 if(buffer == NULL)
549 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200550 LOG(LS_ERROR) << "ReadWavDataAsMono: output buffer NULL!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000551 return -1;
552 }
553
554 // Make sure that a read won't return too few samples.
555 // TODO (hellner): why not read the remaining bytes needed from the start
556 // of the file?
pkasting25702cb2016-01-08 13:50:27 -0800557 if(_dataSize < (_readPos + dataLengthInBytes))
niklase@google.com470e71d2011-07-07 08:21:25 +0000558 {
559 // Rewind() being -1 may be due to the file not supposed to be looped.
560 if(wav.Rewind() == -1)
561 {
562 _reading = false;
563 return 0;
564 }
565 if(InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1)
566 {
567 _reading = false;
568 return -1;
569 }
570 }
571
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000572 int32_t bytesRead = wav.Read(buffer, dataLengthInBytes);
niklase@google.com470e71d2011-07-07 08:21:25 +0000573 if(bytesRead < 0)
574 {
575 _reading = false;
576 return -1;
577 }
578
579 // This should never happen due to earlier sanity checks.
580 // TODO (hellner): change to an assert and fail here since this should
581 // never happen...
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000582 if(bytesRead < (int32_t)dataLengthInBytes)
niklase@google.com470e71d2011-07-07 08:21:25 +0000583 {
584 if((wav.Rewind() == -1) ||
585 (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1))
586 {
587 _reading = false;
588 return -1;
589 }
590 else
591 {
592 bytesRead = wav.Read(buffer, dataLengthInBytes);
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000593 if(bytesRead < (int32_t)dataLengthInBytes)
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 {
595 _reading = false;
596 return -1;
597 }
598 }
599 }
600
601 _readPos += bytesRead;
602
603 // TODO (hellner): Why is dataLengthInBytes let dictate the number of bytes
604 // to read when exactly 10ms should be read?!
605 _playoutPositionMs += 10;
606 if((_stopPointInMs > 0) &&
607 (_playoutPositionMs >= _stopPointInMs))
608 {
609 if((wav.Rewind() == -1) ||
610 (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1))
611 {
612 _reading = false;
613 }
614 }
615 return bytesRead;
616}
617
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000618int32_t ModuleFileUtility::InitWavWriting(OutStream& wav,
619 const CodecInst& codecInst)
niklase@google.com470e71d2011-07-07 08:21:25 +0000620{
niklase@google.com470e71d2011-07-07 08:21:25 +0000621
622 if(set_codec_info(codecInst) != 0)
623 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200624 LOG(LS_ERROR) << "codecInst identifies unsupported codec!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000625 return -1;
626 }
627 _writing = false;
Peter Kasting69558702016-01-12 16:26:35 -0800628 size_t channels = (codecInst.channels == 0) ? 1 : codecInst.channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000629
630 if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0)
631 {
632 _bytesPerSample = 1;
633 if(WriteWavHeader(wav, 8000, _bytesPerSample, channels,
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000634 kWavFormatMuLaw, 0) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000635 {
636 return -1;
637 }
pkasting25702cb2016-01-08 13:50:27 -0800638 }
639 else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000640 {
641 _bytesPerSample = 1;
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000642 if(WriteWavHeader(wav, 8000, _bytesPerSample, channels, kWavFormatALaw,
niklase@google.com470e71d2011-07-07 08:21:25 +0000643 0) == -1)
644 {
645 return -1;
646 }
647 }
648 else if(STR_CASE_CMP(codecInst.plname, "L16") == 0)
649 {
650 _bytesPerSample = 2;
651 if(WriteWavHeader(wav, codecInst.plfreq, _bytesPerSample, channels,
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000652 kWavFormatPcm, 0) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000653 {
654 return -1;
655 }
656 }
657 else
658 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200659 LOG(LS_ERROR) << "codecInst identifies unsupported codec for WAV file!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000660 return -1;
661 }
662 _writing = true;
663 _bytesWritten = 0;
664 return 0;
665}
666
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000667int32_t ModuleFileUtility::WriteWavData(OutStream& out,
668 const int8_t* buffer,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000669 const size_t dataLength)
niklase@google.com470e71d2011-07-07 08:21:25 +0000670{
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200671 LOG(LS_VERBOSE) << "ModuleFileUtility::WriteWavData(out= " << &out
672 << ", buf= " << static_cast<const void*>(buffer)
673 << ", dataLen= " << dataLength << ")";
niklase@google.com470e71d2011-07-07 08:21:25 +0000674
675 if(buffer == NULL)
676 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200677 LOG(LS_ERROR) << "WriteWavData: input buffer NULL!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000678 return -1;
679 }
680
681 if(!out.Write(buffer, dataLength))
682 {
683 return -1;
684 }
685 _bytesWritten += dataLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000686 return static_cast<int32_t>(dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +0000687}
688
689
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000690int32_t ModuleFileUtility::WriteWavHeader(
niklase@google.com470e71d2011-07-07 08:21:25 +0000691 OutStream& wav,
pkasting25702cb2016-01-08 13:50:27 -0800692 uint32_t freq,
693 size_t bytesPerSample,
Peter Kasting69558702016-01-12 16:26:35 -0800694 size_t channels,
pkasting25702cb2016-01-08 13:50:27 -0800695 uint32_t format,
696 size_t lengthInBytes)
niklase@google.com470e71d2011-07-07 08:21:25 +0000697{
niklase@google.com470e71d2011-07-07 08:21:25 +0000698 // Frame size in bytes for 10 ms of audio.
699 // TODO (hellner): 44.1 kHz has 440 samples frame size. Doesn't seem to
700 // be taken into consideration here!
pkasting25702cb2016-01-08 13:50:27 -0800701 const size_t frameSize = (freq / 100) * channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000702
703 // Calculate the number of full frames that the wave file contain.
pkasting25702cb2016-01-08 13:50:27 -0800704 const size_t dataLengthInBytes = frameSize * (lengthInBytes / frameSize);
niklase@google.com470e71d2011-07-07 08:21:25 +0000705
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000706 uint8_t buf[kWavHeaderSize];
707 webrtc::WriteWavHeader(buf, channels, freq, static_cast<WavFormat>(format),
708 bytesPerSample, dataLengthInBytes / bytesPerSample);
709 wav.Write(buf, kWavHeaderSize);
niklase@google.com470e71d2011-07-07 08:21:25 +0000710 return 0;
711}
712
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000713int32_t ModuleFileUtility::UpdateWavHeader(OutStream& wav)
niklase@google.com470e71d2011-07-07 08:21:25 +0000714{
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000715 int32_t res = -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000716 if(wav.Rewind() == -1)
717 {
718 return -1;
719 }
Peter Kasting69558702016-01-12 16:26:35 -0800720 size_t channels = (codec_info_.channels == 0) ? 1 : codec_info_.channels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000721
722 if(STR_CASE_CMP(codec_info_.plname, "L16") == 0)
723 {
724 res = WriteWavHeader(wav, codec_info_.plfreq, 2, channels,
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000725 kWavFormatPcm, _bytesWritten);
niklase@google.com470e71d2011-07-07 08:21:25 +0000726 } else if(STR_CASE_CMP(codec_info_.plname, "PCMU") == 0) {
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000727 res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatMuLaw,
niklase@google.com470e71d2011-07-07 08:21:25 +0000728 _bytesWritten);
henrike@webrtc.org4df8c9a2011-10-19 18:30:25 +0000729 } else if(STR_CASE_CMP(codec_info_.plname, "PCMA") == 0) {
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000730 res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatALaw,
niklase@google.com470e71d2011-07-07 08:21:25 +0000731 _bytesWritten);
732 } else {
733 // Allow calling this API even if not writing to a WAVE file.
734 // TODO (hellner): why?!
735 return 0;
736 }
737 return res;
738}
739
740
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000741int32_t ModuleFileUtility::InitPreEncodedReading(InStream& in,
742 const CodecInst& cinst)
niklase@google.com470e71d2011-07-07 08:21:25 +0000743{
niklase@google.com470e71d2011-07-07 08:21:25 +0000744
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000745 uint8_t preEncodedID;
niklase@google.com470e71d2011-07-07 08:21:25 +0000746 in.Read(&preEncodedID, 1);
747
748 MediaFileUtility_CodecType codecType =
749 (MediaFileUtility_CodecType)preEncodedID;
750
751 if(set_codec_info(cinst) != 0)
752 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200753 LOG(LS_ERROR) << "Pre-encoded file send codec mismatch!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000754 return -1;
755 }
756 if(codecType != _codecId)
757 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200758 LOG(LS_ERROR) << "Pre-encoded file format codec mismatch!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000759 return -1;
760 }
761 memcpy(&codec_info_,&cinst,sizeof(CodecInst));
762 _reading = true;
763 return 0;
764}
765
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000766int32_t ModuleFileUtility::ReadPreEncodedData(
niklase@google.com470e71d2011-07-07 08:21:25 +0000767 InStream& in,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000768 int8_t* outData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000769 const size_t bufferSize)
niklase@google.com470e71d2011-07-07 08:21:25 +0000770{
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200771 LOG(LS_VERBOSE) << "ModuleFileUtility::ReadPreEncodedData(in= " << &in
772 << ", outData= " << static_cast<void*>(outData)
773 << ", bufferSize= " << bufferSize << ")";
niklase@google.com470e71d2011-07-07 08:21:25 +0000774
775 if(outData == NULL)
776 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200777 LOG(LS_ERROR) << "output buffer NULL";
niklase@google.com470e71d2011-07-07 08:21:25 +0000778 }
779
pkasting25702cb2016-01-08 13:50:27 -0800780 size_t frameLen;
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000781 uint8_t buf[64];
niklase@google.com470e71d2011-07-07 08:21:25 +0000782 // Each frame has a two byte header containing the frame length.
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000783 int32_t res = in.Read(buf, 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000784 if(res != 2)
785 {
786 if(!in.Rewind())
787 {
788 // The first byte is the codec identifier.
789 in.Read(buf, 1);
790 res = in.Read(buf, 2);
791 }
792 else
793 {
794 return -1;
795 }
796 }
797 frameLen = buf[0] + buf[1] * 256;
798 if(bufferSize < frameLen)
799 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200800 LOG(LS_ERROR) << "buffer not large enough to read " << frameLen
801 << " bytes of pre-encoded data!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000802 return -1;
803 }
804 return in.Read(outData, frameLen);
805}
806
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000807int32_t ModuleFileUtility::InitPreEncodedWriting(
niklase@google.com470e71d2011-07-07 08:21:25 +0000808 OutStream& out,
809 const CodecInst& codecInst)
810{
niklase@google.com470e71d2011-07-07 08:21:25 +0000811
812 if(set_codec_info(codecInst) != 0)
813 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200814 LOG(LS_ERROR) << "CodecInst not recognized!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000815 return -1;
816 }
817 _writing = true;
818 _bytesWritten = 1;
Peter Kasting69558702016-01-12 16:26:35 -0800819 out.Write(&_codecId, 1);
820 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000821}
822
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000823int32_t ModuleFileUtility::WritePreEncodedData(
niklase@google.com470e71d2011-07-07 08:21:25 +0000824 OutStream& out,
Peter Kasting69558702016-01-12 16:26:35 -0800825 const int8_t* buffer,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000826 const size_t dataLength)
niklase@google.com470e71d2011-07-07 08:21:25 +0000827{
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200828 LOG(LS_VERBOSE) << "ModuleFileUtility::WritePreEncodedData(out= " << &out
829 << " , inData= " << static_cast<const void*>(buffer)
830 << ", dataLen= " << dataLength << ")";
niklase@google.com470e71d2011-07-07 08:21:25 +0000831
832 if(buffer == NULL)
833 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200834 LOG(LS_ERROR) << "buffer NULL";
niklase@google.com470e71d2011-07-07 08:21:25 +0000835 }
836
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000837 size_t bytesWritten = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000838 // The first two bytes is the size of the frame.
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000839 int16_t lengthBuf;
840 lengthBuf = (int16_t)dataLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000841 if(dataLength > static_cast<size_t>(std::numeric_limits<int16_t>::max()) ||
842 !out.Write(&lengthBuf, 2))
niklase@google.com470e71d2011-07-07 08:21:25 +0000843 {
844 return -1;
845 }
846 bytesWritten = 2;
847
848 if(!out.Write(buffer, dataLength))
849 {
850 return -1;
851 }
852 bytesWritten += dataLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000853 return static_cast<int32_t>(bytesWritten);
niklase@google.com470e71d2011-07-07 08:21:25 +0000854}
855
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000856int32_t ModuleFileUtility::InitCompressedReading(
niklase@google.com470e71d2011-07-07 08:21:25 +0000857 InStream& in,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000858 const uint32_t start,
859 const uint32_t stop)
niklase@google.com470e71d2011-07-07 08:21:25 +0000860{
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200861 LOG(LS_VERBOSE) << "ModuleFileUtility::InitCompressedReading(in= " << &in
862 << ", start= " << start << ", stop= " << stop << ")";
niklase@google.com470e71d2011-07-07 08:21:25 +0000863
henrik.lundin@webrtc.orgfa587452015-02-23 09:25:40 +0000864#if defined(WEBRTC_CODEC_ILBC)
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000865 int16_t read_len = 0;
henrikg@webrtc.orgaf225d62011-12-09 09:58:39 +0000866#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000867 _codecId = kCodecNoCodec;
868 _playoutPositionMs = 0;
869 _reading = false;
870
871 _startPointInMs = start;
872 _stopPointInMs = stop;
873
niklase@google.com470e71d2011-07-07 08:21:25 +0000874 // Read the codec name
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000875 int32_t cnt = 0;
leozwang@webrtc.org09e77192012-03-01 18:35:54 +0000876 char buf[64];
niklase@google.com470e71d2011-07-07 08:21:25 +0000877 do
878 {
879 in.Read(&buf[cnt++], 1);
880 } while ((buf[cnt-1] != '\n') && (64 > cnt));
881
882 if(cnt==64)
883 {
884 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000885 }
pkasting25702cb2016-01-08 13:50:27 -0800886 buf[cnt]=0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000887
niklase@google.com470e71d2011-07-07 08:21:25 +0000888#ifdef WEBRTC_CODEC_ILBC
889 if(!strcmp("#!iLBC20\n", buf))
890 {
891 codec_info_.pltype = 102;
892 strcpy(codec_info_.plname, "ilbc");
893 codec_info_.plfreq = 8000;
894 codec_info_.pacsize = 160;
895 codec_info_.channels = 1;
896 codec_info_.rate = 13300;
897 _codecId = kCodecIlbc20Ms;
898
899 if(_startPointInMs > 0)
900 {
901 while (_playoutPositionMs <= _startPointInMs)
902 {
903 read_len = in.Read(buf, 38);
pkasting25702cb2016-01-08 13:50:27 -0800904 if(read_len != 38)
niklase@google.com470e71d2011-07-07 08:21:25 +0000905 {
906 return -1;
907 }
pkasting25702cb2016-01-08 13:50:27 -0800908 _playoutPositionMs += 20;
niklase@google.com470e71d2011-07-07 08:21:25 +0000909 }
910 }
911 }
912
913 if(!strcmp("#!iLBC30\n", buf))
914 {
915 codec_info_.pltype = 102;
916 strcpy(codec_info_.plname, "ilbc");
917 codec_info_.plfreq = 8000;
918 codec_info_.pacsize = 240;
919 codec_info_.channels = 1;
920 codec_info_.rate = 13300;
921 _codecId = kCodecIlbc30Ms;
922
923 if(_startPointInMs > 0)
924 {
925 while (_playoutPositionMs <= _startPointInMs)
926 {
927 read_len = in.Read(buf, 50);
pkasting25702cb2016-01-08 13:50:27 -0800928 if(read_len != 50)
niklase@google.com470e71d2011-07-07 08:21:25 +0000929 {
930 return -1;
931 }
pkasting25702cb2016-01-08 13:50:27 -0800932 _playoutPositionMs += 20;
niklase@google.com470e71d2011-07-07 08:21:25 +0000933 }
934 }
935 }
936#endif
937 if(_codecId == kCodecNoCodec)
938 {
939 return -1;
940 }
941 _reading = true;
942 return 0;
943}
944
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +0000945int32_t ModuleFileUtility::ReadCompressedData(InStream& in,
946 int8_t* outData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000947 size_t bufferSize)
niklase@google.com470e71d2011-07-07 08:21:25 +0000948{
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200949 LOG(LS_VERBOSE) << "ModuleFileUtility::ReadCompressedData(in=" << &in
950 << ", outData=" << static_cast<void*>(outData) << ", bytes="
951 << bufferSize << ")";
niklase@google.com470e71d2011-07-07 08:21:25 +0000952
pkasting25702cb2016-01-08 13:50:27 -0800953 int bytesRead = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000954
955 if(! _reading)
956 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200957 LOG(LS_ERROR) << "not currently reading!";
niklase@google.com470e71d2011-07-07 08:21:25 +0000958 return -1;
959 }
960
niklase@google.com470e71d2011-07-07 08:21:25 +0000961#ifdef WEBRTC_CODEC_ILBC
962 if((_codecId == kCodecIlbc20Ms) ||
963 (_codecId == kCodecIlbc30Ms))
964 {
pkasting25702cb2016-01-08 13:50:27 -0800965 size_t byteSize = 0;
Peter Kasting69558702016-01-12 16:26:35 -0800966 if(_codecId == kCodecIlbc30Ms)
niklase@google.com470e71d2011-07-07 08:21:25 +0000967 {
968 byteSize = 50;
969 }
970 if(_codecId == kCodecIlbc20Ms)
971 {
972 byteSize = 38;
973 }
974 if(bufferSize < byteSize)
975 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +0200976 LOG(LS_ERROR)
977 << "output buffer is too short to read ILBC compressed data.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000978 assert(false);
979 return -1;
980 }
981
982 bytesRead = in.Read(outData, byteSize);
pkasting25702cb2016-01-08 13:50:27 -0800983 if(bytesRead != static_cast<int>(byteSize))
niklase@google.com470e71d2011-07-07 08:21:25 +0000984 {
985 if(!in.Rewind())
986 {
987 InitCompressedReading(in, _startPointInMs, _stopPointInMs);
988 bytesRead = in.Read(outData, byteSize);
pkasting25702cb2016-01-08 13:50:27 -0800989 if(bytesRead != static_cast<int>(byteSize))
niklase@google.com470e71d2011-07-07 08:21:25 +0000990 {
991 _reading = false;
992 return -1;
993 }
994 }
995 else
996 {
997 _reading = false;
998 return -1;
999 }
1000 }
1001 }
1002#endif
1003 if(bytesRead == 0)
1004 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001005 LOG(LS_ERROR)
1006 << "ReadCompressedData() no bytes read, codec not supported";
niklase@google.com470e71d2011-07-07 08:21:25 +00001007 return -1;
1008 }
1009
1010 _playoutPositionMs += 20;
1011 if((_stopPointInMs > 0) &&
1012 (_playoutPositionMs >= _stopPointInMs))
1013 {
1014 if(!in.Rewind())
1015 {
1016 InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1017 }
1018 else
1019 {
1020 _reading = false;
1021 }
1022 }
1023 return bytesRead;
1024}
1025
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001026int32_t ModuleFileUtility::InitCompressedWriting(
niklase@google.com470e71d2011-07-07 08:21:25 +00001027 OutStream& out,
1028 const CodecInst& codecInst)
1029{
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001030 LOG(LS_VERBOSE) << "ModuleFileUtility::InitCompressedWriting(out= " << &out
1031 << ", codecName= " << codecInst.plname << ")";
niklase@google.com470e71d2011-07-07 08:21:25 +00001032
1033 _writing = false;
1034
niklase@google.com470e71d2011-07-07 08:21:25 +00001035#ifdef WEBRTC_CODEC_ILBC
1036 if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0)
1037 {
1038 if(codecInst.pacsize == 160)
1039 {
1040 _codecId = kCodecIlbc20Ms;
1041 out.Write("#!iLBC20\n",9);
1042 }
1043 else if(codecInst.pacsize == 240)
1044 {
1045 _codecId = kCodecIlbc30Ms;
1046 out.Write("#!iLBC30\n",9);
1047 }
1048 else
1049 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001050 LOG(LS_ERROR) << "codecInst defines unsupported compression codec!";
niklase@google.com470e71d2011-07-07 08:21:25 +00001051 return -1;
1052 }
1053 memcpy(&codec_info_,&codecInst,sizeof(CodecInst));
1054 _writing = true;
1055 return 0;
1056 }
1057#endif
1058
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001059 LOG(LS_ERROR) << "codecInst defines unsupported compression codec!";
niklase@google.com470e71d2011-07-07 08:21:25 +00001060 return -1;
1061}
1062
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001063int32_t ModuleFileUtility::WriteCompressedData(
niklase@google.com470e71d2011-07-07 08:21:25 +00001064 OutStream& out,
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001065 const int8_t* buffer,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001066 const size_t dataLength)
niklase@google.com470e71d2011-07-07 08:21:25 +00001067{
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001068 LOG(LS_VERBOSE) << "ModuleFileUtility::WriteCompressedData(out= " << &out
1069 << ", buf= " << static_cast<const void*>(buffer)
1070 << ", dataLen= " << dataLength << ")";
niklase@google.com470e71d2011-07-07 08:21:25 +00001071
1072 if(buffer == NULL)
1073 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001074 LOG(LS_ERROR) << "buffer NULL";
niklase@google.com470e71d2011-07-07 08:21:25 +00001075 }
1076
1077 if(!out.Write(buffer, dataLength))
1078 {
1079 return -1;
1080 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001081 return static_cast<int32_t>(dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +00001082}
1083
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001084int32_t ModuleFileUtility::InitPCMReading(InStream& pcm,
1085 const uint32_t start,
1086 const uint32_t stop,
1087 uint32_t freq)
niklase@google.com470e71d2011-07-07 08:21:25 +00001088{
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001089 LOG(LS_VERBOSE) << "ModuleFileUtility::InitPCMReading(pcm= " << &pcm
1090 << ", start=" << start << ", stop=" << stop << ", freq="
1091 << freq << ")";
niklase@google.com470e71d2011-07-07 08:21:25 +00001092
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001093 int8_t dummy[320];
pkasting25702cb2016-01-08 13:50:27 -08001094 int read_len;
niklase@google.com470e71d2011-07-07 08:21:25 +00001095
1096 _playoutPositionMs = 0;
1097 _startPointInMs = start;
1098 _stopPointInMs = stop;
1099 _reading = false;
1100
1101 if(freq == 8000)
1102 {
1103 strcpy(codec_info_.plname, "L16");
1104 codec_info_.pltype = -1;
1105 codec_info_.plfreq = 8000;
1106 codec_info_.pacsize = 160;
1107 codec_info_.channels = 1;
1108 codec_info_.rate = 128000;
1109 _codecId = kCodecL16_8Khz;
1110 }
1111 else if(freq == 16000)
1112 {
1113 strcpy(codec_info_.plname, "L16");
1114 codec_info_.pltype = -1;
1115 codec_info_.plfreq = 16000;
1116 codec_info_.pacsize = 320;
1117 codec_info_.channels = 1;
1118 codec_info_.rate = 256000;
1119 _codecId = kCodecL16_16kHz;
1120 }
1121 else if(freq == 32000)
1122 {
1123 strcpy(codec_info_.plname, "L16");
1124 codec_info_.pltype = -1;
1125 codec_info_.plfreq = 32000;
1126 codec_info_.pacsize = 320;
1127 codec_info_.channels = 1;
1128 codec_info_.rate = 512000;
1129 _codecId = kCodecL16_32Khz;
1130 }
Minyue Li85a3b6b2017-09-01 14:36:33 +02001131 else if(freq == 48000)
1132 {
1133 strcpy(codec_info_.plname, "L16");
1134 codec_info_.pltype = -1;
1135 codec_info_.plfreq = 48000;
1136 codec_info_.pacsize = 480;
1137 codec_info_.channels = 1;
1138 codec_info_.rate = 768000;
1139 _codecId = kCodecL16_48Khz;
1140 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001141
1142 // Readsize for 10ms of audio data (2 bytes per sample).
1143 _readSizeBytes = 2 * codec_info_. plfreq / 100;
1144 if(_startPointInMs > 0)
1145 {
1146 while (_playoutPositionMs < _startPointInMs)
1147 {
1148 read_len = pcm.Read(dummy, _readSizeBytes);
pkasting25702cb2016-01-08 13:50:27 -08001149 if(read_len != static_cast<int>(_readSizeBytes))
niklase@google.com470e71d2011-07-07 08:21:25 +00001150 {
pkasting25702cb2016-01-08 13:50:27 -08001151 return -1; // Must have reached EOF before start position!
niklase@google.com470e71d2011-07-07 08:21:25 +00001152 }
pkasting25702cb2016-01-08 13:50:27 -08001153 _playoutPositionMs += 10;
niklase@google.com470e71d2011-07-07 08:21:25 +00001154 }
1155 }
1156 _reading = true;
1157 return 0;
1158}
1159
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001160int32_t ModuleFileUtility::ReadPCMData(InStream& pcm,
1161 int8_t* outData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001162 size_t bufferSize)
niklase@google.com470e71d2011-07-07 08:21:25 +00001163{
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001164 LOG(LS_VERBOSE) << "ModuleFileUtility::ReadPCMData(pcm= " << &pcm
1165 << ", outData= " << static_cast<void*>(outData)
1166 << ", bufSize= " << bufferSize << ")";
niklase@google.com470e71d2011-07-07 08:21:25 +00001167
1168 if(outData == NULL)
1169 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001170 LOG(LS_ERROR) << "buffer NULL";
niklase@google.com470e71d2011-07-07 08:21:25 +00001171 }
1172
1173 // Readsize for 10ms of audio data (2 bytes per sample).
pkasting25702cb2016-01-08 13:50:27 -08001174 size_t bytesRequested = static_cast<size_t>(2 * codec_info_.plfreq / 100);
niklase@google.com470e71d2011-07-07 08:21:25 +00001175 if(bufferSize < bytesRequested)
1176 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001177 LOG(LS_ERROR)
1178 << "ReadPCMData: buffer not long enough for a 10ms frame.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001179 assert(false);
1180 return -1;
1181 }
1182
pkasting25702cb2016-01-08 13:50:27 -08001183 int bytesRead = pcm.Read(outData, bytesRequested);
1184 if(bytesRead < static_cast<int>(bytesRequested))
niklase@google.com470e71d2011-07-07 08:21:25 +00001185 {
1186 if(pcm.Rewind() == -1)
1187 {
1188 _reading = false;
1189 }
1190 else
1191 {
1192 if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
1193 codec_info_.plfreq) == -1)
1194 {
1195 _reading = false;
1196 }
1197 else
1198 {
pkasting25702cb2016-01-08 13:50:27 -08001199 size_t rest = bytesRequested - bytesRead;
1200 int len = pcm.Read(&(outData[bytesRead]), rest);
1201 if(len == static_cast<int>(rest))
niklase@google.com470e71d2011-07-07 08:21:25 +00001202 {
1203 bytesRead += len;
1204 }
1205 else
1206 {
1207 _reading = false;
1208 }
1209 }
1210 if(bytesRead <= 0)
1211 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001212 LOG(LS_ERROR) << "ReadPCMData: Failed to rewind audio file.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001213 return -1;
1214 }
1215 }
1216 }
1217
1218 if(bytesRead <= 0)
1219 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001220 LOG(LS_VERBOSE) << "ReadPCMData: end of file";
niklase@google.com470e71d2011-07-07 08:21:25 +00001221 return -1;
1222 }
1223 _playoutPositionMs += 10;
1224 if(_stopPointInMs && _playoutPositionMs >= _stopPointInMs)
1225 {
1226 if(!pcm.Rewind())
1227 {
1228 if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
1229 codec_info_.plfreq) == -1)
1230 {
1231 _reading = false;
1232 }
1233 }
1234 }
1235 return bytesRead;
1236}
1237
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001238int32_t ModuleFileUtility::InitPCMWriting(OutStream& out, uint32_t freq)
niklase@google.com470e71d2011-07-07 08:21:25 +00001239{
niklase@google.com470e71d2011-07-07 08:21:25 +00001240
1241 if(freq == 8000)
1242 {
1243 strcpy(codec_info_.plname, "L16");
1244 codec_info_.pltype = -1;
1245 codec_info_.plfreq = 8000;
1246 codec_info_.pacsize = 160;
1247 codec_info_.channels = 1;
1248 codec_info_.rate = 128000;
1249
1250 _codecId = kCodecL16_8Khz;
1251 }
1252 else if(freq == 16000)
1253 {
1254 strcpy(codec_info_.plname, "L16");
1255 codec_info_.pltype = -1;
1256 codec_info_.plfreq = 16000;
1257 codec_info_.pacsize = 320;
1258 codec_info_.channels = 1;
1259 codec_info_.rate = 256000;
1260
1261 _codecId = kCodecL16_16kHz;
1262 }
1263 else if(freq == 32000)
1264 {
1265 strcpy(codec_info_.plname, "L16");
1266 codec_info_.pltype = -1;
1267 codec_info_.plfreq = 32000;
1268 codec_info_.pacsize = 320;
1269 codec_info_.channels = 1;
1270 codec_info_.rate = 512000;
1271
1272 _codecId = kCodecL16_32Khz;
1273 }
Minyue Li85a3b6b2017-09-01 14:36:33 +02001274 else if(freq == 48000)
1275 {
1276 strcpy(codec_info_.plname, "L16");
1277 codec_info_.pltype = -1;
1278 codec_info_.plfreq = 48000;
1279 codec_info_.pacsize = 480;
1280 codec_info_.channels = 1;
1281 codec_info_.rate = 768000;
1282
1283 _codecId = kCodecL16_48Khz;
1284 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001285 if((_codecId != kCodecL16_8Khz) &&
1286 (_codecId != kCodecL16_16kHz) &&
Minyue Li85a3b6b2017-09-01 14:36:33 +02001287 (_codecId != kCodecL16_32Khz) &&
1288 (_codecId != kCodecL16_48Khz))
niklase@google.com470e71d2011-07-07 08:21:25 +00001289 {
Minyue Li85a3b6b2017-09-01 14:36:33 +02001290 LOG(LS_ERROR) << "CodecInst is not 8KHz, 16KHz, 32kHz or 48kHz PCM!";
niklase@google.com470e71d2011-07-07 08:21:25 +00001291 return -1;
1292 }
1293 _writing = true;
1294 _bytesWritten = 0;
1295 return 0;
1296}
1297
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001298int32_t ModuleFileUtility::WritePCMData(OutStream& out,
1299 const int8_t* buffer,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001300 const size_t dataLength)
niklase@google.com470e71d2011-07-07 08:21:25 +00001301{
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001302 LOG(LS_VERBOSE) << "ModuleFileUtility::WritePCMData(out= " << &out
1303 << ", buf= " << static_cast<const void*>(buffer)
1304 << ", dataLen= " << dataLength << ")";
niklase@google.com470e71d2011-07-07 08:21:25 +00001305
1306 if(buffer == NULL)
1307 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001308 LOG(LS_ERROR) << "buffer NULL";
niklase@google.com470e71d2011-07-07 08:21:25 +00001309 }
1310
1311 if(!out.Write(buffer, dataLength))
1312 {
1313 return -1;
1314 }
1315
1316 _bytesWritten += dataLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001317 return static_cast<int32_t>(dataLength);
niklase@google.com470e71d2011-07-07 08:21:25 +00001318}
1319
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001320int32_t ModuleFileUtility::codec_info(CodecInst& codecInst)
niklase@google.com470e71d2011-07-07 08:21:25 +00001321{
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001322 LOG(LS_VERBOSE) << "ModuleFileUtility::codec_info(codecInst= " << &codecInst
1323 << ")";
niklase@google.com470e71d2011-07-07 08:21:25 +00001324
1325 if(!_reading && !_writing)
1326 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001327 LOG(LS_ERROR) << "CodecInst: not currently reading audio file!";
niklase@google.com470e71d2011-07-07 08:21:25 +00001328 return -1;
1329 }
1330 memcpy(&codecInst,&codec_info_,sizeof(CodecInst));
1331 return 0;
1332}
1333
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001334int32_t ModuleFileUtility::set_codec_info(const CodecInst& codecInst)
niklase@google.com470e71d2011-07-07 08:21:25 +00001335{
niklase@google.com470e71d2011-07-07 08:21:25 +00001336
1337 _codecId = kCodecNoCodec;
1338 if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0)
1339 {
1340 _codecId = kCodecPcmu;
1341 }
1342 else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0)
1343 {
1344 _codecId = kCodecPcma;
1345 }
1346 else if(STR_CASE_CMP(codecInst.plname, "L16") == 0)
1347 {
1348 if(codecInst.plfreq == 8000)
1349 {
1350 _codecId = kCodecL16_8Khz;
1351 }
1352 else if(codecInst.plfreq == 16000)
1353 {
1354 _codecId = kCodecL16_16kHz;
1355 }
1356 else if(codecInst.plfreq == 32000)
1357 {
1358 _codecId = kCodecL16_32Khz;
1359 }
Minyue Li85a3b6b2017-09-01 14:36:33 +02001360 else if(codecInst.plfreq == 48000)
1361 {
1362 _codecId = kCodecL16_48Khz;
1363 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001364 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001365#ifdef WEBRTC_CODEC_ILBC
1366 else if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0)
1367 {
1368 if(codecInst.pacsize == 160)
1369 {
1370 _codecId = kCodecIlbc20Ms;
1371 }
1372 else if(codecInst.pacsize == 240)
1373 {
1374 _codecId = kCodecIlbc30Ms;
1375 }
1376 }
1377#endif
1378#if(defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
1379 else if(STR_CASE_CMP(codecInst.plname, "isac") == 0)
1380 {
1381 if(codecInst.plfreq == 16000)
1382 {
1383 _codecId = kCodecIsac;
1384 }
1385 else if(codecInst.plfreq == 32000)
1386 {
1387 _codecId = kCodecIsacSwb;
1388 }
1389 }
1390#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001391#ifdef WEBRTC_CODEC_G722
1392 else if(STR_CASE_CMP(codecInst.plname, "G722") == 0)
1393 {
1394 _codecId = kCodecG722;
1395 }
1396#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001397 if(_codecId == kCodecNoCodec)
1398 {
1399 return -1;
1400 }
1401 memcpy(&codec_info_, &codecInst, sizeof(CodecInst));
1402 return 0;
1403}
1404
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001405int32_t ModuleFileUtility::FileDurationMs(const char* fileName,
1406 const FileFormats fileFormat,
1407 const uint32_t freqInHz)
niklase@google.com470e71d2011-07-07 08:21:25 +00001408{
niklase@google.com470e71d2011-07-07 08:21:25 +00001409
1410 if(fileName == NULL)
1411 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001412 LOG(LS_ERROR) << "filename NULL";
henrike@webrtc.org26085e12012-02-27 21:50:40 +00001413 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001414 }
1415
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001416 int32_t time_in_ms = -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001417 struct stat file_size;
1418 if(stat(fileName,&file_size) == -1)
1419 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001420 LOG(LS_ERROR) << "failed to retrieve file size with stat!";
niklase@google.com470e71d2011-07-07 08:21:25 +00001421 return -1;
1422 }
1423 FileWrapper* inStreamObj = FileWrapper::Create();
1424 if(inStreamObj == NULL)
1425 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001426 LOG(LS_INFO) << "failed to create InStream object!";
niklase@google.com470e71d2011-07-07 08:21:25 +00001427 return -1;
1428 }
tommia6219cc2016-06-15 10:30:14 -07001429 if (!inStreamObj->OpenFile(fileName, true)) {
1430 delete inStreamObj;
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001431 LOG(LS_ERROR) << "failed to open file " << fileName << "!";
tommia6219cc2016-06-15 10:30:14 -07001432 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001433 }
1434
1435 switch (fileFormat)
1436 {
1437 case kFileFormatWavFile:
1438 {
1439 if(ReadWavHeader(*inStreamObj) == -1)
1440 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001441 LOG(LS_ERROR) << "failed to read WAV file header!";
niklase@google.com470e71d2011-07-07 08:21:25 +00001442 return -1;
1443 }
1444 time_in_ms = ((file_size.st_size - 44) /
1445 (_wavFormatObj.nAvgBytesPerSec/1000));
1446 break;
1447 }
1448 case kFileFormatPcm16kHzFile:
1449 {
1450 // 16 samples per ms. 2 bytes per sample.
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001451 int32_t denominator = 16*2;
niklase@google.com470e71d2011-07-07 08:21:25 +00001452 time_in_ms = (file_size.st_size)/denominator;
1453 break;
1454 }
1455 case kFileFormatPcm8kHzFile:
1456 {
1457 // 8 samples per ms. 2 bytes per sample.
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001458 int32_t denominator = 8*2;
niklase@google.com470e71d2011-07-07 08:21:25 +00001459 time_in_ms = (file_size.st_size)/denominator;
1460 break;
1461 }
1462 case kFileFormatCompressedFile:
1463 {
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001464 int32_t cnt = 0;
pkasting25702cb2016-01-08 13:50:27 -08001465 int read_len = 0;
leozwang@webrtc.org09e77192012-03-01 18:35:54 +00001466 char buf[64];
niklase@google.com470e71d2011-07-07 08:21:25 +00001467 do
1468 {
1469 read_len = inStreamObj->Read(&buf[cnt++], 1);
1470 if(read_len != 1)
1471 {
1472 return -1;
1473 }
1474 } while ((buf[cnt-1] != '\n') && (64 > cnt));
1475
1476 if(cnt == 64)
1477 {
1478 return -1;
1479 }
1480 else
1481 {
1482 buf[cnt] = 0;
1483 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001484#ifdef WEBRTC_CODEC_ILBC
1485 if(!strcmp("#!iLBC20\n", buf))
1486 {
1487 // 20 ms is 304 bits
1488 time_in_ms = ((file_size.st_size)*160)/304;
1489 break;
1490 }
1491 if(!strcmp("#!iLBC30\n", buf))
1492 {
1493 // 30 ms takes 400 bits.
1494 // file size in bytes * 8 / 400 is the number of
1495 // 30 ms frames in the file ->
1496 // time_in_ms = file size * 8 / 400 * 30
1497 time_in_ms = ((file_size.st_size)*240)/400;
1498 break;
1499 }
1500#endif
mflodman@webrtc.org19fc09e2014-06-04 05:21:56 +00001501 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001502 }
1503 case kFileFormatPreencodedFile:
1504 {
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001505 LOG(LS_ERROR) << "cannot determine duration of Pre-Encoded file!";
niklase@google.com470e71d2011-07-07 08:21:25 +00001506 break;
1507 }
1508 default:
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001509 LOG(LS_ERROR) << "unsupported file format " << fileFormat << "!";
niklase@google.com470e71d2011-07-07 08:21:25 +00001510 break;
1511 }
1512 inStreamObj->CloseFile();
1513 delete inStreamObj;
1514 return time_in_ms;
1515}
1516
pbos@webrtc.org0ea11c12013-04-09 13:31:37 +00001517uint32_t ModuleFileUtility::PlayoutPositionMs()
niklase@google.com470e71d2011-07-07 08:21:25 +00001518{
Sam Zackrisson45ca37c2017-08-22 13:44:09 +02001519 LOG(LS_VERBOSE) << "ModuleFileUtility::PlayoutPosition()";
niklase@google.com470e71d2011-07-07 08:21:25 +00001520
pkasting25702cb2016-01-08 13:50:27 -08001521 return _reading ? _playoutPositionMs : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001522}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001523} // namespace webrtc