Implement sender/receiver getStats
authoryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Sep 2018 15:54:08 +0000 (15:54 +0000)
committeryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Sep 2018 15:54:08 +0000 (15:54 +0000)
https://bugs.webkit.org/show_bug.cgi?id=189707

Reviewed by Eric Carlson.

LayoutTests/imported/w3c:

* web-platform-tests/webrtc/RTCRtpReceiver-getStats.https-expected.txt:
* web-platform-tests/webrtc/RTCRtpSender-getStats.https-expected.txt:

Source/WebCore:

Add support for sender and receiver getStats.
Also add support for peer connection selector parameter.

Add the plumbing of the selector to LibWebRTCMediaEndpoint.
Then make use of libwebrtc overloaded methods to retrieve the right stats.

Covered by updated/rebased tests.

* Modules/mediastream/PeerConnectionBackend.h:
* Modules/mediastream/RTCPeerConnection.cpp:
(WebCore::RTCPeerConnection::getStats):
* Modules/mediastream/RTCPeerConnection.h:
* Modules/mediastream/RTCPeerConnection.idl:
* Modules/mediastream/RTCRtpReceiver.cpp:
(WebCore::RTCRtpReceiver::RTCRtpReceiver):
(WebCore::RTCRtpReceiver::getStats):
* Modules/mediastream/RTCRtpReceiver.h:
(WebCore::RTCRtpReceiver::create):
(WebCore::RTCRtpReceiver::backend):
* Modules/mediastream/RTCRtpReceiver.idl:
* Modules/mediastream/RTCRtpSender.cpp:
(WebCore::RTCRtpSender::create):
(WebCore::RTCRtpSender::RTCRtpSender):
(WebCore::RTCRtpSender::getStats):
* Modules/mediastream/RTCRtpSender.h:
* Modules/mediastream/RTCRtpSender.idl:
* Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp:
(WebCore::LibWebRTCMediaEndpoint::getStats):
* Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.h:
* Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.cpp:
(WebCore::LibWebRTCPeerConnectionBackend::getStats):
(WebCore::backendFromRTPSender):
(WebCore::createReceiverForSource):
(WebCore::LibWebRTCPeerConnectionBackend::createReceiver):
(WebCore::LibWebRTCPeerConnectionBackend::videoReceiver):
(WebCore::LibWebRTCPeerConnectionBackend::audioReceiver):
(WebCore::LibWebRTCPeerConnectionBackend::addTrack):
(WebCore::LibWebRTCPeerConnectionBackend::addUnifiedPlanTransceiver):
(WebCore::LibWebRTCPeerConnectionBackend::addTransceiver):
(WebCore::LibWebRTCPeerConnectionBackend::newRemoteTransceiver):
* Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h:
* Modules/mediastream/libwebrtc/LibWebRTCRtpReceiverBackend.h:

LayoutTests:

* webrtc/video-stats-expected.txt:
* webrtc/video-stats.html:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@236207 268f45cc-cd09-0410-ab3c-d52691b4dbfc

21 files changed:
LayoutTests/ChangeLog
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/webrtc/RTCRtpReceiver-getStats.https-expected.txt
LayoutTests/imported/w3c/web-platform-tests/webrtc/RTCRtpSender-getStats.https-expected.txt
LayoutTests/webrtc/video-stats-expected.txt
LayoutTests/webrtc/video-stats.html
Source/WebCore/ChangeLog
Source/WebCore/Modules/mediastream/PeerConnectionBackend.h
Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp
Source/WebCore/Modules/mediastream/RTCPeerConnection.idl
Source/WebCore/Modules/mediastream/RTCRtpReceiver.cpp
Source/WebCore/Modules/mediastream/RTCRtpReceiver.h
Source/WebCore/Modules/mediastream/RTCRtpReceiver.idl
Source/WebCore/Modules/mediastream/RTCRtpSender.cpp
Source/WebCore/Modules/mediastream/RTCRtpSender.h
Source/WebCore/Modules/mediastream/RTCRtpSender.idl
Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp
Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.h
Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.cpp
Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h
Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCRtpReceiverBackend.h

index 5f448c0..20a578d 100644 (file)
@@ -1,3 +1,13 @@
+2018-09-19  Youenn Fablet  <youenn@apple.com>
+
+        Implement sender/receiver getStats
+        https://bugs.webkit.org/show_bug.cgi?id=189707
+
+        Reviewed by Eric Carlson.
+
+        * webrtc/video-stats-expected.txt:
+        * webrtc/video-stats.html:
+
 2018-09-19  Ms2ger  <Ms2ger@igalia.com>
 
         [GTK] Unreviewed test gardening
index 95e4faa..f96cdd6 100644 (file)
@@ -1,3 +1,13 @@
+2018-09-19  Youenn Fablet  <youenn@apple.com>
+
+        Implement sender/receiver getStats
+        https://bugs.webkit.org/show_bug.cgi?id=189707
+
+        Reviewed by Eric Carlson.
+
+        * web-platform-tests/webrtc/RTCRtpReceiver-getStats.https-expected.txt:
+        * web-platform-tests/webrtc/RTCRtpSender-getStats.https-expected.txt:
+
 2018-09-18  Youenn Fablet  <youenn@apple.com>
 
         Implement RTCRtpReceiver getContributingSources/getSynchronizationSources
index ecb88a2..4ee77a4 100644 (file)
@@ -1,4 +1,4 @@
 
-FAIL receiver.getStats() via addTransceiver should return stats report containing inbound-rtp stats promise_test: Unhandled rejection with value: object "TypeError: receiver.getStats is not a function. (In 'receiver.getStats()', 'receiver.getStats' is undefined)"
-FAIL receiver.getStats() via addTrack should return stats report containing inbound-rtp stats promise_test: Unhandled rejection with value: object "TypeError: receiver.getStats is not a function. (In 'receiver.getStats()', 'receiver.getStats' is undefined)"
+FAIL receiver.getStats() via addTransceiver should return stats report containing inbound-rtp stats assert_true: Expect statsReport to contain stats object of type inbound-rtp expected true got false
+FAIL receiver.getStats() via addTrack should return stats report containing inbound-rtp stats assert_equals: Expect dictionary.mediaType to be string expected "string" but got "undefined"
 
