Remove VoEFile and things it uses.
BUG=webrtc:4690 Review-Url: https://codereview.webrtc.org/3013033002 Cr-Commit-Position: refs/heads/master@{#19885}
This commit is contained in:
parent
2352ce3c43
commit
b63310a256
@ -134,55 +134,6 @@ class MockVoiceEngine : public VoiceEngineImpl {
|
||||
MOCK_METHOD2(SetOpusMaxPlaybackRate, int(int channel, int frequency_hz));
|
||||
MOCK_METHOD2(SetOpusDtx, int(int channel, bool enable_dtx));
|
||||
|
||||
// VoEFile
|
||||
MOCK_METHOD7(StartPlayingFileLocally,
|
||||
int(int channel,
|
||||
const char fileNameUTF8[1024],
|
||||
bool loop,
|
||||
FileFormats format,
|
||||
float volumeScaling,
|
||||
int startPointMs,
|
||||
int stopPointMs));
|
||||
MOCK_METHOD6(StartPlayingFileLocally,
|
||||
int(int channel,
|
||||
InStream* stream,
|
||||
FileFormats format,
|
||||
float volumeScaling,
|
||||
int startPointMs,
|
||||
int stopPointMs));
|
||||
MOCK_METHOD1(StopPlayingFileLocally, int(int channel));
|
||||
MOCK_METHOD1(IsPlayingFileLocally, int(int channel));
|
||||
MOCK_METHOD6(StartPlayingFileAsMicrophone,
|
||||
int(int channel,
|
||||
const char fileNameUTF8[1024],
|
||||
bool loop,
|
||||
bool mixWithMicrophone,
|
||||
FileFormats format,
|
||||
float volumeScaling));
|
||||
MOCK_METHOD5(StartPlayingFileAsMicrophone,
|
||||
int(int channel,
|
||||
InStream* stream,
|
||||
bool mixWithMicrophone,
|
||||
FileFormats format,
|
||||
float volumeScaling));
|
||||
MOCK_METHOD1(StopPlayingFileAsMicrophone, int(int channel));
|
||||
MOCK_METHOD1(IsPlayingFileAsMicrophone, int(int channel));
|
||||
MOCK_METHOD4(StartRecordingPlayout,
|
||||
int(int channel,
|
||||
const char* fileNameUTF8,
|
||||
CodecInst* compression,
|
||||
int maxSizeBytes));
|
||||
MOCK_METHOD1(StopRecordingPlayout, int(int channel));
|
||||
MOCK_METHOD3(StartRecordingPlayout,
|
||||
int(int channel, OutStream* stream, CodecInst* compression));
|
||||
MOCK_METHOD3(StartRecordingMicrophone,
|
||||
int(const char* fileNameUTF8,
|
||||
CodecInst* compression,
|
||||
int maxSizeBytes));
|
||||
MOCK_METHOD2(StartRecordingMicrophone,
|
||||
int(OutStream* stream, CodecInst* compression));
|
||||
MOCK_METHOD0(StopRecordingMicrophone, int());
|
||||
|
||||
// VoENetwork
|
||||
MOCK_METHOD2(RegisterExternalTransport,
|
||||
int(int channel, Transport& transport));
|
||||
|
||||
@ -8,69 +8,6 @@
|
||||
|
||||
import("../webrtc.gni")
|
||||
|
||||
rtc_static_library("audio_coder") {
|
||||
sources = [
|
||||
"coder.cc",
|
||||
"coder.h",
|
||||
]
|
||||
deps = [
|
||||
"..:webrtc_common",
|
||||
"../api/audio_codecs:builtin_audio_decoder_factory",
|
||||
"../api/audio_codecs:builtin_audio_encoder_factory",
|
||||
"../modules:module_api",
|
||||
"../modules/audio_coding",
|
||||
"../modules/audio_coding:audio_format_conversion",
|
||||
"../modules/audio_coding:rent_a_codec",
|
||||
]
|
||||
|
||||
if (!build_with_chromium && is_clang) {
|
||||
# Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
|
||||
suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
|
||||
}
|
||||
}
|
||||
|
||||
rtc_static_library("file_player") {
|
||||
sources = [
|
||||
"file_player.cc",
|
||||
"file_player.h",
|
||||
]
|
||||
deps = [
|
||||
":audio_coder",
|
||||
"..:webrtc_common",
|
||||
"../common_audio",
|
||||
"../modules:module_api",
|
||||
"../modules/media_file",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
]
|
||||
|
||||
if (!build_with_chromium && is_clang) {
|
||||
# Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
|
||||
suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
|
||||
}
|
||||
}
|
||||
|
||||
rtc_static_library("file_recorder") {
|
||||
sources = [
|
||||
"file_recorder.cc",
|
||||
"file_recorder.h",
|
||||
]
|
||||
deps = [
|
||||
":audio_coder",
|
||||
"..:webrtc_common",
|
||||
"../audio/utility:audio_frame_operations",
|
||||
"../common_audio",
|
||||
"../modules:module_api",
|
||||
"../modules/media_file:media_file",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
"../system_wrappers",
|
||||
]
|
||||
|
||||
if (!build_with_chromium && is_clang) {
|
||||
# Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
|
||||
suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
|
||||
}
|
||||
}
|
||||
|
||||
rtc_static_library("voice_engine") {
|
||||
sources = [
|
||||
"channel.cc",
|
||||
@ -82,7 +19,6 @@ rtc_static_library("voice_engine") {
|
||||
"include/voe_base.h",
|
||||
"include/voe_codec.h",
|
||||
"include/voe_errors.h",
|
||||
"include/voe_file.h",
|
||||
"include/voe_network.h",
|
||||
"include/voe_rtp_rtcp.h",
|
||||
"monitor_module.h",
|
||||
@ -102,8 +38,6 @@ rtc_static_library("voice_engine") {
|
||||
"voe_base_impl.h",
|
||||
"voe_codec_impl.cc",
|
||||
"voe_codec_impl.h",
|
||||
"voe_file_impl.cc",
|
||||
"voe_file_impl.h",
|
||||
"voe_network_impl.cc",
|
||||
"voe_network_impl.h",
|
||||
"voe_rtp_rtcp_impl.cc",
|
||||
@ -132,8 +66,6 @@ rtc_static_library("voice_engine") {
|
||||
]
|
||||
deps = [
|
||||
":audio_level",
|
||||
":file_player",
|
||||
":file_recorder",
|
||||
"..:webrtc_common",
|
||||
"../api:array_view",
|
||||
"../api:audio_mixer_api",
|
||||
@ -182,7 +114,6 @@ rtc_static_library("audio_level") {
|
||||
if (rtc_include_tests) {
|
||||
rtc_test("voice_engine_unittests") {
|
||||
deps = [
|
||||
":file_player",
|
||||
":voice_engine",
|
||||
"../common_audio",
|
||||
"../modules:module_api",
|
||||
@ -211,7 +142,6 @@ if (rtc_include_tests) {
|
||||
|
||||
sources = [
|
||||
"channel_unittest.cc",
|
||||
"file_player_unittests.cc",
|
||||
"transport_feedback_packet_loss_tracker_unittest.cc",
|
||||
"utility_unittest.cc",
|
||||
"voe_base_unittest.cc",
|
||||
|
||||
@ -651,8 +651,6 @@ MixerParticipant::AudioFrameInfo Channel::GetAudioFrameWithMuted(
|
||||
// Store speech type for dead-or-alive detection
|
||||
_outputSpeechType = audioFrame->speech_type_;
|
||||
|
||||
ChannelState::State state = channel_state_.Get();
|
||||
|
||||
{
|
||||
// Pass the audio buffers to an optional sink callback, before applying
|
||||
// scaling/panning, as that applies to the mix operation.
|
||||
@ -680,21 +678,6 @@ MixerParticipant::AudioFrameInfo Channel::GetAudioFrameWithMuted(
|
||||
AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
|
||||
}
|
||||
|
||||
// Mix decoded PCM output with file if file mixing is enabled
|
||||
if (state.output_file_playing) {
|
||||
MixAudioWithFile(*audioFrame, audioFrame->sample_rate_hz_);
|
||||
muted = false; // We may have added non-zero samples.
|
||||
}
|
||||
|
||||
// Record playout if enabled
|
||||
{
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
|
||||
if (_outputFileRecording && output_file_recorder_) {
|
||||
output_file_recorder_->RecordAudioToFile(*audioFrame);
|
||||
}
|
||||
}
|
||||
|
||||
// Measure audio level (0-9)
|
||||
// TODO(henrik.lundin) Use the |muted| information here too.
|
||||
// TODO(deadbeef): Use RmsLevel for |_outputAudioLevel| (see
|
||||
@ -774,20 +757,7 @@ int32_t Channel::NeededFrequency(int32_t id) const {
|
||||
highestNeeded = receiveFrequency;
|
||||
}
|
||||
|
||||
// Special case, if we're playing a file on the playout side
|
||||
// we take that frequency into consideration as well
|
||||
// This is not needed on sending side, since the codec will
|
||||
// limit the spectrum anyway.
|
||||
if (channel_state_.Get().output_file_playing) {
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
if (output_file_player_) {
|
||||
if (output_file_player_->Frequency() > highestNeeded) {
|
||||
highestNeeded = output_file_player_->Frequency();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (highestNeeded);
|
||||
return highestNeeded;
|
||||
}
|
||||
|
||||
int32_t Channel::CreateChannel(Channel*& channel,
|
||||
@ -808,53 +778,6 @@ int32_t Channel::CreateChannel(Channel*& channel,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Channel::PlayNotification(int32_t id, uint32_t durationMs) {
|
||||
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::PlayNotification(id=%d, durationMs=%d)", id,
|
||||
durationMs);
|
||||
|
||||
// Not implement yet
|
||||
}
|
||||
|
||||
void Channel::RecordNotification(int32_t id, uint32_t durationMs) {
|
||||
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::RecordNotification(id=%d, durationMs=%d)", id,
|
||||
durationMs);
|
||||
|
||||
// Not implement yet
|
||||
}
|
||||
|
||||
void Channel::PlayFileEnded(int32_t id) {
|
||||
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::PlayFileEnded(id=%d)", id);
|
||||
|
||||
if (id == _inputFilePlayerId) {
|
||||
channel_state_.SetInputFilePlaying(false);
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::PlayFileEnded() => input file player module is"
|
||||
" shutdown");
|
||||
} else if (id == _outputFilePlayerId) {
|
||||
channel_state_.SetOutputFilePlaying(false);
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::PlayFileEnded() => output file player module is"
|
||||
" shutdown");
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::RecordFileEnded(int32_t id) {
|
||||
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::RecordFileEnded(id=%d)", id);
|
||||
|
||||
assert(id == _outputFileRecorderId);
|
||||
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
|
||||
_outputFileRecording = false;
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::RecordFileEnded() => output file recorder module is"
|
||||
" shutdown");
|
||||
}
|
||||
|
||||
Channel::Channel(int32_t channelId,
|
||||
uint32_t instanceId,
|
||||
const VoEBase::ChannelConfig& config)
|
||||
@ -874,12 +797,6 @@ Channel::Channel(int32_t channelId,
|
||||
telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
|
||||
_outputAudioLevel(),
|
||||
_externalTransport(false),
|
||||
// Avoid conflict with other channels by adding 1024 - 1026,
|
||||
// won't use as much as 1024 channels.
|
||||
_inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
|
||||
_outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
|
||||
_outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
|
||||
_outputFileRecording(false),
|
||||
_timeStamp(0), // This is just an offset, RTP module will add it's own
|
||||
// random offset
|
||||
ntp_estimator_(Clock::GetRealTimeClock()),
|
||||
@ -899,7 +816,6 @@ Channel::Channel(int32_t channelId,
|
||||
input_mute_(false),
|
||||
previous_frame_muted_(false),
|
||||
_outputGain(1.0f),
|
||||
_mixFileWithMicrophone(false),
|
||||
_includeAudioLevelIndication(false),
|
||||
transport_overhead_per_packet_(0),
|
||||
rtp_overhead_per_packet_(0),
|
||||
@ -1088,22 +1004,6 @@ void Channel::Terminate() {
|
||||
StopSend();
|
||||
StopPlayout();
|
||||
|
||||
{
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
if (input_file_player_) {
|
||||
input_file_player_->RegisterModuleFileCallback(NULL);
|
||||
input_file_player_->StopPlayingFile();
|
||||
}
|
||||
if (output_file_player_) {
|
||||
output_file_player_->RegisterModuleFileCallback(NULL);
|
||||
output_file_player_->StopPlayingFile();
|
||||
}
|
||||
if (output_file_recorder_) {
|
||||
output_file_recorder_->RegisterModuleFileCallback(NULL);
|
||||
output_file_recorder_->StopRecording();
|
||||
}
|
||||
}
|
||||
|
||||
// The order to safely shutdown modules in a channel is:
|
||||
// 1. De-register callbacks in modules
|
||||
// 2. De-register modules in process thread
|
||||
@ -1174,8 +1074,6 @@ int32_t Channel::StartPlayout() {
|
||||
}
|
||||
|
||||
channel_state_.SetPlaying(true);
|
||||
if (RegisterFilePlayingToMixer() != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1823,508 +1721,6 @@ int32_t Channel::ReceivedRTCPPacket(const uint8_t* data, size_t length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Channel::StartPlayingFileLocally(const char* fileName,
|
||||
bool loop,
|
||||
FileFormats format,
|
||||
int startPosition,
|
||||
float volumeScaling,
|
||||
int stopPosition,
|
||||
const CodecInst* codecInst) {
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
|
||||
" format=%d, volumeScaling=%5.3f, startPosition=%d, "
|
||||
"stopPosition=%d)",
|
||||
fileName, loop, format, volumeScaling, startPosition,
|
||||
stopPosition);
|
||||
|
||||
if (channel_state_.Get().output_file_playing) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_ALREADY_PLAYING, kTraceError,
|
||||
"StartPlayingFileLocally() is already playing");
|
||||
return -1;
|
||||
}
|
||||
|
||||
{
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
|
||||
if (output_file_player_) {
|
||||
output_file_player_->RegisterModuleFileCallback(NULL);
|
||||
output_file_player_.reset();
|
||||
}
|
||||
|
||||
output_file_player_ = FilePlayer::CreateFilePlayer(
|
||||
_outputFilePlayerId, (const FileFormats)format);
|
||||
|
||||
if (!output_file_player_) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_INVALID_ARGUMENT, kTraceError,
|
||||
"StartPlayingFileLocally() filePlayer format is not correct");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint32_t notificationTime(0);
|
||||
|
||||
if (output_file_player_->StartPlayingFile(
|
||||
fileName, loop, startPosition, volumeScaling, notificationTime,
|
||||
stopPosition, (const CodecInst*)codecInst) != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_FILE, kTraceError,
|
||||
"StartPlayingFile() failed to start file playout");
|
||||
output_file_player_->StopPlayingFile();
|
||||
output_file_player_.reset();
|
||||
return -1;
|
||||
}
|
||||
output_file_player_->RegisterModuleFileCallback(this);
|
||||
channel_state_.SetOutputFilePlaying(true);
|
||||
}
|
||||
|
||||
if (RegisterFilePlayingToMixer() != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Channel::StartPlayingFileLocally(InStream* stream,
|
||||
FileFormats format,
|
||||
int startPosition,
|
||||
float volumeScaling,
|
||||
int stopPosition,
|
||||
const CodecInst* codecInst) {
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::StartPlayingFileLocally(format=%d,"
|
||||
" volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
|
||||
format, volumeScaling, startPosition, stopPosition);
|
||||
|
||||
if (stream == NULL) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_FILE, kTraceError,
|
||||
"StartPlayingFileLocally() NULL as input stream");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (channel_state_.Get().output_file_playing) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_ALREADY_PLAYING, kTraceError,
|
||||
"StartPlayingFileLocally() is already playing");
|
||||
return -1;
|
||||
}
|
||||
|
||||
{
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
|
||||
// Destroy the old instance
|
||||
if (output_file_player_) {
|
||||
output_file_player_->RegisterModuleFileCallback(NULL);
|
||||
output_file_player_.reset();
|
||||
}
|
||||
|
||||
// Create the instance
|
||||
output_file_player_ = FilePlayer::CreateFilePlayer(
|
||||
_outputFilePlayerId, (const FileFormats)format);
|
||||
|
||||
if (!output_file_player_) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_INVALID_ARGUMENT, kTraceError,
|
||||
"StartPlayingFileLocally() filePlayer format isnot correct");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint32_t notificationTime(0);
|
||||
|
||||
if (output_file_player_->StartPlayingFile(stream, startPosition,
|
||||
volumeScaling, notificationTime,
|
||||
stopPosition, codecInst) != 0) {
|
||||
_engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
|
||||
"StartPlayingFile() failed to "
|
||||
"start file playout");
|
||||
output_file_player_->StopPlayingFile();
|
||||
output_file_player_.reset();
|
||||
return -1;
|
||||
}
|
||||
output_file_player_->RegisterModuleFileCallback(this);
|
||||
channel_state_.SetOutputFilePlaying(true);
|
||||
}
|
||||
|
||||
if (RegisterFilePlayingToMixer() != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Channel::StopPlayingFileLocally() {
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::StopPlayingFileLocally()");
|
||||
|
||||
if (!channel_state_.Get().output_file_playing) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
{
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
|
||||
if (output_file_player_->StopPlayingFile() != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_STOP_RECORDING_FAILED, kTraceError,
|
||||
"StopPlayingFile() could not stop playing");
|
||||
return -1;
|
||||
}
|
||||
output_file_player_->RegisterModuleFileCallback(NULL);
|
||||
output_file_player_.reset();
|
||||
channel_state_.SetOutputFilePlaying(false);
|
||||
}
|
||||
// _fileCritSect cannot be taken while calling
|
||||
// SetAnonymousMixibilityStatus. Refer to comments in
|
||||
// StartPlayingFileLocally(const char* ...) for more details.
|
||||
if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
|
||||
"StopPlayingFile() failed to stop participant from playing as"
|
||||
"file in the mixer");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Channel::IsPlayingFileLocally() const {
|
||||
return channel_state_.Get().output_file_playing;
|
||||
}
|
||||
|
||||
int Channel::RegisterFilePlayingToMixer() {
|
||||
// Return success for not registering for file playing to mixer if:
|
||||
// 1. playing file before playout is started on that channel.
|
||||
// 2. starting playout without file playing on that channel.
|
||||
if (!channel_state_.Get().playing ||
|
||||
!channel_state_.Get().output_file_playing) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// |_fileCritSect| cannot be taken while calling
|
||||
// SetAnonymousMixabilityStatus() since as soon as the participant is added
|
||||
// frames can be pulled by the mixer. Since the frames are generated from
|
||||
// the file, _fileCritSect will be taken. This would result in a deadlock.
|
||||
if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0) {
|
||||
channel_state_.SetOutputFilePlaying(false);
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
|
||||
"StartPlayingFile() failed to add participant as file to mixer");
|
||||
output_file_player_->StopPlayingFile();
|
||||
output_file_player_.reset();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Channel::StartPlayingFileAsMicrophone(const char* fileName,
|
||||
bool loop,
|
||||
FileFormats format,
|
||||
int startPosition,
|
||||
float volumeScaling,
|
||||
int stopPosition,
|
||||
const CodecInst* codecInst) {
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
|
||||
"loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
|
||||
"stopPosition=%d)",
|
||||
fileName, loop, format, volumeScaling, startPosition,
|
||||
stopPosition);
|
||||
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
|
||||
if (channel_state_.Get().input_file_playing) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_ALREADY_PLAYING, kTraceWarning,
|
||||
"StartPlayingFileAsMicrophone() filePlayer is playing");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Destroy the old instance
|
||||
if (input_file_player_) {
|
||||
input_file_player_->RegisterModuleFileCallback(NULL);
|
||||
input_file_player_.reset();
|
||||
}
|
||||
|
||||
// Create the instance
|
||||
input_file_player_ = FilePlayer::CreateFilePlayer(_inputFilePlayerId,
|
||||
(const FileFormats)format);
|
||||
|
||||
if (!input_file_player_) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_INVALID_ARGUMENT, kTraceError,
|
||||
"StartPlayingFileAsMicrophone() filePlayer format isnot correct");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint32_t notificationTime(0);
|
||||
|
||||
if (input_file_player_->StartPlayingFile(
|
||||
fileName, loop, startPosition, volumeScaling, notificationTime,
|
||||
stopPosition, (const CodecInst*)codecInst) != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_FILE, kTraceError,
|
||||
"StartPlayingFile() failed to start file playout");
|
||||
input_file_player_->StopPlayingFile();
|
||||
input_file_player_.reset();
|
||||
return -1;
|
||||
}
|
||||
input_file_player_->RegisterModuleFileCallback(this);
|
||||
channel_state_.SetInputFilePlaying(true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Channel::StartPlayingFileAsMicrophone(InStream* stream,
|
||||
FileFormats format,
|
||||
int startPosition,
|
||||
float volumeScaling,
|
||||
int stopPosition,
|
||||
const CodecInst* codecInst) {
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::StartPlayingFileAsMicrophone(format=%d, "
|
||||
"volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
|
||||
format, volumeScaling, startPosition, stopPosition);
|
||||
|
||||
if (stream == NULL) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_FILE, kTraceError,
|
||||
"StartPlayingFileAsMicrophone NULL as input stream");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
|
||||
if (channel_state_.Get().input_file_playing) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_ALREADY_PLAYING, kTraceWarning,
|
||||
"StartPlayingFileAsMicrophone() is playing");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Destroy the old instance
|
||||
if (input_file_player_) {
|
||||
input_file_player_->RegisterModuleFileCallback(NULL);
|
||||
input_file_player_.reset();
|
||||
}
|
||||
|
||||
// Create the instance
|
||||
input_file_player_ = FilePlayer::CreateFilePlayer(_inputFilePlayerId,
|
||||
(const FileFormats)format);
|
||||
|
||||
if (!input_file_player_) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_INVALID_ARGUMENT, kTraceError,
|
||||
"StartPlayingInputFile() filePlayer format isnot correct");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint32_t notificationTime(0);
|
||||
|
||||
if (input_file_player_->StartPlayingFile(stream, startPosition, volumeScaling,
|
||||
notificationTime, stopPosition,
|
||||
codecInst) != 0) {
|
||||
_engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
|
||||
"StartPlayingFile() failed to start "
|
||||
"file playout");
|
||||
input_file_player_->StopPlayingFile();
|
||||
input_file_player_.reset();
|
||||
return -1;
|
||||
}
|
||||
|
||||
input_file_player_->RegisterModuleFileCallback(this);
|
||||
channel_state_.SetInputFilePlaying(true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Channel::StopPlayingFileAsMicrophone() {
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::StopPlayingFileAsMicrophone()");
|
||||
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
|
||||
if (!channel_state_.Get().input_file_playing) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (input_file_player_->StopPlayingFile() != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_STOP_RECORDING_FAILED, kTraceError,
|
||||
"StopPlayingFile() could not stop playing");
|
||||
return -1;
|
||||
}
|
||||
input_file_player_->RegisterModuleFileCallback(NULL);
|
||||
input_file_player_.reset();
|
||||
channel_state_.SetInputFilePlaying(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Channel::IsPlayingFileAsMicrophone() const {
|
||||
return channel_state_.Get().input_file_playing;
|
||||
}
|
||||
|
||||
int Channel::StartRecordingPlayout(const char* fileName,
|
||||
const CodecInst* codecInst) {
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::StartRecordingPlayout(fileName=%s)", fileName);
|
||||
|
||||
if (_outputFileRecording) {
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"StartRecordingPlayout() is already recording");
|
||||
return 0;
|
||||
}
|
||||
|
||||
FileFormats format;
|
||||
const uint32_t notificationTime(0); // Not supported in VoE
|
||||
CodecInst dummyCodec = {100, "L16", 16000, 320, 1, 320000};
|
||||
|
||||
if ((codecInst != NULL) &&
|
||||
((codecInst->channels < 1) || (codecInst->channels > 2))) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_ARGUMENT, kTraceError,
|
||||
"StartRecordingPlayout() invalid compression");
|
||||
return (-1);
|
||||
}
|
||||
if (codecInst == NULL) {
|
||||
format = kFileFormatPcm16kHzFile;
|
||||
codecInst = &dummyCodec;
|
||||
} else if ((STR_CASE_CMP(codecInst->plname, "L16") == 0) ||
|
||||
(STR_CASE_CMP(codecInst->plname, "PCMU") == 0) ||
|
||||
(STR_CASE_CMP(codecInst->plname, "PCMA") == 0)) {
|
||||
format = kFileFormatWavFile;
|
||||
} else {
|
||||
format = kFileFormatCompressedFile;
|
||||
}
|
||||
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
|
||||
// Destroy the old instance
|
||||
if (output_file_recorder_) {
|
||||
output_file_recorder_->RegisterModuleFileCallback(NULL);
|
||||
output_file_recorder_.reset();
|
||||
}
|
||||
|
||||
output_file_recorder_ = FileRecorder::CreateFileRecorder(
|
||||
_outputFileRecorderId, (const FileFormats)format);
|
||||
if (!output_file_recorder_) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_INVALID_ARGUMENT, kTraceError,
|
||||
"StartRecordingPlayout() fileRecorder format isnot correct");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (output_file_recorder_->StartRecordingAudioFile(
|
||||
fileName, (const CodecInst&)*codecInst, notificationTime) != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_FILE, kTraceError,
|
||||
"StartRecordingAudioFile() failed to start file recording");
|
||||
output_file_recorder_->StopRecording();
|
||||
output_file_recorder_.reset();
|
||||
return -1;
|
||||
}
|
||||
output_file_recorder_->RegisterModuleFileCallback(this);
|
||||
_outputFileRecording = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Channel::StartRecordingPlayout(OutStream* stream,
|
||||
const CodecInst* codecInst) {
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::StartRecordingPlayout()");
|
||||
|
||||
if (_outputFileRecording) {
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"StartRecordingPlayout() is already recording");
|
||||
return 0;
|
||||
}
|
||||
|
||||
FileFormats format;
|
||||
const uint32_t notificationTime(0); // Not supported in VoE
|
||||
CodecInst dummyCodec = {100, "L16", 16000, 320, 1, 320000};
|
||||
|
||||
if (codecInst != NULL && codecInst->channels != 1) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_ARGUMENT, kTraceError,
|
||||
"StartRecordingPlayout() invalid compression");
|
||||
return (-1);
|
||||
}
|
||||
if (codecInst == NULL) {
|
||||
format = kFileFormatPcm16kHzFile;
|
||||
codecInst = &dummyCodec;
|
||||
} else if ((STR_CASE_CMP(codecInst->plname, "L16") == 0) ||
|
||||
(STR_CASE_CMP(codecInst->plname, "PCMU") == 0) ||
|
||||
(STR_CASE_CMP(codecInst->plname, "PCMA") == 0)) {
|
||||
format = kFileFormatWavFile;
|
||||
} else {
|
||||
format = kFileFormatCompressedFile;
|
||||
}
|
||||
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
|
||||
// Destroy the old instance
|
||||
if (output_file_recorder_) {
|
||||
output_file_recorder_->RegisterModuleFileCallback(NULL);
|
||||
output_file_recorder_.reset();
|
||||
}
|
||||
|
||||
output_file_recorder_ = FileRecorder::CreateFileRecorder(
|
||||
_outputFileRecorderId, (const FileFormats)format);
|
||||
if (!output_file_recorder_) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_INVALID_ARGUMENT, kTraceError,
|
||||
"StartRecordingPlayout() fileRecorder format isnot correct");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (output_file_recorder_->StartRecordingAudioFile(stream, *codecInst,
|
||||
notificationTime) != 0) {
|
||||
_engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
|
||||
"StartRecordingPlayout() failed to "
|
||||
"start file recording");
|
||||
output_file_recorder_->StopRecording();
|
||||
output_file_recorder_.reset();
|
||||
return -1;
|
||||
}
|
||||
|
||||
output_file_recorder_->RegisterModuleFileCallback(this);
|
||||
_outputFileRecording = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Channel::StopRecordingPlayout() {
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"Channel::StopRecordingPlayout()");
|
||||
|
||||
if (!_outputFileRecording) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"StopRecordingPlayout() isnot recording");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
|
||||
if (output_file_recorder_->StopRecording() != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_STOP_RECORDING_FAILED, kTraceError,
|
||||
"StopRecording() could not stop recording");
|
||||
return (-1);
|
||||
}
|
||||
output_file_recorder_->RegisterModuleFileCallback(NULL);
|
||||
output_file_recorder_.reset();
|
||||
_outputFileRecording = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Channel::SetMixWithMicStatus(bool mix) {
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
_mixFileWithMicrophone = mix;
|
||||
}
|
||||
|
||||
int Channel::GetSpeechOutputLevel() const {
|
||||
return _outputAudioLevel.Level();
|
||||
}
|
||||
@ -2760,10 +2156,6 @@ void Channel::ProcessAndEncodeAudioOnTaskQueue(AudioFrame* audio_input) {
|
||||
RTC_DCHECK_LE(audio_input->num_channels_, 2);
|
||||
RTC_DCHECK_EQ(audio_input->id_, ChannelId());
|
||||
|
||||
if (channel_state_.Get().input_file_playing) {
|
||||
MixOrReplaceAudioWithFile(audio_input);
|
||||
}
|
||||
|
||||
bool is_muted = InputMute();
|
||||
AudioFrameOperations::Mute(audio_input, previous_frame_muted_, is_muted);
|
||||
|
||||
@ -2903,96 +2295,6 @@ int Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule,
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
|
||||
// a shared helper.
|
||||
int32_t Channel::MixOrReplaceAudioWithFile(AudioFrame* audio_input) {
|
||||
RTC_DCHECK_RUN_ON(encoder_queue_);
|
||||
std::unique_ptr<int16_t[]> fileBuffer(new int16_t[640]);
|
||||
size_t fileSamples(0);
|
||||
const int mixingFrequency = audio_input->sample_rate_hz_;
|
||||
{
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
|
||||
if (!input_file_player_) {
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::MixOrReplaceAudioWithFile() fileplayer"
|
||||
" doesnt exist");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (input_file_player_->Get10msAudioFromFile(fileBuffer.get(), &fileSamples,
|
||||
mixingFrequency) == -1) {
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::MixOrReplaceAudioWithFile() file mixing "
|
||||
"failed");
|
||||
return -1;
|
||||
}
|
||||
if (fileSamples == 0) {
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::MixOrReplaceAudioWithFile() file is ended");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
RTC_DCHECK_EQ(audio_input->samples_per_channel_, fileSamples);
|
||||
|
||||
if (_mixFileWithMicrophone) {
|
||||
// Currently file stream is always mono.
|
||||
// TODO(xians): Change the code when FilePlayer supports real stereo.
|
||||
MixWithSat(audio_input->mutable_data(), audio_input->num_channels_,
|
||||
fileBuffer.get(), 1, fileSamples);
|
||||
} else {
|
||||
// Replace ACM audio with file.
|
||||
// Currently file stream is always mono.
|
||||
// TODO(xians): Change the code when FilePlayer supports real stereo.
|
||||
audio_input->UpdateFrame(
|
||||
_channelId, 0xFFFFFFFF, fileBuffer.get(), fileSamples, mixingFrequency,
|
||||
AudioFrame::kNormalSpeech, AudioFrame::kVadUnknown, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t Channel::MixAudioWithFile(AudioFrame& audioFrame, int mixingFrequency) {
|
||||
assert(mixingFrequency <= 48000);
|
||||
|
||||
std::unique_ptr<int16_t[]> fileBuffer(new int16_t[960]);
|
||||
size_t fileSamples(0);
|
||||
|
||||
{
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
|
||||
if (!output_file_player_) {
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::MixAudioWithFile() file mixing failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// We should get the frequency we ask for.
|
||||
if (output_file_player_->Get10msAudioFromFile(
|
||||
fileBuffer.get(), &fileSamples, mixingFrequency) == -1) {
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::MixAudioWithFile() file mixing failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (audioFrame.samples_per_channel_ == fileSamples) {
|
||||
// Currently file stream is always mono.
|
||||
// TODO(xians): Change the code when FilePlayer supports real stereo.
|
||||
MixWithSat(audioFrame.mutable_data(), audioFrame.num_channels_,
|
||||
fileBuffer.get(), 1, fileSamples);
|
||||
} else {
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
|
||||
"Channel::MixAudioWithFile() samples_per_channel_(%" PRIuS
|
||||
") != "
|
||||
"fileSamples(%" PRIuS ")",
|
||||
audioFrame.samples_per_channel_, fileSamples);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Channel::UpdatePlayoutTimestamp(bool rtcp) {
|
||||
jitter_buffer_playout_timestamp_ = audio_coding_->PlayoutTimestamp();
|
||||
|
||||
|
||||
@ -32,8 +32,6 @@
|
||||
#include "rtc_base/event.h"
|
||||
#include "rtc_base/thread_checker.h"
|
||||
#include "voice_engine/audio_level.h"
|
||||
#include "voice_engine/file_player.h"
|
||||
#include "voice_engine/file_recorder.h"
|
||||
#include "voice_engine/include/voe_base.h"
|
||||
#include "voice_engine/include/voe_network.h"
|
||||
#include "voice_engine/shared_data.h"
|
||||
@ -46,7 +44,6 @@ class TimestampWrapAroundHandler;
|
||||
namespace webrtc {
|
||||
|
||||
class AudioDeviceModule;
|
||||
class FileWrapper;
|
||||
class PacketRouter;
|
||||
class ProcessThread;
|
||||
class RateLimiter;
|
||||
@ -85,8 +82,6 @@ class VoERtcpObserver;
|
||||
class ChannelState {
|
||||
public:
|
||||
struct State {
|
||||
bool output_file_playing = false;
|
||||
bool input_file_playing = false;
|
||||
bool playing = false;
|
||||
bool sending = false;
|
||||
};
|
||||
@ -104,16 +99,6 @@ class ChannelState {
|
||||
return state_;
|
||||
}
|
||||
|
||||
void SetOutputFilePlaying(bool enable) {
|
||||
rtc::CritScope lock(&lock_);
|
||||
state_.output_file_playing = enable;
|
||||
}
|
||||
|
||||
void SetInputFilePlaying(bool enable) {
|
||||
rtc::CritScope lock(&lock_);
|
||||
state_.input_file_playing = enable;
|
||||
}
|
||||
|
||||
void SetPlaying(bool enable) {
|
||||
rtc::CritScope lock(&lock_);
|
||||
state_.playing = enable;
|
||||
@ -132,8 +117,6 @@ class ChannelState {
|
||||
class Channel
|
||||
: public RtpData,
|
||||
public RtpFeedback,
|
||||
public FileCallback, // receiving notification from file player &
|
||||
// recorder
|
||||
public Transport,
|
||||
public AudioPacketizationCallback, // receive encoded packets from the
|
||||
// ACM
|
||||
@ -217,44 +200,6 @@ class Channel
|
||||
int32_t ReceivedRTCPPacket(const uint8_t* data, size_t length);
|
||||
void OnRtpPacket(const RtpPacketReceived& packet);
|
||||
|
||||
// VoEFile
|
||||
int StartPlayingFileLocally(const char* fileName,
|
||||
bool loop,
|
||||
FileFormats format,
|
||||
int startPosition,
|
||||
float volumeScaling,
|
||||
int stopPosition,
|
||||
const CodecInst* codecInst);
|
||||
int StartPlayingFileLocally(InStream* stream,
|
||||
FileFormats format,
|
||||
int startPosition,
|
||||
float volumeScaling,
|
||||
int stopPosition,
|
||||
const CodecInst* codecInst);
|
||||
int StopPlayingFileLocally();
|
||||
int IsPlayingFileLocally() const;
|
||||
int RegisterFilePlayingToMixer();
|
||||
int StartPlayingFileAsMicrophone(const char* fileName,
|
||||
bool loop,
|
||||
FileFormats format,
|
||||
int startPosition,
|
||||
float volumeScaling,
|
||||
int stopPosition,
|
||||
const CodecInst* codecInst);
|
||||
int StartPlayingFileAsMicrophone(InStream* stream,
|
||||
FileFormats format,
|
||||
int startPosition,
|
||||
float volumeScaling,
|
||||
int stopPosition,
|
||||
const CodecInst* codecInst);
|
||||
int StopPlayingFileAsMicrophone();
|
||||
int IsPlayingFileAsMicrophone() const;
|
||||
int StartRecordingPlayout(const char* fileName, const CodecInst* codecInst);
|
||||
int StartRecordingPlayout(OutStream* stream, const CodecInst* codecInst);
|
||||
int StopRecordingPlayout();
|
||||
|
||||
void SetMixWithMicStatus(bool mix);
|
||||
|
||||
// Muting, Volume and Level.
|
||||
void SetInputMute(bool enable);
|
||||
void SetChannelOutputVolumeScaling(float scaling);
|
||||
@ -348,12 +293,6 @@ class Channel
|
||||
int sample_rate_hz,
|
||||
AudioFrame* audio_frame);
|
||||
|
||||
// From FileCallback
|
||||
void PlayNotification(int32_t id, uint32_t durationMs) override;
|
||||
void RecordNotification(int32_t id, uint32_t durationMs) override;
|
||||
void PlayFileEnded(int32_t id) override;
|
||||
void RecordFileEnded(int32_t id) override;
|
||||
|
||||
uint32_t InstanceId() const { return _instanceId; }
|
||||
int32_t ChannelId() const { return _channelId; }
|
||||
bool Playing() const { return channel_state_.Get().playing; }
|
||||
@ -430,8 +369,6 @@ class Channel
|
||||
bool IsPacketInOrder(const RTPHeader& header) const;
|
||||
bool IsPacketRetransmitted(const RTPHeader& header, bool in_order) const;
|
||||
int ResendPackets(const uint16_t* sequence_numbers, int length);
|
||||
int32_t MixOrReplaceAudioWithFile(AudioFrame* audio_frame);
|
||||
int32_t MixAudioWithFile(AudioFrame& audioFrame, int mixingFrequency);
|
||||
void UpdatePlayoutTimestamp(bool rtcp);
|
||||
void RegisterReceiveCodecsToRTPModule();
|
||||
|
||||
@ -452,7 +389,6 @@ class Channel
|
||||
uint32_t _instanceId;
|
||||
int32_t _channelId;
|
||||
|
||||
rtc::CriticalSection _fileCritSect;
|
||||
rtc::CriticalSection _callbackCritSect;
|
||||
rtc::CriticalSection volume_settings_critsect_;
|
||||
|
||||
@ -475,13 +411,6 @@ class Channel
|
||||
bool _externalTransport;
|
||||
// Downsamples to the codec rate if necessary.
|
||||
PushResampler<int16_t> input_resampler_;
|
||||
std::unique_ptr<FilePlayer> input_file_player_;
|
||||
std::unique_ptr<FilePlayer> output_file_player_;
|
||||
std::unique_ptr<FileRecorder> output_file_recorder_;
|
||||
int _inputFilePlayerId;
|
||||
int _outputFilePlayerId;
|
||||
int _outputFileRecorderId;
|
||||
bool _outputFileRecording;
|
||||
uint32_t _timeStamp RTC_ACCESS_ON(encoder_queue_);
|
||||
|
||||
RemoteNtpTimeEstimator ntp_estimator_ RTC_GUARDED_BY(ts_stats_lock_);
|
||||
@ -515,8 +444,6 @@ class Channel
|
||||
bool input_mute_ RTC_GUARDED_BY(volume_settings_critsect_);
|
||||
bool previous_frame_muted_ RTC_ACCESS_ON(encoder_queue_);
|
||||
float _outputGain RTC_GUARDED_BY(volume_settings_critsect_);
|
||||
// VoEBase
|
||||
bool _mixFileWithMicrophone;
|
||||
// VoeRTP_RTCP
|
||||
// TODO(henrika): can today be accessed on the main thread and on the
|
||||
// task queue; hence potential race.
|
||||
|
||||
@ -1,118 +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 "voice_engine/coder.h"
|
||||
|
||||
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
|
||||
#include "common_types.h" // NOLINT(build/include)
|
||||
#include "modules/audio_coding/codecs/audio_format_conversion.h"
|
||||
#include "modules/include/module_common_types.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;
|
||||
encoded_data_ = encoded_data;
|
||||
if (acm_->Add10MsData((AudioFrame&)audio_frame) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*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 VOICE_ENGINE_CODER_H_
|
||||
#define VOICE_ENGINE_CODER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "common_types.h" // NOLINT(build/include)
|
||||
#include "modules/audio_coding/acm2/codec_manager.h"
|
||||
#include "modules/audio_coding/acm2/rent_a_codec.h"
|
||||
#include "modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "typedefs.h" // NOLINT(build/include)
|
||||
|
||||
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 // VOICE_ENGINE_CODER_H_
|
||||
@ -1,397 +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 "voice_engine/file_player.h"
|
||||
|
||||
#include "common_audio/resampler/include/resampler.h"
|
||||
#include "common_types.h" // NOLINT(build/include)
|
||||
#include "modules/media_file/media_file.h"
|
||||
#include "modules/media_file/media_file_defines.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "typedefs.h" // NOLINT(build/include)
|
||||
#include "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
|
||||
@ -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 VOICE_ENGINE_FILE_PLAYER_H_
|
||||
#define VOICE_ENGINE_FILE_PLAYER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "common_types.h" // NOLINT(build/include)
|
||||
#include "modules/include/module_common_types.h"
|
||||
#include "typedefs.h" // NOLINT(build/include)
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class FileCallback;
|
||||
|
||||
class FilePlayer {
|
||||
public:
|
||||
// The largest decoded frame size in samples (60ms with 48kHz sample rate).
|
||||
enum { MAX_AUDIO_BUFFER_IN_SAMPLES = 60 * 48 };
|
||||
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 // VOICE_ENGINE_FILE_PLAYER_H_
|
||||
@ -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 "voice_engine/file_player.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rtc_base/flags.h"
|
||||
#include "rtc_base/md5digest.h"
|
||||
#include "rtc_base/stringencode.h"
|
||||
#include "test/gtest.h"
|
||||
#include "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 (FLAG_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 (FLAG_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,260 +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 "voice_engine/file_recorder.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "audio/utility/audio_frame_operations.h"
|
||||
#include "common_audio/resampler/include/resampler.h"
|
||||
#include "common_types.h" // NOLINT(build/include)
|
||||
#include "modules/include/module_common_types.h"
|
||||
#include "modules/media_file/media_file.h"
|
||||
#include "modules/media_file/media_file_defines.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/platform_thread.h"
|
||||
#include "system_wrappers/include/event_wrapper.h"
|
||||
#include "typedefs.h" // NOLINT(build/include)
|
||||
#include "voice_engine/coder.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 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_;
|
||||
if (!incomingAudioFrame.muted()) {
|
||||
AudioFrameOperations::StereoToMono(
|
||||
incomingAudioFrame.data(), incomingAudioFrame.samples_per_channel_,
|
||||
tempAudioFrame.mutable_data());
|
||||
}
|
||||
} 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_;
|
||||
if (!incomingAudioFrame.muted()) {
|
||||
AudioFrameOperations::MonoToStereo(
|
||||
incomingAudioFrame.data(), incomingAudioFrame.samples_per_channel_,
|
||||
tempAudioFrame.mutable_data());
|
||||
}
|
||||
}
|
||||
|
||||
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_);
|
||||
// TODO(yujo): skip resample if frame is muted.
|
||||
_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
|
||||
@ -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 VOICE_ENGINE_FILE_RECORDER_H_
|
||||
#define VOICE_ENGINE_FILE_RECORDER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "common_types.h" // NOLINT(build/include)
|
||||
#include "modules/include/module_common_types.h"
|
||||
#include "modules/media_file/media_file_defines.h"
|
||||
#include "typedefs.h" // NOLINT(build/include)
|
||||
|
||||
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 // VOICE_ENGINE_FILE_RECORDER_H_
|
||||
@ -1,144 +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.
|
||||
*/
|
||||
|
||||
// This sub-API supports the following functionalities:
|
||||
//
|
||||
// - File playback.
|
||||
// - File recording.
|
||||
// - File conversion.
|
||||
//
|
||||
// Usage example, omitting error checking:
|
||||
//
|
||||
// using namespace webrtc;
|
||||
// VoiceEngine* voe = VoiceEngine::Create();
|
||||
// VoEBase* base = VoEBase::GetInterface(voe);
|
||||
// VoEFile* file = VoEFile::GetInterface(voe);
|
||||
// base->Init();
|
||||
// int ch = base->CreateChannel();
|
||||
// ...
|
||||
// base->StartPlayout(ch);
|
||||
// file->StartPlayingFileAsMicrophone(ch, "data_file_16kHz.pcm", true);
|
||||
// ...
|
||||
// file->StopPlayingFileAsMicrophone(ch);
|
||||
// base->StopPlayout(ch);
|
||||
// ...
|
||||
// base->DeleteChannel(ch);
|
||||
// base->Terminate();
|
||||
// base->Release();
|
||||
// file->Release();
|
||||
// VoiceEngine::Delete(voe);
|
||||
//
|
||||
#ifndef VOICE_ENGINE_VOE_FILE_H_
|
||||
#define VOICE_ENGINE_VOE_FILE_H_
|
||||
|
||||
#include "common_types.h" // NOLINT(build/include)
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class VoiceEngine;
|
||||
|
||||
class WEBRTC_DLLEXPORT VoEFile {
|
||||
public:
|
||||
// Factory for the VoEFile sub-API. Increases an internal
|
||||
// reference counter if successful. Returns NULL if the API is not
|
||||
// supported or if construction fails.
|
||||
static VoEFile* GetInterface(VoiceEngine* voiceEngine);
|
||||
|
||||
// Releases the VoEFile sub-API and decreases an internal
|
||||
// reference counter. Returns the new reference count. This value should
|
||||
// be zero for all sub-API:s before the VoiceEngine object can be safely
|
||||
// deleted.
|
||||
virtual int Release() = 0;
|
||||
|
||||
// Starts playing and mixing files with the local speaker signal for
|
||||
// playout.
|
||||
virtual int StartPlayingFileLocally(
|
||||
int channel,
|
||||
const char fileNameUTF8[1024],
|
||||
bool loop = false,
|
||||
FileFormats format = kFileFormatPcm16kHzFile,
|
||||
float volumeScaling = 1.0,
|
||||
int startPointMs = 0,
|
||||
int stopPointMs = 0) = 0;
|
||||
|
||||
// Starts playing and mixing streams with the local speaker signal for
|
||||
// playout.
|
||||
virtual int StartPlayingFileLocally(
|
||||
int channel,
|
||||
InStream* stream,
|
||||
FileFormats format = kFileFormatPcm16kHzFile,
|
||||
float volumeScaling = 1.0,
|
||||
int startPointMs = 0,
|
||||
int stopPointMs = 0) = 0;
|
||||
|
||||
// Stops playback of a file on a specific |channel|.
|
||||
virtual int StopPlayingFileLocally(int channel) = 0;
|
||||
|
||||
// Returns the current file playing state for a specific |channel|.
|
||||
virtual int IsPlayingFileLocally(int channel) = 0;
|
||||
|
||||
// Starts reading data from a file and transmits the data either
|
||||
// mixed with or instead of the microphone signal.
|
||||
virtual int StartPlayingFileAsMicrophone(
|
||||
int channel,
|
||||
const char fileNameUTF8[1024],
|
||||
bool loop = false,
|
||||
bool mixWithMicrophone = false,
|
||||
FileFormats format = kFileFormatPcm16kHzFile,
|
||||
float volumeScaling = 1.0) = 0;
|
||||
|
||||
// Starts reading data from a stream and transmits the data either
|
||||
// mixed with or instead of the microphone signal.
|
||||
virtual int StartPlayingFileAsMicrophone(
|
||||
int channel,
|
||||
InStream* stream,
|
||||
bool mixWithMicrophone = false,
|
||||
FileFormats format = kFileFormatPcm16kHzFile,
|
||||
float volumeScaling = 1.0) = 0;
|
||||
|
||||
// Stops playing of a file as microphone signal for a specific |channel|.
|
||||
virtual int StopPlayingFileAsMicrophone(int channel) = 0;
|
||||
|
||||
// Returns whether the |channel| is currently playing a file as microphone.
|
||||
virtual int IsPlayingFileAsMicrophone(int channel) = 0;
|
||||
|
||||
// Starts recording the mixed playout audio.
|
||||
virtual int StartRecordingPlayout(int channel,
|
||||
const char* fileNameUTF8,
|
||||
CodecInst* compression = NULL,
|
||||
int maxSizeBytes = -1) = 0;
|
||||
|
||||
// Stops recording the mixed playout audio.
|
||||
virtual int StopRecordingPlayout(int channel) = 0;
|
||||
|
||||
virtual int StartRecordingPlayout(int channel,
|
||||
OutStream* stream,
|
||||
CodecInst* compression = NULL) = 0;
|
||||
|
||||
// Starts recording the microphone signal to a file.
|
||||
virtual int StartRecordingMicrophone(const char* fileNameUTF8,
|
||||
CodecInst* compression = NULL,
|
||||
int maxSizeBytes = -1) = 0;
|
||||
|
||||
// Starts recording the microphone signal to a stream.
|
||||
virtual int StartRecordingMicrophone(OutStream* stream,
|
||||
CodecInst* compression = NULL) = 0;
|
||||
|
||||
// Stops recording the microphone signal.
|
||||
virtual int StopRecordingMicrophone() = 0;
|
||||
|
||||
protected:
|
||||
VoEFile() {}
|
||||
virtual ~VoEFile() {}
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // VOICE_ENGINE_VOE_FILE_H_
|
||||
@ -12,7 +12,6 @@
|
||||
|
||||
#include "modules/audio_processing/include/audio_processing.h"
|
||||
#include "rtc_base/format_macros.h"
|
||||
#include "system_wrappers/include/file_wrapper.h"
|
||||
#include "system_wrappers/include/trace.h"
|
||||
#include "voice_engine/statistics.h"
|
||||
#include "voice_engine/utility.h"
|
||||
@ -33,45 +32,6 @@ OutputMixer::NewMixedAudio(int32_t id,
|
||||
_audioFrame.id_ = id;
|
||||
}
|
||||
|
||||
void OutputMixer::PlayNotification(int32_t id, uint32_t durationMs)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
|
||||
"OutputMixer::PlayNotification(id=%d, durationMs=%d)",
|
||||
id, durationMs);
|
||||
// Not implement yet
|
||||
}
|
||||
|
||||
void OutputMixer::RecordNotification(int32_t id,
|
||||
uint32_t durationMs)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
|
||||
"OutputMixer::RecordNotification(id=%d, durationMs=%d)",
|
||||
id, durationMs);
|
||||
|
||||
// Not implement yet
|
||||
}
|
||||
|
||||
void OutputMixer::PlayFileEnded(int32_t id)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
|
||||
"OutputMixer::PlayFileEnded(id=%d)", id);
|
||||
|
||||
// not needed
|
||||
}
|
||||
|
||||
void OutputMixer::RecordFileEnded(int32_t id)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
|
||||
"OutputMixer::RecordFileEnded(id=%d)", id);
|
||||
assert(id == _instanceId);
|
||||
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
_outputFileRecording = false;
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
|
||||
"OutputMixer::RecordFileEnded() =>"
|
||||
"output file recorder module is shutdown");
|
||||
}
|
||||
|
||||
int32_t
|
||||
OutputMixer::Create(OutputMixer*& mixer, uint32_t instanceId)
|
||||
{
|
||||
@ -91,8 +51,7 @@ OutputMixer::Create(OutputMixer*& mixer, uint32_t instanceId)
|
||||
OutputMixer::OutputMixer(uint32_t instanceId) :
|
||||
_mixerModule(*AudioConferenceMixer::Create(instanceId)),
|
||||
_instanceId(instanceId),
|
||||
_mixingFrequencyHz(8000),
|
||||
_outputFileRecording(false)
|
||||
_mixingFrequencyHz(8000)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,-1),
|
||||
"OutputMixer::OutputMixer() - ctor");
|
||||
@ -119,13 +78,6 @@ OutputMixer::~OutputMixer()
|
||||
{
|
||||
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,-1),
|
||||
"OutputMixer::~OutputMixer() - dtor");
|
||||
{
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
if (output_file_recorder_) {
|
||||
output_file_recorder_->RegisterModuleFileCallback(NULL);
|
||||
output_file_recorder_->StopRecording();
|
||||
}
|
||||
}
|
||||
_mixerModule.UnRegisterMixedStreamCallback();
|
||||
delete &_mixerModule;
|
||||
}
|
||||
@ -156,13 +108,6 @@ OutputMixer::SetMixabilityStatus(MixerParticipant& participant,
|
||||
return _mixerModule.SetMixabilityStatus(&participant, mixable);
|
||||
}
|
||||
|
||||
int32_t
|
||||
OutputMixer::SetAnonymousMixabilityStatus(MixerParticipant& participant,
|
||||
bool mixable)
|
||||
{
|
||||
return _mixerModule.SetAnonymousMixabilityStatus(&participant, mixable);
|
||||
}
|
||||
|
||||
int32_t
|
||||
OutputMixer::MixActiveChannels()
|
||||
{
|
||||
@ -170,179 +115,6 @@ OutputMixer::MixActiveChannels()
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OutputMixer::StartRecordingPlayout(const char* fileName,
|
||||
const CodecInst* codecInst)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
|
||||
"OutputMixer::StartRecordingPlayout(fileName=%s)", fileName);
|
||||
|
||||
if (_outputFileRecording)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
|
||||
"StartRecordingPlayout() is already recording");
|
||||
return 0;
|
||||
}
|
||||
|
||||
FileFormats format;
|
||||
const uint32_t notificationTime(0);
|
||||
CodecInst dummyCodec={100,"L16",16000,320,1,320000};
|
||||
|
||||
if ((codecInst != NULL) &&
|
||||
((codecInst->channels < 1) || (codecInst->channels > 2)))
|
||||
{
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_ARGUMENT, kTraceError,
|
||||
"StartRecordingPlayout() invalid compression");
|
||||
return(-1);
|
||||
}
|
||||
if(codecInst == NULL)
|
||||
{
|
||||
format = kFileFormatPcm16kHzFile;
|
||||
codecInst=&dummyCodec;
|
||||
}
|
||||
else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
|
||||
(STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
|
||||
(STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
|
||||
{
|
||||
format = kFileFormatWavFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
format = kFileFormatCompressedFile;
|
||||
}
|
||||
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
|
||||
// Destroy the old instance
|
||||
if (output_file_recorder_) {
|
||||
output_file_recorder_->RegisterModuleFileCallback(NULL);
|
||||
output_file_recorder_.reset();
|
||||
}
|
||||
|
||||
output_file_recorder_ = FileRecorder::CreateFileRecorder(
|
||||
_instanceId, (const FileFormats)format);
|
||||
if (!output_file_recorder_) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_INVALID_ARGUMENT, kTraceError,
|
||||
"StartRecordingPlayout() fileRecorder format isnot correct");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (output_file_recorder_->StartRecordingAudioFile(
|
||||
fileName, (const CodecInst&)*codecInst, notificationTime) != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_FILE, kTraceError,
|
||||
"StartRecordingAudioFile() failed to start file recording");
|
||||
output_file_recorder_->StopRecording();
|
||||
output_file_recorder_.reset();
|
||||
return -1;
|
||||
}
|
||||
output_file_recorder_->RegisterModuleFileCallback(this);
|
||||
_outputFileRecording = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OutputMixer::StartRecordingPlayout(OutStream* stream,
|
||||
const CodecInst* codecInst)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
|
||||
"OutputMixer::StartRecordingPlayout()");
|
||||
|
||||
if (_outputFileRecording)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
|
||||
"StartRecordingPlayout() is already recording");
|
||||
return 0;
|
||||
}
|
||||
|
||||
FileFormats format;
|
||||
const uint32_t notificationTime(0);
|
||||
CodecInst dummyCodec={100,"L16",16000,320,1,320000};
|
||||
|
||||
if (codecInst != NULL && codecInst->channels != 1)
|
||||
{
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_ARGUMENT, kTraceError,
|
||||
"StartRecordingPlayout() invalid compression");
|
||||
return(-1);
|
||||
}
|
||||
if(codecInst == NULL)
|
||||
{
|
||||
format = kFileFormatPcm16kHzFile;
|
||||
codecInst=&dummyCodec;
|
||||
}
|
||||
else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
|
||||
(STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
|
||||
(STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
|
||||
{
|
||||
format = kFileFormatWavFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
format = kFileFormatCompressedFile;
|
||||
}
|
||||
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
|
||||
// Destroy the old instance
|
||||
if (output_file_recorder_) {
|
||||
output_file_recorder_->RegisterModuleFileCallback(NULL);
|
||||
output_file_recorder_.reset();
|
||||
}
|
||||
|
||||
output_file_recorder_ = FileRecorder::CreateFileRecorder(
|
||||
_instanceId, (const FileFormats)format);
|
||||
if (!output_file_recorder_) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_INVALID_ARGUMENT, kTraceError,
|
||||
"StartRecordingPlayout() fileRecorder format isnot correct");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (output_file_recorder_->StartRecordingAudioFile(stream, *codecInst,
|
||||
notificationTime) != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_FILE, kTraceError,
|
||||
"StartRecordingAudioFile() failed to start file recording");
|
||||
output_file_recorder_->StopRecording();
|
||||
output_file_recorder_.reset();
|
||||
return -1;
|
||||
}
|
||||
|
||||
output_file_recorder_->RegisterModuleFileCallback(this);
|
||||
_outputFileRecording = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OutputMixer::StopRecordingPlayout()
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
|
||||
"OutputMixer::StopRecordingPlayout()");
|
||||
|
||||
if (!_outputFileRecording)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
|
||||
"StopRecordingPlayout() file isnot recording");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
|
||||
if (output_file_recorder_->StopRecording() != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_STOP_RECORDING_FAILED, kTraceError,
|
||||
"StopRecording(), could not stop recording");
|
||||
return -1;
|
||||
}
|
||||
output_file_recorder_->RegisterModuleFileCallback(NULL);
|
||||
output_file_recorder_.reset();
|
||||
_outputFileRecording = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OutputMixer::GetMixedAudio(int sample_rate_hz,
|
||||
size_t num_channels,
|
||||
AudioFrame* frame) {
|
||||
@ -351,13 +123,6 @@ int OutputMixer::GetMixedAudio(int sample_rate_hz,
|
||||
"OutputMixer::GetMixedAudio(sample_rate_hz=%d, num_channels=%" PRIuS ")",
|
||||
sample_rate_hz, num_channels);
|
||||
|
||||
// --- Record playout if enabled
|
||||
{
|
||||
rtc::CritScope cs(&_fileCritSect);
|
||||
if (_outputFileRecording && output_file_recorder_)
|
||||
output_file_recorder_->RecordAudioToFile(_audioFrame);
|
||||
}
|
||||
|
||||
frame->num_channels_ = num_channels;
|
||||
frame->sample_rate_hz_ = sample_rate_hz;
|
||||
// TODO(andrew): Ideally the downmixing would occur much earlier, in
|
||||
|
||||
@ -18,7 +18,6 @@
|
||||
#include "modules/audio_conference_mixer/include/audio_conference_mixer.h"
|
||||
#include "modules/audio_conference_mixer/include/audio_conference_mixer_defines.h"
|
||||
#include "rtc_base/criticalsection.h"
|
||||
#include "voice_engine/file_recorder.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -29,8 +28,7 @@ namespace voe {
|
||||
|
||||
class Statistics;
|
||||
|
||||
class OutputMixer : public AudioMixerOutputReceiver,
|
||||
public FileCallback
|
||||
class OutputMixer : public AudioMixerOutputReceiver
|
||||
{
|
||||
public:
|
||||
static int32_t Create(OutputMixer*& mixer, uint32_t instanceId);
|
||||
@ -49,20 +47,9 @@ public:
|
||||
int32_t SetMixabilityStatus(MixerParticipant& participant,
|
||||
bool mixable);
|
||||
|
||||
int32_t SetAnonymousMixabilityStatus(MixerParticipant& participant,
|
||||
bool mixable);
|
||||
|
||||
int GetMixedAudio(int sample_rate_hz, size_t num_channels,
|
||||
AudioFrame* audioFrame);
|
||||
|
||||
// VoEFile
|
||||
int StartRecordingPlayout(const char* fileName,
|
||||
const CodecInst* codecInst);
|
||||
|
||||
int StartRecordingPlayout(OutStream* stream,
|
||||
const CodecInst* codecInst);
|
||||
int StopRecordingPlayout();
|
||||
|
||||
virtual ~OutputMixer();
|
||||
|
||||
// from AudioMixerOutputReceiver
|
||||
@ -72,14 +59,6 @@ public:
|
||||
const AudioFrame** uniqueAudioFrames,
|
||||
uint32_t size);
|
||||
|
||||
// For file recording
|
||||
void PlayNotification(int32_t id, uint32_t durationMs);
|
||||
|
||||
void RecordNotification(int32_t id, uint32_t durationMs);
|
||||
|
||||
void PlayFileEnded(int32_t id);
|
||||
void RecordFileEnded(int32_t id);
|
||||
|
||||
private:
|
||||
OutputMixer(uint32_t instanceId);
|
||||
|
||||
@ -87,8 +66,6 @@ private:
|
||||
Statistics* _engineStatisticsPtr;
|
||||
AudioProcessing* _audioProcessingModulePtr;
|
||||
|
||||
// Protects output_file_recorder_ and _outputFileRecording.
|
||||
rtc::CriticalSection _fileCritSect;
|
||||
AudioConferenceMixer& _mixerModule;
|
||||
AudioFrame _audioFrame;
|
||||
// Converts mixed audio to the audio device output rate.
|
||||
@ -97,8 +74,6 @@ private:
|
||||
PushResampler<int16_t> audioproc_resampler_;
|
||||
int _instanceId;
|
||||
int _mixingFrequencyHz;
|
||||
std::unique_ptr<FileRecorder> output_file_recorder_;
|
||||
bool _outputFileRecording;
|
||||
};
|
||||
|
||||
} // namespace voe
|
||||
|
||||
@ -67,64 +67,6 @@ void TransmitMixer::OnPeriodicProcess()
|
||||
}
|
||||
#endif // WEBRTC_VOICE_ENGINE_TYPING_DETECTION
|
||||
|
||||
void TransmitMixer::PlayNotification(int32_t id,
|
||||
uint32_t durationMs)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::PlayNotification(id=%d, durationMs=%d)",
|
||||
id, durationMs);
|
||||
|
||||
// Not implement yet
|
||||
}
|
||||
|
||||
void TransmitMixer::RecordNotification(int32_t id,
|
||||
uint32_t durationMs)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
|
||||
"TransmitMixer::RecordNotification(id=%d, durationMs=%d)",
|
||||
id, durationMs);
|
||||
|
||||
// Not implement yet
|
||||
}
|
||||
|
||||
void TransmitMixer::PlayFileEnded(int32_t id)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::PlayFileEnded(id=%d)", id);
|
||||
|
||||
assert(id == _filePlayerId);
|
||||
|
||||
rtc::CritScope cs(&_critSect);
|
||||
|
||||
_filePlaying = false;
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::PlayFileEnded() =>"
|
||||
"file player module is shutdown");
|
||||
}
|
||||
|
||||
void
|
||||
TransmitMixer::RecordFileEnded(int32_t id)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::RecordFileEnded(id=%d)", id);
|
||||
|
||||
if (id == _fileRecorderId)
|
||||
{
|
||||
rtc::CritScope cs(&_critSect);
|
||||
_fileRecording = false;
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::RecordFileEnded() => fileRecorder module"
|
||||
"is shutdown");
|
||||
} else if (id == _fileCallRecorderId)
|
||||
{
|
||||
rtc::CritScope cs(&_critSect);
|
||||
_fileCallRecording = false;
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::RecordFileEnded() => fileCallRecorder"
|
||||
"module is shutdown");
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
TransmitMixer::Create(TransmitMixer*& mixer, uint32_t instanceId)
|
||||
{
|
||||
@ -152,11 +94,6 @@ TransmitMixer::Destroy(TransmitMixer*& mixer)
|
||||
}
|
||||
|
||||
TransmitMixer::TransmitMixer(uint32_t instanceId) :
|
||||
// Avoid conflict with other channels by adding 1024 - 1026,
|
||||
// won't use as much as 1024 channels.
|
||||
_filePlayerId(instanceId + 1024),
|
||||
_fileRecorderId(instanceId + 1025),
|
||||
_fileCallRecorderId(instanceId + 1026),
|
||||
#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
|
||||
_monitorModule(this),
|
||||
#endif
|
||||
@ -174,21 +111,6 @@ TransmitMixer::~TransmitMixer()
|
||||
if (_processThreadPtr)
|
||||
_processThreadPtr->DeRegisterModule(&_monitorModule);
|
||||
#endif
|
||||
{
|
||||
rtc::CritScope cs(&_critSect);
|
||||
if (file_recorder_) {
|
||||
file_recorder_->RegisterModuleFileCallback(NULL);
|
||||
file_recorder_->StopRecording();
|
||||
}
|
||||
if (file_call_recorder_) {
|
||||
file_call_recorder_->RegisterModuleFileCallback(NULL);
|
||||
file_call_recorder_->StopRecording();
|
||||
}
|
||||
if (file_player_) {
|
||||
file_player_->RegisterModuleFileCallback(NULL);
|
||||
file_player_->StopPlayingFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
@ -295,23 +217,6 @@ TransmitMixer::PrepareDemux(const void* audioSamples,
|
||||
TypingDetection(keyPressed);
|
||||
#endif
|
||||
|
||||
// --- Mix with file (does not affect the mixing frequency)
|
||||
if (_filePlaying)
|
||||
{
|
||||
MixOrReplaceAudioWithFile(_audioFrame.sample_rate_hz_);
|
||||
}
|
||||
|
||||
// --- Record to file
|
||||
bool file_recording = false;
|
||||
{
|
||||
rtc::CritScope cs(&_critSect);
|
||||
file_recording = _fileRecording;
|
||||
}
|
||||
if (file_recording)
|
||||
{
|
||||
RecordAudioToFile(_audioFrame.sample_rate_hz_);
|
||||
}
|
||||
|
||||
// --- Measure audio level of speech after all processing.
|
||||
double sample_duration = static_cast<double>(nSamples) / samplesPerSec;
|
||||
_audioLevel.ComputeLevel(_audioFrame, sample_duration);
|
||||
@ -344,509 +249,6 @@ TransmitMixer::StopSend()
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TransmitMixer::StartPlayingFileAsMicrophone(const char* fileName,
|
||||
bool loop,
|
||||
FileFormats format,
|
||||
int startPosition,
|
||||
float volumeScaling,
|
||||
int stopPosition,
|
||||
const CodecInst* codecInst)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::StartPlayingFileAsMicrophone("
|
||||
"fileNameUTF8[]=%s,loop=%d, format=%d, volumeScaling=%5.3f,"
|
||||
" startPosition=%d, stopPosition=%d)", fileName, loop,
|
||||
format, volumeScaling, startPosition, stopPosition);
|
||||
|
||||
if (_filePlaying)
|
||||
{
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_ALREADY_PLAYING, kTraceWarning,
|
||||
"StartPlayingFileAsMicrophone() is already playing");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtc::CritScope cs(&_critSect);
|
||||
|
||||
// Destroy the old instance
|
||||
if (file_player_) {
|
||||
file_player_->RegisterModuleFileCallback(NULL);
|
||||
file_player_.reset();
|
||||
}
|
||||
|
||||
// Dynamically create the instance
|
||||
file_player_ =
|
||||
FilePlayer::CreateFilePlayer(_filePlayerId, (const FileFormats)format);
|
||||
|
||||
if (!file_player_) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_INVALID_ARGUMENT, kTraceError,
|
||||
"StartPlayingFileAsMicrophone() filePlayer format isnot correct");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint32_t notificationTime(0);
|
||||
|
||||
if (file_player_->StartPlayingFile(
|
||||
fileName, loop, startPosition, volumeScaling, notificationTime,
|
||||
stopPosition, (const CodecInst*)codecInst) != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_FILE, kTraceError,
|
||||
"StartPlayingFile() failed to start file playout");
|
||||
file_player_->StopPlayingFile();
|
||||
file_player_.reset();
|
||||
return -1;
|
||||
}
|
||||
|
||||
file_player_->RegisterModuleFileCallback(this);
|
||||
_filePlaying = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TransmitMixer::StartPlayingFileAsMicrophone(InStream* stream,
|
||||
FileFormats format,
|
||||
int startPosition,
|
||||
float volumeScaling,
|
||||
int stopPosition,
|
||||
const CodecInst* codecInst)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
|
||||
"TransmitMixer::StartPlayingFileAsMicrophone(format=%d,"
|
||||
" volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
|
||||
format, volumeScaling, startPosition, stopPosition);
|
||||
|
||||
if (stream == NULL)
|
||||
{
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_FILE, kTraceError,
|
||||
"StartPlayingFileAsMicrophone() NULL as input stream");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_filePlaying)
|
||||
{
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_ALREADY_PLAYING, kTraceWarning,
|
||||
"StartPlayingFileAsMicrophone() is already playing");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtc::CritScope cs(&_critSect);
|
||||
|
||||
// Destroy the old instance
|
||||
if (file_player_) {
|
||||
file_player_->RegisterModuleFileCallback(NULL);
|
||||
file_player_.reset();
|
||||
}
|
||||
|
||||
// Dynamically create the instance
|
||||
file_player_ =
|
||||
FilePlayer::CreateFilePlayer(_filePlayerId, (const FileFormats)format);
|
||||
|
||||
if (!file_player_) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_INVALID_ARGUMENT, kTraceWarning,
|
||||
"StartPlayingFileAsMicrophone() filePlayer format isnot correct");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint32_t notificationTime(0);
|
||||
|
||||
if (file_player_->StartPlayingFile(stream, startPosition, volumeScaling,
|
||||
notificationTime, stopPosition,
|
||||
(const CodecInst*)codecInst) != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_FILE, kTraceError,
|
||||
"StartPlayingFile() failed to start file playout");
|
||||
file_player_->StopPlayingFile();
|
||||
file_player_.reset();
|
||||
return -1;
|
||||
}
|
||||
file_player_->RegisterModuleFileCallback(this);
|
||||
_filePlaying = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TransmitMixer::StopPlayingFileAsMicrophone()
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
|
||||
"TransmitMixer::StopPlayingFileAsMicrophone()");
|
||||
|
||||
if (!_filePlaying)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtc::CritScope cs(&_critSect);
|
||||
|
||||
if (file_player_->StopPlayingFile() != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_CANNOT_STOP_PLAYOUT, kTraceError,
|
||||
"StopPlayingFile() couldnot stop playing file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
file_player_->RegisterModuleFileCallback(NULL);
|
||||
file_player_.reset();
|
||||
_filePlaying = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TransmitMixer::IsPlayingFileAsMicrophone() const
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::IsPlayingFileAsMicrophone()");
|
||||
return _filePlaying;
|
||||
}
|
||||
|
||||
int TransmitMixer::StartRecordingMicrophone(const char* fileName,
|
||||
const CodecInst* codecInst)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::StartRecordingMicrophone(fileName=%s)",
|
||||
fileName);
|
||||
|
||||
rtc::CritScope cs(&_critSect);
|
||||
|
||||
if (_fileRecording)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"StartRecordingMicrophone() is already recording");
|
||||
return 0;
|
||||
}
|
||||
|
||||
FileFormats format;
|
||||
const uint32_t notificationTime(0); // Not supported in VoE
|
||||
CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
|
||||
|
||||
if (codecInst != NULL && codecInst->channels > 2)
|
||||
{
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_ARGUMENT, kTraceError,
|
||||
"StartRecordingMicrophone() invalid compression");
|
||||
return (-1);
|
||||
}
|
||||
if (codecInst == NULL)
|
||||
{
|
||||
format = kFileFormatPcm16kHzFile;
|
||||
codecInst = &dummyCodec;
|
||||
} else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
|
||||
(STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
|
||||
(STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
|
||||
{
|
||||
format = kFileFormatWavFile;
|
||||
} else
|
||||
{
|
||||
format = kFileFormatCompressedFile;
|
||||
}
|
||||
|
||||
// Destroy the old instance
|
||||
if (file_recorder_) {
|
||||
file_recorder_->RegisterModuleFileCallback(NULL);
|
||||
file_recorder_.reset();
|
||||
}
|
||||
|
||||
file_recorder_ = FileRecorder::CreateFileRecorder(
|
||||
_fileRecorderId, (const FileFormats)format);
|
||||
if (!file_recorder_) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_INVALID_ARGUMENT, kTraceError,
|
||||
"StartRecordingMicrophone() fileRecorder format isnot correct");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (file_recorder_->StartRecordingAudioFile(
|
||||
fileName, (const CodecInst&)*codecInst, notificationTime) != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_FILE, kTraceError,
|
||||
"StartRecordingAudioFile() failed to start file recording");
|
||||
file_recorder_->StopRecording();
|
||||
file_recorder_.reset();
|
||||
return -1;
|
||||
}
|
||||
file_recorder_->RegisterModuleFileCallback(this);
|
||||
_fileRecording = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TransmitMixer::StartRecordingMicrophone(OutStream* stream,
|
||||
const CodecInst* codecInst)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::StartRecordingMicrophone()");
|
||||
|
||||
rtc::CritScope cs(&_critSect);
|
||||
|
||||
if (_fileRecording)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"StartRecordingMicrophone() is already recording");
|
||||
return 0;
|
||||
}
|
||||
|
||||
FileFormats format;
|
||||
const uint32_t notificationTime(0); // Not supported in VoE
|
||||
CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
|
||||
|
||||
if (codecInst != NULL && codecInst->channels != 1)
|
||||
{
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_ARGUMENT, kTraceError,
|
||||
"StartRecordingMicrophone() invalid compression");
|
||||
return (-1);
|
||||
}
|
||||
if (codecInst == NULL)
|
||||
{
|
||||
format = kFileFormatPcm16kHzFile;
|
||||
codecInst = &dummyCodec;
|
||||
} else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
|
||||
(STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
|
||||
(STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
|
||||
{
|
||||
format = kFileFormatWavFile;
|
||||
} else
|
||||
{
|
||||
format = kFileFormatCompressedFile;
|
||||
}
|
||||
|
||||
// Destroy the old instance
|
||||
if (file_recorder_) {
|
||||
file_recorder_->RegisterModuleFileCallback(NULL);
|
||||
file_recorder_.reset();
|
||||
}
|
||||
|
||||
file_recorder_ = FileRecorder::CreateFileRecorder(
|
||||
_fileRecorderId, (const FileFormats)format);
|
||||
if (!file_recorder_) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_INVALID_ARGUMENT, kTraceError,
|
||||
"StartRecordingMicrophone() fileRecorder format isnot correct");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (file_recorder_->StartRecordingAudioFile(stream, *codecInst,
|
||||
notificationTime) != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_FILE, kTraceError,
|
||||
"StartRecordingAudioFile() failed to start file recording");
|
||||
file_recorder_->StopRecording();
|
||||
file_recorder_.reset();
|
||||
return -1;
|
||||
}
|
||||
|
||||
file_recorder_->RegisterModuleFileCallback(this);
|
||||
_fileRecording = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int TransmitMixer::StopRecordingMicrophone()
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::StopRecordingMicrophone()");
|
||||
|
||||
rtc::CritScope cs(&_critSect);
|
||||
|
||||
if (!_fileRecording)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"StopRecordingMicrophone() isnot recording");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (file_recorder_->StopRecording() != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_STOP_RECORDING_FAILED, kTraceError,
|
||||
"StopRecording(), could not stop recording");
|
||||
return -1;
|
||||
}
|
||||
file_recorder_->RegisterModuleFileCallback(NULL);
|
||||
file_recorder_.reset();
|
||||
_fileRecording = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TransmitMixer::StartRecordingCall(const char* fileName,
|
||||
const CodecInst* codecInst)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::StartRecordingCall(fileName=%s)", fileName);
|
||||
|
||||
if (_fileCallRecording)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"StartRecordingCall() is already recording");
|
||||
return 0;
|
||||
}
|
||||
|
||||
FileFormats format;
|
||||
const uint32_t notificationTime(0); // Not supported in VoE
|
||||
CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
|
||||
|
||||
if (codecInst != NULL && codecInst->channels != 1)
|
||||
{
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_ARGUMENT, kTraceError,
|
||||
"StartRecordingCall() invalid compression");
|
||||
return (-1);
|
||||
}
|
||||
if (codecInst == NULL)
|
||||
{
|
||||
format = kFileFormatPcm16kHzFile;
|
||||
codecInst = &dummyCodec;
|
||||
} else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
|
||||
(STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
|
||||
(STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
|
||||
{
|
||||
format = kFileFormatWavFile;
|
||||
} else
|
||||
{
|
||||
format = kFileFormatCompressedFile;
|
||||
}
|
||||
|
||||
rtc::CritScope cs(&_critSect);
|
||||
|
||||
// Destroy the old instance
|
||||
if (file_call_recorder_) {
|
||||
file_call_recorder_->RegisterModuleFileCallback(NULL);
|
||||
file_call_recorder_.reset();
|
||||
}
|
||||
|
||||
file_call_recorder_ = FileRecorder::CreateFileRecorder(
|
||||
_fileCallRecorderId, (const FileFormats)format);
|
||||
if (!file_call_recorder_) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_INVALID_ARGUMENT, kTraceError,
|
||||
"StartRecordingCall() fileRecorder format isnot correct");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (file_call_recorder_->StartRecordingAudioFile(
|
||||
fileName, (const CodecInst&)*codecInst, notificationTime) != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_FILE, kTraceError,
|
||||
"StartRecordingAudioFile() failed to start file recording");
|
||||
file_call_recorder_->StopRecording();
|
||||
file_call_recorder_.reset();
|
||||
return -1;
|
||||
}
|
||||
file_call_recorder_->RegisterModuleFileCallback(this);
|
||||
_fileCallRecording = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TransmitMixer::StartRecordingCall(OutStream* stream,
|
||||
const CodecInst* codecInst)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::StartRecordingCall()");
|
||||
|
||||
if (_fileCallRecording)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"StartRecordingCall() is already recording");
|
||||
return 0;
|
||||
}
|
||||
|
||||
FileFormats format;
|
||||
const uint32_t notificationTime(0); // Not supported in VoE
|
||||
CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
|
||||
|
||||
if (codecInst != NULL && codecInst->channels != 1)
|
||||
{
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_ARGUMENT, kTraceError,
|
||||
"StartRecordingCall() invalid compression");
|
||||
return (-1);
|
||||
}
|
||||
if (codecInst == NULL)
|
||||
{
|
||||
format = kFileFormatPcm16kHzFile;
|
||||
codecInst = &dummyCodec;
|
||||
} else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
|
||||
(STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
|
||||
(STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
|
||||
{
|
||||
format = kFileFormatWavFile;
|
||||
} else
|
||||
{
|
||||
format = kFileFormatCompressedFile;
|
||||
}
|
||||
|
||||
rtc::CritScope cs(&_critSect);
|
||||
|
||||
// Destroy the old instance
|
||||
if (file_call_recorder_) {
|
||||
file_call_recorder_->RegisterModuleFileCallback(NULL);
|
||||
file_call_recorder_.reset();
|
||||
}
|
||||
|
||||
file_call_recorder_ = FileRecorder::CreateFileRecorder(
|
||||
_fileCallRecorderId, (const FileFormats)format);
|
||||
if (!file_call_recorder_) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_INVALID_ARGUMENT, kTraceError,
|
||||
"StartRecordingCall() fileRecorder format isnot correct");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (file_call_recorder_->StartRecordingAudioFile(stream, *codecInst,
|
||||
notificationTime) != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_BAD_FILE, kTraceError,
|
||||
"StartRecordingAudioFile() failed to start file recording");
|
||||
file_call_recorder_->StopRecording();
|
||||
file_call_recorder_.reset();
|
||||
return -1;
|
||||
}
|
||||
|
||||
file_call_recorder_->RegisterModuleFileCallback(this);
|
||||
_fileCallRecording = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TransmitMixer::StopRecordingCall()
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::StopRecordingCall()");
|
||||
|
||||
if (!_fileCallRecording)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"StopRecordingCall() file isnot recording");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rtc::CritScope cs(&_critSect);
|
||||
|
||||
if (file_call_recorder_->StopRecording() != 0) {
|
||||
_engineStatisticsPtr->SetLastError(
|
||||
VE_STOP_RECORDING_FAILED, kTraceError,
|
||||
"StopRecording(), could not stop recording");
|
||||
return -1;
|
||||
}
|
||||
|
||||
file_call_recorder_->RegisterModuleFileCallback(NULL);
|
||||
file_call_recorder_.reset();
|
||||
_fileCallRecording = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
TransmitMixer::SetMixWithMicStatus(bool mix)
|
||||
{
|
||||
_mixFileWithMicrophone = mix;
|
||||
}
|
||||
|
||||
int8_t TransmitMixer::AudioLevel() const
|
||||
{
|
||||
// Speech + file level [0,9]
|
||||
@ -867,17 +269,6 @@ double TransmitMixer::GetTotalInputDuration() const {
|
||||
return _audioLevel.TotalDuration();
|
||||
}
|
||||
|
||||
bool TransmitMixer::IsRecordingCall()
|
||||
{
|
||||
return _fileCallRecording;
|
||||
}
|
||||
|
||||
bool TransmitMixer::IsRecordingMic()
|
||||
{
|
||||
rtc::CritScope cs(&_critSect);
|
||||
return _fileRecording;
|
||||
}
|
||||
|
||||
void TransmitMixer::GenerateAudioFrame(const int16_t* audio,
|
||||
size_t samples_per_channel,
|
||||
size_t num_channels,
|
||||
@ -901,79 +292,6 @@ void TransmitMixer::GenerateAudioFrame(const int16_t* audio,
|
||||
&resampler_, &_audioFrame);
|
||||
}
|
||||
|
||||
int32_t TransmitMixer::RecordAudioToFile(
|
||||
uint32_t mixingFrequency)
|
||||
{
|
||||
rtc::CritScope cs(&_critSect);
|
||||
if (!file_recorder_) {
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::RecordAudioToFile() filerecorder doesnot"
|
||||
"exist");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (file_recorder_->RecordAudioToFile(_audioFrame) != 0) {
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::RecordAudioToFile() file recording"
|
||||
"failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t TransmitMixer::MixOrReplaceAudioWithFile(
|
||||
int mixingFrequency)
|
||||
{
|
||||
std::unique_ptr<int16_t[]> fileBuffer(new int16_t[640]);
|
||||
|
||||
size_t fileSamples(0);
|
||||
{
|
||||
rtc::CritScope cs(&_critSect);
|
||||
if (!file_player_) {
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::MixOrReplaceAudioWithFile()"
|
||||
"fileplayer doesnot exist");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (file_player_->Get10msAudioFromFile(fileBuffer.get(), &fileSamples,
|
||||
mixingFrequency) == -1) {
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
|
||||
"TransmitMixer::MixOrReplaceAudioWithFile() file"
|
||||
" mixing failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
assert(_audioFrame.samples_per_channel_ == fileSamples);
|
||||
|
||||
if (_mixFileWithMicrophone)
|
||||
{
|
||||
// Currently file stream is always mono.
|
||||
// TODO(xians): Change the code when FilePlayer supports real stereo.
|
||||
MixWithSat(_audioFrame.mutable_data(),
|
||||
_audioFrame.num_channels_,
|
||||
fileBuffer.get(),
|
||||
1,
|
||||
fileSamples);
|
||||
} else
|
||||
{
|
||||
// Replace ACM audio with file.
|
||||
// Currently file stream is always mono.
|
||||
// TODO(xians): Change the code when FilePlayer supports real stereo.
|
||||
_audioFrame.UpdateFrame(-1,
|
||||
0xFFFFFFFF,
|
||||
fileBuffer.get(),
|
||||
fileSamples,
|
||||
mixingFrequency,
|
||||
AudioFrame::kNormalSpeech,
|
||||
AudioFrame::kVadUnknown,
|
||||
1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TransmitMixer::ProcessAudio(int delay_ms, int clock_drift,
|
||||
int current_mic_level, bool key_pressed) {
|
||||
if (audioproc_->set_stream_delay_ms(delay_ms) != 0) {
|
||||
|
||||
@ -19,8 +19,6 @@
|
||||
#include "modules/include/module_common_types.h"
|
||||
#include "rtc_base/criticalsection.h"
|
||||
#include "voice_engine/audio_level.h"
|
||||
#include "voice_engine/file_player.h"
|
||||
#include "voice_engine/file_recorder.h"
|
||||
#include "voice_engine/include/voe_base.h"
|
||||
#include "voice_engine/monitor_module.h"
|
||||
#include "voice_engine/voice_engine_defines.h"
|
||||
@ -41,7 +39,7 @@ class ChannelManager;
|
||||
class MixedAudio;
|
||||
class Statistics;
|
||||
|
||||
class TransmitMixer : public FileCallback {
|
||||
class TransmitMixer {
|
||||
public:
|
||||
static int32_t Create(TransmitMixer*& mixer, uint32_t instanceId);
|
||||
|
||||
@ -84,45 +82,6 @@ public:
|
||||
// 'virtual' to allow mocking.
|
||||
virtual double GetTotalInputDuration() const;
|
||||
|
||||
bool IsRecordingCall();
|
||||
|
||||
bool IsRecordingMic();
|
||||
|
||||
int StartPlayingFileAsMicrophone(const char* fileName,
|
||||
bool loop,
|
||||
FileFormats format,
|
||||
int startPosition,
|
||||
float volumeScaling,
|
||||
int stopPosition,
|
||||
const CodecInst* codecInst);
|
||||
|
||||
int StartPlayingFileAsMicrophone(InStream* stream,
|
||||
FileFormats format,
|
||||
int startPosition,
|
||||
float volumeScaling,
|
||||
int stopPosition,
|
||||
const CodecInst* codecInst);
|
||||
|
||||
int StopPlayingFileAsMicrophone();
|
||||
|
||||
int IsPlayingFileAsMicrophone() const;
|
||||
|
||||
int StartRecordingMicrophone(const char* fileName,
|
||||
const CodecInst* codecInst);
|
||||
|
||||
int StartRecordingMicrophone(OutStream* stream,
|
||||
const CodecInst* codecInst);
|
||||
|
||||
int StopRecordingMicrophone();
|
||||
|
||||
int StartRecordingCall(const char* fileName, const CodecInst* codecInst);
|
||||
|
||||
int StartRecordingCall(OutStream* stream, const CodecInst* codecInst);
|
||||
|
||||
int StopRecordingCall();
|
||||
|
||||
void SetMixWithMicStatus(bool mix);
|
||||
|
||||
int32_t RegisterVoiceEngineObserver(VoiceEngineObserver& observer);
|
||||
|
||||
virtual ~TransmitMixer();
|
||||
@ -132,17 +91,6 @@ public:
|
||||
void OnPeriodicProcess();
|
||||
#endif
|
||||
|
||||
// FileCallback
|
||||
void PlayNotification(const int32_t id,
|
||||
const uint32_t durationMs);
|
||||
|
||||
void RecordNotification(const int32_t id,
|
||||
const uint32_t durationMs);
|
||||
|
||||
void PlayFileEnded(const int32_t id);
|
||||
|
||||
void RecordFileEnded(const int32_t id);
|
||||
|
||||
// Virtual to allow mocking.
|
||||
virtual void EnableStereoChannelSwapping(bool enable);
|
||||
bool IsStereoChannelSwappingEnabled();
|
||||
@ -165,10 +113,6 @@ private:
|
||||
size_t nSamples,
|
||||
size_t nChannels,
|
||||
int samplesPerSec);
|
||||
int32_t RecordAudioToFile(uint32_t mixingFrequency);
|
||||
|
||||
int32_t MixOrReplaceAudioWithFile(
|
||||
int mixingFrequency);
|
||||
|
||||
void ProcessAudio(int delay_ms, int clock_drift, int current_mic_level,
|
||||
bool key_pressed);
|
||||
@ -187,15 +131,6 @@ private:
|
||||
// owns
|
||||
AudioFrame _audioFrame;
|
||||
PushResampler<int16_t> resampler_; // ADM sample rate -> mixing rate
|
||||
std::unique_ptr<FilePlayer> file_player_;
|
||||
std::unique_ptr<FileRecorder> file_recorder_;
|
||||
std::unique_ptr<FileRecorder> file_call_recorder_;
|
||||
int _filePlayerId = 0;
|
||||
int _fileRecorderId = 0;
|
||||
int _fileCallRecorderId = 0;
|
||||
bool _filePlaying = false;
|
||||
bool _fileRecording = false;
|
||||
bool _fileCallRecording = false;
|
||||
voe::AudioLevel _audioLevel;
|
||||
// protect file instances and their variables in MixedParticipants()
|
||||
rtc::CriticalSection _critSect;
|
||||
@ -209,7 +144,6 @@ private:
|
||||
#endif
|
||||
|
||||
int _instanceId = 0;
|
||||
bool _mixFileWithMicrophone = false;
|
||||
uint32_t _captureLevel = 0;
|
||||
bool stereo_codec_ = false;
|
||||
bool swap_stereo_channels_ = false;
|
||||
|
||||
@ -88,41 +88,5 @@ void RemixAndResample(const int16_t* src_data,
|
||||
}
|
||||
}
|
||||
|
||||
void MixWithSat(int16_t target[],
|
||||
size_t target_channel,
|
||||
const int16_t source[],
|
||||
size_t source_channel,
|
||||
size_t source_len) {
|
||||
RTC_DCHECK_GE(target_channel, 1);
|
||||
RTC_DCHECK_LE(target_channel, 2);
|
||||
RTC_DCHECK_GE(source_channel, 1);
|
||||
RTC_DCHECK_LE(source_channel, 2);
|
||||
|
||||
if (target_channel == 2 && source_channel == 1) {
|
||||
// Convert source from mono to stereo.
|
||||
int32_t left = 0;
|
||||
int32_t right = 0;
|
||||
for (size_t i = 0; i < source_len; ++i) {
|
||||
left = source[i] + target[i * 2];
|
||||
right = source[i] + target[i * 2 + 1];
|
||||
target[i * 2] = WebRtcSpl_SatW32ToW16(left);
|
||||
target[i * 2 + 1] = WebRtcSpl_SatW32ToW16(right);
|
||||
}
|
||||
} else if (target_channel == 1 && source_channel == 2) {
|
||||
// Convert source from stereo to mono.
|
||||
int32_t temp = 0;
|
||||
for (size_t i = 0; i < source_len / 2; ++i) {
|
||||
temp = ((source[i * 2] + source[i * 2 + 1]) >> 1) + target[i];
|
||||
target[i] = WebRtcSpl_SatW32ToW16(temp);
|
||||
}
|
||||
} else {
|
||||
int32_t temp = 0;
|
||||
for (size_t i = 0; i < source_len; ++i) {
|
||||
temp = source[i] + target[i];
|
||||
target[i] = WebRtcSpl_SatW32ToW16(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace voe
|
||||
} // namespace webrtc
|
||||
|
||||
@ -45,12 +45,6 @@ void RemixAndResample(const int16_t* src_data,
|
||||
PushResampler<int16_t>* resampler,
|
||||
AudioFrame* dst_frame);
|
||||
|
||||
void MixWithSat(int16_t target[],
|
||||
size_t target_channel,
|
||||
const int16_t source[],
|
||||
size_t source_channel,
|
||||
size_t source_len);
|
||||
|
||||
} // namespace voe
|
||||
} // namespace webrtc
|
||||
|
||||
|
||||
@ -597,8 +597,7 @@ int32_t VoEBaseImpl::StartSend() {
|
||||
}
|
||||
|
||||
int32_t VoEBaseImpl::StopSend() {
|
||||
if (shared_->NumOfSendingChannels() == 0 &&
|
||||
!shared_->transmit_mixer()->IsRecordingMic()) {
|
||||
if (shared_->NumOfSendingChannels() == 0) {
|
||||
// Stop audio-device recording if no channel is recording
|
||||
if (shared_->audio_device()->StopRecording() != 0) {
|
||||
shared_->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
|
||||
|
||||
@ -1,466 +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 "voice_engine/voe_file_impl.h"
|
||||
|
||||
#include "system_wrappers/include/file_wrapper.h"
|
||||
#include "system_wrappers/include/trace.h"
|
||||
#include "voice_engine/channel.h"
|
||||
#include "voice_engine/include/voe_errors.h"
|
||||
#include "voice_engine/output_mixer.h"
|
||||
#include "voice_engine/transmit_mixer.h"
|
||||
#include "voice_engine/voice_engine_impl.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
VoEFile* VoEFile::GetInterface(VoiceEngine* voiceEngine) {
|
||||
if (NULL == voiceEngine) {
|
||||
return NULL;
|
||||
}
|
||||
VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
|
||||
s->AddRef();
|
||||
return s;
|
||||
}
|
||||
|
||||
VoEFileImpl::VoEFileImpl(voe::SharedData* shared) : _shared(shared) {
|
||||
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"VoEFileImpl::VoEFileImpl() - ctor");
|
||||
}
|
||||
|
||||
VoEFileImpl::~VoEFileImpl() {
|
||||
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"VoEFileImpl::~VoEFileImpl() - dtor");
|
||||
}
|
||||
|
||||
int VoEFileImpl::StartPlayingFileLocally(int channel,
|
||||
const char fileNameUTF8[1024],
|
||||
bool loop,
|
||||
FileFormats format,
|
||||
float volumeScaling,
|
||||
int startPointMs,
|
||||
int stopPointMs) {
|
||||
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartPlayingFileLocally(channel=%d, fileNameUTF8[]=%s, "
|
||||
"loop=%d, format=%d, volumeScaling=%5.3f, startPointMs=%d,"
|
||||
" stopPointMs=%d)",
|
||||
channel, fileNameUTF8, loop, format, volumeScaling, startPointMs,
|
||||
stopPointMs);
|
||||
static_assert(1024 == FileWrapper::kMaxFileNameSize, "");
|
||||
if (!_shared->statistics().Initialized()) {
|
||||
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||||
return -1;
|
||||
}
|
||||
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||||
voe::Channel* channelPtr = ch.channel();
|
||||
if (channelPtr == NULL) {
|
||||
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
||||
"StartPlayingFileLocally() failed to locate channel");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return channelPtr->StartPlayingFileLocally(fileNameUTF8, loop, format,
|
||||
startPointMs, volumeScaling,
|
||||
stopPointMs, NULL);
|
||||
}
|
||||
|
||||
int VoEFileImpl::StartPlayingFileLocally(int channel,
|
||||
InStream* stream,
|
||||
FileFormats format,
|
||||
float volumeScaling,
|
||||
int startPointMs,
|
||||
int stopPointMs) {
|
||||
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartPlayingFileLocally(channel=%d, stream, format=%d, "
|
||||
"volumeScaling=%5.3f, startPointMs=%d, stopPointMs=%d)",
|
||||
channel, format, volumeScaling, startPointMs, stopPointMs);
|
||||
|
||||
if (!_shared->statistics().Initialized()) {
|
||||
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||||
voe::Channel* channelPtr = ch.channel();
|
||||
if (channelPtr == NULL) {
|
||||
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
||||
"StartPlayingFileLocally() failed to locate channel");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return channelPtr->StartPlayingFileLocally(stream, format, startPointMs,
|
||||
volumeScaling, stopPointMs, NULL);
|
||||
}
|
||||
|
||||
int VoEFileImpl::StopPlayingFileLocally(int channel) {
|
||||
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StopPlayingFileLocally()");
|
||||
if (!_shared->statistics().Initialized()) {
|
||||
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||||
return -1;
|
||||
}
|
||||
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||||
voe::Channel* channelPtr = ch.channel();
|
||||
if (channelPtr == NULL) {
|
||||
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
||||
"StopPlayingFileLocally() failed to locate channel");
|
||||
return -1;
|
||||
}
|
||||
return channelPtr->StopPlayingFileLocally();
|
||||
}
|
||||
|
||||
int VoEFileImpl::IsPlayingFileLocally(int channel) {
|
||||
if (!_shared->statistics().Initialized()) {
|
||||
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||||
return -1;
|
||||
}
|
||||
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||||
voe::Channel* channelPtr = ch.channel();
|
||||
if (channelPtr == NULL) {
|
||||
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
||||
"StopPlayingFileLocally() failed to locate channel");
|
||||
return -1;
|
||||
}
|
||||
return channelPtr->IsPlayingFileLocally();
|
||||
}
|
||||
|
||||
int VoEFileImpl::StartPlayingFileAsMicrophone(int channel,
|
||||
const char fileNameUTF8[1024],
|
||||
bool loop,
|
||||
bool mixWithMicrophone,
|
||||
FileFormats format,
|
||||
float volumeScaling) {
|
||||
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartPlayingFileAsMicrophone(channel=%d, fileNameUTF8=%s, "
|
||||
"loop=%d, mixWithMicrophone=%d, format=%d, "
|
||||
"volumeScaling=%5.3f)",
|
||||
channel, fileNameUTF8, loop, mixWithMicrophone, format,
|
||||
volumeScaling);
|
||||
static_assert(1024 == FileWrapper::kMaxFileNameSize, "");
|
||||
if (!_shared->statistics().Initialized()) {
|
||||
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint32_t startPointMs(0);
|
||||
const uint32_t stopPointMs(0);
|
||||
|
||||
if (channel == -1) {
|
||||
int res = _shared->transmit_mixer()->StartPlayingFileAsMicrophone(
|
||||
fileNameUTF8, loop, format, startPointMs, volumeScaling, stopPointMs,
|
||||
NULL);
|
||||
if (res) {
|
||||
WEBRTC_TRACE(
|
||||
kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartPlayingFileAsMicrophone() failed to start playing file");
|
||||
return (-1);
|
||||
} else {
|
||||
_shared->transmit_mixer()->SetMixWithMicStatus(mixWithMicrophone);
|
||||
return (0);
|
||||
}
|
||||
} else {
|
||||
// Add file after demultiplexing <=> affects one channel only
|
||||
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||||
voe::Channel* channelPtr = ch.channel();
|
||||
if (channelPtr == NULL) {
|
||||
_shared->SetLastError(
|
||||
VE_CHANNEL_NOT_VALID, kTraceError,
|
||||
"StartPlayingFileAsMicrophone() failed to locate channel");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int res = channelPtr->StartPlayingFileAsMicrophone(
|
||||
fileNameUTF8, loop, format, startPointMs, volumeScaling, stopPointMs,
|
||||
NULL);
|
||||
if (res) {
|
||||
WEBRTC_TRACE(
|
||||
kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartPlayingFileAsMicrophone() failed to start playing file");
|
||||
return -1;
|
||||
} else {
|
||||
channelPtr->SetMixWithMicStatus(mixWithMicrophone);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int VoEFileImpl::StartPlayingFileAsMicrophone(int channel,
|
||||
InStream* stream,
|
||||
bool mixWithMicrophone,
|
||||
FileFormats format,
|
||||
float volumeScaling) {
|
||||
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartPlayingFileAsMicrophone(channel=%d, stream,"
|
||||
" mixWithMicrophone=%d, format=%d, volumeScaling=%5.3f)",
|
||||
channel, mixWithMicrophone, format, volumeScaling);
|
||||
|
||||
if (!_shared->statistics().Initialized()) {
|
||||
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint32_t startPointMs(0);
|
||||
const uint32_t stopPointMs(0);
|
||||
|
||||
if (channel == -1) {
|
||||
int res = _shared->transmit_mixer()->StartPlayingFileAsMicrophone(
|
||||
stream, format, startPointMs, volumeScaling, stopPointMs, NULL);
|
||||
if (res) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartPlayingFileAsMicrophone() failed to start "
|
||||
"playing stream");
|
||||
return (-1);
|
||||
} else {
|
||||
_shared->transmit_mixer()->SetMixWithMicStatus(mixWithMicrophone);
|
||||
return (0);
|
||||
}
|
||||
} else {
|
||||
// Add file after demultiplexing <=> affects one channel only
|
||||
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||||
voe::Channel* channelPtr = ch.channel();
|
||||
if (channelPtr == NULL) {
|
||||
_shared->SetLastError(
|
||||
VE_CHANNEL_NOT_VALID, kTraceError,
|
||||
"StartPlayingFileAsMicrophone() failed to locate channel");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int res = channelPtr->StartPlayingFileAsMicrophone(
|
||||
stream, format, startPointMs, volumeScaling, stopPointMs, NULL);
|
||||
if (res) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartPlayingFileAsMicrophone() failed to start "
|
||||
"playing stream");
|
||||
return -1;
|
||||
} else {
|
||||
channelPtr->SetMixWithMicStatus(mixWithMicrophone);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int VoEFileImpl::StopPlayingFileAsMicrophone(int channel) {
|
||||
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StopPlayingFileAsMicrophone(channel=%d)", channel);
|
||||
if (!_shared->statistics().Initialized()) {
|
||||
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||||
return -1;
|
||||
}
|
||||
if (channel == -1) {
|
||||
// Stop adding file before demultiplexing <=> affects all channels
|
||||
return _shared->transmit_mixer()->StopPlayingFileAsMicrophone();
|
||||
} else {
|
||||
// Stop adding file after demultiplexing <=> affects one channel only
|
||||
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||||
voe::Channel* channelPtr = ch.channel();
|
||||
if (channelPtr == NULL) {
|
||||
_shared->SetLastError(
|
||||
VE_CHANNEL_NOT_VALID, kTraceError,
|
||||
"StopPlayingFileAsMicrophone() failed to locate channel");
|
||||
return -1;
|
||||
}
|
||||
return channelPtr->StopPlayingFileAsMicrophone();
|
||||
}
|
||||
}
|
||||
|
||||
int VoEFileImpl::IsPlayingFileAsMicrophone(int channel) {
|
||||
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"IsPlayingFileAsMicrophone(channel=%d)", channel);
|
||||
if (!_shared->statistics().Initialized()) {
|
||||
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||||
return -1;
|
||||
}
|
||||
if (channel == -1) {
|
||||
return _shared->transmit_mixer()->IsPlayingFileAsMicrophone();
|
||||
} else {
|
||||
// Stop adding file after demultiplexing <=> affects one channel only
|
||||
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||||
voe::Channel* channelPtr = ch.channel();
|
||||
if (channelPtr == NULL) {
|
||||
_shared->SetLastError(
|
||||
VE_CHANNEL_NOT_VALID, kTraceError,
|
||||
"IsPlayingFileAsMicrophone() failed to locate channel");
|
||||
return -1;
|
||||
}
|
||||
return channelPtr->IsPlayingFileAsMicrophone();
|
||||
}
|
||||
}
|
||||
|
||||
int VoEFileImpl::StartRecordingPlayout(int channel,
|
||||
const char* fileNameUTF8,
|
||||
CodecInst* compression,
|
||||
int maxSizeBytes) {
|
||||
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartRecordingPlayout(channel=%d, fileNameUTF8=%s, "
|
||||
"compression, maxSizeBytes=%d)",
|
||||
channel, fileNameUTF8, maxSizeBytes);
|
||||
static_assert(1024 == FileWrapper::kMaxFileNameSize, "");
|
||||
|
||||
if (!_shared->statistics().Initialized()) {
|
||||
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||||
return -1;
|
||||
}
|
||||
if (channel == -1) {
|
||||
return _shared->output_mixer()->StartRecordingPlayout(fileNameUTF8,
|
||||
compression);
|
||||
} else {
|
||||
// Add file after demultiplexing <=> affects one channel only
|
||||
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||||
voe::Channel* channelPtr = ch.channel();
|
||||
if (channelPtr == NULL) {
|
||||
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
||||
"StartRecordingPlayout() failed to locate channel");
|
||||
return -1;
|
||||
}
|
||||
return channelPtr->StartRecordingPlayout(fileNameUTF8, compression);
|
||||
}
|
||||
}
|
||||
|
||||
int VoEFileImpl::StartRecordingPlayout(int channel,
|
||||
OutStream* stream,
|
||||
CodecInst* compression) {
|
||||
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartRecordingPlayout(channel=%d, stream, compression)",
|
||||
channel);
|
||||
if (!_shared->statistics().Initialized()) {
|
||||
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||||
return -1;
|
||||
}
|
||||
if (channel == -1) {
|
||||
return _shared->output_mixer()->StartRecordingPlayout(stream, compression);
|
||||
} else {
|
||||
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||||
voe::Channel* channelPtr = ch.channel();
|
||||
if (channelPtr == NULL) {
|
||||
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
||||
"StartRecordingPlayout() failed to locate channel");
|
||||
return -1;
|
||||
}
|
||||
return channelPtr->StartRecordingPlayout(stream, compression);
|
||||
}
|
||||
}
|
||||
|
||||
int VoEFileImpl::StopRecordingPlayout(int channel) {
|
||||
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StopRecordingPlayout(channel=%d)", channel);
|
||||
if (!_shared->statistics().Initialized()) {
|
||||
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||||
return -1;
|
||||
}
|
||||
if (channel == -1) {
|
||||
return _shared->output_mixer()->StopRecordingPlayout();
|
||||
} else {
|
||||
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||||
voe::Channel* channelPtr = ch.channel();
|
||||
if (channelPtr == NULL) {
|
||||
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
||||
"StopRecordingPlayout() failed to locate channel");
|
||||
return -1;
|
||||
}
|
||||
return channelPtr->StopRecordingPlayout();
|
||||
}
|
||||
}
|
||||
|
||||
int VoEFileImpl::StartRecordingMicrophone(const char* fileNameUTF8,
|
||||
CodecInst* compression,
|
||||
int maxSizeBytes) {
|
||||
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartRecordingMicrophone(fileNameUTF8=%s, compression, "
|
||||
"maxSizeBytes=%d)",
|
||||
fileNameUTF8, maxSizeBytes);
|
||||
static_assert(1024 == FileWrapper::kMaxFileNameSize, "");
|
||||
|
||||
if (!_shared->statistics().Initialized()) {
|
||||
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||||
return -1;
|
||||
}
|
||||
if (_shared->transmit_mixer()->StartRecordingMicrophone(fileNameUTF8,
|
||||
compression)) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartRecordingMicrophone() failed to start recording");
|
||||
return -1;
|
||||
}
|
||||
if (!_shared->audio_device()->Recording()) {
|
||||
if (_shared->audio_device()->InitRecording() != 0) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartRecordingMicrophone() failed to initialize recording");
|
||||
return -1;
|
||||
}
|
||||
if (_shared->audio_device()->StartRecording() != 0) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartRecordingMicrophone() failed to start recording");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int VoEFileImpl::StartRecordingMicrophone(OutStream* stream,
|
||||
CodecInst* compression) {
|
||||
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartRecordingMicrophone(stream, compression)");
|
||||
|
||||
if (!_shared->statistics().Initialized()) {
|
||||
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||||
return -1;
|
||||
}
|
||||
if (_shared->transmit_mixer()->StartRecordingMicrophone(stream,
|
||||
compression) == -1) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartRecordingMicrophone() failed to start recording");
|
||||
return -1;
|
||||
}
|
||||
if (!_shared->audio_device()->Recording()) {
|
||||
if (_shared->audio_device()->InitRecording() != 0) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartRecordingMicrophone() failed to initialize recording");
|
||||
return -1;
|
||||
}
|
||||
if (_shared->audio_device()->StartRecording() != 0) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StartRecordingMicrophone() failed to start recording");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int VoEFileImpl::StopRecordingMicrophone() {
|
||||
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StopRecordingMicrophone()");
|
||||
if (!_shared->statistics().Initialized()) {
|
||||
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int err = 0;
|
||||
|
||||
// TODO(xians): consider removing Start/StopRecording() in
|
||||
// Start/StopRecordingMicrophone() if no channel is recording.
|
||||
if (_shared->NumOfSendingChannels() == 0 &&
|
||||
_shared->audio_device()->Recording()) {
|
||||
// Stop audio-device recording if no channel is recording
|
||||
if (_shared->audio_device()->StopRecording() != 0) {
|
||||
_shared->SetLastError(
|
||||
VE_CANNOT_STOP_RECORDING, kTraceError,
|
||||
"StopRecordingMicrophone() failed to stop recording");
|
||||
err = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (_shared->transmit_mixer()->StopRecordingMicrophone() != 0) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||||
"StopRecordingMicrophone() failed to stop recording to mixer");
|
||||
err = -1;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -1,95 +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 VOICE_ENGINE_VOE_FILE_IMPL_H_
|
||||
#define VOICE_ENGINE_VOE_FILE_IMPL_H_
|
||||
|
||||
#include "voice_engine/include/voe_file.h"
|
||||
#include "voice_engine/shared_data.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class VoEFileImpl : public VoEFile {
|
||||
public:
|
||||
// Playout file locally
|
||||
|
||||
int StartPlayingFileLocally(int channel,
|
||||
const char fileNameUTF8[1024],
|
||||
bool loop = false,
|
||||
FileFormats format = kFileFormatPcm16kHzFile,
|
||||
float volumeScaling = 1.0,
|
||||
int startPointMs = 0,
|
||||
int stopPointMs = 0) override;
|
||||
|
||||
int StartPlayingFileLocally(int channel,
|
||||
InStream* stream,
|
||||
FileFormats format = kFileFormatPcm16kHzFile,
|
||||
float volumeScaling = 1.0,
|
||||
int startPointMs = 0,
|
||||
int stopPointMs = 0) override;
|
||||
|
||||
int StopPlayingFileLocally(int channel) override;
|
||||
|
||||
int IsPlayingFileLocally(int channel) override;
|
||||
|
||||
// Use file as microphone input
|
||||
|
||||
int StartPlayingFileAsMicrophone(int channel,
|
||||
const char fileNameUTF8[1024],
|
||||
bool loop = false,
|
||||
bool mixWithMicrophone = false,
|
||||
FileFormats format = kFileFormatPcm16kHzFile,
|
||||
float volumeScaling = 1.0) override;
|
||||
|
||||
int StartPlayingFileAsMicrophone(int channel,
|
||||
InStream* stream,
|
||||
bool mixWithMicrophone = false,
|
||||
FileFormats format = kFileFormatPcm16kHzFile,
|
||||
float volumeScaling = 1.0) override;
|
||||
|
||||
int StopPlayingFileAsMicrophone(int channel) override;
|
||||
|
||||
int IsPlayingFileAsMicrophone(int channel) override;
|
||||
|
||||
// Record speaker signal to file
|
||||
|
||||
int StartRecordingPlayout(int channel,
|
||||
const char* fileNameUTF8,
|
||||
CodecInst* compression = NULL,
|
||||
int maxSizeBytes = -1) override;
|
||||
|
||||
int StartRecordingPlayout(int channel,
|
||||
OutStream* stream,
|
||||
CodecInst* compression = NULL) override;
|
||||
|
||||
int StopRecordingPlayout(int channel) override;
|
||||
|
||||
// Record microphone signal to file
|
||||
|
||||
int StartRecordingMicrophone(const char* fileNameUTF8,
|
||||
CodecInst* compression = NULL,
|
||||
int maxSizeBytes = -1) override;
|
||||
|
||||
int StartRecordingMicrophone(OutStream* stream,
|
||||
CodecInst* compression = NULL) override;
|
||||
|
||||
int StopRecordingMicrophone() override;
|
||||
|
||||
protected:
|
||||
VoEFileImpl(voe::SharedData* shared);
|
||||
~VoEFileImpl() override;
|
||||
|
||||
private:
|
||||
voe::SharedData* _shared;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // VOICE_ENGINE_VOE_FILE_IMPL_H_
|
||||
@ -17,7 +17,6 @@
|
||||
#include "typedefs.h" // NOLINT(build/include)
|
||||
#include "voice_engine/voe_base_impl.h"
|
||||
#include "voice_engine/voe_codec_impl.h"
|
||||
#include "voice_engine/voe_file_impl.h"
|
||||
#include "voice_engine/voe_network_impl.h"
|
||||
#include "voice_engine/voe_rtp_rtcp_impl.h"
|
||||
|
||||
@ -29,7 +28,6 @@ class ChannelProxy;
|
||||
class VoiceEngineImpl : public voe::SharedData, // Must be the first base class
|
||||
public VoiceEngine,
|
||||
public VoECodecImpl,
|
||||
public VoEFileImpl,
|
||||
public VoENetworkImpl,
|
||||
public VoERTP_RTCPImpl,
|
||||
public VoEBaseImpl {
|
||||
@ -37,7 +35,6 @@ class VoiceEngineImpl : public voe::SharedData, // Must be the first base class
|
||||
VoiceEngineImpl()
|
||||
: SharedData(),
|
||||
VoECodecImpl(this),
|
||||
VoEFileImpl(this),
|
||||
VoENetworkImpl(this),
|
||||
VoERTP_RTCPImpl(this),
|
||||
VoEBaseImpl(this),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user