/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "webrtc/modules/utility/source/file_player_impl.h" #include "webrtc/system_wrappers/include/logging.h" namespace webrtc { FilePlayer* FilePlayer::CreateFilePlayer(uint32_t instanceID, FileFormats fileFormat) { switch(fileFormat) { case kFileFormatWavFile: case kFileFormatCompressedFile: case kFileFormatPreencodedFile: case kFileFormatPcm16kHzFile: case kFileFormatPcm8kHzFile: case kFileFormatPcm32kHzFile: // audio formats return new FilePlayerImpl(instanceID, fileFormat); default: assert(false); return NULL; } } void FilePlayer::DestroyFilePlayer(FilePlayer* player) { delete player; } FilePlayerImpl::FilePlayerImpl(const uint32_t instanceID, const FileFormats fileFormat) : _instanceID(instanceID), _fileFormat(fileFormat), _fileModule(*MediaFile::CreateMediaFile(instanceID)), _decodedLengthInMS(0), _audioDecoder(instanceID), _codec(), _numberOf10MsPerFrame(0), _numberOf10MsInDecoder(0), _resampler(), _scaling(1.0) { _codec.plfreq = 0; } FilePlayerImpl::~FilePlayerImpl() { MediaFile::DestroyMediaFile(&_fileModule); } int32_t FilePlayerImpl::Frequency() const { if(_codec.plfreq == 0) { return -1; } // Make sure that sample rate is 8,16 or 32 kHz. E.g. WAVE files may have // other sampling rates. if(_codec.plfreq == 11000) { return 16000; } else if(_codec.plfreq == 22000) { return 32000; } else if(_codec.plfreq == 44000) { return 32000; } else if(_codec.plfreq == 48000) { return 32000; } else { return _codec.plfreq; } } int32_t FilePlayerImpl::AudioCodec(CodecInst& audioCodec) const { audioCodec = _codec; return 0; } int32_t FilePlayerImpl::Get10msAudioFromFile( int16_t* outBuffer, size_t& lengthInSamples, int frequencyInHz) { if(_codec.plfreq == 0) { LOG(LS_WARNING) << "Get10msAudioFromFile() playing not started!" << " codec freq = " << _codec.plfreq << ", wanted freq = " << frequencyInHz; return -1; } AudioFrame unresampledAudioFrame; if(STR_CASE_CMP(_codec.plname, "L16") == 0) { unresampledAudioFrame.sample_rate_hz_ = _codec.plfreq; // L16 is un-encoded data. Just pull 10 ms. size_t lengthInBytes = sizeof(unresampledAudioFrame.data_); if (_fileModule.PlayoutAudioData( (int8_t*)unresampledAudioFrame.data_, lengthInBytes) == -1) { // End of file reached. return -1; } if(lengthInBytes == 0) { lengthInSamples = 0; return 0; } // One sample is two bytes. unresampledAudioFrame.samples_per_channel_ = lengthInBytes >> 1; } else { // Decode will generate 10 ms of audio data. PlayoutAudioData(..) // expects a full frame. If the frame size is larger than 10 ms, // PlayoutAudioData(..) data should be called proportionally less often. int16_t encodedBuffer[MAX_AUDIO_BUFFER_IN_SAMPLES]; size_t encodedLengthInBytes = 0; if(++_numberOf10MsInDecoder >= _numberOf10MsPerFrame) { _numberOf10MsInDecoder = 0; size_t bytesFromFile = sizeof(encodedBuffer); if (_fileModule.PlayoutAudioData((int8_t*)encodedBuffer, bytesFromFile) == -1) { // End of file reached. return -1; } encodedLengthInBytes = bytesFromFile; } if(_audioDecoder.Decode(unresampledAudioFrame,frequencyInHz, (int8_t*)encodedBuffer, encodedLengthInBytes) == -1) { return -1; } } size_t outLen = 0; if(_resampler.ResetIfNeeded(unresampledAudioFrame.sample_rate_hz_, frequencyInHz, 1)) { LOG(LS_WARNING) << "Get10msAudioFromFile() unexpected codec."; // New sampling frequency. Update state. outLen = static_cast(frequencyInHz / 100); memset(outBuffer, 0, outLen * sizeof(int16_t)); return 0; } _resampler.Push(unresampledAudioFrame.data_, unresampledAudioFrame.samples_per_channel_, outBuffer, MAX_AUDIO_BUFFER_IN_SAMPLES, outLen); lengthInSamples = outLen; if(_scaling != 1.0) { for (size_t i = 0;i < outLen; i++) { outBuffer[i] = (int16_t)(outBuffer[i] * _scaling); } } _decodedLengthInMS += 10; return 0; } int32_t FilePlayerImpl::RegisterModuleFileCallback(FileCallback* callback) { return _fileModule.SetModuleFileCallback(callback); } int32_t FilePlayerImpl::SetAudioScaling(float scaleFactor) { if((scaleFactor >= 0)&&(scaleFactor <= 2.0)) { _scaling = scaleFactor; return 0; } LOG(LS_WARNING) << "SetAudioScaling() non-allowed scale factor."; return -1; } int32_t FilePlayerImpl::StartPlayingFile(const char* fileName, bool loop, uint32_t startPosition, float volumeScaling, uint32_t notification, uint32_t stopPosition, const CodecInst* codecInst) { if (_fileFormat == kFileFormatPcm16kHzFile || _fileFormat == kFileFormatPcm8kHzFile|| _fileFormat == kFileFormatPcm32kHzFile ) { CodecInst codecInstL16; strncpy(codecInstL16.plname,"L16",32); codecInstL16.pltype = 93; codecInstL16.channels = 1; if (_fileFormat == kFileFormatPcm8kHzFile) { codecInstL16.rate = 128000; codecInstL16.plfreq = 8000; codecInstL16.pacsize = 80; } else if(_fileFormat == kFileFormatPcm16kHzFile) { codecInstL16.rate = 256000; codecInstL16.plfreq = 16000; codecInstL16.pacsize = 160; }else if(_fileFormat == kFileFormatPcm32kHzFile) { codecInstL16.rate = 512000; codecInstL16.plfreq = 32000; codecInstL16.pacsize = 160; } else { LOG(LS_ERROR) << "StartPlayingFile() sample frequency not " << "supported for PCM format."; return -1; } if (_fileModule.StartPlayingAudioFile(fileName, notification, loop, _fileFormat, &codecInstL16, startPosition, stopPosition) == -1) { LOG(LS_WARNING) << "StartPlayingFile() failed to initialize " << "pcm file " << fileName; return -1; } SetAudioScaling(volumeScaling); }else if(_fileFormat == kFileFormatPreencodedFile) { if (_fileModule.StartPlayingAudioFile(fileName, notification, loop, _fileFormat, codecInst) == -1) { LOG(LS_WARNING) << "StartPlayingFile() failed to initialize " << "pre-encoded file " << fileName; return -1; } } else { CodecInst* no_inst = NULL; if (_fileModule.StartPlayingAudioFile(fileName, notification, loop, _fileFormat, no_inst, startPosition, stopPosition) == -1) { LOG(LS_WARNING) << "StartPlayingFile() failed to initialize file " << fileName; return -1; } SetAudioScaling(volumeScaling); } if (SetUpAudioDecoder() == -1) { StopPlayingFile(); return -1; } return 0; } int32_t FilePlayerImpl::StartPlayingFile(InStream& sourceStream, uint32_t startPosition, float volumeScaling, uint32_t notification, uint32_t stopPosition, const CodecInst* codecInst) { if (_fileFormat == kFileFormatPcm16kHzFile || _fileFormat == kFileFormatPcm32kHzFile || _fileFormat == kFileFormatPcm8kHzFile) { CodecInst codecInstL16; strncpy(codecInstL16.plname,"L16",32); codecInstL16.pltype = 93; codecInstL16.channels = 1; if (_fileFormat == kFileFormatPcm8kHzFile) { codecInstL16.rate = 128000; codecInstL16.plfreq = 8000; codecInstL16.pacsize = 80; }else if (_fileFormat == kFileFormatPcm16kHzFile) { codecInstL16.rate = 256000; codecInstL16.plfreq = 16000; codecInstL16.pacsize = 160; }else if (_fileFormat == kFileFormatPcm32kHzFile) { codecInstL16.rate = 512000; codecInstL16.plfreq = 32000; codecInstL16.pacsize = 160; }else { LOG(LS_ERROR) << "StartPlayingFile() sample frequency not " << "supported for PCM format."; return -1; } if (_fileModule.StartPlayingAudioStream(sourceStream, notification, _fileFormat, &codecInstL16, startPosition, stopPosition) == -1) { LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream " << "playout."; return -1; } }else if(_fileFormat == kFileFormatPreencodedFile) { if (_fileModule.StartPlayingAudioStream(sourceStream, notification, _fileFormat, codecInst) == -1) { LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream " << "playout."; return -1; } } else { CodecInst* no_inst = NULL; if (_fileModule.StartPlayingAudioStream(sourceStream, notification, _fileFormat, no_inst, startPosition, stopPosition) == -1) { LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream " << "playout."; return -1; } } SetAudioScaling(volumeScaling); if (SetUpAudioDecoder() == -1) { StopPlayingFile(); return -1; } return 0; } int32_t FilePlayerImpl::StopPlayingFile() { memset(&_codec, 0, sizeof(CodecInst)); _numberOf10MsPerFrame = 0; _numberOf10MsInDecoder = 0; return _fileModule.StopPlaying(); } bool FilePlayerImpl::IsPlayingFile() const { return _fileModule.IsPlaying(); } int32_t FilePlayerImpl::GetPlayoutPosition(uint32_t& durationMs) { return _fileModule.PlayoutPositionMs(durationMs); } int32_t FilePlayerImpl::SetUpAudioDecoder() { if ((_fileModule.codec_info(_codec) == -1)) { LOG(LS_WARNING) << "Failed to retrieve codec info of file data."; return -1; } if( STR_CASE_CMP(_codec.plname, "L16") != 0 && _audioDecoder.SetDecodeCodec(_codec) == -1) { LOG(LS_WARNING) << "SetUpAudioDecoder() codec " << _codec.plname << " not supported."; return -1; } _numberOf10MsPerFrame = _codec.pacsize / (_codec.plfreq / 100); _numberOf10MsInDecoder = 0; return 0; } } // namespace webrtc