index 8bbc38e..8e98e45 100644 (file)
@@ -1,4 +1,4 @@
 
-FAIL sender.getStats() via addTransceiver should return stats report containing outbound-rtp stats promise_test: Unhandled rejection with value: object "TypeError: sender.getStats is not a function. (In 'sender.getStats()', 'sender.getStats' is undefined)"
-FAIL sender.getStats() via addTrack should return stats report containing outbound-rtp stats promise_test: Unhandled rejection with value: object "TypeError: sender.getStats is not a function. (In 'sender.getStats()', 'sender.getStats' is undefined)"
+FAIL sender.getStats() via addTransceiver should return stats report containing outbound-rtp stats assert_true: Expect statsReport to contain stats object of type outbound-rtp expected true got false
+FAIL sender.getStats() via addTrack should return stats report containing outbound-rtp stats assert_equals: Expect dictionary.trackId to be string expected "string" but got "undefined"
 
index 242a4a5..ef1b227 100644 (file)
@@ -1,3 +1,5 @@
 
 PASS Basic video stats 
+PASS Sender stats 
+PASS Receiver stats 
 
index 52a766a..8286ca7 100644 (file)
@@ -96,55 +96,76 @@ function checkOutboundFramesNumberIncreased(firstConnection, statsFirstConnectio
 }
 
 var firstConnection, secondConnection;
