diff --git a/talk/media/webrtc/fakewebrtccall.cc b/talk/media/webrtc/fakewebrtccall.cc index 04deeb4c43..d86bfb553c 100644 --- a/talk/media/webrtc/fakewebrtccall.cc +++ b/talk/media/webrtc/fakewebrtccall.cc @@ -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) diff --git a/talk/media/webrtc/fakewebrtccall.h b/talk/media/webrtc/fakewebrtccall.h index 212c062b0b..88edc60d78 100644 --- a/talk/media/webrtc/fakewebrtccall.h +++ b/talk/media/webrtc/fakewebrtccall.h @@ -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_; diff --git a/talk/media/webrtc/fakewebrtcvoiceengine.h b/talk/media/webrtc/fakewebrtcvoiceengine.h index 9b913276a6..2405e07b5f 100644 --- a/talk/media/webrtc/fakewebrtcvoiceengine.h +++ b/talk/media/webrtc/fakewebrtcvoiceengine.h @@ -45,11 +45,6 @@ namespace cricket { -// Function returning stats will return these values -// for all values based on type. -const int kIntStatValue = 123; -const float kFractionLostStatValue = 0.5; - static const char kFakeDefaultDeviceName[] = "Fake Default"; static const int kFakeDefaultDeviceId = -1; static const char kFakeDeviceName[] = "Fake Device"; @@ -268,6 +263,8 @@ 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(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* 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* 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(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)); diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc index fd93535bea..1d12fbf2ff 100644 --- a/talk/media/webrtc/webrtcvoiceengine.cc +++ b/talk/media/webrtc/webrtcvoiceengine.cc @@ -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 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(block.fraction_lost) / 256; - // Convert samples to milliseconds. - if (codec.plfreq / 1000 > 0) { - sinfo.jitter_ms = block.interarrival_jitter / (codec.plfreq / 1000); - } - sinfo.packets_lost = block.cumulative_num_packets_lost; - sinfo.ext_seqnum = block.extended_highest_sequence_number; - break; - } - } - } - - // Local speech level. - unsigned int level = 0; - sinfo.audio_level = (engine()->voe()->volume()-> - GetSpeechInputLevelFullRange(level) != -1) ? level : -1; - - // TODO(xians): We are injecting the same APM logging to all the send - // channels here because there is no good way to know which send channel - // is using the APM. The correct fix is to allow the send channels to have - // their own APM so that we can feed the correct APM logging to different - // send channels. See issue crbug/264611 . - sinfo.echo_return_loss = echo_return_loss; - sinfo.echo_return_loss_enhancement = echo_return_loss_enhancement; - sinfo.echo_delay_median_ms = echo_delay_median_ms; - sinfo.echo_delay_std_ms = echo_delay_std_ms; - // TODO(ajm): Re-enable this metric once we have a reliable implementation. - sinfo.aec_quality_min = -1; + sinfo.add_ssrc(stats.local_ssrc); + sinfo.bytes_sent = stats.bytes_sent; + sinfo.packets_sent = stats.packets_sent; + sinfo.packets_lost = stats.packets_lost; + sinfo.fraction_lost = stats.fraction_lost; + sinfo.codec_name = stats.codec_name; + sinfo.ext_seqnum = stats.ext_seqnum; + sinfo.jitter_ms = stats.jitter_ms; + sinfo.rtt_ms = stats.rtt_ms; + sinfo.audio_level = stats.audio_level; + sinfo.aec_quality_min = stats.aec_quality_min; + sinfo.echo_delay_median_ms = stats.echo_delay_median_ms; + sinfo.echo_delay_std_ms = stats.echo_delay_std_ms; + sinfo.echo_return_loss = stats.echo_return_loss; + sinfo.echo_return_loss_enhancement = stats.echo_return_loss_enhancement; sinfo.typing_noise_detected = typing_noise_detected_; - + // TODO(solenberg): Move to AudioSendStream. + // sinfo.typing_noise_detected = stats.typing_noise_detected; info->senders.push_back(sinfo); } - // Get the SSRC and stats for each receiver. - info->receivers.clear(); + // Get SSRC and stats for each receiver. + RTC_DCHECK(info->receivers.size() == 0); for (const auto& stream : receive_streams_) { webrtc::AudioReceiveStream::Stats stats = stream.second->GetStats(); VoiceReceiverInfo rinfo; diff --git a/talk/media/webrtc/webrtcvoiceengine_unittest.cc b/talk/media/webrtc/webrtcvoiceengine_unittest.cc index 4491929784..ce5115cb10 100644 --- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc +++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc @@ -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(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(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(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(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(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()); diff --git a/webrtc/audio/audio_receive_stream.cc b/webrtc/audio/audio_receive_stream.cc index 0fd96d01cc..b3cacba430 100644 --- a/webrtc/audio/audio_receive_stream.cc +++ b/webrtc/audio/audio_receive_stream.cc @@ -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 sync(voice_engine_); ScopedVoEInterface 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(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; } diff --git a/webrtc/audio/audio_receive_stream.h b/webrtc/audio/audio_receive_stream.h index 5c77653a75..5d02b0e2ae 100644 --- a/webrtc/audio/audio_receive_stream.h +++ b/webrtc/audio/audio_receive_stream.h @@ -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 voe_base_; rtc::scoped_ptr 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 8809b35b8d..4e267f1738 100644 --- a/webrtc/audio/audio_receive_stream_unittest.cc +++ b/webrtc/audio/audio_receive_stream_unittest.cc @@ -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(call_stats.bytesReceived), stats.bytes_rcvd); EXPECT_EQ(static_cast(call_stats.packetsReceived), stats.packets_rcvd); EXPECT_EQ(call_stats.cumulativeLost, stats.packets_lost); - EXPECT_EQ(static_cast(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(voice_engine.kRecvJitterBufferDelay + - voice_engine.kRecvPlayoutBufferDelay), stats.delay_estimate_ms); - EXPECT_EQ(static_cast(voice_engine.kRecvSpeechOutputLevel), + EXPECT_EQ(static_cast(FakeVoiceEngine::kRecvJitterBufferDelay + + FakeVoiceEngine::kRecvPlayoutBufferDelay), stats.delay_estimate_ms); + EXPECT_EQ(static_cast(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 0d0c072bf4..ccfdca546d 100644 --- a/webrtc/audio/audio_send_stream.cc +++ b/webrtc/audio/audio_send_stream.cc @@ -12,8 +12,13 @@ #include +#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 processing(voice_engine_); + ScopedVoEInterface codec(voice_engine_); + ScopedVoEInterface rtp(voice_engine_); + ScopedVoEInterface 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 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(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 54046fcea9..ae81dfc8fc 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 @@ 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 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 e5d73ff0f2..227ec83799 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 @@ 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(call_stats.bytesSent), stats.bytes_sent); + EXPECT_EQ(call_stats.packetsSent, stats.packets_sent); + EXPECT_EQ(static_cast(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(report_block.extended_highest_sequence_number), + stats.ext_seqnum); + EXPECT_EQ(static_cast(report_block.interarrival_jitter / + (codec_inst.plfreq / 1000)), stats.jitter_ms); + EXPECT_EQ(call_stats.rttMs, stats.rtt_ms); + EXPECT_EQ(static_cast(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 c1cf9b632e..6ae32432d3 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(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(v) / (1 << 14); } } // namespace webrtc diff --git a/webrtc/audio_send_stream.h b/webrtc/audio_send_stream.h index b96a8ef988..89b73e6e3e 100644 --- a/webrtc/audio_send_stream.h +++ b/webrtc/audio_send_stream.h @@ -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; diff --git a/webrtc/call/call.cc b/webrtc/call/call.cc index cdb4f5d1a6..eda209a01e 100644 --- a/webrtc/call/call.cc +++ b/webrtc/call/call.cc @@ -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); { diff --git a/webrtc/test/fake_voice_engine.cc b/webrtc/test/fake_voice_engine.cc new file mode 100644 index 0000000000..1a32e082b7 --- /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 72f6b27dd2..8f08929720 100644 --- a/webrtc/test/fake_voice_engine.h +++ b/webrtc/test/fake_voice_engine.h @@ -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* receive_blocks) override { return -1; } + std::vector* 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; } diff --git a/webrtc/test/webrtc_test_common.gyp b/webrtc/test/webrtc_test_common.gyp index 5076900f94..42fa1e707e 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',