 Chromium Code Reviews
 Chromium Code Reviews Issue 1414743004:
  Implement AudioSendStream::GetStats().  (Closed) 
  Base URL: https://chromium.googlesource.com/external/webrtc.git@master
    
  
    Issue 1414743004:
  Implement AudioSendStream::GetStats().  (Closed) 
  Base URL: https://chromium.googlesource.com/external/webrtc.git@master| Index: webrtc/audio/audio_send_stream.cc | 
| diff --git a/webrtc/audio/audio_send_stream.cc b/webrtc/audio/audio_send_stream.cc | 
| index 0d0c072bf4a58fd94ac82639a439530afc5bea5a..1729cb9c291ad5f76d7c53c079f63c2f00419c97 100644 | 
| --- a/webrtc/audio/audio_send_stream.cc | 
| +++ b/webrtc/audio/audio_send_stream.cc | 
| @@ -12,8 +12,13 @@ | 
| #include <string> | 
| +#include "webrtc/audio/conversion.h" | 
| #include "webrtc/base/checks.h" | 
| #include "webrtc/base/logging.h" | 
| +#include "webrtc/voice_engine/include/voe_audio_processing.h" | 
| +#include "webrtc/voice_engine/include/voe_codec.h" | 
| +#include "webrtc/voice_engine/include/voe_rtp_rtcp.h" | 
| +#include "webrtc/voice_engine/include/voe_volume_control.h" | 
| namespace webrtc { | 
| std::string AudioSendStream::Config::Rtp::ToString() const { | 
| @@ -22,8 +27,9 @@ std::string AudioSendStream::Config::Rtp::ToString() const { | 
| ss << ", extensions: ["; | 
| for (size_t i = 0; i < extensions.size(); ++i) { | 
| ss << extensions[i].ToString(); | 
| - if (i != extensions.size() - 1) | 
| + if (i != extensions.size() - 1) { | 
| ss << ", "; | 
| + } | 
| } | 
| ss << ']'; | 
| ss << '}'; | 
| @@ -42,30 +48,134 @@ std::string AudioSendStream::Config::ToString() const { | 
| } | 
| namespace internal { | 
| -AudioSendStream::AudioSendStream(const webrtc::AudioSendStream::Config& config) | 
| - : config_(config) { | 
| +AudioSendStream::AudioSendStream(const webrtc::AudioSendStream::Config& config, | 
| + VoiceEngine* voice_engine) | 
| + : config_(config), | 
| + voice_engine_(voice_engine), | 
| + voe_base_(voice_engine) { | 
| LOG(LS_INFO) << "AudioSendStream: " << config_.ToString(); | 
| RTC_DCHECK(config.voe_channel_id != -1); | 
| + RTC_DCHECK(voice_engine_ != nullptr); | 
| 
kwiberg-webrtc
2015/10/26 13:19:53
Just RTC_DCHECK(voice_engine_);? Otherwise, RTC_DC
 
the sun
2015/10/26 14:44:02
Done.
 | 
| } | 
| AudioSendStream::~AudioSendStream() { | 
| + RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 
| LOG(LS_INFO) << "~AudioSendStream: " << config_.ToString(); | 
| } | 
| webrtc::AudioSendStream::Stats AudioSendStream::GetStats() const { | 
| - return webrtc::AudioSendStream::Stats(); | 
| + RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 
| + webrtc::AudioSendStream::Stats stats; | 
| + stats.local_ssrc = config_.rtp.ssrc; | 
| + ScopedVoEInterface<VoEAudioProcessing> processing(voice_engine_); | 
| + ScopedVoEInterface<VoECodec> codec(voice_engine_); | 
| + ScopedVoEInterface<VoERTP_RTCP> rtp(voice_engine_); | 
| + ScopedVoEInterface<VoEVolumeControl> volume(voice_engine_); | 
| + unsigned int ssrc = 0; | 
| + webrtc::CallStatistics call_stats = {0}; | 
| + if (rtp->GetLocalSSRC(config_.voe_channel_id, ssrc) == -1 || | 
| + rtp->GetRTCPStatistics(config_.voe_channel_id, call_stats) == -1) { | 
| + return stats; | 
| + } | 
| + | 
| + stats.bytes_sent = call_stats.bytesSent; | 
| + stats.packets_sent = call_stats.packetsSent; | 
| + | 
| + webrtc::CodecInst codec_inst = {0}; | 
| + if (codec->GetSendCodec(config_.voe_channel_id, codec_inst) != -1) { | 
| + RTC_DCHECK(codec_inst.pltype != -1); | 
| 
kwiberg-webrtc
2015/10/26 13:19:53
RTC_DCHECK_NE
 
the sun
2015/10/26 14:44:02
Done.
 | 
| + stats.codec_name = codec_inst.plname; | 
| + | 
| + // Get data from the last remote RTCP report. | 
| + std::vector<webrtc::ReportBlock> blocks; | 
| + if (rtp->GetRemoteRTCPReportBlocks(config_.voe_channel_id, &blocks) != -1) { | 
| + for (const webrtc::ReportBlock& block : blocks) { | 
| + // Lookup report for send ssrc only. | 
| + if (block.source_SSRC == stats.local_ssrc) { | 
| + stats.packets_lost = block.cumulative_num_packets_lost; | 
| + stats.fraction_lost = Q8ToFloat(block.fraction_lost); | 
| + stats.ext_seqnum = block.extended_highest_sequence_number; | 
| + // Convert samples to milliseconds. | 
| + if (codec_inst.plfreq / 1000 > 0) { | 
| + stats.jitter_ms = | 
| + block.interarrival_jitter / (codec_inst.plfreq / 1000); | 
| + } | 
| + break; | 
| + } | 
| + } | 
| + } | 
| + } | 
| + | 
| + // RTT isn't known until a RTCP report is received. Until then, VoiceEngine | 
| + // returns 0 to indicate an error value. | 
| + if (call_stats.rttMs > 0) { | 
| + stats.rtt_ms = call_stats.rttMs; | 
| + } | 
| + | 
| + // Local speech level. | 
| + { | 
| + unsigned int level = 0; | 
| + if (volume->GetSpeechInputLevelFullRange(level) != -1) { | 
| + stats.audio_level = static_cast<int32_t>(level); | 
| + } | 
| + } | 
| + | 
| + // TODO(ajm): Re-enable this metric once we have a reliable implementation. | 
| + stats.aec_quality_min = -1; | 
| + | 
| + bool echo_metrics_on = false; | 
| + if (processing->GetEcMetricsStatus(echo_metrics_on) != -1 && | 
| + echo_metrics_on) { | 
| + // These can also be negative, but in practice -1 is only used to signal | 
| + // insufficient data, since the resolution is limited to multiples of 4 ms. | 
| 
kwiberg-webrtc
2015/10/26 13:19:53
:-)
 
the sun
2015/10/26 14:44:02
This is actually copy+paste. There's some likeliho
 | 
| + int median = -1; | 
| + int std = -1; | 
| + float dummy = 0.0f; | 
| + if (processing->GetEcDelayMetrics(median, std, dummy) != -1) { | 
| + stats.echo_delay_median_ms = median; | 
| + stats.echo_delay_std_ms = std; | 
| + } | 
| + | 
| + // These can take on valid negative values, so use the lowest possible level | 
| + // as default rather than -1. | 
| 
kwiberg-webrtc
2015/10/26 13:19:53
:-)
 
the sun
2015/10/26 14:44:02
Acknowledged.
 | 
| + int erl = -100; | 
| + int erle = -100; | 
| + int dummy1 = 0; | 
| + int dummy2 = 0; | 
| + if (processing->GetEchoMetrics(erl, erle, dummy1, dummy2) != -1) { | 
| + stats.echo_return_loss = erl; | 
| + stats.echo_return_loss_enhancement = erle; | 
| + } | 
| + } | 
| + | 
| + // TODO(solenberg): Collect typing noise warnings here too! | 
| + // bool typing_noise_detected = typing_noise_detected_; | 
| + | 
| + return stats; | 
| +} | 
| + | 
| +const webrtc::AudioSendStream::Config& AudioSendStream::config() const { | 
| + RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 
| + return config_; | 
| } | 
| void AudioSendStream::Start() { | 
| + RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 
| } | 
| void AudioSendStream::Stop() { | 
| + RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 
| } | 
| void AudioSendStream::SignalNetworkState(NetworkState state) { | 
| + RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 
| } | 
| bool AudioSendStream::DeliverRtcp(const uint8_t* packet, size_t length) { | 
| + // TODO(solenberg): Tests call this function on a network thread, libjingle | 
| + // calls on the worker thread. We should move towards always using a network | 
| + // thread. Then this check can be enabled. | 
| + // RTC_DCHECK(!thread_checker_.CalledOnValidThread()); | 
| return false; | 
| } | 
| } // namespace internal |