-promise_test((test) => {
+promise_test(async (test) => {
     if (window.testRunner)
         testRunner.setUserMediaPermission(true);
 
-    var localStream, remoteStream;
-    return navigator.mediaDevices.getUserMedia({ video: true}).then((stream) => {
-        localStream = stream;
-        return new Promise((resolve, reject) => {
-            createConnections((connection) => {
-                firstConnection = connection;
-                firstConnection.addTrack(stream.getVideoTracks()[0], stream);
-            }, (connection) => {
-                secondConnection = connection;
-                secondConnection.ontrack = (trackEvent) => {
-                    remoteStream = trackEvent.streams[0];
-                    resolve();
-                };
-            });
-            setTimeout(() => reject("Test timed out"), 5000);
+    const localStream = await navigator.mediaDevices.getUserMedia({ video: true});
+    await new Promise((resolve, reject) => {
+        createConnections((connection) => {
+            firstConnection = connection;
+            firstConnection.addTrack(localStream.getVideoTracks()[0], localStream);
+        }, (connection) => {
+            secondConnection = connection;
+            secondConnection.addTrack(localStream.getVideoTracks()[0], localStream);
+            secondConnection.ontrack = (trackEvent) => {
+                resolve();
+            };
         });
-    }).then(() => {
-        return getOutboundRTPStats(firstConnection);
-    }).then((stats) => {
-        assert_true(!!stats, "outbound-rtp stats should not be null");
-        assert_true(Number.isInteger(stats.framesEncoded), "framesEncoded should be an integer");
-        assert_true(Number.isInteger(stats.qpSum), "outbound qpSum should be an integer");
-        assert_true(typeof stats.timestamp === "number", "timestamp should be a double");
-        statsFirstConnection = stats;
-        return getInboundRTPStats(secondConnection);
-    }).then((stats) => {
-        assert_true(!!stats, "inbound-rtp stats should not be null");
-        assert_true(Number.isInteger(stats.framesDecoded), "framesDecoded should be an integer");
-        assert_true(Number.isInteger(stats.qpSum), "inbound qpSum should be an integer");
-        assert_true(typeof stats.timestamp === "number", "timestamp should be a double");
-        statsSecondConnection = stats;
-    }).then(() => {
-        return checkInboundFramesNumberIncreased(secondConnection, statsSecondConnection, 0);
-    }).then(() => {
-        return checkOutboundFramesNumberIncreased(firstConnection, statsFirstConnection, 0);
-    }).then(() => {
-        return getStatsType(firstConnection);
-    }).then((types) => {
-        assert_array_equals(types, ["candidate-pair", "certificate", "outbound-rtp", "track"]);
-    }).then(() => {
-        return getStatsType(secondConnection);
-    }).then((types) => {
-        assert_array_equals(types, ["candidate-pair", "certificate", "inbound-rtp", "track"]);
+        setTimeout(() => reject("Test timed out"), 5000);
     });
+
+    let stats = await getOutboundRTPStats(firstConnection);
+    assert_true(!!stats, "outbound-rtp stats should not be null");
+    assert_true(Number.isInteger(stats.framesEncoded), "framesEncoded should be an integer");
+    assert_true(Number.isInteger(stats.qpSum), "outbound qpSum should be an integer");
+    assert_true(typeof stats.timestamp === "number", "timestamp should be a double");
+    statsFirstConnection = stats;
+
+    stats = await getInboundRTPStats(secondConnection);
+    assert_true(!!stats, "inbound-rtp stats should not be null");
+    assert_true(Number.isInteger(stats.framesDecoded), "framesDecoded should be an integer");
+    assert_true(Number.isInteger(stats.qpSum), "inbound qpSum should be an integer");
+    assert_true(typeof stats.timestamp === "number", "timestamp should be a double");
+    statsSecondConnection = stats;
+
+    await checkInboundFramesNumberIncreased(secondConnection, statsSecondConnection, 0);
+    await checkOutboundFramesNumberIncreased(firstConnection, statsFirstConnection, 0);
+
+    let types = await getStatsType(firstConnection);
+    assert_array_equals(types, ["candidate-pair", "certificate", "inbound-rtp", "outbound-rtp", "track"]);
+
+    types = await getStatsType(secondConnection);
+    assert_array_equals(types, ["candidate-pair", "certificate", "inbound-rtp", "outbound-rtp", "track"]);
 }, "Basic video stats");
+
+promise_test(async (test) => {
+    const report = await firstConnection.getSenders()[0].getStats();
+    checkStatsReportIterator(report);
+    var instats, outstats;
+    report.forEach((statItem) => {
+        if (statItem.type === "outbound-rtp")
+            outstats = statItem;
+        else if (statItem.type === "inbound-rtp")
+            instats = statItem;
+    });
+    assert_true(!!outstats);
+    assert_false(!!instats);
+}, "Sender stats");
+
+promise_test(async (test) => {
+    const report = await secondConnection.getReceivers()[0].getStats();
+    checkStatsReportIterator(report);
+    var instats, outstats;
+    report.forEach((statItem) => {
+        if (statItem.type === "outbound-rtp")
+            outstats = statItem;
+        else if (statItem.type === "inbound-rtp")
+            instats = statItem;
+    });
+    assert_false(!!outstats);
+    assert_true(!!instats);
+}, "Receiver stats");
         </script>
     </body>
 </html>
index 694b58f..9fbcc30 100644 (file)
@@ -1,3 +1,53 @@
+2018-09-19  Youenn Fablet  <youenn@apple.com>
+
+        Implement sender/receiver getStats
+        https://bugs.webkit.org/show_bug.cgi?id=189707
+
+        Reviewed by Eric Carlson.
+
+        Add support for sender and receiver getStats.
+        Also add support for peer connection selector parameter.
+
+        Add the plumbing of the selector to LibWebRTCMediaEndpoint.
+        Then make use of libwebrtc overloaded methods to retrieve the right stats.
+
+        Covered by updated/rebased tests.
+
+        * Modules/mediastream/PeerConnectionBackend.h:
+        * Modules/mediastream/RTCPeerConnection.cpp:
+        (WebCore::RTCPeerConnection::getStats):
+        * Modules/mediastream/RTCPeerConnection.h:
+        * Modules/mediastream/RTCPeerConnection.idl:
+        * Modules/mediastream/RTCRtpReceiver.cpp:
+        (WebCore::RTCRtpReceiver::RTCRtpReceiver):
+        (WebCore::RTCRtpReceiver::getStats):
+        * Modules/mediastream/RTCRtpReceiver.h:
+        (WebCore::RTCRtpReceiver::create):
+        (WebCore::RTCRtpReceiver::backend):
+        * Modules/mediastream/RTCRtpReceiver.idl:
+        * Modules/mediastream/RTCRtpSender.cpp:
+        (WebCore::RTCRtpSender::create):
+        (WebCore::RTCRtpSender::RTCRtpSender):
+        (WebCore::RTCRtpSender::getStats):
+        * Modules/mediastream/RTCRtpSender.h:
+        * Modules/mediastream/RTCRtpSender.idl:
+        * Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp:
+        (WebCore::LibWebRTCMediaEndpoint::getStats):
+        * Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.h:
+        * Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.cpp:
+        (WebCore::LibWebRTCPeerConnectionBackend::getStats):
+        (WebCore::backendFromRTPSender):
+        (WebCore::createReceiverForSource):
+        (WebCore::LibWebRTCPeerConnectionBackend::createReceiver):
+        (WebCore::LibWebRTCPeerConnectionBackend::videoReceiver):
+        (WebCore::LibWebRTCPeerConnectionBackend::audioReceiver):
+        (WebCore::LibWebRTCPeerConnectionBackend::addTrack):
+        (WebCore::LibWebRTCPeerConnectionBackend::addUnifiedPlanTransceiver):
+        (WebCore::LibWebRTCPeerConnectionBackend::addTransceiver):
+        (WebCore::LibWebRTCPeerConnectionBackend::newRemoteTransceiver):
+        * Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h:
+        * Modules/mediastream/libwebrtc/LibWebRTCRtpReceiverBackend.h:
+
 2018-09-19  Jer Noble  <jer.noble@apple.com>
 
         REGRESSION (r236006): New waitingForKey() requirement breaks Modern EME tests.
index 06e9272..6521765 100644 (file)
@@ -39,6 +39,7 @@
 #include "RTCSessionDescription.h"
 #include "RTCSignalingState.h"
 #include <wtf/LoggerHelper.h>
+#include <wtf/WeakPtr.h>
 
 namespace WebCore {
 
@@ -68,8 +69,9 @@ using StatsPromise = DOMPromiseDeferred<IDLInterface<RTCStatsReport>>;
 using CreatePeerConnectionBackend = std::unique_ptr<PeerConnectionBackend> (*)(RTCPeerConnection&);
 
 class PeerConnectionBackend
+    : public CanMakeWeakPtr<PeerConnectionBackend>
 #if !RELEASE_LOG_DISABLED
-    : private LoggerHelper
+    , private LoggerHelper
 #endif
 {
 public:
@@ -98,7 +100,9 @@ public:
 
     virtual bool setConfiguration(MediaEndpointConfiguration&&) = 0;
 
-    virtual void getStats(MediaStreamTrack*, Ref<DeferredPromise>&&) = 0;
+    virtual void getStats(Ref<DeferredPromise>&&) = 0;
+    virtual void getStats(RTCRtpSender&, Ref<DeferredPromise>&&) = 0;
+    virtual void getStats(RTCRtpReceiver&, Ref<DeferredPromise>&&) = 0;
 
     virtual ExceptionOr<Ref<RTCRtpSender>> addTrack(MediaStreamTrack&, Vector<String>&&);
     virtual void removeTrack(RTCRtpSender&) { }
index ba2ee56..ee90075 100644 (file)
@@ -328,7 +328,19 @@ ExceptionOr<void> RTCPeerConnection::setConfiguration(RTCConfiguration&& configu
 
 void RTCPeerConnection::getStats(MediaStreamTrack* selector, Ref<DeferredPromise>&& promise)
 {
-    m_backend->getStats(selector, WTFMove(promise));
+    if (selector) {
+        for (auto& transceiver : m_transceiverSet->list()) {
+            if (transceiver->sender().track() == selector) {
+                m_backend->getStats(transceiver->sender(), WTFMove(promise));
+                return;
+            }
+            if (&transceiver->receiver().track() == selector) {
+                m_backend->getStats(transceiver->receiver(), WTFMove(promise));
+                return;
+            }
+        }
+    }
+    m_backend->getStats(WTFMove(promise));
 }
 
 ExceptionOr<Ref<RTCDataChannel>> RTCPeerConnection::createDataChannel(ScriptExecutionContext& context, String&& label, RTCDataChannelInit&& options)
index 1f4359b..f32262b 100644 (file)
@@ -138,7 +138,6 @@ typedef RTCRtpTransceiverDirection RtpTransceiverDirection;
 
 
     // 8.2 Statistics API
-    // FIXME 169644: |selector| may go away in a future version of the spec
     Promise<RTCStatsReport> getStats(optional MediaStreamTrack? selector = null);
 
 
index 58f42ca..fb01e9c 100644 (file)
 
 namespace WebCore {
 
-RTCRtpReceiver::RTCRtpReceiver(Ref<MediaStreamTrack>&& track, std::unique_ptr<RTCRtpReceiverBackend>&& backend)
+RTCRtpReceiver::RTCRtpReceiver(PeerConnectionBackend& connection, Ref<MediaStreamTrack>&& track, std::unique_ptr<RTCRtpReceiverBackend>&& backend)
     : m_track(WTFMove(track))
     , m_backend(WTFMove(backend))
+    , m_connection(makeWeakPtr(&connection))
 {
 }
 
@@ -50,6 +51,15 @@ void RTCRtpReceiver::stop()
     m_track->stopTrack(MediaStreamTrack::StopMode::PostEvent);
 }
 
+void RTCRtpReceiver::getStats(Ref<DeferredPromise>&& promise)
+{
+    if (!m_connection) {
+        promise->reject(InvalidStateError);
+        return;
+    }
+    m_connection->getStats(*this, WTFMove(promise));
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(WEB_RTC)
index 532e2c0..b4fee60 100644 (file)
 
 namespace WebCore {
 
+class PeerConnectionBackend;
 
 class RTCRtpReceiver : public RefCounted<RTCRtpReceiver>, public ScriptWrappable  {
 public:
-    static Ref<RTCRtpReceiver> create(Ref<MediaStreamTrack>&& track, std::unique_ptr<RTCRtpReceiverBackend>&& backend)
+    static Ref<RTCRtpReceiver> create(PeerConnectionBackend& connection, Ref<MediaStreamTrack>&& track, std::unique_ptr<RTCRtpReceiverBackend>&& backend)
     {
-        return adoptRef(*new RTCRtpReceiver(WTFMove(track), WTFMove(backend)));
+        return adoptRef(*new RTCRtpReceiver(connection, WTFMove(track), WTFMove(backend)));
     }
 
     void stop();
@@ -56,11 +57,15 @@ public:
 
     MediaStreamTrack& track() { return m_track.get(); }
 
+    RTCRtpReceiverBackend* backend() { return m_backend.get(); }
+    void getStats(Ref<DeferredPromise>&&);
+
 private:
-    RTCRtpReceiver(Ref<MediaStreamTrack>&&, std::unique_ptr<RTCRtpReceiverBackend>&&);
+    RTCRtpReceiver(PeerConnectionBackend&, Ref<MediaStreamTrack>&&, std::unique_ptr<RTCRtpReceiverBackend>&&);
 
     Ref<MediaStreamTrack> m_track;
     std::unique_ptr<RTCRtpReceiverBackend> m_backend;
+    WeakPtr<PeerConnectionBackend> m_connection;
 };
 
 } // namespace WebCore
index 9f53d5d..9d8565a 100644 (file)
@@ -41,4 +41,5 @@
     // FIXME 169662: missing getCapabilities
     sequence<RTCRtpContributingSource> getContributingSources();
     sequence<RTCRtpSynchronizationSource> getSynchronizationSources();
+    Promise<RTCStatsReport> getStats();
 };
index 7ebddd9..c7ca2b4 100644 (file)
 
 namespace WebCore {
 
-Ref<RTCRtpSender> RTCRtpSender::create(Ref<MediaStreamTrack>&& track, Vector<String>&& mediaStreamIds, std::unique_ptr<RTCRtpSenderBackend>&& backend)
+Ref<RTCRtpSender> RTCRtpSender::create(PeerConnectionBackend& connection, Ref<MediaStreamTrack>&& track, Vector<String>&& mediaStreamIds, std::unique_ptr<RTCRtpSenderBackend>&& backend)
 {
-    auto sender = adoptRef(*new RTCRtpSender(String(track->kind()), WTFMove(mediaStreamIds), WTFMove(backend)));
+    auto sender = adoptRef(*new RTCRtpSender(connection, String(track->kind()), WTFMove(mediaStreamIds), WTFMove(backend)));
     sender->setTrack(WTFMove(track));
     return sender;
 }
 
-Ref<RTCRtpSender> RTCRtpSender::create(String&& trackKind, Vector<String>&& mediaStreamIds, std::unique_ptr<RTCRtpSenderBackend>&& backend)
+Ref<RTCRtpSender> RTCRtpSender::create(PeerConnectionBackend& connection, String&& trackKind, Vector<String>&& mediaStreamIds, std::unique_ptr<RTCRtpSenderBackend>&& backend)
 {
-    return adoptRef(*new RTCRtpSender(WTFMove(trackKind), WTFMove(mediaStreamIds), WTFMove(backend)));
+    return adoptRef(*new RTCRtpSender(connection, WTFMove(trackKind), WTFMove(mediaStreamIds), WTFMove(backend)));
 }
 
-RTCRtpSender::RTCRtpSender(String&& trackKind, Vector<String>&& mediaStreamIds, std::unique_ptr<RTCRtpSenderBackend>&& backend)
+RTCRtpSender::RTCRtpSender(PeerConnectionBackend& connection, String&& trackKind, Vector<String>&& mediaStreamIds, std::unique_ptr<RTCRtpSenderBackend>&& backend)
     : m_trackKind(WTFMove(trackKind))
     , m_mediaStreamIds(WTFMove(mediaStreamIds))
     , m_backend(WTFMove(backend))
+    , m_connection(makeWeakPtr(&connection))
 {
     ASSERT(!RuntimeEnabledFeatures::sharedFeatures().webRTCUnifiedPlanEnabled() || m_backend);
 }
@@ -110,6 +111,15 @@ void RTCRtpSender::setParameters(const RTCRtpSendParameters& parameters, DOMProm
     return m_backend->setParameters(parameters, WTFMove(promise));
 }
 
+void RTCRtpSender::getStats(Ref<DeferredPromise>&& promise)
+{
+    if (!m_connection) {
+        promise->reject(InvalidStateError);
+        return;
+    }
+    m_connection->getStats(*this, WTFMove(promise));
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(WEB_RTC)
index 20bbfde..49aad3e 100644 (file)
 
 namespace WebCore {
 
+class PeerConnectionBackend;
+
 class RTCRtpSender : public RefCounted<RTCRtpSender>, public ScriptWrappable {
 public:
-    static Ref<RTCRtpSender> create(Ref<MediaStreamTrack>&&, Vector<String>&& mediaStreamIds, std::unique_ptr<RTCRtpSenderBackend>&&);
-    static Ref<RTCRtpSender> create(String&& trackKind, Vector<String>&& mediaStreamIds, std::unique_ptr<RTCRtpSenderBackend>&&);
+    static Ref<RTCRtpSender> create(PeerConnectionBackend&, Ref<MediaStreamTrack>&&, Vector<String>&& mediaStreamIds, std::unique_ptr<RTCRtpSenderBackend>&&);
+    static Ref<RTCRtpSender> create(PeerConnectionBackend&, String&& trackKind, Vector<String>&& mediaStreamIds, std::unique_ptr<RTCRtpSenderBackend>&&);
 
     MediaStreamTrack* track() { return m_track.get(); }
 
@@ -64,14 +66,17 @@ public:
 
     RTCRtpSenderBackend* backend() { return m_backend.get(); }
 
+    void getStats(Ref<DeferredPromise>&&);
+
 private:
-    RTCRtpSender(String&& trackKind, Vector<String>&& mediaStreamIds, std::unique_ptr<RTCRtpSenderBackend>&&);
+    RTCRtpSender(PeerConnectionBackend&, String&& trackKind, Vector<String>&& mediaStreamIds, std::unique_ptr<RTCRtpSenderBackend>&&);
 
     RefPtr<MediaStreamTrack> m_track;
     String m_trackId;
     String m_trackKind;
     Vector<String> m_mediaStreamIds;
     std::unique_ptr<RTCRtpSenderBackend> m_backend;
+    WeakPtr<PeerConnectionBackend> m_connection;
 };
 
 } // namespace WebCore
index 91f65b3..09cdb8e 100644 (file)
@@ -42,4 +42,5 @@
     RTCRtpSendParameters getParameters();
     Promise<void> setParameters(RTCRtpSendParameters parameters);
     [CallWith=ScriptExecutionContext] Promise<void> replaceTrack(MediaStreamTrack? withTrack);
+    Promise<RTCStatsReport> getStats();
 };
index b25b564..cd00353 100644 (file)
@@ -277,7 +277,7 @@ void LibWebRTCMediaEndpoint::doCreateAnswer()
     m_backend->CreateAnswer(&m_createSessionDescriptionObserver, nullptr);
 }
 
-void LibWebRTCMediaEndpoint::getStats(MediaStreamTrack*, Ref<DeferredPromise>&& promise)
+void LibWebRTCMediaEndpoint::getStats(Ref<DeferredPromise>&& promise, WTF::Function<void(rtc::scoped_refptr<LibWebRTCStatsCollector>&&)>&& getStatsFunction)
 {
     auto collector = LibWebRTCStatsCollector::create([promise = WTFMove(promise), protectedThis = makeRef(*this)](auto&& report) mutable {
         ASSERT(isMainThread());
@@ -287,9 +287,32 @@ void LibWebRTCMediaEndpoint::getStats(MediaStreamTrack*, Ref<DeferredPromise>&&
         promise->resolve<IDLInterface<RTCStatsReport>>(report.releaseNonNull());
         return true;
     });
-    LibWebRTCProvider::callOnWebRTCSignalingThread([this, collector = WTFMove(collector)] {
+    LibWebRTCProvider::callOnWebRTCSignalingThread([getStatsFunction = WTFMove(getStatsFunction), collector = WTFMove(collector)]() mutable {
+        getStatsFunction(WTFMove(collector));
+    });
+}
+
+void LibWebRTCMediaEndpoint::getStats(Ref<DeferredPromise>&& promise)
+{
+    getStats(WTFMove(promise), [this](auto&& collector) {
+        if (m_backend)
+            m_backend->GetStats(WTFMove(collector));
+    });
+}
+
+void LibWebRTCMediaEndpoint::getStats(webrtc::RtpReceiverInterface& receiver, Ref<DeferredPromise>&& promise)
+{
+    getStats(WTFMove(promise), [this, receiver = rtc::scoped_refptr<webrtc::RtpReceiverInterface>(&receiver)](auto&& collector) mutable {
+        if (m_backend)
+            m_backend->GetStats(WTFMove(receiver), WTFMove(collector));
+    });
+}
+
+void LibWebRTCMediaEndpoint::getStats(webrtc::RtpSenderInterface& sender, Ref<DeferredPromise>&& promise)
+{
+    getStats(WTFMove(promise), [this, sender = rtc::scoped_refptr<webrtc::RtpSenderInterface>(&sender)](auto&& collector)  mutable {
         if (m_backend)
-            m_backend->GetStats(collector.get());
+            m_backend->GetStats(WTFMove(sender), WTFMove(collector));
     });
 }
 
index 177e7aa..efb5113 100644 (file)
@@ -55,11 +55,11 @@ class SetSessionDescriptionObserver;
 }
 
 namespace WebCore {
-
 class LibWebRTCProvider;
 class LibWebRTCPeerConnectionBackend;
 class LibWebRTCRtpReceiverBackend;
 class LibWebRTCRtpTransceiverBackend;
+class LibWebRTCStatsCollector;
 class MediaStreamTrack;
 class RTCSessionDescription;
 
@@ -82,7 +82,9 @@ public:
     void doSetRemoteDescription(RTCSessionDescription&);
     void doCreateOffer(const RTCOfferOptions&);
     void doCreateAnswer();
-    void getStats(MediaStreamTrack*, Ref<DeferredPromise>&&);
+    void getStats(Ref<DeferredPromise>&&);
+    void getStats(webrtc::RtpReceiverInterface&, Ref<DeferredPromise>&&);
+    void getStats(webrtc::RtpSenderInterface&, Ref<DeferredPromise>&&);
     std::unique_ptr<RTCDataChannelHandler> createDataChannel(const String&, const RTCDataChannelInit&);
     bool addIceCandidate(webrtc::IceCandidateInterface& candidate) { return m_backend->AddIceCandidate(&candidate); }
 
@@ -148,6 +150,8 @@ private:
     void startLoggingStats();
     void stopLoggingStats();
 
+    void getStats(Ref<DeferredPromise>&&, WTF::Function<void(rtc::scoped_refptr<LibWebRTCStatsCollector>&&)>&&);
+
     MediaStream& mediaStreamFromRTCStream(webrtc::MediaStreamInterface&);
 
     void AddRef() const { ref(); }
index 3c4f99a..605f2e7 100644 (file)
@@ -129,9 +129,37 @@ bool LibWebRTCPeerConnectionBackend::setConfiguration(MediaEndpointConfiguration
     return m_endpoint->setConfiguration(page->libWebRTCProvider(), configurationFromMediaEndpointConfiguration(WTFMove(configuration)));
 }
 
-void LibWebRTCPeerConnectionBackend::getStats(MediaStreamTrack* track, Ref<DeferredPromise>&& promise)
+void LibWebRTCPeerConnectionBackend::getStats(Ref<DeferredPromise>&& promise)
 {
-    m_endpoint->getStats(track, WTFMove(promise));
+    m_endpoint->getStats(WTFMove(promise));
+}
+
+static inline LibWebRTCRtpSenderBackend& backendFromRTPSender(RTCRtpSender& sender)
+{
+    ASSERT(!sender.isStopped());
+    return static_cast<LibWebRTCRtpSenderBackend&>(*sender.backend());
+}
+
+void LibWebRTCPeerConnectionBackend::getStats(RTCRtpSender& sender, Ref<DeferredPromise>&& promise)
+{
+    webrtc::RtpSenderInterface* rtcSender = sender.backend() ? backendFromRTPSender(sender).rtcSender() : nullptr;
+
+    if (!rtcSender) {
+        m_endpoint->getStats(WTFMove(promise));
+        return;
+    }
+    m_endpoint->getStats(*rtcSender, WTFMove(promise));
+}
+
+void LibWebRTCPeerConnectionBackend::getStats(RTCRtpReceiver& receiver, Ref<DeferredPromise>&& promise)
+{
+    webrtc::RtpReceiverInterface* rtcReceiver = receiver.backend() ? static_cast<LibWebRTCRtpReceiverBackend*>(receiver.backend())->rtcReceiver() : nullptr;
+
+    if (!rtcReceiver) {
+        m_endpoint->getStats(WTFMove(promise));
+        return;
+    }
+    m_endpoint->getStats(*rtcReceiver, WTFMove(promise));
 }
 
 void LibWebRTCPeerConnectionBackend::doSetLocalDescription(RTCSessionDescription& description)
@@ -201,12 +229,12 @@ void LibWebRTCPeerConnectionBackend::doAddIceCandidate(RTCIceCandidate& candidat
     addIceCandidateSucceeded();
 }
 
-static inline Ref<RTCRtpReceiver> createReceiverForSource(ScriptExecutionContext& context, Ref<RealtimeMediaSource>&& source, std::unique_ptr<RTCRtpReceiverBackend>&& backend)
+Ref<RTCRtpReceiver> LibWebRTCPeerConnectionBackend::createReceiverForSource(Ref<RealtimeMediaSource>&& source, std::unique_ptr<RTCRtpReceiverBackend>&& backend)
 {
     auto remoteTrackPrivate = MediaStreamTrackPrivate::create(WTFMove(source), String { source->id() });
-    auto remoteTrack = MediaStreamTrack::create(context, WTFMove(remoteTrackPrivate));
+    auto remoteTrack = MediaStreamTrack::create(*m_peerConnection.scriptExecutionContext(), WTFMove(remoteTrackPrivate));
 
-    return RTCRtpReceiver::create(WTFMove(remoteTrack), WTFMove(backend));
+    return RTCRtpReceiver::create(*this, WTFMove(remoteTrack), WTFMove(backend));
 }
 
 static inline Ref<RealtimeMediaSource> createEmptySource(const String& trackKind, String&& trackId)
@@ -220,7 +248,7 @@ static inline Ref<RealtimeMediaSource> createEmptySource(const String& trackKind
 
 Ref<RTCRtpReceiver> LibWebRTCPeerConnectionBackend::createReceiver(const String& trackKind, const String& trackId)
 {
-    auto receiver = createReceiverForSource(*m_peerConnection.scriptExecutionContext(), createEmptySource(trackKind, String(trackId)), nullptr);
+    auto receiver = createReceiverForSource(createEmptySource(trackKind, String(trackId)), nullptr);
     m_pendingReceivers.append(receiver.copyRef());
     return receiver;
 }
@@ -238,10 +266,10 @@ LibWebRTCPeerConnectionBackend::VideoReceiver LibWebRTCPeerConnectionBackend::vi
         }
     }
     auto source = RealtimeIncomingVideoSource::create(nullptr, WTFMove(trackId));
-    auto receiver = createReceiverForSource(*m_peerConnection.scriptExecutionContext(), source.copyRef(), nullptr);
+    auto receiver = createReceiverForSource(source.copyRef(), nullptr);
 
     auto senderBackend = std::make_unique<LibWebRTCRtpSenderBackend>(*this, nullptr);
-    auto transceiver = RTCRtpTransceiver::create(RTCRtpSender::create("video", { }, WTFMove(senderBackend)), receiver.copyRef(), nullptr);
+    auto transceiver = RTCRtpTransceiver::create(RTCRtpSender::create(*this, "video"_s, { }, WTFMove(senderBackend)), receiver.copyRef(), nullptr);
     transceiver->disableSendingDirection();
     m_peerConnection.addTransceiver(WTFMove(transceiver));
 
@@ -261,10 +289,10 @@ LibWebRTCPeerConnectionBackend::AudioReceiver LibWebRTCPeerConnectionBackend::au
         }
     }
     auto source = RealtimeIncomingAudioSource::create(nullptr, WTFMove(trackId));
-    auto receiver = createReceiverForSource(*m_peerConnection.scriptExecutionContext(), source.copyRef(), nullptr);
+    auto receiver = createReceiverForSource(source.copyRef(), nullptr);
 
     auto senderBackend = std::make_unique<LibWebRTCRtpSenderBackend>(*this, nullptr);
-    auto transceiver = RTCRtpTransceiver::create(RTCRtpSender::create("audio", { }, WTFMove(senderBackend)), receiver.copyRef(), nullptr);
+    auto transceiver = RTCRtpTransceiver::create(RTCRtpSender::create(*this, "audio"_s, { }, WTFMove(senderBackend)), receiver.copyRef(), nullptr);
     transceiver->disableSendingDirection();
     m_peerConnection.addTransceiver(WTFMove(transceiver));
 
@@ -315,13 +343,6 @@ RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::remoteDescription(
     return m_endpoint->remoteDescription();
 }
 
-static inline LibWebRTCRtpSenderBackend& backendFromRTPSender(RTCRtpSender& sender)
-{
-    ASSERT(!sender.isStopped());
-    return static_cast<LibWebRTCRtpSenderBackend&>(*sender.backend());
-}
-
-
 static inline RefPtr<RTCRtpSender> findExistingSender(const Vector<std::reference_wrapper<RTCRtpSender>>& senders, LibWebRTCRtpSenderBackend& senderBackend)
 {
     ASSERT(senderBackend.rtcSender());
@@ -347,8 +368,8 @@ ExceptionOr<Ref<RTCRtpSender>> LibWebRTCPeerConnectionBackend::addTrack(MediaStr
 
         auto transceiverBackend = m_endpoint->transceiverBackendFromSender(*senderBackend);
 
-        auto sender = RTCRtpSender::create(makeRef(track), WTFMove(mediaStreamIds), WTFMove(senderBackend));
-        auto receiver = createReceiverForSource(*m_peerConnection.scriptExecutionContext(), createEmptySource(track.kind(), createCanonicalUUIDString()), transceiverBackend->createReceiverBackend());
+        auto sender = RTCRtpSender::create(*this, makeRef(track), WTFMove(mediaStreamIds), WTFMove(senderBackend));
+        auto receiver = createReceiverForSource(createEmptySource(track.kind(), createCanonicalUUIDString()), transceiverBackend->createReceiverBackend());
         auto transceiver = RTCRtpTransceiver::create(sender.copyRef(), WTFMove(receiver), WTFMove(transceiverBackend));
         m_peerConnection.addInternalTransceiver(WTFMove(transceiver));
         return WTFMove(sender);
@@ -373,7 +394,7 @@ ExceptionOr<Ref<RTCRtpSender>> LibWebRTCPeerConnectionBackend::addTrack(MediaStr
         String trackId = createCanonicalUUIDString();
 
         auto senderBackend = std::make_unique<LibWebRTCRtpSenderBackend>(*this, nullptr);
-        auto newSender = RTCRtpSender::create(makeRef(track), Vector<String> { mediaStreamIds }, WTFMove(senderBackend));
+        auto newSender = RTCRtpSender::create(*this, makeRef(track), Vector<String> { mediaStreamIds }, WTFMove(senderBackend));
         auto receiver = createReceiver(trackKind, trackId);
         auto transceiver = RTCRtpTransceiver::create(WTFMove(newSender), WTFMove(receiver), nullptr);
 
@@ -394,8 +415,8 @@ ExceptionOr<Ref<RTCRtpTransceiver>> LibWebRTCPeerConnectionBackend::addUnifiedPl
     if (!backends)
         return Exception { InvalidAccessError, "Unable to add transceiver"_s };
 
-    auto sender = RTCRtpSender::create(WTFMove(trackOrKind), Vector<String> { }, WTFMove(backends->senderBackend));
-    auto receiver = createReceiverForSource(*m_peerConnection.scriptExecutionContext(), createEmptySource(sender->trackKind(), createCanonicalUUIDString()), WTFMove(backends->receiverBackend));
+    auto sender = RTCRtpSender::create(*this, WTFMove(trackOrKind), Vector<String> { }, WTFMove(backends->senderBackend));
+    auto receiver = createReceiverForSource(createEmptySource(sender->trackKind(), createCanonicalUUIDString()), WTFMove(backends->receiverBackend));
     auto transceiver = RTCRtpTransceiver::create(WTFMove(sender), WTFMove(receiver), WTFMove(backends->transceiverBackend));
     m_peerConnection.addInternalTransceiver(transceiver.copyRef());
     return WTFMove(transceiver);
@@ -407,7 +428,7 @@ ExceptionOr<Ref<RTCRtpTransceiver>> LibWebRTCPeerConnectionBackend::addTransceiv
         return addUnifiedPlanTransceiver(String { trackKind }, init);
 
     auto senderBackend = std::make_unique<LibWebRTCRtpSenderBackend>(*this, nullptr);
-    auto newSender = RTCRtpSender::create(String(trackKind), Vector<String>(), WTFMove(senderBackend));
+    auto newSender = RTCRtpSender::create(*this, String(trackKind), Vector<String>(), WTFMove(senderBackend));
     return completeAddTransceiver(WTFMove(newSender), init, createCanonicalUUIDString(), trackKind);
 }
 
@@ -418,7 +439,7 @@ ExceptionOr<Ref<RTCRtpTransceiver>> LibWebRTCPeerConnectionBackend::addTransceiv
 
     auto senderBackend = std::make_unique<LibWebRTCRtpSenderBackend>(*this, nullptr);
     auto& backend = *senderBackend;
-    auto sender = RTCRtpSender::create(track.copyRef(), Vector<String>(), WTFMove(senderBackend));
+    auto sender = RTCRtpSender::create(*this, track.copyRef(), Vector<String>(), WTFMove(senderBackend));
     if (!m_endpoint->addTrack(backend, track, Vector<String> { }))
         return Exception { InvalidAccessError, "Unable to add track"_s };
 
@@ -441,8 +462,8 @@ RTCRtpTransceiver* LibWebRTCPeerConnectionBackend::existingTransceiver(WTF::Func
 
 RTCRtpTransceiver& LibWebRTCPeerConnectionBackend::newRemoteTransceiver(std::unique_ptr<LibWebRTCRtpTransceiverBackend>&& transceiverBackend, Ref<RealtimeMediaSource>&& receiverSource)
 {
-    auto sender = RTCRtpSender::create(receiverSource->type() == RealtimeMediaSource::Type::Audio ? "audio"_s : "video"_s, Vector<String> { }, transceiverBackend->createSenderBackend(*this, nullptr));
-    auto receiver = createReceiverForSource(*m_peerConnection.scriptExecutionContext(), WTFMove(receiverSource), transceiverBackend->createReceiverBackend());
+    auto sender = RTCRtpSender::create(*this, receiverSource->type() == RealtimeMediaSource::Type::Audio ? "audio"_s : "video"_s, Vector<String> { }, transceiverBackend->createSenderBackend(*this, nullptr));
+    auto receiver = createReceiverForSource(WTFMove(receiverSource), transceiverBackend->createReceiverBackend());
     auto transceiver = RTCRtpTransceiver::create(WTFMove(sender), WTFMove(receiver), WTFMove(transceiverBackend));
     m_peerConnection.addInternalTransceiver(transceiver.copyRef());
     return transceiver.get();
index 1f6850d..5ec7918 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "PeerConnectionBackend.h"
 #include <wtf/HashMap.h>
-#include <wtf/WeakPtr.h>
 
 namespace webrtc {
 class IceCandidateInterface;
@@ -40,6 +39,7 @@ class LibWebRTCMediaEndpoint;
 class LibWebRTCProvider;
 class LibWebRTCRtpTransceiverBackend;
 class RTCRtpReceiver;
+class RTCRtpReceiverBackend;
 class RTCSessionDescription;
 class RTCStatsReport;
 class RealtimeIncomingAudioSource;
@@ -48,7 +48,7 @@ class RealtimeMediaSource;
 class RealtimeOutgoingAudioSource;
 class RealtimeOutgoingVideoSource;
 
-class LibWebRTCPeerConnectionBackend final : public PeerConnectionBackend, public CanMakeWeakPtr<LibWebRTCPeerConnectionBackend> {
+class LibWebRTCPeerConnectionBackend final : public PeerConnectionBackend {
     WTF_MAKE_FAST_ALLOCATED;
 public:
     LibWebRTCPeerConnectionBackend(RTCPeerConnection&, LibWebRTCProvider&);
@@ -67,7 +67,9 @@ private:
     void doStop() final;
     std::unique_ptr<RTCDataChannelHandler> createDataChannelHandler(const String&, const RTCDataChannelInit&) final;
     bool setConfiguration(MediaEndpointConfiguration&&) final;
-    void getStats(MediaStreamTrack*, Ref<DeferredPromise>&&) final;
+    void getStats(Ref<DeferredPromise>&&) final;
+    void getStats(RTCRtpSender&, Ref<DeferredPromise>&&) final;
+    void getStats(RTCRtpReceiver&, Ref<DeferredPromise>&&) final;
 
     RefPtr<RTCSessionDescription> localDescription() const final;
     RefPtr<RTCSessionDescription> currentLocalDescription() const final;
@@ -116,6 +118,8 @@ private:
     template<typename T>
     ExceptionOr<Ref<RTCRtpTransceiver>> addUnifiedPlanTransceiver(T&& trackOrKind, const RTCRtpTransceiverInit&);
 
+    Ref<RTCRtpReceiver> createReceiverForSource(Ref<RealtimeMediaSource>&&, std::unique_ptr<RTCRtpReceiverBackend>&&);
+
     Ref<LibWebRTCMediaEndpoint> m_endpoint;
     bool m_isLocalDescriptionSet { false };
     bool m_isRemoteDescriptionSet { false };
index fd0d95e..3124323 100644 (file)
@@ -45,6 +45,8 @@ public:
     {
     }
 
+    webrtc::RtpReceiverInterface* rtcReceiver() { return m_rtcReceiver.get(); }
+
 private:
     RTCRtpParameters getParameters() final;
     Vector<RTCRtpContributingSource> getContributingSources() const final;