xref: /aosp_15_r20/external/webrtc/audio/voip/audio_ingress.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "audio/voip/audio_ingress.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
14*d9f75844SAndroid Build Coastguard Worker #include <utility>
15*d9f75844SAndroid Build Coastguard Worker #include <vector>
16*d9f75844SAndroid Build Coastguard Worker 
17*d9f75844SAndroid Build Coastguard Worker #include "api/audio_codecs/audio_format.h"
18*d9f75844SAndroid Build Coastguard Worker #include "audio/utility/audio_frame_operations.h"
19*d9f75844SAndroid Build Coastguard Worker #include "modules/audio_coding/include/audio_coding_module.h"
20*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/byte_io.h"
21*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
22*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
23*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
24*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
25*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/numerics/safe_minmax.h"
26*d9f75844SAndroid Build Coastguard Worker 
27*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
28*d9f75844SAndroid Build Coastguard Worker 
29*d9f75844SAndroid Build Coastguard Worker namespace {
30*d9f75844SAndroid Build Coastguard Worker 
CreateAcmConfig(rtc::scoped_refptr<AudioDecoderFactory> decoder_factory)31*d9f75844SAndroid Build Coastguard Worker AudioCodingModule::Config CreateAcmConfig(
32*d9f75844SAndroid Build Coastguard Worker     rtc::scoped_refptr<AudioDecoderFactory> decoder_factory) {
33*d9f75844SAndroid Build Coastguard Worker   AudioCodingModule::Config acm_config;
34*d9f75844SAndroid Build Coastguard Worker   acm_config.neteq_config.enable_muted_state = true;
35*d9f75844SAndroid Build Coastguard Worker   acm_config.decoder_factory = decoder_factory;
36*d9f75844SAndroid Build Coastguard Worker   return acm_config;
37*d9f75844SAndroid Build Coastguard Worker }
38*d9f75844SAndroid Build Coastguard Worker 
39*d9f75844SAndroid Build Coastguard Worker }  // namespace
40*d9f75844SAndroid Build Coastguard Worker 
AudioIngress(RtpRtcpInterface * rtp_rtcp,Clock * clock,ReceiveStatistics * receive_statistics,rtc::scoped_refptr<AudioDecoderFactory> decoder_factory)41*d9f75844SAndroid Build Coastguard Worker AudioIngress::AudioIngress(
42*d9f75844SAndroid Build Coastguard Worker     RtpRtcpInterface* rtp_rtcp,
43*d9f75844SAndroid Build Coastguard Worker     Clock* clock,
44*d9f75844SAndroid Build Coastguard Worker     ReceiveStatistics* receive_statistics,
45*d9f75844SAndroid Build Coastguard Worker     rtc::scoped_refptr<AudioDecoderFactory> decoder_factory)
46*d9f75844SAndroid Build Coastguard Worker     : playing_(false),
47*d9f75844SAndroid Build Coastguard Worker       remote_ssrc_(0),
48*d9f75844SAndroid Build Coastguard Worker       first_rtp_timestamp_(-1),
49*d9f75844SAndroid Build Coastguard Worker       rtp_receive_statistics_(receive_statistics),
50*d9f75844SAndroid Build Coastguard Worker       rtp_rtcp_(rtp_rtcp),
51*d9f75844SAndroid Build Coastguard Worker       acm_receiver_(CreateAcmConfig(decoder_factory)),
52*d9f75844SAndroid Build Coastguard Worker       ntp_estimator_(clock) {}
53*d9f75844SAndroid Build Coastguard Worker 
54*d9f75844SAndroid Build Coastguard Worker AudioIngress::~AudioIngress() = default;
55*d9f75844SAndroid Build Coastguard Worker 
GetAudioFrameWithInfo(int sampling_rate,AudioFrame * audio_frame)56*d9f75844SAndroid Build Coastguard Worker AudioMixer::Source::AudioFrameInfo AudioIngress::GetAudioFrameWithInfo(
57*d9f75844SAndroid Build Coastguard Worker     int sampling_rate,
58*d9f75844SAndroid Build Coastguard Worker     AudioFrame* audio_frame) {
59*d9f75844SAndroid Build Coastguard Worker   audio_frame->sample_rate_hz_ = sampling_rate;
60*d9f75844SAndroid Build Coastguard Worker 
61*d9f75844SAndroid Build Coastguard Worker   // Get 10ms raw PCM data from the ACM.
62*d9f75844SAndroid Build Coastguard Worker   bool muted = false;
63*d9f75844SAndroid Build Coastguard Worker   if (acm_receiver_.GetAudio(sampling_rate, audio_frame, &muted) == -1) {
64*d9f75844SAndroid Build Coastguard Worker     RTC_DLOG(LS_ERROR) << "GetAudio() failed!";
65*d9f75844SAndroid Build Coastguard Worker     // In all likelihood, the audio in this frame is garbage. We return an
66*d9f75844SAndroid Build Coastguard Worker     // error so that the audio mixer module doesn't add it to the mix. As
67*d9f75844SAndroid Build Coastguard Worker     // a result, it won't be played out and the actions skipped here are
68*d9f75844SAndroid Build Coastguard Worker     // irrelevant.
69*d9f75844SAndroid Build Coastguard Worker     return AudioMixer::Source::AudioFrameInfo::kError;
70*d9f75844SAndroid Build Coastguard Worker   }
71*d9f75844SAndroid Build Coastguard Worker 
72*d9f75844SAndroid Build Coastguard Worker   if (muted) {
73*d9f75844SAndroid Build Coastguard Worker     AudioFrameOperations::Mute(audio_frame);
74*d9f75844SAndroid Build Coastguard Worker   }
75*d9f75844SAndroid Build Coastguard Worker 
76*d9f75844SAndroid Build Coastguard Worker   // Measure audio level.
77*d9f75844SAndroid Build Coastguard Worker   constexpr double kAudioSampleDurationSeconds = 0.01;
78*d9f75844SAndroid Build Coastguard Worker   output_audio_level_.ComputeLevel(*audio_frame, kAudioSampleDurationSeconds);
79*d9f75844SAndroid Build Coastguard Worker 
80*d9f75844SAndroid Build Coastguard Worker   // If caller invoked StopPlay(), then mute the frame.
81*d9f75844SAndroid Build Coastguard Worker   if (!playing_) {
82*d9f75844SAndroid Build Coastguard Worker     AudioFrameOperations::Mute(audio_frame);
83*d9f75844SAndroid Build Coastguard Worker     muted = true;
84*d9f75844SAndroid Build Coastguard Worker   }
85*d9f75844SAndroid Build Coastguard Worker 
86*d9f75844SAndroid Build Coastguard Worker   // Set first rtp timestamp with first audio frame with valid timestamp.
87*d9f75844SAndroid Build Coastguard Worker   if (first_rtp_timestamp_ < 0 && audio_frame->timestamp_ != 0) {
88*d9f75844SAndroid Build Coastguard Worker     first_rtp_timestamp_ = audio_frame->timestamp_;
89*d9f75844SAndroid Build Coastguard Worker   }
90*d9f75844SAndroid Build Coastguard Worker 
91*d9f75844SAndroid Build Coastguard Worker   if (first_rtp_timestamp_ >= 0) {
92*d9f75844SAndroid Build Coastguard Worker     // Compute elapsed and NTP times.
93*d9f75844SAndroid Build Coastguard Worker     int64_t unwrap_timestamp;
94*d9f75844SAndroid Build Coastguard Worker     {
95*d9f75844SAndroid Build Coastguard Worker       MutexLock lock(&lock_);
96*d9f75844SAndroid Build Coastguard Worker       unwrap_timestamp =
97*d9f75844SAndroid Build Coastguard Worker           timestamp_wrap_handler_.Unwrap(audio_frame->timestamp_);
98*d9f75844SAndroid Build Coastguard Worker       audio_frame->ntp_time_ms_ =
99*d9f75844SAndroid Build Coastguard Worker           ntp_estimator_.Estimate(audio_frame->timestamp_);
100*d9f75844SAndroid Build Coastguard Worker     }
101*d9f75844SAndroid Build Coastguard Worker     // For clock rate, default to the playout sampling rate if we haven't
102*d9f75844SAndroid Build Coastguard Worker     // received any packets yet.
103*d9f75844SAndroid Build Coastguard Worker     absl::optional<std::pair<int, SdpAudioFormat>> decoder =
104*d9f75844SAndroid Build Coastguard Worker         acm_receiver_.LastDecoder();
105*d9f75844SAndroid Build Coastguard Worker     int clock_rate = decoder ? decoder->second.clockrate_hz
106*d9f75844SAndroid Build Coastguard Worker                              : acm_receiver_.last_output_sample_rate_hz();
107*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_GT(clock_rate, 0);
108*d9f75844SAndroid Build Coastguard Worker     audio_frame->elapsed_time_ms_ =
109*d9f75844SAndroid Build Coastguard Worker         (unwrap_timestamp - first_rtp_timestamp_) / (clock_rate / 1000);
110*d9f75844SAndroid Build Coastguard Worker   }
111*d9f75844SAndroid Build Coastguard Worker 
112*d9f75844SAndroid Build Coastguard Worker   return muted ? AudioMixer::Source::AudioFrameInfo::kMuted
113*d9f75844SAndroid Build Coastguard Worker                : AudioMixer::Source::AudioFrameInfo::kNormal;
114*d9f75844SAndroid Build Coastguard Worker }
115*d9f75844SAndroid Build Coastguard Worker 
StartPlay()116*d9f75844SAndroid Build Coastguard Worker bool AudioIngress::StartPlay() {
117*d9f75844SAndroid Build Coastguard Worker   {
118*d9f75844SAndroid Build Coastguard Worker     MutexLock lock(&lock_);
119*d9f75844SAndroid Build Coastguard Worker     if (receive_codec_info_.empty()) {
120*d9f75844SAndroid Build Coastguard Worker       RTC_DLOG(LS_WARNING) << "Receive codecs have not been set yet";
121*d9f75844SAndroid Build Coastguard Worker       return false;
122*d9f75844SAndroid Build Coastguard Worker     }
123*d9f75844SAndroid Build Coastguard Worker   }
124*d9f75844SAndroid Build Coastguard Worker   playing_ = true;
125*d9f75844SAndroid Build Coastguard Worker   return true;
126*d9f75844SAndroid Build Coastguard Worker }
127*d9f75844SAndroid Build Coastguard Worker 
SetReceiveCodecs(const std::map<int,SdpAudioFormat> & codecs)128*d9f75844SAndroid Build Coastguard Worker void AudioIngress::SetReceiveCodecs(
129*d9f75844SAndroid Build Coastguard Worker     const std::map<int, SdpAudioFormat>& codecs) {
130*d9f75844SAndroid Build Coastguard Worker   {
131*d9f75844SAndroid Build Coastguard Worker     MutexLock lock(&lock_);
132*d9f75844SAndroid Build Coastguard Worker     for (const auto& kv : codecs) {
133*d9f75844SAndroid Build Coastguard Worker       receive_codec_info_[kv.first] = kv.second.clockrate_hz;
134*d9f75844SAndroid Build Coastguard Worker     }
135*d9f75844SAndroid Build Coastguard Worker   }
136*d9f75844SAndroid Build Coastguard Worker   acm_receiver_.SetCodecs(codecs);
137*d9f75844SAndroid Build Coastguard Worker }
138*d9f75844SAndroid Build Coastguard Worker 
ReceivedRTPPacket(rtc::ArrayView<const uint8_t> rtp_packet)139*d9f75844SAndroid Build Coastguard Worker void AudioIngress::ReceivedRTPPacket(rtc::ArrayView<const uint8_t> rtp_packet) {
140*d9f75844SAndroid Build Coastguard Worker   RtpPacketReceived rtp_packet_received;
141*d9f75844SAndroid Build Coastguard Worker   rtp_packet_received.Parse(rtp_packet.data(), rtp_packet.size());
142*d9f75844SAndroid Build Coastguard Worker 
143*d9f75844SAndroid Build Coastguard Worker   // Set payload type's sampling rate before we feed it into ReceiveStatistics.
144*d9f75844SAndroid Build Coastguard Worker   {
145*d9f75844SAndroid Build Coastguard Worker     MutexLock lock(&lock_);
146*d9f75844SAndroid Build Coastguard Worker     const auto& it =
147*d9f75844SAndroid Build Coastguard Worker         receive_codec_info_.find(rtp_packet_received.PayloadType());
148*d9f75844SAndroid Build Coastguard Worker     // If sampling rate info is not available in our received codec set, it
149*d9f75844SAndroid Build Coastguard Worker     // would mean that remote media endpoint is sending incorrect payload id
150*d9f75844SAndroid Build Coastguard Worker     // which can't be processed correctly especially on payload type id in
151*d9f75844SAndroid Build Coastguard Worker     // dynamic range.
152*d9f75844SAndroid Build Coastguard Worker     if (it == receive_codec_info_.end()) {
153*d9f75844SAndroid Build Coastguard Worker       RTC_DLOG(LS_WARNING) << "Unexpected payload id received: "
154*d9f75844SAndroid Build Coastguard Worker                            << rtp_packet_received.PayloadType();
155*d9f75844SAndroid Build Coastguard Worker       return;
156*d9f75844SAndroid Build Coastguard Worker     }
157*d9f75844SAndroid Build Coastguard Worker     rtp_packet_received.set_payload_type_frequency(it->second);
158*d9f75844SAndroid Build Coastguard Worker   }
159*d9f75844SAndroid Build Coastguard Worker 
160*d9f75844SAndroid Build Coastguard Worker   // Track current remote SSRC.
161*d9f75844SAndroid Build Coastguard Worker   if (rtp_packet_received.Ssrc() != remote_ssrc_) {
162*d9f75844SAndroid Build Coastguard Worker     rtp_rtcp_->SetRemoteSSRC(rtp_packet_received.Ssrc());
163*d9f75844SAndroid Build Coastguard Worker     remote_ssrc_.store(rtp_packet_received.Ssrc());
164*d9f75844SAndroid Build Coastguard Worker   }
165*d9f75844SAndroid Build Coastguard Worker 
166*d9f75844SAndroid Build Coastguard Worker   rtp_receive_statistics_->OnRtpPacket(rtp_packet_received);
167*d9f75844SAndroid Build Coastguard Worker 
168*d9f75844SAndroid Build Coastguard Worker   RTPHeader header;
169*d9f75844SAndroid Build Coastguard Worker   rtp_packet_received.GetHeader(&header);
170*d9f75844SAndroid Build Coastguard Worker 
171*d9f75844SAndroid Build Coastguard Worker   size_t packet_length = rtp_packet_received.size();
172*d9f75844SAndroid Build Coastguard Worker   if (packet_length < header.headerLength ||
173*d9f75844SAndroid Build Coastguard Worker       (packet_length - header.headerLength) < header.paddingLength) {
174*d9f75844SAndroid Build Coastguard Worker     RTC_DLOG(LS_ERROR) << "Packet length(" << packet_length << ") header("
175*d9f75844SAndroid Build Coastguard Worker                        << header.headerLength << ") padding("
176*d9f75844SAndroid Build Coastguard Worker                        << header.paddingLength << ")";
177*d9f75844SAndroid Build Coastguard Worker     return;
178*d9f75844SAndroid Build Coastguard Worker   }
179*d9f75844SAndroid Build Coastguard Worker 
180*d9f75844SAndroid Build Coastguard Worker   const uint8_t* payload = rtp_packet_received.data() + header.headerLength;
181*d9f75844SAndroid Build Coastguard Worker   size_t payload_length = packet_length - header.headerLength;
182*d9f75844SAndroid Build Coastguard Worker   size_t payload_data_length = payload_length - header.paddingLength;
183*d9f75844SAndroid Build Coastguard Worker   auto data_view = rtc::ArrayView<const uint8_t>(payload, payload_data_length);
184*d9f75844SAndroid Build Coastguard Worker 
185*d9f75844SAndroid Build Coastguard Worker   // Push the incoming payload (parsed and ready for decoding) into the ACM.
186*d9f75844SAndroid Build Coastguard Worker   if (acm_receiver_.InsertPacket(header, data_view) != 0) {
187*d9f75844SAndroid Build Coastguard Worker     RTC_DLOG(LS_ERROR) << "AudioIngress::ReceivedRTPPacket() unable to "
188*d9f75844SAndroid Build Coastguard Worker                           "push data to the ACM";
189*d9f75844SAndroid Build Coastguard Worker   }
190*d9f75844SAndroid Build Coastguard Worker }
191*d9f75844SAndroid Build Coastguard Worker 
ReceivedRTCPPacket(rtc::ArrayView<const uint8_t> rtcp_packet)192*d9f75844SAndroid Build Coastguard Worker void AudioIngress::ReceivedRTCPPacket(
193*d9f75844SAndroid Build Coastguard Worker     rtc::ArrayView<const uint8_t> rtcp_packet) {
194*d9f75844SAndroid Build Coastguard Worker   rtcp::CommonHeader rtcp_header;
195*d9f75844SAndroid Build Coastguard Worker   if (rtcp_header.Parse(rtcp_packet.data(), rtcp_packet.size()) &&
196*d9f75844SAndroid Build Coastguard Worker       (rtcp_header.type() == rtcp::SenderReport::kPacketType ||
197*d9f75844SAndroid Build Coastguard Worker        rtcp_header.type() == rtcp::ReceiverReport::kPacketType)) {
198*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_GE(rtcp_packet.size(), 8);
199*d9f75844SAndroid Build Coastguard Worker 
200*d9f75844SAndroid Build Coastguard Worker     uint32_t sender_ssrc =
201*d9f75844SAndroid Build Coastguard Worker         ByteReader<uint32_t>::ReadBigEndian(rtcp_packet.data() + 4);
202*d9f75844SAndroid Build Coastguard Worker 
203*d9f75844SAndroid Build Coastguard Worker     // If we don't have remote ssrc at this point, it's likely that remote
204*d9f75844SAndroid Build Coastguard Worker     // endpoint is receive-only or it could have restarted the media.
205*d9f75844SAndroid Build Coastguard Worker     if (sender_ssrc != remote_ssrc_) {
206*d9f75844SAndroid Build Coastguard Worker       rtp_rtcp_->SetRemoteSSRC(sender_ssrc);
207*d9f75844SAndroid Build Coastguard Worker       remote_ssrc_.store(sender_ssrc);
208*d9f75844SAndroid Build Coastguard Worker     }
209*d9f75844SAndroid Build Coastguard Worker   }
210*d9f75844SAndroid Build Coastguard Worker 
211*d9f75844SAndroid Build Coastguard Worker   // Deliver RTCP packet to RTP/RTCP module for parsing and processing.
212*d9f75844SAndroid Build Coastguard Worker   rtp_rtcp_->IncomingRtcpPacket(rtcp_packet.data(), rtcp_packet.size());
213*d9f75844SAndroid Build Coastguard Worker 
214*d9f75844SAndroid Build Coastguard Worker   int64_t rtt = 0;
215*d9f75844SAndroid Build Coastguard Worker   if (rtp_rtcp_->RTT(remote_ssrc_, &rtt, nullptr, nullptr, nullptr) != 0) {
216*d9f75844SAndroid Build Coastguard Worker     // Waiting for valid RTT.
217*d9f75844SAndroid Build Coastguard Worker     return;
218*d9f75844SAndroid Build Coastguard Worker   }
219*d9f75844SAndroid Build Coastguard Worker 
220*d9f75844SAndroid Build Coastguard Worker   uint32_t ntp_secs = 0, ntp_frac = 0, rtp_timestamp = 0;
221*d9f75844SAndroid Build Coastguard Worker   if (rtp_rtcp_->RemoteNTP(&ntp_secs, &ntp_frac, nullptr, nullptr,
222*d9f75844SAndroid Build Coastguard Worker                            &rtp_timestamp) != 0) {
223*d9f75844SAndroid Build Coastguard Worker     // Waiting for RTCP.
224*d9f75844SAndroid Build Coastguard Worker     return;
225*d9f75844SAndroid Build Coastguard Worker   }
226*d9f75844SAndroid Build Coastguard Worker 
227*d9f75844SAndroid Build Coastguard Worker   {
228*d9f75844SAndroid Build Coastguard Worker     MutexLock lock(&lock_);
229*d9f75844SAndroid Build Coastguard Worker     ntp_estimator_.UpdateRtcpTimestamp(
230*d9f75844SAndroid Build Coastguard Worker         TimeDelta::Millis(rtt), NtpTime(ntp_secs, ntp_frac), rtp_timestamp);
231*d9f75844SAndroid Build Coastguard Worker   }
232*d9f75844SAndroid Build Coastguard Worker }
233*d9f75844SAndroid Build Coastguard Worker 
GetChannelStatistics()234*d9f75844SAndroid Build Coastguard Worker ChannelStatistics AudioIngress::GetChannelStatistics() {
235*d9f75844SAndroid Build Coastguard Worker   ChannelStatistics channel_stats;
236*d9f75844SAndroid Build Coastguard Worker 
237*d9f75844SAndroid Build Coastguard Worker   // Get clockrate for current decoder ahead of jitter calculation.
238*d9f75844SAndroid Build Coastguard Worker   uint32_t clockrate_hz = 0;
239*d9f75844SAndroid Build Coastguard Worker   absl::optional<std::pair<int, SdpAudioFormat>> decoder =
240*d9f75844SAndroid Build Coastguard Worker       acm_receiver_.LastDecoder();
241*d9f75844SAndroid Build Coastguard Worker   if (decoder) {
242*d9f75844SAndroid Build Coastguard Worker     clockrate_hz = decoder->second.clockrate_hz;
243*d9f75844SAndroid Build Coastguard Worker   }
244*d9f75844SAndroid Build Coastguard Worker 
245*d9f75844SAndroid Build Coastguard Worker   StreamStatistician* statistician =
246*d9f75844SAndroid Build Coastguard Worker       rtp_receive_statistics_->GetStatistician(remote_ssrc_);
247*d9f75844SAndroid Build Coastguard Worker   if (statistician) {
248*d9f75844SAndroid Build Coastguard Worker     RtpReceiveStats stats = statistician->GetStats();
249*d9f75844SAndroid Build Coastguard Worker     channel_stats.packets_lost = stats.packets_lost;
250*d9f75844SAndroid Build Coastguard Worker     channel_stats.packets_received = stats.packet_counter.packets;
251*d9f75844SAndroid Build Coastguard Worker     channel_stats.bytes_received = stats.packet_counter.payload_bytes;
252*d9f75844SAndroid Build Coastguard Worker     channel_stats.remote_ssrc = remote_ssrc_;
253*d9f75844SAndroid Build Coastguard Worker     if (clockrate_hz > 0) {
254*d9f75844SAndroid Build Coastguard Worker       channel_stats.jitter = static_cast<double>(stats.jitter) / clockrate_hz;
255*d9f75844SAndroid Build Coastguard Worker     }
256*d9f75844SAndroid Build Coastguard Worker   }
257*d9f75844SAndroid Build Coastguard Worker 
258*d9f75844SAndroid Build Coastguard Worker   // Get RTCP report using remote SSRC.
259*d9f75844SAndroid Build Coastguard Worker   const std::vector<ReportBlockData>& report_data =
260*d9f75844SAndroid Build Coastguard Worker       rtp_rtcp_->GetLatestReportBlockData();
261*d9f75844SAndroid Build Coastguard Worker   for (const ReportBlockData& block_data : report_data) {
262*d9f75844SAndroid Build Coastguard Worker     const RTCPReportBlock& rtcp_report = block_data.report_block();
263*d9f75844SAndroid Build Coastguard Worker     if (rtp_rtcp_->SSRC() != rtcp_report.source_ssrc ||
264*d9f75844SAndroid Build Coastguard Worker         remote_ssrc_ != rtcp_report.sender_ssrc) {
265*d9f75844SAndroid Build Coastguard Worker       continue;
266*d9f75844SAndroid Build Coastguard Worker     }
267*d9f75844SAndroid Build Coastguard Worker     RemoteRtcpStatistics remote_stat;
268*d9f75844SAndroid Build Coastguard Worker     remote_stat.packets_lost = rtcp_report.packets_lost;
269*d9f75844SAndroid Build Coastguard Worker     remote_stat.fraction_lost =
270*d9f75844SAndroid Build Coastguard Worker         static_cast<double>(rtcp_report.fraction_lost) / (1 << 8);
271*d9f75844SAndroid Build Coastguard Worker     if (clockrate_hz > 0) {
272*d9f75844SAndroid Build Coastguard Worker       remote_stat.jitter =
273*d9f75844SAndroid Build Coastguard Worker           static_cast<double>(rtcp_report.jitter) / clockrate_hz;
274*d9f75844SAndroid Build Coastguard Worker     }
275*d9f75844SAndroid Build Coastguard Worker     if (block_data.has_rtt()) {
276*d9f75844SAndroid Build Coastguard Worker       remote_stat.round_trip_time =
277*d9f75844SAndroid Build Coastguard Worker           static_cast<double>(block_data.last_rtt_ms()) /
278*d9f75844SAndroid Build Coastguard Worker           rtc::kNumMillisecsPerSec;
279*d9f75844SAndroid Build Coastguard Worker     }
280*d9f75844SAndroid Build Coastguard Worker     remote_stat.last_report_received_timestamp_ms =
281*d9f75844SAndroid Build Coastguard Worker         block_data.report_block_timestamp_utc_us() /
282*d9f75844SAndroid Build Coastguard Worker         rtc::kNumMicrosecsPerMillisec;
283*d9f75844SAndroid Build Coastguard Worker     channel_stats.remote_rtcp = remote_stat;
284*d9f75844SAndroid Build Coastguard Worker 
285*d9f75844SAndroid Build Coastguard Worker     // Receive only channel won't send any RTP packets.
286*d9f75844SAndroid Build Coastguard Worker     if (!channel_stats.remote_ssrc.has_value()) {
287*d9f75844SAndroid Build Coastguard Worker       channel_stats.remote_ssrc = remote_ssrc_;
288*d9f75844SAndroid Build Coastguard Worker     }
289*d9f75844SAndroid Build Coastguard Worker     break;
290*d9f75844SAndroid Build Coastguard Worker   }
291*d9f75844SAndroid Build Coastguard Worker 
292*d9f75844SAndroid Build Coastguard Worker   return channel_stats;
293*d9f75844SAndroid Build Coastguard Worker }
294*d9f75844SAndroid Build Coastguard Worker 
295*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
296