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