OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include "webrtc/modules/media_file/source/media_file_utility.h" | |
12 | |
13 #include <assert.h> | |
14 #include <sys/stat.h> | |
15 #include <sys/types.h> | |
16 #include <limits> | |
17 | |
18 #include "webrtc/base/format_macros.h" | |
19 #include "webrtc/common_audio/wav_header.h" | |
20 #include "webrtc/common_types.h" | |
21 #include "webrtc/engine_configurations.h" | |
22 #include "webrtc/modules/include/module_common_types.h" | |
23 #include "webrtc/system_wrappers/include/file_wrapper.h" | |
24 #include "webrtc/system_wrappers/include/trace.h" | |
25 | |
26 namespace { | |
27 | |
28 // First 16 bytes the WAVE header. ckID should be "RIFF", wave_ckID should be | |
29 // "WAVE" and ckSize is the chunk size (4 + n) | |
30 struct WAVE_RIFF_header | |
31 { | |
32 int8_t ckID[4]; | |
33 int32_t ckSize; | |
34 int8_t wave_ckID[4]; | |
35 }; | |
36 | |
37 // First 8 byte of the format chunk. fmt_ckID should be "fmt ". fmt_ckSize is | |
38 // the chunk size (16, 18 or 40 byte) | |
39 struct WAVE_CHUNK_header | |
40 { | |
41 int8_t fmt_ckID[4]; | |
42 int32_t fmt_ckSize; | |
43 }; | |
44 } // unnamed namespace | |
45 | |
46 namespace webrtc { | |
47 ModuleFileUtility::ModuleFileUtility(const int32_t id) | |
48 : _wavFormatObj(), | |
49 _dataSize(0), | |
50 _readSizeBytes(0), | |
51 _id(id), | |
52 _stopPointInMs(0), | |
53 _startPointInMs(0), | |
54 _playoutPositionMs(0), | |
55 _bytesWritten(0), | |
56 codec_info_(), | |
57 _codecId(kCodecNoCodec), | |
58 _bytesPerSample(0), | |
59 _readPos(0), | |
60 _reading(false), | |
61 _writing(false), | |
62 _tempData() { | |
63 WEBRTC_TRACE(kTraceMemory, kTraceFile, _id, | |
64 "ModuleFileUtility::ModuleFileUtility()"); | |
65 memset(&codec_info_,0,sizeof(CodecInst)); | |
66 codec_info_.pltype = -1; | |
67 } | |
68 | |
69 ModuleFileUtility::~ModuleFileUtility() | |
70 { | |
71 WEBRTC_TRACE(kTraceMemory, kTraceFile, _id, | |
72 "ModuleFileUtility::~ModuleFileUtility()"); | |
73 } | |
74 | |
75 int32_t ModuleFileUtility::ReadWavHeader(InStream& wav) | |
76 { | |
77 WAVE_RIFF_header RIFFheaderObj; | |
78 WAVE_CHUNK_header CHUNKheaderObj; | |
79 // TODO (hellner): tmpStr and tmpStr2 seems unnecessary here. | |
80 char tmpStr[6] = "FOUR"; | |
81 unsigned char tmpStr2[4]; | |
82 int32_t i, len; | |
83 bool dataFound = false; | |
84 bool fmtFound = false; | |
85 int8_t dummyRead; | |
86 | |
87 | |
88 _dataSize = 0; | |
89 len = wav.Read(&RIFFheaderObj, sizeof(WAVE_RIFF_header)); | |
90 if(len != sizeof(WAVE_RIFF_header)) | |
91 { | |
92 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
93 "Not a wave file (too short)"); | |
94 return -1; | |
95 } | |
96 | |
97 for (i = 0; i < 4; i++) | |
98 { | |
99 tmpStr[i] = RIFFheaderObj.ckID[i]; | |
100 } | |
101 if(strcmp(tmpStr, "RIFF") != 0) | |
102 { | |
103 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
104 "Not a wave file (does not have RIFF)"); | |
105 return -1; | |
106 } | |
107 for (i = 0; i < 4; i++) | |
108 { | |
109 tmpStr[i] = RIFFheaderObj.wave_ckID[i]; | |
110 } | |
111 if(strcmp(tmpStr, "WAVE") != 0) | |
112 { | |
113 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
114 "Not a wave file (does not have WAVE)"); | |
115 return -1; | |
116 } | |
117 | |
118 len = wav.Read(&CHUNKheaderObj, sizeof(WAVE_CHUNK_header)); | |
119 | |
120 // WAVE files are stored in little endian byte order. Make sure that the | |
121 // data can be read on big endian as well. | |
122 // TODO (hellner): little endian to system byte order should be done in | |
123 // in a subroutine. | |
124 memcpy(tmpStr2, &CHUNKheaderObj.fmt_ckSize, 4); | |
125 CHUNKheaderObj.fmt_ckSize = | |
126 (int32_t) ((uint32_t) tmpStr2[0] + | |
127 (((uint32_t)tmpStr2[1])<<8) + | |
128 (((uint32_t)tmpStr2[2])<<16) + | |
129 (((uint32_t)tmpStr2[3])<<24)); | |
130 | |
131 memcpy(tmpStr, CHUNKheaderObj.fmt_ckID, 4); | |
132 | |
133 while ((len == sizeof(WAVE_CHUNK_header)) && (!fmtFound || !dataFound)) | |
134 { | |
135 if(strcmp(tmpStr, "fmt ") == 0) | |
136 { | |
137 len = wav.Read(&_wavFormatObj, sizeof(WAVE_FMTINFO_header)); | |
138 | |
139 memcpy(tmpStr2, &_wavFormatObj.formatTag, 2); | |
140 _wavFormatObj.formatTag = | |
141 (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1])<<8); | |
142 memcpy(tmpStr2, &_wavFormatObj.nChannels, 2); | |
143 _wavFormatObj.nChannels = | |
144 (int16_t) ((uint32_t)tmpStr2[0] + | |
145 (((uint32_t)tmpStr2[1])<<8)); | |
146 memcpy(tmpStr2, &_wavFormatObj.nSamplesPerSec, 4); | |
147 _wavFormatObj.nSamplesPerSec = | |
148 (int32_t) ((uint32_t)tmpStr2[0] + | |
149 (((uint32_t)tmpStr2[1])<<8) + | |
150 (((uint32_t)tmpStr2[2])<<16) + | |
151 (((uint32_t)tmpStr2[3])<<24)); | |
152 memcpy(tmpStr2, &_wavFormatObj.nAvgBytesPerSec, 4); | |
153 _wavFormatObj.nAvgBytesPerSec = | |
154 (int32_t) ((uint32_t)tmpStr2[0] + | |
155 (((uint32_t)tmpStr2[1])<<8) + | |
156 (((uint32_t)tmpStr2[2])<<16) + | |
157 (((uint32_t)tmpStr2[3])<<24)); | |
158 memcpy(tmpStr2, &_wavFormatObj.nBlockAlign, 2); | |
159 _wavFormatObj.nBlockAlign = | |
160 (int16_t) ((uint32_t)tmpStr2[0] + | |
161 (((uint32_t)tmpStr2[1])<<8)); | |
162 memcpy(tmpStr2, &_wavFormatObj.nBitsPerSample, 2); | |
163 _wavFormatObj.nBitsPerSample = | |
164 (int16_t) ((uint32_t)tmpStr2[0] + | |
165 (((uint32_t)tmpStr2[1])<<8)); | |
166 | |
167 for (i = 0; | |
168 i < (CHUNKheaderObj.fmt_ckSize - | |
169 (int32_t)sizeof(WAVE_FMTINFO_header)); | |
170 i++) | |
171 { | |
172 len = wav.Read(&dummyRead, 1); | |
173 if(len != 1) | |
174 { | |
175 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
176 "File corrupted, reached EOF (reading fmt)"); | |
177 return -1; | |
178 } | |
179 } | |
180 fmtFound = true; | |
181 } | |
182 else if(strcmp(tmpStr, "data") == 0) | |
183 { | |
184 _dataSize = CHUNKheaderObj.fmt_ckSize; | |
185 dataFound = true; | |
186 break; | |
187 } | |
188 else | |
189 { | |
190 for (i = 0; i < (CHUNKheaderObj.fmt_ckSize); i++) | |
191 { | |
192 len = wav.Read(&dummyRead, 1); | |
193 if(len != 1) | |
194 { | |
195 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
196 "File corrupted, reached EOF (reading other)"); | |
197 return -1; | |
198 } | |
199 } | |
200 } | |
201 | |
202 len = wav.Read(&CHUNKheaderObj, sizeof(WAVE_CHUNK_header)); | |
203 | |
204 memcpy(tmpStr2, &CHUNKheaderObj.fmt_ckSize, 4); | |
205 CHUNKheaderObj.fmt_ckSize = | |
206 (int32_t) ((uint32_t)tmpStr2[0] + | |
207 (((uint32_t)tmpStr2[1])<<8) + | |
208 (((uint32_t)tmpStr2[2])<<16) + | |
209 (((uint32_t)tmpStr2[3])<<24)); | |
210 | |
211 memcpy(tmpStr, CHUNKheaderObj.fmt_ckID, 4); | |
212 } | |
213 | |
214 // Either a proper format chunk has been read or a data chunk was come | |
215 // across. | |
216 if( (_wavFormatObj.formatTag != kWavFormatPcm) && | |
217 (_wavFormatObj.formatTag != kWavFormatALaw) && | |
218 (_wavFormatObj.formatTag != kWavFormatMuLaw)) | |
219 { | |
220 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
221 "Coding formatTag value=%d not supported!", | |
222 _wavFormatObj.formatTag); | |
223 return -1; | |
224 } | |
225 if((_wavFormatObj.nChannels < 1) || | |
226 (_wavFormatObj.nChannels > 2)) | |
227 { | |
228 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
229 "nChannels value=%d not supported!", | |
230 _wavFormatObj.nChannels); | |
231 return -1; | |
232 } | |
233 | |
234 if((_wavFormatObj.nBitsPerSample != 8) && | |
235 (_wavFormatObj.nBitsPerSample != 16)) | |
236 { | |
237 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
238 "nBitsPerSample value=%d not supported!", | |
239 _wavFormatObj.nBitsPerSample); | |
240 return -1; | |
241 } | |
242 | |
243 // Calculate the number of bytes that 10 ms of audio data correspond to. | |
244 if(_wavFormatObj.formatTag == kWavFormatPcm) | |
245 { | |
246 // TODO (hellner): integer division for 22050 and 11025 would yield | |
247 // the same result as the else statement. Remove those | |
248 // special cases? | |
249 if(_wavFormatObj.nSamplesPerSec == 44100) | |
250 { | |
251 _readSizeBytes = 440 * _wavFormatObj.nChannels * | |
252 (_wavFormatObj.nBitsPerSample / 8); | |
253 } else if(_wavFormatObj.nSamplesPerSec == 22050) { | |
254 _readSizeBytes = 220 * _wavFormatObj.nChannels * | |
255 (_wavFormatObj.nBitsPerSample / 8); | |
256 } else if(_wavFormatObj.nSamplesPerSec == 11025) { | |
257 _readSizeBytes = 110 * _wavFormatObj.nChannels * | |
258 (_wavFormatObj.nBitsPerSample / 8); | |
259 } else { | |
260 _readSizeBytes = (_wavFormatObj.nSamplesPerSec/100) * | |
261 _wavFormatObj.nChannels * (_wavFormatObj.nBitsPerSample / 8); | |
262 } | |
263 | |
264 } else { | |
265 _readSizeBytes = (_wavFormatObj.nSamplesPerSec/100) * | |
266 _wavFormatObj.nChannels * (_wavFormatObj.nBitsPerSample / 8); | |
267 } | |
268 return 0; | |
269 } | |
270 | |
271 int32_t ModuleFileUtility::InitWavCodec(uint32_t samplesPerSec, | |
272 uint32_t channels, | |
273 uint32_t bitsPerSample, | |
274 uint32_t formatTag) | |
275 { | |
276 codec_info_.pltype = -1; | |
277 codec_info_.plfreq = samplesPerSec; | |
278 codec_info_.channels = channels; | |
279 codec_info_.rate = bitsPerSample * samplesPerSec; | |
280 | |
281 // Calculate the packet size for 10ms frames | |
282 switch(formatTag) | |
283 { | |
284 case kWavFormatALaw: | |
285 strcpy(codec_info_.plname, "PCMA"); | |
286 _codecId = kCodecPcma; | |
287 codec_info_.pltype = 8; | |
288 codec_info_.pacsize = codec_info_.plfreq / 100; | |
289 break; | |
290 case kWavFormatMuLaw: | |
291 strcpy(codec_info_.plname, "PCMU"); | |
292 _codecId = kCodecPcmu; | |
293 codec_info_.pltype = 0; | |
294 codec_info_.pacsize = codec_info_.plfreq / 100; | |
295 break; | |
296 case kWavFormatPcm: | |
297 codec_info_.pacsize = (bitsPerSample * (codec_info_.plfreq / 100)) / 8; | |
298 if(samplesPerSec == 8000) | |
299 { | |
300 strcpy(codec_info_.plname, "L16"); | |
301 _codecId = kCodecL16_8Khz; | |
302 } | |
303 else if(samplesPerSec == 16000) | |
304 { | |
305 strcpy(codec_info_.plname, "L16"); | |
306 _codecId = kCodecL16_16kHz; | |
307 } | |
308 else if(samplesPerSec == 32000) | |
309 { | |
310 strcpy(codec_info_.plname, "L16"); | |
311 _codecId = kCodecL16_32Khz; | |
312 } | |
313 // Set the packet size for "odd" sampling frequencies so that it | |
314 // properly corresponds to _readSizeBytes. | |
315 else if(samplesPerSec == 11025) | |
316 { | |
317 strcpy(codec_info_.plname, "L16"); | |
318 _codecId = kCodecL16_16kHz; | |
319 codec_info_.pacsize = 110; | |
320 codec_info_.plfreq = 11000; | |
321 } | |
322 else if(samplesPerSec == 22050) | |
323 { | |
324 strcpy(codec_info_.plname, "L16"); | |
325 _codecId = kCodecL16_16kHz; | |
326 codec_info_.pacsize = 220; | |
327 codec_info_.plfreq = 22000; | |
328 } | |
329 else if(samplesPerSec == 44100) | |
330 { | |
331 strcpy(codec_info_.plname, "L16"); | |
332 _codecId = kCodecL16_16kHz; | |
333 codec_info_.pacsize = 440; | |
334 codec_info_.plfreq = 44000; | |
335 } | |
336 else if(samplesPerSec == 48000) | |
337 { | |
338 strcpy(codec_info_.plname, "L16"); | |
339 _codecId = kCodecL16_16kHz; | |
340 codec_info_.pacsize = 480; | |
341 codec_info_.plfreq = 48000; | |
342 } | |
343 else | |
344 { | |
345 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
346 "Unsupported PCM frequency!"); | |
347 return -1; | |
348 } | |
349 break; | |
350 default: | |
351 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
352 "unknown WAV format TAG!"); | |
353 return -1; | |
354 break; | |
355 } | |
356 return 0; | |
357 } | |
358 | |
359 int32_t ModuleFileUtility::InitWavReading(InStream& wav, | |
360 const uint32_t start, | |
361 const uint32_t stop) | |
362 { | |
363 | |
364 _reading = false; | |
365 | |
366 if(ReadWavHeader(wav) == -1) | |
367 { | |
368 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
369 "failed to read WAV header!"); | |
370 return -1; | |
371 } | |
372 | |
373 _playoutPositionMs = 0; | |
374 _readPos = 0; | |
375 | |
376 if(start > 0) | |
377 { | |
378 uint8_t dummy[WAV_MAX_BUFFER_SIZE]; | |
379 int32_t readLength; | |
380 if(_readSizeBytes <= WAV_MAX_BUFFER_SIZE) | |
381 { | |
382 while (_playoutPositionMs < start) | |
383 { | |
384 readLength = wav.Read(dummy, _readSizeBytes); | |
385 if(readLength == _readSizeBytes) | |
386 { | |
387 _readPos += readLength; | |
388 _playoutPositionMs += 10; | |
389 } | |
390 else // Must have reached EOF before start position! | |
391 { | |
392 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
393 "InitWavReading(), EOF before start position"); | |
394 return -1; | |
395 } | |
396 } | |
397 } | |
398 else | |
399 { | |
400 return -1; | |
401 } | |
402 } | |
403 if( InitWavCodec(_wavFormatObj.nSamplesPerSec, _wavFormatObj.nChannels, | |
404 _wavFormatObj.nBitsPerSample, | |
405 _wavFormatObj.formatTag) != 0) | |
406 { | |
407 return -1; | |
408 } | |
409 _bytesPerSample = _wavFormatObj.nBitsPerSample / 8; | |
410 | |
411 | |
412 _startPointInMs = start; | |
413 _stopPointInMs = stop; | |
414 _reading = true; | |
415 return 0; | |
416 } | |
417 | |
418 int32_t ModuleFileUtility::ReadWavDataAsMono( | |
419 InStream& wav, | |
420 int8_t* outData, | |
421 const size_t bufferSize) | |
422 { | |
423 WEBRTC_TRACE( | |
424 kTraceStream, | |
425 kTraceFile, | |
426 _id, | |
427 "ModuleFileUtility::ReadWavDataAsMono(wav= 0x%x, outData= 0x%d, " | |
428 "bufSize= %" PRIuS ")", | |
429 &wav, | |
430 outData, | |
431 bufferSize); | |
432 | |
433 // The number of bytes that should be read from file. | |
434 const uint32_t totalBytesNeeded = _readSizeBytes; | |
435 // The number of bytes that will be written to outData. | |
436 const uint32_t bytesRequested = (codec_info_.channels == 2) ? | |
437 totalBytesNeeded >> 1 : totalBytesNeeded; | |
438 if(bufferSize < bytesRequested) | |
439 { | |
440 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
441 "ReadWavDataAsMono: output buffer is too short!"); | |
442 return -1; | |
443 } | |
444 if(outData == NULL) | |
445 { | |
446 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
447 "ReadWavDataAsMono: output buffer NULL!"); | |
448 return -1; | |
449 } | |
450 | |
451 if(!_reading) | |
452 { | |
453 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
454 "ReadWavDataAsMono: no longer reading file."); | |
455 return -1; | |
456 } | |
457 | |
458 int32_t bytesRead = ReadWavData( | |
459 wav, | |
460 (codec_info_.channels == 2) ? _tempData : (uint8_t*)outData, | |
461 totalBytesNeeded); | |
462 if(bytesRead == 0) | |
463 { | |
464 return 0; | |
465 } | |
466 if(bytesRead < 0) | |
467 { | |
468 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
469 "ReadWavDataAsMono: failed to read data from WAV file."); | |
470 return -1; | |
471 } | |
472 // Output data is should be mono. | |
473 if(codec_info_.channels == 2) | |
474 { | |
475 for (uint32_t i = 0; i < bytesRequested / _bytesPerSample; i++) | |
476 { | |
477 // Sample value is the average of left and right buffer rounded to | |
478 // closest integer value. Note samples can be either 1 or 2 byte. | |
479 if(_bytesPerSample == 1) | |
480 { | |
481 _tempData[i] = ((_tempData[2 * i] + _tempData[(2 * i) + 1] + | |
482 1) >> 1); | |
483 } | |
484 else | |
485 { | |
486 int16_t* sampleData = (int16_t*) _tempData; | |
487 sampleData[i] = ((sampleData[2 * i] + sampleData[(2 * i) + 1] + | |
488 1) >> 1); | |
489 } | |
490 } | |
491 memcpy(outData, _tempData, bytesRequested); | |
492 } | |
493 return bytesRequested; | |
494 } | |
495 | |
496 int32_t ModuleFileUtility::ReadWavDataAsStereo( | |
497 InStream& wav, | |
498 int8_t* outDataLeft, | |
499 int8_t* outDataRight, | |
500 const size_t bufferSize) | |
501 { | |
502 WEBRTC_TRACE( | |
503 kTraceStream, | |
504 kTraceFile, | |
505 _id, | |
506 "ModuleFileUtility::ReadWavDataAsStereo(wav= 0x%x, outLeft= 0x%x, " | |
507 "outRight= 0x%x, bufSize= %" PRIuS ")", | |
508 &wav, | |
509 outDataLeft, | |
510 outDataRight, | |
511 bufferSize); | |
512 | |
513 if((outDataLeft == NULL) || | |
514 (outDataRight == NULL)) | |
515 { | |
516 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
517 "ReadWavDataAsMono: an input buffer is NULL!"); | |
518 return -1; | |
519 } | |
520 if(codec_info_.channels != 2) | |
521 { | |
522 WEBRTC_TRACE( | |
523 kTraceError, | |
524 kTraceFile, | |
525 _id, | |
526 "ReadWavDataAsStereo: WAV file does not contain stereo data!"); | |
527 return -1; | |
528 } | |
529 if(! _reading) | |
530 { | |
531 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
532 "ReadWavDataAsStereo: no longer reading file."); | |
533 return -1; | |
534 } | |
535 | |
536 // The number of bytes that should be read from file. | |
537 const uint32_t totalBytesNeeded = _readSizeBytes; | |
538 // The number of bytes that will be written to the left and the right | |
539 // buffers. | |
540 const uint32_t bytesRequested = totalBytesNeeded >> 1; | |
541 if(bufferSize < bytesRequested) | |
542 { | |
543 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
544 "ReadWavData: Output buffers are too short!"); | |
545 assert(false); | |
546 return -1; | |
547 } | |
548 | |
549 int32_t bytesRead = ReadWavData(wav, _tempData, totalBytesNeeded); | |
550 if(bytesRead <= 0) | |
551 { | |
552 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
553 "ReadWavDataAsStereo: failed to read data from WAV file."); | |
554 return -1; | |
555 } | |
556 | |
557 // Turn interleaved audio to left and right buffer. Note samples can be | |
558 // either 1 or 2 bytes | |
559 if(_bytesPerSample == 1) | |
560 { | |
561 for (uint32_t i = 0; i < bytesRequested; i++) | |
562 { | |
563 outDataLeft[i] = _tempData[2 * i]; | |
564 outDataRight[i] = _tempData[(2 * i) + 1]; | |
565 } | |
566 } | |
567 else if(_bytesPerSample == 2) | |
568 { | |
569 int16_t* sampleData = reinterpret_cast<int16_t*>(_tempData); | |
570 int16_t* outLeft = reinterpret_cast<int16_t*>(outDataLeft); | |
571 int16_t* outRight = reinterpret_cast<int16_t*>( | |
572 outDataRight); | |
573 | |
574 // Bytes requested to samples requested. | |
575 uint32_t sampleCount = bytesRequested >> 1; | |
576 for (uint32_t i = 0; i < sampleCount; i++) | |
577 { | |
578 outLeft[i] = sampleData[2 * i]; | |
579 outRight[i] = sampleData[(2 * i) + 1]; | |
580 } | |
581 } else { | |
582 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
583 "ReadWavStereoData: unsupported sample size %d!", | |
584 _bytesPerSample); | |
585 assert(false); | |
586 return -1; | |
587 } | |
588 return bytesRequested; | |
589 } | |
590 | |
591 int32_t ModuleFileUtility::ReadWavData( | |
592 InStream& wav, | |
593 uint8_t* buffer, | |
594 const uint32_t dataLengthInBytes) | |
595 { | |
596 WEBRTC_TRACE( | |
597 kTraceStream, | |
598 kTraceFile, | |
599 _id, | |
600 "ModuleFileUtility::ReadWavData(wav= 0x%x, buffer= 0x%x, dataLen= %ld)", | |
601 &wav, | |
602 buffer, | |
603 dataLengthInBytes); | |
604 | |
605 | |
606 if(buffer == NULL) | |
607 { | |
608 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
609 "ReadWavDataAsMono: output buffer NULL!"); | |
610 return -1; | |
611 } | |
612 | |
613 // Make sure that a read won't return too few samples. | |
614 // TODO (hellner): why not read the remaining bytes needed from the start | |
615 // of the file? | |
616 if((_dataSize - _readPos) < (int32_t)dataLengthInBytes) | |
617 { | |
618 // Rewind() being -1 may be due to the file not supposed to be looped. | |
619 if(wav.Rewind() == -1) | |
620 { | |
621 _reading = false; | |
622 return 0; | |
623 } | |
624 if(InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1) | |
625 { | |
626 _reading = false; | |
627 return -1; | |
628 } | |
629 } | |
630 | |
631 int32_t bytesRead = wav.Read(buffer, dataLengthInBytes); | |
632 if(bytesRead < 0) | |
633 { | |
634 _reading = false; | |
635 return -1; | |
636 } | |
637 | |
638 // This should never happen due to earlier sanity checks. | |
639 // TODO (hellner): change to an assert and fail here since this should | |
640 // never happen... | |
641 if(bytesRead < (int32_t)dataLengthInBytes) | |
642 { | |
643 if((wav.Rewind() == -1) || | |
644 (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1)) | |
645 { | |
646 _reading = false; | |
647 return -1; | |
648 } | |
649 else | |
650 { | |
651 bytesRead = wav.Read(buffer, dataLengthInBytes); | |
652 if(bytesRead < (int32_t)dataLengthInBytes) | |
653 { | |
654 _reading = false; | |
655 return -1; | |
656 } | |
657 } | |
658 } | |
659 | |
660 _readPos += bytesRead; | |
661 | |
662 // TODO (hellner): Why is dataLengthInBytes let dictate the number of bytes | |
663 // to read when exactly 10ms should be read?! | |
664 _playoutPositionMs += 10; | |
665 if((_stopPointInMs > 0) && | |
666 (_playoutPositionMs >= _stopPointInMs)) | |
667 { | |
668 if((wav.Rewind() == -1) || | |
669 (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1)) | |
670 { | |
671 _reading = false; | |
672 } | |
673 } | |
674 return bytesRead; | |
675 } | |
676 | |
677 int32_t ModuleFileUtility::InitWavWriting(OutStream& wav, | |
678 const CodecInst& codecInst) | |
679 { | |
680 | |
681 if(set_codec_info(codecInst) != 0) | |
682 { | |
683 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
684 "codecInst identifies unsupported codec!"); | |
685 return -1; | |
686 } | |
687 _writing = false; | |
688 uint32_t channels = (codecInst.channels == 0) ? | |
689 1 : codecInst.channels; | |
690 | |
691 if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0) | |
692 { | |
693 _bytesPerSample = 1; | |
694 if(WriteWavHeader(wav, 8000, _bytesPerSample, channels, | |
695 kWavFormatMuLaw, 0) == -1) | |
696 { | |
697 return -1; | |
698 } | |
699 }else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0) | |
700 { | |
701 _bytesPerSample = 1; | |
702 if(WriteWavHeader(wav, 8000, _bytesPerSample, channels, kWavFormatALaw, | |
703 0) == -1) | |
704 { | |
705 return -1; | |
706 } | |
707 } | |
708 else if(STR_CASE_CMP(codecInst.plname, "L16") == 0) | |
709 { | |
710 _bytesPerSample = 2; | |
711 if(WriteWavHeader(wav, codecInst.plfreq, _bytesPerSample, channels, | |
712 kWavFormatPcm, 0) == -1) | |
713 { | |
714 return -1; | |
715 } | |
716 } | |
717 else | |
718 { | |
719 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
720 "codecInst identifies unsupported codec for WAV file!"); | |
721 return -1; | |
722 } | |
723 _writing = true; | |
724 _bytesWritten = 0; | |
725 return 0; | |
726 } | |
727 | |
728 int32_t ModuleFileUtility::WriteWavData(OutStream& out, | |
729 const int8_t* buffer, | |
730 const size_t dataLength) | |
731 { | |
732 WEBRTC_TRACE( | |
733 kTraceStream, | |
734 kTraceFile, | |
735 _id, | |
736 "ModuleFileUtility::WriteWavData(out= 0x%x, buf= 0x%x, dataLen= %" PRIuS | |
737 ")", | |
738 &out, | |
739 buffer, | |
740 dataLength); | |
741 | |
742 if(buffer == NULL) | |
743 { | |
744 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
745 "WriteWavData: input buffer NULL!"); | |
746 return -1; | |
747 } | |
748 | |
749 if(!out.Write(buffer, dataLength)) | |
750 { | |
751 return -1; | |
752 } | |
753 _bytesWritten += dataLength; | |
754 return static_cast<int32_t>(dataLength); | |
755 } | |
756 | |
757 | |
758 int32_t ModuleFileUtility::WriteWavHeader( | |
759 OutStream& wav, | |
760 const uint32_t freq, | |
761 const uint32_t bytesPerSample, | |
762 const uint32_t channels, | |
763 const uint32_t format, | |
764 const uint32_t lengthInBytes) | |
765 { | |
766 // Frame size in bytes for 10 ms of audio. | |
767 // TODO (hellner): 44.1 kHz has 440 samples frame size. Doesn't seem to | |
768 // be taken into consideration here! | |
769 const int32_t frameSize = (freq / 100) * channels; | |
770 | |
771 // Calculate the number of full frames that the wave file contain. | |
772 const int32_t dataLengthInBytes = frameSize * (lengthInBytes / frameSize); | |
773 | |
774 uint8_t buf[kWavHeaderSize]; | |
775 webrtc::WriteWavHeader(buf, channels, freq, static_cast<WavFormat>(format), | |
776 bytesPerSample, dataLengthInBytes / bytesPerSample); | |
777 wav.Write(buf, kWavHeaderSize); | |
778 return 0; | |
779 } | |
780 | |
781 int32_t ModuleFileUtility::UpdateWavHeader(OutStream& wav) | |
782 { | |
783 int32_t res = -1; | |
784 if(wav.Rewind() == -1) | |
785 { | |
786 return -1; | |
787 } | |
788 uint32_t channels = (codec_info_.channels == 0) ? | |
789 1 : codec_info_.channels; | |
790 | |
791 if(STR_CASE_CMP(codec_info_.plname, "L16") == 0) | |
792 { | |
793 res = WriteWavHeader(wav, codec_info_.plfreq, 2, channels, | |
794 kWavFormatPcm, _bytesWritten); | |
795 } else if(STR_CASE_CMP(codec_info_.plname, "PCMU") == 0) { | |
796 res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatMuLaw, | |
797 _bytesWritten); | |
798 } else if(STR_CASE_CMP(codec_info_.plname, "PCMA") == 0) { | |
799 res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatALaw, | |
800 _bytesWritten); | |
801 } else { | |
802 // Allow calling this API even if not writing to a WAVE file. | |
803 // TODO (hellner): why?! | |
804 return 0; | |
805 } | |
806 return res; | |
807 } | |
808 | |
809 | |
810 int32_t ModuleFileUtility::InitPreEncodedReading(InStream& in, | |
811 const CodecInst& cinst) | |
812 { | |
813 | |
814 uint8_t preEncodedID; | |
815 in.Read(&preEncodedID, 1); | |
816 | |
817 MediaFileUtility_CodecType codecType = | |
818 (MediaFileUtility_CodecType)preEncodedID; | |
819 | |
820 if(set_codec_info(cinst) != 0) | |
821 { | |
822 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
823 "Pre-encoded file send codec mismatch!"); | |
824 return -1; | |
825 } | |
826 if(codecType != _codecId) | |
827 { | |
828 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
829 "Pre-encoded file format codec mismatch!"); | |
830 return -1; | |
831 } | |
832 memcpy(&codec_info_,&cinst,sizeof(CodecInst)); | |
833 _reading = true; | |
834 return 0; | |
835 } | |
836 | |
837 int32_t ModuleFileUtility::ReadPreEncodedData( | |
838 InStream& in, | |
839 int8_t* outData, | |
840 const size_t bufferSize) | |
841 { | |
842 WEBRTC_TRACE( | |
843 kTraceStream, | |
844 kTraceFile, | |
845 _id, | |
846 "ModuleFileUtility::ReadPreEncodedData(in= 0x%x, outData= 0x%x, " | |
847 "bufferSize= %" PRIuS ")", | |
848 &in, | |
849 outData, | |
850 bufferSize); | |
851 | |
852 if(outData == NULL) | |
853 { | |
854 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "output buffer NULL"); | |
855 } | |
856 | |
857 uint32_t frameLen; | |
858 uint8_t buf[64]; | |
859 // Each frame has a two byte header containing the frame length. | |
860 int32_t res = in.Read(buf, 2); | |
861 if(res != 2) | |
862 { | |
863 if(!in.Rewind()) | |
864 { | |
865 // The first byte is the codec identifier. | |
866 in.Read(buf, 1); | |
867 res = in.Read(buf, 2); | |
868 } | |
869 else | |
870 { | |
871 return -1; | |
872 } | |
873 } | |
874 frameLen = buf[0] + buf[1] * 256; | |
875 if(bufferSize < frameLen) | |
876 { | |
877 WEBRTC_TRACE( | |
878 kTraceError, | |
879 kTraceFile, | |
880 _id, | |
881 "buffer not large enough to read %d bytes of pre-encoded data!", | |
882 frameLen); | |
883 return -1; | |
884 } | |
885 return in.Read(outData, frameLen); | |
886 } | |
887 | |
888 int32_t ModuleFileUtility::InitPreEncodedWriting( | |
889 OutStream& out, | |
890 const CodecInst& codecInst) | |
891 { | |
892 | |
893 if(set_codec_info(codecInst) != 0) | |
894 { | |
895 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "CodecInst not recognized!"); | |
896 return -1; | |
897 } | |
898 _writing = true; | |
899 _bytesWritten = 1; | |
900 out.Write(&_codecId, 1); | |
901 return 0; | |
902 } | |
903 | |
904 int32_t ModuleFileUtility::WritePreEncodedData( | |
905 OutStream& out, | |
906 const int8_t* buffer, | |
907 const size_t dataLength) | |
908 { | |
909 WEBRTC_TRACE( | |
910 kTraceStream, | |
911 kTraceFile, | |
912 _id, | |
913 "ModuleFileUtility::WritePreEncodedData(out= 0x%x, inData= 0x%x, " | |
914 "dataLen= %" PRIuS ")", | |
915 &out, | |
916 buffer, | |
917 dataLength); | |
918 | |
919 if(buffer == NULL) | |
920 { | |
921 WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL"); | |
922 } | |
923 | |
924 size_t bytesWritten = 0; | |
925 // The first two bytes is the size of the frame. | |
926 int16_t lengthBuf; | |
927 lengthBuf = (int16_t)dataLength; | |
928 if(dataLength > static_cast<size_t>(std::numeric_limits<int16_t>::max()) || | |
929 !out.Write(&lengthBuf, 2)) | |
930 { | |
931 return -1; | |
932 } | |
933 bytesWritten = 2; | |
934 | |
935 if(!out.Write(buffer, dataLength)) | |
936 { | |
937 return -1; | |
938 } | |
939 bytesWritten += dataLength; | |
940 return static_cast<int32_t>(bytesWritten); | |
941 } | |
942 | |
943 int32_t ModuleFileUtility::InitCompressedReading( | |
944 InStream& in, | |
945 const uint32_t start, | |
946 const uint32_t stop) | |
947 { | |
948 WEBRTC_TRACE( | |
949 kTraceDebug, | |
950 kTraceFile, | |
951 _id, | |
952 "ModuleFileUtility::InitCompressedReading(in= 0x%x, start= %d,\ | |
953 stop= %d)", | |
954 &in, | |
955 start, | |
956 stop); | |
957 | |
958 #if defined(WEBRTC_CODEC_ILBC) | |
959 int16_t read_len = 0; | |
960 #endif | |
961 _codecId = kCodecNoCodec; | |
962 _playoutPositionMs = 0; | |
963 _reading = false; | |
964 | |
965 _startPointInMs = start; | |
966 _stopPointInMs = stop; | |
967 | |
968 // Read the codec name | |
969 int32_t cnt = 0; | |
970 char buf[64]; | |
971 do | |
972 { | |
973 in.Read(&buf[cnt++], 1); | |
974 } while ((buf[cnt-1] != '\n') && (64 > cnt)); | |
975 | |
976 if(cnt==64) | |
977 { | |
978 return -1; | |
979 } else { | |
980 buf[cnt]=0; | |
981 } | |
982 | |
983 #ifdef WEBRTC_CODEC_ILBC | |
984 if(!strcmp("#!iLBC20\n", buf)) | |
985 { | |
986 codec_info_.pltype = 102; | |
987 strcpy(codec_info_.plname, "ilbc"); | |
988 codec_info_.plfreq = 8000; | |
989 codec_info_.pacsize = 160; | |
990 codec_info_.channels = 1; | |
991 codec_info_.rate = 13300; | |
992 _codecId = kCodecIlbc20Ms; | |
993 | |
994 if(_startPointInMs > 0) | |
995 { | |
996 while (_playoutPositionMs <= _startPointInMs) | |
997 { | |
998 read_len = in.Read(buf, 38); | |
999 if(read_len == 38) | |
1000 { | |
1001 _playoutPositionMs += 20; | |
1002 } | |
1003 else | |
1004 { | |
1005 return -1; | |
1006 } | |
1007 } | |
1008 } | |
1009 } | |
1010 | |
1011 if(!strcmp("#!iLBC30\n", buf)) | |
1012 { | |
1013 codec_info_.pltype = 102; | |
1014 strcpy(codec_info_.plname, "ilbc"); | |
1015 codec_info_.plfreq = 8000; | |
1016 codec_info_.pacsize = 240; | |
1017 codec_info_.channels = 1; | |
1018 codec_info_.rate = 13300; | |
1019 _codecId = kCodecIlbc30Ms; | |
1020 | |
1021 if(_startPointInMs > 0) | |
1022 { | |
1023 while (_playoutPositionMs <= _startPointInMs) | |
1024 { | |
1025 read_len = in.Read(buf, 50); | |
1026 if(read_len == 50) | |
1027 { | |
1028 _playoutPositionMs += 20; | |
1029 } | |
1030 else | |
1031 { | |
1032 return -1; | |
1033 } | |
1034 } | |
1035 } | |
1036 } | |
1037 #endif | |
1038 if(_codecId == kCodecNoCodec) | |
1039 { | |
1040 return -1; | |
1041 } | |
1042 _reading = true; | |
1043 return 0; | |
1044 } | |
1045 | |
1046 int32_t ModuleFileUtility::ReadCompressedData(InStream& in, | |
1047 int8_t* outData, | |
1048 size_t bufferSize) | |
1049 { | |
1050 WEBRTC_TRACE( | |
1051 kTraceStream, | |
1052 kTraceFile, | |
1053 _id, | |
1054 "ModuleFileUtility::ReadCompressedData(in=0x%x, outData=0x%x, bytes=%" | |
1055 PRIuS ")", | |
1056 &in, | |
1057 outData, | |
1058 bufferSize); | |
1059 | |
1060 uint32_t bytesRead = 0; | |
1061 | |
1062 if(! _reading) | |
1063 { | |
1064 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "not currently reading!"); | |
1065 return -1; | |
1066 } | |
1067 | |
1068 #ifdef WEBRTC_CODEC_ILBC | |
1069 if((_codecId == kCodecIlbc20Ms) || | |
1070 (_codecId == kCodecIlbc30Ms)) | |
1071 { | |
1072 uint32_t byteSize = 0; | |
1073 if(_codecId == kCodecIlbc30Ms) | |
1074 { | |
1075 byteSize = 50; | |
1076 } | |
1077 if(_codecId == kCodecIlbc20Ms) | |
1078 { | |
1079 byteSize = 38; | |
1080 } | |
1081 if(bufferSize < byteSize) | |
1082 { | |
1083 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
1084 "output buffer is too short to read ILBC compressed\ | |
1085 data."); | |
1086 assert(false); | |
1087 return -1; | |
1088 } | |
1089 | |
1090 bytesRead = in.Read(outData, byteSize); | |
1091 if(bytesRead != byteSize) | |
1092 { | |
1093 if(!in.Rewind()) | |
1094 { | |
1095 InitCompressedReading(in, _startPointInMs, _stopPointInMs); | |
1096 bytesRead = in.Read(outData, byteSize); | |
1097 if(bytesRead != byteSize) | |
1098 { | |
1099 _reading = false; | |
1100 return -1; | |
1101 } | |
1102 } | |
1103 else | |
1104 { | |
1105 _reading = false; | |
1106 return -1; | |
1107 } | |
1108 } | |
1109 } | |
1110 #endif | |
1111 if(bytesRead == 0) | |
1112 { | |
1113 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
1114 "ReadCompressedData() no bytes read, codec not supported"); | |
1115 return -1; | |
1116 } | |
1117 | |
1118 _playoutPositionMs += 20; | |
1119 if((_stopPointInMs > 0) && | |
1120 (_playoutPositionMs >= _stopPointInMs)) | |
1121 { | |
1122 if(!in.Rewind()) | |
1123 { | |
1124 InitCompressedReading(in, _startPointInMs, _stopPointInMs); | |
1125 } | |
1126 else | |
1127 { | |
1128 _reading = false; | |
1129 } | |
1130 } | |
1131 return bytesRead; | |
1132 } | |
1133 | |
1134 int32_t ModuleFileUtility::InitCompressedWriting( | |
1135 OutStream& out, | |
1136 const CodecInst& codecInst) | |
1137 { | |
1138 WEBRTC_TRACE(kTraceDebug, kTraceFile, _id, | |
1139 "ModuleFileUtility::InitCompressedWriting(out= 0x%x,\ | |
1140 codecName= %s)", | |
1141 &out, codecInst.plname); | |
1142 | |
1143 _writing = false; | |
1144 | |
1145 #ifdef WEBRTC_CODEC_ILBC | |
1146 if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0) | |
1147 { | |
1148 if(codecInst.pacsize == 160) | |
1149 { | |
1150 _codecId = kCodecIlbc20Ms; | |
1151 out.Write("#!iLBC20\n",9); | |
1152 } | |
1153 else if(codecInst.pacsize == 240) | |
1154 { | |
1155 _codecId = kCodecIlbc30Ms; | |
1156 out.Write("#!iLBC30\n",9); | |
1157 } | |
1158 else | |
1159 { | |
1160 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
1161 "codecInst defines unsupported compression codec!"); | |
1162 return -1; | |
1163 } | |
1164 memcpy(&codec_info_,&codecInst,sizeof(CodecInst)); | |
1165 _writing = true; | |
1166 return 0; | |
1167 } | |
1168 #endif | |
1169 | |
1170 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
1171 "codecInst defines unsupported compression codec!"); | |
1172 return -1; | |
1173 } | |
1174 | |
1175 int32_t ModuleFileUtility::WriteCompressedData( | |
1176 OutStream& out, | |
1177 const int8_t* buffer, | |
1178 const size_t dataLength) | |
1179 { | |
1180 WEBRTC_TRACE( | |
1181 kTraceStream, | |
1182 kTraceFile, | |
1183 _id, | |
1184 "ModuleFileUtility::WriteCompressedData(out= 0x%x, buf= 0x%x, " | |
1185 "dataLen= %" PRIuS ")", | |
1186 &out, | |
1187 buffer, | |
1188 dataLength); | |
1189 | |
1190 if(buffer == NULL) | |
1191 { | |
1192 WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL"); | |
1193 } | |
1194 | |
1195 if(!out.Write(buffer, dataLength)) | |
1196 { | |
1197 return -1; | |
1198 } | |
1199 return static_cast<int32_t>(dataLength); | |
1200 } | |
1201 | |
1202 int32_t ModuleFileUtility::InitPCMReading(InStream& pcm, | |
1203 const uint32_t start, | |
1204 const uint32_t stop, | |
1205 uint32_t freq) | |
1206 { | |
1207 WEBRTC_TRACE( | |
1208 kTraceInfo, | |
1209 kTraceFile, | |
1210 _id, | |
1211 "ModuleFileUtility::InitPCMReading(pcm= 0x%x, start=%d, stop=%d,\ | |
1212 freq=%d)", | |
1213 &pcm, | |
1214 start, | |
1215 stop, | |
1216 freq); | |
1217 | |
1218 int8_t dummy[320]; | |
1219 int32_t read_len; | |
1220 | |
1221 _playoutPositionMs = 0; | |
1222 _startPointInMs = start; | |
1223 _stopPointInMs = stop; | |
1224 _reading = false; | |
1225 | |
1226 if(freq == 8000) | |
1227 { | |
1228 strcpy(codec_info_.plname, "L16"); | |
1229 codec_info_.pltype = -1; | |
1230 codec_info_.plfreq = 8000; | |
1231 codec_info_.pacsize = 160; | |
1232 codec_info_.channels = 1; | |
1233 codec_info_.rate = 128000; | |
1234 _codecId = kCodecL16_8Khz; | |
1235 } | |
1236 else if(freq == 16000) | |
1237 { | |
1238 strcpy(codec_info_.plname, "L16"); | |
1239 codec_info_.pltype = -1; | |
1240 codec_info_.plfreq = 16000; | |
1241 codec_info_.pacsize = 320; | |
1242 codec_info_.channels = 1; | |
1243 codec_info_.rate = 256000; | |
1244 _codecId = kCodecL16_16kHz; | |
1245 } | |
1246 else if(freq == 32000) | |
1247 { | |
1248 strcpy(codec_info_.plname, "L16"); | |
1249 codec_info_.pltype = -1; | |
1250 codec_info_.plfreq = 32000; | |
1251 codec_info_.pacsize = 320; | |
1252 codec_info_.channels = 1; | |
1253 codec_info_.rate = 512000; | |
1254 _codecId = kCodecL16_32Khz; | |
1255 } | |
1256 | |
1257 // Readsize for 10ms of audio data (2 bytes per sample). | |
1258 _readSizeBytes = 2 * codec_info_. plfreq / 100; | |
1259 if(_startPointInMs > 0) | |
1260 { | |
1261 while (_playoutPositionMs < _startPointInMs) | |
1262 { | |
1263 read_len = pcm.Read(dummy, _readSizeBytes); | |
1264 if(read_len == _readSizeBytes) | |
1265 { | |
1266 _playoutPositionMs += 10; | |
1267 } | |
1268 else // Must have reached EOF before start position! | |
1269 { | |
1270 return -1; | |
1271 } | |
1272 } | |
1273 } | |
1274 _reading = true; | |
1275 return 0; | |
1276 } | |
1277 | |
1278 int32_t ModuleFileUtility::ReadPCMData(InStream& pcm, | |
1279 int8_t* outData, | |
1280 size_t bufferSize) | |
1281 { | |
1282 WEBRTC_TRACE( | |
1283 kTraceStream, | |
1284 kTraceFile, | |
1285 _id, | |
1286 "ModuleFileUtility::ReadPCMData(pcm= 0x%x, outData= 0x%x, bufSize= %" | |
1287 PRIuS ")", | |
1288 &pcm, | |
1289 outData, | |
1290 bufferSize); | |
1291 | |
1292 if(outData == NULL) | |
1293 { | |
1294 WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL"); | |
1295 } | |
1296 | |
1297 // Readsize for 10ms of audio data (2 bytes per sample). | |
1298 uint32_t bytesRequested = 2 * codec_info_.plfreq / 100; | |
1299 if(bufferSize < bytesRequested) | |
1300 { | |
1301 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
1302 "ReadPCMData: buffer not long enough for a 10ms frame."); | |
1303 assert(false); | |
1304 return -1; | |
1305 } | |
1306 | |
1307 uint32_t bytesRead = pcm.Read(outData, bytesRequested); | |
1308 if(bytesRead < bytesRequested) | |
1309 { | |
1310 if(pcm.Rewind() == -1) | |
1311 { | |
1312 _reading = false; | |
1313 } | |
1314 else | |
1315 { | |
1316 if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs, | |
1317 codec_info_.plfreq) == -1) | |
1318 { | |
1319 _reading = false; | |
1320 } | |
1321 else | |
1322 { | |
1323 int32_t rest = bytesRequested - bytesRead; | |
1324 int32_t len = pcm.Read(&(outData[bytesRead]), rest); | |
1325 if(len == rest) | |
1326 { | |
1327 bytesRead += len; | |
1328 } | |
1329 else | |
1330 { | |
1331 _reading = false; | |
1332 } | |
1333 } | |
1334 if(bytesRead <= 0) | |
1335 { | |
1336 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
1337 "ReadPCMData: Failed to rewind audio file."); | |
1338 return -1; | |
1339 } | |
1340 } | |
1341 } | |
1342 | |
1343 if(bytesRead <= 0) | |
1344 { | |
1345 WEBRTC_TRACE(kTraceStream, kTraceFile, _id, | |
1346 "ReadPCMData: end of file"); | |
1347 return -1; | |
1348 } | |
1349 _playoutPositionMs += 10; | |
1350 if(_stopPointInMs && _playoutPositionMs >= _stopPointInMs) | |
1351 { | |
1352 if(!pcm.Rewind()) | |
1353 { | |
1354 if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs, | |
1355 codec_info_.plfreq) == -1) | |
1356 { | |
1357 _reading = false; | |
1358 } | |
1359 } | |
1360 } | |
1361 return bytesRead; | |
1362 } | |
1363 | |
1364 int32_t ModuleFileUtility::InitPCMWriting(OutStream& out, uint32_t freq) | |
1365 { | |
1366 | |
1367 if(freq == 8000) | |
1368 { | |
1369 strcpy(codec_info_.plname, "L16"); | |
1370 codec_info_.pltype = -1; | |
1371 codec_info_.plfreq = 8000; | |
1372 codec_info_.pacsize = 160; | |
1373 codec_info_.channels = 1; | |
1374 codec_info_.rate = 128000; | |
1375 | |
1376 _codecId = kCodecL16_8Khz; | |
1377 } | |
1378 else if(freq == 16000) | |
1379 { | |
1380 strcpy(codec_info_.plname, "L16"); | |
1381 codec_info_.pltype = -1; | |
1382 codec_info_.plfreq = 16000; | |
1383 codec_info_.pacsize = 320; | |
1384 codec_info_.channels = 1; | |
1385 codec_info_.rate = 256000; | |
1386 | |
1387 _codecId = kCodecL16_16kHz; | |
1388 } | |
1389 else if(freq == 32000) | |
1390 { | |
1391 strcpy(codec_info_.plname, "L16"); | |
1392 codec_info_.pltype = -1; | |
1393 codec_info_.plfreq = 32000; | |
1394 codec_info_.pacsize = 320; | |
1395 codec_info_.channels = 1; | |
1396 codec_info_.rate = 512000; | |
1397 | |
1398 _codecId = kCodecL16_32Khz; | |
1399 } | |
1400 if((_codecId != kCodecL16_8Khz) && | |
1401 (_codecId != kCodecL16_16kHz) && | |
1402 (_codecId != kCodecL16_32Khz)) | |
1403 { | |
1404 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
1405 "CodecInst is not 8KHz PCM or 16KHz PCM!"); | |
1406 return -1; | |
1407 } | |
1408 _writing = true; | |
1409 _bytesWritten = 0; | |
1410 return 0; | |
1411 } | |
1412 | |
1413 int32_t ModuleFileUtility::WritePCMData(OutStream& out, | |
1414 const int8_t* buffer, | |
1415 const size_t dataLength) | |
1416 { | |
1417 WEBRTC_TRACE( | |
1418 kTraceStream, | |
1419 kTraceFile, | |
1420 _id, | |
1421 "ModuleFileUtility::WritePCMData(out= 0x%x, buf= 0x%x, dataLen= %" PRIuS | |
1422 ")", | |
1423 &out, | |
1424 buffer, | |
1425 dataLength); | |
1426 | |
1427 if(buffer == NULL) | |
1428 { | |
1429 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "buffer NULL"); | |
1430 } | |
1431 | |
1432 if(!out.Write(buffer, dataLength)) | |
1433 { | |
1434 return -1; | |
1435 } | |
1436 | |
1437 _bytesWritten += dataLength; | |
1438 return static_cast<int32_t>(dataLength); | |
1439 } | |
1440 | |
1441 int32_t ModuleFileUtility::codec_info(CodecInst& codecInst) | |
1442 { | |
1443 WEBRTC_TRACE(kTraceStream, kTraceFile, _id, | |
1444 "ModuleFileUtility::codec_info(codecInst= 0x%x)", &codecInst); | |
1445 | |
1446 if(!_reading && !_writing) | |
1447 { | |
1448 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
1449 "CodecInst: not currently reading audio file!"); | |
1450 return -1; | |
1451 } | |
1452 memcpy(&codecInst,&codec_info_,sizeof(CodecInst)); | |
1453 return 0; | |
1454 } | |
1455 | |
1456 int32_t ModuleFileUtility::set_codec_info(const CodecInst& codecInst) | |
1457 { | |
1458 | |
1459 _codecId = kCodecNoCodec; | |
1460 if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0) | |
1461 { | |
1462 _codecId = kCodecPcmu; | |
1463 } | |
1464 else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0) | |
1465 { | |
1466 _codecId = kCodecPcma; | |
1467 } | |
1468 else if(STR_CASE_CMP(codecInst.plname, "L16") == 0) | |
1469 { | |
1470 if(codecInst.plfreq == 8000) | |
1471 { | |
1472 _codecId = kCodecL16_8Khz; | |
1473 } | |
1474 else if(codecInst.plfreq == 16000) | |
1475 { | |
1476 _codecId = kCodecL16_16kHz; | |
1477 } | |
1478 else if(codecInst.plfreq == 32000) | |
1479 { | |
1480 _codecId = kCodecL16_32Khz; | |
1481 } | |
1482 } | |
1483 #ifdef WEBRTC_CODEC_ILBC | |
1484 else if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0) | |
1485 { | |
1486 if(codecInst.pacsize == 160) | |
1487 { | |
1488 _codecId = kCodecIlbc20Ms; | |
1489 } | |
1490 else if(codecInst.pacsize == 240) | |
1491 { | |
1492 _codecId = kCodecIlbc30Ms; | |
1493 } | |
1494 } | |
1495 #endif | |
1496 #if(defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) | |
1497 else if(STR_CASE_CMP(codecInst.plname, "isac") == 0) | |
1498 { | |
1499 if(codecInst.plfreq == 16000) | |
1500 { | |
1501 _codecId = kCodecIsac; | |
1502 } | |
1503 else if(codecInst.plfreq == 32000) | |
1504 { | |
1505 _codecId = kCodecIsacSwb; | |
1506 } | |
1507 } | |
1508 #endif | |
1509 #ifdef WEBRTC_CODEC_G722 | |
1510 else if(STR_CASE_CMP(codecInst.plname, "G722") == 0) | |
1511 { | |
1512 _codecId = kCodecG722; | |
1513 } | |
1514 #endif | |
1515 if(_codecId == kCodecNoCodec) | |
1516 { | |
1517 return -1; | |
1518 } | |
1519 memcpy(&codec_info_, &codecInst, sizeof(CodecInst)); | |
1520 return 0; | |
1521 } | |
1522 | |
1523 int32_t ModuleFileUtility::FileDurationMs(const char* fileName, | |
1524 const FileFormats fileFormat, | |
1525 const uint32_t freqInHz) | |
1526 { | |
1527 | |
1528 if(fileName == NULL) | |
1529 { | |
1530 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "filename NULL"); | |
1531 return -1; | |
1532 } | |
1533 | |
1534 int32_t time_in_ms = -1; | |
1535 struct stat file_size; | |
1536 if(stat(fileName,&file_size) == -1) | |
1537 { | |
1538 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
1539 "failed to retrieve file size with stat!"); | |
1540 return -1; | |
1541 } | |
1542 FileWrapper* inStreamObj = FileWrapper::Create(); | |
1543 if(inStreamObj == NULL) | |
1544 { | |
1545 WEBRTC_TRACE(kTraceMemory, kTraceFile, _id, | |
1546 "failed to create InStream object!"); | |
1547 return -1; | |
1548 } | |
1549 if(inStreamObj->OpenFile(fileName, true) == -1) | |
1550 { | |
1551 delete inStreamObj; | |
1552 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
1553 "failed to open file %s!", fileName); | |
1554 return -1; | |
1555 } | |
1556 | |
1557 switch (fileFormat) | |
1558 { | |
1559 case kFileFormatWavFile: | |
1560 { | |
1561 if(ReadWavHeader(*inStreamObj) == -1) | |
1562 { | |
1563 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
1564 "failed to read WAV file header!"); | |
1565 return -1; | |
1566 } | |
1567 time_in_ms = ((file_size.st_size - 44) / | |
1568 (_wavFormatObj.nAvgBytesPerSec/1000)); | |
1569 break; | |
1570 } | |
1571 case kFileFormatPcm16kHzFile: | |
1572 { | |
1573 // 16 samples per ms. 2 bytes per sample. | |
1574 int32_t denominator = 16*2; | |
1575 time_in_ms = (file_size.st_size)/denominator; | |
1576 break; | |
1577 } | |
1578 case kFileFormatPcm8kHzFile: | |
1579 { | |
1580 // 8 samples per ms. 2 bytes per sample. | |
1581 int32_t denominator = 8*2; | |
1582 time_in_ms = (file_size.st_size)/denominator; | |
1583 break; | |
1584 } | |
1585 case kFileFormatCompressedFile: | |
1586 { | |
1587 int32_t cnt = 0; | |
1588 int32_t read_len = 0; | |
1589 char buf[64]; | |
1590 do | |
1591 { | |
1592 read_len = inStreamObj->Read(&buf[cnt++], 1); | |
1593 if(read_len != 1) | |
1594 { | |
1595 return -1; | |
1596 } | |
1597 } while ((buf[cnt-1] != '\n') && (64 > cnt)); | |
1598 | |
1599 if(cnt == 64) | |
1600 { | |
1601 return -1; | |
1602 } | |
1603 else | |
1604 { | |
1605 buf[cnt] = 0; | |
1606 } | |
1607 #ifdef WEBRTC_CODEC_ILBC | |
1608 if(!strcmp("#!iLBC20\n", buf)) | |
1609 { | |
1610 // 20 ms is 304 bits | |
1611 time_in_ms = ((file_size.st_size)*160)/304; | |
1612 break; | |
1613 } | |
1614 if(!strcmp("#!iLBC30\n", buf)) | |
1615 { | |
1616 // 30 ms takes 400 bits. | |
1617 // file size in bytes * 8 / 400 is the number of | |
1618 // 30 ms frames in the file -> | |
1619 // time_in_ms = file size * 8 / 400 * 30 | |
1620 time_in_ms = ((file_size.st_size)*240)/400; | |
1621 break; | |
1622 } | |
1623 #endif | |
1624 break; | |
1625 } | |
1626 case kFileFormatPreencodedFile: | |
1627 { | |
1628 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
1629 "cannot determine duration of Pre-Encoded file!"); | |
1630 break; | |
1631 } | |
1632 default: | |
1633 WEBRTC_TRACE(kTraceError, kTraceFile, _id, | |
1634 "unsupported file format %d!", fileFormat); | |
1635 break; | |
1636 } | |
1637 inStreamObj->CloseFile(); | |
1638 delete inStreamObj; | |
1639 return time_in_ms; | |
1640 } | |
1641 | |
1642 uint32_t ModuleFileUtility::PlayoutPositionMs() | |
1643 { | |
1644 WEBRTC_TRACE(kTraceStream, kTraceFile, _id, | |
1645 "ModuleFileUtility::PlayoutPosition()"); | |
1646 | |
1647 if(_reading) | |
1648 { | |
1649 return _playoutPositionMs; | |
1650 } | |
1651 else | |
1652 { | |
1653 return 0; | |
1654 } | |
1655 } | |
1656 } // namespace webrtc | |
OLD | NEW |