In order to eliminate the WebRTC Subtree mirror in Chromium, WebRTC is moving the content of the src/webrtc directory up to the src/ directory. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true TBR=tommi@webrtc.org Bug: chromium:611808 Change-Id: Iac59c5b51b950f174119565bac87955a7994bc38 Reviewed-on: https://webrtc-review.googlesource.com/1560 Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Henrik Kjellander <kjellander@webrtc.org> Cr-Commit-Position: refs/heads/master@{#19845}
398 lines
13 KiB
C++
398 lines
13 KiB
C++
/*
|
|
* 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/voice_engine/file_player.h"
|
|
|
|
#include "webrtc/common_audio/resampler/include/resampler.h"
|
|
#include "webrtc/common_types.h"
|
|
#include "webrtc/modules/media_file/media_file.h"
|
|
#include "webrtc/modules/media_file/media_file_defines.h"
|
|
#include "webrtc/rtc_base/logging.h"
|
|
#include "webrtc/typedefs.h"
|
|
#include "webrtc/voice_engine/coder.h"
|
|
|
|
namespace webrtc {
|
|
|
|
namespace {
|
|
|
|
class FilePlayerImpl : public FilePlayer {
|
|
public:
|
|
FilePlayerImpl(uint32_t instanceID, FileFormats fileFormat);
|
|
~FilePlayerImpl() override;
|
|
|
|
int Get10msAudioFromFile(int16_t* outBuffer,
|
|
size_t* lengthInSamples,
|
|
int frequencyInHz) override;
|
|
int32_t RegisterModuleFileCallback(FileCallback* callback) override;
|
|
int32_t StartPlayingFile(const char* fileName,
|
|
bool loop,
|
|
uint32_t startPosition,
|
|
float volumeScaling,
|
|
uint32_t notification,
|
|
uint32_t stopPosition,
|
|
const CodecInst* codecInst) override;
|
|
int32_t StartPlayingFile(InStream* sourceStream,
|
|
uint32_t startPosition,
|
|
float volumeScaling,
|
|
uint32_t notification,
|
|
uint32_t stopPosition,
|
|
const CodecInst* codecInst) override;
|
|
int32_t StopPlayingFile() override;
|
|
bool IsPlayingFile() const override;
|
|
int32_t GetPlayoutPosition(uint32_t* durationMs) override;
|
|
int32_t AudioCodec(CodecInst* audioCodec) const override;
|
|
int32_t Frequency() const override;
|
|
int32_t SetAudioScaling(float scaleFactor) override;
|
|
|
|
private:
|
|
int32_t SetUpAudioDecoder();
|
|
|
|
const FileFormats _fileFormat;
|
|
MediaFile& _fileModule;
|
|
|
|
uint32_t _decodedLengthInMS;
|
|
|
|
AudioCoder _audioDecoder;
|
|
|
|
CodecInst _codec;
|
|
int32_t _numberOf10MsPerFrame;
|
|
int32_t _numberOf10MsInDecoder;
|
|
|
|
Resampler _resampler;
|
|
float _scaling;
|
|
};
|
|
|
|
FilePlayerImpl::FilePlayerImpl(const uint32_t instanceID,
|
|
const FileFormats fileFormat)
|
|
: _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 48000;
|
|
} 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 = AudioFrame::kMaxDataSizeBytes;
|
|
if (_fileModule.PlayoutAudioData(
|
|
reinterpret_cast<int8_t*>(unresampledAudioFrame.mutable_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(reinterpret_cast<int8_t*>(encodedBuffer),
|
|
bytesFromFile) == -1) {
|
|
// End of file reached.
|
|
return -1;
|
|
}
|
|
encodedLengthInBytes = bytesFromFile;
|
|
}
|
|
if (_audioDecoder.Decode(&unresampledAudioFrame, frequencyInHz,
|
|
reinterpret_cast<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 = 320;
|
|
} else if (_fileFormat == kFileFormatPcm48kHzFile) {
|
|
codecInstL16.rate = 768000;
|
|
codecInstL16.plfreq = 48000;
|
|
codecInstL16.pacsize = 480;
|
|
} 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 ||
|
|
_fileFormat == kFileFormatPcm48kHzFile) {
|
|
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 = 320;
|
|
} else if (_fileFormat == kFileFormatPcm48kHzFile) {
|
|
codecInstL16.rate = 768000;
|
|
codecInstL16.plfreq = 48000;
|
|
codecInstL16.pacsize = 480;
|
|
} 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
|
|
|
|
std::unique_ptr<FilePlayer> FilePlayer::CreateFilePlayer(
|
|
uint32_t instanceID,
|
|
FileFormats fileFormat) {
|
|
switch (fileFormat) {
|
|
case kFileFormatWavFile:
|
|
case kFileFormatCompressedFile:
|
|
case kFileFormatPreencodedFile:
|
|
case kFileFormatPcm16kHzFile:
|
|
case kFileFormatPcm8kHzFile:
|
|
case kFileFormatPcm32kHzFile:
|
|
case kFileFormatPcm48kHzFile:
|
|
// audio formats
|
|
return std::unique_ptr<FilePlayer>(
|
|
new FilePlayerImpl(instanceID, fileFormat));
|
|
default:
|
|
assert(false);
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
} // namespace webrtc
|