33c44f83cbe995372da40ae9983c48196dc678d7
[WebKit-https.git] / Source / WebCore / Modules / mediastream / libwebrtc / LibWebRTCStatsCollector.cpp
1 /*
2  * Copyright (C) 2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26 #include "LibWebRTCStatsCollector.h"
27
28 #if USE(LIBWEBRTC)
29
30 #include "JSDOMMapLike.h"
31 #include "JSRTCStatsReport.h"
32 #include "Performance.h"
33 #include <wtf/MainThread.h>
34
35 namespace WebCore {
36
37 LibWebRTCStatsCollector::LibWebRTCStatsCollector(CollectorCallback&& callback)
38     : m_callback(WTFMove(callback))
39 {
40 }
41
42 LibWebRTCStatsCollector::~LibWebRTCStatsCollector()
43 {
44     if (!m_callback)
45         return;
46
47     callOnMainThread([callback = WTFMove(m_callback)]() mutable {
48         callback(nullptr);
49     });
50 }
51
52 static inline String fromStdString(const std::string& value)
53 {
54     return String::fromUTF8(value.data(), value.length());
55 }
56
57 static inline void fillRTCStats(RTCStatsReport::Stats& stats, const webrtc::RTCStats& rtcStats)
58 {
59     stats.timestamp = Performance::reduceTimeResolution(Seconds::fromMicroseconds(rtcStats.timestamp_us())).milliseconds();
60     stats.id = fromStdString(rtcStats.id());
61 }
62
63 static inline void fillRTCRTPStreamStats(RTCStatsReport::RTCRTPStreamStats& stats, const webrtc::RTCRTPStreamStats& rtcStats)
64 {
65     fillRTCStats(stats, rtcStats);
66
67     if (rtcStats.ssrc.is_defined())
68         stats.ssrc = *rtcStats.ssrc;
69     if (rtcStats.is_remote.is_defined())
70         stats.isRemote = *rtcStats.is_remote;
71     if (rtcStats.media_type.is_defined())
72         stats.mediaType = fromStdString(*rtcStats.media_type);
73     if (rtcStats.track_id.is_defined())
74         stats.trackId = fromStdString(*rtcStats.track_id);
75     if (rtcStats.transport_id.is_defined())
76         stats.transportId = fromStdString(*rtcStats.transport_id);
77     if (rtcStats.codec_id.is_defined())
78         stats.codecId = fromStdString(*rtcStats.codec_id);
79     if (rtcStats.fir_count.is_defined())
80         stats.firCount = *rtcStats.fir_count;
81     if (rtcStats.pli_count.is_defined())
82         stats.pliCount = *rtcStats.pli_count;
83     if (rtcStats.nack_count.is_defined())
84         stats.nackCount = *rtcStats.nack_count;
85     if (rtcStats.sli_count.is_defined())
86         stats.sliCount = *rtcStats.sli_count;
87     if (rtcStats.qp_sum.is_defined())
88         stats.qpSum = *rtcStats.qp_sum;
89     stats.qpSum = 0;
90 }
91
92 static inline void fillInboundRTPStreamStats(RTCStatsReport::InboundRTPStreamStats& stats, const webrtc::RTCInboundRTPStreamStats& rtcStats)
93 {
94     fillRTCRTPStreamStats(stats, rtcStats);
95
96     // FIXME: Add support for decoder_implementation
97     if (rtcStats.packets_received.is_defined())
98         stats.packetsReceived = *rtcStats.packets_received;
99     if (rtcStats.bytes_received.is_defined())
100         stats.bytesReceived = *rtcStats.bytes_received;
101     if (rtcStats.packets_lost.is_defined())
102         stats.packetsLost = *rtcStats.packets_lost;
103     if (rtcStats.jitter.is_defined())
104         stats.jitter = *rtcStats.jitter;
105     // FIXME: Add support back for fractionLost.
106     if (rtcStats.packets_discarded.is_defined())
107         stats.packetsDiscarded = *rtcStats.packets_discarded;
108     if (rtcStats.packets_repaired.is_defined())
109         stats.packetsRepaired = *rtcStats.packets_repaired;
110     if (rtcStats.burst_packets_lost.is_defined())
111         stats.burstPacketsLost = *rtcStats.burst_packets_lost;
112     if (rtcStats.burst_packets_discarded.is_defined())
113         stats.burstPacketsDiscarded = *rtcStats.burst_packets_discarded;
114     if (rtcStats.burst_loss_count.is_defined())
115         stats.burstLossCount = *rtcStats.burst_loss_count;
116     if (rtcStats.burst_discard_count.is_defined())
117         stats.burstDiscardCount = *rtcStats.burst_discard_count;
118     if (rtcStats.burst_loss_rate.is_defined())
119         stats.burstLossRate = *rtcStats.burst_loss_rate;
120     if (rtcStats.burst_discard_rate.is_defined())
121         stats.burstDiscardRate = *rtcStats.burst_discard_rate;
122     if (rtcStats.gap_loss_rate.is_defined())
123         stats.gapLossRate = *rtcStats.gap_loss_rate;
124     if (rtcStats.gap_discard_rate.is_defined())
125         stats.gapDiscardRate = *rtcStats.gap_discard_rate;
126     if (rtcStats.frames_decoded.is_defined())
127         stats.framesDecoded = *rtcStats.frames_decoded;
128 }
129
130 static inline void fillOutboundRTPStreamStats(RTCStatsReport::OutboundRTPStreamStats& stats, const webrtc::RTCOutboundRTPStreamStats& rtcStats)
131 {
132     fillRTCRTPStreamStats(stats, rtcStats);
133
134     // FIXME: Add support for encoder_implementation
135     if (rtcStats.packets_sent.is_defined())
136         stats.packetsSent = *rtcStats.packets_sent;
137     if (rtcStats.bytes_sent.is_defined())
138         stats.bytesSent = *rtcStats.bytes_sent;
139     if (rtcStats.target_bitrate.is_defined())
140         stats.targetBitrate = *rtcStats.target_bitrate;
141     if (rtcStats.frames_encoded.is_defined())
142         stats.framesEncoded = *rtcStats.frames_encoded;
143 }
144
145 static inline void fillRTCMediaStreamTrackStats(RTCStatsReport::MediaStreamTrackStats& stats, const webrtc::RTCMediaStreamTrackStats& rtcStats)
146 {
147     fillRTCStats(stats, rtcStats);
148
149     if (rtcStats.track_identifier.is_defined())
150         stats.trackIdentifier = fromStdString(*rtcStats.track_identifier);
151     if (rtcStats.remote_source.is_defined())
152         stats.remoteSource = *rtcStats.remote_source;
153     if (rtcStats.ended.is_defined())
154         stats.ended = *rtcStats.ended;
155     if (rtcStats.detached.is_defined())
156         stats.detached = *rtcStats.detached;
157     if (rtcStats.frame_width.is_defined())
158         stats.frameWidth = *rtcStats.frame_width;
159     if (rtcStats.frame_height.is_defined())
160         stats.frameHeight = *rtcStats.frame_height;
161     if (rtcStats.frames_per_second.is_defined())
162         stats.framesPerSecond = *rtcStats.frames_per_second;
163     if (rtcStats.frames_sent.is_defined())
164         stats.framesSent = *rtcStats.frames_sent;
165     if (rtcStats.frames_received.is_defined())
166         stats.framesReceived = *rtcStats.frames_received;
167     if (rtcStats.frames_decoded.is_defined())
168         stats.framesDecoded = *rtcStats.frames_decoded;
169     if (rtcStats.frames_dropped.is_defined())
170         stats.framesDropped = *rtcStats.frames_dropped;
171     if (rtcStats.partial_frames_lost.is_defined())
172         stats.partialFramesLost = *rtcStats.partial_frames_lost;
173     if (rtcStats.full_frames_lost.is_defined())
174         stats.fullFramesLost = *rtcStats.full_frames_lost;
175     if (rtcStats.audio_level.is_defined())
176         stats.audioLevel = *rtcStats.audio_level;
177     if (rtcStats.echo_return_loss.is_defined())
178         stats.echoReturnLoss = *rtcStats.echo_return_loss;
179     if (rtcStats.echo_return_loss_enhancement.is_defined())
180         stats.echoReturnLossEnhancement = *rtcStats.echo_return_loss_enhancement;
181 }
182
183 static inline void fillRTCDataChannelStats(RTCStatsReport::DataChannelStats& stats, const webrtc::RTCDataChannelStats& rtcStats)
184 {
185     fillRTCStats(stats, rtcStats);
186
187     if (rtcStats.label.is_defined())
188         stats.label = fromStdString(*rtcStats.label);
189     if (rtcStats.protocol.is_defined())
190         stats.protocol = fromStdString(*rtcStats.protocol);
191     if (rtcStats.datachannelid.is_defined())
192         stats.datachannelid = *rtcStats.datachannelid;
193     if (rtcStats.state.is_defined())
194         stats.state = fromStdString(*rtcStats.state);
195     if (rtcStats.messages_sent.is_defined())
196         stats.messagesSent = *rtcStats.messages_sent;
197     if (rtcStats.bytes_sent.is_defined())
198         stats.bytesSent = *rtcStats.bytes_sent;
199     if (rtcStats.messages_received.is_defined())
200         stats.messagesReceived = *rtcStats.messages_received;
201     if (rtcStats.bytes_received.is_defined())
202         stats.bytesReceived = *rtcStats.bytes_received;
203 }
204
205 static inline RTCStatsReport::IceCandidatePairState iceCandidatePairState(const std::string& state)
206 {
207     if (state == "frozen")
208         return RTCStatsReport::IceCandidatePairState::Frozen;
209     if (state == "waiting")
210         return RTCStatsReport::IceCandidatePairState::Waiting;
211     if (state == "in-progress")
212         return RTCStatsReport::IceCandidatePairState::Inprogress;
213     if (state == "failed")
214         return RTCStatsReport::IceCandidatePairState::Failed;
215     if (state == "succeeded")
216         return RTCStatsReport::IceCandidatePairState::Succeeded;
217     if (state == "cancelled")
218         return RTCStatsReport::IceCandidatePairState::Cancelled;
219     ASSERT_NOT_REACHED();
220     return RTCStatsReport::IceCandidatePairState::Frozen;
221 }
222
223 static inline void fillRTCIceCandidatePairStats(RTCStatsReport::IceCandidatePairStats& stats, const webrtc::RTCIceCandidatePairStats& rtcStats)
224 {
225     fillRTCStats(stats, rtcStats);
226
227     if (rtcStats.transport_id.is_defined())
228         stats.transportId = fromStdString(*rtcStats.transport_id);
229     if (rtcStats.local_candidate_id.is_defined())
230         stats.localCandidateId = fromStdString(*rtcStats.local_candidate_id);
231     if (rtcStats.remote_candidate_id.is_defined())
232         stats.remoteCandidateId = fromStdString(*rtcStats.remote_candidate_id);
233     if (rtcStats.state.is_defined())
234         stats.state = iceCandidatePairState(*rtcStats.state);
235
236     if (rtcStats.priority.is_defined())
237         stats.priority = *rtcStats.priority;
238     if (rtcStats.nominated.is_defined())
239         stats.nominated = *rtcStats.nominated;
240     if (rtcStats.writable.is_defined())
241         stats.writable = *rtcStats.writable;
242     if (rtcStats.readable.is_defined())
243         stats.readable = *rtcStats.readable;
244
245     if (rtcStats.bytes_sent.is_defined())
246         stats.bytesSent = *rtcStats.bytes_sent;
247     if (rtcStats.bytes_received.is_defined())
248         stats.bytesReceived = *rtcStats.bytes_received;
249     if (rtcStats.total_round_trip_time.is_defined())
250         stats.totalRoundTripTime = *rtcStats.total_round_trip_time;
251     if (rtcStats.current_round_trip_time.is_defined())
252         stats.currentRoundTripTime = *rtcStats.current_round_trip_time;
253     if (rtcStats.available_outgoing_bitrate.is_defined())
254         stats.availableOutgoingBitrate = *rtcStats.available_outgoing_bitrate;
255     if (rtcStats.available_incoming_bitrate.is_defined())
256         stats.availableIncomingBitrate = *rtcStats.available_incoming_bitrate;
257
258     if (rtcStats.requests_received.is_defined())
259         stats.requestsReceived = *rtcStats.requests_received;
260     if (rtcStats.requests_sent.is_defined())
261         stats.requestsSent = *rtcStats.requests_sent;
262     if (rtcStats.responses_received.is_defined())
263         stats.responsesReceived = *rtcStats.responses_received;
264     if (rtcStats.responses_sent.is_defined())
265         stats.responsesSent = *rtcStats.responses_sent;
266
267     if (rtcStats.requests_received.is_defined())
268         stats.retransmissionsReceived = *rtcStats.requests_received;
269     if (rtcStats.requests_sent.is_defined())
270         stats.retransmissionsSent = *rtcStats.requests_sent;
271     if (rtcStats.responses_received.is_defined())
272         stats.consentRequestsReceived = *rtcStats.responses_received;
273     if (rtcStats.responses_sent.is_defined())
274         stats.consentRequestsSent = *rtcStats.responses_sent;
275     if (rtcStats.responses_received.is_defined())
276         stats.consentResponsesReceived = *rtcStats.responses_received;
277     if (rtcStats.responses_sent.is_defined())
278         stats.consentResponsesSent = *rtcStats.responses_sent;
279 }
280
281 static inline Optional<RTCStatsReport::IceCandidateType> iceCandidateState(const std::string& state)
282 {
283     if (state == "host")
284         return RTCStatsReport::IceCandidateType::Host;
285     if (state == "srflx")
286         return RTCStatsReport::IceCandidateType::Srflx;
287     if (state == "prflx")
288         return RTCStatsReport::IceCandidateType::Prflx;
289     if (state == "relay")
290         return RTCStatsReport::IceCandidateType::Relay;
291
292     return { };
293 }
294
295 static inline void fillRTCIceCandidateStats(RTCStatsReport::IceCandidateStats& stats, const webrtc::RTCIceCandidateStats& rtcStats)
296 {
297     stats.type = rtcStats.type() == webrtc::RTCRemoteIceCandidateStats::kType ? RTCStatsReport::Type::RemoteCandidate : RTCStatsReport::Type::LocalCandidate;
298
299     fillRTCStats(stats, rtcStats);
300
301     if (rtcStats.transport_id.is_defined())
302         stats.transportId = fromStdString(*rtcStats.transport_id);
303     if (rtcStats.ip.is_defined())
304         stats.address = fromStdString(*rtcStats.ip);
305     if (rtcStats.port.is_defined())
306         stats.port = *rtcStats.port;
307     if (rtcStats.protocol.is_defined())
308         stats.protocol = fromStdString(*rtcStats.protocol);
309
310     if (rtcStats.candidate_type.is_defined())
311         stats.candidateType = iceCandidateState(*rtcStats.candidate_type);
312
313     if (!stats.candidateType || stats.candidateType == RTCStatsReport::IceCandidateType::Prflx || stats.candidateType == RTCStatsReport::IceCandidateType::Host)
314         stats.address = { };
315
316     if (rtcStats.priority.is_defined())
317         stats.priority = *rtcStats.priority;
318     if (rtcStats.url.is_defined())
319         stats.url = fromStdString(*rtcStats.url);
320     if (rtcStats.deleted.is_defined())
321         stats.deleted = *rtcStats.deleted;
322 }
323
324 static inline void fillRTCCertificateStats(RTCStatsReport::CertificateStats& stats, const webrtc::RTCCertificateStats& rtcStats)
325 {
326     fillRTCStats(stats, rtcStats);
327
328     if (rtcStats.fingerprint.is_defined())
329         stats.fingerprint = fromStdString(*rtcStats.fingerprint);
330     if (rtcStats.fingerprint_algorithm.is_defined())
331         stats.fingerprintAlgorithm = fromStdString(*rtcStats.fingerprint_algorithm);
332     if (rtcStats.base64_certificate.is_defined())
333         stats.base64Certificate = fromStdString(*rtcStats.base64_certificate);
334     if (rtcStats.issuer_certificate_id.is_defined())
335         stats.issuerCertificateId = fromStdString(*rtcStats.issuer_certificate_id);
336 }
337
338 static inline void fillRTCCodecStats(RTCStatsReport::CodecStats& stats, const webrtc::RTCCodecStats& rtcStats)
339 {
340     fillRTCStats(stats, rtcStats);
341
342     if (rtcStats.payload_type.is_defined())
343         stats.payloadType = *rtcStats.payload_type;
344     if (rtcStats.mime_type.is_defined())
345         stats.mimeType = fromStdString(*rtcStats.mime_type);
346     if (rtcStats.clock_rate.is_defined())
347         stats.clockRate = *rtcStats.clock_rate;
348     if (rtcStats.channels.is_defined())
349         stats.channels = *rtcStats.channels;
350     if (rtcStats.sdp_fmtp_line.is_defined())
351         stats.sdpFmtpLine = fromStdString(*rtcStats.sdp_fmtp_line);
352 }
353
354 static inline void fillRTCTransportStats(RTCStatsReport::TransportStats& stats, const webrtc::RTCTransportStats& rtcStats)
355 {
356     fillRTCStats(stats, rtcStats);
357
358     if (rtcStats.bytes_sent.is_defined())
359         stats.bytesSent = *rtcStats.bytes_sent;
360     if (rtcStats.bytes_received.is_defined())
361         stats.bytesReceived = *rtcStats.bytes_received;
362     if (rtcStats.rtcp_transport_stats_id.is_defined())
363         stats.rtcpTransportStatsId = fromStdString(*rtcStats.rtcp_transport_stats_id);
364     if (rtcStats.selected_candidate_pair_id.is_defined())
365         stats.selectedCandidatePairId = fromStdString(*rtcStats.selected_candidate_pair_id);
366     if (rtcStats.local_certificate_id.is_defined())
367         stats.localCertificateId = fromStdString(*rtcStats.local_certificate_id);
368     if (rtcStats.remote_certificate_id.is_defined())
369         stats.remoteCertificateId = fromStdString(*rtcStats.remote_certificate_id);
370 }
371
372 static inline void fillRTCPeerConnectionStats(RTCStatsReport::PeerConnectionStats& stats, const webrtc::RTCPeerConnectionStats& rtcStats)
373 {
374     fillRTCStats(stats, rtcStats);
375
376     if (rtcStats.data_channels_opened.is_defined())
377         stats.dataChannelsOpened = *rtcStats.data_channels_opened;
378     if (rtcStats.data_channels_closed.is_defined())
379         stats.dataChannelsClosed = *rtcStats.data_channels_closed;
380 }
381
382 static inline void initializeRTCStatsReportBackingMap(DOMMapAdapter& report, const webrtc::RTCStatsReport& rtcReport)
383 {
384     for (const auto& rtcStats : rtcReport) {
385         if (rtcStats.type() == webrtc::RTCInboundRTPStreamStats::kType) {
386             RTCStatsReport::InboundRTPStreamStats stats;
387             fillInboundRTPStreamStats(stats, static_cast<const webrtc::RTCInboundRTPStreamStats&>(rtcStats));
388             report.set<IDLDOMString, IDLDictionary<RTCStatsReport::InboundRTPStreamStats>>(stats.id, WTFMove(stats));
389         } else if (rtcStats.type() == webrtc::RTCOutboundRTPStreamStats::kType) {
390             RTCStatsReport::OutboundRTPStreamStats stats;
391             fillOutboundRTPStreamStats(stats, static_cast<const webrtc::RTCOutboundRTPStreamStats&>(rtcStats));
392             report.set<IDLDOMString, IDLDictionary<RTCStatsReport::OutboundRTPStreamStats>>(stats.id, WTFMove(stats));
393         } else if (rtcStats.type() == webrtc::RTCMediaStreamTrackStats::kType) {
394             RTCStatsReport::MediaStreamTrackStats stats;
395             fillRTCMediaStreamTrackStats(stats, static_cast<const webrtc::RTCMediaStreamTrackStats&>(rtcStats));
396             report.set<IDLDOMString, IDLDictionary<RTCStatsReport::MediaStreamTrackStats>>(stats.id, WTFMove(stats));
397         } else if (rtcStats.type() == webrtc::RTCDataChannelStats::kType) {
398             RTCStatsReport::DataChannelStats stats;
399             fillRTCDataChannelStats(stats, static_cast<const webrtc::RTCDataChannelStats&>(rtcStats));
400             report.set<IDLDOMString, IDLDictionary<RTCStatsReport::DataChannelStats>>(stats.id, WTFMove(stats));
401         } else if (rtcStats.type() == webrtc::RTCIceCandidatePairStats::kType) {
402             RTCStatsReport::IceCandidatePairStats stats;
403             fillRTCIceCandidatePairStats(stats, static_cast<const webrtc::RTCIceCandidatePairStats&>(rtcStats));
404             report.set<IDLDOMString, IDLDictionary<RTCStatsReport::IceCandidatePairStats>>(stats.id, WTFMove(stats));
405         } else if (rtcStats.type() == webrtc::RTCRemoteIceCandidateStats::kType || rtcStats.type() == webrtc::RTCLocalIceCandidateStats::kType) {
406             RTCStatsReport::IceCandidateStats stats;
407             fillRTCIceCandidateStats(stats, static_cast<const webrtc::RTCIceCandidateStats&>(rtcStats));
408             report.set<IDLDOMString, IDLDictionary<RTCStatsReport::IceCandidateStats>>(stats.id, WTFMove(stats));
409         } else if (rtcStats.type() == webrtc::RTCCertificateStats::kType) {
410             RTCStatsReport::CertificateStats stats;
411             fillRTCCertificateStats(stats, static_cast<const webrtc::RTCCertificateStats&>(rtcStats));
412             report.set<IDLDOMString, IDLDictionary<RTCStatsReport::CertificateStats>>(stats.id, WTFMove(stats));
413         } else if (rtcStats.type() == webrtc::RTCCodecStats::kType) {
414             RTCStatsReport::CodecStats stats;
415             fillRTCCodecStats(stats, static_cast<const webrtc::RTCCodecStats&>(rtcStats));
416             report.set<IDLDOMString, IDLDictionary<RTCStatsReport::CodecStats>>(stats.id, WTFMove(stats));
417         } else if (rtcStats.type() == webrtc::RTCTransportStats::kType) {
418             RTCStatsReport::TransportStats stats;
419             fillRTCTransportStats(stats, static_cast<const webrtc::RTCTransportStats&>(rtcStats));
420             report.set<IDLDOMString, IDLDictionary<RTCStatsReport::TransportStats>>(stats.id, WTFMove(stats));
421         } else if (rtcStats.type() == webrtc::RTCPeerConnectionStats::kType) {
422             RTCStatsReport::PeerConnectionStats stats;
423             fillRTCPeerConnectionStats(stats, static_cast<const webrtc::RTCPeerConnectionStats&>(rtcStats));
424             report.set<IDLDOMString, IDLDictionary<RTCStatsReport::PeerConnectionStats>>(stats.id, WTFMove(stats));
425         }
426     }
427 }
428
429 void LibWebRTCStatsCollector::OnStatsDelivered(const rtc::scoped_refptr<const webrtc::RTCStatsReport>& rtcReport)
430 {
431     callOnMainThread([this, protectedThis = rtc::scoped_refptr<LibWebRTCStatsCollector>(this), rtcReport]() {
432         m_callback(RTCStatsReport::create([rtcReport](auto& mapAdapter) {
433             if (rtcReport)
434                 initializeRTCStatsReportBackingMap(mapAdapter, *rtcReport);
435         }));
436     });
437 }
438
439 }; // namespace WTF
440
441
442 #endif // USE(LIBWEBRTC)