Implement AudioSendStream::GetStats().
BUG=webrtc:4690
Review URL: https://codereview.webrtc.org/1414743004
Cr-Commit-Position: refs/heads/master@{#10424}
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',