| 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 |