/* * Copyright (c) 2020 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. */ #include "audio/voip/audio_channel.h" #include #include #include "api/audio_codecs/audio_format.h" #include "api/task_queue/task_queue_factory.h" #include "modules/rtp_rtcp/include/receive_statistics.h" #include "modules/rtp_rtcp/source/rtp_rtcp_impl2.h" #include "rtc_base/location.h" #include "rtc_base/logging.h" namespace webrtc { namespace { constexpr int kRtcpReportIntervalMs = 5000; } // namespace AudioChannel::AudioChannel( Transport* transport, uint32_t local_ssrc, TaskQueueFactory* task_queue_factory, ProcessThread* process_thread, AudioMixer* audio_mixer, rtc::scoped_refptr decoder_factory) : audio_mixer_(audio_mixer), process_thread_(process_thread) { RTC_DCHECK(task_queue_factory); RTC_DCHECK(process_thread); RTC_DCHECK(audio_mixer); Clock* clock = Clock::GetRealTimeClock(); receive_statistics_ = ReceiveStatistics::Create(clock); RtpRtcpInterface::Configuration rtp_config; rtp_config.clock = clock; rtp_config.audio = true; rtp_config.receive_statistics = receive_statistics_.get(); rtp_config.rtcp_report_interval_ms = kRtcpReportIntervalMs; rtp_config.outgoing_transport = transport; rtp_config.local_media_ssrc = local_ssrc; rtp_rtcp_ = ModuleRtpRtcpImpl2::Create(rtp_config); rtp_rtcp_->SetSendingMediaStatus(false); rtp_rtcp_->SetRTCPStatus(RtcpMode::kCompound); // ProcessThread periodically services RTP stack for RTCP. process_thread_->RegisterModule(rtp_rtcp_.get(), RTC_FROM_HERE); ingress_ = std::make_unique(rtp_rtcp_.get(), clock, receive_statistics_.get(), std::move(decoder_factory)); egress_ = std::make_unique(rtp_rtcp_.get(), clock, task_queue_factory); // Set the instance of audio ingress to be part of audio mixer for ADM to // fetch audio samples to play. audio_mixer_->AddSource(ingress_.get()); } AudioChannel::~AudioChannel() { if (egress_->IsSending()) { StopSend(); } if (ingress_->IsPlaying()) { StopPlay(); } audio_mixer_->RemoveSource(ingress_.get()); // AudioEgress could hold current global TaskQueueBase that we need to clear // before ProcessThread::DeRegisterModule. egress_.reset(); ingress_.reset(); process_thread_->DeRegisterModule(rtp_rtcp_.get()); } bool AudioChannel::StartSend() { // If encoder has not been set, return false. if (!egress_->StartSend()) { return false; } // Start sending with RTP stack if it has not been sending yet. if (!rtp_rtcp_->Sending()) { rtp_rtcp_->SetSendingStatus(true); } return true; } void AudioChannel::StopSend() { egress_->StopSend(); // Deactivate RTP stack when both sending and receiving are stopped. // SetSendingStatus(false) triggers the transmission of RTCP BYE // message to remote endpoint. if (!ingress_->IsPlaying() && rtp_rtcp_->Sending()) { rtp_rtcp_->SetSendingStatus(false); } } bool AudioChannel::StartPlay() { // If decoders have not been set, return false. if (!ingress_->StartPlay()) { return false; } // If RTP stack is not sending then start sending as in recv-only mode, RTCP // receiver report is expected. if (!rtp_rtcp_->Sending()) { rtp_rtcp_->SetSendingStatus(true); } return true; } void AudioChannel::StopPlay() { ingress_->StopPlay(); // Deactivate RTP stack only when both sending and receiving are stopped. if (!rtp_rtcp_->SendingMedia() && rtp_rtcp_->Sending()) { rtp_rtcp_->SetSendingStatus(false); } } IngressStatistics AudioChannel::GetIngressStatistics() { IngressStatistics ingress_stats; NetworkStatistics stats = ingress_->GetNetworkStatistics(); ingress_stats.neteq_stats.total_samples_received = stats.totalSamplesReceived; ingress_stats.neteq_stats.concealed_samples = stats.concealedSamples; ingress_stats.neteq_stats.concealment_events = stats.concealmentEvents; ingress_stats.neteq_stats.jitter_buffer_delay_ms = stats.jitterBufferDelayMs; ingress_stats.neteq_stats.jitter_buffer_emitted_count = stats.jitterBufferEmittedCount; ingress_stats.neteq_stats.jitter_buffer_target_delay_ms = stats.jitterBufferTargetDelayMs; ingress_stats.neteq_stats.inserted_samples_for_deceleration = stats.insertedSamplesForDeceleration; ingress_stats.neteq_stats.removed_samples_for_acceleration = stats.removedSamplesForAcceleration; ingress_stats.neteq_stats.silent_concealed_samples = stats.silentConcealedSamples; ingress_stats.neteq_stats.fec_packets_received = stats.fecPacketsReceived; ingress_stats.neteq_stats.fec_packets_discarded = stats.fecPacketsDiscarded; ingress_stats.neteq_stats.delayed_packet_outage_samples = stats.delayedPacketOutageSamples; ingress_stats.neteq_stats.relative_packet_arrival_delay_ms = stats.relativePacketArrivalDelayMs; ingress_stats.neteq_stats.interruption_count = stats.interruptionCount; ingress_stats.neteq_stats.total_interruption_duration_ms = stats.totalInterruptionDurationMs; ingress_stats.total_duration = ingress_->GetOutputTotalDuration(); return ingress_stats; } ChannelStatistics AudioChannel::GetChannelStatistics() { ChannelStatistics channel_stat = ingress_->GetChannelStatistics(); StreamDataCounters rtp_stats, rtx_stats; rtp_rtcp_->GetSendStreamDataCounters(&rtp_stats, &rtx_stats); channel_stat.bytes_sent = rtp_stats.transmitted.payload_bytes + rtx_stats.transmitted.payload_bytes; channel_stat.packets_sent = rtp_stats.transmitted.packets + rtx_stats.transmitted.packets; return channel_stat; } } // namespace webrtc