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 17 #include "webrtc/common_audio/wav_header.h" 18 #include "webrtc/common_types.h" 19 #include "webrtc/engine_configurations.h" 20 #include "webrtc/modules/interface/module_common_types.h" 21 #include "webrtc/system_wrappers/interface/file_wrapper.h" 22 #include "webrtc/system_wrappers/interface/trace.h" 23 24 #ifdef WEBRTC_MODULE_UTILITY_VIDEO 25 #include "avi_file.h" 26 #endif 27 28 namespace { 29 30 // First 16 bytes the WAVE header. ckID should be "RIFF", wave_ckID should be 31 // "WAVE" and ckSize is the chunk size (4 + n) 32 struct WAVE_RIFF_header 33 { 34 int8_t ckID[4]; 35 int32_t ckSize; 36 int8_t wave_ckID[4]; 37 }; 38 39 // First 8 byte of the format chunk. fmt_ckID should be "fmt ". fmt_ckSize is 40 // the chunk size (16, 18 or 40 byte) 41 struct WAVE_CHUNK_header 42 { 43 int8_t fmt_ckID[4]; 44 int32_t fmt_ckSize; 45 }; 46 } // unnamed namespace 47 48 namespace webrtc { 49 ModuleFileUtility::ModuleFileUtility(const int32_t id) 50 : _wavFormatObj(), 51 _dataSize(0), 52 _readSizeBytes(0), 53 _id(id), 54 _stopPointInMs(0), 55 _startPointInMs(0), 56 _playoutPositionMs(0), 57 _bytesWritten(0), 58 codec_info_(), 59 _codecId(kCodecNoCodec), 60 _bytesPerSample(0), 61 _readPos(0), 62 _reading(false), 63 _writing(false), 64 _tempData() 65 #ifdef WEBRTC_MODULE_UTILITY_VIDEO 66 , 67 _aviAudioInFile(0), 68 _aviVideoInFile(0), 69 _aviOutFile(0) 70 #endif 71 { 72 WEBRTC_TRACE(kTraceMemory, kTraceFile, _id, 73 "ModuleFileUtility::ModuleFileUtility()"); 74 memset(&codec_info_,0,sizeof(CodecInst)); 75 codec_info_.pltype = -1; 76 #ifdef WEBRTC_MODULE_UTILITY_VIDEO 77 memset(&_videoCodec,0,sizeof(_videoCodec)); 78 #endif 79 } 80 81 ModuleFileUtility::~ModuleFileUtility() 82 { 83 WEBRTC_TRACE(kTraceMemory, kTraceFile, _id, 84 "ModuleFileUtility::~ModuleFileUtility()"); 85 #ifdef WEBRTC_MODULE_UTILITY_VIDEO 86 delete _aviAudioInFile; 87 delete _aviVideoInFile; 88 #endif 89 } 90 91 #ifdef WEBRTC_MODULE_UTILITY_VIDEO 92 int32_t ModuleFileUtility::InitAviWriting( 93 const char* filename, 94 const CodecInst& audioCodecInst, 95 const VideoCodec& videoCodecInst, 96 const bool videoOnly /*= false*/) 97 { 98 _writing = false; 99 100 delete _aviOutFile; 101 _aviOutFile = new AviFile( ); 102 103 AVISTREAMHEADER videoStreamHeader; 104 videoStreamHeader.fccType = AviFile::MakeFourCc('v', 'i', 'd', 's'); 105 106 #ifdef VIDEOCODEC_I420 107 if (strncmp(videoCodecInst.plName, "I420", 7) == 0) 108 { 109 videoStreamHeader.fccHandler = AviFile::MakeFourCc('I','4','2','0'); 110 } 111 #endif 112 #ifdef VIDEOCODEC_VP8 113 if (strncmp(videoCodecInst.plName, "VP8", 7) == 0) 114 { 115 videoStreamHeader.fccHandler = AviFile::MakeFourCc('V','P','8','0'); 116 } 117 #endif 118 if (videoStreamHeader.fccHandler == 0) 119 { 120 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 121 "InitAviWriting() Codec not supported"); 122 123 return -1; 124 } 125 videoStreamHeader.dwScale = 1; 126 videoStreamHeader.dwRate = videoCodecInst.maxFramerate; 127 videoStreamHeader.dwSuggestedBufferSize = videoCodecInst.height * 128 (videoCodecInst.width >> 1) * 3; 129 videoStreamHeader.dwQuality = (uint32_t)-1; 130 videoStreamHeader.dwSampleSize = 0; 131 videoStreamHeader.rcFrame.top = 0; 132 videoStreamHeader.rcFrame.bottom = videoCodecInst.height; 133 videoStreamHeader.rcFrame.left = 0; 134 videoStreamHeader.rcFrame.right = videoCodecInst.width; 135 136 BITMAPINFOHEADER bitMapInfoHeader; 137 bitMapInfoHeader.biSize = sizeof(BITMAPINFOHEADER); 138 bitMapInfoHeader.biHeight = videoCodecInst.height; 139 bitMapInfoHeader.biWidth = videoCodecInst.width; 140 bitMapInfoHeader.biPlanes = 1; 141 bitMapInfoHeader.biBitCount = 12; 142 bitMapInfoHeader.biClrImportant = 0; 143 bitMapInfoHeader.biClrUsed = 0; 144 bitMapInfoHeader.biCompression = videoStreamHeader.fccHandler; 145 bitMapInfoHeader.biSizeImage = bitMapInfoHeader.biWidth * 146 bitMapInfoHeader.biHeight * bitMapInfoHeader.biBitCount / 8; 147 148 if (_aviOutFile->CreateVideoStream( 149 videoStreamHeader, 150 bitMapInfoHeader, 151 NULL, 152 0) != 0) 153 { 154 return -1; 155 } 156 157 if(!videoOnly) 158 { 159 AVISTREAMHEADER audioStreamHeader; 160 audioStreamHeader.fccType = AviFile::MakeFourCc('a', 'u', 'd', 's'); 161 // fccHandler is the FOURCC of the codec for decoding the stream. 162 // It's an optional parameter that is not used by audio streams. 163 audioStreamHeader.fccHandler = 0; 164 audioStreamHeader.dwScale = 1; 165 166 WAVEFORMATEX waveFormatHeader; 167 waveFormatHeader.cbSize = 0; 168 waveFormatHeader.nChannels = 1; 169 170 if (strncmp(audioCodecInst.plname, "PCMU", 4) == 0) 171 { 172 audioStreamHeader.dwSampleSize = 1; 173 audioStreamHeader.dwRate = 8000; 174 audioStreamHeader.dwQuality = (uint32_t)-1; 175 audioStreamHeader.dwSuggestedBufferSize = 80; 176 177 waveFormatHeader.nAvgBytesPerSec = 8000; 178 waveFormatHeader.nSamplesPerSec = 8000; 179 waveFormatHeader.wBitsPerSample = 8; 180 waveFormatHeader.nBlockAlign = 1; 181 waveFormatHeader.wFormatTag = kWavFormatMuLaw; 182 183 } else if (strncmp(audioCodecInst.plname, "PCMA", 4) == 0) 184 { 185 audioStreamHeader.dwSampleSize = 1; 186 audioStreamHeader.dwRate = 8000; 187 audioStreamHeader.dwQuality = (uint32_t)-1; 188 audioStreamHeader.dwSuggestedBufferSize = 80; 189 190 waveFormatHeader.nAvgBytesPerSec = 8000; 191 waveFormatHeader.nSamplesPerSec = 8000; 192 waveFormatHeader.wBitsPerSample = 8; 193 waveFormatHeader.nBlockAlign = 1; 194 waveFormatHeader.wFormatTag = kWavFormatALaw; 195 196 } else if (strncmp(audioCodecInst.plname, "L16", 3) == 0) 197 { 198 audioStreamHeader.dwSampleSize = 2; 199 audioStreamHeader.dwRate = audioCodecInst.plfreq; 200 audioStreamHeader.dwQuality = (uint32_t)-1; 201 audioStreamHeader.dwSuggestedBufferSize = 202 (audioCodecInst.plfreq/100) * 2; 203 204 waveFormatHeader.nAvgBytesPerSec = audioCodecInst.plfreq * 2; 205 waveFormatHeader.nSamplesPerSec = audioCodecInst.plfreq; 206 waveFormatHeader.wBitsPerSample = 16; 207 waveFormatHeader.nBlockAlign = 2; 208 waveFormatHeader.wFormatTag = kWavFormatPcm; 209 } else 210 { 211 return -1; 212 } 213 214 if(_aviOutFile->CreateAudioStream( 215 audioStreamHeader, 216 waveFormatHeader) != 0) 217 { 218 return -1; 219 } 220 221 222 if( InitWavCodec(waveFormatHeader.nSamplesPerSec, 223 waveFormatHeader.nChannels, 224 waveFormatHeader.wBitsPerSample, 225 waveFormatHeader.wFormatTag) != 0) 226 { 227 return -1; 228 } 229 } 230 _aviOutFile->Create(filename); 231 _writing = true; 232 return 0; 233 } 234 235 int32_t ModuleFileUtility::WriteAviAudioData( 236 const int8_t* buffer, 237 uint32_t bufferLengthInBytes) 238 { 239 if( _aviOutFile != 0) 240 { 241 return _aviOutFile->WriteAudio( 242 reinterpret_cast<const uint8_t*>(buffer), 243 bufferLengthInBytes); 244 } 245 else 246 { 247 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "AVI file not initialized"); 248 return -1; 249 } 250 } 251 252 int32_t ModuleFileUtility::WriteAviVideoData( 253 const int8_t* buffer, 254 uint32_t bufferLengthInBytes) 255 { 256 if( _aviOutFile != 0) 257 { 258 return _aviOutFile->WriteVideo( 259 reinterpret_cast<const uint8_t*>(buffer), 260 bufferLengthInBytes); 261 } 262 else 263 { 264 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "AVI file not initialized"); 265 return -1; 266 } 267 } 268 269 270 int32_t ModuleFileUtility::CloseAviFile( ) 271 { 272 if( _reading && _aviAudioInFile) 273 { 274 delete _aviAudioInFile; 275 _aviAudioInFile = 0; 276 } 277 278 if( _reading && _aviVideoInFile) 279 { 280 delete _aviVideoInFile; 281 _aviVideoInFile = 0; 282 } 283 284 if( _writing && _aviOutFile) 285 { 286 delete _aviOutFile; 287 _aviOutFile = 0; 288 } 289 return 0; 290 } 291 292 293 int32_t ModuleFileUtility::InitAviReading(const char* filename, bool videoOnly, 294 bool loop) 295 { 296 _reading = false; 297 delete _aviVideoInFile; 298 _aviVideoInFile = new AviFile( ); 299 300 if ((_aviVideoInFile != 0) && _aviVideoInFile->Open(AviFile::AVI_VIDEO, 301 filename, loop) == -1) 302 { 303 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, 304 "Unable to open AVI file (video)"); 305 return -1; 306 } 307 308 309 AVISTREAMHEADER videoInStreamHeader; 310 BITMAPINFOHEADER bitmapInfo; 311 char codecConfigParameters[AviFile::CODEC_CONFIG_LENGTH] = {}; 312 int32_t configLength = 0; 313 if( _aviVideoInFile->GetVideoStreamInfo(videoInStreamHeader, bitmapInfo, 314 codecConfigParameters, 315 configLength) != 0) 316 { 317 return -1; 318 } 319 _videoCodec.width = static_cast<uint16_t>( 320 videoInStreamHeader.rcFrame.right); 321 _videoCodec.height = static_cast<uint16_t>( 322 videoInStreamHeader.rcFrame.bottom); 323 _videoCodec.maxFramerate = static_cast<uint8_t>( 324 videoInStreamHeader.dwRate); 325 326 const size_t plnameLen = sizeof(_videoCodec.plName) / sizeof(char); 327 if (bitmapInfo.biCompression == AviFile::MakeFourCc('I','4','2','0')) 328 { 329 strncpy(_videoCodec.plName, "I420", plnameLen); 330 _videoCodec.codecType = kVideoCodecI420; 331 } 332 else if (bitmapInfo.biCompression == 333 AviFile::MakeFourCc('V', 'P', '8', '0')) 334 { 335 strncpy(_videoCodec.plName, "VP8", plnameLen); 336 _videoCodec.codecType = kVideoCodecVP8; 337 } 338 else 339 { 340 return -1; 341 } 342 343 if(!videoOnly) 344 { 345 delete _aviAudioInFile; 346 _aviAudioInFile = new AviFile(); 347 348 if ( (_aviAudioInFile != 0) && 349 _aviAudioInFile->Open(AviFile::AVI_AUDIO, filename, loop) == -1) 350 { 351 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, 352 "Unable to open AVI file (audio)"); 353 return -1; 354 } 355 356 WAVEFORMATEX waveHeader; 357 if(_aviAudioInFile->GetAudioStreamInfo(waveHeader) != 0) 358 { 359 return -1; 360 } 361 if(InitWavCodec(waveHeader.nSamplesPerSec, waveHeader.nChannels, 362 waveHeader.wBitsPerSample, waveHeader.wFormatTag) != 0) 363 { 364 return -1; 365 } 366 } 367 _reading = true; 368 return 0; 369 } 370 371 int32_t ModuleFileUtility::ReadAviAudioData( 372 int8_t* outBuffer, 373 const uint32_t bufferLengthInBytes) 374 { 375 if(_aviAudioInFile == 0) 376 { 377 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "AVI file not opened."); 378 return -1; 379 } 380 381 int32_t length = bufferLengthInBytes; 382 if(_aviAudioInFile->ReadAudio( 383 reinterpret_cast<uint8_t*>(outBuffer), 384 length) != 0) 385 { 386 return -1; 387 } 388 else 389 { 390 return length; 391 } 392 } 393 394 int32_t ModuleFileUtility::ReadAviVideoData( 395 int8_t* outBuffer, 396 const uint32_t bufferLengthInBytes) 397 { 398 if(_aviVideoInFile == 0) 399 { 400 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "AVI file not opened."); 401 return -1; 402 } 403 404 int32_t length = bufferLengthInBytes; 405 if( _aviVideoInFile->ReadVideo( 406 reinterpret_cast<uint8_t*>(outBuffer), 407 length) != 0) 408 { 409 return -1; 410 } else { 411 return length; 412 } 413 } 414 415 int32_t ModuleFileUtility::VideoCodecInst(VideoCodec& codecInst) 416 { 417 WEBRTC_TRACE(kTraceStream, kTraceFile, _id, 418 "ModuleFileUtility::CodecInst(codecInst= 0x%x)", &codecInst); 419 420 if(!_reading) 421 { 422 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 423 "CodecInst: not currently reading audio file!"); 424 return -1; 425 } 426 memcpy(&codecInst,&_videoCodec,sizeof(VideoCodec)); 427 return 0; 428 } 429 #endif 430 431 int32_t ModuleFileUtility::ReadWavHeader(InStream& wav) 432 { 433 WAVE_RIFF_header RIFFheaderObj; 434 WAVE_CHUNK_header CHUNKheaderObj; 435 // TODO (hellner): tmpStr and tmpStr2 seems unnecessary here. 436 char tmpStr[6] = "FOUR"; 437 unsigned char tmpStr2[4]; 438 int32_t i, len; 439 bool dataFound = false; 440 bool fmtFound = false; 441 int8_t dummyRead; 442 443 444 _dataSize = 0; 445 len = wav.Read(&RIFFheaderObj, sizeof(WAVE_RIFF_header)); 446 if(len != sizeof(WAVE_RIFF_header)) 447 { 448 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 449 "Not a wave file (too short)"); 450 return -1; 451 } 452 453 for (i = 0; i < 4; i++) 454 { 455 tmpStr[i] = RIFFheaderObj.ckID[i]; 456 } 457 if(strcmp(tmpStr, "RIFF") != 0) 458 { 459 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 460 "Not a wave file (does not have RIFF)"); 461 return -1; 462 } 463 for (i = 0; i < 4; i++) 464 { 465 tmpStr[i] = RIFFheaderObj.wave_ckID[i]; 466 } 467 if(strcmp(tmpStr, "WAVE") != 0) 468 { 469 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 470 "Not a wave file (does not have WAVE)"); 471 return -1; 472 } 473 474 len = wav.Read(&CHUNKheaderObj, sizeof(WAVE_CHUNK_header)); 475 476 // WAVE files are stored in little endian byte order. Make sure that the 477 // data can be read on big endian as well. 478 // TODO (hellner): little endian to system byte order should be done in 479 // in a subroutine. 480 memcpy(tmpStr2, &CHUNKheaderObj.fmt_ckSize, 4); 481 CHUNKheaderObj.fmt_ckSize = 482 (int32_t) ((uint32_t) tmpStr2[0] + 483 (((uint32_t)tmpStr2[1])<<8) + 484 (((uint32_t)tmpStr2[2])<<16) + 485 (((uint32_t)tmpStr2[3])<<24)); 486 487 memcpy(tmpStr, CHUNKheaderObj.fmt_ckID, 4); 488 489 while ((len == sizeof(WAVE_CHUNK_header)) && (!fmtFound || !dataFound)) 490 { 491 if(strcmp(tmpStr, "fmt ") == 0) 492 { 493 len = wav.Read(&_wavFormatObj, sizeof(WAVE_FMTINFO_header)); 494 495 memcpy(tmpStr2, &_wavFormatObj.formatTag, 2); 496 _wavFormatObj.formatTag = 497 (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1])<<8); 498 memcpy(tmpStr2, &_wavFormatObj.nChannels, 2); 499 _wavFormatObj.nChannels = 500 (int16_t) ((uint32_t)tmpStr2[0] + 501 (((uint32_t)tmpStr2[1])<<8)); 502 memcpy(tmpStr2, &_wavFormatObj.nSamplesPerSec, 4); 503 _wavFormatObj.nSamplesPerSec = 504 (int32_t) ((uint32_t)tmpStr2[0] + 505 (((uint32_t)tmpStr2[1])<<8) + 506 (((uint32_t)tmpStr2[2])<<16) + 507 (((uint32_t)tmpStr2[3])<<24)); 508 memcpy(tmpStr2, &_wavFormatObj.nAvgBytesPerSec, 4); 509 _wavFormatObj.nAvgBytesPerSec = 510 (int32_t) ((uint32_t)tmpStr2[0] + 511 (((uint32_t)tmpStr2[1])<<8) + 512 (((uint32_t)tmpStr2[2])<<16) + 513 (((uint32_t)tmpStr2[3])<<24)); 514 memcpy(tmpStr2, &_wavFormatObj.nBlockAlign, 2); 515 _wavFormatObj.nBlockAlign = 516 (int16_t) ((uint32_t)tmpStr2[0] + 517 (((uint32_t)tmpStr2[1])<<8)); 518 memcpy(tmpStr2, &_wavFormatObj.nBitsPerSample, 2); 519 _wavFormatObj.nBitsPerSample = 520 (int16_t) ((uint32_t)tmpStr2[0] + 521 (((uint32_t)tmpStr2[1])<<8)); 522 523 for (i = 0; 524 i < (CHUNKheaderObj.fmt_ckSize - 525 (int32_t)sizeof(WAVE_FMTINFO_header)); 526 i++) 527 { 528 len = wav.Read(&dummyRead, 1); 529 if(len != 1) 530 { 531 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 532 "File corrupted, reached EOF (reading fmt)"); 533 return -1; 534 } 535 } 536 fmtFound = true; 537 } 538 else if(strcmp(tmpStr, "data") == 0) 539 { 540 _dataSize = CHUNKheaderObj.fmt_ckSize; 541 dataFound = true; 542 break; 543 } 544 else 545 { 546 for (i = 0; i < (CHUNKheaderObj.fmt_ckSize); i++) 547 { 548 len = wav.Read(&dummyRead, 1); 549 if(len != 1) 550 { 551 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 552 "File corrupted, reached EOF (reading other)"); 553 return -1; 554 } 555 } 556 } 557 558 len = wav.Read(&CHUNKheaderObj, sizeof(WAVE_CHUNK_header)); 559 560 memcpy(tmpStr2, &CHUNKheaderObj.fmt_ckSize, 4); 561 CHUNKheaderObj.fmt_ckSize = 562 (int32_t) ((uint32_t)tmpStr2[0] + 563 (((uint32_t)tmpStr2[1])<<8) + 564 (((uint32_t)tmpStr2[2])<<16) + 565 (((uint32_t)tmpStr2[3])<<24)); 566 567 memcpy(tmpStr, CHUNKheaderObj.fmt_ckID, 4); 568 } 569 570 // Either a proper format chunk has been read or a data chunk was come 571 // across. 572 if( (_wavFormatObj.formatTag != kWavFormatPcm) && 573 (_wavFormatObj.formatTag != kWavFormatALaw) && 574 (_wavFormatObj.formatTag != kWavFormatMuLaw)) 575 { 576 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 577 "Coding formatTag value=%d not supported!", 578 _wavFormatObj.formatTag); 579 return -1; 580 } 581 if((_wavFormatObj.nChannels < 1) || 582 (_wavFormatObj.nChannels > 2)) 583 { 584 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 585 "nChannels value=%d not supported!", 586 _wavFormatObj.nChannels); 587 return -1; 588 } 589 590 if((_wavFormatObj.nBitsPerSample != 8) && 591 (_wavFormatObj.nBitsPerSample != 16)) 592 { 593 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 594 "nBitsPerSample value=%d not supported!", 595 _wavFormatObj.nBitsPerSample); 596 return -1; 597 } 598 599 // Calculate the number of bytes that 10 ms of audio data correspond to. 600 if(_wavFormatObj.formatTag == kWavFormatPcm) 601 { 602 // TODO (hellner): integer division for 22050 and 11025 would yield 603 // the same result as the else statement. Remove those 604 // special cases? 605 if(_wavFormatObj.nSamplesPerSec == 44100) 606 { 607 _readSizeBytes = 440 * _wavFormatObj.nChannels * 608 (_wavFormatObj.nBitsPerSample / 8); 609 } else if(_wavFormatObj.nSamplesPerSec == 22050) { 610 _readSizeBytes = 220 * _wavFormatObj.nChannels * 611 (_wavFormatObj.nBitsPerSample / 8); 612 } else if(_wavFormatObj.nSamplesPerSec == 11025) { 613 _readSizeBytes = 110 * _wavFormatObj.nChannels * 614 (_wavFormatObj.nBitsPerSample / 8); 615 } else { 616 _readSizeBytes = (_wavFormatObj.nSamplesPerSec/100) * 617 _wavFormatObj.nChannels * (_wavFormatObj.nBitsPerSample / 8); 618 } 619 620 } else { 621 _readSizeBytes = (_wavFormatObj.nSamplesPerSec/100) * 622 _wavFormatObj.nChannels * (_wavFormatObj.nBitsPerSample / 8); 623 } 624 return 0; 625 } 626 627 int32_t ModuleFileUtility::InitWavCodec(uint32_t samplesPerSec, 628 uint32_t channels, 629 uint32_t bitsPerSample, 630 uint32_t formatTag) 631 { 632 codec_info_.pltype = -1; 633 codec_info_.plfreq = samplesPerSec; 634 codec_info_.channels = channels; 635 codec_info_.rate = bitsPerSample * samplesPerSec; 636 637 // Calculate the packet size for 10ms frames 638 switch(formatTag) 639 { 640 case kWavFormatALaw: 641 strcpy(codec_info_.plname, "PCMA"); 642 _codecId = kCodecPcma; 643 codec_info_.pltype = 8; 644 codec_info_.pacsize = codec_info_.plfreq / 100; 645 break; 646 case kWavFormatMuLaw: 647 strcpy(codec_info_.plname, "PCMU"); 648 _codecId = kCodecPcmu; 649 codec_info_.pltype = 0; 650 codec_info_.pacsize = codec_info_.plfreq / 100; 651 break; 652 case kWavFormatPcm: 653 codec_info_.pacsize = (bitsPerSample * (codec_info_.plfreq / 100)) / 8; 654 if(samplesPerSec == 8000) 655 { 656 strcpy(codec_info_.plname, "L16"); 657 _codecId = kCodecL16_8Khz; 658 } 659 else if(samplesPerSec == 16000) 660 { 661 strcpy(codec_info_.plname, "L16"); 662 _codecId = kCodecL16_16kHz; 663 } 664 else if(samplesPerSec == 32000) 665 { 666 strcpy(codec_info_.plname, "L16"); 667 _codecId = kCodecL16_32Khz; 668 } 669 // Set the packet size for "odd" sampling frequencies so that it 670 // properly corresponds to _readSizeBytes. 671 else if(samplesPerSec == 11025) 672 { 673 strcpy(codec_info_.plname, "L16"); 674 _codecId = kCodecL16_16kHz; 675 codec_info_.pacsize = 110; 676 codec_info_.plfreq = 11000; 677 } 678 else if(samplesPerSec == 22050) 679 { 680 strcpy(codec_info_.plname, "L16"); 681 _codecId = kCodecL16_16kHz; 682 codec_info_.pacsize = 220; 683 codec_info_.plfreq = 22000; 684 } 685 else if(samplesPerSec == 44100) 686 { 687 strcpy(codec_info_.plname, "L16"); 688 _codecId = kCodecL16_16kHz; 689 codec_info_.pacsize = 440; 690 codec_info_.plfreq = 44000; 691 } 692 else if(samplesPerSec == 48000) 693 { 694 strcpy(codec_info_.plname, "L16"); 695 _codecId = kCodecL16_16kHz; 696 codec_info_.pacsize = 480; 697 codec_info_.plfreq = 48000; 698 } 699 else 700 { 701 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 702 "Unsupported PCM frequency!"); 703 return -1; 704 } 705 break; 706 default: 707 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 708 "unknown WAV format TAG!"); 709 return -1; 710 break; 711 } 712 return 0; 713 } 714 715 int32_t ModuleFileUtility::InitWavReading(InStream& wav, 716 const uint32_t start, 717 const uint32_t stop) 718 { 719 720 _reading = false; 721 722 if(ReadWavHeader(wav) == -1) 723 { 724 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 725 "failed to read WAV header!"); 726 return -1; 727 } 728 729 _playoutPositionMs = 0; 730 _readPos = 0; 731 732 if(start > 0) 733 { 734 uint8_t dummy[WAV_MAX_BUFFER_SIZE]; 735 int32_t readLength; 736 if(_readSizeBytes <= WAV_MAX_BUFFER_SIZE) 737 { 738 while (_playoutPositionMs < start) 739 { 740 readLength = wav.Read(dummy, _readSizeBytes); 741 if(readLength == _readSizeBytes) 742 { 743 _readPos += readLength; 744 _playoutPositionMs += 10; 745 } 746 else // Must have reached EOF before start position! 747 { 748 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 749 "InitWavReading(), EOF before start position"); 750 return -1; 751 } 752 } 753 } 754 else 755 { 756 return -1; 757 } 758 } 759 if( InitWavCodec(_wavFormatObj.nSamplesPerSec, _wavFormatObj.nChannels, 760 _wavFormatObj.nBitsPerSample, 761 _wavFormatObj.formatTag) != 0) 762 { 763 return -1; 764 } 765 _bytesPerSample = _wavFormatObj.nBitsPerSample / 8; 766 767 768 _startPointInMs = start; 769 _stopPointInMs = stop; 770 _reading = true; 771 return 0; 772 } 773 774 int32_t ModuleFileUtility::ReadWavDataAsMono( 775 InStream& wav, 776 int8_t* outData, 777 const uint32_t bufferSize) 778 { 779 WEBRTC_TRACE( 780 kTraceStream, 781 kTraceFile, 782 _id, 783 "ModuleFileUtility::ReadWavDataAsMono(wav= 0x%x, outData= 0x%d,\ 784 bufSize= %ld)", 785 &wav, 786 outData, 787 bufferSize); 788 789 // The number of bytes that should be read from file. 790 const uint32_t totalBytesNeeded = _readSizeBytes; 791 // The number of bytes that will be written to outData. 792 const uint32_t bytesRequested = (codec_info_.channels == 2) ? 793 totalBytesNeeded >> 1 : totalBytesNeeded; 794 if(bufferSize < bytesRequested) 795 { 796 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 797 "ReadWavDataAsMono: output buffer is too short!"); 798 return -1; 799 } 800 if(outData == NULL) 801 { 802 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 803 "ReadWavDataAsMono: output buffer NULL!"); 804 return -1; 805 } 806 807 if(!_reading) 808 { 809 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 810 "ReadWavDataAsMono: no longer reading file."); 811 return -1; 812 } 813 814 int32_t bytesRead = ReadWavData( 815 wav, 816 (codec_info_.channels == 2) ? _tempData : (uint8_t*)outData, 817 totalBytesNeeded); 818 if(bytesRead == 0) 819 { 820 return 0; 821 } 822 if(bytesRead < 0) 823 { 824 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 825 "ReadWavDataAsMono: failed to read data from WAV file."); 826 return -1; 827 } 828 // Output data is should be mono. 829 if(codec_info_.channels == 2) 830 { 831 for (uint32_t i = 0; i < bytesRequested / _bytesPerSample; i++) 832 { 833 // Sample value is the average of left and right buffer rounded to 834 // closest integer value. Note samples can be either 1 or 2 byte. 835 if(_bytesPerSample == 1) 836 { 837 _tempData[i] = ((_tempData[2 * i] + _tempData[(2 * i) + 1] + 838 1) >> 1); 839 } 840 else 841 { 842 int16_t* sampleData = (int16_t*) _tempData; 843 sampleData[i] = ((sampleData[2 * i] + sampleData[(2 * i) + 1] + 844 1) >> 1); 845 } 846 } 847 memcpy(outData, _tempData, bytesRequested); 848 } 849 return bytesRequested; 850 } 851 852 int32_t ModuleFileUtility::ReadWavDataAsStereo( 853 InStream& wav, 854 int8_t* outDataLeft, 855 int8_t* outDataRight, 856 const uint32_t bufferSize) 857 { 858 WEBRTC_TRACE( 859 kTraceStream, 860 kTraceFile, 861 _id, 862 "ModuleFileUtility::ReadWavDataAsStereo(wav= 0x%x, outLeft= 0x%x,\ 863 outRight= 0x%x, bufSize= %ld)", 864 &wav, 865 outDataLeft, 866 outDataRight, 867 bufferSize); 868 869 if((outDataLeft == NULL) || 870 (outDataRight == NULL)) 871 { 872 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 873 "ReadWavDataAsMono: an input buffer is NULL!"); 874 return -1; 875 } 876 if(codec_info_.channels != 2) 877 { 878 WEBRTC_TRACE( 879 kTraceError, 880 kTraceFile, 881 _id, 882 "ReadWavDataAsStereo: WAV file does not contain stereo data!"); 883 return -1; 884 } 885 if(! _reading) 886 { 887 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 888 "ReadWavDataAsStereo: no longer reading file."); 889 return -1; 890 } 891 892 // The number of bytes that should be read from file. 893 const uint32_t totalBytesNeeded = _readSizeBytes; 894 // The number of bytes that will be written to the left and the right 895 // buffers. 896 const uint32_t bytesRequested = totalBytesNeeded >> 1; 897 if(bufferSize < bytesRequested) 898 { 899 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 900 "ReadWavData: Output buffers are too short!"); 901 assert(false); 902 return -1; 903 } 904 905 int32_t bytesRead = ReadWavData(wav, _tempData, totalBytesNeeded); 906 if(bytesRead <= 0) 907 { 908 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 909 "ReadWavDataAsStereo: failed to read data from WAV file."); 910 return -1; 911 } 912 913 // Turn interleaved audio to left and right buffer. Note samples can be 914 // either 1 or 2 bytes 915 if(_bytesPerSample == 1) 916 { 917 for (uint32_t i = 0; i < bytesRequested; i++) 918 { 919 outDataLeft[i] = _tempData[2 * i]; 920 outDataRight[i] = _tempData[(2 * i) + 1]; 921 } 922 } 923 else if(_bytesPerSample == 2) 924 { 925 int16_t* sampleData = reinterpret_cast<int16_t*>(_tempData); 926 int16_t* outLeft = reinterpret_cast<int16_t*>(outDataLeft); 927 int16_t* outRight = reinterpret_cast<int16_t*>( 928 outDataRight); 929 930 // Bytes requested to samples requested. 931 uint32_t sampleCount = bytesRequested >> 1; 932 for (uint32_t i = 0; i < sampleCount; i++) 933 { 934 outLeft[i] = sampleData[2 * i]; 935 outRight[i] = sampleData[(2 * i) + 1]; 936 } 937 } else { 938 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 939 "ReadWavStereoData: unsupported sample size %d!", 940 _bytesPerSample); 941 assert(false); 942 return -1; 943 } 944 return bytesRequested; 945 } 946 947 int32_t ModuleFileUtility::ReadWavData( 948 InStream& wav, 949 uint8_t* buffer, 950 const uint32_t dataLengthInBytes) 951 { 952 WEBRTC_TRACE( 953 kTraceStream, 954 kTraceFile, 955 _id, 956 "ModuleFileUtility::ReadWavData(wav= 0x%x, buffer= 0x%x, dataLen= %ld)", 957 &wav, 958 buffer, 959 dataLengthInBytes); 960 961 962 if(buffer == NULL) 963 { 964 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 965 "ReadWavDataAsMono: output buffer NULL!"); 966 return -1; 967 } 968 969 // Make sure that a read won't return too few samples. 970 // TODO (hellner): why not read the remaining bytes needed from the start 971 // of the file? 972 if((_dataSize - _readPos) < (int32_t)dataLengthInBytes) 973 { 974 // Rewind() being -1 may be due to the file not supposed to be looped. 975 if(wav.Rewind() == -1) 976 { 977 _reading = false; 978 return 0; 979 } 980 if(InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1) 981 { 982 _reading = false; 983 return -1; 984 } 985 } 986 987 int32_t bytesRead = wav.Read(buffer, dataLengthInBytes); 988 if(bytesRead < 0) 989 { 990 _reading = false; 991 return -1; 992 } 993 994 // This should never happen due to earlier sanity checks. 995 // TODO (hellner): change to an assert and fail here since this should 996 // never happen... 997 if(bytesRead < (int32_t)dataLengthInBytes) 998 { 999 if((wav.Rewind() == -1) || 1000 (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1)) 1001 { 1002 _reading = false; 1003 return -1; 1004 } 1005 else 1006 { 1007 bytesRead = wav.Read(buffer, dataLengthInBytes); 1008 if(bytesRead < (int32_t)dataLengthInBytes) 1009 { 1010 _reading = false; 1011 return -1; 1012 } 1013 } 1014 } 1015 1016 _readPos += bytesRead; 1017 1018 // TODO (hellner): Why is dataLengthInBytes let dictate the number of bytes 1019 // to read when exactly 10ms should be read?! 1020 _playoutPositionMs += 10; 1021 if((_stopPointInMs > 0) && 1022 (_playoutPositionMs >= _stopPointInMs)) 1023 { 1024 if((wav.Rewind() == -1) || 1025 (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1)) 1026 { 1027 _reading = false; 1028 } 1029 } 1030 return bytesRead; 1031 } 1032 1033 int32_t ModuleFileUtility::InitWavWriting(OutStream& wav, 1034 const CodecInst& codecInst) 1035 { 1036 1037 if(set_codec_info(codecInst) != 0) 1038 { 1039 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 1040 "codecInst identifies unsupported codec!"); 1041 return -1; 1042 } 1043 _writing = false; 1044 uint32_t channels = (codecInst.channels == 0) ? 1045 1 : codecInst.channels; 1046 1047 if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0) 1048 { 1049 _bytesPerSample = 1; 1050 if(WriteWavHeader(wav, 8000, _bytesPerSample, channels, 1051 kWavFormatMuLaw, 0) == -1) 1052 { 1053 return -1; 1054 } 1055 }else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0) 1056 { 1057 _bytesPerSample = 1; 1058 if(WriteWavHeader(wav, 8000, _bytesPerSample, channels, kWavFormatALaw, 1059 0) == -1) 1060 { 1061 return -1; 1062 } 1063 } 1064 else if(STR_CASE_CMP(codecInst.plname, "L16") == 0) 1065 { 1066 _bytesPerSample = 2; 1067 if(WriteWavHeader(wav, codecInst.plfreq, _bytesPerSample, channels, 1068 kWavFormatPcm, 0) == -1) 1069 { 1070 return -1; 1071 } 1072 } 1073 else 1074 { 1075 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 1076 "codecInst identifies unsupported codec for WAV file!"); 1077 return -1; 1078 } 1079 _writing = true; 1080 _bytesWritten = 0; 1081 return 0; 1082 } 1083 1084 int32_t ModuleFileUtility::WriteWavData(OutStream& out, 1085 const int8_t* buffer, 1086 const uint32_t dataLength) 1087 { 1088 WEBRTC_TRACE( 1089 kTraceStream, 1090 kTraceFile, 1091 _id, 1092 "ModuleFileUtility::WriteWavData(out= 0x%x, buf= 0x%x, dataLen= %d)", 1093 &out, 1094 buffer, 1095 dataLength); 1096 1097 if(buffer == NULL) 1098 { 1099 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 1100 "WriteWavData: input buffer NULL!"); 1101 return -1; 1102 } 1103 1104 if(!out.Write(buffer, dataLength)) 1105 { 1106 return -1; 1107 } 1108 _bytesWritten += dataLength; 1109 return dataLength; 1110 } 1111 1112 1113 int32_t ModuleFileUtility::WriteWavHeader( 1114 OutStream& wav, 1115 const uint32_t freq, 1116 const uint32_t bytesPerSample, 1117 const uint32_t channels, 1118 const uint32_t format, 1119 const uint32_t lengthInBytes) 1120 { 1121 // Frame size in bytes for 10 ms of audio. 1122 // TODO (hellner): 44.1 kHz has 440 samples frame size. Doesn't seem to 1123 // be taken into consideration here! 1124 const int32_t frameSize = (freq / 100) * channels; 1125 1126 // Calculate the number of full frames that the wave file contain. 1127 const int32_t dataLengthInBytes = frameSize * (lengthInBytes / frameSize); 1128 1129 uint8_t buf[kWavHeaderSize]; 1130 webrtc::WriteWavHeader(buf, channels, freq, static_cast<WavFormat>(format), 1131 bytesPerSample, dataLengthInBytes / bytesPerSample); 1132 wav.Write(buf, kWavHeaderSize); 1133 return 0; 1134 } 1135 1136 int32_t ModuleFileUtility::UpdateWavHeader(OutStream& wav) 1137 { 1138 int32_t res = -1; 1139 if(wav.Rewind() == -1) 1140 { 1141 return -1; 1142 } 1143 uint32_t channels = (codec_info_.channels == 0) ? 1144 1 : codec_info_.channels; 1145 1146 if(STR_CASE_CMP(codec_info_.plname, "L16") == 0) 1147 { 1148 res = WriteWavHeader(wav, codec_info_.plfreq, 2, channels, 1149 kWavFormatPcm, _bytesWritten); 1150 } else if(STR_CASE_CMP(codec_info_.plname, "PCMU") == 0) { 1151 res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatMuLaw, 1152 _bytesWritten); 1153 } else if(STR_CASE_CMP(codec_info_.plname, "PCMA") == 0) { 1154 res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatALaw, 1155 _bytesWritten); 1156 } else { 1157 // Allow calling this API even if not writing to a WAVE file. 1158 // TODO (hellner): why?! 1159 return 0; 1160 } 1161 return res; 1162 } 1163 1164 1165 int32_t ModuleFileUtility::InitPreEncodedReading(InStream& in, 1166 const CodecInst& cinst) 1167 { 1168 1169 uint8_t preEncodedID; 1170 in.Read(&preEncodedID, 1); 1171 1172 MediaFileUtility_CodecType codecType = 1173 (MediaFileUtility_CodecType)preEncodedID; 1174 1175 if(set_codec_info(cinst) != 0) 1176 { 1177 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 1178 "Pre-encoded file send codec mismatch!"); 1179 return -1; 1180 } 1181 if(codecType != _codecId) 1182 { 1183 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 1184 "Pre-encoded file format codec mismatch!"); 1185 return -1; 1186 } 1187 memcpy(&codec_info_,&cinst,sizeof(CodecInst)); 1188 _reading = true; 1189 return 0; 1190 } 1191 1192 int32_t ModuleFileUtility::ReadPreEncodedData( 1193 InStream& in, 1194 int8_t* outData, 1195 const uint32_t bufferSize) 1196 { 1197 WEBRTC_TRACE( 1198 kTraceStream, 1199 kTraceFile, 1200 _id, 1201 "ModuleFileUtility::ReadPreEncodedData(in= 0x%x, outData= 0x%x,\ 1202 bufferSize= %d)", 1203 &in, 1204 outData, 1205 bufferSize); 1206 1207 if(outData == NULL) 1208 { 1209 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "output buffer NULL"); 1210 } 1211 1212 uint32_t frameLen; 1213 uint8_t buf[64]; 1214 // Each frame has a two byte header containing the frame length. 1215 int32_t res = in.Read(buf, 2); 1216 if(res != 2) 1217 { 1218 if(!in.Rewind()) 1219 { 1220 // The first byte is the codec identifier. 1221 in.Read(buf, 1); 1222 res = in.Read(buf, 2); 1223 } 1224 else 1225 { 1226 return -1; 1227 } 1228 } 1229 frameLen = buf[0] + buf[1] * 256; 1230 if(bufferSize < frameLen) 1231 { 1232 WEBRTC_TRACE( 1233 kTraceError, 1234 kTraceFile, 1235 _id, 1236 "buffer not large enough to read %d bytes of pre-encoded data!", 1237 frameLen); 1238 return -1; 1239 } 1240 return in.Read(outData, frameLen); 1241 } 1242 1243 int32_t ModuleFileUtility::InitPreEncodedWriting( 1244 OutStream& out, 1245 const CodecInst& codecInst) 1246 { 1247 1248 if(set_codec_info(codecInst) != 0) 1249 { 1250 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "CodecInst not recognized!"); 1251 return -1; 1252 } 1253 _writing = true; 1254 _bytesWritten = 1; 1255 out.Write(&_codecId, 1); 1256 return 0; 1257 } 1258 1259 int32_t ModuleFileUtility::WritePreEncodedData( 1260 OutStream& out, 1261 const int8_t* buffer, 1262 const uint32_t dataLength) 1263 { 1264 WEBRTC_TRACE( 1265 kTraceStream, 1266 kTraceFile, 1267 _id, 1268 "ModuleFileUtility::WritePreEncodedData(out= 0x%x, inData= 0x%x,\ 1269 dataLen= %d)", 1270 &out, 1271 buffer, 1272 dataLength); 1273 1274 if(buffer == NULL) 1275 { 1276 WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL"); 1277 } 1278 1279 int32_t bytesWritten = 0; 1280 // The first two bytes is the size of the frame. 1281 int16_t lengthBuf; 1282 lengthBuf = (int16_t)dataLength; 1283 if(!out.Write(&lengthBuf, 2)) 1284 { 1285 return -1; 1286 } 1287 bytesWritten = 2; 1288 1289 if(!out.Write(buffer, dataLength)) 1290 { 1291 return -1; 1292 } 1293 bytesWritten += dataLength; 1294 return bytesWritten; 1295 } 1296 1297 int32_t ModuleFileUtility::InitCompressedReading( 1298 InStream& in, 1299 const uint32_t start, 1300 const uint32_t stop) 1301 { 1302 WEBRTC_TRACE( 1303 kTraceDebug, 1304 kTraceFile, 1305 _id, 1306 "ModuleFileUtility::InitCompressedReading(in= 0x%x, start= %d,\ 1307 stop= %d)", 1308 &in, 1309 start, 1310 stop); 1311 1312 #if defined(WEBRTC_CODEC_AMR) || defined(WEBRTC_CODEC_AMRWB) || \ 1313 defined(WEBRTC_CODEC_ILBC) 1314 int16_t read_len = 0; 1315 #endif 1316 _codecId = kCodecNoCodec; 1317 _playoutPositionMs = 0; 1318 _reading = false; 1319 1320 _startPointInMs = start; 1321 _stopPointInMs = stop; 1322 1323 #ifdef WEBRTC_CODEC_AMR 1324 int32_t AMRmode2bytes[9]={12,13,15,17,19,20,26,31,5}; 1325 #endif 1326 #ifdef WEBRTC_CODEC_AMRWB 1327 int32_t AMRWBmode2bytes[10]={17,23,32,36,40,46,50,58,60,6}; 1328 #endif 1329 1330 // Read the codec name 1331 int32_t cnt = 0; 1332 char buf[64]; 1333 do 1334 { 1335 in.Read(&buf[cnt++], 1); 1336 } while ((buf[cnt-1] != '\n') && (64 > cnt)); 1337 1338 if(cnt==64) 1339 { 1340 return -1; 1341 } else { 1342 buf[cnt]=0; 1343 } 1344 1345 #ifdef WEBRTC_CODEC_AMR 1346 if(!strcmp("#!AMR\n", buf)) 1347 { 1348 strcpy(codec_info_.plname, "amr"); 1349 codec_info_.pacsize = 160; 1350 _codecId = kCodecAmr; 1351 codec_info_.pltype = 112; 1352 codec_info_.rate = 12200; 1353 codec_info_.plfreq = 8000; 1354 codec_info_.channels = 1; 1355 1356 int16_t mode = 0; 1357 if(_startPointInMs > 0) 1358 { 1359 while (_playoutPositionMs <= _startPointInMs) 1360 { 1361 // First read byte contain the AMR mode. 1362 read_len = in.Read(buf, 1); 1363 if(read_len != 1) 1364 { 1365 return -1; 1366 } 1367 1368 mode = (buf[0]>>3)&0xF; 1369 if((mode < 0) || (mode > 8)) 1370 { 1371 if(mode != 15) 1372 { 1373 return -1; 1374 } 1375 } 1376 if(mode != 15) 1377 { 1378 read_len = in.Read(&buf[1], AMRmode2bytes[mode]); 1379 if(read_len != AMRmode2bytes[mode]) 1380 { 1381 return -1; 1382 } 1383 } 1384 _playoutPositionMs += 20; 1385 } 1386 } 1387 } 1388 #endif 1389 #ifdef WEBRTC_CODEC_AMRWB 1390 if(!strcmp("#!AMRWB\n", buf)) 1391 { 1392 strcpy(codec_info_.plname, "amr-wb"); 1393 codec_info_.pacsize = 320; 1394 _codecId = kCodecAmrWb; 1395 codec_info_.pltype = 120; 1396 codec_info_.rate = 20000; 1397 codec_info_.plfreq = 16000; 1398 codec_info_.channels = 1; 1399 1400 int16_t mode = 0; 1401 if(_startPointInMs > 0) 1402 { 1403 while (_playoutPositionMs <= _startPointInMs) 1404 { 1405 // First read byte contain the AMR mode. 1406 read_len = in.Read(buf, 1); 1407 if(read_len != 1) 1408 { 1409 return -1; 1410 } 1411 1412 mode = (buf[0]>>3)&0xF; 1413 if((mode < 0) || (mode > 9)) 1414 { 1415 if(mode != 15) 1416 { 1417 return -1; 1418 } 1419 } 1420 if(mode != 15) 1421 { 1422 read_len = in.Read(&buf[1], AMRWBmode2bytes[mode]); 1423 if(read_len != AMRWBmode2bytes[mode]) 1424 { 1425 return -1; 1426 } 1427 } 1428 _playoutPositionMs += 20; 1429 } 1430 } 1431 } 1432 #endif 1433 #ifdef WEBRTC_CODEC_ILBC 1434 if(!strcmp("#!iLBC20\n", buf)) 1435 { 1436 codec_info_.pltype = 102; 1437 strcpy(codec_info_.plname, "ilbc"); 1438 codec_info_.plfreq = 8000; 1439 codec_info_.pacsize = 160; 1440 codec_info_.channels = 1; 1441 codec_info_.rate = 13300; 1442 _codecId = kCodecIlbc20Ms; 1443 1444 if(_startPointInMs > 0) 1445 { 1446 while (_playoutPositionMs <= _startPointInMs) 1447 { 1448 read_len = in.Read(buf, 38); 1449 if(read_len == 38) 1450 { 1451 _playoutPositionMs += 20; 1452 } 1453 else 1454 { 1455 return -1; 1456 } 1457 } 1458 } 1459 } 1460 1461 if(!strcmp("#!iLBC30\n", buf)) 1462 { 1463 codec_info_.pltype = 102; 1464 strcpy(codec_info_.plname, "ilbc"); 1465 codec_info_.plfreq = 8000; 1466 codec_info_.pacsize = 240; 1467 codec_info_.channels = 1; 1468 codec_info_.rate = 13300; 1469 _codecId = kCodecIlbc30Ms; 1470 1471 if(_startPointInMs > 0) 1472 { 1473 while (_playoutPositionMs <= _startPointInMs) 1474 { 1475 read_len = in.Read(buf, 50); 1476 if(read_len == 50) 1477 { 1478 _playoutPositionMs += 20; 1479 } 1480 else 1481 { 1482 return -1; 1483 } 1484 } 1485 } 1486 } 1487 #endif 1488 if(_codecId == kCodecNoCodec) 1489 { 1490 return -1; 1491 } 1492 _reading = true; 1493 return 0; 1494 } 1495 1496 int32_t ModuleFileUtility::ReadCompressedData(InStream& in, 1497 int8_t* outData, 1498 uint32_t bufferSize) 1499 { 1500 WEBRTC_TRACE( 1501 kTraceStream, 1502 kTraceFile, 1503 _id, 1504 "ModuleFileUtility::ReadCompressedData(in=0x%x, outData=0x%x,\ 1505 bytes=%ld)", 1506 &in, 1507 outData, 1508 bufferSize); 1509 1510 #ifdef WEBRTC_CODEC_AMR 1511 uint32_t AMRmode2bytes[9]={12,13,15,17,19,20,26,31,5}; 1512 #endif 1513 #ifdef WEBRTC_CODEC_AMRWB 1514 uint32_t AMRWBmode2bytes[10]={17,23,32,36,40,46,50,58,60,6}; 1515 #endif 1516 uint32_t bytesRead = 0; 1517 1518 if(! _reading) 1519 { 1520 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "not currently reading!"); 1521 return -1; 1522 } 1523 1524 #ifdef WEBRTC_CODEC_AMR 1525 if(_codecId == kCodecAmr) 1526 { 1527 int32_t res = in.Read(outData, 1); 1528 if(res != 1) 1529 { 1530 if(!in.Rewind()) 1531 { 1532 InitCompressedReading(in, _startPointInMs, _stopPointInMs); 1533 res = in.Read(outData, 1); 1534 if(res != 1) 1535 { 1536 _reading = false; 1537 return -1; 1538 } 1539 } 1540 else 1541 { 1542 _reading = false; 1543 return -1; 1544 } 1545 } 1546 const int16_t mode = (outData[0]>>3)&0xF; 1547 if((mode < 0) || 1548 (mode > 8)) 1549 { 1550 if(mode != 15) 1551 { 1552 return -1; 1553 } 1554 } 1555 if(mode != 15) 1556 { 1557 if(bufferSize < AMRmode2bytes[mode] + 1) 1558 { 1559 WEBRTC_TRACE( 1560 kTraceError, 1561 kTraceFile, 1562 _id, 1563 "output buffer is too short to read AMR compressed data."); 1564 assert(false); 1565 return -1; 1566 } 1567 bytesRead = in.Read(&outData[1], AMRmode2bytes[mode]); 1568 if(bytesRead != AMRmode2bytes[mode]) 1569 { 1570 _reading = false; 1571 return -1; 1572 } 1573 // Count the mode byte to bytes read. 1574 bytesRead++; 1575 } 1576 else 1577 { 1578 bytesRead = 1; 1579 } 1580 } 1581 #endif 1582 #ifdef WEBRTC_CODEC_AMRWB 1583 if(_codecId == kCodecAmrWb) 1584 { 1585 int32_t res = in.Read(outData, 1); 1586 if(res != 1) 1587 { 1588 if(!in.Rewind()) 1589 { 1590 InitCompressedReading(in, _startPointInMs, _stopPointInMs); 1591 res = in.Read(outData, 1); 1592 if(res != 1) 1593 { 1594 _reading = false; 1595 return -1; 1596 } 1597 } 1598 else 1599 { 1600 _reading = false; 1601 return -1; 1602 } 1603 } 1604 int16_t mode = (outData[0]>>3)&0xF; 1605 if((mode < 0) || 1606 (mode > 8)) 1607 { 1608 if(mode != 15) 1609 { 1610 return -1; 1611 } 1612 } 1613 if(mode != 15) 1614 { 1615 if(bufferSize < AMRWBmode2bytes[mode] + 1) 1616 { 1617 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 1618 "output buffer is too short to read AMRWB\ 1619 compressed."); 1620 assert(false); 1621 return -1; 1622 } 1623 bytesRead = in.Read(&outData[1], AMRWBmode2bytes[mode]); 1624 if(bytesRead != AMRWBmode2bytes[mode]) 1625 { 1626 _reading = false; 1627 return -1; 1628 } 1629 bytesRead++; 1630 } 1631 else 1632 { 1633 bytesRead = 1; 1634 } 1635 } 1636 #endif 1637 #ifdef WEBRTC_CODEC_ILBC 1638 if((_codecId == kCodecIlbc20Ms) || 1639 (_codecId == kCodecIlbc30Ms)) 1640 { 1641 uint32_t byteSize = 0; 1642 if(_codecId == kCodecIlbc30Ms) 1643 { 1644 byteSize = 50; 1645 } 1646 if(_codecId == kCodecIlbc20Ms) 1647 { 1648 byteSize = 38; 1649 } 1650 if(bufferSize < byteSize) 1651 { 1652 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 1653 "output buffer is too short to read ILBC compressed\ 1654 data."); 1655 assert(false); 1656 return -1; 1657 } 1658 1659 bytesRead = in.Read(outData, byteSize); 1660 if(bytesRead != byteSize) 1661 { 1662 if(!in.Rewind()) 1663 { 1664 InitCompressedReading(in, _startPointInMs, _stopPointInMs); 1665 bytesRead = in.Read(outData, byteSize); 1666 if(bytesRead != byteSize) 1667 { 1668 _reading = false; 1669 return -1; 1670 } 1671 } 1672 else 1673 { 1674 _reading = false; 1675 return -1; 1676 } 1677 } 1678 } 1679 #endif 1680 if(bytesRead == 0) 1681 { 1682 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 1683 "ReadCompressedData() no bytes read, codec not supported"); 1684 return -1; 1685 } 1686 1687 _playoutPositionMs += 20; 1688 if((_stopPointInMs > 0) && 1689 (_playoutPositionMs >= _stopPointInMs)) 1690 { 1691 if(!in.Rewind()) 1692 { 1693 InitCompressedReading(in, _startPointInMs, _stopPointInMs); 1694 } 1695 else 1696 { 1697 _reading = false; 1698 } 1699 } 1700 return bytesRead; 1701 } 1702 1703 int32_t ModuleFileUtility::InitCompressedWriting( 1704 OutStream& out, 1705 const CodecInst& codecInst) 1706 { 1707 WEBRTC_TRACE(kTraceDebug, kTraceFile, _id, 1708 "ModuleFileUtility::InitCompressedWriting(out= 0x%x,\ 1709 codecName= %s)", 1710 &out, codecInst.plname); 1711 1712 _writing = false; 1713 1714 #ifdef WEBRTC_CODEC_AMR 1715 if(STR_CASE_CMP(codecInst.plname, "amr") == 0) 1716 { 1717 if(codecInst.pacsize == 160) 1718 { 1719 memcpy(&codec_info_,&codecInst,sizeof(CodecInst)); 1720 _codecId = kCodecAmr; 1721 out.Write("#!AMR\n",6); 1722 _writing = true; 1723 return 0; 1724 } 1725 } 1726 #endif 1727 #ifdef WEBRTC_CODEC_AMRWB 1728 if(STR_CASE_CMP(codecInst.plname, "amr-wb") == 0) 1729 { 1730 if(codecInst.pacsize == 320) 1731 { 1732 memcpy(&codec_info_,&codecInst,sizeof(CodecInst)); 1733 _codecId = kCodecAmrWb; 1734 out.Write("#!AMRWB\n",8); 1735 _writing = true; 1736 return 0; 1737 } 1738 } 1739 #endif 1740 #ifdef WEBRTC_CODEC_ILBC 1741 if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0) 1742 { 1743 if(codecInst.pacsize == 160) 1744 { 1745 _codecId = kCodecIlbc20Ms; 1746 out.Write("#!iLBC20\n",9); 1747 } 1748 else if(codecInst.pacsize == 240) 1749 { 1750 _codecId = kCodecIlbc30Ms; 1751 out.Write("#!iLBC30\n",9); 1752 } 1753 else 1754 { 1755 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 1756 "codecInst defines unsupported compression codec!"); 1757 return -1; 1758 } 1759 memcpy(&codec_info_,&codecInst,sizeof(CodecInst)); 1760 _writing = true; 1761 return 0; 1762 } 1763 #endif 1764 1765 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 1766 "codecInst defines unsupported compression codec!"); 1767 return -1; 1768 } 1769 1770 int32_t ModuleFileUtility::WriteCompressedData( 1771 OutStream& out, 1772 const int8_t* buffer, 1773 const uint32_t dataLength) 1774 { 1775 WEBRTC_TRACE( 1776 kTraceStream, 1777 kTraceFile, 1778 _id, 1779 "ModuleFileUtility::WriteCompressedData(out= 0x%x, buf= 0x%x,\ 1780 dataLen= %d)", 1781 &out, 1782 buffer, 1783 dataLength); 1784 1785 if(buffer == NULL) 1786 { 1787 WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL"); 1788 } 1789 1790 if(!out.Write(buffer, dataLength)) 1791 { 1792 return -1; 1793 } 1794 return dataLength; 1795 } 1796 1797 int32_t ModuleFileUtility::InitPCMReading(InStream& pcm, 1798 const uint32_t start, 1799 const uint32_t stop, 1800 uint32_t freq) 1801 { 1802 WEBRTC_TRACE( 1803 kTraceInfo, 1804 kTraceFile, 1805 _id, 1806 "ModuleFileUtility::InitPCMReading(pcm= 0x%x, start=%d, stop=%d,\ 1807 freq=%d)", 1808 &pcm, 1809 start, 1810 stop, 1811 freq); 1812 1813 int8_t dummy[320]; 1814 int32_t read_len; 1815 1816 _playoutPositionMs = 0; 1817 _startPointInMs = start; 1818 _stopPointInMs = stop; 1819 _reading = false; 1820 1821 if(freq == 8000) 1822 { 1823 strcpy(codec_info_.plname, "L16"); 1824 codec_info_.pltype = -1; 1825 codec_info_.plfreq = 8000; 1826 codec_info_.pacsize = 160; 1827 codec_info_.channels = 1; 1828 codec_info_.rate = 128000; 1829 _codecId = kCodecL16_8Khz; 1830 } 1831 else if(freq == 16000) 1832 { 1833 strcpy(codec_info_.plname, "L16"); 1834 codec_info_.pltype = -1; 1835 codec_info_.plfreq = 16000; 1836 codec_info_.pacsize = 320; 1837 codec_info_.channels = 1; 1838 codec_info_.rate = 256000; 1839 _codecId = kCodecL16_16kHz; 1840 } 1841 else if(freq == 32000) 1842 { 1843 strcpy(codec_info_.plname, "L16"); 1844 codec_info_.pltype = -1; 1845 codec_info_.plfreq = 32000; 1846 codec_info_.pacsize = 320; 1847 codec_info_.channels = 1; 1848 codec_info_.rate = 512000; 1849 _codecId = kCodecL16_32Khz; 1850 } 1851 1852 // Readsize for 10ms of audio data (2 bytes per sample). 1853 _readSizeBytes = 2 * codec_info_. plfreq / 100; 1854 if(_startPointInMs > 0) 1855 { 1856 while (_playoutPositionMs < _startPointInMs) 1857 { 1858 read_len = pcm.Read(dummy, _readSizeBytes); 1859 if(read_len == _readSizeBytes) 1860 { 1861 _playoutPositionMs += 10; 1862 } 1863 else // Must have reached EOF before start position! 1864 { 1865 return -1; 1866 } 1867 } 1868 } 1869 _reading = true; 1870 return 0; 1871 } 1872 1873 int32_t ModuleFileUtility::ReadPCMData(InStream& pcm, 1874 int8_t* outData, 1875 uint32_t bufferSize) 1876 { 1877 WEBRTC_TRACE( 1878 kTraceStream, 1879 kTraceFile, 1880 _id, 1881 "ModuleFileUtility::ReadPCMData(pcm= 0x%x, outData= 0x%x, bufSize= %d)", 1882 &pcm, 1883 outData, 1884 bufferSize); 1885 1886 if(outData == NULL) 1887 { 1888 WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL"); 1889 } 1890 1891 // Readsize for 10ms of audio data (2 bytes per sample). 1892 uint32_t bytesRequested = 2 * codec_info_.plfreq / 100; 1893 if(bufferSize < bytesRequested) 1894 { 1895 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 1896 "ReadPCMData: buffer not long enough for a 10ms frame."); 1897 assert(false); 1898 return -1; 1899 } 1900 1901 uint32_t bytesRead = pcm.Read(outData, bytesRequested); 1902 if(bytesRead < bytesRequested) 1903 { 1904 if(pcm.Rewind() == -1) 1905 { 1906 _reading = false; 1907 } 1908 else 1909 { 1910 if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs, 1911 codec_info_.plfreq) == -1) 1912 { 1913 _reading = false; 1914 } 1915 else 1916 { 1917 int32_t rest = bytesRequested - bytesRead; 1918 int32_t len = pcm.Read(&(outData[bytesRead]), rest); 1919 if(len == rest) 1920 { 1921 bytesRead += len; 1922 } 1923 else 1924 { 1925 _reading = false; 1926 } 1927 } 1928 if(bytesRead <= 0) 1929 { 1930 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 1931 "ReadPCMData: Failed to rewind audio file."); 1932 return -1; 1933 } 1934 } 1935 } 1936 1937 if(bytesRead <= 0) 1938 { 1939 WEBRTC_TRACE(kTraceStream, kTraceFile, _id, 1940 "ReadPCMData: end of file"); 1941 return -1; 1942 } 1943 _playoutPositionMs += 10; 1944 if(_stopPointInMs && _playoutPositionMs >= _stopPointInMs) 1945 { 1946 if(!pcm.Rewind()) 1947 { 1948 if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs, 1949 codec_info_.plfreq) == -1) 1950 { 1951 _reading = false; 1952 } 1953 } 1954 } 1955 return bytesRead; 1956 } 1957 1958 int32_t ModuleFileUtility::InitPCMWriting(OutStream& out, uint32_t freq) 1959 { 1960 1961 if(freq == 8000) 1962 { 1963 strcpy(codec_info_.plname, "L16"); 1964 codec_info_.pltype = -1; 1965 codec_info_.plfreq = 8000; 1966 codec_info_.pacsize = 160; 1967 codec_info_.channels = 1; 1968 codec_info_.rate = 128000; 1969 1970 _codecId = kCodecL16_8Khz; 1971 } 1972 else if(freq == 16000) 1973 { 1974 strcpy(codec_info_.plname, "L16"); 1975 codec_info_.pltype = -1; 1976 codec_info_.plfreq = 16000; 1977 codec_info_.pacsize = 320; 1978 codec_info_.channels = 1; 1979 codec_info_.rate = 256000; 1980 1981 _codecId = kCodecL16_16kHz; 1982 } 1983 else if(freq == 32000) 1984 { 1985 strcpy(codec_info_.plname, "L16"); 1986 codec_info_.pltype = -1; 1987 codec_info_.plfreq = 32000; 1988 codec_info_.pacsize = 320; 1989 codec_info_.channels = 1; 1990 codec_info_.rate = 512000; 1991 1992 _codecId = kCodecL16_32Khz; 1993 } 1994 if((_codecId != kCodecL16_8Khz) && 1995 (_codecId != kCodecL16_16kHz) && 1996 (_codecId != kCodecL16_32Khz)) 1997 { 1998 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 1999 "CodecInst is not 8KHz PCM or 16KHz PCM!"); 2000 return -1; 2001 } 2002 _writing = true; 2003 _bytesWritten = 0; 2004 return 0; 2005 } 2006 2007 int32_t ModuleFileUtility::WritePCMData(OutStream& out, 2008 const int8_t* buffer, 2009 const uint32_t dataLength) 2010 { 2011 WEBRTC_TRACE( 2012 kTraceStream, 2013 kTraceFile, 2014 _id, 2015 "ModuleFileUtility::WritePCMData(out= 0x%x, buf= 0x%x, dataLen= %d)", 2016 &out, 2017 buffer, 2018 dataLength); 2019 2020 if(buffer == NULL) 2021 { 2022 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "buffer NULL"); 2023 } 2024 2025 if(!out.Write(buffer, dataLength)) 2026 { 2027 return -1; 2028 } 2029 2030 _bytesWritten += dataLength; 2031 return dataLength; 2032 } 2033 2034 int32_t ModuleFileUtility::codec_info(CodecInst& codecInst) 2035 { 2036 WEBRTC_TRACE(kTraceStream, kTraceFile, _id, 2037 "ModuleFileUtility::codec_info(codecInst= 0x%x)", &codecInst); 2038 2039 if(!_reading && !_writing) 2040 { 2041 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 2042 "CodecInst: not currently reading audio file!"); 2043 return -1; 2044 } 2045 memcpy(&codecInst,&codec_info_,sizeof(CodecInst)); 2046 return 0; 2047 } 2048 2049 int32_t ModuleFileUtility::set_codec_info(const CodecInst& codecInst) 2050 { 2051 2052 _codecId = kCodecNoCodec; 2053 if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0) 2054 { 2055 _codecId = kCodecPcmu; 2056 } 2057 else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0) 2058 { 2059 _codecId = kCodecPcma; 2060 } 2061 else if(STR_CASE_CMP(codecInst.plname, "L16") == 0) 2062 { 2063 if(codecInst.plfreq == 8000) 2064 { 2065 _codecId = kCodecL16_8Khz; 2066 } 2067 else if(codecInst.plfreq == 16000) 2068 { 2069 _codecId = kCodecL16_16kHz; 2070 } 2071 else if(codecInst.plfreq == 32000) 2072 { 2073 _codecId = kCodecL16_32Khz; 2074 } 2075 } 2076 #ifdef WEBRTC_CODEC_AMR 2077 else if(STR_CASE_CMP(codecInst.plname, "amr") == 0) 2078 { 2079 _codecId = kCodecAmr; 2080 } 2081 #endif 2082 #ifdef WEBRTC_CODEC_AMRWB 2083 else if(STR_CASE_CMP(codecInst.plname, "amr-wb") == 0) 2084 { 2085 _codecId = kCodecAmrWb; 2086 } 2087 #endif 2088 #ifdef WEBRTC_CODEC_ILBC 2089 else if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0) 2090 { 2091 if(codecInst.pacsize == 160) 2092 { 2093 _codecId = kCodecIlbc20Ms; 2094 } 2095 else if(codecInst.pacsize == 240) 2096 { 2097 _codecId = kCodecIlbc30Ms; 2098 } 2099 } 2100 #endif 2101 #if(defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) 2102 else if(STR_CASE_CMP(codecInst.plname, "isac") == 0) 2103 { 2104 if(codecInst.plfreq == 16000) 2105 { 2106 _codecId = kCodecIsac; 2107 } 2108 else if(codecInst.plfreq == 32000) 2109 { 2110 _codecId = kCodecIsacSwb; 2111 } 2112 } 2113 #endif 2114 #ifdef WEBRTC_CODEC_ISACLC 2115 else if(STR_CASE_CMP(codecInst.plname, "isaclc") == 0) 2116 { 2117 _codecId = kCodecIsacLc; 2118 } 2119 #endif 2120 #ifdef WEBRTC_CODEC_G722 2121 else if(STR_CASE_CMP(codecInst.plname, "G722") == 0) 2122 { 2123 _codecId = kCodecG722; 2124 } 2125 #endif 2126 else if(STR_CASE_CMP(codecInst.plname, "G7221") == 0) 2127 { 2128 #ifdef WEBRTC_CODEC_G722_1 2129 if(codecInst.plfreq == 16000) 2130 { 2131 if(codecInst.rate == 16000) 2132 { 2133 _codecId = kCodecG722_1_16Kbps; 2134 } 2135 else if(codecInst.rate == 24000) 2136 { 2137 _codecId = kCodecG722_1_24Kbps; 2138 } 2139 else if(codecInst.rate == 32000) 2140 { 2141 _codecId = kCodecG722_1_32Kbps; 2142 } 2143 } 2144 #endif 2145 #ifdef WEBRTC_CODEC_G722_1C 2146 if(codecInst.plfreq == 32000) 2147 { 2148 if(codecInst.rate == 48000) 2149 { 2150 _codecId = kCodecG722_1c_48; 2151 } 2152 else if(codecInst.rate == 32000) 2153 { 2154 _codecId = kCodecG722_1c_32; 2155 } 2156 else if(codecInst.rate == 24000) 2157 { 2158 _codecId = kCodecG722_1c_24; 2159 } 2160 } 2161 #endif 2162 } 2163 #ifdef WEBRTC_CODEC_G726 2164 else if(STR_CASE_CMP(codecInst.plname, "G726-40") == 0) 2165 { 2166 _codecId = kCodecG726_40; 2167 } 2168 else if(STR_CASE_CMP(codecInst.plname, "G726-32") == 0) 2169 { 2170 _codecId = kCodecG726_24; 2171 } 2172 else if(STR_CASE_CMP(codecInst.plname, "G726-24") == 0) 2173 { 2174 _codecId = kCodecG726_32; 2175 } 2176 else if(STR_CASE_CMP(codecInst.plname, "G726-16") == 0) 2177 { 2178 _codecId = kCodecG726_16; 2179 } 2180 #endif 2181 #ifdef WEBRTC_CODEC_G729 2182 else if(STR_CASE_CMP(codecInst.plname, "G729") == 0) 2183 { 2184 _codecId = kCodecG729; 2185 } 2186 #endif 2187 #ifdef WEBRTC_CODEC_G729_1 2188 else if(STR_CASE_CMP(codecInst.plname, "G7291") == 0) 2189 { 2190 _codecId = kCodecG729_1; 2191 } 2192 #endif 2193 #ifdef WEBRTC_CODEC_SPEEX 2194 else if(STR_CASE_CMP(codecInst.plname, "speex") == 0) 2195 { 2196 if(codecInst.plfreq == 8000) 2197 { 2198 _codecId = kCodecSpeex8Khz; 2199 } 2200 else if(codecInst.plfreq == 16000) 2201 { 2202 _codecId = kCodecSpeex16Khz; 2203 } 2204 } 2205 #endif 2206 if(_codecId == kCodecNoCodec) 2207 { 2208 return -1; 2209 } 2210 memcpy(&codec_info_, &codecInst, sizeof(CodecInst)); 2211 return 0; 2212 } 2213 2214 int32_t ModuleFileUtility::FileDurationMs(const char* fileName, 2215 const FileFormats fileFormat, 2216 const uint32_t freqInHz) 2217 { 2218 2219 if(fileName == NULL) 2220 { 2221 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "filename NULL"); 2222 return -1; 2223 } 2224 2225 int32_t time_in_ms = -1; 2226 struct stat file_size; 2227 if(stat(fileName,&file_size) == -1) 2228 { 2229 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 2230 "failed to retrieve file size with stat!"); 2231 return -1; 2232 } 2233 FileWrapper* inStreamObj = FileWrapper::Create(); 2234 if(inStreamObj == NULL) 2235 { 2236 WEBRTC_TRACE(kTraceMemory, kTraceFile, _id, 2237 "failed to create InStream object!"); 2238 return -1; 2239 } 2240 if(inStreamObj->OpenFile(fileName, true) == -1) 2241 { 2242 delete inStreamObj; 2243 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 2244 "failed to open file %s!", fileName); 2245 return -1; 2246 } 2247 2248 switch (fileFormat) 2249 { 2250 case kFileFormatWavFile: 2251 { 2252 if(ReadWavHeader(*inStreamObj) == -1) 2253 { 2254 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 2255 "failed to read WAV file header!"); 2256 return -1; 2257 } 2258 time_in_ms = ((file_size.st_size - 44) / 2259 (_wavFormatObj.nAvgBytesPerSec/1000)); 2260 break; 2261 } 2262 case kFileFormatPcm16kHzFile: 2263 { 2264 // 16 samples per ms. 2 bytes per sample. 2265 int32_t denominator = 16*2; 2266 time_in_ms = (file_size.st_size)/denominator; 2267 break; 2268 } 2269 case kFileFormatPcm8kHzFile: 2270 { 2271 // 8 samples per ms. 2 bytes per sample. 2272 int32_t denominator = 8*2; 2273 time_in_ms = (file_size.st_size)/denominator; 2274 break; 2275 } 2276 case kFileFormatCompressedFile: 2277 { 2278 int32_t cnt = 0; 2279 int32_t read_len = 0; 2280 char buf[64]; 2281 do 2282 { 2283 read_len = inStreamObj->Read(&buf[cnt++], 1); 2284 if(read_len != 1) 2285 { 2286 return -1; 2287 } 2288 } while ((buf[cnt-1] != '\n') && (64 > cnt)); 2289 2290 if(cnt == 64) 2291 { 2292 return -1; 2293 } 2294 else 2295 { 2296 buf[cnt] = 0; 2297 } 2298 #ifdef WEBRTC_CODEC_AMR 2299 if(!strcmp("#!AMR\n", buf)) 2300 { 2301 uint8_t dummy; 2302 read_len = inStreamObj->Read(&dummy, 1); 2303 if(read_len != 1) 2304 { 2305 return -1; 2306 } 2307 2308 int16_t AMRMode = (dummy>>3)&0xF; 2309 2310 // TODO (hellner): use tables instead of hardcoding like this! 2311 // Additionally, this calculation does not 2312 // take octet alignment into consideration. 2313 switch (AMRMode) 2314 { 2315 // Mode 0: 4.75 kbit/sec -> 95 bits per 20 ms frame. 2316 // 20 ms = 95 bits -> 2317 // file size in bytes * 8 / 95 is the number of 2318 // 20 ms frames in the file -> 2319 // time_in_ms = file size * 8 / 95 * 20 2320 case 0: 2321 time_in_ms = ((file_size.st_size)*160)/95; 2322 break; 2323 // Mode 1: 5.15 kbit/sec -> 103 bits per 20 ms frame. 2324 case 1: 2325 time_in_ms = ((file_size.st_size)*160)/103; 2326 break; 2327 // Mode 2: 5.90 kbit/sec -> 118 bits per 20 ms frame. 2328 case 2: 2329 time_in_ms = ((file_size.st_size)*160)/118; 2330 break; 2331 // Mode 3: 6.70 kbit/sec -> 134 bits per 20 ms frame. 2332 case 3: 2333 time_in_ms = ((file_size.st_size)*160)/134; 2334 break; 2335 // Mode 4: 7.40 kbit/sec -> 148 bits per 20 ms frame. 2336 case 4: 2337 time_in_ms = ((file_size.st_size)*160)/148; 2338 break; 2339 // Mode 5: 7.95 bit/sec -> 159 bits per 20 ms frame. 2340 case 5: 2341 time_in_ms = ((file_size.st_size)*160)/159; 2342 break; 2343 // Mode 6: 10.2 bit/sec -> 204 bits per 20 ms frame. 2344 case 6: 2345 time_in_ms = ((file_size.st_size)*160)/204; 2346 break; 2347 // Mode 7: 12.2 bit/sec -> 244 bits per 20 ms frame. 2348 case 7: 2349 time_in_ms = ((file_size.st_size)*160)/244; 2350 break; 2351 // Mode 8: SID Mode -> 39 bits per 20 ms frame. 2352 case 8: 2353 time_in_ms = ((file_size.st_size)*160)/39; 2354 break; 2355 default: 2356 break; 2357 } 2358 } 2359 #endif 2360 #ifdef WEBRTC_CODEC_AMRWB 2361 if(!strcmp("#!AMRWB\n", buf)) 2362 { 2363 uint8_t dummy; 2364 read_len = inStreamObj->Read(&dummy, 1); 2365 if(read_len != 1) 2366 { 2367 return -1; 2368 } 2369 2370 // TODO (hellner): use tables instead of hardcoding like this! 2371 int16_t AMRWBMode = (dummy>>3)&0xF; 2372 switch(AMRWBMode) 2373 { 2374 // Mode 0: 6.6 kbit/sec -> 132 bits per 20 ms frame. 2375 case 0: 2376 time_in_ms = ((file_size.st_size)*160)/132; 2377 break; 2378 // Mode 1: 8.85 kbit/sec -> 177 bits per 20 ms frame. 2379 case 1: 2380 time_in_ms = ((file_size.st_size)*160)/177; 2381 break; 2382 // Mode 2: 12.65 kbit/sec -> 253 bits per 20 ms frame. 2383 case 2: 2384 time_in_ms = ((file_size.st_size)*160)/253; 2385 break; 2386 // Mode 3: 14.25 kbit/sec -> 285 bits per 20 ms frame. 2387 case 3: 2388 time_in_ms = ((file_size.st_size)*160)/285; 2389 break; 2390 // Mode 4: 15.85 kbit/sec -> 317 bits per 20 ms frame. 2391 case 4: 2392 time_in_ms = ((file_size.st_size)*160)/317; 2393 break; 2394 // Mode 5: 18.25 kbit/sec -> 365 bits per 20 ms frame. 2395 case 5: 2396 time_in_ms = ((file_size.st_size)*160)/365; 2397 break; 2398 // Mode 6: 19.85 kbit/sec -> 397 bits per 20 ms frame. 2399 case 6: 2400 time_in_ms = ((file_size.st_size)*160)/397; 2401 break; 2402 // Mode 7: 23.05 kbit/sec -> 461 bits per 20 ms frame. 2403 case 7: 2404 time_in_ms = ((file_size.st_size)*160)/461; 2405 break; 2406 // Mode 8: 23.85 kbit/sec -> 477 bits per 20 ms frame. 2407 case 8: 2408 time_in_ms = ((file_size.st_size)*160)/477; 2409 break; 2410 default: 2411 delete inStreamObj; 2412 return -1; 2413 } 2414 } 2415 #endif 2416 #ifdef WEBRTC_CODEC_ILBC 2417 if(!strcmp("#!iLBC20\n", buf)) 2418 { 2419 // 20 ms is 304 bits 2420 time_in_ms = ((file_size.st_size)*160)/304; 2421 break; 2422 } 2423 if(!strcmp("#!iLBC30\n", buf)) 2424 { 2425 // 30 ms takes 400 bits. 2426 // file size in bytes * 8 / 400 is the number of 2427 // 30 ms frames in the file -> 2428 // time_in_ms = file size * 8 / 400 * 30 2429 time_in_ms = ((file_size.st_size)*240)/400; 2430 break; 2431 } 2432 #endif 2433 break; 2434 } 2435 case kFileFormatPreencodedFile: 2436 { 2437 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 2438 "cannot determine duration of Pre-Encoded file!"); 2439 break; 2440 } 2441 default: 2442 WEBRTC_TRACE(kTraceError, kTraceFile, _id, 2443 "unsupported file format %d!", fileFormat); 2444 break; 2445 } 2446 inStreamObj->CloseFile(); 2447 delete inStreamObj; 2448 return time_in_ms; 2449 } 2450 2451 uint32_t ModuleFileUtility::PlayoutPositionMs() 2452 { 2453 WEBRTC_TRACE(kTraceStream, kTraceFile, _id, 2454 "ModuleFileUtility::PlayoutPosition()"); 2455 2456 if(_reading) 2457 { 2458 return _playoutPositionMs; 2459 } 2460 else 2461 { 2462 return 0; 2463 } 2464 } 2465 } // namespace webrtc 2466