Replace VoEBase::[Start/Stop]Playout().

The functionality is moved into AudioState.

TBR: henrika@webrtc.org
Bug: webrtc:4690
Change-Id: I015482ad18a39609634f6ead9e991d5210107f0f
Reviewed-on: https://webrtc-review.googlesource.com/34502
Reviewed-by: Fredrik Solenberg <solenberg@webrtc.org>
Commit-Queue: Fredrik Solenberg <solenberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#21338}
This commit is contained in:
Fredrik Solenberg 2017-12-18 22:41:03 +01:00 committed by Commit Bot
parent 086c9f5e4e
commit d5247510dc
16 changed files with 110 additions and 210 deletions

View File

@ -118,9 +118,7 @@ AudioReceiveStream::AudioReceiveStream(
AudioReceiveStream::~AudioReceiveStream() {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
RTC_LOG(LS_INFO) << "~AudioReceiveStream: " << config_.ToString();
if (playing_) {
Stop();
}
Stop();
channel_proxy_->DisassociateSendChannel();
channel_proxy_->RegisterTransport(nullptr);
channel_proxy_->ResetReceiverCongestionControlObjects();
@ -132,21 +130,9 @@ void AudioReceiveStream::Start() {
if (playing_) {
return;
}
int error = SetVoiceEnginePlayout(true);
if (error != 0) {
RTC_LOG(LS_ERROR) << "AudioReceiveStream::Start failed with error: "
<< error;
return;
}
if (!audio_state()->mixer()->AddSource(this)) {
RTC_LOG(LS_ERROR) << "Failed to add source to mixer.";
SetVoiceEnginePlayout(false);
return;
}
channel_proxy_->StartPlayout();
playing_ = true;
audio_state()->AddReceivingStream(this);
}
void AudioReceiveStream::Stop() {
@ -154,10 +140,9 @@ void AudioReceiveStream::Stop() {
if (!playing_) {
return;
}
channel_proxy_->StopPlayout();
playing_ = false;
audio_state()->mixer()->RemoveSource(this);
SetVoiceEnginePlayout(false);
audio_state()->RemoveReceivingStream(this);
}
webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const {
@ -344,14 +329,5 @@ internal::AudioState* AudioReceiveStream::audio_state() const {
RTC_DCHECK(audio_state);
return audio_state;
}
int AudioReceiveStream::SetVoiceEnginePlayout(bool playout) {
ScopedVoEInterface<VoEBase> base(voice_engine());
if (playout) {
return base->StartPlayout(config_.voe_channel_id);
} else {
return base->StopPlayout(config_.voe_channel_id);
}
}
} // namespace internal
} // namespace webrtc

View File

@ -82,7 +82,6 @@ class AudioReceiveStream final : public webrtc::AudioReceiveStream,
private:
VoiceEngine* voice_engine() const;
AudioState* audio_state() const;
int SetVoiceEnginePlayout(bool playout);
rtc::ThreadChecker worker_thread_checker_;
rtc::ThreadChecker module_process_thread_checker_;

View File

@ -48,7 +48,8 @@ AudioDecodingCallStats MakeAudioDecodeStatsForTest() {
return audio_decode_stats;
}
const int kChannelId = 2;
const int kChannelId1 = 2;
const int kChannelId2 = 29;
const uint32_t kRemoteSsrc = 1234;
const uint32_t kLocalSsrc = 5678;
const size_t kOneByteExtensionHeaderLength = 4;
@ -84,7 +85,7 @@ struct ConfigHelper {
new rtc::RefCountedObject<MockAudioDeviceModule>();
audio_state_ = AudioState::Create(config);
EXPECT_CALL(voice_engine_, ChannelProxyFactory(kChannelId))
EXPECT_CALL(voice_engine_, ChannelProxyFactory(kChannelId1))
.WillOnce(Invoke([this](int channel_id) {
EXPECT_FALSE(channel_proxy_);
channel_proxy_ = new testing::StrictMock<MockVoEChannelProxy>();
@ -118,7 +119,15 @@ struct ConfigHelper {
}));
return channel_proxy_;
}));
stream_config_.voe_channel_id = kChannelId;
EXPECT_CALL(voice_engine_, ChannelProxyFactory(kChannelId2))
.WillRepeatedly(Invoke([this](int channel_id) {
testing::NiceMock<MockVoEChannelProxy>* proxy =
new testing::NiceMock<MockVoEChannelProxy>();
EXPECT_CALL(*proxy, GetAudioDecoderFactory())
.WillOnce(ReturnRef(decoder_factory_));
return proxy;
}));
stream_config_.voe_channel_id = kChannelId1;
stream_config_.rtp.local_ssrc = kLocalSsrc;
stream_config_.rtp.remote_ssrc = kRemoteSsrc;
stream_config_.rtp.nack.rtp_history_ms = 300;
@ -231,7 +240,7 @@ TEST(AudioReceiveStreamTest, ConfigToString) {
AudioReceiveStream::Config config;
config.rtp.remote_ssrc = kRemoteSsrc;
config.rtp.local_ssrc = kLocalSsrc;
config.voe_channel_id = kChannelId;
config.voe_channel_id = kChannelId1;
config.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAudioLevelUri, kAudioLevelId));
EXPECT_EQ(
@ -354,32 +363,36 @@ TEST(AudioReceiveStreamTest, SetGain) {
recv_stream.SetGain(0.765f);
}
TEST(AudioReceiveStreamTest, StreamShouldNotBeAddedToMixerWhenVoEReturnsError) {
TEST(AudioReceiveStreamTest, StreamsShouldBeAddedToMixerOnceOnStart) {
ConfigHelper helper;
internal::AudioReceiveStream recv_stream(
internal::AudioReceiveStream recv_stream1(
helper.rtp_stream_receiver_controller(),
helper.packet_router(),
helper.config(), helper.audio_state(), helper.event_log());
EXPECT_CALL(helper.voice_engine(), StartPlayout(_)).WillOnce(Return(-1));
EXPECT_CALL(*helper.audio_mixer(), AddSource(_)).Times(0);
recv_stream.Start();
}
TEST(AudioReceiveStreamTest, StreamShouldBeAddedToMixerOnStart) {
ConfigHelper helper;
internal::AudioReceiveStream recv_stream(
AudioReceiveStream::Config config2 = helper.config();
config2.voe_channel_id = kChannelId2;
internal::AudioReceiveStream recv_stream2(
helper.rtp_stream_receiver_controller(),
helper.packet_router(),
helper.config(), helper.audio_state(), helper.event_log());
config2, helper.audio_state(), helper.event_log());
EXPECT_CALL(helper.voice_engine(), StartPlayout(_)).WillOnce(Return(0));
EXPECT_CALL(helper.voice_engine(), StopPlayout(_));
EXPECT_CALL(*helper.audio_mixer(), AddSource(&recv_stream))
EXPECT_CALL(*helper.channel_proxy(), StartPlayout()).Times(1);
EXPECT_CALL(*helper.channel_proxy(), StopPlayout()).Times(1);
EXPECT_CALL(*helper.audio_mixer(), AddSource(&recv_stream1))
.WillOnce(Return(true));
EXPECT_CALL(*helper.audio_mixer(), AddSource(&recv_stream2))
.WillOnce(Return(true));
EXPECT_CALL(*helper.audio_mixer(), RemoveSource(&recv_stream1)).Times(1);
EXPECT_CALL(*helper.audio_mixer(), RemoveSource(&recv_stream2)).Times(1);
recv_stream.Start();
recv_stream1.Start();
recv_stream2.Start();
// One more should not result in any more mixer sources added.
recv_stream1.Start();
// Stop stream before it is being destructed.
recv_stream2.Stop();
}
} // namespace test
} // namespace webrtc

View File

@ -14,6 +14,7 @@
#include <utility>
#include <vector>
#include "audio/audio_receive_stream.h"
#include "modules/audio_device/include/audio_device.h"
#include "rtc_base/atomicops.h"
#include "rtc_base/checks.h"
@ -37,6 +38,7 @@ AudioState::AudioState(const AudioState::Config& config)
AudioState::~AudioState() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
RTC_DCHECK(receiving_streams_.empty());
RTC_DCHECK(sending_streams_.empty());
}
@ -45,16 +47,44 @@ VoiceEngine* AudioState::voice_engine() {
return config_.voice_engine;
}
rtc::scoped_refptr<AudioMixer> AudioState::mixer() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
return config_.audio_mixer;
}
bool AudioState::typing_noise_detected() const {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
return audio_transport_.typing_noise_detected();
}
void AudioState::AddReceivingStream(webrtc::AudioReceiveStream* stream) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
RTC_DCHECK_EQ(0, receiving_streams_.count(stream));
receiving_streams_.insert(stream);
if (!config_.audio_mixer->AddSource(
static_cast<internal::AudioReceiveStream*>(stream))) {
RTC_LOG(LS_ERROR) << "Failed to add source to mixer.";
}
// Make sure playback is initialized; start playing if enabled.
auto* adm = config_.audio_device_module.get();
if (!adm->Playing()) {
if (adm->InitPlayout() == 0) {
if (playout_enabled_) {
adm->StartPlayout();
}
} else {
RTC_DLOG_F(LS_ERROR) << "Failed to initialize playout.";
}
}
}
void AudioState::RemoveReceivingStream(webrtc::AudioReceiveStream* stream) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
auto count = receiving_streams_.erase(stream);
RTC_DCHECK_EQ(1, count);
config_.audio_mixer->RemoveSource(
static_cast<internal::AudioReceiveStream*>(stream));
if (receiving_streams_.empty()) {
config_.audio_device_module->StopPlayout();
}
}
void AudioState::AddSendingStream(webrtc::AudioSendStream* stream,
int sample_rate_hz, size_t num_channels) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
@ -89,20 +119,18 @@ void AudioState::RemoveSendingStream(webrtc::AudioSendStream* stream) {
void AudioState::SetPlayout(bool enabled) {
RTC_LOG(INFO) << "SetPlayout(" << enabled << ")";
RTC_DCHECK(thread_checker_.CalledOnValidThread());
const bool currently_enabled = (null_audio_poller_ == nullptr);
if (enabled == currently_enabled) {
return;
}
if (enabled) {
null_audio_poller_.reset();
}
// Will stop/start playout of the underlying device, if necessary, and
// remember the setting for when it receives subsequent calls of
// StartPlayout.
voe_base_->SetPlayout(enabled);
if (!enabled) {
null_audio_poller_ =
rtc::MakeUnique<NullAudioPoller>(&audio_transport_);
if (playout_enabled_ != enabled) {
playout_enabled_ = enabled;
if (enabled) {
null_audio_poller_.reset();
if (!receiving_streams_.empty()) {
config_.audio_device_module->StartPlayout();
}
} else {
config_.audio_device_module->StopPlayout();
null_audio_poller_ =
rtc::MakeUnique<NullAudioPoller>(&audio_transport_);
}
}
}
@ -157,7 +185,7 @@ rtc::RefCountReleaseStatus AudioState::Release() const {
void AudioState::UpdateAudioTransportWithSendingStreams() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
std::vector<AudioSendStream*> sending_streams;
std::vector<webrtc::AudioSendStream*> sending_streams;
int max_sample_rate_hz = 8000;
size_t max_num_channels = 1;
for (const auto& kv : sending_streams_) {

View File

@ -13,6 +13,7 @@
#include <map>
#include <memory>
#include <unordered_set>
#include "audio/audio_transport_impl.h"
#include "audio/null_audio_poller.h"
@ -27,6 +28,7 @@
namespace webrtc {
class AudioSendStream;
class AudioReceiveStream;
namespace internal {
@ -50,9 +52,11 @@ class AudioState final : public webrtc::AudioState {
void SetStereoChannelSwapping(bool enable) override;
VoiceEngine* voice_engine();
rtc::scoped_refptr<AudioMixer> mixer();
bool typing_noise_detected() const;
void AddReceivingStream(webrtc::AudioReceiveStream* stream);
void RemoveReceivingStream(webrtc::AudioReceiveStream* stream);
void AddSendingStream(webrtc::AudioSendStream* stream,
int sample_rate_hz, size_t num_channels);
void RemoveSendingStream(webrtc::AudioSendStream* stream);
@ -68,6 +72,7 @@ class AudioState final : public webrtc::AudioState {
rtc::ThreadChecker process_thread_checker_;
const webrtc::AudioState::Config config_;
bool recording_enabled_ = true;
bool playout_enabled_ = true;
// We hold one interface pointer to the VoE to make sure it is kept alive.
ScopedVoEInterface<VoEBase> voe_base_;
@ -85,6 +90,7 @@ class AudioState final : public webrtc::AudioState {
// stats are still updated.
std::unique_ptr<NullAudioPoller> null_audio_poller_;
std::unordered_set<webrtc::AudioReceiveStream*> receiving_streams_;
struct StreamProperties {
int sample_rate_hz = 0;
size_t num_channels = 0;

View File

@ -81,9 +81,6 @@ class FakeWebRtcVoiceEngine : public webrtc::VoEBase {
channels_.erase(channel);
return 0;
}
WEBRTC_STUB(StartPlayout, (int channel));
WEBRTC_STUB(StopPlayout, (int channel));
WEBRTC_STUB(SetPlayout, (bool enable));
size_t GetNetEqCapacity() const {
auto ch = channels_.find(last_channel_);

View File

@ -100,6 +100,8 @@ class MockVoEChannelProxy : public voe::ChannelProxy {
MOCK_CONST_METHOD0(GetSources, std::vector<RtpSource>());
MOCK_METHOD0(StartSend, void());
MOCK_METHOD0(StopSend, void());
MOCK_METHOD0(StartPlayout, void());
MOCK_METHOD0(StopPlayout, void());
};
} // namespace test
} // namespace webrtc

View File

@ -90,8 +90,6 @@ class MockVoiceEngine : public VoiceEngineImpl {
MOCK_METHOD0(CreateChannel, int());
MOCK_METHOD1(CreateChannel, int(const ChannelConfig& config));
MOCK_METHOD1(DeleteChannel, int(int channel));
MOCK_METHOD1(StartPlayout, int(int channel));
MOCK_METHOD1(StopPlayout, int(int channel));
private:
// TODO(ossu): I'm not particularly happy about keeping the decoder factory

View File

@ -2080,7 +2080,6 @@ void VideoQualityTest::RunWithRenderers(const Params& params) {
if (params_.audio.enabled) {
// Start receiving audio.
audio_receive_stream->Start();
EXPECT_EQ(0, voe.base->StartPlayout(voe.receive_channel_id));
// Start sending audio.
audio_send_stream_->Start();
@ -2095,7 +2094,6 @@ void VideoQualityTest::RunWithRenderers(const Params& params) {
audio_send_stream_->Stop();
// Stop receiving audio.
EXPECT_EQ(0, voe.base->StopPlayout(voe.receive_channel_id));
audio_receive_stream->Stop();
sender_call_->DestroyAudioSendStream(audio_send_stream_);
receiver_call_->DestroyAudioReceiveStream(audio_receive_stream);

View File

@ -343,6 +343,18 @@ void ChannelProxy::StopSend() {
channel()->StopSend();
}
void ChannelProxy::StartPlayout() {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
int error = channel()->StartPlayout();
RTC_DCHECK_EQ(0, error);
}
void ChannelProxy::StopPlayout() {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
int error = channel()->StopPlayout();
RTC_DCHECK_EQ(0, error);
}
Channel* ChannelProxy::channel() const {
RTC_DCHECK(channel_owner_.channel());
return channel_owner_.channel();

View File

@ -123,6 +123,8 @@ class ChannelProxy : public RtpPacketSinkInterface {
virtual std::vector<webrtc::RtpSource> GetSources() const;
virtual void StartSend();
virtual void StopSend();
virtual void StartPlayout();
virtual void StopPlayout();
private:
Channel* channel() const;

View File

@ -109,21 +109,6 @@ class WEBRTC_DLLEXPORT VoEBase {
// Returns -1 in case of an error, 0 otherwise.
virtual int DeleteChannel(int channel) = 0;
// Starts forwarding the packets to the mixer/soundcard for a
// specified |channel|.
virtual int StartPlayout(int channel) = 0;
// Stops forwarding the packets to the mixer/soundcard for a
// specified |channel|.
virtual int StopPlayout(int channel) = 0;
// Enable or disable playout to the underlying device. Takes precedence over
// StartPlayout. Though calls to StartPlayout are remembered; if
// SetPlayout(true) is called after StartPlayout, playout will be started.
//
// By default, playout is enabled.
virtual int SetPlayout(bool enabled) = 0;
protected:
VoEBase() {}
virtual ~VoEBase() {}

View File

@ -43,20 +43,6 @@ void SharedData::set_audio_device(
const rtc::scoped_refptr<AudioDeviceModule>& audio_device) {
_audioDevicePtr = audio_device;
}
int SharedData::NumOfPlayingChannels() {
ChannelManager::Iterator it(&_channelManager);
int playout_channels = 0;
for (ChannelManager::Iterator it(&_channelManager); it.IsValid();
it.Increment()) {
if (it.GetChannel()->Playing())
++playout_channels;
}
return playout_channels;
}
} // namespace voe
} // namespace webrtc

View File

@ -40,8 +40,6 @@ public:
ProcessThread* process_thread() { return _moduleProcessThreadPtr.get(); }
rtc::TaskQueue* encoder_queue();
int NumOfPlayingChannels();
protected:
rtc::ThreadChecker construction_thread_;
const uint32_t _instanceId;

View File

@ -107,99 +107,9 @@ int VoEBaseImpl::DeleteChannel(int channel) {
}
shared_->channel_manager().DestroyChannel(channel);
if (StopPlayout() != 0) {
return -1;
}
return 0;
}
int VoEBaseImpl::StartPlayout(int channel) {
rtc::CritScope cs(shared_->crit_sec());
voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
voe::Channel* channelPtr = ch.channel();
if (channelPtr == nullptr) {
RTC_LOG(LS_ERROR) << "StartPlayout() failed to locate channel";
return -1;
}
if (channelPtr->Playing()) {
return 0;
}
if (StartPlayout() != 0) {
RTC_LOG(LS_ERROR) << "StartPlayout() failed to start playout";
return -1;
}
return channelPtr->StartPlayout();
}
int VoEBaseImpl::StopPlayout(int channel) {
rtc::CritScope cs(shared_->crit_sec());
voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
voe::Channel* channelPtr = ch.channel();
if (channelPtr == nullptr) {
RTC_LOG(LS_ERROR) << "StopPlayout() failed to locate channel";
return -1;
}
if (channelPtr->StopPlayout() != 0) {
RTC_LOG_F(LS_WARNING) << "StopPlayout() failed to stop playout for channel "
<< channel;
}
return StopPlayout();
}
int32_t VoEBaseImpl::StartPlayout() {
if (!shared_->audio_device()->Playing()) {
if (shared_->audio_device()->InitPlayout() != 0) {
RTC_LOG_F(LS_ERROR) << "Failed to initialize playout";
return -1;
}
if (playout_enabled_ && shared_->audio_device()->StartPlayout() != 0) {
RTC_LOG_F(LS_ERROR) << "Failed to start playout";
return -1;
}
}
return 0;
}
int32_t VoEBaseImpl::StopPlayout() {
if (!playout_enabled_) {
return 0;
}
// Stop audio-device playing if no channel is playing out.
if (shared_->NumOfPlayingChannels() == 0) {
if (shared_->audio_device()->StopPlayout() != 0) {
RTC_LOG(LS_ERROR) << "StopPlayout() failed to stop playout";
return -1;
}
}
return 0;
}
int32_t VoEBaseImpl::SetPlayout(bool enabled) {
RTC_LOG(INFO) << "SetPlayout(" << enabled << ")";
if (playout_enabled_ == enabled) {
return 0;
}
playout_enabled_ = enabled;
if (shared_->NumOfPlayingChannels() == 0) {
// If there are no channels attempting to play out yet, there's nothing to
// be done; we should be in a "not playing out" state either way.
return 0;
}
int32_t ret;
if (enabled) {
ret = shared_->audio_device()->StartPlayout();
if (ret != 0) {
RTC_LOG(LS_ERROR) << "SetPlayout(true) failed to start playout";
}
} else {
ret = shared_->audio_device()->StopPlayout();
if (ret != 0) {
RTC_LOG(LS_ERROR) << "SetPlayout(false) failed to stop playout";
}
}
return ret;
}
void VoEBaseImpl::TerminateInternal() {
// Delete any remaining channel objects
shared_->channel_manager().DestroyAllChannels();

View File

@ -33,28 +33,18 @@ class VoEBaseImpl : public VoEBase {
int CreateChannel(const ChannelConfig& config) override;
int DeleteChannel(int channel) override;
int StartPlayout(int channel) override;
int StopPlayout(int channel) override;
int SetPlayout(bool enabled) override;
protected:
VoEBaseImpl(voe::SharedData* shared);
~VoEBaseImpl() override;
private:
int32_t StartPlayout();
int32_t StopPlayout();
void TerminateInternal();
// Initialize channel by setting Engine Information then initializing
// channel.
int InitializeChannel(voe::ChannelOwner* channel_owner);
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory_;
AudioFrame audioFrame_;
voe::SharedData* shared_;
bool playout_enabled_ = true;
};
} // namespace webrtc