blob: 29ad9e3fe18cde26b97ad2467753baa564655635 [file] [log] [blame]
/*
* 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/interface/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<size_t>(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