Home | History | Annotate | Download | only in audio
      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