Prevent a voice channel from sending data before a source is set.
At the top level, setting a track on an RtpSender is equivalent to setting a source (previously called a renderer) on a voice send stream. An RtpSender without a track is not supposed to send data (not even muted data), so a send stream without a source shouldn't send data. Also replacing SendFlags with a boolean and implementing "Start" and "Stop" methods on AudioSendStream, which was planned anyway and simplifies this CL. R=pthatcher@webrtc.org, solenberg@webrtc.org Review URL: https://codereview.webrtc.org/1741933002 . Cr-Commit-Position: refs/heads/master@{#11918}
This commit is contained in:
parent
1ae6a45986
commit
1a018dcda3
@ -17,7 +17,7 @@
|
||||
|
||||
namespace cricket {
|
||||
|
||||
class AudioRenderer;
|
||||
class AudioSource;
|
||||
class VideoCapturer;
|
||||
class VideoFrame;
|
||||
class VideoRenderer;
|
||||
@ -49,7 +49,7 @@ class AudioProviderInterface {
|
||||
virtual void SetAudioSend(uint32_t ssrc,
|
||||
bool enable,
|
||||
const cricket::AudioOptions& options,
|
||||
cricket::AudioRenderer* renderer) = 0;
|
||||
cricket::AudioSource* source) = 0;
|
||||
|
||||
// Sets the audio playout volume of a remote audio track with |ssrc|.
|
||||
// |volume| is in the range of [0, 10].
|
||||
|
||||
@ -18,7 +18,6 @@
|
||||
#include "webrtc/api/notifier.h"
|
||||
#include "webrtc/audio_sink.h"
|
||||
#include "webrtc/base/criticalsection.h"
|
||||
#include "webrtc/media/base/audiorenderer.h"
|
||||
|
||||
namespace rtc {
|
||||
struct Message;
|
||||
|
||||
@ -36,7 +36,7 @@ void LocalAudioSinkAdapter::OnData(const void* audio_data,
|
||||
}
|
||||
}
|
||||
|
||||
void LocalAudioSinkAdapter::SetSink(cricket::AudioRenderer::Sink* sink) {
|
||||
void LocalAudioSinkAdapter::SetSink(cricket::AudioSource::Sink* sink) {
|
||||
rtc::CritScope lock(&lock_);
|
||||
ASSERT(!sink || !sink_);
|
||||
sink_ = sink;
|
||||
@ -194,9 +194,9 @@ void AudioRtpSender::SetAudioSend() {
|
||||
}
|
||||
#endif
|
||||
|
||||
cricket::AudioRenderer* renderer = sink_adapter_.get();
|
||||
ASSERT(renderer != nullptr);
|
||||
provider_->SetAudioSend(ssrc_, track_->enabled(), options, renderer);
|
||||
cricket::AudioSource* source = sink_adapter_.get();
|
||||
ASSERT(source != nullptr);
|
||||
provider_->SetAudioSend(ssrc_, track_->enabled(), options, source);
|
||||
}
|
||||
|
||||
VideoRtpSender::VideoRtpSender(VideoTrackInterface* track,
|
||||
|
||||
@ -23,14 +23,14 @@
|
||||
#include "webrtc/base/basictypes.h"
|
||||
#include "webrtc/base/criticalsection.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/media/base/audiorenderer.h"
|
||||
#include "webrtc/media/base/audiosource.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// LocalAudioSinkAdapter receives data callback as a sink to the local
|
||||
// AudioTrack, and passes the data to the sink of AudioRenderer.
|
||||
// AudioTrack, and passes the data to the sink of AudioSource.
|
||||
class LocalAudioSinkAdapter : public AudioTrackSinkInterface,
|
||||
public cricket::AudioRenderer {
|
||||
public cricket::AudioSource {
|
||||
public:
|
||||
LocalAudioSinkAdapter();
|
||||
virtual ~LocalAudioSinkAdapter();
|
||||
@ -43,10 +43,10 @@ class LocalAudioSinkAdapter : public AudioTrackSinkInterface,
|
||||
size_t number_of_channels,
|
||||
size_t number_of_frames) override;
|
||||
|
||||
// cricket::AudioRenderer implementation.
|
||||
void SetSink(cricket::AudioRenderer::Sink* sink) override;
|
||||
// cricket::AudioSource implementation.
|
||||
void SetSink(cricket::AudioSource::Sink* sink) override;
|
||||
|
||||
cricket::AudioRenderer::Sink* sink_;
|
||||
cricket::AudioSource::Sink* sink_;
|
||||
// Critical section protecting |sink_|.
|
||||
rtc::CriticalSection lock_;
|
||||
};
|
||||
@ -113,7 +113,7 @@ class AudioRtpSender : public ObserverInterface,
|
||||
bool stopped_ = false;
|
||||
|
||||
// Used to pass the data callback from the |track_| to the other end of
|
||||
// cricket::AudioRenderer.
|
||||
// cricket::AudioSource.
|
||||
rtc::scoped_ptr<LocalAudioSinkAdapter> sink_adapter_;
|
||||
};
|
||||
|
||||
|
||||
@ -50,7 +50,7 @@ class MockAudioProvider : public AudioProviderInterface {
|
||||
void(uint32_t ssrc,
|
||||
bool enable,
|
||||
const cricket::AudioOptions& options,
|
||||
cricket::AudioRenderer* renderer));
|
||||
cricket::AudioSource* source));
|
||||
MOCK_METHOD2(SetAudioPlayoutVolume, void(uint32_t ssrc, double volume));
|
||||
|
||||
void SetRawAudioSink(uint32_t,
|
||||
|
||||
@ -1180,13 +1180,13 @@ void WebRtcSession::SetAudioPlayout(uint32_t ssrc, bool enable) {
|
||||
void WebRtcSession::SetAudioSend(uint32_t ssrc,
|
||||
bool enable,
|
||||
const cricket::AudioOptions& options,
|
||||
cricket::AudioRenderer* renderer) {
|
||||
cricket::AudioSource* source) {
|
||||
ASSERT(signaling_thread()->IsCurrent());
|
||||
if (!voice_channel_) {
|
||||
LOG(LS_ERROR) << "SetAudioSend: No audio channel exists.";
|
||||
return;
|
||||
}
|
||||
if (!voice_channel_->SetAudioSend(ssrc, enable, &options, renderer)) {
|
||||
if (!voice_channel_->SetAudioSend(ssrc, enable, &options, source)) {
|
||||
LOG(LS_ERROR) << "SetAudioSend: ssrc is incorrect: " << ssrc;
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,7 +232,7 @@ class WebRtcSession : public AudioProviderInterface,
|
||||
void SetAudioSend(uint32_t ssrc,
|
||||
bool enable,
|
||||
const cricket::AudioOptions& options,
|
||||
cricket::AudioRenderer* renderer) override;
|
||||
cricket::AudioSource* source) override;
|
||||
void SetAudioPlayoutVolume(uint32_t ssrc, double volume) override;
|
||||
void SetRawAudioSink(uint32_t ssrc,
|
||||
rtc::scoped_ptr<AudioSinkInterface> sink) override;
|
||||
|
||||
@ -294,19 +294,20 @@ class WebRtcSessionCreateSDPObserverForTest
|
||||
State state_;
|
||||
};
|
||||
|
||||
class FakeAudioRenderer : public cricket::AudioRenderer {
|
||||
class FakeAudioSource : public cricket::AudioSource {
|
||||
public:
|
||||
FakeAudioRenderer() : sink_(NULL) {}
|
||||
virtual ~FakeAudioRenderer() {
|
||||
FakeAudioSource() : sink_(NULL) {}
|
||||
virtual ~FakeAudioSource() {
|
||||
if (sink_)
|
||||
sink_->OnClose();
|
||||
}
|
||||
|
||||
void SetSink(Sink* sink) override { sink_ = sink; }
|
||||
|
||||
cricket::AudioRenderer::Sink* sink() const { return sink_; }
|
||||
const cricket::AudioSource::Sink* sink() const { return sink_; }
|
||||
|
||||
private:
|
||||
cricket::AudioRenderer::Sink* sink_;
|
||||
cricket::AudioSource::Sink* sink_;
|
||||
};
|
||||
|
||||
class WebRtcSessionTest
|
||||
@ -3337,20 +3338,20 @@ TEST_F(WebRtcSessionTest, SetAudioSend) {
|
||||
cricket::AudioOptions options;
|
||||
options.echo_cancellation = rtc::Optional<bool>(true);
|
||||
|
||||
rtc::scoped_ptr<FakeAudioRenderer> renderer(new FakeAudioRenderer());
|
||||
session_->SetAudioSend(send_ssrc, false, options, renderer.get());
|
||||
rtc::scoped_ptr<FakeAudioSource> source(new FakeAudioSource());
|
||||
session_->SetAudioSend(send_ssrc, false, options, source.get());
|
||||
EXPECT_TRUE(channel->IsStreamMuted(send_ssrc));
|
||||
EXPECT_EQ(rtc::Optional<bool>(), channel->options().echo_cancellation);
|
||||
EXPECT_TRUE(renderer->sink() != NULL);
|
||||
EXPECT_TRUE(source->sink() != nullptr);
|
||||
|
||||
// This will trigger SetSink(NULL) to the |renderer|.
|
||||
session_->SetAudioSend(send_ssrc, true, options, NULL);
|
||||
// This will trigger SetSink(nullptr) to the |source|.
|
||||
session_->SetAudioSend(send_ssrc, true, options, nullptr);
|
||||
EXPECT_FALSE(channel->IsStreamMuted(send_ssrc));
|
||||
EXPECT_EQ(rtc::Optional<bool>(true), channel->options().echo_cancellation);
|
||||
EXPECT_TRUE(renderer->sink() == NULL);
|
||||
EXPECT_TRUE(source->sink() == nullptr);
|
||||
}
|
||||
|
||||
TEST_F(WebRtcSessionTest, AudioRendererForLocalStream) {
|
||||
TEST_F(WebRtcSessionTest, AudioSourceForLocalStream) {
|
||||
Init();
|
||||
SendAudioVideoStream1();
|
||||
CreateAndSetRemoteOfferAndLocalAnswer();
|
||||
@ -3359,18 +3360,18 @@ TEST_F(WebRtcSessionTest, AudioRendererForLocalStream) {
|
||||
ASSERT_EQ(1u, channel->send_streams().size());
|
||||
uint32_t send_ssrc = channel->send_streams()[0].first_ssrc();
|
||||
|
||||
rtc::scoped_ptr<FakeAudioRenderer> renderer(new FakeAudioRenderer());
|
||||
rtc::scoped_ptr<FakeAudioSource> source(new FakeAudioSource());
|
||||
cricket::AudioOptions options;
|
||||
session_->SetAudioSend(send_ssrc, true, options, renderer.get());
|
||||
EXPECT_TRUE(renderer->sink() != NULL);
|
||||
session_->SetAudioSend(send_ssrc, true, options, source.get());
|
||||
EXPECT_TRUE(source->sink() != nullptr);
|
||||
|
||||
// Delete the |renderer| and it will trigger OnClose() to the sink, and this
|
||||
// will invalidate the |renderer_| pointer in the sink and prevent getting a
|
||||
// SetSink(NULL) callback afterwards.
|
||||
renderer.reset();
|
||||
// Delete the |source| and it will trigger OnClose() to the sink, and this
|
||||
// will invalidate the |source_| pointer in the sink and prevent getting a
|
||||
// SetSink(nullptr) callback afterwards.
|
||||
source.reset();
|
||||
|
||||
// This will trigger SetSink(NULL) if no OnClose() callback.
|
||||
session_->SetAudioSend(send_ssrc, true, options, NULL);
|
||||
// This will trigger SetSink(nullptr) if no OnClose() callback.
|
||||
session_->SetAudioSend(send_ssrc, true, options, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(WebRtcSessionTest, SetVideoPlayout) {
|
||||
|
||||
@ -97,10 +97,20 @@ AudioSendStream::~AudioSendStream() {
|
||||
|
||||
void AudioSendStream::Start() {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
ScopedVoEInterface<VoEBase> base(voice_engine());
|
||||
int error = base->StartSend(config_.voe_channel_id);
|
||||
if (error != 0) {
|
||||
LOG(LS_ERROR) << "AudioSendStream::Start failed with error: " << error;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioSendStream::Stop() {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
ScopedVoEInterface<VoEBase> base(voice_engine());
|
||||
int error = base->StopSend(config_.voe_channel_id);
|
||||
if (error != 0) {
|
||||
LOG(LS_ERROR) << "AudioSendStream::Stop failed with error: " << error;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioSendStream::SignalNetworkState(NetworkState state) {
|
||||
|
||||
@ -11,37 +11,6 @@
|
||||
#ifndef WEBRTC_MEDIA_BASE_AUDIORENDERER_H_
|
||||
#define WEBRTC_MEDIA_BASE_AUDIORENDERER_H_
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace cricket {
|
||||
|
||||
// Abstract interface for rendering the audio data.
|
||||
class AudioRenderer {
|
||||
public:
|
||||
class Sink {
|
||||
public:
|
||||
// Callback to receive data from the AudioRenderer.
|
||||
virtual void OnData(const void* audio_data,
|
||||
int bits_per_sample,
|
||||
int sample_rate,
|
||||
size_t number_of_channels,
|
||||
size_t number_of_frames) = 0;
|
||||
|
||||
// Called when the AudioRenderer is going away.
|
||||
virtual void OnClose() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~Sink() {}
|
||||
};
|
||||
|
||||
// Sets a sink to the AudioRenderer. There can be only one sink connected
|
||||
// to the renderer at a time.
|
||||
virtual void SetSink(Sink* sink) {}
|
||||
|
||||
protected:
|
||||
virtual ~AudioRenderer() {}
|
||||
};
|
||||
|
||||
} // namespace cricket
|
||||
// TODO(deadbeef): Remove this once not included by Chromium.
|
||||
|
||||
#endif // WEBRTC_MEDIA_BASE_AUDIORENDERER_H_
|
||||
|
||||
49
webrtc/media/base/audiosource.h
Normal file
49
webrtc/media/base/audiosource.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MEDIA_BASE_AUDIOSOURCE_H_
|
||||
#define WEBRTC_MEDIA_BASE_AUDIOSOURCE_H_
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace cricket {
|
||||
|
||||
// Abstract interface for providing the audio data.
|
||||
// TODO(deadbeef): Rename this to AudioSourceInterface, and rename
|
||||
// webrtc::AudioSourceInterface to AudioTrackSourceInterface.
|
||||
class AudioSource {
|
||||
public:
|
||||
class Sink {
|
||||
public:
|
||||
// Callback to receive data from the AudioSource.
|
||||
virtual void OnData(const void* audio_data,
|
||||
int bits_per_sample,
|
||||
int sample_rate,
|
||||
size_t number_of_channels,
|
||||
size_t number_of_frames) = 0;
|
||||
|
||||
// Called when the AudioSource is going away.
|
||||
virtual void OnClose() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~Sink() {}
|
||||
};
|
||||
|
||||
// Sets a sink to the AudioSource. There can be only one sink connected
|
||||
// to the source at a time.
|
||||
virtual void SetSink(Sink* sink) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~AudioSource() {}
|
||||
};
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
#endif // WEBRTC_MEDIA_BASE_AUDIOSOURCE_H_
|
||||
@ -21,7 +21,7 @@
|
||||
#include "webrtc/audio_sink.h"
|
||||
#include "webrtc/base/buffer.h"
|
||||
#include "webrtc/base/stringutils.h"
|
||||
#include "webrtc/media/base/audiorenderer.h"
|
||||
#include "webrtc/media/base/audiosource.h"
|
||||
#include "webrtc/media/base/mediaengine.h"
|
||||
#include "webrtc/media/base/rtputils.h"
|
||||
#include "webrtc/media/base/streamparams.h"
|
||||
@ -253,14 +253,12 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> {
|
||||
set_playout(playout);
|
||||
return true;
|
||||
}
|
||||
virtual bool SetSend(SendFlags flag) {
|
||||
return set_sending(flag != SEND_NOTHING);
|
||||
}
|
||||
virtual void SetSend(bool send) { set_sending(send); }
|
||||
virtual bool SetAudioSend(uint32_t ssrc,
|
||||
bool enable,
|
||||
const AudioOptions* options,
|
||||
AudioRenderer* renderer) {
|
||||
if (!SetLocalRenderer(ssrc, renderer)) {
|
||||
AudioSource* source) {
|
||||
if (!SetLocalSource(ssrc, source)) {
|
||||
return false;
|
||||
}
|
||||
if (!RtpHelper<VoiceMediaChannel>::MuteStream(ssrc, !enable)) {
|
||||
@ -338,15 +336,14 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> {
|
||||
}
|
||||
|
||||
private:
|
||||
class VoiceChannelAudioSink : public AudioRenderer::Sink {
|
||||
class VoiceChannelAudioSink : public AudioSource::Sink {
|
||||
public:
|
||||
explicit VoiceChannelAudioSink(AudioRenderer* renderer)
|
||||
: renderer_(renderer) {
|
||||
renderer_->SetSink(this);
|
||||
explicit VoiceChannelAudioSink(AudioSource* source) : source_(source) {
|
||||
source_->SetSink(this);
|
||||
}
|
||||
virtual ~VoiceChannelAudioSink() {
|
||||
if (renderer_) {
|
||||
renderer_->SetSink(NULL);
|
||||
if (source_) {
|
||||
source_->SetSink(nullptr);
|
||||
}
|
||||
}
|
||||
void OnData(const void* audio_data,
|
||||
@ -354,11 +351,11 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> {
|
||||
int sample_rate,
|
||||
size_t number_of_channels,
|
||||
size_t number_of_frames) override {}
|
||||
void OnClose() override { renderer_ = NULL; }
|
||||
AudioRenderer* renderer() const { return renderer_; }
|
||||
void OnClose() override { source_ = nullptr; }
|
||||
AudioSource* source() const { return source_; }
|
||||
|
||||
private:
|
||||
AudioRenderer* renderer_;
|
||||
AudioSource* source_;
|
||||
};
|
||||
|
||||
bool SetRecvCodecs(const std::vector<AudioCodec>& codecs) {
|
||||
@ -383,19 +380,19 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> {
|
||||
options_.SetAll(options);
|
||||
return true;
|
||||
}
|
||||
bool SetLocalRenderer(uint32_t ssrc, AudioRenderer* renderer) {
|
||||
auto it = local_renderers_.find(ssrc);
|
||||
if (renderer) {
|
||||
if (it != local_renderers_.end()) {
|
||||
ASSERT(it->second->renderer() == renderer);
|
||||
bool SetLocalSource(uint32_t ssrc, AudioSource* source) {
|
||||
auto it = local_sinks_.find(ssrc);
|
||||
if (source) {
|
||||
if (it != local_sinks_.end()) {
|
||||
ASSERT(it->second->source() == source);
|
||||
} else {
|
||||
local_renderers_.insert(std::make_pair(
|
||||
ssrc, new VoiceChannelAudioSink(renderer)));
|
||||
local_sinks_.insert(
|
||||
std::make_pair(ssrc, new VoiceChannelAudioSink(source)));
|
||||
}
|
||||
} else {
|
||||
if (it != local_renderers_.end()) {
|
||||
if (it != local_sinks_.end()) {
|
||||
delete it->second;
|
||||
local_renderers_.erase(it);
|
||||
local_sinks_.erase(it);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -408,7 +405,7 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> {
|
||||
std::vector<DtmfInfo> dtmf_info_queue_;
|
||||
int time_since_last_typing_;
|
||||
AudioOptions options_;
|
||||
std::map<uint32_t, VoiceChannelAudioSink*> local_renderers_;
|
||||
std::map<uint32_t, VoiceChannelAudioSink*> local_sinks_;
|
||||
std::unique_ptr<webrtc::AudioSinkInterface> sink_;
|
||||
};
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ class AudioSinkInterface;
|
||||
|
||||
namespace cricket {
|
||||
|
||||
class AudioRenderer;
|
||||
class AudioSource;
|
||||
class ScreencastId;
|
||||
class VideoCapturer;
|
||||
class VideoFrame;
|
||||
@ -448,11 +448,6 @@ class MediaChannel : public sigslot::has_slots<> {
|
||||
NetworkInterface* network_interface_;
|
||||
};
|
||||
|
||||
enum SendFlags {
|
||||
SEND_NOTHING,
|
||||
SEND_MICROPHONE
|
||||
};
|
||||
|
||||
// The stats information is structured as follows:
|
||||
// Media are represented by either MediaSenderInfo or MediaReceiverInfo.
|
||||
// Media contains a vector of SSRC infos that are exclusively used by this
|
||||
@ -901,12 +896,12 @@ class VoiceMediaChannel : public MediaChannel {
|
||||
// Starts or stops playout of received audio.
|
||||
virtual bool SetPlayout(bool playout) = 0;
|
||||
// Starts or stops sending (and potentially capture) of local audio.
|
||||
virtual bool SetSend(SendFlags flag) = 0;
|
||||
virtual void SetSend(bool send) = 0;
|
||||
// Configure stream for sending.
|
||||
virtual bool SetAudioSend(uint32_t ssrc,
|
||||
bool enable,
|
||||
const AudioOptions* options,
|
||||
AudioRenderer* renderer) = 0;
|
||||
AudioSource* source) = 0;
|
||||
// Gets current energy levels for all incoming streams.
|
||||
virtual bool GetActiveStreams(AudioInfo::StreamList* actives) = 0;
|
||||
// Get the current energy level of the stream sent to the speaker.
|
||||
|
||||
@ -44,11 +44,12 @@ class FakeAudioSendStream final : public webrtc::AudioSendStream {
|
||||
const webrtc::AudioSendStream::Config& GetConfig() const;
|
||||
void SetStats(const webrtc::AudioSendStream::Stats& stats);
|
||||
TelephoneEvent GetLatestTelephoneEvent() const;
|
||||
bool IsSending() const { return sending_; }
|
||||
|
||||
private:
|
||||
// webrtc::SendStream implementation.
|
||||
void Start() override {}
|
||||
void Stop() override {}
|
||||
void Start() override { sending_ = true; }
|
||||
void Stop() override { sending_ = false; }
|
||||
void SignalNetworkState(webrtc::NetworkState state) override {}
|
||||
bool DeliverRtcp(const uint8_t* packet, size_t length) override {
|
||||
return true;
|
||||
@ -62,6 +63,7 @@ class FakeAudioSendStream final : public webrtc::AudioSendStream {
|
||||
TelephoneEvent latest_telephone_event_;
|
||||
webrtc::AudioSendStream::Config config_;
|
||||
webrtc::AudioSendStream::Stats stats_;
|
||||
bool sending_ = false;
|
||||
};
|
||||
|
||||
class FakeAudioReceiveStream final : public webrtc::AudioReceiveStream {
|
||||
|
||||
@ -130,7 +130,6 @@ class FakeWebRtcVoiceEngine
|
||||
struct Channel {
|
||||
explicit Channel()
|
||||
: external_transport(false),
|
||||
send(false),
|
||||
playout(false),
|
||||
volume_scale(1.0),
|
||||
vad(false),
|
||||
@ -151,7 +150,6 @@ class FakeWebRtcVoiceEngine
|
||||
memset(&send_codec, 0, sizeof(send_codec));
|
||||
}
|
||||
bool external_transport;
|
||||
bool send;
|
||||
bool playout;
|
||||
float volume_scale;
|
||||
bool vad;
|
||||
@ -193,7 +191,6 @@ class FakeWebRtcVoiceEngine
|
||||
agc_mode_(webrtc::kAgcDefault),
|
||||
observer_(NULL),
|
||||
playout_fail_channel_(-1),
|
||||
send_fail_channel_(-1),
|
||||
recording_sample_rate_(-1),
|
||||
playout_sample_rate_(-1) {
|
||||
memset(&agc_config_, 0, sizeof(agc_config_));
|
||||
@ -213,9 +210,6 @@ class FakeWebRtcVoiceEngine
|
||||
bool GetPlayout(int channel) {
|
||||
return channels_[channel]->playout;
|
||||
}
|
||||
bool GetSend(int channel) {
|
||||
return channels_[channel]->send;
|
||||
}
|
||||
bool GetVAD(int channel) {
|
||||
return channels_[channel]->vad;
|
||||
}
|
||||
@ -268,9 +262,6 @@ class FakeWebRtcVoiceEngine
|
||||
void set_playout_fail_channel(int channel) {
|
||||
playout_fail_channel_ = channel;
|
||||
}
|
||||
void set_send_fail_channel(int channel) {
|
||||
send_fail_channel_ = channel;
|
||||
}
|
||||
void set_fail_create_channel(bool fail_create_channel) {
|
||||
fail_create_channel_ = fail_create_channel;
|
||||
}
|
||||
@ -347,28 +338,14 @@ class FakeWebRtcVoiceEngine
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
WEBRTC_FUNC(StartSend, (int channel)) {
|
||||
if (send_fail_channel_ != channel) {
|
||||
WEBRTC_CHECK_CHANNEL(channel);
|
||||
channels_[channel]->send = true;
|
||||
return 0;
|
||||
} else {
|
||||
// When send_fail_channel_ == channel, fail the StartSend on this
|
||||
// channel.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
WEBRTC_STUB(StartSend, (int channel));
|
||||
WEBRTC_STUB(StopReceive, (int channel));
|
||||
WEBRTC_FUNC(StopPlayout, (int channel)) {
|
||||
WEBRTC_CHECK_CHANNEL(channel);
|
||||
channels_[channel]->playout = false;
|
||||
return 0;
|
||||
}
|
||||
WEBRTC_FUNC(StopSend, (int channel)) {
|
||||
WEBRTC_CHECK_CHANNEL(channel);
|
||||
channels_[channel]->send = false;
|
||||
return 0;
|
||||
}
|
||||
WEBRTC_STUB(StopSend, (int channel));
|
||||
WEBRTC_STUB(GetVersion, (char version[1024]));
|
||||
WEBRTC_STUB(LastError, ());
|
||||
WEBRTC_FUNC(AssociateSendChannel, (int channel,
|
||||
@ -797,7 +774,6 @@ class FakeWebRtcVoiceEngine
|
||||
webrtc::AgcConfig agc_config_;
|
||||
webrtc::VoiceEngineObserver* observer_;
|
||||
int playout_fail_channel_;
|
||||
int send_fail_channel_;
|
||||
int recording_sample_rate_;
|
||||
int playout_sample_rate_;
|
||||
FakeAudioProcessing audio_processing_;
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
#include "webrtc/call/rtc_event_log.h"
|
||||
#include "webrtc/common.h"
|
||||
#include "webrtc/media/base/audioframe.h"
|
||||
#include "webrtc/media/base/audiorenderer.h"
|
||||
#include "webrtc/media/base/audiosource.h"
|
||||
#include "webrtc/media/base/mediaconstants.h"
|
||||
#include "webrtc/media/base/streamparams.h"
|
||||
#include "webrtc/media/engine/webrtcmediaengine.h"
|
||||
@ -1138,7 +1138,7 @@ int WebRtcVoiceEngine::CreateVoEChannel() {
|
||||
}
|
||||
|
||||
class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
|
||||
: public AudioRenderer::Sink {
|
||||
: public AudioSource::Sink {
|
||||
public:
|
||||
WebRtcAudioSendStream(int ch, webrtc::AudioTransport* voe_audio_transport,
|
||||
uint32_t ssrc, const std::string& c_name,
|
||||
@ -1160,7 +1160,7 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
|
||||
|
||||
~WebRtcAudioSendStream() override {
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
Stop();
|
||||
ClearSource();
|
||||
call_->DestroyAudioSendStream(stream_);
|
||||
}
|
||||
|
||||
@ -1184,39 +1184,47 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
|
||||
return stream_->SendTelephoneEvent(payload_type, event, duration_ms);
|
||||
}
|
||||
|
||||
void SetSend(bool send) {
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
send_ = send;
|
||||
UpdateSendState();
|
||||
}
|
||||
|
||||
webrtc::AudioSendStream::Stats GetStats() const {
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
RTC_DCHECK(stream_);
|
||||
return stream_->GetStats();
|
||||
}
|
||||
|
||||
// Starts the rendering by setting a sink to the renderer to get data
|
||||
// callback.
|
||||
// Starts the sending by setting ourselves as a sink to the AudioSource to
|
||||
// get data callbacks.
|
||||
// This method is called on the libjingle worker thread.
|
||||
// TODO(xians): Make sure Start() is called only once.
|
||||
void Start(AudioRenderer* renderer) {
|
||||
void SetSource(AudioSource* source) {
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
RTC_DCHECK(renderer);
|
||||
if (renderer_) {
|
||||
RTC_DCHECK(renderer_ == renderer);
|
||||
RTC_DCHECK(source);
|
||||
if (source_) {
|
||||
RTC_DCHECK(source_ == source);
|
||||
return;
|
||||
}
|
||||
renderer->SetSink(this);
|
||||
renderer_ = renderer;
|
||||
source->SetSink(this);
|
||||
source_ = source;
|
||||
UpdateSendState();
|
||||
}
|
||||
|
||||
// Stops rendering by setting the sink of the renderer to nullptr. No data
|
||||
// Stops sending by setting the sink of the AudioSource to nullptr. No data
|
||||
// callback will be received after this method.
|
||||
// This method is called on the libjingle worker thread.
|
||||
void Stop() {
|
||||
void ClearSource() {
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
if (renderer_) {
|
||||
renderer_->SetSink(nullptr);
|
||||
renderer_ = nullptr;
|
||||
if (source_) {
|
||||
source_->SetSink(nullptr);
|
||||
source_ = nullptr;
|
||||
}
|
||||
UpdateSendState();
|
||||
}
|
||||
|
||||
// AudioRenderer::Sink implementation.
|
||||
// AudioSource::Sink implementation.
|
||||
// This method is called on the audio thread.
|
||||
void OnData(const void* audio_data,
|
||||
int bits_per_sample,
|
||||
@ -1234,13 +1242,14 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
|
||||
number_of_frames);
|
||||
}
|
||||
|
||||
// Callback from the |renderer_| when it is going away. In case Start() has
|
||||
// Callback from the |source_| when it is going away. In case Start() has
|
||||
// never been called, this callback won't be triggered.
|
||||
void OnClose() override {
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
// Set |renderer_| to nullptr to make sure no more callback will get into
|
||||
// the renderer.
|
||||
renderer_ = nullptr;
|
||||
// Set |source_| to nullptr to make sure no more callback will get into
|
||||
// the source.
|
||||
source_ = nullptr;
|
||||
UpdateSendState();
|
||||
}
|
||||
|
||||
// Accessor to the VoE channel ID.
|
||||
@ -1250,6 +1259,16 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
|
||||
}
|
||||
|
||||
private:
|
||||
void UpdateSendState() {
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
RTC_DCHECK(stream_);
|
||||
if (send_ && source_ != nullptr) {
|
||||
stream_->Start();
|
||||
} else { // !send || source_ = nullptr
|
||||
stream_->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
rtc::ThreadChecker worker_thread_checker_;
|
||||
rtc::ThreadChecker audio_capture_thread_checker_;
|
||||
webrtc::AudioTransport* const voe_audio_transport_ = nullptr;
|
||||
@ -1259,10 +1278,11 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
|
||||
// configuration changes.
|
||||
webrtc::AudioSendStream* stream_ = nullptr;
|
||||
|
||||
// Raw pointer to AudioRenderer owned by LocalAudioTrackHandler.
|
||||
// Raw pointer to AudioSource owned by LocalAudioTrackHandler.
|
||||
// PeerConnection will make sure invalidating the pointer before the object
|
||||
// goes away.
|
||||
AudioRenderer* renderer_ = nullptr;
|
||||
AudioSource* source_ = nullptr;
|
||||
bool send_ = false;
|
||||
|
||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioSendStream);
|
||||
};
|
||||
@ -1827,68 +1847,32 @@ bool WebRtcVoiceMediaChannel::ChangePlayout(bool playout) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebRtcVoiceMediaChannel::SetSend(SendFlags send) {
|
||||
desired_send_ = send;
|
||||
if (!send_streams_.empty()) {
|
||||
return ChangeSend(desired_send_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebRtcVoiceMediaChannel::PauseSend() {
|
||||
return ChangeSend(SEND_NOTHING);
|
||||
}
|
||||
|
||||
bool WebRtcVoiceMediaChannel::ResumeSend() {
|
||||
return ChangeSend(desired_send_);
|
||||
}
|
||||
|
||||
bool WebRtcVoiceMediaChannel::ChangeSend(SendFlags send) {
|
||||
void WebRtcVoiceMediaChannel::SetSend(bool send) {
|
||||
if (send_ == send) {
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply channel specific options when channel is enabled for sending.
|
||||
if (send == SEND_MICROPHONE) {
|
||||
if (send) {
|
||||
engine()->ApplyOptions(options_);
|
||||
}
|
||||
|
||||
// Change the settings on each send channel.
|
||||
for (const auto& ch : send_streams_) {
|
||||
if (!ChangeSend(ch.second->channel(), send)) {
|
||||
return false;
|
||||
}
|
||||
for (auto& kv : send_streams_) {
|
||||
kv.second->SetSend(send);
|
||||
}
|
||||
|
||||
send_ = send;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebRtcVoiceMediaChannel::ChangeSend(int channel, SendFlags send) {
|
||||
if (send == SEND_MICROPHONE) {
|
||||
if (engine()->voe()->base()->StartSend(channel) == -1) {
|
||||
LOG_RTCERR1(StartSend, channel);
|
||||
return false;
|
||||
}
|
||||
} else { // SEND_NOTHING
|
||||
RTC_DCHECK(send == SEND_NOTHING);
|
||||
if (engine()->voe()->base()->StopSend(channel) == -1) {
|
||||
LOG_RTCERR1(StopSend, channel);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebRtcVoiceMediaChannel::SetAudioSend(uint32_t ssrc,
|
||||
bool enable,
|
||||
const AudioOptions* options,
|
||||
AudioRenderer* renderer) {
|
||||
AudioSource* source) {
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
// TODO(solenberg): The state change should be fully rolled back if any one of
|
||||
// these calls fail.
|
||||
if (!SetLocalRenderer(ssrc, renderer)) {
|
||||
if (!SetLocalSource(ssrc, source)) {
|
||||
return false;
|
||||
}
|
||||
if (!MuteStream(ssrc, !enable)) {
|
||||
@ -1975,7 +1959,8 @@ bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
|
||||
}
|
||||
}
|
||||
|
||||
return ChangeSend(channel, desired_send_);
|
||||
send_streams_[ssrc]->SetSend(send_);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32_t ssrc) {
|
||||
@ -1989,10 +1974,10 @@ bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32_t ssrc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int channel = it->second->channel();
|
||||
ChangeSend(channel, SEND_NOTHING);
|
||||
it->second->SetSend(false);
|
||||
|
||||
// Clean up and delete the send stream+channel.
|
||||
int channel = it->second->channel();
|
||||
LOG(LS_INFO) << "Removing audio send stream " << ssrc
|
||||
<< " with VoiceEngine channel #" << channel << ".";
|
||||
delete it->second;
|
||||
@ -2001,7 +1986,7 @@ bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32_t ssrc) {
|
||||
return false;
|
||||
}
|
||||
if (send_streams_.empty()) {
|
||||
ChangeSend(SEND_NOTHING);
|
||||
SetSend(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -2110,13 +2095,13 @@ bool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32_t ssrc) {
|
||||
return DeleteVoEChannel(channel);
|
||||
}
|
||||
|
||||
bool WebRtcVoiceMediaChannel::SetLocalRenderer(uint32_t ssrc,
|
||||
AudioRenderer* renderer) {
|
||||
bool WebRtcVoiceMediaChannel::SetLocalSource(uint32_t ssrc,
|
||||
AudioSource* source) {
|
||||
auto it = send_streams_.find(ssrc);
|
||||
if (it == send_streams_.end()) {
|
||||
if (renderer) {
|
||||
// Return an error if trying to set a valid renderer with an invalid ssrc.
|
||||
LOG(LS_ERROR) << "SetLocalRenderer failed with ssrc "<< ssrc;
|
||||
if (source) {
|
||||
// Return an error if trying to set a valid source with an invalid ssrc.
|
||||
LOG(LS_ERROR) << "SetLocalSource failed with ssrc " << ssrc;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2124,10 +2109,10 @@ bool WebRtcVoiceMediaChannel::SetLocalRenderer(uint32_t ssrc,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (renderer) {
|
||||
it->second->Start(renderer);
|
||||
if (source) {
|
||||
it->second->SetSource(source);
|
||||
} else {
|
||||
it->second->Stop();
|
||||
it->second->ClearSource();
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -2445,8 +2430,7 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
|
||||
sinfo.echo_delay_std_ms = stats.echo_delay_std_ms;
|
||||
sinfo.echo_return_loss = stats.echo_return_loss;
|
||||
sinfo.echo_return_loss_enhancement = stats.echo_return_loss_enhancement;
|
||||
sinfo.typing_noise_detected =
|
||||
(send_ == SEND_NOTHING ? false : stats.typing_noise_detected);
|
||||
sinfo.typing_noise_detected = (send_ ? stats.typing_noise_detected : false);
|
||||
info->senders.push_back(sinfo);
|
||||
}
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
namespace cricket {
|
||||
|
||||
class AudioDeviceModule;
|
||||
class AudioRenderer;
|
||||
class AudioSource;
|
||||
class VoEWrapper;
|
||||
class WebRtcVoiceMediaChannel;
|
||||
|
||||
@ -155,13 +155,13 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel,
|
||||
bool SetPlayout(bool playout) override;
|
||||
bool PausePlayout();
|
||||
bool ResumePlayout();
|
||||
bool SetSend(SendFlags send) override;
|
||||
void SetSend(bool send) override;
|
||||
bool PauseSend();
|
||||
bool ResumeSend();
|
||||
bool SetAudioSend(uint32_t ssrc,
|
||||
bool enable,
|
||||
const AudioOptions* options,
|
||||
AudioRenderer* renderer) override;
|
||||
AudioSource* source) override;
|
||||
bool AddSendStream(const StreamParams& sp) override;
|
||||
bool RemoveSendStream(uint32_t ssrc) override;
|
||||
bool AddRecvStream(const StreamParams& sp) override;
|
||||
@ -218,7 +218,7 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel,
|
||||
void SetNack(int channel, bool nack_enabled);
|
||||
bool SetSendCodec(int channel, const webrtc::CodecInst& send_codec);
|
||||
bool SetMaxSendBandwidth(int bps);
|
||||
bool SetLocalRenderer(uint32_t ssrc, AudioRenderer* renderer);
|
||||
bool SetLocalSource(uint32_t ssrc, AudioSource* source);
|
||||
bool MuteStream(uint32_t ssrc, bool mute);
|
||||
|
||||
WebRtcVoiceEngine* engine() { return engine_; }
|
||||
@ -226,8 +226,6 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel,
|
||||
int GetOutputLevel(int channel);
|
||||
bool SetPlayout(int channel, bool playout);
|
||||
bool ChangePlayout(bool playout);
|
||||
bool ChangeSend(SendFlags send);
|
||||
bool ChangeSend(int channel, SendFlags send);
|
||||
int CreateVoEChannel();
|
||||
bool DeleteVoEChannel(int channel);
|
||||
bool IsDefaultRecvStream(uint32_t ssrc) {
|
||||
@ -249,8 +247,7 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel,
|
||||
bool desired_playout_ = false;
|
||||
bool recv_transport_cc_enabled_ = false;
|
||||
bool playout_ = false;
|
||||
SendFlags desired_send_ = SEND_NOTHING;
|
||||
SendFlags send_ = SEND_NOTHING;
|
||||
bool send_ = false;
|
||||
webrtc::Call* const call_ = nullptr;
|
||||
|
||||
// SSRC of unsignalled receive stream, or -1 if there isn't one.
|
||||
|
||||
@ -41,7 +41,8 @@ const cricket::AudioCodec kCn16000Codec(105, "CN", 16000, 0, 1, 0);
|
||||
const cricket::AudioCodec kTelephoneEventCodec(106, "telephone-event", 8000, 0,
|
||||
1, 0);
|
||||
const uint32_t kSsrc1 = 0x99;
|
||||
const uint32_t kSsrc2 = 0x98;
|
||||
const uint32_t kSsrc2 = 2;
|
||||
const uint32_t kSsrc3 = 3;
|
||||
const uint32_t kSsrcs4[] = { 1, 2, 3, 4 };
|
||||
|
||||
class FakeVoEWrapper : public cricket::VoEWrapper {
|
||||
@ -63,6 +64,10 @@ class FakeAudioSink : public webrtc::AudioSinkInterface {
|
||||
void OnData(const Data& audio) override {}
|
||||
};
|
||||
|
||||
class FakeAudioSource : public cricket::AudioSource {
|
||||
void SetSink(Sink* sink) override {}
|
||||
};
|
||||
|
||||
class WebRtcVoiceEngineTestFake : public testing::Test {
|
||||
public:
|
||||
WebRtcVoiceEngineTestFake() : WebRtcVoiceEngineTestFake("") {}
|
||||
@ -94,8 +99,10 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
|
||||
if (!SetupEngine()) {
|
||||
return false;
|
||||
}
|
||||
return channel_->AddSendStream(
|
||||
cricket::StreamParams::CreateLegacy(kSsrc1));
|
||||
if (!channel_->AddSendStream(cricket::StreamParams::CreateLegacy(kSsrc1))) {
|
||||
return false;
|
||||
}
|
||||
return channel_->SetAudioSend(kSsrc1, true, nullptr, &fake_source_);
|
||||
}
|
||||
void SetupForMultiSendStream() {
|
||||
EXPECT_TRUE(SetupEngineWithSendStream());
|
||||
@ -127,15 +134,11 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
|
||||
}
|
||||
|
||||
const webrtc::AudioSendStream::Config& GetSendStreamConfig(uint32_t ssrc) {
|
||||
const auto* send_stream = call_.GetAudioSendStream(ssrc);
|
||||
EXPECT_TRUE(send_stream);
|
||||
return send_stream->GetConfig();
|
||||
return GetSendStream(ssrc).GetConfig();
|
||||
}
|
||||
|
||||
const webrtc::AudioReceiveStream::Config& GetRecvStreamConfig(uint32_t ssrc) {
|
||||
const auto* recv_stream = call_.GetAudioReceiveStream(ssrc);
|
||||
EXPECT_TRUE(recv_stream);
|
||||
return recv_stream->GetConfig();
|
||||
return GetRecvStream(ssrc).GetConfig();
|
||||
}
|
||||
|
||||
void TestInsertDtmf(uint32_t ssrc, bool caller) {
|
||||
@ -152,7 +155,7 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
|
||||
|
||||
// Test we can only InsertDtmf when the other side supports telephone-event.
|
||||
EXPECT_TRUE(channel_->SetSendParameters(send_parameters_));
|
||||
EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE));
|
||||
channel_->SetSend(true);
|
||||
EXPECT_FALSE(channel_->CanInsertDtmf());
|
||||
EXPECT_FALSE(channel_->InsertDtmf(ssrc, 1, 111));
|
||||
send_parameters_.codecs.push_back(kTelephoneEventCodec);
|
||||
@ -401,6 +404,7 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
|
||||
cricket::VoiceMediaChannel* channel_;
|
||||
cricket::AudioSendParameters send_parameters_;
|
||||
cricket::AudioRecvParameters recv_parameters_;
|
||||
FakeAudioSource fake_source_;
|
||||
|
||||
private:
|
||||
webrtc::test::ScopedFieldTrials override_field_trials_;
|
||||
@ -2001,12 +2005,25 @@ TEST_F(WebRtcVoiceEngineTestFake, RecvAbsoluteSendTimeHeaderExtensions) {
|
||||
// Test that we can create a channel and start sending on it.
|
||||
TEST_F(WebRtcVoiceEngineTestFake, Send) {
|
||||
EXPECT_TRUE(SetupEngineWithSendStream());
|
||||
int channel_num = voe_.GetLastChannel();
|
||||
EXPECT_TRUE(channel_->SetSendParameters(send_parameters_));
|
||||
EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE));
|
||||
EXPECT_TRUE(voe_.GetSend(channel_num));
|
||||
EXPECT_TRUE(channel_->SetSend(cricket::SEND_NOTHING));
|
||||
EXPECT_FALSE(voe_.GetSend(channel_num));
|
||||
channel_->SetSend(true);
|
||||
EXPECT_TRUE(GetSendStream(kSsrc1).IsSending());
|
||||
channel_->SetSend(false);
|
||||
EXPECT_FALSE(GetSendStream(kSsrc1).IsSending());
|
||||
}
|
||||
|
||||
// Test that a channel will send if and only if it has a source and is enabled
|
||||
// for sending.
|
||||
TEST_F(WebRtcVoiceEngineTestFake, SendStateWithAndWithoutSource) {
|
||||
EXPECT_TRUE(SetupEngineWithSendStream());
|
||||
EXPECT_TRUE(channel_->SetSendParameters(send_parameters_));
|
||||
EXPECT_TRUE(channel_->SetAudioSend(kSsrc1, true, nullptr, nullptr));
|
||||
channel_->SetSend(true);
|
||||
EXPECT_FALSE(GetSendStream(kSsrc1).IsSending());
|
||||
EXPECT_TRUE(channel_->SetAudioSend(kSsrc1, true, nullptr, &fake_source_));
|
||||
EXPECT_TRUE(GetSendStream(kSsrc1).IsSending());
|
||||
EXPECT_TRUE(channel_->SetAudioSend(kSsrc1, true, nullptr, nullptr));
|
||||
EXPECT_FALSE(GetSendStream(kSsrc1).IsSending());
|
||||
}
|
||||
|
||||
// Test that we can create a channel and start playing out on it.
|
||||
@ -2025,13 +2042,14 @@ TEST_F(WebRtcVoiceEngineTestFake, CreateAndDeleteMultipleSendStreams) {
|
||||
SetupForMultiSendStream();
|
||||
|
||||
// Set the global state for sending.
|
||||
EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE));
|
||||
channel_->SetSend(true);
|
||||
|
||||
for (uint32_t ssrc : kSsrcs4) {
|
||||
EXPECT_TRUE(channel_->AddSendStream(
|
||||
cricket::StreamParams::CreateLegacy(ssrc)));
|
||||
EXPECT_TRUE(channel_->SetAudioSend(ssrc, true, nullptr, &fake_source_));
|
||||
// Verify that we are in a sending state for all the created streams.
|
||||
EXPECT_TRUE(voe_.GetSend(GetSendStreamConfig(ssrc).voe_channel_id));
|
||||
EXPECT_TRUE(GetSendStream(ssrc).IsSending());
|
||||
}
|
||||
EXPECT_EQ(arraysize(kSsrcs4), call_.GetAudioSendStreams().size());
|
||||
|
||||
@ -2086,28 +2104,26 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsWithMultipleSendStreams) {
|
||||
TEST_F(WebRtcVoiceEngineTestFake, SetSendWithMultipleSendStreams) {
|
||||
SetupForMultiSendStream();
|
||||
|
||||
// Create the send channels and they should be a SEND_NOTHING date.
|
||||
// Create the send channels and they should be a "not sending" date.
|
||||
for (uint32_t ssrc : kSsrcs4) {
|
||||
EXPECT_TRUE(channel_->AddSendStream(
|
||||
cricket::StreamParams::CreateLegacy(ssrc)));
|
||||
int channel_num = voe_.GetLastChannel();
|
||||
EXPECT_FALSE(voe_.GetSend(channel_num));
|
||||
EXPECT_TRUE(channel_->SetAudioSend(ssrc, true, nullptr, &fake_source_));
|
||||
EXPECT_FALSE(GetSendStream(ssrc).IsSending());
|
||||
}
|
||||
|
||||
// Set the global state for starting sending.
|
||||
EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE));
|
||||
channel_->SetSend(true);
|
||||
for (uint32_t ssrc : kSsrcs4) {
|
||||
// Verify that we are in a sending state for all the send streams.
|
||||
int channel_num = GetSendStreamConfig(ssrc).voe_channel_id;
|
||||
EXPECT_TRUE(voe_.GetSend(channel_num));
|
||||
EXPECT_TRUE(GetSendStream(ssrc).IsSending());
|
||||
}
|
||||
|
||||
// Set the global state for stopping sending.
|
||||
EXPECT_TRUE(channel_->SetSend(cricket::SEND_NOTHING));
|
||||
channel_->SetSend(false);
|
||||
for (uint32_t ssrc : kSsrcs4) {
|
||||
// Verify that we are in a stop state for all the send streams.
|
||||
int channel_num = GetSendStreamConfig(ssrc).voe_channel_id;
|
||||
EXPECT_FALSE(voe_.GetSend(channel_num));
|
||||
EXPECT_FALSE(GetSendStream(ssrc).IsSending());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2180,29 +2196,27 @@ TEST_F(WebRtcVoiceEngineTestFake, PlayoutWithMultipleStreams) {
|
||||
EXPECT_FALSE(voe_.GetPlayout(channel_num1));
|
||||
|
||||
// Adding another stream should enable playout on the new stream only.
|
||||
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
|
||||
EXPECT_TRUE(
|
||||
channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(kSsrc2)));
|
||||
int channel_num2 = voe_.GetLastChannel();
|
||||
EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE));
|
||||
EXPECT_TRUE(voe_.GetSend(channel_num1));
|
||||
EXPECT_FALSE(voe_.GetSend(channel_num2));
|
||||
channel_->SetSend(true);
|
||||
EXPECT_TRUE(GetSendStream(kSsrc1).IsSending());
|
||||
|
||||
// Make sure only the new stream is played out.
|
||||
EXPECT_FALSE(voe_.GetPlayout(channel_num1));
|
||||
EXPECT_TRUE(voe_.GetPlayout(channel_num2));
|
||||
|
||||
// Adding yet another stream should have stream 2 and 3 enabled for playout.
|
||||
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(3)));
|
||||
EXPECT_TRUE(
|
||||
channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(kSsrc3)));
|
||||
int channel_num3 = voe_.GetLastChannel();
|
||||
EXPECT_FALSE(voe_.GetPlayout(channel_num1));
|
||||
EXPECT_TRUE(voe_.GetPlayout(channel_num2));
|
||||
EXPECT_TRUE(voe_.GetPlayout(channel_num3));
|
||||
EXPECT_FALSE(voe_.GetSend(channel_num3));
|
||||
|
||||
// Stop sending.
|
||||
EXPECT_TRUE(channel_->SetSend(cricket::SEND_NOTHING));
|
||||
EXPECT_FALSE(voe_.GetSend(channel_num1));
|
||||
EXPECT_FALSE(voe_.GetSend(channel_num2));
|
||||
EXPECT_FALSE(voe_.GetSend(channel_num3));
|
||||
channel_->SetSend(false);
|
||||
EXPECT_FALSE(GetSendStream(kSsrc1).IsSending());
|
||||
|
||||
// Stop playout.
|
||||
EXPECT_TRUE(channel_->SetPlayout(false));
|
||||
@ -2228,18 +2242,17 @@ TEST_F(WebRtcVoiceEngineTestFake, CodianSend) {
|
||||
EXPECT_TRUE(SetupEngineWithSendStream());
|
||||
cricket::AudioOptions options_adjust_agc;
|
||||
options_adjust_agc.adjust_agc_delta = rtc::Optional<int>(-10);
|
||||
int channel_num = voe_.GetLastChannel();
|
||||
webrtc::AgcConfig agc_config;
|
||||
EXPECT_EQ(0, voe_.GetAgcConfig(agc_config));
|
||||
EXPECT_EQ(0, agc_config.targetLeveldBOv);
|
||||
send_parameters_.options = options_adjust_agc;
|
||||
EXPECT_TRUE(channel_->SetSendParameters(send_parameters_));
|
||||
EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE));
|
||||
EXPECT_TRUE(voe_.GetSend(channel_num));
|
||||
channel_->SetSend(true);
|
||||
EXPECT_TRUE(GetSendStream(kSsrc1).IsSending());
|
||||
EXPECT_EQ(0, voe_.GetAgcConfig(agc_config));
|
||||
EXPECT_EQ(agc_config.targetLeveldBOv, 10); // level was attenuated
|
||||
EXPECT_TRUE(channel_->SetSend(cricket::SEND_NOTHING));
|
||||
EXPECT_FALSE(voe_.GetSend(channel_num));
|
||||
channel_->SetSend(false);
|
||||
EXPECT_FALSE(GetSendStream(kSsrc1).IsSending());
|
||||
EXPECT_EQ(0, voe_.GetAgcConfig(agc_config));
|
||||
}
|
||||
|
||||
@ -2315,7 +2328,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
|
||||
// Start sending - this affects some reported stats.
|
||||
{
|
||||
cricket::VoiceMediaInfo info;
|
||||
EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE));
|
||||
channel_->SetSend(true);
|
||||
EXPECT_EQ(true, channel_->GetStats(&info));
|
||||
VerifyVoiceSenderInfo(info.senders[0], true);
|
||||
}
|
||||
@ -2574,7 +2587,7 @@ TEST_F(WebRtcVoiceEngineTestFake, InsertDtmfOnSendStreamAsCallee) {
|
||||
TEST_F(WebRtcVoiceEngineTestFake, TestSetPlayoutError) {
|
||||
EXPECT_TRUE(SetupEngineWithSendStream());
|
||||
EXPECT_TRUE(channel_->SetSendParameters(send_parameters_));
|
||||
EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE));
|
||||
channel_->SetSend(true);
|
||||
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
|
||||
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(3)));
|
||||
EXPECT_TRUE(channel_->SetPlayout(true));
|
||||
@ -2844,7 +2857,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetOptionOverridesViaChannels) {
|
||||
EXPECT_TRUE(agc_enabled);
|
||||
EXPECT_TRUE(ns_enabled);
|
||||
|
||||
channel1->SetSend(cricket::SEND_MICROPHONE);
|
||||
channel1->SetSend(true);
|
||||
voe_.GetEcStatus(ec_enabled, ec_mode);
|
||||
voe_.GetAgcStatus(agc_enabled, agc_mode);
|
||||
voe_.GetNsStatus(ns_enabled, ns_mode);
|
||||
@ -2852,7 +2865,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetOptionOverridesViaChannels) {
|
||||
EXPECT_TRUE(agc_enabled);
|
||||
EXPECT_FALSE(ns_enabled);
|
||||
|
||||
channel2->SetSend(cricket::SEND_MICROPHONE);
|
||||
channel2->SetSend(true);
|
||||
voe_.GetEcStatus(ec_enabled, ec_mode);
|
||||
voe_.GetAgcStatus(agc_enabled, agc_mode);
|
||||
voe_.GetNsStatus(ns_enabled, ns_mode);
|
||||
@ -2868,7 +2881,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetOptionOverridesViaChannels) {
|
||||
rtc::Optional<bool>(false);
|
||||
parameters_options_no_agc_nor_ns.options.noise_suppression =
|
||||
rtc::Optional<bool>(false);
|
||||
channel2->SetSend(cricket::SEND_MICROPHONE);
|
||||
channel2->SetSend(true);
|
||||
channel2->SetSendParameters(parameters_options_no_agc_nor_ns);
|
||||
expected_options.echo_cancellation = rtc::Optional<bool>(true);
|
||||
expected_options.auto_gain_control = rtc::Optional<bool>(false);
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
},
|
||||
'sources': [
|
||||
'base/audioframe.h',
|
||||
'base/audiorenderer.h',
|
||||
'base/audiosource.h',
|
||||
'base/capturemanager.cc',
|
||||
'base/capturemanager.h',
|
||||
'base/codec.cc',
|
||||
|
||||
@ -1334,9 +1334,9 @@ bool VoiceChannel::Init() {
|
||||
bool VoiceChannel::SetAudioSend(uint32_t ssrc,
|
||||
bool enable,
|
||||
const AudioOptions* options,
|
||||
AudioRenderer* renderer) {
|
||||
AudioSource* source) {
|
||||
return InvokeOnWorker(Bind(&VoiceMediaChannel::SetAudioSend, media_channel(),
|
||||
ssrc, enable, options, renderer));
|
||||
ssrc, enable, options, source));
|
||||
}
|
||||
|
||||
// TODO(juberti): Handle early media the right way. We should get an explicit
|
||||
@ -1454,10 +1454,7 @@ void VoiceChannel::ChangeState() {
|
||||
// Send outgoing data if we're the active call, we have the remote content,
|
||||
// and we have had some form of connectivity.
|
||||
bool send = IsReadyToSend();
|
||||
SendFlags send_flag = send ? SEND_MICROPHONE : SEND_NOTHING;
|
||||
if (!media_channel()->SetSend(send_flag)) {
|
||||
LOG(LS_ERROR) << "Failed to SetSend " << send_flag << " on voice channel";
|
||||
}
|
||||
media_channel()->SetSend(send);
|
||||
|
||||
LOG(LS_INFO) << "Changing voice state, recv=" << recv << " send=" << send;
|
||||
}
|
||||
|
||||
@ -336,7 +336,7 @@ class VoiceChannel : public BaseChannel {
|
||||
bool SetAudioSend(uint32_t ssrc,
|
||||
bool enable,
|
||||
const AudioOptions* options,
|
||||
AudioRenderer* renderer);
|
||||
AudioSource* source);
|
||||
|
||||
// downcasts a MediaChannel
|
||||
virtual VoiceMediaChannel* media_channel() const {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user