Implement AudioSendStream::GetStats().

BUG=webrtc:4690

Review URL: https://codereview.webrtc.org/1414743004

Cr-Commit-Position: refs/heads/master@{#10424}
This commit is contained in:
solenberg 2015-10-27 03:35:21 -07:00 committed by Commit bot
parent 2a0a2a410f
commit 85a0496b8c
17 changed files with 712 additions and 410 deletions

View File

@ -39,8 +39,9 @@ FakeAudioSendStream::FakeAudioSendStream(
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 @@ const webrtc::AudioSendStream::Config&
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 @@ void FakeAudioReceiveStream::IncrementReceivedPackets() {
received_packets_++;
}
webrtc::AudioReceiveStream::Stats FakeAudioReceiveStream::GetStats() const {
return stats_;
}
FakeVideoSendStream::FakeVideoSendStream(
const webrtc::VideoSendStream::Config& config,
const webrtc::VideoEncoderConfig& encoder_config)

View File

@ -53,10 +53,8 @@ class FakeAudioSendStream : public webrtc::AudioSendStream {
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 @@ class FakeAudioSendStream : public webrtc::AudioSendStream {
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 @@ class FakeAudioReceiveStream : public webrtc::AudioReceiveStream {
}
// 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_;

View File

@ -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 @@ class FakeWebRtcVoiceEngine
}
}
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 @@ class FakeWebRtcVoiceEngine
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 @@ class FakeWebRtcVoiceEngine
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 @@ class FakeWebRtcVoiceEngine
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 @@ class FakeWebRtcVoiceEngine
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));

View File

@ -1321,7 +1321,11 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
: 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 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
RTC_DCHECK(stream_);
}
~WebRtcAudioSendStream() override {
RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
Stop();
call_->DestroyAudioSendStream(stream_);
}
@ -1338,7 +1343,7 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
// 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 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
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 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
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 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
// 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 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
// goes away.
AudioRenderer* renderer_ = nullptr;
// Protects |renderer_| in Start(), Stop() and OnClose().
rtc::CriticalSection lock_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioSendStream);
};
@ -1433,7 +1446,6 @@ WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel(WebRtcVoiceEngine* engine,
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::SetSendBitrateInternal(int bps) {
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;

View File

@ -57,9 +57,9 @@ const cricket::AudioCodec* const kAudioCodecs[] = {
&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 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
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 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
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 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
}
}
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 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStatsWithMultipleSendStreams) {
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 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStatsWithMultipleSendStreams) {
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 @@ TEST_F(WebRtcVoiceEngineTestFake, TraceFilterViaTraceOptions) {
// 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 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
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 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrcAfterCreatingReceiveChannel) {
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 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) {
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 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) {
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 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) {
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 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) {
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 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) {
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 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) {
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 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) {
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 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) {
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 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) {
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 @@ TEST_F(WebRtcVoiceEngineTestFake, DefaultOptions) {
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 @@ TEST_F(WebRtcVoiceEngineTestFake, DefaultOptions) {
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 @@ TEST_F(WebRtcVoiceEngineTestFake, CanChangeCombinedBweOption) {
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 @@ TEST_F(WebRtcVoiceEngineTestFake, CanChangeCombinedBweOption) {
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());

View File

@ -28,6 +28,7 @@ namespace webrtc {
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::Rtp::ToString() const {
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 @@ AudioReceiveStream::AudioReceiveStream(
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 @@ webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const {
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 @@ webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const {
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;
}

View File

@ -24,7 +24,7 @@ class VoiceEngine;
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 @@ class AudioReceiveStream : public webrtc::AudioReceiveStream {
// 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

View File

@ -61,12 +61,36 @@ size_t CreateRtpHeaderWithAbsSendTime(uint8_t* header,
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, AudioPacketUpdatesBweWithTimestamp) {
}
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),

View File

@ -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 @@ std::string AudioSendStream::Config::Rtp::ToString() const {
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 @@ std::string AudioSendStream::Config::ToString() const {
}
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

View File

@ -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 @@ class AudioSendStream : public webrtc::AudioSendStream {
// 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

View File

@ -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 @@ TEST(AudioSendStreamTest, ConfigToString) {
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

View File

@ -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

View File

@ -25,7 +25,25 @@ namespace webrtc {
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;

View File

@ -145,7 +145,6 @@ Call::Call(const Call::Config& config)
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 @@ webrtc::AudioSendStream* Call::CreateAudioSendStream(
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);
{

View File

@ -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

View File

@ -24,12 +24,25 @@ namespace test {
// 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 @@ class FakeVoiceEngine final : public VoiceEngineImpl {
--_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 @@ class FakeVoiceEngine final : public VoiceEngineImpl {
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 @@ class FakeVoiceEngine final : public VoiceEngineImpl {
// 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 @@ class FakeVoiceEngine final : public VoiceEngineImpl {
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 @@ class FakeVoiceEngine final : public VoiceEngineImpl {
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 @@ class FakeVoiceEngine final : public VoiceEngineImpl {
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;
}

View File

@ -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',