1 /* 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "webrtc/audio/audio_send_stream.h" 12 13 #include <string> 14 15 #include "webrtc/audio/audio_state.h" 16 #include "webrtc/audio/conversion.h" 17 #include "webrtc/audio/scoped_voe_interface.h" 18 #include "webrtc/base/checks.h" 19 #include "webrtc/base/logging.h" 20 #include "webrtc/call/congestion_controller.h" 21 #include "webrtc/modules/pacing/paced_sender.h" 22 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" 23 #include "webrtc/voice_engine/channel_proxy.h" 24 #include "webrtc/voice_engine/include/voe_audio_processing.h" 25 #include "webrtc/voice_engine/include/voe_codec.h" 26 #include "webrtc/voice_engine/include/voe_rtp_rtcp.h" 27 #include "webrtc/voice_engine/include/voe_volume_control.h" 28 #include "webrtc/voice_engine/voice_engine_impl.h" 29 30 namespace webrtc { 31 std::string AudioSendStream::Config::Rtp::ToString() const { 32 std::stringstream ss; 33 ss << "{ssrc: " << ssrc; 34 ss << ", extensions: ["; 35 for (size_t i = 0; i < extensions.size(); ++i) { 36 ss << extensions[i].ToString(); 37 if (i != extensions.size() - 1) { 38 ss << ", "; 39 } 40 } 41 ss << ']'; 42 ss << ", c_name: " << c_name; 43 ss << '}'; 44 return ss.str(); 45 } 46 47 std::string AudioSendStream::Config::ToString() const { 48 std::stringstream ss; 49 ss << "{rtp: " << rtp.ToString(); 50 ss << ", voe_channel_id: " << voe_channel_id; 51 // TODO(solenberg): Encoder config. 52 ss << ", cng_payload_type: " << cng_payload_type; 53 ss << ", red_payload_type: " << red_payload_type; 54 ss << '}'; 55 return ss.str(); 56 } 57 58 namespace internal { 59 AudioSendStream::AudioSendStream( 60 const webrtc::AudioSendStream::Config& config, 61 const rtc::scoped_refptr<webrtc::AudioState>& audio_state, 62 CongestionController* congestion_controller) 63 : config_(config), audio_state_(audio_state) { 64 LOG(LS_INFO) << "AudioSendStream: " << config_.ToString(); 65 RTC_DCHECK_NE(config_.voe_channel_id, -1); 66 RTC_DCHECK(audio_state_.get()); 67 RTC_DCHECK(congestion_controller); 68 69 VoiceEngineImpl* voe_impl = static_cast<VoiceEngineImpl*>(voice_engine()); 70 channel_proxy_ = voe_impl->GetChannelProxy(config_.voe_channel_id); 71 channel_proxy_->SetCongestionControlObjects( 72 congestion_controller->pacer(), 73 congestion_controller->GetTransportFeedbackObserver(), 74 congestion_controller->packet_router()); 75 channel_proxy_->SetRTCPStatus(true); 76 channel_proxy_->SetLocalSSRC(config.rtp.ssrc); 77 channel_proxy_->SetRTCP_CNAME(config.rtp.c_name); 78 79 for (const auto& extension : config.rtp.extensions) { 80 if (extension.name == RtpExtension::kAbsSendTime) { 81 channel_proxy_->SetSendAbsoluteSenderTimeStatus(true, extension.id); 82 } else if (extension.name == RtpExtension::kAudioLevel) { 83 channel_proxy_->SetSendAudioLevelIndicationStatus(true, extension.id); 84 } else if (extension.name == RtpExtension::kTransportSequenceNumber) { 85 channel_proxy_->EnableSendTransportSequenceNumber(extension.id); 86 } else { 87 RTC_NOTREACHED() << "Registering unsupported RTP extension."; 88 } 89 } 90 } 91 92 AudioSendStream::~AudioSendStream() { 93 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 94 LOG(LS_INFO) << "~AudioSendStream: " << config_.ToString(); 95 channel_proxy_->SetCongestionControlObjects(nullptr, nullptr, nullptr); 96 } 97 98 void AudioSendStream::Start() { 99 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 100 } 101 102 void AudioSendStream::Stop() { 103 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 104 } 105 106 void AudioSendStream::SignalNetworkState(NetworkState state) { 107 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 108 } 109 110 bool AudioSendStream::DeliverRtcp(const uint8_t* packet, size_t length) { 111 // TODO(solenberg): Tests call this function on a network thread, libjingle 112 // calls on the worker thread. We should move towards always using a network 113 // thread. Then this check can be enabled. 114 // RTC_DCHECK(!thread_checker_.CalledOnValidThread()); 115 return false; 116 } 117 118 bool AudioSendStream::SendTelephoneEvent(int payload_type, uint8_t event, 119 uint32_t duration_ms) { 120 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 121 return channel_proxy_->SetSendTelephoneEventPayloadType(payload_type) && 122 channel_proxy_->SendTelephoneEventOutband(event, duration_ms); 123 } 124 125 webrtc::AudioSendStream::Stats AudioSendStream::GetStats() const { 126 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 127 webrtc::AudioSendStream::Stats stats; 128 stats.local_ssrc = config_.rtp.ssrc; 129 ScopedVoEInterface<VoEAudioProcessing> processing(voice_engine()); 130 ScopedVoEInterface<VoECodec> codec(voice_engine()); 131 ScopedVoEInterface<VoEVolumeControl> volume(voice_engine()); 132 133 webrtc::CallStatistics call_stats = channel_proxy_->GetRTCPStatistics(); 134 stats.bytes_sent = call_stats.bytesSent; 135 stats.packets_sent = call_stats.packetsSent; 136 // RTT isn't known until a RTCP report is received. Until then, VoiceEngine 137 // returns 0 to indicate an error value. 138 if (call_stats.rttMs > 0) { 139 stats.rtt_ms = call_stats.rttMs; 140 } 141 // TODO(solenberg): [was ajm]: Re-enable this metric once we have a reliable 142 // implementation. 143 stats.aec_quality_min = -1; 144 145 webrtc::CodecInst codec_inst = {0}; 146 if (codec->GetSendCodec(config_.voe_channel_id, codec_inst) != -1) { 147 RTC_DCHECK_NE(codec_inst.pltype, -1); 148 stats.codec_name = codec_inst.plname; 149 150 // Get data from the last remote RTCP report. 151 for (const auto& block : channel_proxy_->GetRemoteRTCPReportBlocks()) { 152 // Lookup report for send ssrc only. 153 if (block.source_SSRC == stats.local_ssrc) { 154 stats.packets_lost = block.cumulative_num_packets_lost; 155 stats.fraction_lost = Q8ToFloat(block.fraction_lost); 156 stats.ext_seqnum = block.extended_highest_sequence_number; 157 // Convert samples to milliseconds. 158 if (codec_inst.plfreq / 1000 > 0) { 159 stats.jitter_ms = 160 block.interarrival_jitter / (codec_inst.plfreq / 1000); 161 } 162 break; 163 } 164 } 165 } 166 167 // Local speech level. 168 { 169 unsigned int level = 0; 170 int error = volume->GetSpeechInputLevelFullRange(level); 171 RTC_DCHECK_EQ(0, error); 172 stats.audio_level = static_cast<int32_t>(level); 173 } 174 175 bool echo_metrics_on = false; 176 int error = processing->GetEcMetricsStatus(echo_metrics_on); 177 RTC_DCHECK_EQ(0, error); 178 if (echo_metrics_on) { 179 // These can also be negative, but in practice -1 is only used to signal 180 // insufficient data, since the resolution is limited to multiples of 4 ms. 181 int median = -1; 182 int std = -1; 183 float dummy = 0.0f; 184 error = processing->GetEcDelayMetrics(median, std, dummy); 185 RTC_DCHECK_EQ(0, error); 186 stats.echo_delay_median_ms = median; 187 stats.echo_delay_std_ms = std; 188 189 // These can take on valid negative values, so use the lowest possible level 190 // as default rather than -1. 191 int erl = -100; 192 int erle = -100; 193 int dummy1 = 0; 194 int dummy2 = 0; 195 error = processing->GetEchoMetrics(erl, erle, dummy1, dummy2); 196 RTC_DCHECK_EQ(0, error); 197 stats.echo_return_loss = erl; 198 stats.echo_return_loss_enhancement = erle; 199 } 200 201 internal::AudioState* audio_state = 202 static_cast<internal::AudioState*>(audio_state_.get()); 203 stats.typing_noise_detected = audio_state->typing_noise_detected(); 204 205 return stats; 206 } 207 208 const webrtc::AudioSendStream::Config& AudioSendStream::config() const { 209 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 210 return config_; 211 } 212 213 VoiceEngine* AudioSendStream::voice_engine() const { 214 internal::AudioState* audio_state = 215 static_cast<internal::AudioState*>(audio_state_.get()); 216 VoiceEngine* voice_engine = audio_state->voice_engine(); 217 RTC_DCHECK(voice_engine); 218 return voice_engine; 219 } 220 } // namespace internal 221 } // namespace webrtc 222