From a457752f4afc496ed7f4d6b584b08d8635f18cc0 Mon Sep 17 00:00:00 2001 From: Fredrik Solenberg Date: Tue, 20 Oct 2015 15:01:35 +0200 Subject: [PATCH] Implement AudioReceiveStream::GetStats(). R=tommi@webrtc.org TBR=hta@webrtc.org BUG=webrtc:4690 Review URL: https://codereview.webrtc.org/1390753002 . Cr-Commit-Position: refs/heads/master@{#10338} --- .../contents.xcworkspacedata | 5 + .../UserInterfaceState.xcuserstate | Bin 0 -> 43608 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 929 ++++++++++++++++++ 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 | 162 +-- 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 | 70 +- webrtc/audio/conversion.h | 21 + webrtc/audio/scoped_voe_interface.h | 43 + 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_unittest.cc | 6 +- webrtc/test/fake_voice_engine.h | 421 ++++++++ webrtc/test/webrtc_test_common.gyp | 1 + webrtc/voice_engine/voice_engine_impl.h | 4 +- 23 files changed, 1805 insertions(+), 250 deletions(-) create mode 100644 all.ninja.xcworkspace/contents.xcworkspacedata create mode 100644 all.ninja.xcworkspace/xcuserdata/solenberg.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 all.ninja.xcworkspace/xcuserdata/solenberg.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist 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/all.ninja.xcworkspace/contents.xcworkspacedata b/all.ninja.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..7dff14eb85 --- /dev/null +++ b/all.ninja.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,5 @@ + + + + + diff --git a/all.ninja.xcworkspace/xcuserdata/solenberg.xcuserdatad/UserInterfaceState.xcuserstate b/all.ninja.xcworkspace/xcuserdata/solenberg.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..807ae8c54b29124efe4a01f43fdeca986d5698aa GIT binary patch literal 43608 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 X(!Zr|JW)cUMm^!Utxx#>P51u~L1j=7 literal 0 HcmV?d00001 diff --git a/all.ninja.xcworkspace/xcuserdata/solenberg.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/all.ninja.xcworkspace/xcuserdata/solenberg.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000000..8ebb6dff9b --- /dev/null +++ b/all.ninja.xcworkspace/xcuserdata/solenberg.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,929 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/talk/media/webrtc/fakewebrtccall.cc b/talk/media/webrtc/fakewebrtccall.cc index a0386b011e..399ab138df 100644 --- a/talk/media/webrtc/fakewebrtccall.cc +++ b/talk/media/webrtc/fakewebrtccall.cc @@ -40,15 +40,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 fb271f2215..0ec854f9fc 100644 --- a/talk/media/webrtc/fakewebrtccall.h +++ b/talk/media/webrtc/fakewebrtccall.h @@ -42,11 +42,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(); @@ -64,7 +61,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 2a3df2db63..d880e4bdca 100644 --- a/talk/media/webrtc/webrtcvoiceengine.cc +++ b/talk/media/webrtc/webrtcvoiceengine.cc @@ -2694,11 +2694,6 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { } } - webrtc::CallStatistics cs; - unsigned int ssrc; - webrtc::CodecInst codec; - unsigned int level; - for (const auto& ch : send_channels_) { const int channel = ch.second->channel(); @@ -2706,6 +2701,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; @@ -2726,6 +2723,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) { @@ -2746,6 +2744,7 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { } // Local speech level. + unsigned int level = 0; sinfo.audio_level = (engine()->voe()->volume()-> GetSpeechInputLevelFullRange(level) != -1) ? level : -1; @@ -2766,76 +2765,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 b0fc2bb8d7..491af192be 100644 --- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc +++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc @@ -38,27 +38,27 @@ #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, }; -static uint32_t kSsrc1 = 0x99; -static uint32_t kSsrc2 = 0x98; +const uint32_t kSsrc1 = 0x99; +const uint32_t kSsrc2 = 0x98; class FakeVoEWrapper : public cricket::VoEWrapper { public: @@ -68,10 +68,8 @@ class FakeVoEWrapper : public cricket::VoEWrapper { engine, // codec engine, // dtmf engine, // hw - engine, // neteq engine, // network engine, // rtp - engine, // sync engine) { // volume } }; @@ -86,6 +84,7 @@ class FakeVoETraceWrapper : public cricket::VoETraceWrapper { int SetTraceCallback(webrtc::TraceCallback* callback) override { return 0; } unsigned int filter_; }; +} // namespace class WebRtcVoiceEngineTestFake : public testing::Test { public: @@ -293,6 +292,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_; @@ -2008,38 +2072,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. @@ -2300,33 +2349,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..4a1c8c6343 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,23 +49,28 @@ 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; + FakeVoiceEngine fve; AudioReceiveStream::Config config; config.combined_audio_video_bwe = true; - config.voe_channel_id = 1; + config.voe_channel_id = fve.kReceiveChannelId; const int kAbsSendTimeId = 3; config.rtp.extensions.push_back( RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId)); - internal::AudioReceiveStream recv_stream(&rbe, config); + internal::AudioReceiveStream recv_stream(&rbe, config, &fve); uint8_t rtp_packet[30]; const int kAbsSendTimeValue = 1234; CreateRtpHeaderWithAbsSendTime(rtp_packet, kAbsSendTimeId, kAbsSendTimeValue); @@ -74,4 +83,57 @@ TEST(AudioReceiveStreamTest, AudioPacketUpdatesBweWithTimestamp) { EXPECT_TRUE( recv_stream.DeliverRtp(rtp_packet, sizeof(rtp_packet), packet_time)); } + +TEST(AudioReceiveStreamTest, GetStats) { + const uint32_t kSsrc1 = 667; + + MockRemoteBitrateEstimator rbe; + FakeVoiceEngine fve; + AudioReceiveStream::Config config; + config.rtp.remote_ssrc = kSsrc1; + config.voe_channel_id = fve.kReceiveChannelId; + internal::AudioReceiveStream recv_stream(&rbe, config, &fve); + + AudioReceiveStream::Stats stats = recv_stream.GetStats(); + const CallStatistics& call_stats = fve.GetRecvCallStats(); + const CodecInst& codec_inst = fve.GetRecvRecCodecInst(); + const NetworkStatistics& net_stats = fve.GetRecvNetworkStats(); + const AudioDecodingCallStats& decode_stats = + fve.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(fve.kRecvJitterBufferDelay + + fve.kRecvPlayoutBufferDelay), stats.delay_estimate_ms); + EXPECT_EQ(static_cast(fve.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..4c0b7aab10 --- /dev/null +++ b/webrtc/audio/conversion.h @@ -0,0 +1,21 @@ +/* + * 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 { + +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..5a88fc93f6 --- /dev/null +++ b/webrtc/audio/scoped_voe_interface.h @@ -0,0 +1,43 @@ +/* + * 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 { + +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 9a036c9ede..a69be98bbb 100644 --- a/webrtc/call/call.cc +++ b/webrtc/call/call.cc @@ -123,7 +123,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); }; @@ -142,8 +143,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, @@ -153,11 +153,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(); @@ -179,6 +179,9 @@ Call::~Call() { module_process_thread_->Stop(); Trace::ReturnTrace(); + + if (voe_codec_) + voe_codec_->Release(); } PacketReceiver* Call::Receiver() { @@ -229,7 +232,8 @@ webrtc::AudioReceiveStream* Call::CreateAudioReceiveStream( TRACE_EVENT0("webrtc", "Call::CreateAudioReceiveStream"); RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); AudioReceiveStream* receive_stream = new AudioReceiveStream( - channel_group_->GetRemoteBitrateEstimator(false), config); + channel_group_->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_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/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..a21aabdd70 100644 --- a/webrtc/voice_engine/voice_engine_impl.h +++ b/webrtc/voice_engine/voice_engine_impl.h @@ -128,7 +128,9 @@ 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; rtc::scoped_ptr own_config_; };