| 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..ccfdca546dcf5c9699b85f7745b21c4c2ade671f 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_NE(config.voe_channel_id, -1);
|
| + RTC_DCHECK(voice_engine_);
|
| }
|
|
|
| AudioSendStream::~AudioSendStream() {
|
| + RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| LOG(LS_INFO) << "~AudioSendStream: " << config_.ToString();
|
| }
|
|
|
| webrtc::AudioSendStream::Stats AudioSendStream::GetStats() const {
|
| - return webrtc::AudioSendStream::Stats();
|
| + RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| + webrtc::AudioSendStream::Stats stats;
|
| + stats.local_ssrc = config_.rtp.ssrc;
|
| + ScopedVoEInterface<VoEAudioProcessing> processing(voice_engine_);
|
| + ScopedVoEInterface<VoECodec> codec(voice_engine_);
|
| + ScopedVoEInterface<VoERTP_RTCP> rtp(voice_engine_);
|
| + ScopedVoEInterface<VoEVolumeControl> volume(voice_engine_);
|
| + unsigned int ssrc = 0;
|
| + webrtc::CallStatistics call_stats = {0};
|
| + if (rtp->GetLocalSSRC(config_.voe_channel_id, ssrc) == -1 ||
|
| + rtp->GetRTCPStatistics(config_.voe_channel_id, call_stats) == -1) {
|
| + return stats;
|
| + }
|
| +
|
| + stats.bytes_sent = call_stats.bytesSent;
|
| + stats.packets_sent = call_stats.packetsSent;
|
| +
|
| + webrtc::CodecInst codec_inst = {0};
|
| + if (codec->GetSendCodec(config_.voe_channel_id, codec_inst) != -1) {
|
| + RTC_DCHECK_NE(codec_inst.pltype, -1);
|
| + stats.codec_name = codec_inst.plname;
|
| +
|
| + // Get data from the last remote RTCP report.
|
| + std::vector<webrtc::ReportBlock> blocks;
|
| + if (rtp->GetRemoteRTCPReportBlocks(config_.voe_channel_id, &blocks) != -1) {
|
| + for (const webrtc::ReportBlock& block : blocks) {
|
| + // Lookup report for send ssrc only.
|
| + if (block.source_SSRC == stats.local_ssrc) {
|
| + stats.packets_lost = block.cumulative_num_packets_lost;
|
| + stats.fraction_lost = Q8ToFloat(block.fraction_lost);
|
| + stats.ext_seqnum = block.extended_highest_sequence_number;
|
| + // Convert samples to milliseconds.
|
| + if (codec_inst.plfreq / 1000 > 0) {
|
| + stats.jitter_ms =
|
| + block.interarrival_jitter / (codec_inst.plfreq / 1000);
|
| + }
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + // RTT isn't known until a RTCP report is received. Until then, VoiceEngine
|
| + // returns 0 to indicate an error value.
|
| + if (call_stats.rttMs > 0) {
|
| + stats.rtt_ms = call_stats.rttMs;
|
| + }
|
| +
|
| + // Local speech level.
|
| + {
|
| + unsigned int level = 0;
|
| + if (volume->GetSpeechInputLevelFullRange(level) != -1) {
|
| + stats.audio_level = static_cast<int32_t>(level);
|
| + }
|
| + }
|
| +
|
| + // TODO(ajm): Re-enable this metric once we have a reliable implementation.
|
| + stats.aec_quality_min = -1;
|
| +
|
| + bool echo_metrics_on = false;
|
| + if (processing->GetEcMetricsStatus(echo_metrics_on) != -1 &&
|
| + echo_metrics_on) {
|
| + // These can also be negative, but in practice -1 is only used to signal
|
| + // insufficient data, since the resolution is limited to multiples of 4 ms.
|
| + int median = -1;
|
| + int std = -1;
|
| + float dummy = 0.0f;
|
| + if (processing->GetEcDelayMetrics(median, std, dummy) != -1) {
|
| + stats.echo_delay_median_ms = median;
|
| + stats.echo_delay_std_ms = std;
|
| + }
|
| +
|
| + // These can take on valid negative values, so use the lowest possible level
|
| + // as default rather than -1.
|
| + int erl = -100;
|
| + int erle = -100;
|
| + int dummy1 = 0;
|
| + int dummy2 = 0;
|
| + if (processing->GetEchoMetrics(erl, erle, dummy1, dummy2) != -1) {
|
| + stats.echo_return_loss = erl;
|
| + stats.echo_return_loss_enhancement = erle;
|
| + }
|
| + }
|
| +
|
| + // TODO(solenberg): Collect typing noise warnings here too!
|
| + // bool typing_noise_detected = typing_noise_detected_;
|
| +
|
| + return stats;
|
| +}
|
| +
|
| +const webrtc::AudioSendStream::Config& AudioSendStream::config() const {
|
| + RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| + return config_;
|
| }
|
|
|
| void AudioSendStream::Start() {
|
| + RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| }
|
|
|
| void AudioSendStream::Stop() {
|
| + RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| }
|
|
|
| void AudioSendStream::SignalNetworkState(NetworkState state) {
|
| + RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| }
|
|
|
| bool AudioSendStream::DeliverRtcp(const uint8_t* packet, size_t length) {
|
| + // TODO(solenberg): Tests call this function on a network thread, libjingle
|
| + // calls on the worker thread. We should move towards always using a network
|
| + // thread. Then this check can be enabled.
|
| + // RTC_DCHECK(!thread_checker_.CalledOnValidThread());
|
| return false;
|
| }
|
| } // namespace internal
|
|
|