Add GetAudioFrame API to VoiceEngine.

Allows the caller to pull frames from a channel instead of sending them to the output mixer.

BUG=

Review URL: https://webrtc-codereview.appspot.com/973012

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3273 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
roosa@google.com 2012-12-12 23:00:29 +00:00
parent b718619f0a
commit 1b60ceb499
6 changed files with 199 additions and 14 deletions

View File

@ -1133,6 +1133,7 @@ Channel::Channel(const WebRtc_Word32 channelId,
_rtcpObserverPtr(NULL),
_outputIsOnHold(false),
_externalPlayout(false),
_externalMixing(false),
_inputIsOnHold(false),
_playing(false),
_sending(false),
@ -1601,13 +1602,16 @@ Channel::StartPlayout()
{
return 0;
}
// Add participant as candidates for mixing.
if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
{
_engineStatisticsPtr->SetLastError(
VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
"StartPlayout() failed to add participant to mixer");
return -1;
if (!_externalMixing) {
// Add participant as candidates for mixing.
if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
{
_engineStatisticsPtr->SetLastError(
VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
"StartPlayout() failed to add participant to mixer");
return -1;
}
}
_playing = true;
@ -1627,13 +1631,16 @@ Channel::StopPlayout()
{
return 0;
}
// Remove participant as candidates for mixing
if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
{
_engineStatisticsPtr->SetLastError(
VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
"StartPlayout() failed to remove participant from mixer");
return -1;
if (!_externalMixing) {
// Remove participant as candidates for mixing
if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
{
_engineStatisticsPtr->SetLastError(
VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
"StopPlayout() failed to remove participant from mixer");
return -1;
}
}
_playing = false;
@ -5981,6 +5988,24 @@ int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
return 0;
}
int Channel::SetExternalMixing(bool enabled) {
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
"Channel::SetExternalMixing(enabled=%d)", enabled);
if (_playing)
{
_engineStatisticsPtr->SetLastError(
VE_INVALID_OPERATION, kTraceError,
"Channel::SetExternalMixing() "
"external mixing cannot be changed while playing.");
return -1;
}
_externalMixing = enabled;
return 0;
}
int
Channel::ResetRTCPStatistics()
{

View File

@ -231,6 +231,7 @@ public:
int RegisterExternalMediaProcessing(ProcessingTypes type,
VoEMediaProcess& processObject);
int DeRegisterExternalMediaProcessing(ProcessingTypes type);
int SetExternalMixing(bool enabled);
// VoEVolumeControl
int GetSpeechOutputLevel(WebRtc_UWord32& level) const;
@ -494,6 +495,10 @@ public:
{
return _externalTransport;
}
bool ExternalMixing() const
{
return _externalMixing;
}
bool OutputIsOnHold() const
{
return _outputIsOnHold;
@ -611,6 +616,7 @@ private:
// VoEBase
bool _outputIsOnHold;
bool _externalPlayout;
bool _externalMixing;
bool _inputIsOnHold;
bool _playing;
bool _sending;

View File

@ -37,6 +37,7 @@
namespace webrtc {
class VoiceEngine;
class AudioFrame;
class WEBRTC_DLLEXPORT VoEMediaProcess
{
@ -104,6 +105,16 @@ public:
WebRtc_Word16 speechData10ms[], int samplingFreqHz,
int current_delay_ms, int& lengthSamples) = 0;
// Pulls an audio frame from the specified |channel| for external mixing.
// If the |desired_sample_rate_hz| is 0, the signal will be returned with
// its native frequency, otherwise it will be resampled. Valid frequencies
// are 16, 22, 32, 44 or 48 kHz.
virtual int GetAudioFrame(int channel, int desired_sample_rate_hz,
AudioFrame* frame) = 0;
// Sets the state of external mixing. Cannot be changed during playback.
virtual int SetExternalMixing(int channel, bool enable) = 0;
protected:
VoEExternalMedia() {}
virtual ~VoEExternalMedia() {}

View File

@ -8,6 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/interface/module_common_types.h"
#include "voice_engine/include/voe_external_media.h"
#include "voice_engine/test/auto_test/fakes/fake_media_process.h"
#include "voice_engine/test/auto_test/fixtures/after_streaming_fixture.h"
@ -82,3 +83,80 @@ TEST_F(ExternalMediaTest,
TEST_LOG("Speak and verify your voice is distorted.\n");
TestRegisterExternalMedia(-1, webrtc::kRecordingAllChannelsMixed);
}
TEST_F(ExternalMediaTest,
ExternalMixingCannotBeChangedDuringPlayback) {
EXPECT_EQ(-1, voe_xmedia_->SetExternalMixing(channel_, true));
EXPECT_EQ(-1, voe_xmedia_->SetExternalMixing(channel_, false));
}
TEST_F(ExternalMediaTest,
ExternalMixingIsRequiredForGetAudioFrame) {
webrtc::AudioFrame frame;
EXPECT_EQ(-1, voe_xmedia_->GetAudioFrame(channel_, 0, &frame));
}
TEST_F(ExternalMediaTest,
ExternalMixingPreventsAndRestoresRegularPlayback) {
PausePlaying();
ASSERT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, true));
TEST_LOG("Verify that no sound is played out.\n");
ResumePlaying();
Sleep(1000);
PausePlaying();
ASSERT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, false));
ResumePlaying();
TEST_LOG("Verify that sound is played out.\n");
ResumePlaying();
Sleep(1000);
}
TEST_F(ExternalMediaTest,
ExternalMixingWorks) {
webrtc::AudioFrame frame;
PausePlaying();
EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, true));
ResumePlaying();
EXPECT_EQ(0, voe_xmedia_->GetAudioFrame(channel_, 0, &frame));
EXPECT_LT(0, frame.sample_rate_hz_);
EXPECT_LT(0, frame.samples_per_channel_);
PausePlaying();
EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, false));
ResumePlaying();
}
TEST_F(ExternalMediaTest,
ExternalMixingResamplesToDesiredFrequency) {
const int kValidFrequencies[] = {8000, 16000, 22000, 32000, 48000};
webrtc::AudioFrame frame;
PausePlaying();
EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, true));
ResumePlaying();
for (size_t i = 0; i < sizeof(kValidFrequencies) / sizeof(int); i++) {
int f = kValidFrequencies[i];
EXPECT_EQ(0, voe_xmedia_->GetAudioFrame(channel_, f, &frame))
<< "Resampling succeeds for freq=" << f;
EXPECT_EQ(f, frame.sample_rate_hz_);
EXPECT_EQ(f / 100, frame.samples_per_channel_);
}
PausePlaying();
EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, false));
ResumePlaying();
}
TEST_F(ExternalMediaTest,
ExternalMixingResamplingToInvalidFrequenciesFails) {
const int kInvalidFrequencies[] = {-8000, -1, 1, 1000, 8001, 16001};
webrtc::AudioFrame frame;
PausePlaying();
EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, true));
ResumePlaying();
for (size_t i = 0; i < sizeof(kInvalidFrequencies) / sizeof(int); i++) {
int f = kInvalidFrequencies[i];
EXPECT_EQ(-1, voe_xmedia_->GetAudioFrame(channel_, f, &frame))
<< "Resampling fails for freq=" << f;
}
PausePlaying();
EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, false));
ResumePlaying();
}

