From 4f4ec0a9270a8cefadfa12e9fa3b979b58b15392 Mon Sep 17 00:00:00 2001 From: Fredrik Solenberg Date: Thu, 22 Oct 2015 10:49:27 +0200 Subject: [PATCH] Re-Land: Implement AudioReceiveStream::GetStats(). R=tommi@webrtc.org BUG=webrtc:4690 Committed: https://chromium.googlesource.com/external/webrtc/+/a457752f4afc496ed7f4d6b584b08d8635f18cc0 Review URL: https://codereview.webrtc.org/1390753002 . Cr-Commit-Position: refs/heads/master@{#10369} --- talk/media/webrtc/fakewebrtccall.cc | 9 +- talk/media/webrtc/fakewebrtccall.h | 11 +- talk/media/webrtc/fakewebrtcvoiceengine.h | 70 +-- talk/media/webrtc/webrtcvoe.h | 16 +- talk/media/webrtc/webrtcvoiceengine.cc | 109 ++--- .../webrtc/webrtcvoiceengine_unittest.cc | 158 ++++--- webrtc/audio/BUILD.gn | 2 + webrtc/audio/audio_receive_stream.cc | 106 ++++- webrtc/audio/audio_receive_stream.h | 11 +- webrtc/audio/audio_receive_stream_unittest.cc | 80 +++- webrtc/audio/conversion.h | 22 + webrtc/audio/scoped_voe_interface.h | 45 ++ webrtc/audio/webrtc_audio.gypi | 2 + webrtc/audio_receive_stream.h | 27 +- webrtc/call/bitrate_estimator_tests.cc | 8 +- webrtc/call/call.cc | 22 +- webrtc/call/call_perf_tests.cc | 2 + webrtc/call/call_unittest.cc | 6 +- webrtc/test/call_test.cc | 5 + webrtc/test/call_test.h | 1 + webrtc/test/fake_voice_engine.h | 421 ++++++++++++++++++ webrtc/test/webrtc_test_common.gyp | 1 + webrtc/voice_engine/voice_engine_impl.h | 5 +- 23 files changed, 887 insertions(+), 252 deletions(-) create mode 100644 webrtc/audio/conversion.h create mode 100644 webrtc/audio/scoped_voe_interface.h create mode 100644 webrtc/test/fake_voice_engine.h diff --git a/talk/media/webrtc/fakewebrtccall.cc b/talk/media/webrtc/fakewebrtccall.cc index 6e2a88fce2..04deeb4c43 100644 --- a/talk/media/webrtc/fakewebrtccall.cc +++ b/talk/media/webrtc/fakewebrtccall.cc @@ -54,15 +54,16 @@ FakeAudioReceiveStream::FakeAudioReceiveStream( RTC_DCHECK(config.voe_channel_id != -1); } -webrtc::AudioReceiveStream::Stats FakeAudioReceiveStream::GetStats() const { - return webrtc::AudioReceiveStream::Stats(); -} - const webrtc::AudioReceiveStream::Config& FakeAudioReceiveStream::GetConfig() const { return config_; } +void FakeAudioReceiveStream::SetStats( + const webrtc::AudioReceiveStream::Stats& stats) { + stats_ = stats; +} + void FakeAudioReceiveStream::IncrementReceivedPackets() { received_packets_++; } diff --git a/talk/media/webrtc/fakewebrtccall.h b/talk/media/webrtc/fakewebrtccall.h index de56a033bc..212c062b0b 100644 --- a/talk/media/webrtc/fakewebrtccall.h +++ b/talk/media/webrtc/fakewebrtccall.h @@ -75,11 +75,8 @@ class FakeAudioReceiveStream : public webrtc::AudioReceiveStream { explicit FakeAudioReceiveStream( const webrtc::AudioReceiveStream::Config& config); - // webrtc::AudioReceiveStream implementation. - webrtc::AudioReceiveStream::Stats GetStats() const override; - const webrtc::AudioReceiveStream::Config& GetConfig() const; - + void SetStats(const webrtc::AudioReceiveStream::Stats& stats); int received_packets() const { return received_packets_; } void IncrementReceivedPackets(); @@ -97,7 +94,13 @@ class FakeAudioReceiveStream : public webrtc::AudioReceiveStream { return true; } + // webrtc::AudioReceiveStream implementation. + webrtc::AudioReceiveStream::Stats GetStats() const override { + return stats_; + } + webrtc::AudioReceiveStream::Config config_; + webrtc::AudioReceiveStream::Stats stats_; int received_packets_; }; diff --git a/talk/media/webrtc/fakewebrtcvoiceengine.h b/talk/media/webrtc/fakewebrtcvoiceengine.h index 1167b6b983..9b913276a6 100644 --- a/talk/media/webrtc/fakewebrtcvoiceengine.h +++ b/talk/media/webrtc/fakewebrtcvoiceengine.h @@ -65,25 +65,6 @@ static const int kOpusBandwidthWb = 8000; static const int kOpusBandwidthSwb = 12000; static const int kOpusBandwidthFb = 20000; -static const webrtc::NetworkStatistics kNetStats = { - 1, // uint16_t currentBufferSize; - 2, // uint16_t preferredBufferSize; - true, // bool jitterPeaksFound; - 1234, // uint16_t currentPacketLossRate; - 567, // uint16_t currentDiscardRate; - 8901, // uint16_t currentExpandRate; - 234, // uint16_t currentSpeechExpandRate; - 5678, // uint16_t currentPreemptiveRate; - 9012, // uint16_t currentAccelerateRate; - 3456, // uint16_t currentSecondaryDecodedRate; - 7890, // int32_t clockDriftPPM; - 54, // meanWaitingTimeMs; - 32, // int medianWaitingTimeMs; - 1, // int minWaitingTimeMs; - 98, // int maxWaitingTimeMs; - 7654, // int addedSamples; -}; // These random but non-trivial numbers are used for testing. - #define WEBRTC_CHECK_CHANNEL(channel) \ if (channels_.find(channel) == channels_.end()) return -1; @@ -181,9 +162,9 @@ class FakeAudioProcessing : public webrtc::AudioProcessing { class FakeWebRtcVoiceEngine : public webrtc::VoEAudioProcessing, public webrtc::VoEBase, public webrtc::VoECodec, public webrtc::VoEDtmf, - public webrtc::VoEHardware, public webrtc::VoENetEqStats, + public webrtc::VoEHardware, public webrtc::VoENetwork, public webrtc::VoERTP_RTCP, - public webrtc::VoEVideoSync, public webrtc::VoEVolumeControl { + public webrtc::VoEVolumeControl { public: struct DtmfInfo { DtmfInfo() @@ -527,26 +508,7 @@ class FakeWebRtcVoiceEngine return 0; } WEBRTC_STUB(SetBitRate, (int channel, int bitrate_bps)); - WEBRTC_FUNC(GetRecCodec, (int channel, webrtc::CodecInst& codec)) { - WEBRTC_CHECK_CHANNEL(channel); - const Channel* c = channels_[channel]; - for (std::list::const_iterator it_packet = c->packets.begin(); - it_packet != c->packets.end(); ++it_packet) { - int pltype; - if (!GetRtpPayloadType(it_packet->data(), it_packet->length(), &pltype)) { - continue; - } - for (std::vector::const_iterator it_codec = - c->recv_codecs.begin(); it_codec != c->recv_codecs.end(); - ++it_codec) { - if (it_codec->pltype == pltype) { - codec = *it_codec; - return 0; - } - } - } - return -1; - } + WEBRTC_STUB(GetRecCodec, (int channel, webrtc::CodecInst& codec)); WEBRTC_FUNC(SetRecPayloadType, (int channel, const webrtc::CodecInst& codec)) { WEBRTC_CHECK_CHANNEL(channel); @@ -725,20 +687,6 @@ class FakeWebRtcVoiceEngine WEBRTC_STUB(EnableBuiltInNS, (bool enable)); virtual bool BuiltInNSIsAvailable() const { return false; } - // webrtc::VoENetEqStats - WEBRTC_FUNC(GetNetworkStatistics, (int channel, - webrtc::NetworkStatistics& ns)) { - WEBRTC_CHECK_CHANNEL(channel); - memcpy(&ns, &kNetStats, sizeof(webrtc::NetworkStatistics)); - return 0; - } - - WEBRTC_FUNC_CONST(GetDecodingCallStatistics, (int channel, - webrtc::AudioDecodingCallStats*)) { - WEBRTC_CHECK_CHANNEL(channel); - return 0; - } - // webrtc::VoENetwork WEBRTC_FUNC(RegisterExternalTransport, (int channel, webrtc::Transport& transport)) { @@ -887,18 +835,6 @@ class FakeWebRtcVoiceEngine return 0; } - // webrtc::VoEVideoSync - WEBRTC_STUB(GetPlayoutBufferSize, (int& bufferMs)); - WEBRTC_STUB(GetPlayoutTimestamp, (int channel, unsigned int& timestamp)); - WEBRTC_STUB(GetRtpRtcp, (int, webrtc::RtpRtcp**, webrtc::RtpReceiver**)); - WEBRTC_STUB(SetInitTimestamp, (int channel, unsigned int timestamp)); - WEBRTC_STUB(SetInitSequenceNumber, (int channel, short sequenceNumber)); - WEBRTC_STUB(SetMinimumPlayoutDelay, (int channel, int delayMs)); - WEBRTC_STUB(SetInitialPlayoutDelay, (int channel, int delay_ms)); - WEBRTC_STUB(GetDelayEstimate, (int channel, int* jitter_buffer_delay_ms, - int* playout_buffer_delay_ms)); - WEBRTC_STUB_CONST(GetLeastRequiredDelayMs, (int channel)); - // webrtc::VoEVolumeControl WEBRTC_STUB(SetSpeakerVolume, (unsigned int)); WEBRTC_STUB(GetSpeakerVolume, (unsigned int&)); diff --git a/talk/media/webrtc/webrtcvoe.h b/talk/media/webrtc/webrtcvoe.h index 844831feb9..db6a64a1fe 100644 --- a/talk/media/webrtc/webrtcvoe.h +++ b/talk/media/webrtc/webrtcvoe.h @@ -38,13 +38,9 @@ #include "webrtc/voice_engine/include/voe_codec.h" #include "webrtc/voice_engine/include/voe_dtmf.h" #include "webrtc/voice_engine/include/voe_errors.h" -#include "webrtc/voice_engine/include/voe_external_media.h" -#include "webrtc/voice_engine/include/voe_file.h" #include "webrtc/voice_engine/include/voe_hardware.h" -#include "webrtc/voice_engine/include/voe_neteq_stats.h" #include "webrtc/voice_engine/include/voe_network.h" #include "webrtc/voice_engine/include/voe_rtp_rtcp.h" -#include "webrtc/voice_engine/include/voe_video_sync.h" #include "webrtc/voice_engine/include/voe_volume_control.h" namespace cricket { @@ -96,18 +92,16 @@ class VoEWrapper { VoEWrapper() : engine_(webrtc::VoiceEngine::Create()), processing_(engine_), base_(engine_), codec_(engine_), dtmf_(engine_), - hw_(engine_), neteq_(engine_), network_(engine_), - rtp_(engine_), sync_(engine_), volume_(engine_) { + hw_(engine_), network_(engine_), + rtp_(engine_), volume_(engine_) { } VoEWrapper(webrtc::VoEAudioProcessing* processing, webrtc::VoEBase* base, webrtc::VoECodec* codec, webrtc::VoEDtmf* dtmf, webrtc::VoEHardware* hw, - webrtc::VoENetEqStats* neteq, webrtc::VoENetwork* network, webrtc::VoERTP_RTCP* rtp, - webrtc::VoEVideoSync* sync, webrtc::VoEVolumeControl* volume) : engine_(NULL), processing_(processing), @@ -115,10 +109,8 @@ class VoEWrapper { codec_(codec), dtmf_(dtmf), hw_(hw), - neteq_(neteq), network_(network), rtp_(rtp), - sync_(sync), volume_(volume) { } ~VoEWrapper() {} @@ -128,10 +120,8 @@ class VoEWrapper { webrtc::VoECodec* codec() const { return codec_.get(); } webrtc::VoEDtmf* dtmf() const { return dtmf_.get(); } webrtc::VoEHardware* hw() const { return hw_.get(); } - webrtc::VoENetEqStats* neteq() const { return neteq_.get(); } webrtc::VoENetwork* network() const { return network_.get(); } webrtc::VoERTP_RTCP* rtp() const { return rtp_.get(); } - webrtc::VoEVideoSync* sync() const { return sync_.get(); } webrtc::VoEVolumeControl* volume() const { return volume_.get(); } int error() { return base_->LastError(); } @@ -142,10 +132,8 @@ class VoEWrapper { scoped_voe_ptr codec_; scoped_voe_ptr dtmf_; scoped_voe_ptr hw_; - scoped_voe_ptr neteq_; scoped_voe_ptr network_; scoped_voe_ptr rtp_; - scoped_voe_ptr sync_; scoped_voe_ptr volume_; }; diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc index eed1195975..fd93535bea 100644 --- a/talk/media/webrtc/webrtcvoiceengine.cc +++ b/talk/media/webrtc/webrtcvoiceengine.cc @@ -2649,11 +2649,6 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { } } - webrtc::CallStatistics cs; - unsigned int ssrc; - webrtc::CodecInst codec; - unsigned int level; - for (const auto& ch : send_streams_) { const int channel = ch.second->channel(); @@ -2661,6 +2656,8 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { // remote side told us it got from its RTCP report. 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; @@ -2681,6 +2678,7 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { 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) { @@ -2701,6 +2699,7 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { } // Local speech level. + unsigned int level = 0; sinfo.audio_level = (engine()->voe()->volume()-> GetSpeechInputLevelFullRange(level) != -1) ? level : -1; @@ -2721,76 +2720,36 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { } // Get the SSRC and stats for each receiver. - for (const auto& ch : receive_channels_) { - int ch_id = ch.second->channel(); - memset(&cs, 0, sizeof(cs)); - if (engine()->voe()->rtp()->GetRemoteSSRC(ch_id, ssrc) != -1 && - engine()->voe()->rtp()->GetRTCPStatistics(ch_id, cs) != -1 && - engine()->voe()->codec()->GetRecCodec(ch_id, codec) != -1) { - VoiceReceiverInfo rinfo; - rinfo.add_ssrc(ssrc); - rinfo.bytes_rcvd = cs.bytesReceived; - rinfo.packets_rcvd = cs.packetsReceived; - // The next four fields are from the most recently sent RTCP report. - // Convert Q8 to floating point. - rinfo.fraction_lost = static_cast(cs.fractionLost) / (1 << 8); - rinfo.packets_lost = cs.cumulativeLost; - rinfo.ext_seqnum = cs.extendedMax; - rinfo.capture_start_ntp_time_ms = cs.capture_start_ntp_time_ms_; - if (codec.pltype != -1) { - rinfo.codec_name = codec.plname; - } - // Convert samples to milliseconds. - if (codec.plfreq / 1000 > 0) { - rinfo.jitter_ms = cs.jitterSamples / (codec.plfreq / 1000); - } - - // Get jitter buffer and total delay (alg + jitter + playout) stats. - webrtc::NetworkStatistics ns; - if (engine()->voe()->neteq() && - engine()->voe()->neteq()->GetNetworkStatistics( - ch_id, ns) != -1) { - rinfo.jitter_buffer_ms = ns.currentBufferSize; - rinfo.jitter_buffer_preferred_ms = ns.preferredBufferSize; - rinfo.expand_rate = - static_cast(ns.currentExpandRate) / (1 << 14); - rinfo.speech_expand_rate = - static_cast(ns.currentSpeechExpandRate) / (1 << 14); - rinfo.secondary_decoded_rate = - static_cast(ns.currentSecondaryDecodedRate) / (1 << 14); - rinfo.accelerate_rate = - static_cast(ns.currentAccelerateRate) / (1 << 14); - rinfo.preemptive_expand_rate = - static_cast(ns.currentPreemptiveRate) / (1 << 14); - } - - webrtc::AudioDecodingCallStats ds; - if (engine()->voe()->neteq() && - engine()->voe()->neteq()->GetDecodingCallStatistics( - ch_id, &ds) != -1) { - rinfo.decoding_calls_to_silence_generator = - ds.calls_to_silence_generator; - rinfo.decoding_calls_to_neteq = ds.calls_to_neteq; - rinfo.decoding_normal = ds.decoded_normal; - rinfo.decoding_plc = ds.decoded_plc; - rinfo.decoding_cng = ds.decoded_cng; - rinfo.decoding_plc_cng = ds.decoded_plc_cng; - } - - if (engine()->voe()->sync()) { - int jitter_buffer_delay_ms = 0; - int playout_buffer_delay_ms = 0; - engine()->voe()->sync()->GetDelayEstimate( - ch_id, &jitter_buffer_delay_ms, &playout_buffer_delay_ms); - rinfo.delay_estimate_ms = jitter_buffer_delay_ms + - playout_buffer_delay_ms; - } - - // Get speech level. - rinfo.audio_level = (engine()->voe()->volume()-> - GetSpeechOutputLevelFullRange(ch_id, level) != -1) ? level : -1; - info->receivers.push_back(rinfo); - } + info->receivers.clear(); + for (const auto& stream : receive_streams_) { + webrtc::AudioReceiveStream::Stats stats = stream.second->GetStats(); + VoiceReceiverInfo rinfo; + rinfo.add_ssrc(stats.remote_ssrc); + rinfo.bytes_rcvd = stats.bytes_rcvd; + rinfo.packets_rcvd = stats.packets_rcvd; + rinfo.packets_lost = stats.packets_lost; + rinfo.fraction_lost = stats.fraction_lost; + rinfo.codec_name = stats.codec_name; + rinfo.ext_seqnum = stats.ext_seqnum; + rinfo.jitter_ms = stats.jitter_ms; + rinfo.jitter_buffer_ms = stats.jitter_buffer_ms; + rinfo.jitter_buffer_preferred_ms = stats.jitter_buffer_preferred_ms; + rinfo.delay_estimate_ms = stats.delay_estimate_ms; + rinfo.audio_level = stats.audio_level; + rinfo.expand_rate = stats.expand_rate; + rinfo.speech_expand_rate = stats.speech_expand_rate; + rinfo.secondary_decoded_rate = stats.secondary_decoded_rate; + rinfo.accelerate_rate = stats.accelerate_rate; + rinfo.preemptive_expand_rate = stats.preemptive_expand_rate; + rinfo.decoding_calls_to_silence_generator = + stats.decoding_calls_to_silence_generator; + rinfo.decoding_calls_to_neteq = stats.decoding_calls_to_neteq; + rinfo.decoding_normal = stats.decoding_normal; + rinfo.decoding_plc = stats.decoding_plc; + rinfo.decoding_cng = stats.decoding_cng; + rinfo.decoding_plc_cng = stats.decoding_plc_cng; + rinfo.capture_start_ntp_time_ms = stats.capture_start_ntp_time_ms; + info->receivers.push_back(rinfo); } return true; diff --git a/talk/media/webrtc/webrtcvoiceengine_unittest.cc b/talk/media/webrtc/webrtcvoiceengine_unittest.cc index 477369e182..4491929784 100644 --- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc +++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc @@ -38,22 +38,22 @@ #include "webrtc/p2p/base/faketransportcontroller.h" #include "talk/session/media/channel.h" -// Tests for the WebRtcVoiceEngine/VoiceChannel code. - using cricket::kRtpAudioLevelHeaderExtension; using cricket::kRtpAbsoluteSenderTimeHeaderExtension; -static const cricket::AudioCodec kPcmuCodec(0, "PCMU", 8000, 64000, 1, 0); -static const cricket::AudioCodec kIsacCodec(103, "ISAC", 16000, 32000, 1, 0); -static const cricket::AudioCodec kOpusCodec(111, "opus", 48000, 64000, 2, 0); -static const cricket::AudioCodec kG722CodecVoE(9, "G722", 16000, 64000, 1, 0); -static const cricket::AudioCodec kG722CodecSdp(9, "G722", 8000, 64000, 1, 0); -static const cricket::AudioCodec kRedCodec(117, "red", 8000, 0, 1, 0); -static const cricket::AudioCodec kCn8000Codec(13, "CN", 8000, 0, 1, 0); -static const cricket::AudioCodec kCn16000Codec(105, "CN", 16000, 0, 1, 0); -static const cricket::AudioCodec - kTelephoneEventCodec(106, "telephone-event", 8000, 0, 1, 0); -static const cricket::AudioCodec* const kAudioCodecs[] = { +namespace { + +const cricket::AudioCodec kPcmuCodec(0, "PCMU", 8000, 64000, 1, 0); +const cricket::AudioCodec kIsacCodec(103, "ISAC", 16000, 32000, 1, 0); +const cricket::AudioCodec kOpusCodec(111, "opus", 48000, 64000, 2, 0); +const cricket::AudioCodec kG722CodecVoE(9, "G722", 16000, 64000, 1, 0); +const cricket::AudioCodec kG722CodecSdp(9, "G722", 8000, 64000, 1, 0); +const cricket::AudioCodec kRedCodec(117, "red", 8000, 0, 1, 0); +const cricket::AudioCodec kCn8000Codec(13, "CN", 8000, 0, 1, 0); +const cricket::AudioCodec kCn16000Codec(105, "CN", 16000, 0, 1, 0); +const cricket::AudioCodec kTelephoneEventCodec(106, "telephone-event", 8000, 0, + 1, 0); +const cricket::AudioCodec* const kAudioCodecs[] = { &kPcmuCodec, &kIsacCodec, &kOpusCodec, &kG722CodecVoE, &kRedCodec, &kCn8000Codec, &kCn16000Codec, &kTelephoneEventCodec, }; @@ -69,10 +69,8 @@ class FakeVoEWrapper : public cricket::VoEWrapper { engine, // codec engine, // dtmf engine, // hw - engine, // neteq engine, // network engine, // rtp - engine, // sync engine) { // volume } }; @@ -87,6 +85,7 @@ class FakeVoETraceWrapper : public cricket::VoETraceWrapper { int SetTraceCallback(webrtc::TraceCallback* callback) override { return 0; } unsigned int filter_; }; +} // namespace class WebRtcVoiceEngineTestFake : public testing::Test { public: @@ -291,6 +290,71 @@ 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; + } + return stats; + } + void SetAudioReceiveStreamStats() { + for (auto* s : call_.GetAudioReceiveStreams()) { + s->SetStats(GetAudioReceiveStreamStats()); + } + } + 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); + 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); + 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); + } + protected: cricket::FakeCall call_; cricket::FakeWebRtcVoiceEngine voe_; @@ -1990,38 +2054,23 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStatsWithMultipleSendStreams) { EXPECT_EQ(cricket::kIntStatValue, info.senders[i].jitter_ms); EXPECT_EQ(kPcmuCodec.name, info.senders[i].codec_name); } - EXPECT_EQ(0u, info.receivers.size()); - // Registered stream's remote SSRC is kSsrc2. Send a packet with SSRC=1. - // We should drop the packet and no stats should be available. - DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame)); + // 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()); - // Remove the kSsrc2 stream and deliver a new packet - a default receive - // stream should be created and we should see stats. - EXPECT_TRUE(channel_->RemoveRecvStream(kSsrc2)); + // 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()); - - EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].bytes_rcvd); - EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].packets_rcvd); - EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].packets_lost); - EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].ext_seqnum); - EXPECT_EQ(kPcmuCodec.name, info.receivers[0].codec_name); - EXPECT_EQ(static_cast(cricket::kNetStats.currentExpandRate) / - (1 << 14), info.receivers[0].expand_rate); - EXPECT_EQ(static_cast(cricket::kNetStats.currentSpeechExpandRate) / - (1 << 14), info.receivers[0].speech_expand_rate); - EXPECT_EQ(static_cast(cricket::kNetStats.currentSecondaryDecodedRate) / - (1 << 14), info.receivers[0].secondary_decoded_rate); - EXPECT_EQ( - static_cast(cricket::kNetStats.currentAccelerateRate) / (1 << 14), - info.receivers[0].accelerate_rate); - EXPECT_EQ( - static_cast(cricket::kNetStats.currentPreemptiveRate) / (1 << 14), - info.receivers[0].preemptive_expand_rate); + VerifyVoiceReceiverInfo(info.receivers[0]); } // Test that we can add and remove receive streams, and do proper send/playout. @@ -2282,33 +2331,22 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) { // EXPECT_EQ(cricket::kIntStatValue, info.senders[0].echo_return_loss); // EXPECT_EQ(cricket::kIntStatValue, // info.senders[0].echo_return_loss_enhancement); - EXPECT_EQ(0u, info.receivers.size()); + // 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); - // Registered stream's remote SSRC is kSsrc2. Send a packet with SSRC=1. - // We should drop the packet and no stats should be available. - DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame)); + // Remove the kSsrc2 stream. No receiver stats. + EXPECT_TRUE(channel_->RemoveRecvStream(kSsrc2)); EXPECT_EQ(true, channel_->GetStats(&info)); EXPECT_EQ(0u, info.receivers.size()); - // Remove the kSsrc2 stream and deliver a new packet - a default receive - // stream should be created and we should see stats. - EXPECT_TRUE(channel_->RemoveRecvStream(kSsrc2)); + // 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()); - - EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].bytes_rcvd); - EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].packets_rcvd); - EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].packets_lost); - EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].ext_seqnum); - EXPECT_EQ(kPcmuCodec.name, info.receivers[0].codec_name); - EXPECT_EQ(static_cast(cricket::kNetStats.currentExpandRate) / - (1 << 14), info.receivers[0].expand_rate); - EXPECT_EQ(static_cast(cricket::kNetStats.currentSpeechExpandRate) / - (1 << 14), info.receivers[0].speech_expand_rate); - EXPECT_EQ(static_cast(cricket::kNetStats.currentSecondaryDecodedRate) / - (1 << 14), info.receivers[0].secondary_decoded_rate); - // TODO(sriniv): Add testing for more receiver fields. + VerifyVoiceReceiverInfo(info.receivers[0]); } // Test that we can set the outgoing SSRC properly with multiple streams. diff --git a/webrtc/audio/BUILD.gn b/webrtc/audio/BUILD.gn index c6f4b6bde0..d5061db9dc 100644 --- a/webrtc/audio/BUILD.gn +++ b/webrtc/audio/BUILD.gn @@ -14,6 +14,8 @@ source_set("audio") { "audio_receive_stream.h", "audio_send_stream.cc", "audio_send_stream.h", + "conversion.h", + "scoped_voe_interface.h", ] configs += [ "..:common_config" ] diff --git a/webrtc/audio/audio_receive_stream.cc b/webrtc/audio/audio_receive_stream.cc index c725e37477..0fd96d01cc 100644 --- a/webrtc/audio/audio_receive_stream.cc +++ b/webrtc/audio/audio_receive_stream.cc @@ -12,10 +12,17 @@ #include +#include "webrtc/audio/conversion.h" #include "webrtc/base/checks.h" #include "webrtc/base/logging.h" #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" #include "webrtc/system_wrappers/interface/tick_util.h" +#include "webrtc/voice_engine/include/voe_base.h" +#include "webrtc/voice_engine/include/voe_codec.h" +#include "webrtc/voice_engine/include/voe_neteq_stats.h" +#include "webrtc/voice_engine/include/voe_rtp_rtcp.h" +#include "webrtc/voice_engine/include/voe_video_sync.h" +#include "webrtc/voice_engine/include/voe_volume_control.h" namespace webrtc { std::string AudioReceiveStream::Config::Rtp::ToString() const { @@ -24,8 +31,9 @@ std::string AudioReceiveStream::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 << '}'; @@ -36,8 +44,9 @@ std::string AudioReceiveStream::Config::ToString() const { std::stringstream ss; ss << "{rtp: " << rtp.ToString(); ss << ", voe_channel_id: " << voe_channel_id; - if (!sync_group.empty()) + if (!sync_group.empty()) { ss << ", sync_group: " << sync_group; + } ss << '}'; return ss.str(); } @@ -45,13 +54,18 @@ std::string AudioReceiveStream::Config::ToString() const { namespace internal { AudioReceiveStream::AudioReceiveStream( RemoteBitrateEstimator* remote_bitrate_estimator, - const webrtc::AudioReceiveStream::Config& config) + const webrtc::AudioReceiveStream::Config& config, + VoiceEngine* voice_engine) : remote_bitrate_estimator_(remote_bitrate_estimator), config_(config), + 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); + RTC_DCHECK(voice_engine_ != nullptr); RTC_DCHECK(rtp_header_parser_ != nullptr); for (const auto& ext : config.rtp.extensions) { // One-byte-extension local identifiers are in the range 1-14 inclusive. @@ -73,33 +87,117 @@ AudioReceiveStream::AudioReceiveStream( } AudioReceiveStream::~AudioReceiveStream() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); LOG(LS_INFO) << "~AudioReceiveStream: " << config_.ToString(); } webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const { - return webrtc::AudioReceiveStream::Stats(); + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + webrtc::AudioReceiveStream::Stats stats; + stats.remote_ssrc = config_.rtp.remote_ssrc; + ScopedVoEInterface codec(voice_engine_); + ScopedVoEInterface neteq(voice_engine_); + ScopedVoEInterface rtp(voice_engine_); + ScopedVoEInterface sync(voice_engine_); + ScopedVoEInterface volume(voice_engine_); + unsigned int ssrc = 0; + webrtc::CallStatistics cs = {0}; + webrtc::CodecInst ci = {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) { + 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.ext_seqnum = cs.extendedMax; + if (ci.plfreq / 1000 > 0) { + stats.jitter_ms = cs.jitterSamples / (ci.plfreq / 1000); + } + { + int jitter_buffer_delay_ms = 0; + int playout_buffer_delay_ms = 0; + sync->GetDelayEstimate(config_.voe_channel_id, &jitter_buffer_delay_ms, + &playout_buffer_delay_ms); + stats.delay_estimate_ms = + jitter_buffer_delay_ms + playout_buffer_delay_ms; + } + { + unsigned int level = 0; + if (volume->GetSpeechOutputLevelFullRange(config_.voe_channel_id, level) + != -1) { + stats.audio_level = static_cast(level); + } + } + + webrtc::NetworkStatistics ns = {0}; + if (neteq->GetNetworkStatistics(config_.voe_channel_id, ns) != -1) { + // Get jitter buffer and total delay (alg + jitter + playout) stats. + stats.jitter_buffer_ms = ns.currentBufferSize; + stats.jitter_buffer_preferred_ms = ns.preferredBufferSize; + stats.expand_rate = Q14ToFloat(ns.currentExpandRate); + stats.speech_expand_rate = Q14ToFloat(ns.currentSpeechExpandRate); + stats.secondary_decoded_rate = Q14ToFloat(ns.currentSecondaryDecodedRate); + stats.accelerate_rate = Q14ToFloat(ns.currentAccelerateRate); + stats.preemptive_expand_rate = Q14ToFloat(ns.currentPreemptiveRate); + } + + webrtc::AudioDecodingCallStats ds; + if (neteq->GetDecodingCallStatistics(config_.voe_channel_id, &ds) != -1) { + stats.decoding_calls_to_silence_generator = + ds.calls_to_silence_generator; + stats.decoding_calls_to_neteq = ds.calls_to_neteq; + stats.decoding_normal = ds.decoded_normal; + stats.decoding_plc = ds.decoded_plc; + stats.decoding_cng = ds.decoded_cng; + stats.decoding_plc_cng = ds.decoded_plc_cng; + } + + stats.capture_start_ntp_time_ms = cs.capture_start_ntp_time_ms_; + + return stats; } const webrtc::AudioReceiveStream::Config& AudioReceiveStream::config() const { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); return config_; } void AudioReceiveStream::Start() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); } void AudioReceiveStream::Stop() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); } void AudioReceiveStream::SignalNetworkState(NetworkState state) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); } bool AudioReceiveStream::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; } bool AudioReceiveStream::DeliverRtp(const uint8_t* packet, size_t length, const PacketTime& packet_time) { + // 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()); RTPHeader header; if (!rtp_header_parser_->Parse(packet, length, &header)) { diff --git a/webrtc/audio/audio_receive_stream.h b/webrtc/audio/audio_receive_stream.h index 1e52724020..5c77653a75 100644 --- a/webrtc/audio/audio_receive_stream.h +++ b/webrtc/audio/audio_receive_stream.h @@ -12,18 +12,23 @@ #define WEBRTC_AUDIO_AUDIO_RECEIVE_STREAM_H_ #include "webrtc/audio_receive_stream.h" +#include "webrtc/audio/scoped_voe_interface.h" +#include "webrtc/base/thread_checker.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" +#include "webrtc/voice_engine/include/voe_base.h" namespace webrtc { class RemoteBitrateEstimator; +class VoiceEngine; namespace internal { class AudioReceiveStream : public webrtc::AudioReceiveStream { public: AudioReceiveStream(RemoteBitrateEstimator* remote_bitrate_estimator, - const webrtc::AudioReceiveStream::Config& config); + const webrtc::AudioReceiveStream::Config& config, + VoiceEngine* voice_engine); ~AudioReceiveStream() override; // webrtc::ReceiveStream implementation. @@ -41,8 +46,12 @@ class AudioReceiveStream : public webrtc::AudioReceiveStream { const webrtc::AudioReceiveStream::Config& config() const; private: + rtc::ThreadChecker thread_checker_; RemoteBitrateEstimator* const remote_bitrate_estimator_; const webrtc::AudioReceiveStream::Config config_; + VoiceEngine* voice_engine_; + // We hold one interface pointer to the VoE to make sure it is kept alive. + ScopedVoEInterface voe_base_; rtc::scoped_ptr rtp_header_parser_; }; } // namespace internal diff --git a/webrtc/audio/audio_receive_stream_unittest.cc b/webrtc/audio/audio_receive_stream_unittest.cc index d6cce69dbf..8809b35b8d 100644 --- a/webrtc/audio/audio_receive_stream_unittest.cc +++ b/webrtc/audio/audio_receive_stream_unittest.cc @@ -11,10 +11,14 @@ #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/audio/audio_receive_stream.h" +#include "webrtc/audio/conversion.h" #include "webrtc/modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_estimator.h" #include "webrtc/modules/rtp_rtcp/source/byte_io.h" +#include "webrtc/test/fake_voice_engine.h" -namespace webrtc { +namespace { + +using webrtc::ByteWriter; const size_t kAbsoluteSendTimeLength = 4; @@ -45,33 +49,93 @@ size_t CreateRtpHeaderWithAbsSendTime(uint8_t* header, ByteWriter::WriteBigEndian(header + 2, 0x1234); // Sequence number. ByteWriter::WriteBigEndian(header + 4, 0x5678); // Timestamp. ByteWriter::WriteBigEndian(header + 8, 0x4321); // SSRC. - int32_t rtp_header_length = kRtpHeaderSize; + int32_t rtp_header_length = webrtc::kRtpHeaderSize; BuildAbsoluteSendTimeExtension(header + rtp_header_length, extension_id, abs_send_time); rtp_header_length += kAbsoluteSendTimeLength; return rtp_header_length; } +} // namespace + +namespace webrtc { +namespace test { TEST(AudioReceiveStreamTest, AudioPacketUpdatesBweWithTimestamp) { - MockRemoteBitrateEstimator rbe; + MockRemoteBitrateEstimator remote_bitrate_estimator; + FakeVoiceEngine voice_engine; AudioReceiveStream::Config config; config.combined_audio_video_bwe = true; - config.voe_channel_id = 1; + config.voe_channel_id = voice_engine.kReceiveChannelId; const int kAbsSendTimeId = 3; config.rtp.extensions.push_back( RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId)); - internal::AudioReceiveStream recv_stream(&rbe, config); + internal::AudioReceiveStream recv_stream(&remote_bitrate_estimator, config, + &voice_engine); uint8_t rtp_packet[30]; const int kAbsSendTimeValue = 1234; CreateRtpHeaderWithAbsSendTime(rtp_packet, kAbsSendTimeId, kAbsSendTimeValue); PacketTime packet_time(5678000, 0); const size_t kExpectedHeaderLength = 20; - EXPECT_CALL(rbe, IncomingPacket(packet_time.timestamp / 1000, - sizeof(rtp_packet) - kExpectedHeaderLength, - testing::_, false)) + EXPECT_CALL(remote_bitrate_estimator, + IncomingPacket(packet_time.timestamp / 1000, + sizeof(rtp_packet) - kExpectedHeaderLength, testing::_, false)) .Times(1); EXPECT_TRUE( recv_stream.DeliverRtp(rtp_packet, sizeof(rtp_packet), packet_time)); } + +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; + 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 AudioDecodingCallStats& decode_stats = + voice_engine.GetRecvAudioDecodingCallStats(); + EXPECT_EQ(kSsrc1, 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(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), + stats.audio_level); + EXPECT_EQ(Q14ToFloat(net_stats.currentExpandRate), stats.expand_rate); + EXPECT_EQ(Q14ToFloat(net_stats.currentSpeechExpandRate), + stats.speech_expand_rate); + EXPECT_EQ(Q14ToFloat(net_stats.currentSecondaryDecodedRate), + stats.secondary_decoded_rate); + EXPECT_EQ(Q14ToFloat(net_stats.currentAccelerateRate), stats.accelerate_rate); + EXPECT_EQ(Q14ToFloat(net_stats.currentPreemptiveRate), + stats.preemptive_expand_rate); + EXPECT_EQ(decode_stats.calls_to_silence_generator, + stats.decoding_calls_to_silence_generator); + EXPECT_EQ(decode_stats.calls_to_neteq, stats.decoding_calls_to_neteq); + EXPECT_EQ(decode_stats.decoded_normal, stats.decoding_normal); + EXPECT_EQ(decode_stats.decoded_plc, stats.decoding_plc); + EXPECT_EQ(decode_stats.decoded_cng, stats.decoding_cng); + EXPECT_EQ(decode_stats.decoded_plc_cng, stats.decoding_plc_cng); + EXPECT_EQ(call_stats.capture_start_ntp_time_ms_, + stats.capture_start_ntp_time_ms); +} +} // namespace test } // namespace webrtc diff --git a/webrtc/audio/conversion.h b/webrtc/audio/conversion.h new file mode 100644 index 0000000000..c1cf9b632e --- /dev/null +++ b/webrtc/audio/conversion.h @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#ifndef WEBRTC_AUDIO_CONVERSION_H_ +#define WEBRTC_AUDIO_CONVERSION_H_ + +namespace webrtc { + +// Convert fixed point number with 14 bit fractional part, to floating point. +inline float Q14ToFloat(uint16_t v) { + return static_cast(v) / (1 << 14); +} +} // namespace webrtc + +#endif // WEBRTC_AUDIO_CONVERSION_H_ diff --git a/webrtc/audio/scoped_voe_interface.h b/webrtc/audio/scoped_voe_interface.h new file mode 100644 index 0000000000..1029337228 --- /dev/null +++ b/webrtc/audio/scoped_voe_interface.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#ifndef WEBRTC_AUDIO_SCOPED_VOE_INTERFACE_H_ +#define WEBRTC_AUDIO_SCOPED_VOE_INTERFACE_H_ + +#include "webrtc/base/checks.h" + +namespace webrtc { + +class VoiceEngine; + +namespace internal { + +// Utility template for obtaining and holding a reference to a VoiceEngine +// interface and making sure it is released when this object goes out of scope. +template class ScopedVoEInterface { + public: + explicit ScopedVoEInterface(webrtc::VoiceEngine* e) + : ptr_(T::GetInterface(e)) { + RTC_DCHECK(ptr_); + } + ~ScopedVoEInterface() { + if (ptr_) { + ptr_->Release(); + } + } + T* operator->() { + RTC_DCHECK(ptr_); + return ptr_; + } + private: + T* ptr_; +}; +} // namespace internal +} // namespace webrtc + +#endif // WEBRTC_AUDIO_SCOPED_VOE_INTERFACE_H_ diff --git a/webrtc/audio/webrtc_audio.gypi b/webrtc/audio/webrtc_audio.gypi index 40ccff6b2a..b9d45db56d 100644 --- a/webrtc/audio/webrtc_audio.gypi +++ b/webrtc/audio/webrtc_audio.gypi @@ -18,6 +18,8 @@ 'audio/audio_receive_stream.h', 'audio/audio_send_stream.cc', 'audio/audio_send_stream.h', + 'audio/conversion.h', + 'audio/scoped_voe_interface.h', ], }, } diff --git a/webrtc/audio_receive_stream.h b/webrtc/audio_receive_stream.h index 70d6480b10..3e5a518a7d 100644 --- a/webrtc/audio_receive_stream.h +++ b/webrtc/audio_receive_stream.h @@ -26,7 +26,32 @@ class AudioDecoder; class AudioReceiveStream : public ReceiveStream { public: - struct Stats {}; + struct Stats { + uint32_t remote_ssrc = 0; + int64_t bytes_rcvd = 0; + uint32_t packets_rcvd = 0; + uint32_t packets_lost = 0; + float fraction_lost = 0.0f; + std::string codec_name; + uint32_t ext_seqnum = 0; + uint32_t jitter_ms = 0; + uint32_t jitter_buffer_ms = 0; + uint32_t jitter_buffer_preferred_ms = 0; + uint32_t delay_estimate_ms = 0; + int32_t audio_level = -1; + float expand_rate = 0.0f; + float speech_expand_rate = 0.0f; + float secondary_decoded_rate = 0.0f; + float accelerate_rate = 0.0f; + float preemptive_expand_rate = 0.0f; + int32_t decoding_calls_to_silence_generator = 0; + int32_t decoding_calls_to_neteq = 0; + int32_t decoding_normal = 0; + int32_t decoding_plc = 0; + int32_t decoding_cng = 0; + int32_t decoding_plc_cng = 0; + int64_t capture_start_ntp_time_ms = 0; + }; struct Config { std::string ToString() const; diff --git a/webrtc/call/bitrate_estimator_tests.cc b/webrtc/call/bitrate_estimator_tests.cc index f7044ae33e..08e36c893a 100644 --- a/webrtc/call/bitrate_estimator_tests.cc +++ b/webrtc/call/bitrate_estimator_tests.cc @@ -25,6 +25,7 @@ #include "webrtc/test/encoder_settings.h" #include "webrtc/test/fake_decoder.h" #include "webrtc/test/fake_encoder.h" +#include "webrtc/test/fake_voice_engine.h" #include "webrtc/test/frame_generator_capturer.h" namespace webrtc { @@ -130,8 +131,10 @@ class BitrateEstimatorTest : public test::CallTest { } virtual void SetUp() { - receiver_call_.reset(Call::Create(Call::Config())); - sender_call_.reset(Call::Create(Call::Config())); + Call::Config config; + config.voice_engine = &fake_voice_engine_; + receiver_call_.reset(Call::Create(config)); + sender_call_.reset(Call::Create(config)); send_transport_.SetReceiver(receiver_call_->Receiver()); receive_transport_.SetReceiver(sender_call_->Receiver()); @@ -265,6 +268,7 @@ class BitrateEstimatorTest : public test::CallTest { test::FakeDecoder fake_decoder_; }; + test::FakeVoiceEngine fake_voice_engine_; TraceObserver receiver_trace_; test::DirectTransport send_transport_; test::DirectTransport receive_transport_; diff --git a/webrtc/call/call.cc b/webrtc/call/call.cc index b1424531d6..3969bc6b51 100644 --- a/webrtc/call/call.cc +++ b/webrtc/call/call.cc @@ -126,7 +126,8 @@ class Call : public webrtc::Call, public PacketReceiver { VideoSendStream::RtpStateMap suspended_video_send_ssrcs_; - RtcEventLog* event_log_; + RtcEventLog* event_log_ = nullptr; + VoECodec* voe_codec_ = nullptr; RTC_DISALLOW_COPY_AND_ASSIGN(Call); }; @@ -147,8 +148,7 @@ Call::Call(const Call::Config& config) config_(config), network_enabled_(true), receive_crit_(RWLockWrapper::CreateRWLock()), - send_crit_(RWLockWrapper::CreateRWLock()), - event_log_(nullptr) { + 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, @@ -158,11 +158,11 @@ Call::Call(const Call::Config& config) config.bitrate_config.start_bitrate_bps); } if (config.voice_engine) { - VoECodec* voe_codec = VoECodec::GetInterface(config.voice_engine); - if (voe_codec) { - event_log_ = voe_codec->GetEventLog(); - voe_codec->Release(); - } + // Keep a reference to VoECodec, so we're sure the VoiceEngine lives for the + // duration of the call. + voe_codec_ = VoECodec::GetInterface(config.voice_engine); + if (voe_codec_) + event_log_ = voe_codec_->GetEventLog(); } Trace::CreateTrace(); @@ -187,6 +187,9 @@ Call::~Call() { module_process_thread_->DeRegisterModule(call_stats_.get()); module_process_thread_->Stop(); Trace::ReturnTrace(); + + if (voe_codec_) + voe_codec_->Release(); } PacketReceiver* Call::Receiver() { @@ -237,7 +240,8 @@ webrtc::AudioReceiveStream* Call::CreateAudioReceiveStream( TRACE_EVENT0("webrtc", "Call::CreateAudioReceiveStream"); RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); AudioReceiveStream* receive_stream = new AudioReceiveStream( - congestion_controller_->GetRemoteBitrateEstimator(false), config); + congestion_controller_->GetRemoteBitrateEstimator(false), config, + config_.voice_engine); { WriteLockScoped write_lock(*receive_crit_); RTC_DCHECK(audio_receive_ssrcs_.find(config.rtp.remote_ssrc) == diff --git a/webrtc/call/call_perf_tests.cc b/webrtc/call/call_perf_tests.cc index a7714b19c6..cab3914450 100644 --- a/webrtc/call/call_perf_tests.cc +++ b/webrtc/call/call_perf_tests.cc @@ -321,6 +321,8 @@ void CallPerfTest::TestAudioVideoSync(bool fec, bool create_audio_first) { receiver_call_->DestroyAudioReceiveStream(audio_receive_stream); + DestroyCalls(); + VoiceEngine::Delete(voice_engine); } diff --git a/webrtc/call/call_unittest.cc b/webrtc/call/call_unittest.cc index 9adecc349b..9819b538f8 100644 --- a/webrtc/call/call_unittest.cc +++ b/webrtc/call/call_unittest.cc @@ -13,19 +13,21 @@ #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/call.h" +#include "webrtc/test/fake_voice_engine.h" namespace { struct CallHelper { - CallHelper() { + CallHelper() : voice_engine_(new webrtc::test::FakeVoiceEngine()) { webrtc::Call::Config config; - // TODO(solenberg): Fill in with VoiceEngine* etc. + config.voice_engine = voice_engine_.get(); call_.reset(webrtc::Call::Create(config)); } webrtc::Call* operator->() { return call_.get(); } private: + rtc::scoped_ptr voice_engine_; rtc::scoped_ptr call_; }; } // namespace diff --git a/webrtc/test/call_test.cc b/webrtc/test/call_test.cc index 0986df5d61..f2b5f91c7b 100644 --- a/webrtc/test/call_test.cc +++ b/webrtc/test/call_test.cc @@ -89,6 +89,11 @@ void CallTest::CreateReceiverCall(const Call::Config& config) { receiver_call_.reset(Call::Create(config)); } +void CallTest::DestroyCalls() { + sender_call_.reset(nullptr); + receiver_call_.reset(nullptr); +} + void CallTest::CreateSendConfig(size_t num_streams, Transport* send_transport) { assert(num_streams <= kNumSsrcs); diff --git a/webrtc/test/call_test.h b/webrtc/test/call_test.h index 2b9dcee9a8..4a645b4cfd 100644 --- a/webrtc/test/call_test.h +++ b/webrtc/test/call_test.h @@ -52,6 +52,7 @@ class CallTest : public ::testing::Test { const Call::Config& receiver_config); void CreateSenderCall(const Call::Config& config); void CreateReceiverCall(const Call::Config& config); + void DestroyCalls(); void CreateSendConfig(size_t num_streams, Transport* send_transport); void CreateMatchingReceiveConfigs(Transport* rtcp_send_transport); diff --git a/webrtc/test/fake_voice_engine.h b/webrtc/test/fake_voice_engine.h new file mode 100644 index 0000000000..72f6b27dd2 --- /dev/null +++ b/webrtc/test/fake_voice_engine.h @@ -0,0 +1,421 @@ +/* + * 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. + */ + +#ifndef WEBRTC_AUDIO_FAKE_VOICE_ENGINE_H_ +#define WEBRTC_AUDIO_FAKE_VOICE_ENGINE_H_ + +#include + +#include "testing/gtest/include/gtest/gtest.h" + +#include "webrtc/voice_engine/voice_engine_impl.h" + +namespace webrtc { +namespace test { + +// NOTE: This class inherits from VoiceEngineImpl so that its clients will be +// 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; + + FakeVoiceEngine() : VoiceEngineImpl(new Config(), true) { + // Increase ref count so this object isn't automatically deleted whenever + // interfaces are Release():d. + ++_ref_count; + } + ~FakeVoiceEngine() override { + // Decrease ref count before base class d-tor is called; otherwise it will + // trigger an assertion. + --_ref_count; + } + + const CallStatistics& GetRecvCallStats() const { + static const CallStatistics kStats = { + 345, 678, 901, 234, -1, 0, 0, 567, 890, 123 + }; + return kStats; + } + + const CodecInst& GetRecvRecCodecInst() const { + static const CodecInst kStats = { + 123, "codec_name", 96000, -1, -1, -1 + }; + return kStats; + } + + 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; + } + + 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; + } + + // VoEBase + int RegisterVoiceEngineObserver(VoiceEngineObserver& observer) override { + return -1; + } + int DeRegisterVoiceEngineObserver() override { return -1; } + int Init(AudioDeviceModule* external_adm = NULL, + AudioProcessing* audioproc = NULL) override { return -1; } + AudioProcessing* audio_processing() override { return nullptr; } + int Terminate() override { return -1; } + int CreateChannel() override { return -1; } + int CreateChannel(const Config& config) override { return -1; } + int DeleteChannel(int channel) override { return -1; } + int StartReceive(int channel) override { return -1; } + int StopReceive(int channel) override { return -1; } + int StartPlayout(int channel) override { return -1; } + int StopPlayout(int channel) override { return -1; } + int StartSend(int channel) override { return -1; } + int StopSend(int channel) override { return -1; } + int GetVersion(char version[1024]) override { return -1; } + int LastError() override { return -1; } + AudioTransport* audio_transport() { return nullptr; } + int AssociateSendChannel(int channel, int accociate_send_channel) override { + return -1; + } + + // VoECodec + 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 SetBitRate(int channel, int bitrate_bps) override { return -1; } + int GetRecCodec(int channel, CodecInst& codec) override { + EXPECT_EQ(channel, kReceiveChannelId); + codec = GetRecvRecCodecInst(); + return 0; + } + int SetRecPayloadType(int channel, const CodecInst& codec) override { + return -1; + } + int GetRecPayloadType(int channel, CodecInst& codec) override { return -1; } + int SetSendCNPayloadType(int channel, int type, + PayloadFrequencies frequency = kFreq16000Hz) override { return -1; } + int SetVADStatus(int channel, + bool enable, + VadModes mode = kVadConventional, + bool disableDTX = false) override { return -1; } + int GetVADStatus(int channel, + bool& enabled, + VadModes& mode, + bool& disabledDTX) override { return -1; } + int SetOpusMaxPlaybackRate(int channel, int frequency_hz) override { + return -1; + } + int SetOpusDtx(int channel, bool enable_dtx) override { return -1; } + RtcEventLog* GetEventLog() override { return nullptr; } + + // VoEDtmf + int SendTelephoneEvent(int channel, + int eventCode, + bool outOfBand = true, + int lengthMs = 160, + int attenuationDb = 10) override { return -1; } + int SetSendTelephoneEventPayloadType(int channel, + unsigned char type) override { + return -1; + } + int GetSendTelephoneEventPayloadType(int channel, + unsigned char& type) override { + return -1; + } + int SetDtmfFeedbackStatus(bool enable, + bool directFeedback = false) override { return -1; } + int GetDtmfFeedbackStatus(bool& enabled, bool& directFeedback) override { + return -1; + } + int PlayDtmfTone(int eventCode, + int lengthMs = 200, + int attenuationDb = 10) override { return -1; } + + // VoEExternalMedia + int RegisterExternalMediaProcessing( + int channel, + ProcessingTypes type, + VoEMediaProcess& processObject) override { return -1; } + int DeRegisterExternalMediaProcessing(int channel, + ProcessingTypes type) override { + return -1; + } + int GetAudioFrame(int channel, + int desired_sample_rate_hz, + AudioFrame* frame) override { return -1; } + int SetExternalMixing(int channel, bool enable) override { return -1; } + + // VoEFile + int StartPlayingFileLocally( + int channel, + const char fileNameUTF8[1024], + bool loop = false, + FileFormats format = kFileFormatPcm16kHzFile, + float volumeScaling = 1.0, + int startPointMs = 0, + int stopPointMs = 0) override { return -1; } + int StartPlayingFileLocally( + int channel, + InStream* stream, + FileFormats format = kFileFormatPcm16kHzFile, + float volumeScaling = 1.0, + int startPointMs = 0, + int stopPointMs = 0) override { return -1; } + int StopPlayingFileLocally(int channel) override { return -1; } + int IsPlayingFileLocally(int channel) override { return -1; } + int StartPlayingFileAsMicrophone( + int channel, + const char fileNameUTF8[1024], + bool loop = false, + bool mixWithMicrophone = false, + FileFormats format = kFileFormatPcm16kHzFile, + float volumeScaling = 1.0) override { return -1; } + int StartPlayingFileAsMicrophone( + int channel, + InStream* stream, + bool mixWithMicrophone = false, + FileFormats format = kFileFormatPcm16kHzFile, + float volumeScaling = 1.0) override { return -1; } + int StopPlayingFileAsMicrophone(int channel) override { return -1; } + int IsPlayingFileAsMicrophone(int channel) override { return -1; } + int StartRecordingPlayout(int channel, + const char* fileNameUTF8, + CodecInst* compression = NULL, + int maxSizeBytes = -1) override { return -1; } + int StopRecordingPlayout(int channel) override { return -1; } + int StartRecordingPlayout(int channel, + OutStream* stream, + CodecInst* compression = NULL) override { + return -1; + } + int StartRecordingMicrophone(const char* fileNameUTF8, + CodecInst* compression = NULL, + int maxSizeBytes = -1) override { return -1; } + int StartRecordingMicrophone(OutStream* stream, + CodecInst* compression = NULL) override { + return -1; + } + int StopRecordingMicrophone() override { return -1; } + + // VoEHardware + int GetNumOfRecordingDevices(int& devices) override { return -1; } + + // Gets the number of audio devices available for playout. + int GetNumOfPlayoutDevices(int& devices) override { return -1; } + + // Gets the name of a specific recording device given by an |index|. + // On Windows Vista/7, it also retrieves an additional unique ID + // (GUID) for the recording device. + int GetRecordingDeviceName(int index, + char strNameUTF8[128], + char strGuidUTF8[128]) override { return -1; } + + // Gets the name of a specific playout device given by an |index|. + // On Windows Vista/7, it also retrieves an additional unique ID + // (GUID) for the playout device. + int GetPlayoutDeviceName(int index, + char strNameUTF8[128], + char strGuidUTF8[128]) override { return -1; } + + // Sets the audio device used for recording. + int SetRecordingDevice( + int index, + StereoChannel recordingChannel = kStereoBoth) override { return -1; } + + // Sets the audio device used for playout. + int SetPlayoutDevice(int index) override { return -1; } + + // Sets the type of audio device layer to use. + int SetAudioDeviceLayer(AudioLayers audioLayer) override { return -1; } + + // Gets the currently used (active) audio device layer. + int GetAudioDeviceLayer(AudioLayers& audioLayer) override { return -1; } + + // Native sample rate controls (samples/sec) + int SetRecordingSampleRate(unsigned int samples_per_sec) override { + return -1; + } + int RecordingSampleRate(unsigned int* samples_per_sec) const override { + return -1; + } + int SetPlayoutSampleRate(unsigned int samples_per_sec) override { + return -1; + } + int PlayoutSampleRate(unsigned int* samples_per_sec) const override { + return -1; + } + + // Queries and controls platform audio effects on Android devices. + bool BuiltInAECIsAvailable() const override { return false; } + int EnableBuiltInAEC(bool enable) override { return -1; } + bool BuiltInAGCIsAvailable() const override { return false; } + int EnableBuiltInAGC(bool enable) override { return -1; } + bool BuiltInNSIsAvailable() const override { return false; } + int EnableBuiltInNS(bool enable) override { return -1; } + + // VoENetwork + int RegisterExternalTransport(int channel, Transport& transport) override { + return -1; + } + int DeRegisterExternalTransport(int channel) override { return -1; } + int ReceivedRTPPacket(int channel, + const void* data, + size_t length) override { return -1; } + int ReceivedRTPPacket(int channel, + const void* data, + size_t length, + const PacketTime& packet_time) override { return -1; } + int ReceivedRTCPPacket(int channel, + const void* data, + size_t length) { return -1; } + + // VoENetEqStats + int GetNetworkStatistics(int channel, NetworkStatistics& stats) override { + EXPECT_EQ(channel, kReceiveChannelId); + stats = GetRecvNetworkStats(); + return 0; + } + int GetDecodingCallStatistics(int channel, + AudioDecodingCallStats* stats) const override { + EXPECT_EQ(channel, kReceiveChannelId); + EXPECT_NE(nullptr, stats); + *stats = GetRecvAudioDecodingCallStats(); + 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 GetRemoteSSRC(int channel, unsigned int& ssrc) override { + EXPECT_EQ(channel, kReceiveChannelId); + ssrc = 0; + return 0; + } + int SetSendAudioLevelIndicationStatus(int channel, + bool enable, + unsigned char id = 1) override { + return -1; + } + int SetSendAbsoluteSenderTimeStatus(int channel, + bool enable, + unsigned char id) override { return -1; } + int SetReceiveAbsoluteSenderTimeStatus(int channel, + bool enable, + unsigned char id) override { + return -1; + } + int SetRTCPStatus(int channel, bool enable) override { return -1; } + int GetRTCPStatus(int channel, bool& enabled) override { return -1; } + int SetRTCP_CNAME(int channel, const char cName[256]) override { return -1; } + int GetRTCP_CNAME(int channel, char cName[256]) { return -1; } + int GetRemoteRTCP_CNAME(int channel, char cName[256]) override { return -1; } + int GetRemoteRTCPData(int channel, + unsigned int& NTPHigh, + unsigned int& NTPLow, + unsigned int& timestamp, + unsigned int& playoutTimestamp, + unsigned int* jitter = NULL, + unsigned short* fractionLost = NULL) override { + return -1; + } + int GetRTPStatistics(int channel, + unsigned int& averageJitterMs, + unsigned int& maxJitterMs, + unsigned int& discardedPackets) override { return -1; } + int GetRTCPStatistics(int channel, CallStatistics& stats) override { + EXPECT_EQ(channel, kReceiveChannelId); + stats = GetRecvCallStats(); + return 0; + } + int GetRemoteRTCPReportBlocks( + int channel, + std::vector* receive_blocks) override { return -1; } + int SetNACKStatus(int channel, bool enable, int maxNoPackets) override { + return -1; + } + + // VoEVideoSync + int GetPlayoutBufferSize(int& buffer_ms) override { return -1; } + int SetMinimumPlayoutDelay(int channel, int delay_ms) override { return -1; } + int SetInitialPlayoutDelay(int channel, int delay_ms) override { return -1; } + int GetDelayEstimate(int channel, + int* jitter_buffer_delay_ms, + int* playout_buffer_delay_ms) override { + EXPECT_EQ(channel, kReceiveChannelId); + *jitter_buffer_delay_ms = kRecvJitterBufferDelay; + *playout_buffer_delay_ms = kRecvPlayoutBufferDelay; + return 0; + } + int GetLeastRequiredDelayMs(int channel) const override { return -1; } + int SetInitTimestamp(int channel, unsigned int timestamp) override { + return -1; + } + int SetInitSequenceNumber(int channel, short sequenceNumber) override { + return -1; + } + int GetPlayoutTimestamp(int channel, unsigned int& timestamp) override { + return -1; + } + int GetRtpRtcp(int channel, + RtpRtcp** rtpRtcpModule, + RtpReceiver** rtp_receiver) override { return -1; } + + // VoEVolumeControl + int SetSpeakerVolume(unsigned int volume) override { return -1; } + int GetSpeakerVolume(unsigned int& volume) override { return -1; } + int SetMicVolume(unsigned int volume) override { return -1; } + int GetMicVolume(unsigned int& volume) override { return -1; } + int SetInputMute(int channel, bool enable) override { return -1; } + int GetInputMute(int channel, bool& enabled) override { return -1; } + int GetSpeechInputLevel(unsigned int& level) override { return -1; } + int GetSpeechOutputLevel(int channel, unsigned int& level) override { + return -1; + } + int GetSpeechInputLevelFullRange(unsigned int& level) override { return -1; } + int GetSpeechOutputLevelFullRange(int channel, + unsigned int& level) override { + EXPECT_EQ(channel, kReceiveChannelId); + level = kRecvSpeechOutputLevel; + return 0; + } + int SetChannelOutputVolumeScaling(int channel, float scaling) override { + return -1; + } + int GetChannelOutputVolumeScaling(int channel, float& scaling) override { + return -1; + } + int SetOutputVolumePan(int channel, float left, float right) override { + return -1; + } + int GetOutputVolumePan(int channel, float& left, float& right) override { + return -1; + } +}; +} // namespace test +} // namespace webrtc + +#endif // WEBRTC_AUDIO_FAKE_VOICE_ENGINE_H_ diff --git a/webrtc/test/webrtc_test_common.gyp b/webrtc/test/webrtc_test_common.gyp index f8d33658c4..5076900f94 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.h', 'frame_generator_capturer.cc', 'frame_generator_capturer.h', 'layer_filtering_transport.cc', diff --git a/webrtc/voice_engine/voice_engine_impl.h b/webrtc/voice_engine/voice_engine_impl.h index 07f29c37b9..21039943fd 100644 --- a/webrtc/voice_engine/voice_engine_impl.h +++ b/webrtc/voice_engine/voice_engine_impl.h @@ -128,8 +128,11 @@ class VoiceEngineImpl : public voe::SharedData, // Must be the first base class // This implements the Release() method for all the inherited interfaces. int Release() override; - private: + // This is *protected* so that FakeVoiceEngine can inherit from the class and + // manipulate the reference count. See: fake_voice_engine.h. + protected: Atomic32 _ref_count; + private: rtc::scoped_ptr own_config_; };