Move FilePlayer and FileRecorder to Voice Engine
Because Voice Engine was the only user. (We have tried to land this many times before. I'm hoping that this time all external dependencies on these files will really be gone.) BUG=none Review-Url: https://codereview.webrtc.org/2622493002 Cr-Commit-Position: refs/heads/master@{#15978}
This commit is contained in:
@ -231,8 +231,6 @@ if (rtc_include_tests) {
|
||||
"//resources/synthetic-trace.rx",
|
||||
"//resources/tmobile-downlink.rx",
|
||||
"//resources/tmobile-uplink.rx",
|
||||
"//resources/utility/encapsulated_pcm16b_8khz.wav",
|
||||
"//resources/utility/encapsulated_pcmu_8khz.wav",
|
||||
"//resources/verizon3g-downlink.rx",
|
||||
"//resources/verizon3g-uplink.rx",
|
||||
"//resources/verizon4g-downlink.rx",
|
||||
@ -483,7 +481,6 @@ if (rtc_include_tests) {
|
||||
"rtp_rtcp/test/testAPI/test_api_audio.cc",
|
||||
"rtp_rtcp/test/testAPI/test_api_rtcp.cc",
|
||||
"rtp_rtcp/test/testAPI/test_api_video.cc",
|
||||
"utility/source/file_player_unittests.cc",
|
||||
"utility/source/process_thread_impl_unittest.cc",
|
||||
"video_coding/codecs/test/packet_manipulator_unittest.cc",
|
||||
"video_coding/codecs/test/stats_unittest.cc",
|
||||
|
||||
@ -11,15 +11,9 @@ import("../../build/webrtc.gni")
|
||||
rtc_static_library("utility") {
|
||||
sources = [
|
||||
"include/audio_frame_operations.h",
|
||||
"include/file_player.h",
|
||||
"include/file_recorder.h",
|
||||
"include/helpers_android.h",
|
||||
"include/jvm_android.h",
|
||||
"include/process_thread.h",
|
||||
"source/coder.cc",
|
||||
"source/coder.h",
|
||||
"source/file_player.cc",
|
||||
"source/file_recorder.cc",
|
||||
"source/helpers_android.cc",
|
||||
"source/jvm_android.cc",
|
||||
"source/process_thread_impl.cc",
|
||||
|
||||
@ -1,80 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_UTILITY_INCLUDE_FILE_PLAYER_H_
|
||||
#define WEBRTC_MODULES_UTILITY_INCLUDE_FILE_PLAYER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/include/module_common_types.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class FileCallback;
|
||||
|
||||
class FilePlayer {
|
||||
public:
|
||||
// The largest decoded frame size in samples (60ms with 32kHz sample rate).
|
||||
enum { MAX_AUDIO_BUFFER_IN_SAMPLES = 60 * 32 };
|
||||
enum { MAX_AUDIO_BUFFER_IN_BYTES = MAX_AUDIO_BUFFER_IN_SAMPLES * 2 };
|
||||
|
||||
// Note: will return NULL for unsupported formats.
|
||||
static std::unique_ptr<FilePlayer> CreateFilePlayer(
|
||||
const uint32_t instanceID,
|
||||
const FileFormats fileFormat);
|
||||
|
||||
virtual ~FilePlayer() = default;
|
||||
|
||||
// Read 10 ms of audio at |frequencyInHz| to |outBuffer|. |lengthInSamples|
|
||||
// will be set to the number of samples read (not the number of samples per
|
||||
// channel).
|
||||
virtual int Get10msAudioFromFile(int16_t* outBuffer,
|
||||
size_t* lengthInSamples,
|
||||
int frequencyInHz) = 0;
|
||||
|
||||
// Register callback for receiving file playing notifications.
|
||||
virtual int32_t RegisterModuleFileCallback(FileCallback* callback) = 0;
|
||||
|
||||
// API for playing audio from fileName to channel.
|
||||
// Note: codecInst is used for pre-encoded files.
|
||||
virtual int32_t StartPlayingFile(const char* fileName,
|
||||
bool loop,
|
||||
uint32_t startPosition,
|
||||
float volumeScaling,
|
||||
uint32_t notification,
|
||||
uint32_t stopPosition,
|
||||
const CodecInst* codecInst) = 0;
|
||||
|
||||
// Note: codecInst is used for pre-encoded files.
|
||||
virtual int32_t StartPlayingFile(InStream* sourceStream,
|
||||
uint32_t startPosition,
|
||||
float volumeScaling,
|
||||
uint32_t notification,
|
||||
uint32_t stopPosition,
|
||||
const CodecInst* codecInst) = 0;
|
||||
|
||||
virtual int32_t StopPlayingFile() = 0;
|
||||
|
||||
virtual bool IsPlayingFile() const = 0;
|
||||
|
||||
virtual int32_t GetPlayoutPosition(uint32_t* durationMs) = 0;
|
||||
|
||||
// Set audioCodec to the currently used audio codec.
|
||||
virtual int32_t AudioCodec(CodecInst* audioCodec) const = 0;
|
||||
|
||||
virtual int32_t Frequency() const = 0;
|
||||
|
||||
// Note: scaleFactor is in the range [0.0 - 2.0]
|
||||
virtual int32_t SetAudioScaling(float scaleFactor) = 0;
|
||||
};
|
||||
} // namespace webrtc
|
||||
#endif // WEBRTC_MODULES_UTILITY_INCLUDE_FILE_PLAYER_H_
|
||||
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_UTILITY_INCLUDE_FILE_RECORDER_H_
|
||||
#define WEBRTC_MODULES_UTILITY_INCLUDE_FILE_RECORDER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/include/module_common_types.h"
|
||||
#include "webrtc/modules/media_file/media_file_defines.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class FileRecorder {
|
||||
public:
|
||||
// Note: will return NULL for unsupported formats.
|
||||
static std::unique_ptr<FileRecorder> CreateFileRecorder(
|
||||
const uint32_t instanceID,
|
||||
const FileFormats fileFormat);
|
||||
|
||||
virtual ~FileRecorder() = default;
|
||||
|
||||
virtual int32_t RegisterModuleFileCallback(FileCallback* callback) = 0;
|
||||
|
||||
virtual FileFormats RecordingFileFormat() const = 0;
|
||||
|
||||
virtual int32_t StartRecordingAudioFile(const char* fileName,
|
||||
const CodecInst& codecInst,
|
||||
uint32_t notification) = 0;
|
||||
|
||||
virtual int32_t StartRecordingAudioFile(OutStream* destStream,
|
||||
const CodecInst& codecInst,
|
||||
uint32_t notification) = 0;
|
||||
|
||||
// Stop recording.
|
||||
virtual int32_t StopRecording() = 0;
|
||||
|
||||
// Return true if recording.
|
||||
virtual bool IsRecording() const = 0;
|
||||
|
||||
virtual int32_t codec_info(CodecInst* codecInst) const = 0;
|
||||
|
||||
// Write frame to file. Frame should contain 10ms of un-ecoded audio data.
|
||||
virtual int32_t RecordAudioToFile(const AudioFrame& frame) = 0;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // WEBRTC_MODULES_UTILITY_INCLUDE_FILE_RECORDER_H_
|
||||
@ -1,116 +0,0 @@
|
||||
/*
|
||||
* 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/common_types.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/audio_format_conversion.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.h"
|
||||
#include "webrtc/modules/include/module_common_types.h"
|
||||
#include "webrtc/modules/utility/source/coder.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
AudioCodingModule::Config GetAcmConfig(uint32_t id) {
|
||||
AudioCodingModule::Config config;
|
||||
// This class does not handle muted output.
|
||||
config.neteq_config.enable_muted_state = false;
|
||||
config.id = id;
|
||||
config.decoder_factory = CreateBuiltinAudioDecoderFactory();
|
||||
return config;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
AudioCoder::AudioCoder(uint32_t instance_id)
|
||||
: acm_(AudioCodingModule::Create(GetAcmConfig(instance_id))),
|
||||
receive_codec_(),
|
||||
encode_timestamp_(0),
|
||||
encoded_data_(nullptr),
|
||||
encoded_length_in_bytes_(0),
|
||||
decode_timestamp_(0) {
|
||||
acm_->InitializeReceiver();
|
||||
acm_->RegisterTransportCallback(this);
|
||||
}
|
||||
|
||||
AudioCoder::~AudioCoder() {}
|
||||
|
||||
int32_t AudioCoder::SetEncodeCodec(const CodecInst& codec_inst) {
|
||||
const bool success = codec_manager_.RegisterEncoder(codec_inst) &&
|
||||
codec_manager_.MakeEncoder(&rent_a_codec_, acm_.get());
|
||||
return success ? 0 : -1;
|
||||
}
|
||||
|
||||
int32_t AudioCoder::SetDecodeCodec(const CodecInst& codec_inst) {
|
||||
if (!acm_->RegisterReceiveCodec(codec_inst.pltype,
|
||||
CodecInstToSdp(codec_inst))) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(&receive_codec_, &codec_inst, sizeof(CodecInst));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t AudioCoder::Decode(AudioFrame* decoded_audio,
|
||||
uint32_t samp_freq_hz,
|
||||
const int8_t* incoming_payload,
|
||||
size_t payload_length) {
|
||||
if (payload_length > 0) {
|
||||
const uint8_t payload_type = receive_codec_.pltype;
|
||||
decode_timestamp_ += receive_codec_.pacsize;
|
||||
if (acm_->IncomingPayload((const uint8_t*)incoming_payload, payload_length,
|
||||
payload_type, decode_timestamp_) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
bool muted;
|
||||
int32_t ret =
|
||||
acm_->PlayoutData10Ms((uint16_t)samp_freq_hz, decoded_audio, &muted);
|
||||
RTC_DCHECK(!muted);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t AudioCoder::PlayoutData(AudioFrame* decoded_audio,
|
||||
uint16_t samp_freq_hz) {
|
||||
bool muted;
|
||||
int32_t ret = acm_->PlayoutData10Ms(samp_freq_hz, decoded_audio, &muted);
|
||||
RTC_DCHECK(!muted);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t AudioCoder::Encode(const AudioFrame& audio,
|
||||
int8_t* encoded_data,
|
||||
size_t* encoded_length_in_bytes) {
|
||||
// Fake a timestamp in case audio doesn't contain a correct timestamp.
|
||||
// Make a local copy of the audio frame since audio is const
|
||||
AudioFrame audio_frame;
|
||||
audio_frame.CopyFrom(audio);
|
||||
audio_frame.timestamp_ = encode_timestamp_;
|
||||
encode_timestamp_ += static_cast<uint32_t>(audio_frame.samples_per_channel_);
|
||||
|
||||
// For any codec with a frame size that is longer than 10 ms the encoded
|
||||
// length in bytes should be zero until a a full frame has been encoded.
|
||||
encoded_length_in_bytes_ = 0;
|
||||
if (acm_->Add10MsData((AudioFrame&)audio_frame) == -1) {
|
||||
return -1;
|
||||
}
|
||||
encoded_data_ = encoded_data;
|
||||
*encoded_length_in_bytes = encoded_length_in_bytes_;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t AudioCoder::SendData(FrameType /* frame_type */,
|
||||
uint8_t /* payload_type */,
|
||||
uint32_t /* time_stamp */,
|
||||
const uint8_t* payload_data,
|
||||
size_t payload_size,
|
||||
const RTPFragmentationHeader* /* fragmentation*/) {
|
||||
memcpy(encoded_data_, payload_data, sizeof(uint8_t) * payload_size);
|
||||
encoded_length_in_bytes_ = payload_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_UTILITY_SOURCE_CODER_H_
|
||||
#define WEBRTC_MODULES_UTILITY_SOURCE_CODER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/audio_coding/acm2/codec_manager.h"
|
||||
#include "webrtc/modules/audio_coding/acm2/rent_a_codec.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
class AudioFrame;
|
||||
|
||||
class AudioCoder : public AudioPacketizationCallback {
|
||||
public:
|
||||
explicit AudioCoder(uint32_t instance_id);
|
||||
~AudioCoder();
|
||||
|
||||
int32_t SetEncodeCodec(const CodecInst& codec_inst);
|
||||
|
||||
int32_t SetDecodeCodec(const CodecInst& codec_inst);
|
||||
|
||||
int32_t Decode(AudioFrame* decoded_audio,
|
||||
uint32_t samp_freq_hz,
|
||||
const int8_t* incoming_payload,
|
||||
size_t payload_length);
|
||||
|
||||
int32_t PlayoutData(AudioFrame* decoded_audio, uint16_t samp_freq_hz);
|
||||
|
||||
int32_t Encode(const AudioFrame& audio,
|
||||
int8_t* encoded_data,
|
||||
size_t* encoded_length_in_bytes);
|
||||
|
||||
protected:
|
||||
int32_t SendData(FrameType frame_type,
|
||||
uint8_t payload_type,
|
||||
uint32_t time_stamp,
|
||||
const uint8_t* payload_data,
|
||||
size_t payload_size,
|
||||
const RTPFragmentationHeader* fragmentation) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<AudioCodingModule> acm_;
|
||||
acm2::CodecManager codec_manager_;
|
||||
acm2::RentACodec rent_a_codec_;
|
||||
|
||||
CodecInst receive_codec_;
|
||||
|
||||
uint32_t encode_timestamp_;
|
||||
int8_t* encoded_data_;
|
||||
size_t encoded_length_in_bytes_;
|
||||
|
||||
uint32_t decode_timestamp_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_UTILITY_SOURCE_CODER_H_
|
||||
@ -1,392 +0,0 @@
|
||||
/*
|
||||
* 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/include/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/modules/utility/source/coder.h"
|
||||
#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
|
||||
#include "webrtc/system_wrappers/include/logging.h"
|
||||
#include "webrtc/typedefs.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 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(
|
||||
reinterpret_cast<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(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 = 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
|
||||
|
||||
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:
|
||||
// audio formats
|
||||
return std::unique_ptr<FilePlayer>(
|
||||
new FilePlayerImpl(instanceID, fileFormat));
|
||||
default:
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 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.
|
||||
*/
|
||||
|
||||
// Unit tests for FilePlayer.
|
||||
|
||||
#include "webrtc/modules/utility/include/file_player.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "gflags/gflags.h"
|
||||
#include "webrtc/base/md5digest.h"
|
||||
#include "webrtc/base/stringencode.h"
|
||||
#include "webrtc/test/gtest.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
DEFINE_bool(file_player_output, false, "Generate reference files.");
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class FilePlayerTest : public ::testing::Test {
|
||||
protected:
|
||||
static const uint32_t kId = 0;
|
||||
static const FileFormats kFileFormat = kFileFormatWavFile;
|
||||
static const int kSampleRateHz = 8000;
|
||||
|
||||
FilePlayerTest()
|
||||
: player_(FilePlayer::CreateFilePlayer(kId, kFileFormat)),
|
||||
output_file_(NULL) {}
|
||||
|
||||
void SetUp() override {
|
||||
if (FLAGS_file_player_output) {
|
||||
std::string output_file =
|
||||
webrtc::test::OutputPath() + "file_player_unittest_out.pcm";
|
||||
output_file_ = fopen(output_file.c_str(), "wb");
|
||||
ASSERT_TRUE(output_file_ != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
if (output_file_)
|
||||
fclose(output_file_);
|
||||
}
|
||||
|
||||
void PlayFileAndCheck(const std::string& input_file,
|
||||
const std::string& ref_checksum,
|
||||
int output_length_ms) {
|
||||
const float kScaling = 1;
|
||||
ASSERT_EQ(0, player_->StartPlayingFile(input_file.c_str(), false, 0,
|
||||
kScaling, 0, 0, NULL));
|
||||
rtc::Md5Digest checksum;
|
||||
for (int i = 0; i < output_length_ms / 10; ++i) {
|
||||
int16_t out[10 * kSampleRateHz / 1000] = {0};
|
||||
size_t num_samples;
|
||||
EXPECT_EQ(
|
||||
0, player_->Get10msAudioFromFile(out, &num_samples, kSampleRateHz));
|
||||
checksum.Update(out, num_samples * sizeof(out[0]));
|
||||
if (FLAGS_file_player_output) {
|
||||
ASSERT_EQ(num_samples,
|
||||
fwrite(out, sizeof(out[0]), num_samples, output_file_));
|
||||
}
|
||||
}
|
||||
char checksum_result[rtc::Md5Digest::kSize];
|
||||
EXPECT_EQ(rtc::Md5Digest::kSize,
|
||||
checksum.Finish(checksum_result, rtc::Md5Digest::kSize));
|
||||
EXPECT_EQ(ref_checksum,
|
||||
rtc::hex_encode(checksum_result, sizeof(checksum_result)));
|
||||
}
|
||||
|
||||
std::unique_ptr<FilePlayer> player_;
|
||||
FILE* output_file_;
|
||||
};
|
||||
|
||||
#if defined(WEBRTC_IOS)
|
||||
#define MAYBE_PlayWavPcmuFile DISABLED_PlayWavPcmuFile
|
||||
#else
|
||||
#define MAYBE_PlayWavPcmuFile PlayWavPcmuFile
|
||||
#endif
|
||||
TEST_F(FilePlayerTest, MAYBE_PlayWavPcmuFile) {
|
||||
const std::string kFileName =
|
||||
test::ResourcePath("utility/encapsulated_pcmu_8khz", "wav");
|
||||
// The file is longer than this, but keeping the output shorter limits the
|
||||
// runtime for the test.
|
||||
const int kOutputLengthMs = 10000;
|
||||
const std::string kRefChecksum = "c74e7fd432d439b1311e1c16815b3e9a";
|
||||
|
||||
PlayFileAndCheck(kFileName, kRefChecksum, kOutputLengthMs);
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_IOS)
|
||||
#define MAYBE_PlayWavPcm16File DISABLED_PlayWavPcm16File
|
||||
#else
|
||||
#define MAYBE_PlayWavPcm16File PlayWavPcm16File
|
||||
#endif
|
||||
TEST_F(FilePlayerTest, MAYBE_PlayWavPcm16File) {
|
||||
const std::string kFileName =
|
||||
test::ResourcePath("utility/encapsulated_pcm16b_8khz", "wav");
|
||||
// The file is longer than this, but keeping the output shorter limits the
|
||||
// runtime for the test.
|
||||
const int kOutputLengthMs = 10000;
|
||||
const std::string kRefChecksum = "e41d7e1dac8aeae9f21e8e03cd7ecd71";
|
||||
|
||||
PlayFileAndCheck(kFileName, kRefChecksum, kOutputLengthMs);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -1,262 +0,0 @@
|
||||
/*
|
||||
* 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/include/file_recorder.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "webrtc/base/platform_thread.h"
|
||||
#include "webrtc/common_audio/resampler/include/resampler.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/include/module_common_types.h"
|
||||
#include "webrtc/modules/media_file/media_file.h"
|
||||
#include "webrtc/modules/media_file/media_file_defines.h"
|
||||
#include "webrtc/modules/utility/source/coder.h"
|
||||
#include "webrtc/system_wrappers/include/event_wrapper.h"
|
||||
#include "webrtc/system_wrappers/include/logging.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
// The largest decoded frame size in samples (60ms with 32kHz sample rate).
|
||||
enum { MAX_AUDIO_BUFFER_IN_SAMPLES = 60 * 32 };
|
||||
enum { MAX_AUDIO_BUFFER_IN_BYTES = MAX_AUDIO_BUFFER_IN_SAMPLES * 2 };
|
||||
enum { kMaxAudioBufferQueueLength = 100 };
|
||||
|
||||
class CriticalSectionWrapper;
|
||||
|
||||
class FileRecorderImpl : public FileRecorder {
|
||||
public:
|
||||
FileRecorderImpl(uint32_t instanceID, FileFormats fileFormat);
|
||||
~FileRecorderImpl() override;
|
||||
|
||||
// FileRecorder functions.
|
||||
int32_t RegisterModuleFileCallback(FileCallback* callback) override;
|
||||
FileFormats RecordingFileFormat() const override;
|
||||
int32_t StartRecordingAudioFile(const char* fileName,
|
||||
const CodecInst& codecInst,
|
||||
uint32_t notificationTimeMs) override;
|
||||
int32_t StartRecordingAudioFile(OutStream* destStream,
|
||||
const CodecInst& codecInst,
|
||||
uint32_t notificationTimeMs) override;
|
||||
int32_t StopRecording() override;
|
||||
bool IsRecording() const override;
|
||||
int32_t codec_info(CodecInst* codecInst) const override;
|
||||
int32_t RecordAudioToFile(const AudioFrame& frame) override;
|
||||
|
||||
private:
|
||||
int32_t WriteEncodedAudioData(const int8_t* audioBuffer, size_t bufferLength);
|
||||
|
||||
int32_t SetUpAudioEncoder();
|
||||
|
||||
uint32_t _instanceID;
|
||||
FileFormats _fileFormat;
|
||||
MediaFile* _moduleFile;
|
||||
|
||||
CodecInst codec_info_;
|
||||
int8_t _audioBuffer[MAX_AUDIO_BUFFER_IN_BYTES];
|
||||
AudioCoder _audioEncoder;
|
||||
Resampler _audioResampler;
|
||||
};
|
||||
|
||||
FileRecorderImpl::FileRecorderImpl(uint32_t instanceID, FileFormats fileFormat)
|
||||
: _instanceID(instanceID),
|
||||
_fileFormat(fileFormat),
|
||||
_moduleFile(MediaFile::CreateMediaFile(_instanceID)),
|
||||
codec_info_(),
|
||||
_audioBuffer(),
|
||||
_audioEncoder(instanceID),
|
||||
_audioResampler() {}
|
||||
|
||||
FileRecorderImpl::~FileRecorderImpl() {
|
||||
MediaFile::DestroyMediaFile(_moduleFile);
|
||||
}
|
||||
|
||||
FileFormats FileRecorderImpl::RecordingFileFormat() const {
|
||||
return _fileFormat;
|
||||
}
|
||||
|
||||
int32_t FileRecorderImpl::RegisterModuleFileCallback(FileCallback* callback) {
|
||||
if (_moduleFile == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return _moduleFile->SetModuleFileCallback(callback);
|
||||
}
|
||||
|
||||
int32_t FileRecorderImpl::StartRecordingAudioFile(const char* fileName,
|
||||
const CodecInst& codecInst,
|
||||
uint32_t notificationTimeMs) {
|
||||
if (_moduleFile == NULL) {
|
||||
return -1;
|
||||
}
|
||||
codec_info_ = codecInst;
|
||||
int32_t retVal = 0;
|
||||
retVal = _moduleFile->StartRecordingAudioFile(fileName, _fileFormat,
|
||||
codecInst, notificationTimeMs);
|
||||
|
||||
if (retVal == 0) {
|
||||
retVal = SetUpAudioEncoder();
|
||||
}
|
||||
if (retVal != 0) {
|
||||
LOG(LS_WARNING) << "Failed to initialize file " << fileName
|
||||
<< " for recording.";
|
||||
|
||||
if (IsRecording()) {
|
||||
StopRecording();
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
int32_t FileRecorderImpl::StartRecordingAudioFile(OutStream* destStream,
|
||||
const CodecInst& codecInst,
|
||||
uint32_t notificationTimeMs) {
|
||||
codec_info_ = codecInst;
|
||||
int32_t retVal = _moduleFile->StartRecordingAudioStream(
|
||||
*destStream, _fileFormat, codecInst, notificationTimeMs);
|
||||
|
||||
if (retVal == 0) {
|
||||
retVal = SetUpAudioEncoder();
|
||||
}
|
||||
if (retVal != 0) {
|
||||
LOG(LS_WARNING) << "Failed to initialize outStream for recording.";
|
||||
|
||||
if (IsRecording()) {
|
||||
StopRecording();
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
int32_t FileRecorderImpl::StopRecording() {
|
||||
memset(&codec_info_, 0, sizeof(CodecInst));
|
||||
return _moduleFile->StopRecording();
|
||||
}
|
||||
|
||||
bool FileRecorderImpl::IsRecording() const {
|
||||
return _moduleFile->IsRecording();
|
||||
}
|
||||
|
||||
int32_t FileRecorderImpl::RecordAudioToFile(
|
||||
const AudioFrame& incomingAudioFrame) {
|
||||
if (codec_info_.plfreq == 0) {
|
||||
LOG(LS_WARNING) << "RecordAudioToFile() recording audio is not "
|
||||
<< "turned on.";
|
||||
return -1;
|
||||
}
|
||||
AudioFrame tempAudioFrame;
|
||||
tempAudioFrame.samples_per_channel_ = 0;
|
||||
if (incomingAudioFrame.num_channels_ == 2 && !_moduleFile->IsStereo()) {
|
||||
// Recording mono but incoming audio is (interleaved) stereo.
|
||||
tempAudioFrame.num_channels_ = 1;
|
||||
tempAudioFrame.sample_rate_hz_ = incomingAudioFrame.sample_rate_hz_;
|
||||
tempAudioFrame.samples_per_channel_ =
|
||||
incomingAudioFrame.samples_per_channel_;
|
||||
for (size_t i = 0; i < (incomingAudioFrame.samples_per_channel_); i++) {
|
||||
// Sample value is the average of left and right buffer rounded to
|
||||
// closest integer value. Note samples can be either 1 or 2 byte.
|
||||
tempAudioFrame.data_[i] = ((incomingAudioFrame.data_[2 * i] +
|
||||
incomingAudioFrame.data_[(2 * i) + 1] + 1) >>
|
||||
1);
|
||||
}
|
||||
} else if (incomingAudioFrame.num_channels_ == 1 && _moduleFile->IsStereo()) {
|
||||
// Recording stereo but incoming audio is mono.
|
||||
tempAudioFrame.num_channels_ = 2;
|
||||
tempAudioFrame.sample_rate_hz_ = incomingAudioFrame.sample_rate_hz_;
|
||||
tempAudioFrame.samples_per_channel_ =
|
||||
incomingAudioFrame.samples_per_channel_;
|
||||
for (size_t i = 0; i < (incomingAudioFrame.samples_per_channel_); i++) {
|
||||
// Duplicate sample to both channels
|
||||
tempAudioFrame.data_[2 * i] = incomingAudioFrame.data_[i];
|
||||
tempAudioFrame.data_[2 * i + 1] = incomingAudioFrame.data_[i];
|
||||
}
|
||||
}
|
||||
|
||||
const AudioFrame* ptrAudioFrame = &incomingAudioFrame;
|
||||
if (tempAudioFrame.samples_per_channel_ != 0) {
|
||||
// If ptrAudioFrame is not empty it contains the audio to be recorded.
|
||||
ptrAudioFrame = &tempAudioFrame;
|
||||
}
|
||||
|
||||
// Encode the audio data before writing to file. Don't encode if the codec
|
||||
// is PCM.
|
||||
// NOTE: stereo recording is only supported for WAV files.
|
||||
// TODO(hellner): WAV expect PCM in little endian byte order. Not
|
||||
// "encoding" with PCM coder should be a problem for big endian systems.
|
||||
size_t encodedLenInBytes = 0;
|
||||
if (_fileFormat == kFileFormatPreencodedFile ||
|
||||
STR_CASE_CMP(codec_info_.plname, "L16") != 0) {
|
||||
if (_audioEncoder.Encode(*ptrAudioFrame, _audioBuffer,
|
||||
&encodedLenInBytes) == -1) {
|
||||
LOG(LS_WARNING) << "RecordAudioToFile() codec " << codec_info_.plname
|
||||
<< " not supported or failed to encode stream.";
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
size_t outLen = 0;
|
||||
_audioResampler.ResetIfNeeded(ptrAudioFrame->sample_rate_hz_,
|
||||
codec_info_.plfreq,
|
||||
ptrAudioFrame->num_channels_);
|
||||
_audioResampler.Push(
|
||||
ptrAudioFrame->data_,
|
||||
ptrAudioFrame->samples_per_channel_ * ptrAudioFrame->num_channels_,
|
||||
reinterpret_cast<int16_t*>(_audioBuffer), MAX_AUDIO_BUFFER_IN_BYTES,
|
||||
outLen);
|
||||
encodedLenInBytes = outLen * sizeof(int16_t);
|
||||
}
|
||||
|
||||
// Codec may not be operating at a frame rate of 10 ms. Whenever enough
|
||||
// 10 ms chunks of data has been pushed to the encoder an encoded frame
|
||||
// will be available. Wait until then.
|
||||
if (encodedLenInBytes) {
|
||||
if (WriteEncodedAudioData(_audioBuffer, encodedLenInBytes) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t FileRecorderImpl::SetUpAudioEncoder() {
|
||||
if (_fileFormat == kFileFormatPreencodedFile ||
|
||||
STR_CASE_CMP(codec_info_.plname, "L16") != 0) {
|
||||
if (_audioEncoder.SetEncodeCodec(codec_info_) == -1) {
|
||||
LOG(LS_ERROR) << "SetUpAudioEncoder() codec " << codec_info_.plname
|
||||
<< " not supported.";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t FileRecorderImpl::codec_info(CodecInst* codecInst) const {
|
||||
if (codec_info_.plfreq == 0) {
|
||||
return -1;
|
||||
}
|
||||
*codecInst = codec_info_;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t FileRecorderImpl::WriteEncodedAudioData(const int8_t* audioBuffer,
|
||||
size_t bufferLength) {
|
||||
return _moduleFile->IncomingAudioData(audioBuffer, bufferLength);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<FileRecorder> FileRecorder::CreateFileRecorder(
|
||||
uint32_t instanceID,
|
||||
FileFormats fileFormat) {
|
||||
return std::unique_ptr<FileRecorder>(
|
||||
new FileRecorderImpl(instanceID, fileFormat));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
Reference in New Issue
Block a user