View File

@ -346,6 +346,66 @@ int VoEExternalMediaImpl::ExternalPlayoutGetData(
#endif
}
int VoEExternalMediaImpl::GetAudioFrame(int channel, int desired_sample_rate_hz,
AudioFrame* frame) {
WEBRTC_TRACE(kTraceApiCall, kTraceVoice,
VoEId(shared_->instance_id(), channel),
"GetAudioFrame(channel=%d, desired_sample_rate_hz=%d)",
channel, desired_sample_rate_hz);
if (!shared_->statistics().Initialized())
{
shared_->SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
voe::ScopedChannel sc(shared_->channel_manager(), channel);
voe::Channel* channelPtr = sc.ChannelPtr();
if (channelPtr == NULL)
{
shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
"GetAudioFrame() failed to locate channel");
return -1;
}
if (!channelPtr->ExternalMixing()) {
shared_->SetLastError(VE_INVALID_OPERATION, kTraceError,
"GetAudioFrame() was called on channel that is not"
" externally mixed.");
return -1;
}
if (!channelPtr->Playing()) {
shared_->SetLastError(VE_INVALID_OPERATION, kTraceError,
"GetAudioFrame() was called on channel that is not playing.");
return -1;
}
if (desired_sample_rate_hz == -1) {
shared_->SetLastError(VE_BAD_ARGUMENT, kTraceError,
"GetAudioFrame() was called with bad sample rate.");
return -1;
}
frame->sample_rate_hz_ = desired_sample_rate_hz == 0 ? -1 :
desired_sample_rate_hz;
return channelPtr->GetAudioFrame(channel, *frame);
}
int VoEExternalMediaImpl::SetExternalMixing(int channel, bool enable) {
WEBRTC_TRACE(kTraceApiCall, kTraceVoice,
VoEId(shared_->instance_id(), channel),
"SetExternalMixing(channel=%d, enable=%d)", channel, enable);
if (!shared_->statistics().Initialized())
{
shared_->SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
voe::ScopedChannel sc(shared_->channel_manager(), channel);
voe::Channel* channelPtr = sc.ChannelPtr();
if (channelPtr == NULL)
{
shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
"SetExternalMixing() failed to locate channel");
return -1;
}
return channelPtr->SetExternalMixing(enable);
}
#endif // WEBRTC_VOICE_ENGINE_EXTERNAL_MEDIA_API
} // namespace webrtc

View File

@ -44,6 +44,11 @@ public:
int current_delay_ms,
int& lengthSamples);
virtual int GetAudioFrame(int channel, int desired_sample_rate_hz,
AudioFrame* frame);
virtual int SetExternalMixing(int channel, bool enable);
protected:
VoEExternalMediaImpl(voe::SharedData* shared);
virtual ~VoEExternalMediaImpl();