WebRTC: Update RTCPeerConnection.addTrack() to create (or reuse) an RTCRtpTransceiver
authoradam.bergkvist@ericsson.com <adam.bergkvist@ericsson.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 2 Jun 2016 17:50:25 +0000 (17:50 +0000)
committeradam.bergkvist@ericsson.com <adam.bergkvist@ericsson.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 2 Jun 2016 17:50:25 +0000 (17:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=158191

Reviewed by Eric Carlson.

Source/WebCore:

Update RTCPeerConnection.addTrack to create an RTCRtpTranscevier, or reuse an existing
transceiver that has not been used to send [1].

A new RtpTransceiverSet type is added that wraps a vector of RTCRtpTransceiver objects
and internally maintains two lists for efficient access to RTCRtpSender and RTCRtpReceiver
objects.

[1] https://w3c.github.io/webrtc-pc/archives/20160513/webrtc.html#dom-rtcpeerconnection-addtrack

Updated existing test: fast/mediastream/RTCPeerConnection-add-removeTrack.html

* Modules/mediastream/PeerConnectionBackend.h:
* Modules/mediastream/RTCPeerConnection.cpp:
(WebCore::RTCPeerConnection::addTrack):
(WebCore::RTCPeerConnection::removeTrack):
(WebCore::RTCPeerConnection::completeAddTransceiver):
(WebCore::RTCPeerConnection::close):
* Modules/mediastream/RTCPeerConnection.h:
* Modules/mediastream/RTCRtpTransceiver.cpp:
(WebCore::RtpTransceiverSet::append):
* Modules/mediastream/RTCRtpTransceiver.h:
(WebCore::RtpTransceiverSet::list):
(WebCore::RtpTransceiverSet::getSenders):
(WebCore::RtpTransceiverSet::getReceivers):

LayoutTests:

Extend existing test to verify the created RTCRtpTransceiver object.

* fast/mediastream/RTCPeerConnection-add-removeTrack-expected.txt:
* fast/mediastream/RTCPeerConnection-add-removeTrack.html:
Add checks for bad argument lists and verify the created RTCRtpTransceiver.

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

LayoutTests/ChangeLog
LayoutTests/fast/mediastream/RTCPeerConnection-add-removeTrack-expected.txt
LayoutTests/fast/mediastream/RTCPeerConnection-add-removeTrack.html
Source/WebCore/ChangeLog
Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.cpp
Source/WebCore/Modules/mediastream/PeerConnectionBackend.h
Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp
Source/WebCore/Modules/mediastream/RTCPeerConnection.h
Source/WebCore/Modules/mediastream/RTCRtpTransceiver.cpp
Source/WebCore/Modules/mediastream/RTCRtpTransceiver.h

index c66c421..846e01b 100644 (file)
@@ -1,3 +1,16 @@
+2016-06-02  Adam Bergkvist  <adam.bergkvist@ericsson.com>
+
+        WebRTC: Update RTCPeerConnection.addTrack() to create (or reuse) an RTCRtpTransceiver
+        https://bugs.webkit.org/show_bug.cgi?id=158191
+
+        Reviewed by Eric Carlson.
+
+        Extend existing test to verify the created RTCRtpTransceiver object.
+
+        * fast/mediastream/RTCPeerConnection-add-removeTrack-expected.txt:
+        * fast/mediastream/RTCPeerConnection-add-removeTrack.html:
+        Add checks for bad argument lists and verify the created RTCRtpTransceiver.
+
 2016-06-02  Per Arne Vollan  <pvollan@apple.com>
 
         Unreviewed test gardening.
index 5fd5c74..c34d8de 100644 (file)
@@ -3,12 +3,34 @@ Test basic behavior of RTCPeerConnection.add/removeTrack()
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
+Test bad addTrack() arguments
+PASS pc.addTrack() threw exception TypeError: Not enough arguments.
+PASS pc.addTrack(null) threw exception TypeError: Argument 1 ('track') to RTCPeerConnection.addTrack must be an instance of MediaStreamTrack.
+PASS pc.addTrack({}) threw exception TypeError: Argument 1 ('track') to RTCPeerConnection.addTrack must be an instance of MediaStreamTrack.
+PASS pc.addTrack(track, null) threw exception TypeError: Argument 2 ('streams') to RTCPeerConnection.addTrack must be an instance of MediaStream.
+PASS pc.addTrack(track, {}) threw exception TypeError: Argument 2 ('streams') to RTCPeerConnection.addTrack must be an instance of MediaStream.
+PASS pc.addTrack(track, stream, null) threw exception TypeError: Argument 3 ('streams') to RTCPeerConnection.addTrack must be an instance of MediaStream.
+
+Test bad removeTrack() arguments
+PASS pc.removeTrack() threw exception TypeError: Not enough arguments.
+PASS pc.removeTrack(null) threw exception TypeError: Argument 1 ('sender') to RTCPeerConnection.removeTrack must be an instance of RTCRtpSender.
+PASS pc.removeTrack({}) threw exception TypeError: Argument 1 ('sender') to RTCPeerConnection.removeTrack must be an instance of RTCRtpSender.
+
 PASS pc.getSenders().length is 0
 PASS sender = pc.addTrack(track, stream) did not throw exception.
 PASS sender is an instance of RTCRtpSender
 PASS sender.track is track
 PASS pc.getSenders().length is 1
 PASS pc.getSenders()[0] is sender
+PASS pc.getReceivers().length is 1
+PASS receiver.track is an instance of MediaStreamTrack
+PASS receiver.track.muted is true
+PASS receiver.track.kind is sender.track.kind
+PASS pc.getTransceivers().length is 1
+PASS transceiver.mid is null
+PASS transceiver.sender is sender
+PASS transceiver.receiver is receiver
+PASS transceiver.stopped is false
 Try to add same track again
 PASS sender = pc.addTrack(track, stream) threw exception Error: InvalidModificationError: DOM Exception 13.
 PASS sender2 = pc.addTrack(track2, stream, stream2) did not throw exception.
index 7a6d0cf..4828a85 100644 (file)
@@ -12,6 +12,8 @@
             var sender;
             var sender2;
             var senderFromPc2
+            var receiver;
+            var transceiver;
 
             description("Test basic behavior of RTCPeerConnection.add/removeTrack()");
 
                 stream = s;
                 track = stream.getTracks()[0];
 
+                debug("Test bad addTrack() arguments");
+                shouldThrow("pc.addTrack()");
+                shouldThrow("pc.addTrack(null)");
+                shouldThrow("pc.addTrack({})");
+                shouldThrow("pc.addTrack(track, null)");
+                shouldThrow("pc.addTrack(track, {})");
+                shouldThrow("pc.addTrack(track, stream, null)");
+                debug("");
+
+                debug("Test bad removeTrack() arguments");
+                shouldThrow("pc.removeTrack()");
+                shouldThrow("pc.removeTrack(null)");
+                shouldThrow("pc.removeTrack({})");
+                debug("");
+
                 shouldBe("pc.getSenders().length", "0");
 
                 shouldNotThrow("sender = pc.addTrack(track, stream)");
                 shouldBe("pc.getSenders().length", "1");
                 shouldBe("pc.getSenders()[0]", "sender");
 
+                shouldBe("pc.getReceivers().length", "1");
+                receiver = pc.getReceivers()[0];
+                shouldBeType("receiver.track", "MediaStreamTrack");
+                shouldBeTrue("receiver.track.muted");
+
+                shouldBe("receiver.track.kind", "sender.track.kind");
+
+                shouldBe("pc.getTransceivers().length", "1");
+                transceiver = pc.getTransceivers()[0];
+                shouldBeNull("transceiver.mid");
+                shouldBe("transceiver.sender", "sender");
+                shouldBe("transceiver.receiver", "receiver");
+                shouldBeFalse("transceiver.stopped");
+
                 debug("Try to add same track again");
                 shouldThrow("sender = pc.addTrack(track, stream)");
 
index 115a1e0..ae2955c 100644 (file)
@@ -1,3 +1,35 @@
+2016-06-02  Adam Bergkvist  <adam.bergkvist@ericsson.com>
+
+        WebRTC: Update RTCPeerConnection.addTrack() to create (or reuse) an RTCRtpTransceiver
+        https://bugs.webkit.org/show_bug.cgi?id=158191
+
+        Reviewed by Eric Carlson.
+
+        Update RTCPeerConnection.addTrack to create an RTCRtpTranscevier, or reuse an existing
+        transceiver that has not been used to send [1].
+
+        A new RtpTransceiverSet type is added that wraps a vector of RTCRtpTransceiver objects
+        and internally maintains two lists for efficient access to RTCRtpSender and RTCRtpReceiver
+        objects.
+
+        [1] https://w3c.github.io/webrtc-pc/archives/20160513/webrtc.html#dom-rtcpeerconnection-addtrack
+
+        Updated existing test: fast/mediastream/RTCPeerConnection-add-removeTrack.html
+
+        * Modules/mediastream/PeerConnectionBackend.h:
+        * Modules/mediastream/RTCPeerConnection.cpp:
+        (WebCore::RTCPeerConnection::addTrack):
+        (WebCore::RTCPeerConnection::removeTrack):
+        (WebCore::RTCPeerConnection::completeAddTransceiver):
+        (WebCore::RTCPeerConnection::close):
+        * Modules/mediastream/RTCPeerConnection.h:
+        * Modules/mediastream/RTCRtpTransceiver.cpp:
+        (WebCore::RtpTransceiverSet::append):
+        * Modules/mediastream/RTCRtpTransceiver.h:
+        (WebCore::RtpTransceiverSet::list):
+        (WebCore::RtpTransceiverSet::getSenders):
+        (WebCore::RtpTransceiverSet::getReceivers):
+
 2016-06-02  Youenn Fablet  <youenn.fablet@crf.canon.fr>
 
         Use more references in ResourceLoader related code
index dc851bf..9668f30 100644 (file)
@@ -132,7 +132,7 @@ void MediaEndpointPeerConnection::createOfferTask(RTCOfferOptions&, SessionDescr
 
     configurationSnapshot->setSessionVersion(m_sdpSessionVersion++);
 
-    RtpSenderVector senders = m_client->getSenders();
+    RtpSenderVector senders = RtpSenderVector(m_client->getSenders());
 
     // Add media descriptions for senders.
     for (auto& sender : senders) {
index f4b37f8..b381ce5 100644 (file)
@@ -61,7 +61,8 @@ typedef DOMPromise<RTCStatsResponse> StatsPromise;
 
 class PeerConnectionBackendClient {
 public:
-    virtual Vector<RefPtr<RTCRtpSender>> getSenders() const = 0;
+    virtual const Vector<RefPtr<RTCRtpTransceiver>>& getTransceivers() const = 0;
+    virtual const Vector<RefPtr<RTCRtpSender>>& getSenders() const = 0;
     virtual void fireEvent(Event&) = 0;
 
     virtual void setSignalingState(PeerConnectionStates::SignalingState) = 0;
index 8f2ec9b..42345fd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2012 Google Inc. All rights reserved.
  * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
- * Copyright (C) 2015 Ericsson AB. All rights reserved.
+ * Copyright (C) 2015, 2016 Ericsson AB. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -113,7 +113,7 @@ RefPtr<RTCRtpSender> RTCPeerConnection::addTrack(Ref<MediaStreamTrack>&& track,
         return nullptr;
     }
 
-    for (auto& sender : m_senderSet) {
+    for (auto& sender : m_transceiverSet->getSenders()) {
         if (sender->trackId() == track->id()) {
             // FIXME: Spec says InvalidParameter
             ec = INVALID_MODIFICATION_ERR;
@@ -125,8 +125,36 @@ RefPtr<RTCRtpSender> RTCPeerConnection::addTrack(Ref<MediaStreamTrack>&& track,
     for (auto stream : streams)
         mediaStreamIds.append(stream->id());
 
-    RefPtr<RTCRtpSender> sender = RTCRtpSender::create(WTFMove(track), WTFMove(mediaStreamIds), *this);
-    m_senderSet.append(sender);
+    RTCRtpSender* sender = nullptr;
+
+    // Reuse an existing sender with the same track kind if it has never been used to send before.
+    for (auto& transceiver : m_transceiverSet->list()) {
+        RTCRtpSender& existingSender = *transceiver->sender();
+        if (existingSender.trackKind() == track->kind() && existingSender.trackId().isNull() && !transceiver->hasSendingDirection()) {
+            existingSender.setTrack(WTFMove(track));
+            existingSender.setMediaStreamIds(WTFMove(mediaStreamIds));
+            transceiver->enableSendingDirection();
+            sender = &existingSender;
+            break;
+        }
+    }
+
+    if (!sender) {
+        String transceiverMid = RTCRtpTransceiver::getNextMid();
+        const String& trackKind = track->kind();
+        String trackId = createCanonicalUUIDString();
+
+        auto newSender = RTCRtpSender::create(WTFMove(track), WTFMove(mediaStreamIds), *this);
+        auto receiver = m_backend->createReceiver(transceiverMid, trackKind, trackId);
+        auto transceiver = RTCRtpTransceiver::create(WTFMove(newSender), WTFMove(receiver));
+
+        // This transceiver is not yet associated with an m-line (null mid), but we need a
+        // provisional mid if the transceiver is used to create an offer.
+        transceiver->setProvisionalMid(transceiverMid);
+
+        sender = transceiver->sender();
+        m_transceiverSet->append(WTFMove(transceiver));
+    }
 
     m_backend->markAsNeedingNegotiation();
 
@@ -140,7 +168,7 @@ void RTCPeerConnection::removeTrack(RTCRtpSender& sender, ExceptionCode& ec)
         return;
     }
 
-    if (!m_senderSet.contains(&sender))
+    if (!m_transceiverSet->getSenders().contains(&sender))
         return;
 
     sender.stop();
@@ -194,7 +222,7 @@ RefPtr<RTCRtpTransceiver> RTCPeerConnection::completeAddTransceiver(Ref<RTCRtpTr
 {
     transceiver->setDirection(static_cast<RTCRtpTransceiver::Direction>(init.direction));
 
-    m_transceiverSet.append(transceiver.copyRef());
+    m_transceiverSet->append(transceiver.copyRef());
     m_backend->markAsNeedingNegotiation();
 
     return WTFMove(transceiver);
@@ -404,7 +432,7 @@ void RTCPeerConnection::close()
     m_iceConnectionState = IceConnectionState::Closed;
     m_signalingState = SignalingState::Closed;
 
-    for (auto& sender : m_senderSet)
+    for (auto& sender : m_transceiverSet->getSenders())
         sender->stop();
 }
 
index 0536cec..54fa805 100644 (file)
@@ -63,9 +63,9 @@ public:
     static RefPtr<RTCPeerConnection> create(ScriptExecutionContext&, const Dictionary& rtcConfiguration, ExceptionCode&);
     ~RTCPeerConnection();
 
-    Vector<RefPtr<RTCRtpSender>> getSenders() const override { return m_senderSet; }
-    Vector<RefPtr<RTCRtpReceiver>> getReceivers() const { return m_receiverSet; }
-    const Vector<RefPtr<RTCRtpTransceiver>>& getTransceivers() const { return m_transceiverSet; }
+    const Vector<RefPtr<RTCRtpSender>>& getSenders() const override { return m_transceiverSet->getSenders(); }
+    const Vector<RefPtr<RTCRtpReceiver>>& getReceivers() const { return m_transceiverSet->getReceivers(); }
+    const Vector<RefPtr<RTCRtpTransceiver>>& getTransceivers() const override { return m_transceiverSet->list(); }
 
     RefPtr<RTCRtpSender> addTrack(Ref<MediaStreamTrack>&&, Vector<MediaStream*>, ExceptionCode&);
     void removeTrack(RTCRtpSender&, ExceptionCode&);
@@ -149,9 +149,7 @@ private:
     PeerConnectionStates::IceGatheringState m_iceGatheringState;
     PeerConnectionStates::IceConnectionState m_iceConnectionState;
 
-    Vector<RefPtr<RTCRtpSender>> m_senderSet;
-    Vector<RefPtr<RTCRtpReceiver>> m_receiverSet;
-    Vector<RefPtr<RTCRtpTransceiver>> m_transceiverSet;
+    std::unique_ptr<RtpTransceiverSet> m_transceiverSet { std::unique_ptr<RtpTransceiverSet>(new RtpTransceiverSet()) };
 
     Vector<RefPtr<RTCDataChannel>> m_dataChannels;
 
index 762bd4d..e293df4 100644 (file)
@@ -101,6 +101,14 @@ void RTCRtpTransceiver::disableSendingDirection()
         m_direction = Direction::Inactive;
 }
 
+void RtpTransceiverSet::append(RefPtr<RTCRtpTransceiver>&& transceiver)
+{
+    m_senders.append(transceiver->sender());
+    m_receivers.append(transceiver->receiver());
+
+    m_transceivers.append(WTFMove(transceiver));
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(WEB_RTC)
index 1ed4ddc..ba3cb64 100644 (file)
@@ -86,6 +86,21 @@ private:
     bool m_stopped { false };
 };
 
+class RtpTransceiverSet {
+public:
+    const Vector<RefPtr<RTCRtpTransceiver>>& list() const { return m_transceivers; }
+    void append(RefPtr<RTCRtpTransceiver>&&);
+
+    const Vector<RefPtr<RTCRtpSender>>& getSenders() const { return m_senders; }
+    const Vector<RefPtr<RTCRtpReceiver>>& getReceivers() const { return m_receivers; }
+
+private:
+    Vector<RefPtr<RTCRtpTransceiver>> m_transceivers;
+
+    Vector<RefPtr<RTCRtpSender>> m_senders;
+    Vector<RefPtr<RTCRtpReceiver>> m_receivers;
+};
+
 } // namespace WebCore
 
 #endif // ENABLE(WEB_RTC)