addTransceiver should trigger mid generation in the SDP
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 17 Jun 2017 00:27:33 +0000 (00:27 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 17 Jun 2017 00:27:33 +0000 (00:27 +0000)
https://bugs.webkit.org/show_bug.cgi?id=173452

Patch by Youenn Fablet <youenn@apple.com> on 2017-06-16
Reviewed by Alex Christensen.

Source/WebCore:

Test: webrtc/video-addTransceiver.html

Adding support for recvonly SDP based on call to addTransceiver.
Using offer_to_receive options of libwebrtc for that purpose.

Making sure that addTransceiver and using a real track afterwards is working too.

* Modules/mediastream/RTCPeerConnection.cpp:
(WebCore::RTCPeerConnection::enqueueReplaceTrackTask): notify the backend that a track is added in case the sender has no track.
* Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp:
(WebCore::LibWebRTCMediaEndpoint::shouldOfferAllowToReceiveAudio): Detect whether some audio mid should be recvonly.
(WebCore::LibWebRTCMediaEndpoint::shouldOfferAllowToReceiveVideo): Detect whether some video mid should be recvonly.
(WebCore::LibWebRTCMediaEndpoint::doCreateOffer):
* Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.h:
* Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h:

LayoutTests:

* webrtc/routines.js:
(createConnections):
* webrtc/video-addTransceiver-expected.txt: Added.
* webrtc/video-addTransceiver.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/webrtc/routines.js
LayoutTests/webrtc/video-addTransceiver-expected.txt [new file with mode: 0644]
LayoutTests/webrtc/video-addTransceiver.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp
Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp
Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.h
Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h

index a9371ca..5bfa512 100644 (file)
@@ -1,3 +1,15 @@
+2017-06-16  Youenn Fablet  <youenn@apple.com>
+
+        addTransceiver should trigger mid generation in the SDP
+        https://bugs.webkit.org/show_bug.cgi?id=173452
+
+        Reviewed by Alex Christensen.
+
+        * webrtc/routines.js:
+        (createConnections):
+        * webrtc/video-addTransceiver-expected.txt: Added.
+        * webrtc/video-addTransceiver.html: Added.
+
 2017-06-16  Jonathan Bedard  <jbedard@apple.com>
 
         Clean-up lint-test-expectation errors
index f276544..9567b38 100644 (file)
@@ -4,14 +4,16 @@ var remoteConnection;
 
 function createConnections(setupLocalConnection, setupRemoteConnection, options = { }) {
     localConnection = new RTCPeerConnection();
-    localConnection.onicecandidate = (event) => { iceCallback1(event, options.filterOutICECandidate) };
-    setupLocalConnection(localConnection);
-
     remoteConnection = new RTCPeerConnection();
     remoteConnection.onicecandidate = (event) => { iceCallback2(event, options.filterOutICECandidate) };
-    setupRemoteConnection(remoteConnection);
 
-    localConnection.createOffer().then((desc) => gotDescription1(desc, options), onCreateSessionDescriptionError);
+    localConnection.onicecandidate = (event) => { iceCallback1(event, options.filterOutICECandidate) };
+
+    Promise.resolve(setupLocalConnection(localConnection)).then(() => {
+        return Promise.resolve(setupRemoteConnection(remoteConnection));
+    }).then(() => {
+        localConnection.createOffer().then((desc) => gotDescription1(desc, options), onCreateSessionDescriptionError);
+    });
 
     return [localConnection, remoteConnection]
 }
diff --git a/LayoutTests/webrtc/video-addTransceiver-expected.txt b/LayoutTests/webrtc/video-addTransceiver-expected.txt
new file mode 100644 (file)
index 0000000..8790e6b
--- /dev/null
@@ -0,0 +1,6 @@
+
+
+PASS Setting up calls with addTransceiver but with no track 
+PASS Setting up calls with addTransceiver with a track 
+PASS Basic video exchange set up with addTransceiver 
+
diff --git a/LayoutTests/webrtc/video-addTransceiver.html b/LayoutTests/webrtc/video-addTransceiver.html
new file mode 100644 (file)
index 0000000..58f6773
--- /dev/null
@@ -0,0 +1,99 @@
+<!doctype html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <title>Testing basic video exchange from offerer to receiver</title>
+        <script src="../resources/testharness.js"></script>
+        <script src="../resources/testharnessreport.js"></script>
+    </head>
+    <body>
+        <video id="video" autoplay=""></video>
+        <canvas id="canvas" width="640" height="480"></canvas>
+        <script src ="routines.js"></script>
+        <script>
+
+promise_test((test) => {
+    var pc = new RTCPeerConnection();
+    pc.addTransceiver("video");
+
+    return pc.createOffer().then((offer) => {
+        assert_true(offer.sdp.indexOf("mid:video") !== -1);
+        assert_true(offer.sdp.indexOf("a=recvonly") !== -1);
+
+        pc.addTransceiver("audio");
+        return pc.createOffer();
+    }).then((offer) => {
+        assert_true(offer.sdp.indexOf("mid:audio") !== -1);
+    });
+}, "Setting up calls with addTransceiver but with no track");
+
+promise_test((test) => {
+    if (window.testRunner)
+        testRunner.setUserMediaPermission(true);
+
+    return navigator.mediaDevices.getUserMedia({ video: true }).then((stream) => {
+        var pc = new RTCPeerConnection();
+        pc.addTransceiver("video");
+        pc.getSenders()[0].replaceTrack(stream.getVideoTracks()[0]);
+
+        return pc.createOffer().then((offer) => {
+            assert_true(offer.sdp.indexOf("mid:video") !== -1);
+            // Replacing the track is not done yet so we still set it as a recvonly.
+            assert_true(offer.sdp.indexOf("a=recvonly") !== -1);
+        });
+    });
+}, "Setting up calls with addTransceiver with a track");
+
+function testImage()
+{
+    canvas.width = video.videoWidth;
+    canvas.height = video.videoHeight;
+    canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
+
+    imageData = canvas.getContext('2d').getImageData(10, 325, 250, 1);
+    data = imageData.data;
+
+    var index = 20;
+    assert_true(data[index] < 100);
+    assert_true(data[index + 1] < 100);
+    assert_true(data[index + 2] < 100);
+
+    index = 80;
+    assert_true(data[index] > 200);
+    assert_true(data[index + 1] > 200);
+    assert_true(data[index + 2] > 200);
+
+    index += 80;
+    assert_true(data[index] > 200);
+    assert_true(data[index + 1] > 200);
+    assert_true(data[index + 2] < 100);
+}
+
+promise_test((test) => {
+    if (window.testRunner)
+        testRunner.setUserMediaPermission(true);
+
+    return navigator.mediaDevices.getUserMedia({ video: true}).then((stream) => {
+        return new Promise((resolve, reject) => {
+            createConnections((firstConnection) => {
+                var track = stream.getVideoTracks()[0];
+                firstConnection.addTransceiver("video");
+                return firstConnection.getSenders()[0].replaceTrack(stream.getVideoTracks()[0]);
+            }, (secondConnection) => {
+                secondConnection.ontrack = (trackEvent) => {
+                    resolve(trackEvent.streams[0]);
+                };
+            });
+            setTimeout(() => reject("Test timed out"), 5000);
+        });
+    }).then((stream) => {
+        video.srcObject = stream;
+        return video.play();
+    }).then(() => {
+        testImage();
+    });
+}, "Basic video exchange set up with addTransceiver");
+
+        </script>
+    </body>
+</html>
index 52ef9ed..b0e4b25 100644 (file)
@@ -1,5 +1,28 @@
 2017-06-16  Youenn Fablet  <youenn@apple.com>
 
+        addTransceiver should trigger mid generation in the SDP
+        https://bugs.webkit.org/show_bug.cgi?id=173452
+
+        Reviewed by Alex Christensen.
+
+        Test: webrtc/video-addTransceiver.html
+
+        Adding support for recvonly SDP based on call to addTransceiver.
+        Using offer_to_receive options of libwebrtc for that purpose.
+
+        Making sure that addTransceiver and using a real track afterwards is working too.
+
+        * Modules/mediastream/RTCPeerConnection.cpp:
+        (WebCore::RTCPeerConnection::enqueueReplaceTrackTask): notify the backend that a track is added in case the sender has no track.
+        * Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp:
+        (WebCore::LibWebRTCMediaEndpoint::shouldOfferAllowToReceiveAudio): Detect whether some audio mid should be recvonly.
+        (WebCore::LibWebRTCMediaEndpoint::shouldOfferAllowToReceiveVideo): Detect whether some video mid should be recvonly.
+        (WebCore::LibWebRTCMediaEndpoint::doCreateOffer):
+        * Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.h:
+        * Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h:
+
+2017-06-16  Youenn Fablet  <youenn@apple.com>
+
         WebCore::LibWebRTCMediaEndpoint::gatherStatsForLogging is crashing
         https://bugs.webkit.org/show_bug.cgi?id=173493
 
index 95bb609..2c87c30 100644 (file)
@@ -558,8 +558,11 @@ void RTCPeerConnection::fireEvent(Event& event)
 
 void RTCPeerConnection::enqueueReplaceTrackTask(RTCRtpSender& sender, Ref<MediaStreamTrack>&& withTrack, DOMPromiseDeferred<void>&& promise)
 {
-    scriptExecutionContext()->postTask([protectedSender = makeRef(sender), promise = WTFMove(promise), withTrack = WTFMove(withTrack)](ScriptExecutionContext&) mutable {
+    scriptExecutionContext()->postTask([protectedThis = makeRef(*this), protectedSender = makeRef(sender), promise = WTFMove(promise), withTrack = WTFMove(withTrack)](ScriptExecutionContext&) mutable {
+        if (protectedThis->isClosed())
+            return;
         protectedSender->setTrack(WTFMove(withTrack));
+        protectedThis->m_backend->notifyAddedTrack(protectedSender.get());
         promise.resolve();
     });
 }
index a5ac0c3..63bbad5 100644 (file)
@@ -205,12 +205,47 @@ void LibWebRTCMediaEndpoint::removeTrack(RTCRtpSender& sender)
     m_backend->RemoveTrack(rtcSender.get());
 }
 
+bool LibWebRTCMediaEndpoint::shouldOfferAllowToReceiveAudio() const
+{
+    for (const auto& transceiver : m_peerConnectionBackend.connection().getTransceivers()) {
+        if (transceiver->sender().trackKind() != "audio")
+            continue;
+
+        if (transceiver->direction() == RTCRtpTransceiverDirection::Recvonly)
+            return true;
+
+        if (transceiver->direction() == RTCRtpTransceiverDirection::Sendrecv && !m_senders.contains(&transceiver->sender()))
+            return true;
+    }
+    return false;
+}
+
+bool LibWebRTCMediaEndpoint::shouldOfferAllowToReceiveVideo() const
+{
+    for (const auto& transceiver : m_peerConnectionBackend.connection().getTransceivers()) {
+        if (transceiver->sender().trackKind() != "video")
+            continue;
+
+        if (transceiver->direction() == RTCRtpTransceiverDirection::Recvonly)
+            return true;
+
+        if (transceiver->direction() == RTCRtpTransceiverDirection::Sendrecv && !m_senders.contains(&transceiver->sender()))
+            return true;
+    }
+    return false;
+}
+
 void LibWebRTCMediaEndpoint::doCreateOffer(const RTCOfferOptions& options)
 {
     m_isInitiator = true;
     webrtc::PeerConnectionInterface::RTCOfferAnswerOptions rtcOptions;
     rtcOptions.ice_restart = options.iceRestart;
     rtcOptions.voice_activity_detection = options.voiceActivityDetection;
+    // FIXME: offer_to_receive_audio and offer_to_receive_video are used as libwebrtc does not support transceivers yet.
+    if (shouldOfferAllowToReceiveAudio())
+        rtcOptions.offer_to_receive_audio = webrtc::PeerConnectionInterface::RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
+    if (shouldOfferAllowToReceiveVideo())
+        rtcOptions.offer_to_receive_video = webrtc::PeerConnectionInterface::RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
     m_backend->CreateOffer(&m_createSessionDescriptionObserver, rtcOptions);
 }
 
index 8f06b80..6cec3a2 100644 (file)
@@ -121,6 +121,9 @@ private:
     int AddRef() const { ref(); return static_cast<int>(refCount()); }
     int Release() const { deref(); return static_cast<int>(refCount()); }
 
+    bool shouldOfferAllowToReceiveAudio() const;
+    bool shouldOfferAllowToReceiveVideo() const;
+
     class CreateSessionDescriptionObserver final : public webrtc::CreateSessionDescriptionObserver {
     public:
         explicit CreateSessionDescriptionObserver(LibWebRTCMediaEndpoint &endpoint) : m_endpoint(endpoint) { }
index dc97538..0c5212b 100644 (file)
@@ -49,6 +49,9 @@ public:
     explicit LibWebRTCPeerConnectionBackend(RTCPeerConnection&);
     ~LibWebRTCPeerConnectionBackend();
 
+    bool hasAudioSources() const { return m_audioSources.size(); }
+    bool hasVideoSources() const { return m_videoSources.size(); }
+
 private:
     void doCreateOffer(RTCOfferOptions&&) final;
     void doCreateAnswer(RTCAnswerOptions&&) final;