Implement AudioSendStream::GetStats().
BUG=webrtc:4690
Review URL: https://codereview.webrtc.org/1414743004
Cr-Commit-Position: refs/heads/master@{#10424}
diff --git a/talk/media/webrtc/fakewebrtccall.cc b/talk/media/webrtc/fakewebrtccall.cc
index 04deeb4..d86bfb5 100644
--- a/talk/media/webrtc/fakewebrtccall.cc
+++ b/talk/media/webrtc/fakewebrtccall.cc
@@ -39,8 +39,9 @@
RTC_DCHECK(config.voe_channel_id != -1);
}
-webrtc::AudioSendStream::Stats FakeAudioSendStream::GetStats() const {
- return webrtc::AudioSendStream::Stats();
+void FakeAudioSendStream::SetStats(
+ const webrtc::AudioSendStream::Stats& stats) {
+ stats_ = stats;
}
const webrtc::AudioSendStream::Config&
@@ -48,6 +49,10 @@
return config_;
}
+webrtc::AudioSendStream::Stats FakeAudioSendStream::GetStats() const {
+ return stats_;
+}
+
FakeAudioReceiveStream::FakeAudioReceiveStream(
const webrtc::AudioReceiveStream::Config& config)
: config_(config), received_packets_(0) {
@@ -68,6 +73,10 @@
received_packets_++;
}
+webrtc::AudioReceiveStream::Stats FakeAudioReceiveStream::GetStats() const {
+ return stats_;
+}
+
FakeVideoSendStream::FakeVideoSendStream(
const webrtc::VideoSendStream::Config& config,
const webrtc::VideoEncoderConfig& encoder_config)
diff --git a/talk/media/webrtc/fakewebrtccall.h b/talk/media/webrtc/fakewebrtccall.h
index 212c062..88edc60 100644
--- a/talk/media/webrtc/fakewebrtccall.h
+++ b/talk/media/webrtc/fakewebrtccall.h
@@ -53,10 +53,8 @@
explicit FakeAudioSendStream(
const webrtc::AudioSendStream::Config& config);
- // webrtc::AudioSendStream implementation.
- webrtc::AudioSendStream::Stats GetStats() const override;
-
const webrtc::AudioSendStream::Config& GetConfig() const;
+ void SetStats(const webrtc::AudioSendStream::Stats& stats);
private:
// webrtc::SendStream implementation.
@@ -67,7 +65,11 @@
return true;
}
+ // webrtc::AudioSendStream implementation.
+ webrtc::AudioSendStream::Stats GetStats() const override;
+
webrtc::AudioSendStream::Config config_;
+ webrtc::AudioSendStream::Stats stats_;
};
class FakeAudioReceiveStream : public webrtc::AudioReceiveStream {
@@ -95,9 +97,7 @@
}
// webrtc::AudioReceiveStream implementation.
- webrtc::AudioReceiveStream::Stats GetStats() const override {
- return stats_;
- }
+ webrtc::AudioReceiveStream::Stats GetStats() const override;
webrtc::AudioReceiveStream::Config config_;
webrtc::AudioReceiveStream::Stats stats_;
diff --git a/talk/media/webrtc/fakewebrtcvoiceengine.h b/talk/media/webrtc/fakewebrtcvoiceengine.h
index 9b91327..2405e07 100644
--- a/talk/media/webrtc/fakewebrtcvoiceengine.h
+++ b/talk/media/webrtc/fakewebrtcvoiceengine.h
@@ -45,11 +45,6 @@
namespace cricket {
-// Function returning stats will return these values
-// for all values based on type.
-const int kIntStatValue = 123;
-const float kFractionLostStatValue = 0.5;
-
static const char kFakeDefaultDeviceName[] = "Fake Default";
static const int kFakeDefaultDeviceId = -1;
static const char kFakeDeviceName[] = "Fake Device";
@@ -268,6 +263,8 @@
}
}
+ bool ec_metrics_enabled() const { return ec_metrics_enabled_; }
+
bool IsInited() const { return inited_; }
int GetLastChannel() const { return last_channel_; }
int GetChannelFromLocalSsrc(uint32_t local_ssrc) const {
@@ -279,6 +276,9 @@
return -1;
}
int GetNumChannels() const { return static_cast<int>(channels_.size()); }
+ uint32_t GetLocalSSRC(int channel) {
+ return channels_[channel]->send_ssrc;
+ }
bool GetPlayout(int channel) {
return channels_[channel]->playout;
}
@@ -727,11 +727,7 @@
channels_[channel]->send_ssrc = ssrc;
return 0;
}
- WEBRTC_FUNC(GetLocalSSRC, (int channel, unsigned int& ssrc)) {
- WEBRTC_CHECK_CHANNEL(channel);
- ssrc = channels_[channel]->send_ssrc;
- return 0;
- }
+ WEBRTC_STUB(GetLocalSSRC, (int channel, unsigned int& ssrc));
WEBRTC_STUB(GetRemoteSSRC, (int channel, unsigned int& ssrc));
WEBRTC_FUNC(SetSendAudioLevelIndicationStatus, (int channel, bool enable,
unsigned char id)) {
@@ -773,39 +769,12 @@
unsigned int& playoutTimestamp,
unsigned int* jitter,
unsigned short* fractionLost));
- WEBRTC_FUNC(GetRemoteRTCPReportBlocks,
- (int channel, std::vector<webrtc::ReportBlock>* receive_blocks)) {
- WEBRTC_CHECK_CHANNEL(channel);
- webrtc::ReportBlock block;
- block.source_SSRC = channels_[channel]->send_ssrc;
- webrtc::CodecInst send_codec = channels_[channel]->send_codec;
- if (send_codec.pltype >= 0) {
- block.fraction_lost = (unsigned char)(kFractionLostStatValue * 256);
- if (send_codec.plfreq / 1000 > 0) {
- block.interarrival_jitter = kIntStatValue * (send_codec.plfreq / 1000);
- }
- block.cumulative_num_packets_lost = kIntStatValue;
- block.extended_highest_sequence_number = kIntStatValue;
- receive_blocks->push_back(block);
- }
- return 0;
- }
+ WEBRTC_STUB(GetRemoteRTCPReportBlocks,
+ (int channel, std::vector<webrtc::ReportBlock>* receive_blocks));
WEBRTC_STUB(GetRTPStatistics, (int channel, unsigned int& averageJitterMs,
unsigned int& maxJitterMs,
unsigned int& discardedPackets));
- WEBRTC_FUNC(GetRTCPStatistics, (int channel, webrtc::CallStatistics& stats)) {
- WEBRTC_CHECK_CHANNEL(channel);
- stats.fractionLost = static_cast<int16_t>(kIntStatValue);
- stats.cumulativeLost = kIntStatValue;
- stats.extendedMax = kIntStatValue;
- stats.jitterSamples = kIntStatValue;
- stats.rttMs = kIntStatValue;
- stats.bytesSent = kIntStatValue;
- stats.packetsSent = kIntStatValue;
- stats.bytesReceived = kIntStatValue;
- stats.packetsReceived = kIntStatValue;
- return 0;
- }
+ WEBRTC_STUB(GetRTCPStatistics, (int channel, webrtc::CallStatistics& stats));
WEBRTC_FUNC(SetREDStatus, (int channel, bool enable, int redPayloadtype)) {
return SetFECStatus(channel, enable, redPayloadtype);
}
@@ -931,10 +900,7 @@
ec_metrics_enabled_ = enable;
return 0;
}
- WEBRTC_FUNC(GetEcMetricsStatus, (bool& enabled)) {
- enabled = ec_metrics_enabled_;
- return 0;
- }
+ WEBRTC_STUB(GetEcMetricsStatus, (bool& enabled));
WEBRTC_STUB(GetEchoMetrics, (int& ERL, int& ERLE, int& RERL, int& A_NLP));
WEBRTC_STUB(GetEcDelayMetrics, (int& delay_median, int& delay_std,
float& fraction_poor_delays));
diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc
index fd93535..1d12fbf 100644
--- a/talk/media/webrtc/webrtcvoiceengine.cc
+++ b/talk/media/webrtc/webrtcvoiceengine.cc
@@ -1321,7 +1321,11 @@
: channel_(ch),
voe_audio_transport_(voe_audio_transport),
call_(call) {
+ RTC_DCHECK_GE(ch, 0);
+ // TODO(solenberg): Once we're not using FakeWebRtcVoiceEngine anymore:
+ // RTC_DCHECK(voe_audio_transport);
RTC_DCHECK(call);
+ audio_capture_thread_checker_.DetachFromThread();
webrtc::AudioSendStream::Config config(nullptr);
config.voe_channel_id = channel_;
config.rtp.ssrc = ssrc;
@@ -1329,6 +1333,7 @@
RTC_DCHECK(stream_);
}
~WebRtcAudioSendStream() override {
+ RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
Stop();
call_->DestroyAudioSendStream(stream_);
}
@@ -1338,7 +1343,7 @@
// This method is called on the libjingle worker thread.
// TODO(xians): Make sure Start() is called only once.
void Start(AudioRenderer* renderer) {
- rtc::CritScope lock(&lock_);
+ RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
RTC_DCHECK(renderer);
if (renderer_) {
RTC_DCHECK(renderer_ == renderer);
@@ -1348,11 +1353,16 @@
renderer_ = renderer;
}
+ webrtc::AudioSendStream::Stats GetStats() const {
+ RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
+ return stream_->GetStats();
+ }
+
// Stops rendering by setting the sink of the renderer to nullptr. No data
// callback will be received after this method.
// This method is called on the libjingle worker thread.
void Stop() {
- rtc::CritScope lock(&lock_);
+ RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
if (renderer_) {
renderer_->SetSink(nullptr);
renderer_ = nullptr;
@@ -1366,6 +1376,7 @@
int sample_rate,
int number_of_channels,
size_t number_of_frames) override {
+ RTC_DCHECK(audio_capture_thread_checker_.CalledOnValidThread());
RTC_DCHECK(voe_audio_transport_);
voe_audio_transport_->OnData(channel_,
audio_data,
@@ -1378,16 +1389,21 @@
// Callback from the |renderer_| when it is going away. In case Start() has
// never been called, this callback won't be triggered.
void OnClose() override {
- rtc::CritScope lock(&lock_);
+ RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
// Set |renderer_| to nullptr to make sure no more callback will get into
// the renderer.
renderer_ = nullptr;
}
// Accessor to the VoE channel ID.
- int channel() const { return channel_; }
+ int channel() const {
+ RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
+ return channel_;
+ }
private:
+ rtc::ThreadChecker signal_thread_checker_;
+ rtc::ThreadChecker audio_capture_thread_checker_;
const int channel_ = -1;
webrtc::AudioTransport* const voe_audio_transport_ = nullptr;
webrtc::Call* call_ = nullptr;
@@ -1398,9 +1414,6 @@
// goes away.
AudioRenderer* renderer_ = nullptr;
- // Protects |renderer_| in Start(), Stop() and OnClose().
- rtc::CriticalSection lock_;
-
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioSendStream);
};
@@ -1433,7 +1446,6 @@
desired_send_(SEND_NOTHING),
send_(SEND_NOTHING),
call_(call) {
- RTC_DCHECK(thread_checker_.CalledOnValidThread());
LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel";
RTC_DCHECK(nullptr != call);
engine->RegisterChannel(this);
@@ -2618,109 +2630,36 @@
bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ RTC_DCHECK(info);
- bool echo_metrics_on = false;
- // These can take on valid negative values, so use the lowest possible level
- // as default rather than -1.
- int echo_return_loss = -100;
- int echo_return_loss_enhancement = -100;
- // These can also be negative, but in practice -1 is only used to signal
- // insufficient data, since the resolution is limited to multiples of 4 ms.
- int echo_delay_median_ms = -1;
- int echo_delay_std_ms = -1;
- if (engine()->voe()->processing()->GetEcMetricsStatus(
- echo_metrics_on) != -1 && echo_metrics_on) {
- // TODO(ajm): we may want to use VoECallReport::GetEchoMetricsSummary
- // here, but it appears to be unsuitable currently. Revisit after this is
- // investigated: http://b/issue?id=5666755
- int erl, erle, rerl, anlp;
- if (engine()->voe()->processing()->GetEchoMetrics(
- erl, erle, rerl, anlp) != -1) {
- echo_return_loss = erl;
- echo_return_loss_enhancement = erle;
- }
-
- int median, std;
- float dummy;
- if (engine()->voe()->processing()->GetEcDelayMetrics(
- median, std, dummy) != -1) {
- echo_delay_median_ms = median;
- echo_delay_std_ms = std;
- }
- }
-
- for (const auto& ch : send_streams_) {
- const int channel = ch.second->channel();
-
- // Fill in the sender info, based on what we know, and what the
- // remote side told us it got from its RTCP report.
+ // Get SSRC and stats for each sender.
+ RTC_DCHECK(info->senders.size() == 0);
+ for (const auto& stream : send_streams_) {
+ webrtc::AudioSendStream::Stats stats = stream.second->GetStats();
VoiceSenderInfo sinfo;
-
- webrtc::CallStatistics cs = {0};
- unsigned int ssrc = 0;
- if (engine()->voe()->rtp()->GetRTCPStatistics(channel, cs) == -1 ||
- engine()->voe()->rtp()->GetLocalSSRC(channel, ssrc) == -1) {
- continue;
- }
-
- sinfo.add_ssrc(ssrc);
- sinfo.codec_name = send_codec_.get() ? send_codec_->plname : "";
- sinfo.bytes_sent = cs.bytesSent;
- sinfo.packets_sent = cs.packetsSent;
- // RTT isn't known until a RTCP report is received. Until then, VoiceEngine
- // returns 0 to indicate an error value.
- sinfo.rtt_ms = (cs.rttMs > 0) ? cs.rttMs : -1;
-
- // Get data from the last remote RTCP report. Use default values if no data
- // available.
- sinfo.fraction_lost = -1.0;
- sinfo.jitter_ms = -1;
- sinfo.packets_lost = -1;
- sinfo.ext_seqnum = -1;
- std::vector<webrtc::ReportBlock> receive_blocks;
- webrtc::CodecInst codec = {0};
- if (engine()->voe()->rtp()->GetRemoteRTCPReportBlocks(
- channel, &receive_blocks) != -1 &&
- engine()->voe()->codec()->GetSendCodec(channel, codec) != -1) {
- for (const webrtc::ReportBlock& block : receive_blocks) {
- // Lookup report for send ssrc only.
- if (block.source_SSRC == sinfo.ssrc()) {
- // Convert Q8 to floating point.
- sinfo.fraction_lost = static_cast<float>(block.fraction_lost) / 256;
- // Convert samples to milliseconds.
- if (codec.plfreq / 1000 > 0) {
- sinfo.jitter_ms = block.interarrival_jitter / (codec.plfreq / 1000);
- }
- sinfo.packets_lost = block.cumulative_num_packets_lost;
- sinfo.ext_seqnum = block.extended_highest_sequence_number;
- break;
- }
- }
- }
-
- // Local speech level.
- unsigned int level = 0;
- sinfo.audio_level = (engine()->voe()->volume()->
- GetSpeechInputLevelFullRange(level) != -1) ? level : -1;
-
- // TODO(xians): We are injecting the same APM logging to all the send
- // channels here because there is no good way to know which send channel
- // is using the APM. The correct fix is to allow the send channels to have
- // their own APM so that we can feed the correct APM logging to different
- // send channels. See issue crbug/264611 .
- sinfo.echo_return_loss = echo_return_loss;
- sinfo.echo_return_loss_enhancement = echo_return_loss_enhancement;
- sinfo.echo_delay_median_ms = echo_delay_median_ms;
- sinfo.echo_delay_std_ms = echo_delay_std_ms;
- // TODO(ajm): Re-enable this metric once we have a reliable implementation.
- sinfo.aec_quality_min = -1;
+ sinfo.add_ssrc(stats.local_ssrc);
+ sinfo.bytes_sent = stats.bytes_sent;
+ sinfo.packets_sent = stats.packets_sent;
+ sinfo.packets_lost = stats.packets_lost;
+ sinfo.fraction_lost = stats.fraction_lost;
+ sinfo.codec_name = stats.codec_name;
+ sinfo.ext_seqnum = stats.ext_seqnum;
+ sinfo.jitter_ms = stats.jitter_ms;
+ sinfo.rtt_ms = stats.rtt_ms;
+ sinfo.audio_level = stats.audio_level;
+ sinfo.aec_quality_min = stats.aec_quality_min;
+ sinfo.echo_delay_median_ms = stats.echo_delay_median_ms;
+ 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 = typing_noise_detected_;
-
+ // TODO(solenberg): Move to AudioSendStream.
+ // sinfo.typing_noise_detected = stats.typing_noise_detected;
info->senders.push_back(sinfo);
}
- // Get the SSRC and stats for each receiver.
- info->receivers.clear();
+ // Get SSRC and stats for each receiver.
+ RTC_DCHECK(info->receivers.size() == 0);
for (const auto& stream : receive_streams_) {
webrtc::AudioReceiveStream::Stats stats = stream.second->GetStats();
VoiceReceiverInfo rinfo;
diff --git a/talk/media/webrtc/webrtcvoiceengine_unittest.cc b/talk/media/webrtc/webrtcvoiceengine_unittest.cc
index 4491929..ce5115c 100644
--- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc
+++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc
@@ -57,9 +57,9 @@
&kPcmuCodec, &kIsacCodec, &kOpusCodec, &kG722CodecVoE, &kRedCodec,
&kCn8000Codec, &kCn16000Codec, &kTelephoneEventCodec,
};
-static uint32_t kSsrc1 = 0x99;
-static uint32_t kSsrc2 = 0x98;
-static const uint32_t kSsrcs4[] = {1, 2, 3, 4};
+const uint32_t kSsrc1 = 0x99;
+const uint32_t kSsrc2 = 0x98;
+const uint32_t kSsrcs4[] = { 1, 2, 3, 4 };
class FakeVoEWrapper : public cricket::VoEWrapper {
public:
@@ -124,13 +124,11 @@
EXPECT_TRUE(SetupEngineWithSendStream());
// Remove stream added in Setup.
int default_channel_num = voe_.GetLastChannel();
- uint32_t default_send_ssrc = 0u;
- EXPECT_EQ(0, voe_.GetLocalSSRC(default_channel_num, default_send_ssrc));
- EXPECT_EQ(kSsrc1, default_send_ssrc);
- EXPECT_TRUE(channel_->RemoveSendStream(default_send_ssrc));
+ EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(default_channel_num));
+ EXPECT_TRUE(channel_->RemoveSendStream(kSsrc1));
// Verify the channel does not exist.
- EXPECT_EQ(-1, voe_.GetLocalSSRC(default_channel_num, default_send_ssrc));
+ EXPECT_EQ(-1, voe_.GetChannelFromLocalSsrc(kSsrc1));
}
void DeliverPacket(const void* data, int len) {
rtc::Buffer packet(reinterpret_cast<const uint8_t*>(data), len);
@@ -290,34 +288,79 @@
EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(new_channel_num, ext));
}
- const webrtc::AudioReceiveStream::Stats& GetAudioReceiveStreamStats() const {
- static webrtc::AudioReceiveStream::Stats stats;
- if (stats.remote_ssrc == 0) {
- stats.remote_ssrc = 123;
- stats.bytes_rcvd = 456;
- stats.packets_rcvd = 768;
- stats.packets_lost = 101;
- stats.fraction_lost = 23.45f;
- stats.codec_name = "codec_name";
- stats.ext_seqnum = 678;
- stats.jitter_ms = 901;
- stats.jitter_buffer_ms = 234;
- stats.jitter_buffer_preferred_ms = 567;
- stats.delay_estimate_ms = 890;
- stats.audio_level = 1234;
- stats.expand_rate = 5.67f;
- stats.speech_expand_rate = 8.90f;
- stats.secondary_decoded_rate = 1.23f;
- stats.accelerate_rate = 4.56f;
- stats.preemptive_expand_rate = 7.89f;
- stats.decoding_calls_to_silence_generator = 012;
- stats.decoding_calls_to_neteq = 345;
- stats.decoding_normal = 67890;
- stats.decoding_plc = 1234;
- stats.decoding_cng = 5678;
- stats.decoding_plc_cng = 9012;
- stats.capture_start_ntp_time_ms = 3456;
+ webrtc::AudioSendStream::Stats GetAudioSendStreamStats() const {
+ webrtc::AudioSendStream::Stats stats;
+ stats.local_ssrc = 12;
+ stats.bytes_sent = 345;
+ stats.packets_sent = 678;
+ stats.packets_lost = 9012;
+ stats.fraction_lost = 34.56f;
+ stats.codec_name = "codec_name_send";
+ stats.ext_seqnum = 789;
+ stats.jitter_ms = 12;
+ stats.rtt_ms = 345;
+ stats.audio_level = 678;
+ stats.aec_quality_min = 9.01f;
+ stats.echo_delay_median_ms = 234;
+ stats.echo_delay_std_ms = 567;
+ stats.echo_return_loss = 890;
+ stats.echo_return_loss_enhancement = 1234;
+ stats.typing_noise_detected = true;
+ return stats;
+ }
+ void SetAudioSendStreamStats() {
+ for (auto* s : call_.GetAudioSendStreams()) {
+ s->SetStats(GetAudioSendStreamStats());
}
+ }
+ void VerifyVoiceSenderInfo(const cricket::VoiceSenderInfo& info) {
+ const auto stats = GetAudioSendStreamStats();
+ EXPECT_EQ(info.ssrc(), stats.local_ssrc);
+ EXPECT_EQ(info.bytes_sent, stats.bytes_sent);
+ EXPECT_EQ(info.packets_sent, stats.packets_sent);
+ EXPECT_EQ(info.packets_lost, stats.packets_lost);
+ EXPECT_EQ(info.fraction_lost, stats.fraction_lost);
+ EXPECT_EQ(info.codec_name, stats.codec_name);
+ EXPECT_EQ(info.ext_seqnum, stats.ext_seqnum);
+ EXPECT_EQ(info.jitter_ms, stats.jitter_ms);
+ EXPECT_EQ(info.rtt_ms, stats.rtt_ms);
+ EXPECT_EQ(info.audio_level, stats.audio_level);
+ EXPECT_EQ(info.aec_quality_min, stats.aec_quality_min);
+ EXPECT_EQ(info.echo_delay_median_ms, stats.echo_delay_median_ms);
+ EXPECT_EQ(info.echo_delay_std_ms, stats.echo_delay_std_ms);
+ EXPECT_EQ(info.echo_return_loss, stats.echo_return_loss);
+ EXPECT_EQ(info.echo_return_loss_enhancement,
+ stats.echo_return_loss_enhancement);
+ // TODO(solenberg): Move typing noise detection into AudioSendStream.
+ // EXPECT_EQ(info.typing_noise_detected, stats.typing_noise_detected);
+ }
+
+ webrtc::AudioReceiveStream::Stats GetAudioReceiveStreamStats() const {
+ webrtc::AudioReceiveStream::Stats stats;
+ stats.remote_ssrc = 123;
+ stats.bytes_rcvd = 456;
+ stats.packets_rcvd = 768;
+ stats.packets_lost = 101;
+ stats.fraction_lost = 23.45f;
+ stats.codec_name = "codec_name_recv";
+ stats.ext_seqnum = 678;
+ stats.jitter_ms = 901;
+ stats.jitter_buffer_ms = 234;
+ stats.jitter_buffer_preferred_ms = 567;
+ stats.delay_estimate_ms = 890;
+ stats.audio_level = 1234;
+ stats.expand_rate = 5.67f;
+ stats.speech_expand_rate = 8.90f;
+ stats.secondary_decoded_rate = 1.23f;
+ stats.accelerate_rate = 4.56f;
+ stats.preemptive_expand_rate = 7.89f;
+ stats.decoding_calls_to_silence_generator = 12;
+ stats.decoding_calls_to_neteq = 345;
+ stats.decoding_normal = 67890;
+ stats.decoding_plc = 1234;
+ stats.decoding_cng = 5678;
+ stats.decoding_plc_cng = 9012;
+ stats.capture_start_ntp_time_ms = 3456;
return stats;
}
void SetAudioReceiveStreamStats() {
@@ -326,33 +369,33 @@
}
}
void VerifyVoiceReceiverInfo(const cricket::VoiceReceiverInfo& info) {
- const auto& kStats = GetAudioReceiveStreamStats();
- EXPECT_EQ(info.local_stats.front().ssrc, kStats.remote_ssrc);
- EXPECT_EQ(info.bytes_rcvd, kStats.bytes_rcvd);
- EXPECT_EQ(info.packets_rcvd, kStats.packets_rcvd);
- EXPECT_EQ(info.packets_lost, kStats.packets_lost);
- EXPECT_EQ(info.fraction_lost, kStats.fraction_lost);
- EXPECT_EQ(info.codec_name, kStats.codec_name);
- EXPECT_EQ(info.ext_seqnum, kStats.ext_seqnum);
- EXPECT_EQ(info.jitter_ms, kStats.jitter_ms);
- EXPECT_EQ(info.jitter_buffer_ms, kStats.jitter_buffer_ms);
+ const auto stats = GetAudioReceiveStreamStats();
+ EXPECT_EQ(info.ssrc(), stats.remote_ssrc);
+ EXPECT_EQ(info.bytes_rcvd, stats.bytes_rcvd);
+ EXPECT_EQ(info.packets_rcvd, stats.packets_rcvd);
+ EXPECT_EQ(info.packets_lost, stats.packets_lost);
+ EXPECT_EQ(info.fraction_lost, stats.fraction_lost);
+ EXPECT_EQ(info.codec_name, stats.codec_name);
+ EXPECT_EQ(info.ext_seqnum, stats.ext_seqnum);
+ EXPECT_EQ(info.jitter_ms, stats.jitter_ms);
+ EXPECT_EQ(info.jitter_buffer_ms, stats.jitter_buffer_ms);
EXPECT_EQ(info.jitter_buffer_preferred_ms,
- kStats.jitter_buffer_preferred_ms);
- EXPECT_EQ(info.delay_estimate_ms, kStats.delay_estimate_ms);
- EXPECT_EQ(info.audio_level, kStats.audio_level);
- EXPECT_EQ(info.expand_rate, kStats.expand_rate);
- EXPECT_EQ(info.speech_expand_rate, kStats.speech_expand_rate);
- EXPECT_EQ(info.secondary_decoded_rate, kStats.secondary_decoded_rate);
- EXPECT_EQ(info.accelerate_rate, kStats.accelerate_rate);
- EXPECT_EQ(info.preemptive_expand_rate, kStats.preemptive_expand_rate);
+ stats.jitter_buffer_preferred_ms);
+ EXPECT_EQ(info.delay_estimate_ms, stats.delay_estimate_ms);
+ EXPECT_EQ(info.audio_level, stats.audio_level);
+ EXPECT_EQ(info.expand_rate, stats.expand_rate);
+ EXPECT_EQ(info.speech_expand_rate, stats.speech_expand_rate);
+ EXPECT_EQ(info.secondary_decoded_rate, stats.secondary_decoded_rate);
+ EXPECT_EQ(info.accelerate_rate, stats.accelerate_rate);
+ EXPECT_EQ(info.preemptive_expand_rate, stats.preemptive_expand_rate);
EXPECT_EQ(info.decoding_calls_to_silence_generator,
- kStats.decoding_calls_to_silence_generator);
- EXPECT_EQ(info.decoding_calls_to_neteq, kStats.decoding_calls_to_neteq);
- EXPECT_EQ(info.decoding_normal, kStats.decoding_normal);
- EXPECT_EQ(info.decoding_plc, kStats.decoding_plc);
- EXPECT_EQ(info.decoding_cng, kStats.decoding_cng);
- EXPECT_EQ(info.decoding_plc_cng, kStats.decoding_plc_cng);
- EXPECT_EQ(info.capture_start_ntp_time_ms, kStats.capture_start_ntp_time_ms);
+ stats.decoding_calls_to_silence_generator);
+ EXPECT_EQ(info.decoding_calls_to_neteq, stats.decoding_calls_to_neteq);
+ EXPECT_EQ(info.decoding_normal, stats.decoding_normal);
+ EXPECT_EQ(info.decoding_plc, stats.decoding_plc);
+ EXPECT_EQ(info.decoding_cng, stats.decoding_cng);
+ EXPECT_EQ(info.decoding_plc_cng, stats.decoding_plc_cng);
+ EXPECT_EQ(info.capture_start_ntp_time_ms, stats.capture_start_ntp_time_ms);
}
protected:
@@ -2028,6 +2071,8 @@
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(ssrc)));
}
+ SetAudioSendStreamStats();
+
// Create a receive stream to check that none of the send streams end up in
// the receive stream stats.
EXPECT_TRUE(channel_->AddRecvStream(
@@ -2036,41 +2081,42 @@
EXPECT_TRUE(channel_->SetSendParameters(send_parameters_));
EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_));
- cricket::VoiceMediaInfo info;
- EXPECT_EQ(true, channel_->GetStats(&info));
- EXPECT_EQ(static_cast<size_t>(ARRAY_SIZE(kSsrcs4)), info.senders.size());
+ // Check stats for the added streams.
+ {
+ cricket::VoiceMediaInfo info;
+ EXPECT_EQ(true, channel_->GetStats(&info));
- // Verify the statistic information is correct.
- // TODO(solenberg): Make this loop ordering independent.
- for (unsigned int i = 0; i < ARRAY_SIZE(kSsrcs4); ++i) {
- EXPECT_EQ(kSsrcs4[i], info.senders[i].ssrc());
- EXPECT_EQ(kPcmuCodec.name, info.senders[i].codec_name);
- EXPECT_EQ(cricket::kIntStatValue, info.senders[i].bytes_sent);
- EXPECT_EQ(cricket::kIntStatValue, info.senders[i].packets_sent);
- EXPECT_EQ(cricket::kIntStatValue, info.senders[i].packets_lost);
- EXPECT_EQ(cricket::kFractionLostStatValue, info.senders[i].fraction_lost);
- EXPECT_EQ(cricket::kIntStatValue, info.senders[i].ext_seqnum);
- EXPECT_EQ(cricket::kIntStatValue, info.senders[i].rtt_ms);
- EXPECT_EQ(cricket::kIntStatValue, info.senders[i].jitter_ms);
- EXPECT_EQ(kPcmuCodec.name, info.senders[i].codec_name);
+ // We have added 4 send streams. We should see empty stats for all.
+ EXPECT_EQ(static_cast<size_t>(ARRAY_SIZE(kSsrcs4)), info.senders.size());
+ for (const auto& sender : info.senders) {
+ VerifyVoiceSenderInfo(sender);
+ }
+
+ // We have added one receive stream. We should see empty stats.
+ EXPECT_EQ(info.receivers.size(), 1u);
+ EXPECT_EQ(info.receivers[0].ssrc(), 0);
}
- // We have added one receive stream. We should see empty stats.
- EXPECT_EQ(info.receivers.size(), 1u);
- EXPECT_EQ(info.receivers[0].local_stats.front().ssrc, 0);
-
// Remove the kSsrc2 stream. No receiver stats.
- EXPECT_TRUE(channel_->RemoveRecvStream(kSsrc2));
- EXPECT_EQ(true, channel_->GetStats(&info));
- EXPECT_EQ(0u, info.receivers.size());
+ {
+ cricket::VoiceMediaInfo info;
+ EXPECT_TRUE(channel_->RemoveRecvStream(kSsrc2));
+ EXPECT_EQ(true, channel_->GetStats(&info));
+ EXPECT_EQ(static_cast<size_t>(ARRAY_SIZE(kSsrcs4)), info.senders.size());
+ EXPECT_EQ(0u, info.receivers.size());
+ }
// Deliver a new packet - a default receive stream should be created and we
// should see stats again.
- DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
- SetAudioReceiveStreamStats();
- EXPECT_EQ(true, channel_->GetStats(&info));
- EXPECT_EQ(1u, info.receivers.size());
- VerifyVoiceReceiverInfo(info.receivers[0]);
+ {
+ cricket::VoiceMediaInfo info;
+ DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
+ SetAudioReceiveStreamStats();
+ EXPECT_EQ(true, channel_->GetStats(&info));
+ EXPECT_EQ(static_cast<size_t>(ARRAY_SIZE(kSsrcs4)), info.senders.size());
+ EXPECT_EQ(1u, info.receivers.size());
+ VerifyVoiceReceiverInfo(info.receivers[0]);
+ }
}
// Test that we can add and remove receive streams, and do proper send/playout.
@@ -2292,17 +2338,13 @@
// SSRC is set in SetupEngine by calling AddSendStream.
TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrc) {
EXPECT_TRUE(SetupEngineWithSendStream());
- int channel_num = voe_.GetLastChannel();
- unsigned int send_ssrc;
- EXPECT_EQ(0, voe_.GetLocalSSRC(channel_num, send_ssrc));
- EXPECT_NE(0U, send_ssrc);
- EXPECT_EQ(0, voe_.GetLocalSSRC(channel_num, send_ssrc));
- EXPECT_EQ(kSsrc1, send_ssrc);
+ EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(voe_.GetLastChannel()));
}
TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
// Setup. We need send codec to be set to get all stats.
EXPECT_TRUE(SetupEngineWithSendStream());
+ SetAudioSendStreamStats();
// SetupEngineWithSendStream adds a send stream with kSsrc1, so the receive
// stream has to use a different SSRC.
EXPECT_TRUE(channel_->AddRecvStream(
@@ -2310,58 +2352,48 @@
EXPECT_TRUE(channel_->SetSendParameters(send_parameters_));
EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_));
- cricket::VoiceMediaInfo info;
- EXPECT_EQ(true, channel_->GetStats(&info));
- EXPECT_EQ(1u, info.senders.size());
- EXPECT_EQ(kSsrc1, info.senders[0].ssrc());
- EXPECT_EQ(kPcmuCodec.name, info.senders[0].codec_name);
- EXPECT_EQ(cricket::kIntStatValue, info.senders[0].bytes_sent);
- EXPECT_EQ(cricket::kIntStatValue, info.senders[0].packets_sent);
- EXPECT_EQ(cricket::kIntStatValue, info.senders[0].packets_lost);
- EXPECT_EQ(cricket::kFractionLostStatValue, info.senders[0].fraction_lost);
- EXPECT_EQ(cricket::kIntStatValue, info.senders[0].ext_seqnum);
- EXPECT_EQ(cricket::kIntStatValue, info.senders[0].rtt_ms);
- EXPECT_EQ(cricket::kIntStatValue, info.senders[0].jitter_ms);
- EXPECT_EQ(kPcmuCodec.name, info.senders[0].codec_name);
- // TODO(sriniv): Add testing for more fields. These are not populated
- // in FakeWebrtcVoiceEngine yet.
- // EXPECT_EQ(cricket::kIntStatValue, info.senders[0].audio_level);
- // EXPECT_EQ(cricket::kIntStatValue, info.senders[0].echo_delay_median_ms);
- // EXPECT_EQ(cricket::kIntStatValue, info.senders[0].echo_delay_std_ms);
- // EXPECT_EQ(cricket::kIntStatValue, info.senders[0].echo_return_loss);
- // EXPECT_EQ(cricket::kIntStatValue,
- // info.senders[0].echo_return_loss_enhancement);
- // We have added one receive stream. We should see empty stats.
- EXPECT_EQ(info.receivers.size(), 1u);
- EXPECT_EQ(info.receivers[0].local_stats.front().ssrc, 0);
+ // Check stats for the added streams.
+ {
+ cricket::VoiceMediaInfo info;
+ EXPECT_EQ(true, channel_->GetStats(&info));
+
+ // We have added one send stream. We should see the stats we've set.
+ EXPECT_EQ(1u, info.senders.size());
+ VerifyVoiceSenderInfo(info.senders[0]);
+ // We have added one receive stream. We should see empty stats.
+ EXPECT_EQ(info.receivers.size(), 1u);
+ EXPECT_EQ(info.receivers[0].ssrc(), 0);
+ }
// Remove the kSsrc2 stream. No receiver stats.
- EXPECT_TRUE(channel_->RemoveRecvStream(kSsrc2));
- EXPECT_EQ(true, channel_->GetStats(&info));
- EXPECT_EQ(0u, info.receivers.size());
+ {
+ cricket::VoiceMediaInfo info;
+ EXPECT_TRUE(channel_->RemoveRecvStream(kSsrc2));
+ EXPECT_EQ(true, channel_->GetStats(&info));
+ EXPECT_EQ(1u, info.senders.size());
+ EXPECT_EQ(0u, info.receivers.size());
+ }
// Deliver a new packet - a default receive stream should be created and we
// should see stats again.
- DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
- SetAudioReceiveStreamStats();
- EXPECT_EQ(true, channel_->GetStats(&info));
- EXPECT_EQ(1u, info.receivers.size());
- VerifyVoiceReceiverInfo(info.receivers[0]);
+ {
+ cricket::VoiceMediaInfo info;
+ DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
+ SetAudioReceiveStreamStats();
+ EXPECT_EQ(true, channel_->GetStats(&info));
+ EXPECT_EQ(1u, info.senders.size());
+ EXPECT_EQ(1u, info.receivers.size());
+ VerifyVoiceReceiverInfo(info.receivers[0]);
+ }
}
// Test that we can set the outgoing SSRC properly with multiple streams.
// SSRC is set in SetupEngine by calling AddSendStream.
TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrcWithMultipleStreams) {
EXPECT_TRUE(SetupEngineWithSendStream());
- int channel_num1 = voe_.GetLastChannel();
- unsigned int send_ssrc;
- EXPECT_EQ(0, voe_.GetLocalSSRC(channel_num1, send_ssrc));
- EXPECT_EQ(kSsrc1, send_ssrc);
-
+ EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(voe_.GetLastChannel()));
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
- int channel_num2 = voe_.GetLastChannel();
- EXPECT_EQ(0, voe_.GetLocalSSRC(channel_num2, send_ssrc));
- EXPECT_EQ(kSsrc1, send_ssrc);
+ EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(voe_.GetLastChannel()));
}
// Test that the local SSRC is the same on sending and receiving channels if the
@@ -2376,12 +2408,8 @@
cricket::StreamParams::CreateLegacy(1234)));
int send_channel_num = voe_.GetLastChannel();
- unsigned int ssrc = 0;
- EXPECT_EQ(0, voe_.GetLocalSSRC(send_channel_num, ssrc));
- EXPECT_EQ(1234U, ssrc);
- ssrc = 0;
- EXPECT_EQ(0, voe_.GetLocalSSRC(receive_channel_num, ssrc));
- EXPECT_EQ(1234U, ssrc);
+ EXPECT_EQ(1234U, voe_.GetLocalSSRC(send_channel_num));
+ EXPECT_EQ(1234U, voe_.GetLocalSSRC(receive_channel_num));
}
// Test that we can properly receive packets.
@@ -2545,7 +2573,6 @@
bool ec_enabled;
webrtc::EcModes ec_mode;
- bool ec_metrics_enabled;
webrtc::AecmModes aecm_mode;
bool cng_enabled;
bool agc_enabled;
@@ -2557,7 +2584,6 @@
bool stereo_swapping_enabled;
bool typing_detection_enabled;
voe_.GetEcStatus(ec_enabled, ec_mode);
- voe_.GetEcMetricsStatus(ec_metrics_enabled);
voe_.GetAecmMode(aecm_mode, cng_enabled);
voe_.GetAgcStatus(agc_enabled, agc_mode);
voe_.GetAgcConfig(agc_config);
@@ -2566,7 +2592,7 @@
stereo_swapping_enabled = voe_.IsStereoChannelSwappingEnabled();
voe_.GetTypingDetectionStatus(typing_detection_enabled);
EXPECT_TRUE(ec_enabled);
- EXPECT_TRUE(ec_metrics_enabled);
+ EXPECT_TRUE(voe_.ec_metrics_enabled());
EXPECT_FALSE(cng_enabled);
EXPECT_TRUE(agc_enabled);
EXPECT_EQ(0, agc_config.targetLeveldBOv);
@@ -2581,7 +2607,6 @@
cricket::AudioOptions options;
ASSERT_TRUE(engine_.SetOptions(options));
voe_.GetEcStatus(ec_enabled, ec_mode);
- voe_.GetEcMetricsStatus(ec_metrics_enabled);
voe_.GetAecmMode(aecm_mode, cng_enabled);
voe_.GetAgcStatus(agc_enabled, agc_mode);
voe_.GetAgcConfig(agc_config);
@@ -2590,7 +2615,7 @@
stereo_swapping_enabled = voe_.IsStereoChannelSwappingEnabled();
voe_.GetTypingDetectionStatus(typing_detection_enabled);
EXPECT_TRUE(ec_enabled);
- EXPECT_TRUE(ec_metrics_enabled);
+ EXPECT_TRUE(voe_.ec_metrics_enabled());
EXPECT_FALSE(cng_enabled);
EXPECT_TRUE(agc_enabled);
EXPECT_EQ(0, agc_config.targetLeveldBOv);
@@ -2615,7 +2640,6 @@
options.echo_cancellation.Set(true);
ASSERT_TRUE(engine_.SetOptions(options));
voe_.GetEcStatus(ec_enabled, ec_mode);
- voe_.GetEcMetricsStatus(ec_metrics_enabled);
voe_.GetAecmMode(aecm_mode, cng_enabled);
voe_.GetAgcStatus(agc_enabled, agc_mode);
voe_.GetAgcConfig(agc_config);
@@ -2624,7 +2648,7 @@
stereo_swapping_enabled = voe_.IsStereoChannelSwappingEnabled();
voe_.GetTypingDetectionStatus(typing_detection_enabled);
EXPECT_TRUE(ec_enabled);
- EXPECT_TRUE(ec_metrics_enabled);
+ EXPECT_TRUE(voe_.ec_metrics_enabled());
EXPECT_TRUE(agc_enabled);
EXPECT_EQ(0, agc_config.targetLeveldBOv);
EXPECT_TRUE(ns_enabled);
@@ -2639,10 +2663,9 @@
options.delay_agnostic_aec.Set(true);
ASSERT_TRUE(engine_.SetOptions(options));
voe_.GetEcStatus(ec_enabled, ec_mode);
- voe_.GetEcMetricsStatus(ec_metrics_enabled);
voe_.GetAecmMode(aecm_mode, cng_enabled);
EXPECT_TRUE(ec_enabled);
- EXPECT_TRUE(ec_metrics_enabled);
+ EXPECT_TRUE(voe_.ec_metrics_enabled());
EXPECT_EQ(ec_mode, webrtc::kEcConference);
// Turn off echo cancellation and delay agnostic aec.
@@ -2656,9 +2679,8 @@
options.delay_agnostic_aec.Set(true);
ASSERT_TRUE(engine_.SetOptions(options));
voe_.GetEcStatus(ec_enabled, ec_mode);
- voe_.GetEcMetricsStatus(ec_metrics_enabled);
EXPECT_TRUE(ec_enabled);
- EXPECT_TRUE(ec_metrics_enabled);
+ EXPECT_TRUE(voe_.ec_metrics_enabled());
EXPECT_EQ(ec_mode, webrtc::kEcConference);
// Turn off AGC
@@ -2706,7 +2728,6 @@
bool ec_enabled;
webrtc::EcModes ec_mode;
- bool ec_metrics_enabled;
bool agc_enabled;
webrtc::AgcModes agc_mode;
bool ns_enabled;
@@ -2716,7 +2737,6 @@
bool typing_detection_enabled;
voe_.GetEcStatus(ec_enabled, ec_mode);
- voe_.GetEcMetricsStatus(ec_metrics_enabled);
voe_.GetAgcStatus(agc_enabled, agc_mode);
voe_.GetNsStatus(ns_enabled, ns_mode);
highpass_filter_enabled = voe_.IsHighPassFilterEnabled();
@@ -2978,7 +2998,7 @@
for (uint32_t ssrc : ssrcs) {
const auto* s = call_.GetAudioReceiveStream(ssrc);
EXPECT_NE(nullptr, s);
- EXPECT_EQ(false, s->GetConfig().combined_audio_video_bwe);
+ EXPECT_FALSE(s->GetConfig().combined_audio_video_bwe);
}
// Enable combined BWE option - now it should be set up.
@@ -2996,7 +3016,7 @@
for (uint32_t ssrc : ssrcs) {
const auto* s = call_.GetAudioReceiveStream(ssrc);
EXPECT_NE(nullptr, s);
- EXPECT_EQ(false, s->GetConfig().combined_audio_video_bwe);
+ EXPECT_FALSE(s->GetConfig().combined_audio_video_bwe);
}
EXPECT_EQ(2, call_.GetAudioReceiveStreams().size());
diff --git a/webrtc/audio/audio_receive_stream.cc b/webrtc/audio/audio_receive_stream.cc
index 0fd96d0..b3cacba 100644
--- a/webrtc/audio/audio_receive_stream.cc
+++ b/webrtc/audio/audio_receive_stream.cc
@@ -28,6 +28,7 @@
std::string AudioReceiveStream::Config::Rtp::ToString() const {
std::stringstream ss;
ss << "{remote_ssrc: " << remote_ssrc;
+ ss << ", local_ssrc: " << local_ssrc;
ss << ", extensions: [";
for (size_t i = 0; i < extensions.size(); ++i) {
ss << extensions[i].ToString();
@@ -43,10 +44,16 @@
std::string AudioReceiveStream::Config::ToString() const {
std::stringstream ss;
ss << "{rtp: " << rtp.ToString();
+ ss << ", receive_transport: "
+ << (receive_transport ? "(Transport)" : "nullptr");
+ ss << ", rtcp_send_transport: "
+ << (rtcp_send_transport ? "(Transport)" : "nullptr");
ss << ", voe_channel_id: " << voe_channel_id;
if (!sync_group.empty()) {
ss << ", sync_group: " << sync_group;
}
+ ss << ", combined_audio_video_bwe: "
+ << (combined_audio_video_bwe ? "true" : "false");
ss << '}';
return ss.str();
}
@@ -61,7 +68,6 @@
voice_engine_(voice_engine),
voe_base_(voice_engine),
rtp_header_parser_(RtpHeaderParser::Create()) {
- RTC_DCHECK(thread_checker_.CalledOnValidThread());
LOG(LS_INFO) << "AudioReceiveStream: " << config_.ToString();
RTC_DCHECK(config.voe_channel_id != -1);
RTC_DCHECK(remote_bitrate_estimator_ != nullptr);
@@ -101,26 +107,25 @@
ScopedVoEInterface<VoEVideoSync> sync(voice_engine_);
ScopedVoEInterface<VoEVolumeControl> volume(voice_engine_);
unsigned int ssrc = 0;
- webrtc::CallStatistics cs = {0};
- webrtc::CodecInst ci = {0};
+ webrtc::CallStatistics call_stats = {0};
+ webrtc::CodecInst codec_inst = {0};
// Only collect stats if we have seen some traffic with the SSRC.
if (rtp->GetRemoteSSRC(config_.voe_channel_id, ssrc) == -1 ||
- rtp->GetRTCPStatistics(config_.voe_channel_id, cs) == -1 ||
- codec->GetRecCodec(config_.voe_channel_id, ci) == -1) {
+ rtp->GetRTCPStatistics(config_.voe_channel_id, call_stats) == -1 ||
+ codec->GetRecCodec(config_.voe_channel_id, codec_inst) == -1) {
return stats;
}
- stats.bytes_rcvd = cs.bytesReceived;
- stats.packets_rcvd = cs.packetsReceived;
- stats.packets_lost = cs.cumulativeLost;
- stats.fraction_lost = static_cast<float>(cs.fractionLost) / (1 << 8);
- if (ci.pltype != -1) {
- stats.codec_name = ci.plname;
+ stats.bytes_rcvd = call_stats.bytesReceived;
+ stats.packets_rcvd = call_stats.packetsReceived;
+ stats.packets_lost = call_stats.cumulativeLost;
+ stats.fraction_lost = Q8ToFloat(call_stats.fractionLost);
+ if (codec_inst.pltype != -1) {
+ stats.codec_name = codec_inst.plname;
}
-
- stats.ext_seqnum = cs.extendedMax;
- if (ci.plfreq / 1000 > 0) {
- stats.jitter_ms = cs.jitterSamples / (ci.plfreq / 1000);
+ stats.ext_seqnum = call_stats.extendedMax;
+ if (codec_inst.plfreq / 1000 > 0) {
+ stats.jitter_ms = call_stats.jitterSamples / (codec_inst.plfreq / 1000);
}
{
int jitter_buffer_delay_ms = 0;
@@ -161,7 +166,7 @@
stats.decoding_plc_cng = ds.decoded_plc_cng;
}
- stats.capture_start_ntp_time_ms = cs.capture_start_ntp_time_ms_;
+ stats.capture_start_ntp_time_ms = call_stats.capture_start_ntp_time_ms_;
return stats;
}
diff --git a/webrtc/audio/audio_receive_stream.h b/webrtc/audio/audio_receive_stream.h
index 5c77653..5d02b0e 100644
--- a/webrtc/audio/audio_receive_stream.h
+++ b/webrtc/audio/audio_receive_stream.h
@@ -24,7 +24,7 @@
namespace internal {
-class AudioReceiveStream : public webrtc::AudioReceiveStream {
+class AudioReceiveStream final : public webrtc::AudioReceiveStream {
public:
AudioReceiveStream(RemoteBitrateEstimator* remote_bitrate_estimator,
const webrtc::AudioReceiveStream::Config& config,
@@ -53,6 +53,8 @@
// We hold one interface pointer to the VoE to make sure it is kept alive.
ScopedVoEInterface<VoEBase> voe_base_;
rtc::scoped_ptr<RtpHeaderParser> rtp_header_parser_;
+
+ RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioReceiveStream);
};
} // namespace internal
} // namespace webrtc
diff --git a/webrtc/audio/audio_receive_stream_unittest.cc b/webrtc/audio/audio_receive_stream_unittest.cc
index 8809b35..4e267f1 100644
--- a/webrtc/audio/audio_receive_stream_unittest.cc
+++ b/webrtc/audio/audio_receive_stream_unittest.cc
@@ -61,12 +61,36 @@
namespace webrtc {
namespace test {
+TEST(AudioReceiveStreamTest, ConfigToString) {
+ const int kAbsSendTimeId = 3;
+ AudioReceiveStream::Config config;
+ config.rtp.remote_ssrc = 1234;
+ config.rtp.local_ssrc = 5678;
+ config.rtp.extensions.push_back(
+ RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
+ config.voe_channel_id = 1;
+ config.combined_audio_video_bwe = true;
+ EXPECT_EQ("{rtp: {remote_ssrc: 1234, local_ssrc: 5678, extensions: [{name: "
+ "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, id: 3}]}, "
+ "receive_transport: nullptr, rtcp_send_transport: nullptr, "
+ "voe_channel_id: 1, combined_audio_video_bwe: true}", config.ToString());
+}
+
+TEST(AudioReceiveStreamTest, ConstructDestruct) {
+ MockRemoteBitrateEstimator remote_bitrate_estimator;
+ FakeVoiceEngine voice_engine;
+ AudioReceiveStream::Config config;
+ config.voe_channel_id = 1;
+ internal::AudioReceiveStream recv_stream(&remote_bitrate_estimator, config,
+ &voice_engine);
+}
+
TEST(AudioReceiveStreamTest, AudioPacketUpdatesBweWithTimestamp) {
MockRemoteBitrateEstimator remote_bitrate_estimator;
FakeVoiceEngine voice_engine;
AudioReceiveStream::Config config;
config.combined_audio_video_bwe = true;
- config.voe_channel_id = voice_engine.kReceiveChannelId;
+ config.voe_channel_id = FakeVoiceEngine::kRecvChannelId;
const int kAbsSendTimeId = 3;
config.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
@@ -86,38 +110,35 @@
}
TEST(AudioReceiveStreamTest, GetStats) {
- const uint32_t kSsrc1 = 667;
-
MockRemoteBitrateEstimator remote_bitrate_estimator;
FakeVoiceEngine voice_engine;
AudioReceiveStream::Config config;
- config.rtp.remote_ssrc = kSsrc1;
- config.voe_channel_id = voice_engine.kReceiveChannelId;
+ config.rtp.remote_ssrc = FakeVoiceEngine::kRecvSsrc;
+ config.voe_channel_id = FakeVoiceEngine::kRecvChannelId;
internal::AudioReceiveStream recv_stream(&remote_bitrate_estimator, config,
&voice_engine);
AudioReceiveStream::Stats stats = recv_stream.GetStats();
- const CallStatistics& call_stats = voice_engine.GetRecvCallStats();
- const CodecInst& codec_inst = voice_engine.GetRecvRecCodecInst();
- const NetworkStatistics& net_stats = voice_engine.GetRecvNetworkStats();
+ const CallStatistics& call_stats = FakeVoiceEngine::kRecvCallStats;
+ const CodecInst& codec_inst = FakeVoiceEngine::kRecvCodecInst;
+ const NetworkStatistics& net_stats = FakeVoiceEngine::kRecvNetworkStats;
const AudioDecodingCallStats& decode_stats =
- voice_engine.GetRecvAudioDecodingCallStats();
- EXPECT_EQ(kSsrc1, stats.remote_ssrc);
+ FakeVoiceEngine::kRecvAudioDecodingCallStats;
+ EXPECT_EQ(FakeVoiceEngine::kRecvSsrc, stats.remote_ssrc);
EXPECT_EQ(static_cast<int64_t>(call_stats.bytesReceived), stats.bytes_rcvd);
EXPECT_EQ(static_cast<uint32_t>(call_stats.packetsReceived),
stats.packets_rcvd);
EXPECT_EQ(call_stats.cumulativeLost, stats.packets_lost);
- EXPECT_EQ(static_cast<float>(call_stats.fractionLost) / 256,
- stats.fraction_lost);
+ EXPECT_EQ(Q8ToFloat(call_stats.fractionLost), stats.fraction_lost);
EXPECT_EQ(std::string(codec_inst.plname), stats.codec_name);
EXPECT_EQ(call_stats.extendedMax, stats.ext_seqnum);
EXPECT_EQ(call_stats.jitterSamples / (codec_inst.plfreq / 1000),
stats.jitter_ms);
EXPECT_EQ(net_stats.currentBufferSize, stats.jitter_buffer_ms);
EXPECT_EQ(net_stats.preferredBufferSize, stats.jitter_buffer_preferred_ms);
- EXPECT_EQ(static_cast<uint32_t>(voice_engine.kRecvJitterBufferDelay +
- voice_engine.kRecvPlayoutBufferDelay), stats.delay_estimate_ms);
- EXPECT_EQ(static_cast<int32_t>(voice_engine.kRecvSpeechOutputLevel),
+ EXPECT_EQ(static_cast<uint32_t>(FakeVoiceEngine::kRecvJitterBufferDelay +
+ FakeVoiceEngine::kRecvPlayoutBufferDelay), stats.delay_estimate_ms);
+ EXPECT_EQ(static_cast<int32_t>(FakeVoiceEngine::kRecvSpeechOutputLevel),
stats.audio_level);
EXPECT_EQ(Q14ToFloat(net_stats.currentExpandRate), stats.expand_rate);
EXPECT_EQ(Q14ToFloat(net_stats.currentSpeechExpandRate),
diff --git a/webrtc/audio/audio_send_stream.cc b/webrtc/audio/audio_send_stream.cc
index 0d0c072..ccfdca5 100644
--- a/webrtc/audio/audio_send_stream.cc
+++ b/webrtc/audio/audio_send_stream.cc
@@ -12,8 +12,13 @@
#include <string>
+#include "webrtc/audio/conversion.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
+#include "webrtc/voice_engine/include/voe_audio_processing.h"
+#include "webrtc/voice_engine/include/voe_codec.h"
+#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
+#include "webrtc/voice_engine/include/voe_volume_control.h"
namespace webrtc {
std::string AudioSendStream::Config::Rtp::ToString() const {
@@ -22,8 +27,9 @@
ss << ", extensions: [";
for (size_t i = 0; i < extensions.size(); ++i) {
ss << extensions[i].ToString();
- if (i != extensions.size() - 1)
+ if (i != extensions.size() - 1) {
ss << ", ";
+ }
}
ss << ']';
ss << '}';
@@ -42,30 +48,134 @@
}
namespace internal {
-AudioSendStream::AudioSendStream(const webrtc::AudioSendStream::Config& config)
- : config_(config) {
+AudioSendStream::AudioSendStream(const webrtc::AudioSendStream::Config& config,
+ VoiceEngine* voice_engine)
+ : config_(config),
+ voice_engine_(voice_engine),
+ voe_base_(voice_engine) {
LOG(LS_INFO) << "AudioSendStream: " << config_.ToString();
- RTC_DCHECK(config.voe_channel_id != -1);
+ RTC_DCHECK_NE(config.voe_channel_id, -1);
+ RTC_DCHECK(voice_engine_);
}
AudioSendStream::~AudioSendStream() {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
LOG(LS_INFO) << "~AudioSendStream: " << config_.ToString();
}
webrtc::AudioSendStream::Stats AudioSendStream::GetStats() const {
- return webrtc::AudioSendStream::Stats();
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ webrtc::AudioSendStream::Stats stats;
+ stats.local_ssrc = config_.rtp.ssrc;
+ ScopedVoEInterface<VoEAudioProcessing> processing(voice_engine_);
+ ScopedVoEInterface<VoECodec> codec(voice_engine_);
+ ScopedVoEInterface<VoERTP_RTCP> rtp(voice_engine_);
+ ScopedVoEInterface<VoEVolumeControl> volume(voice_engine_);
+ unsigned int ssrc = 0;
+ webrtc::CallStatistics call_stats = {0};
+ if (rtp->GetLocalSSRC(config_.voe_channel_id, ssrc) == -1 ||
+ rtp->GetRTCPStatistics(config_.voe_channel_id, call_stats) == -1) {
+ return stats;
+ }
+
+ stats.bytes_sent = call_stats.bytesSent;
+ stats.packets_sent = call_stats.packetsSent;
+
+ webrtc::CodecInst codec_inst = {0};
+ if (codec->GetSendCodec(config_.voe_channel_id, codec_inst) != -1) {
+ RTC_DCHECK_NE(codec_inst.pltype, -1);
+ stats.codec_name = codec_inst.plname;
+
+ // Get data from the last remote RTCP report.
+ std::vector<webrtc::ReportBlock> blocks;
+ if (rtp->GetRemoteRTCPReportBlocks(config_.voe_channel_id, &blocks) != -1) {
+ for (const webrtc::ReportBlock& block : blocks) {
+ // Lookup report for send ssrc only.
+ if (block.source_SSRC == stats.local_ssrc) {
+ stats.packets_lost = block.cumulative_num_packets_lost;
+ stats.fraction_lost = Q8ToFloat(block.fraction_lost);
+ stats.ext_seqnum = block.extended_highest_sequence_number;
+ // Convert samples to milliseconds.
+ if (codec_inst.plfreq / 1000 > 0) {
+ stats.jitter_ms =
+ block.interarrival_jitter / (codec_inst.plfreq / 1000);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // RTT isn't known until a RTCP report is received. Until then, VoiceEngine
+ // returns 0 to indicate an error value.
+ if (call_stats.rttMs > 0) {
+ stats.rtt_ms = call_stats.rttMs;
+ }
+
+ // Local speech level.
+ {
+ unsigned int level = 0;
+ if (volume->GetSpeechInputLevelFullRange(level) != -1) {
+ stats.audio_level = static_cast<int32_t>(level);
+ }
+ }
+
+ // TODO(ajm): Re-enable this metric once we have a reliable implementation.
+ stats.aec_quality_min = -1;
+
+ bool echo_metrics_on = false;
+ if (processing->GetEcMetricsStatus(echo_metrics_on) != -1 &&
+ echo_metrics_on) {
+ // These can also be negative, but in practice -1 is only used to signal
+ // insufficient data, since the resolution is limited to multiples of 4 ms.
+ int median = -1;
+ int std = -1;
+ float dummy = 0.0f;
+ if (processing->GetEcDelayMetrics(median, std, dummy) != -1) {
+ stats.echo_delay_median_ms = median;
+ stats.echo_delay_std_ms = std;
+ }
+
+ // These can take on valid negative values, so use the lowest possible level
+ // as default rather than -1.
+ int erl = -100;
+ int erle = -100;
+ int dummy1 = 0;
+ int dummy2 = 0;
+ if (processing->GetEchoMetrics(erl, erle, dummy1, dummy2) != -1) {
+ stats.echo_return_loss = erl;
+ stats.echo_return_loss_enhancement = erle;
+ }
+ }
+
+ // TODO(solenberg): Collect typing noise warnings here too!
+ // bool typing_noise_detected = typing_noise_detected_;
+
+ return stats;
+}
+
+const webrtc::AudioSendStream::Config& AudioSendStream::config() const {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ return config_;
}
void AudioSendStream::Start() {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
}
void AudioSendStream::Stop() {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
}
void AudioSendStream::SignalNetworkState(NetworkState state) {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
}
bool AudioSendStream::DeliverRtcp(const uint8_t* packet, size_t length) {
+ // TODO(solenberg): Tests call this function on a network thread, libjingle
+ // calls on the worker thread. We should move towards always using a network
+ // thread. Then this check can be enabled.
+ // RTC_DCHECK(!thread_checker_.CalledOnValidThread());
return false;
}
} // namespace internal
diff --git a/webrtc/audio/audio_send_stream.h b/webrtc/audio/audio_send_stream.h
index 54046fc..ae81dfc 100644
--- a/webrtc/audio/audio_send_stream.h
+++ b/webrtc/audio/audio_send_stream.h
@@ -12,13 +12,20 @@
#define WEBRTC_AUDIO_AUDIO_SEND_STREAM_H_
#include "webrtc/audio_send_stream.h"
+#include "webrtc/audio/scoped_voe_interface.h"
+#include "webrtc/base/thread_checker.h"
+#include "webrtc/voice_engine/include/voe_base.h"
namespace webrtc {
+
+class VoiceEngine;
+
namespace internal {
-class AudioSendStream : public webrtc::AudioSendStream {
+class AudioSendStream final : public webrtc::AudioSendStream {
public:
- explicit AudioSendStream(const webrtc::AudioSendStream::Config& config);
+ AudioSendStream(const webrtc::AudioSendStream::Config& config,
+ VoiceEngine* voice_engine);
~AudioSendStream() override;
// webrtc::SendStream implementation.
@@ -30,12 +37,16 @@
// webrtc::AudioSendStream implementation.
webrtc::AudioSendStream::Stats GetStats() const override;
- const webrtc::AudioSendStream::Config& config() const {
- return config_;
- }
+ const webrtc::AudioSendStream::Config& config() const;
private:
+ rtc::ThreadChecker thread_checker_;
const webrtc::AudioSendStream::Config config_;
+ VoiceEngine* voice_engine_;
+ // We hold one interface pointer to the VoE to make sure it is kept alive.
+ ScopedVoEInterface<VoEBase> voe_base_;
+
+ RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioSendStream);
};
} // namespace internal
} // namespace webrtc
diff --git a/webrtc/audio/audio_send_stream_unittest.cc b/webrtc/audio/audio_send_stream_unittest.cc
index e5d73ff..227ec83 100644
--- a/webrtc/audio/audio_send_stream_unittest.cc
+++ b/webrtc/audio/audio_send_stream_unittest.cc
@@ -11,8 +11,11 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/audio/audio_send_stream.h"
+#include "webrtc/audio/conversion.h"
+#include "webrtc/test/fake_voice_engine.h"
namespace webrtc {
+namespace test {
TEST(AudioSendStreamTest, ConfigToString) {
const int kAbsSendTimeId = 3;
@@ -23,12 +26,51 @@
config.voe_channel_id = 1;
config.cng_payload_type = 42;
config.red_payload_type = 17;
- EXPECT_GT(config.ToString().size(), 0u);
+ EXPECT_EQ("{rtp: {ssrc: 1234, extensions: [{name: "
+ "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, id: 3}]}, "
+ "voe_channel_id: 1, cng_payload_type: 42, red_payload_type: 17}",
+ config.ToString());
}
TEST(AudioSendStreamTest, ConstructDestruct) {
+ FakeVoiceEngine voice_engine;
AudioSendStream::Config config(nullptr);
config.voe_channel_id = 1;
- internal::AudioSendStream send_stream(config);
+ internal::AudioSendStream send_stream(config, &voice_engine);
}
+
+TEST(AudioSendStreamTest, GetStats) {
+ FakeVoiceEngine voice_engine;
+ AudioSendStream::Config config(nullptr);
+ config.rtp.ssrc = FakeVoiceEngine::kSendSsrc;
+ config.voe_channel_id = FakeVoiceEngine::kSendChannelId;
+ internal::AudioSendStream send_stream(config, &voice_engine);
+
+ AudioSendStream::Stats stats = send_stream.GetStats();
+ const CallStatistics& call_stats = FakeVoiceEngine::kSendCallStats;
+ const CodecInst& codec_inst = FakeVoiceEngine::kSendCodecInst;
+ const ReportBlock& report_block = FakeVoiceEngine::kSendReportBlock;
+ EXPECT_EQ(FakeVoiceEngine::kSendSsrc, stats.local_ssrc);
+ EXPECT_EQ(static_cast<int64_t>(call_stats.bytesSent), stats.bytes_sent);
+ EXPECT_EQ(call_stats.packetsSent, stats.packets_sent);
+ EXPECT_EQ(static_cast<int32_t>(report_block.cumulative_num_packets_lost),
+ stats.packets_lost);
+ EXPECT_EQ(Q8ToFloat(report_block.fraction_lost), stats.fraction_lost);
+ EXPECT_EQ(std::string(codec_inst.plname), stats.codec_name);
+ EXPECT_EQ(static_cast<int32_t>(report_block.extended_highest_sequence_number),
+ stats.ext_seqnum);
+ EXPECT_EQ(static_cast<int32_t>(report_block.interarrival_jitter /
+ (codec_inst.plfreq / 1000)), stats.jitter_ms);
+ EXPECT_EQ(call_stats.rttMs, stats.rtt_ms);
+ EXPECT_EQ(static_cast<int32_t>(FakeVoiceEngine::kSendSpeechInputLevel),
+ stats.audio_level);
+ EXPECT_EQ(-1, stats.aec_quality_min);
+ EXPECT_EQ(FakeVoiceEngine::kSendEchoDelayMedian, stats.echo_delay_median_ms);
+ EXPECT_EQ(FakeVoiceEngine::kSendEchoDelayStdDev, stats.echo_delay_std_ms);
+ EXPECT_EQ(FakeVoiceEngine::kSendEchoReturnLoss, stats.echo_return_loss);
+ EXPECT_EQ(FakeVoiceEngine::kSendEchoReturnLossEnhancement,
+ stats.echo_return_loss_enhancement);
+ EXPECT_FALSE(stats.typing_noise_detected);
+}
+} // namespace test
} // namespace webrtc
diff --git a/webrtc/audio/conversion.h b/webrtc/audio/conversion.h
index c1cf9b6..6ae3243 100644
--- a/webrtc/audio/conversion.h
+++ b/webrtc/audio/conversion.h
@@ -13,8 +13,13 @@
namespace webrtc {
+// Convert fixed point number with 8 bit fractional part, to floating point.
+inline float Q8ToFloat(uint32_t v) {
+ return static_cast<float>(v) / (1 << 8);
+}
+
// Convert fixed point number with 14 bit fractional part, to floating point.
-inline float Q14ToFloat(uint16_t v) {
+inline float Q14ToFloat(uint32_t v) {
return static_cast<float>(v) / (1 << 14);
}
} // namespace webrtc
diff --git a/webrtc/audio_send_stream.h b/webrtc/audio_send_stream.h
index b96a8ef..89b73e6 100644
--- a/webrtc/audio_send_stream.h
+++ b/webrtc/audio_send_stream.h
@@ -25,7 +25,25 @@
class AudioSendStream : public SendStream {
public:
- struct Stats {};
+ struct Stats {
+ // TODO(solenberg): Harmonize naming and defaults with receive stream stats.
+ uint32_t local_ssrc = 0;
+ int64_t bytes_sent = 0;
+ int32_t packets_sent = 0;
+ int32_t packets_lost = -1;
+ float fraction_lost = -1.0f;
+ std::string codec_name;
+ int32_t ext_seqnum = -1;
+ int32_t jitter_ms = -1;
+ int64_t rtt_ms = -1;
+ int32_t audio_level = -1;
+ float aec_quality_min = -1.0f;
+ int32_t echo_delay_median_ms = -1;
+ int32_t echo_delay_std_ms = -1;
+ int32_t echo_return_loss = -100;
+ int32_t echo_return_loss_enhancement = -100;
+ bool typing_noise_detected = false;
+ };
struct Config {
Config() = delete;
diff --git a/webrtc/call/call.cc b/webrtc/call/call.cc
index cdb4f5d..eda209a 100644
--- a/webrtc/call/call.cc
+++ b/webrtc/call/call.cc
@@ -145,7 +145,6 @@
network_enabled_(true),
receive_crit_(RWLockWrapper::CreateRWLock()),
send_crit_(RWLockWrapper::CreateRWLock()) {
- RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_GE(config.bitrate_config.min_bitrate_bps, 0);
RTC_DCHECK_GE(config.bitrate_config.start_bitrate_bps,
config.bitrate_config.min_bitrate_bps);
@@ -199,7 +198,8 @@
const webrtc::AudioSendStream::Config& config) {
TRACE_EVENT0("webrtc", "Call::CreateAudioSendStream");
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
- AudioSendStream* send_stream = new AudioSendStream(config);
+ AudioSendStream* send_stream =
+ new AudioSendStream(config, config_.voice_engine);
if (!network_enabled_)
send_stream->SignalNetworkState(kNetworkDown);
{
diff --git a/webrtc/test/fake_voice_engine.cc b/webrtc/test/fake_voice_engine.cc
new file mode 100644
index 0000000..1a32e08
--- /dev/null
+++ b/webrtc/test/fake_voice_engine.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/test/fake_voice_engine.h"
+
+namespace {
+
+webrtc::AudioDecodingCallStats MakeAudioDecodingCallStats() {
+ webrtc::AudioDecodingCallStats stats;
+ stats.calls_to_silence_generator = 234;
+ stats.calls_to_neteq = 567;
+ stats.decoded_normal = 890;
+ stats.decoded_plc = 123;
+ stats.decoded_cng = 456;
+ stats.decoded_plc_cng = 789;
+ return stats;
+}
+} // namespace
+
+namespace webrtc {
+namespace test {
+
+const int FakeVoiceEngine::kSendChannelId = 1;
+const int FakeVoiceEngine::kRecvChannelId = 2;
+const uint32_t FakeVoiceEngine::kSendSsrc = 665;
+const uint32_t FakeVoiceEngine::kRecvSsrc = 667;
+const int FakeVoiceEngine::kSendEchoDelayMedian = 254;
+const int FakeVoiceEngine::kSendEchoDelayStdDev = -3;
+const int FakeVoiceEngine::kSendEchoReturnLoss = -65;
+const int FakeVoiceEngine::kSendEchoReturnLossEnhancement = 101;
+const int FakeVoiceEngine::kRecvJitterBufferDelay = -7;
+const int FakeVoiceEngine::kRecvPlayoutBufferDelay = 302;
+const unsigned int FakeVoiceEngine::kSendSpeechInputLevel = 96;
+const unsigned int FakeVoiceEngine::kRecvSpeechOutputLevel = 99;
+
+const CallStatistics FakeVoiceEngine::kSendCallStats = {
+ 1345, 1678, 1901, 1234, 112, 13456, 17890, 1567, -1890, -1123
+};
+
+const CodecInst FakeVoiceEngine::kSendCodecInst = {
+ -121, "codec_name_send", 48000, -231, -451, -671
+};
+
+const ReportBlock FakeVoiceEngine::kSendReportBlock = {
+ 456, 780, 123, 567, 890, 132, 143, 13354
+};
+
+const CallStatistics FakeVoiceEngine::kRecvCallStats = {
+ 345, 678, 901, 234, -12, 3456, 7890, 567, 890, 123
+};
+
+const CodecInst FakeVoiceEngine::kRecvCodecInst = {
+ 123, "codec_name_recv", 96000, -187, -198, -103
+};
+
+const NetworkStatistics FakeVoiceEngine::kRecvNetworkStats = {
+ 123, 456, false, 0, 0, 789, 12, 345, 678, 901, -1, -1, -1, -1, -1, 0
+};
+
+const AudioDecodingCallStats FakeVoiceEngine::kRecvAudioDecodingCallStats =
+ MakeAudioDecodingCallStats();
+} // namespace test
+} // namespace webrtc
diff --git a/webrtc/test/fake_voice_engine.h b/webrtc/test/fake_voice_engine.h
index 72f6b27..8f08929 100644
--- a/webrtc/test/fake_voice_engine.h
+++ b/webrtc/test/fake_voice_engine.h
@@ -24,12 +24,25 @@
// able to get the various interfaces as usual, via T::GetInterface().
class FakeVoiceEngine final : public VoiceEngineImpl {
public:
- const int kSendChannelId = 1;
- const int kReceiveChannelId = 2;
-
- const int kRecvJitterBufferDelay = -7;
- const int kRecvPlayoutBufferDelay = 302;
- const unsigned int kRecvSpeechOutputLevel = 99;
+ static const int kSendChannelId;
+ static const int kRecvChannelId;
+ static const uint32_t kSendSsrc;
+ static const uint32_t kRecvSsrc;
+ static const int kSendEchoDelayMedian;
+ static const int kSendEchoDelayStdDev;
+ static const int kSendEchoReturnLoss;
+ static const int kSendEchoReturnLossEnhancement;
+ static const int kRecvJitterBufferDelay;
+ static const int kRecvPlayoutBufferDelay;
+ static const unsigned int kSendSpeechInputLevel;
+ static const unsigned int kRecvSpeechOutputLevel;
+ static const CallStatistics kSendCallStats;
+ static const CodecInst kSendCodecInst;
+ static const ReportBlock kSendReportBlock;
+ static const CallStatistics kRecvCallStats;
+ static const CodecInst kRecvCodecInst;
+ static const NetworkStatistics kRecvNetworkStats;
+ static const AudioDecodingCallStats kRecvAudioDecodingCallStats;
FakeVoiceEngine() : VoiceEngineImpl(new Config(), true) {
// Increase ref count so this object isn't automatically deleted whenever
@@ -42,39 +55,83 @@
--_ref_count;
}
- const CallStatistics& GetRecvCallStats() const {
- static const CallStatistics kStats = {
- 345, 678, 901, 234, -1, 0, 0, 567, 890, 123
- };
- return kStats;
+ // VoEAudioProcessing
+ int SetNsStatus(bool enable, NsModes mode = kNsUnchanged) override {
+ return -1;
}
-
- const CodecInst& GetRecvRecCodecInst() const {
- static const CodecInst kStats = {
- 123, "codec_name", 96000, -1, -1, -1
- };
- return kStats;
+ int GetNsStatus(bool& enabled, NsModes& mode) override { return -1; }
+ int SetAgcStatus(bool enable, AgcModes mode = kAgcUnchanged) override {
+ return -1;
}
-
- const NetworkStatistics& GetRecvNetworkStats() const {
- static const NetworkStatistics kStats = {
- 123, 456, false, 0, 0, 789, 12, 345, 678, 901, -1, -1, -1, -1, -1, 0
- };
- return kStats;
+ int GetAgcStatus(bool& enabled, AgcModes& mode) override { return -1; }
+ int SetAgcConfig(AgcConfig config) override { return -1; }
+ int GetAgcConfig(AgcConfig& config) override { return -1; }
+ int SetEcStatus(bool enable, EcModes mode = kEcUnchanged) override {
+ return -1;
}
-
- const AudioDecodingCallStats& GetRecvAudioDecodingCallStats() const {
- static AudioDecodingCallStats stats;
- if (stats.calls_to_silence_generator == 0) {
- stats.calls_to_silence_generator = 234;
- stats.calls_to_neteq = 567;
- stats.decoded_normal = 890;
- stats.decoded_plc = 123;
- stats.decoded_cng = 456;
- stats.decoded_plc_cng = 789;
- }
- return stats;
+ int GetEcStatus(bool& enabled, EcModes& mode) override { return -1; }
+ int EnableDriftCompensation(bool enable) override { return -1; }
+ bool DriftCompensationEnabled() override { return false; }
+ void SetDelayOffsetMs(int offset) override {}
+ int DelayOffsetMs() override { return -1; }
+ int SetAecmMode(AecmModes mode = kAecmSpeakerphone,
+ bool enableCNG = true) override { return -1; }
+ int GetAecmMode(AecmModes& mode, bool& enabledCNG) override { return -1; }
+ int EnableHighPassFilter(bool enable) override { return -1; }
+ bool IsHighPassFilterEnabled() override { return false; }
+ int SetRxNsStatus(int channel,
+ bool enable,
+ NsModes mode = kNsUnchanged) override { return -1; }
+ int GetRxNsStatus(int channel, bool& enabled, NsModes& mode) override {
+ return -1;
}
+ int SetRxAgcStatus(int channel,
+ bool enable,
+ AgcModes mode = kAgcUnchanged) override { return -1; }
+ int GetRxAgcStatus(int channel, bool& enabled, AgcModes& mode) override {
+ return -1;
+ }
+ int SetRxAgcConfig(int channel, AgcConfig config) override { return -1; }
+ int GetRxAgcConfig(int channel, AgcConfig& config) override { return -1; }
+ int RegisterRxVadObserver(int channel,
+ VoERxVadCallback& observer) override { return -1; }
+ int DeRegisterRxVadObserver(int channel) override { return -1; }
+ int VoiceActivityIndicator(int channel) override { return -1; }
+ int SetEcMetricsStatus(bool enable) override { return -1; }
+ int GetEcMetricsStatus(bool& enabled) override {
+ enabled = true;
+ return 0;
+ }
+ int GetEchoMetrics(int& ERL, int& ERLE, int& RERL, int& A_NLP) override {
+ ERL = kSendEchoReturnLoss;
+ ERLE = kSendEchoReturnLossEnhancement;
+ RERL = -123456789;
+ A_NLP = 123456789;
+ return 0;
+ }
+ int GetEcDelayMetrics(int& delay_median,
+ int& delay_std,
+ float& fraction_poor_delays) override {
+ delay_median = kSendEchoDelayMedian;
+ delay_std = kSendEchoDelayStdDev;
+ fraction_poor_delays = -12345.7890f;
+ return 0;
+ }
+ int StartDebugRecording(const char* fileNameUTF8) override { return -1; }
+ int StartDebugRecording(FILE* file_handle) override { return -1; }
+ int StopDebugRecording() override { return -1; }
+ int SetTypingDetectionStatus(bool enable) override { return -1; }
+ int GetTypingDetectionStatus(bool& enabled) override { return -1; }
+ int TimeSinceLastTyping(int& seconds) override { return -1; }
+ int SetTypingDetectionParameters(int timeWindow,
+ int costPerTyping,
+ int reportingThreshold,
+ int penaltyDecay,
+ int typeEventDelay = 0) override {
+ return -1;
+ }
+ void EnableStereoChannelSwapping(bool enable) override {}
+ bool IsStereoChannelSwappingEnabled() override { return false; }
// VoEBase
int RegisterVoiceEngineObserver(VoiceEngineObserver& observer) override {
@@ -105,11 +162,15 @@
int NumOfCodecs() override { return -1; }
int GetCodec(int index, CodecInst& codec) override { return -1; }
int SetSendCodec(int channel, const CodecInst& codec) override { return -1; }
- int GetSendCodec(int channel, CodecInst& codec) override { return -1; }
+ int GetSendCodec(int channel, CodecInst& codec) override {
+ EXPECT_EQ(channel, kSendChannelId);
+ codec = kSendCodecInst;
+ return 0;
+ }
int SetBitRate(int channel, int bitrate_bps) override { return -1; }
int GetRecCodec(int channel, CodecInst& codec) override {
- EXPECT_EQ(channel, kReceiveChannelId);
- codec = GetRecvRecCodecInst();
+ EXPECT_EQ(channel, kRecvChannelId);
+ codec = kRecvCodecInst;
return 0;
}
int SetRecPayloadType(int channel, const CodecInst& codec) override {
@@ -295,23 +356,27 @@
// VoENetEqStats
int GetNetworkStatistics(int channel, NetworkStatistics& stats) override {
- EXPECT_EQ(channel, kReceiveChannelId);
- stats = GetRecvNetworkStats();
+ EXPECT_EQ(channel, kRecvChannelId);
+ stats = kRecvNetworkStats;
return 0;
}
int GetDecodingCallStatistics(int channel,
AudioDecodingCallStats* stats) const override {
- EXPECT_EQ(channel, kReceiveChannelId);
+ EXPECT_EQ(channel, kRecvChannelId);
EXPECT_NE(nullptr, stats);
- *stats = GetRecvAudioDecodingCallStats();
+ *stats = kRecvAudioDecodingCallStats;
return 0;
}
// VoERTP_RTCP
int SetLocalSSRC(int channel, unsigned int ssrc) override { return -1; }
- int GetLocalSSRC(int channel, unsigned int& ssrc) override { return -1; }
+ int GetLocalSSRC(int channel, unsigned int& ssrc) override {
+ EXPECT_EQ(channel, kSendChannelId);
+ ssrc = 0;
+ return 0;
+ }
int GetRemoteSSRC(int channel, unsigned int& ssrc) override {
- EXPECT_EQ(channel, kReceiveChannelId);
+ EXPECT_EQ(channel, kRecvChannelId);
ssrc = 0;
return 0;
}
@@ -347,13 +412,28 @@
unsigned int& maxJitterMs,
unsigned int& discardedPackets) override { return -1; }
int GetRTCPStatistics(int channel, CallStatistics& stats) override {
- EXPECT_EQ(channel, kReceiveChannelId);
- stats = GetRecvCallStats();
+ if (channel == kSendChannelId) {
+ stats = kSendCallStats;
+ } else {
+ EXPECT_EQ(channel, kRecvChannelId);
+ stats = kRecvCallStats;
+ }
return 0;
}
int GetRemoteRTCPReportBlocks(
int channel,
- std::vector<ReportBlock>* receive_blocks) override { return -1; }
+ std::vector<ReportBlock>* receive_blocks) override {
+ EXPECT_EQ(channel, kSendChannelId);
+ EXPECT_NE(receive_blocks, nullptr);
+ EXPECT_EQ(receive_blocks->size(), 0u);
+ webrtc::ReportBlock block = kSendReportBlock;
+ receive_blocks->push_back(block); // Has wrong SSRC.
+ block.source_SSRC = kSendSsrc;
+ receive_blocks->push_back(block); // Correct block.
+ block.fraction_lost = 0;
+ receive_blocks->push_back(block); // Duplicate SSRC, bad fraction_lost.
+ return 0;
+ }
int SetNACKStatus(int channel, bool enable, int maxNoPackets) override {
return -1;
}
@@ -365,7 +445,7 @@
int GetDelayEstimate(int channel,
int* jitter_buffer_delay_ms,
int* playout_buffer_delay_ms) override {
- EXPECT_EQ(channel, kReceiveChannelId);
+ EXPECT_EQ(channel, kRecvChannelId);
*jitter_buffer_delay_ms = kRecvJitterBufferDelay;
*playout_buffer_delay_ms = kRecvPlayoutBufferDelay;
return 0;
@@ -395,10 +475,13 @@
int GetSpeechOutputLevel(int channel, unsigned int& level) override {
return -1;
}
- int GetSpeechInputLevelFullRange(unsigned int& level) override { return -1; }
+ int GetSpeechInputLevelFullRange(unsigned int& level) override {
+ level = kSendSpeechInputLevel;
+ return 0;
+ }
int GetSpeechOutputLevelFullRange(int channel,
unsigned int& level) override {
- EXPECT_EQ(channel, kReceiveChannelId);
+ EXPECT_EQ(channel, kRecvChannelId);
level = kRecvSpeechOutputLevel;
return 0;
}
diff --git a/webrtc/test/webrtc_test_common.gyp b/webrtc/test/webrtc_test_common.gyp
index 5076900..42fa1e7 100644
--- a/webrtc/test/webrtc_test_common.gyp
+++ b/webrtc/test/webrtc_test_common.gyp
@@ -30,6 +30,7 @@
'fake_encoder.h',
'fake_network_pipe.cc',
'fake_network_pipe.h',
+ 'fake_voice_engine.cc',
'fake_voice_engine.h',
'frame_generator_capturer.cc',
'frame_generator_capturer.h',