Diff
Modified: trunk/LayoutTests/ChangeLog (214356 => 214357)
--- trunk/LayoutTests/ChangeLog 2017-03-24 17:46:36 UTC (rev 214356)
+++ trunk/LayoutTests/ChangeLog 2017-03-24 18:01:18 UTC (rev 214357)
@@ -1,3 +1,17 @@
+2017-03-24 Youenn Fablet <[email protected]>
+
+ Add libwebrtc backend support for RTCRtpSender::replaceTrack
+ https://bugs.webkit.org/show_bug.cgi?id=169841
+
+ Reviewed by Alex Christensen.
+
+ * webrtc/audio-replace-track-expected.txt: Added.
+ * webrtc/audio-replace-track.html: Added.
+ * webrtc/video-replace-track-expected.txt: Added.
+ * webrtc/video-replace-track.html: Added.
+ * webrtc/video-replace-track-to-null-expected.txt: Added.
+ * webrtc/video-replace-track-to-null.html: Added.
+
2017-03-24 Ryan Haddad <[email protected]>
Update TestExpectations for media/restore-from-page-cache.html.
Added: trunk/LayoutTests/webrtc/audio-replace-track-expected.txt (0 => 214357)
--- trunk/LayoutTests/webrtc/audio-replace-track-expected.txt (rev 0)
+++ trunk/LayoutTests/webrtc/audio-replace-track-expected.txt 2017-03-24 18:01:18 UTC (rev 214357)
@@ -0,0 +1,3 @@
+
+PASS Replacing audio track from a peer connection
+
Added: trunk/LayoutTests/webrtc/audio-replace-track.html (0 => 214357)
--- trunk/LayoutTests/webrtc/audio-replace-track.html (rev 0)
+++ trunk/LayoutTests/webrtc/audio-replace-track.html 2017-03-24 18:01:18 UTC (rev 214357)
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Testing local audio capture playback causes "playing" event to fire</title>
+ <script src=""
+ <script src=""
+ <script src =""
+ <script>
+ promise_test((test) => {
+ if (window.testRunner)
+ testRunner.setUserMediaPermission(true);
+
+ var sender;
+ var firsStream;
+ var secondStream;
+ var remoteStream;
+ return navigator.mediaDevices.getUserMedia({ audio: { sampleRate: { exact: 48000 } } }).then((stream) => {
+ firstStream = stream;
+ return navigator.mediaDevices.getUserMedia({ audio: { sampleRate: { exact: 48000 } } });
+ }).then((stream) => {
+ secondStream = stream;
+ if (window.internals)
+ internals.useMockRTCPeerConnectionFactory("TwoRealPeerConnections");
+ return new Promise((resolve, reject) => {
+ createConnections((firstConnection) => {
+ sender = firstConnection.addTrack(firstStream.getAudioTracks()[0], firstStream);
+ }, (secondConnection) => {
+ secondConnection._ontrack_ = (trackEvent) => { resolve(trackEvent.streams[0]); };
+ });
+ setTimeout(() => reject("Test timed out"), 5000);
+ });
+ }).then((stream) => {
+ remoteStream = stream;
+ return analyseAudio(remoteStream, 1000);
+ }).then((results) => {
+ assert_true(results.heardHum, "heard hum");
+ return sender.replaceTrack(secondStream.getAudioTracks()[0], secondStream);
+ }).then(() => {
+ assert_true(sender.track === secondStream.getAudioTracks()[0]);
+ return waitFor(500);
+ }).then((results) => {
+ return analyseAudio(remoteStream, 1000);
+ }).then((results) => {
+ assert_true(results.heardHum, "heard hum");
+ });
+ }, "Replacing audio track from a peer connection");
+ </script>
+</head>
+<body>
+</body>
+</html>
Added: trunk/LayoutTests/webrtc/video-replace-track-expected.txt (0 => 214357)
--- trunk/LayoutTests/webrtc/video-replace-track-expected.txt (rev 0)
+++ trunk/LayoutTests/webrtc/video-replace-track-expected.txt 2017-03-24 18:01:18 UTC (rev 214357)
@@ -0,0 +1,5 @@
+
+PASS Switching from front to back camera
+FAIL Switching from front to back camera, with lower resolution assert_true: backStream should be smaller expected true got false
+FAIL Switching from front to back camera, with higher resolution assert_true: front stream should be smaller expected true got false
+
Added: trunk/LayoutTests/webrtc/video-replace-track-to-null-expected.txt (0 => 214357)
--- trunk/LayoutTests/webrtc/video-replace-track-to-null-expected.txt (rev 0)
+++ trunk/LayoutTests/webrtc/video-replace-track-to-null-expected.txt 2017-03-24 18:01:18 UTC (rev 214357)
@@ -0,0 +1,3 @@
+
+PASS Stopping sending video using replaceTrack
+
Added: trunk/LayoutTests/webrtc/video-replace-track-to-null.html (0 => 214357)
--- trunk/LayoutTests/webrtc/video-replace-track-to-null.html (rev 0)
+++ trunk/LayoutTests/webrtc/video-replace-track-to-null.html 2017-03-24 18:01:18 UTC (rev 214357)
@@ -0,0 +1,103 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Testing basic video exchange from offerer to receiver</title>
+ <script src=""
+ <script src=""
+ </head>
+ <body>
+<div id="log"></div>
+ <video id="video" autoplay=""></video>
+ <canvas id="canvas" width="640" height="480"></canvas>
+ <script src =""
+ <script>
+video = document.getElementById("video");
+canvas = document.getElementById("canvas");
+
+function grabImagePixels()
+{
+ canvas.width = video.videoWidth;
+ canvas.height = video.videoHeight;
+ canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
+
+ imageData = canvas.getContext('2d').getImageData(20, 20, 100, 100);
+ return imageData.data;
+ }
+
+var firstFrameData;
+
+function storeFrame()
+{
+ firstFrameData = grabImagePixels();
+}
+
+function testCameraImage()
+{
+ data = ""
+
+ assert_true(data[0] < 20);
+ assert_true(data[1] < 20);
+ assert_true(data[2] < 20);
+
+ var same = true;
+ for (var cptr = 0; cptr < data.length; ++cptr) {
+ if (data[cptr] != firstFrameData[cptr]) {
+ same = false;
+ break;
+ }
+ }
+ assert_false(same);
+}
+
+function testStoppedImage()
+{
+ assert_array_equals(grabImagePixels(), firstFrameData);
+}
+
+promise_test((test) => {
+ if (window.testRunner)
+ testRunner.setUserMediaPermission(true);
+
+ var sender;
+ var frontStream;
+ return navigator.mediaDevices.getUserMedia({ video: true }).then((stream) => {
+ frontStream = stream;
+ }).then(() => {
+ return new Promise((resolve, reject) => {
+ if (window.internals)
+ internals.useMockRTCPeerConnectionFactory("TwoRealPeerConnections");
+
+ createConnections((firstConnection) => {
+ sender = firstConnection.addTrack(frontStream.getVideoTracks()[0], frontStream);
+ }, (secondConnection) => {
+ secondConnection._ontrack_ = (trackEvent) => {
+ resolve(trackEvent.streams[0]);
+ };
+ });
+ setTimeout(() => reject("Test timed out"), 5000);
+ });
+ }).then((remoteStream) => {
+ video.srcObject = remoteStream;
+ return video.play();
+ }).then(() => {
+ storeFrame();
+ return waitFor(100);
+ }).then(() => {
+ testCameraImage();
+ }).then(() => {
+ promise = sender.replaceTrack(null);
+ assert_true(!!sender.track);
+ return promise;
+ }).then(() => {
+ return waitFor(100);
+ }).then(() => {
+ storeFrame();
+ return waitFor(100);
+ }).then(() => {
+ testStoppedImage();
+ });
+}, "Stopping sending video using replaceTrack");
+ </script>
+ </body>
+</html>
Added: trunk/LayoutTests/webrtc/video-replace-track.html (0 => 214357)
--- trunk/LayoutTests/webrtc/video-replace-track.html (rev 0)
+++ trunk/LayoutTests/webrtc/video-replace-track.html 2017-03-24 18:01:18 UTC (rev 214357)
@@ -0,0 +1,181 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Testing basic video exchange from offerer to receiver</title>
+ <script src=""
+ <script src=""
+ </head>
+ <body>
+<div id="log"></div>
+ <video id="video" autoplay=""></video>
+ <canvas id="canvas" width="640" height="480"></canvas>
+ <script src =""
+ <script>
+video = document.getElementById("video");
+canvas = document.getElementById("canvas");
+
+function grabImagePixels()
+{
+ canvas.width = video.videoWidth;
+ canvas.height = video.videoHeight;
+ canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
+
+ imageData = canvas.getContext('2d').getImageData(20, 20, 2, 2);
+ return imageData.data;
+ }
+
+function testFrontCameraImage()
+{
+ data = ""
+
+ assert_true(data[0] < 20);
+ assert_true(data[1] < 20);
+ assert_true(data[2] < 20);
+}
+
+function testBackCameraImage()
+{
+ data = ""
+
+ assert_true(data[0] > 100);
+ assert_true(data[1] > 100);
+ assert_true(data[2] > 100);
+
+ assert_true(data[0] < 200);
+ assert_true(data[1] < 200);
+ assert_true(data[2] < 200);
+}
+
+promise_test((test) => {
+ if (window.testRunner)
+ testRunner.setUserMediaPermission(true);
+
+ var sender;
+ var frontStream;
+ var backStream;
+ return navigator.mediaDevices.getUserMedia({ video: { facingMode: { exact: ["user"] } } }).then((stream) => {
+ frontStream = stream;
+ return navigator.mediaDevices.getUserMedia({ video: { facingMode: { exact: ["environment"] } } });
+ }).then((stream) => {
+ backStream = stream;
+ }).then(() => {
+ return new Promise((resolve, reject) => {
+ if (window.internals)
+ internals.useMockRTCPeerConnectionFactory("TwoRealPeerConnections");
+
+ createConnections((firstConnection) => {
+ sender = firstConnection.addTrack(frontStream.getVideoTracks()[0], frontStream);
+ }, (secondConnection) => {
+ secondConnection._ontrack_ = (trackEvent) => {
+ resolve(trackEvent.streams[0]);
+ };
+ });
+ setTimeout(() => reject("Test timed out"), 5000);
+ });
+ }).then((remoteStream) => {
+ video.srcObject = remoteStream;
+ return video.play();
+ }).then(() => {
+ testFrontCameraImage();
+ }).then(() => {
+ var currentTrack = sender.track;
+ promise = sender.replaceTrack(backStream.getVideoTracks()[0]);
+ assert_true(currentTrack === sender.track);
+ return promise;
+ }).then(() => {
+ assert_true(sender.track === backStream.getVideoTracks()[0]);
+ return waitFor(500);
+ }).then(() => {
+ testBackCameraImage();
+ });
+}, "Switching from front to back camera");
+
+promise_test((test) => {
+ if (window.testRunner)
+ testRunner.setUserMediaPermission(true);
+
+ var sender;
+ var frontStream;
+ var backStream;
+
+ return navigator.mediaDevices.getUserMedia({ video: { height: { min: 400 }, facingMode: { exact: ["user"] } } }).then((stream) => {
+ frontStream = stream;
+ return navigator.mediaDevices.getUserMedia({ video: { height: { max: 400 }, facingMode: { exact: ["environment"] } } });
+ }).then((stream) => {
+ backStream = stream;
+ assert_true(frontStream.getVideoTracks()[0].getSettings().height >= 400, "frontStream should be bigger");
+ assert_true(backStream.getVideoTracks()[0].getSettings().height < 400, "backStream should be smaller");
+ }).then(() => {
+ return new Promise((resolve, reject) => {
+ if (window.internals)
+ internals.useMockRTCPeerConnectionFactory("TwoRealPeerConnections");
+
+ createConnections((firstConnection) => {
+ sender = firstConnection.addTrack(frontStream.getVideoTracks()[0], frontStream);
+ }, (secondConnection) => {
+ secondConnection._ontrack_ = (trackEvent) => {
+ resolve(trackEvent.streams[0]);
+ };
+ });
+ setTimeout(() => reject("Test timed out"), 5000);
+ });
+ }).then((remoteStream) => {
+ video.srcObject = remoteStream;
+ return video.play();
+ }).then(() => {
+ testFrontCameraImage();
+ }).then(() => {
+ return sender.replaceTrack(backStream.getVideoTracks()[0]);
+ }).then(() => {
+ return waitFor(500);
+ }).then(() => {
+ testBackCameraImage();
+ });
+}, "Switching from front to back camera, with lower resolution");
+
+promise_test((test) => {
+ if (window.testRunner)
+ testRunner.setUserMediaPermission(true);
+
+ var sender;
+ var frontStream;
+ var backStream;
+
+ return navigator.mediaDevices.getUserMedia({ video: { height: { max: 400 }, facingMode: { exact: ["user"] } } }).then((stream) => {
+ frontStream = stream;
+ return navigator.mediaDevices.getUserMedia({ video: { height: { min: 400 }, facingMode: { exact: ["environment"] } } });
+ }).then((stream) => {
+ backStream = stream;
+ assert_true(frontStream.getVideoTracks()[0].getSettings().height < 400, "front stream should be smaller");
+ assert_true(backStream.getVideoTracks()[0].getSettings().height >= 400, "back stream should be bigger");
+ }).then(() => {
+ return new Promise((resolve, reject) => {
+ if (window.internals)
+ internals.useMockRTCPeerConnectionFactory("TwoRealPeerConnections");
+
+ createConnections((firstConnection) => {
+ sender = firstConnection.addTrack(frontStream.getVideoTracks()[0], frontStream);
+ }, (secondConnection) => {
+ secondConnection._ontrack_ = (trackEvent) => {
+ resolve(trackEvent.streams[0]);
+ };
+ });
+ setTimeout(() => reject("Test timed out"), 5000);
+ });
+ }).then((remoteStream) => {
+ video.srcObject = remoteStream;
+ return video.play();
+ }).then(() => {
+ testFrontCameraImage();
+ }).then(() => {
+ return promise_rejects(test, "InvalidModificationError", sender.replaceTrack(backStream.getVideoTracks()[0]));
+ }).then(() => {
+ return waitFor(500);
+ }).then(() => {
+ testBackCameraImage();
+ });
+}, "Switching from front to back camera, with higher resolution");
+ </script>
+ </body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (214356 => 214357)
--- trunk/Source/WebCore/ChangeLog 2017-03-24 17:46:36 UTC (rev 214356)
+++ trunk/Source/WebCore/ChangeLog 2017-03-24 18:01:18 UTC (rev 214357)
@@ -1,3 +1,37 @@
+2017-03-24 Youenn Fablet <[email protected]>
+
+ Add libwebrtc backend support for RTCRtpSender::replaceTrack
+ https://bugs.webkit.org/show_bug.cgi?id=169841
+
+ Reviewed by Alex Christensen.
+
+ Tests: webrtc/audio-replace-track.html
+ webrtc/video-replace-track.html
+
+ Adding support for replaceTrack for audio and video sources.
+ Replacing tracks will always succeed for audio sources.
+ For video tracks, it will only succeed if the video resolution is not greater.
+ LibWebRTCPeerConnectionBackend will delegate the track replacing by replacing the source of the outgoing sources with the source wrapped in the replacing track.
+
+ Video test is not fully passing as size constraints for mock video sources are not providing the right video stream resolution.
+
+ * Modules/mediastream/RTCRtpSender.cpp:
+ (WebCore::RTCRtpSender::replaceTrack):
+ * Modules/mediastream/RTCRtpSender.h:
+ * Modules/mediastream/RTCRtpSender.idl:
+ * Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.cpp:
+ (WebCore::LibWebRTCPeerConnectionBackend::replaceTrack):
+ * Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h:
+ * platform/mediastream/mac/RealtimeOutgoingAudioSource.cpp:
+ (WebCore::RealtimeOutgoingAudioSource::setSource):
+ * platform/mediastream/mac/RealtimeOutgoingAudioSource.h:
+ * platform/mediastream/mac/RealtimeOutgoingVideoSource.cpp:
+ (WebCore::RealtimeOutgoingVideoSource::setSource):
+ * platform/mediastream/mac/RealtimeOutgoingVideoSource.h:
+ * platform/mock/MockRealtimeVideoSource.cpp:
+ (WebCore::MockRealtimeVideoSource::drawText):
+ (WebCore::MockRealtimeVideoSource::generateFrame):
+
2017-03-24 Jon Lee <[email protected]>
Remove comment from RTCStatsReport.idl to convert ssrc to DOMString.
Modified: trunk/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp (214356 => 214357)
--- trunk/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp 2017-03-24 17:46:36 UTC (rev 214356)
+++ trunk/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp 2017-03-24 18:01:18 UTC (rev 214357)
@@ -496,11 +496,32 @@
dispatchEvent(event);
}
-void RTCPeerConnection::replaceTrack(RTCRtpSender& sender, Ref<MediaStreamTrack>&& withTrack, DOMPromise<void>&& promise)
+void RTCPeerConnection::enqueueReplaceTrackTask(RTCRtpSender& sender, Ref<MediaStreamTrack>&& withTrack, DOMPromise<void>&& promise)
{
- m_backend->replaceTrack(sender, WTFMove(withTrack), WTFMove(promise));
+ scriptExecutionContext()->postTask([protectedSender = makeRef(sender), promise = WTFMove(promise), withTrack = WTFMove(withTrack)](ScriptExecutionContext&) mutable {
+ protectedSender->setTrack(WTFMove(withTrack));
+ promise.resolve();
+ });
}
+void RTCPeerConnection::replaceTrack(RTCRtpSender& sender, RefPtr<MediaStreamTrack>&& withTrack, DOMPromise<void>&& promise)
+{
+ if (!withTrack) {
+ scriptExecutionContext()->postTask([protectedSender = makeRef(sender), promise = WTFMove(promise)](ScriptExecutionContext&) mutable {
+ protectedSender->setTrackToNull();
+ promise.resolve();
+ });
+ return;
+ }
+
+ if (!sender.track()) {
+ enqueueReplaceTrackTask(sender, withTrack.releaseNonNull(), WTFMove(promise));
+ return;
+ }
+
+ m_backend->replaceTrack(sender, withTrack.releaseNonNull(), WTFMove(promise));
+}
+
} // namespace WebCore
#endif // ENABLE(WEB_RTC)
Modified: trunk/Source/WebCore/Modules/mediastream/RTCPeerConnection.h (214356 => 214357)
--- trunk/Source/WebCore/Modules/mediastream/RTCPeerConnection.h 2017-03-24 17:46:36 UTC (rev 214356)
+++ trunk/Source/WebCore/Modules/mediastream/RTCPeerConnection.h 2017-03-24 18:01:18 UTC (rev 214357)
@@ -140,6 +140,8 @@
void disableICECandidateFiltering() { m_backend->disableICECandidateFiltering(); }
void enableICECandidateFiltering() { m_backend->enableICECandidateFiltering(); }
+ void enqueueReplaceTrackTask(RTCRtpSender&, Ref<MediaStreamTrack>&&, DOMPromise<void>&&);
+
private:
RTCPeerConnection(ScriptExecutionContext&);
@@ -159,7 +161,7 @@
bool canSuspendForDocumentSuspension() const final;
// RTCRtpSenderClient
- void replaceTrack(RTCRtpSender&, Ref<MediaStreamTrack>&&, DOMPromise<void>&&) final;
+ void replaceTrack(RTCRtpSender&, RefPtr<MediaStreamTrack>&&, DOMPromise<void>&&) final;
void updateConnectionState();
bool doClose();
Modified: trunk/Source/WebCore/Modules/mediastream/RTCRtpSender.cpp (214356 => 214357)
--- trunk/Source/WebCore/Modules/mediastream/RTCRtpSender.cpp 2017-03-24 17:46:36 UTC (rev 214356)
+++ trunk/Source/WebCore/Modules/mediastream/RTCRtpSender.cpp 2017-03-24 18:01:18 UTC (rev 214357)
@@ -57,27 +57,37 @@
{
}
+void RTCRtpSender::setTrackToNull()
+{
+ ASSERT(m_track);
+ m_trackId = { };
+ m_track = nullptr;
+}
+
void RTCRtpSender::setTrack(Ref<MediaStreamTrack>&& track)
{
ASSERT(!isStopped());
- ASSERT(!m_track);
- m_trackId = track->id();
+ if (!m_track)
+ m_trackId = track->id();
m_track = WTFMove(track);
}
-ExceptionOr<void> RTCRtpSender::replaceTrack(Ref<MediaStreamTrack>&& withTrack, DOMPromise<void>&& promise)
+void RTCRtpSender::replaceTrack(RefPtr<MediaStreamTrack>&& withTrack, DOMPromise<void>&& promise)
{
if (isStopped()) {
promise.reject(INVALID_STATE_ERR);
- return { };
+ return;
}
- if (m_trackKind != withTrack->kind())
- return Exception { TypeError };
+ if (withTrack && m_trackKind != withTrack->kind()) {
+ promise.reject(TypeError);
+ return;
+ }
+ if (!withTrack && m_track)
+ m_track->stopProducingData();
+
m_client->replaceTrack(*this, WTFMove(withTrack), WTFMove(promise));
-
- return { };
}
} // namespace WebCore
Modified: trunk/Source/WebCore/Modules/mediastream/RTCRtpSender.h (214356 => 214357)
--- trunk/Source/WebCore/Modules/mediastream/RTCRtpSender.h 2017-03-24 17:46:36 UTC (rev 214356)
+++ trunk/Source/WebCore/Modules/mediastream/RTCRtpSender.h 2017-03-24 18:01:18 UTC (rev 214357)
@@ -39,7 +39,7 @@
class RTCRtpSenderClient {
public:
- virtual void replaceTrack(RTCRtpSender&, Ref<MediaStreamTrack>&&, DOMPromise<void>&&) = 0;
+ virtual void replaceTrack(RTCRtpSender&, RefPtr<MediaStreamTrack>&&, DOMPromise<void>&&) = 0;
virtual ~RTCRtpSenderClient() { }
};
@@ -58,8 +58,9 @@
bool isStopped() const { return !m_client; }
void stop() { m_client = nullptr; }
void setTrack(Ref<MediaStreamTrack>&&);
+ void setTrackToNull();
- ExceptionOr<void> replaceTrack(Ref<MediaStreamTrack>&&, DOMPromise<void>&&);
+ void replaceTrack(RefPtr<MediaStreamTrack>&&, DOMPromise<void>&&);
private:
RTCRtpSender(String&& trackKind, Vector<String>&& mediaStreamIds, RTCRtpSenderClient&);
Modified: trunk/Source/WebCore/Modules/mediastream/RTCRtpSender.idl (214356 => 214357)
--- trunk/Source/WebCore/Modules/mediastream/RTCRtpSender.idl 2017-03-24 17:46:36 UTC (rev 214356)
+++ trunk/Source/WebCore/Modules/mediastream/RTCRtpSender.idl 2017-03-24 18:01:18 UTC (rev 214357)
@@ -39,5 +39,5 @@
// FIXME 169662: missing getCapabilities
// FIXME 169662: missing setParameters
// FIXME 169662: missing getParameters
- [MayThrowException] Promise<void> replaceTrack(MediaStreamTrack withTrack);
+ Promise<void> replaceTrack(MediaStreamTrack? withTrack);
};
Modified: trunk/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.cpp (214356 => 214357)
--- trunk/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.cpp 2017-03-24 17:46:36 UTC (rev 214356)
+++ trunk/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.cpp 2017-03-24 18:01:18 UTC (rev 214357)
@@ -28,6 +28,7 @@
#if USE(LIBWEBRTC)
#include "Document.h"
+#include "ExceptionCode.h"
#include "IceCandidate.h"
#include "JSRTCStatsReport.h"
#include "LibWebRTCDataChannelHandler.h"
@@ -321,6 +322,48 @@
m_remoteStreams.append(WTFMove(mediaStream));
}
+void LibWebRTCPeerConnectionBackend::replaceTrack(RTCRtpSender& sender, Ref<MediaStreamTrack>&& track, DOMPromise<void>&& promise)
+{
+ ASSERT(sender.track());
+ auto* currentTrack = sender.track();
+
+ ASSERT(currentTrack->source().type() == track->source().type());
+ switch (currentTrack->source().type()) {
+ case RealtimeMediaSource::Type::None:
+ ASSERT_NOT_REACHED();
+ promise.reject(INVALID_MODIFICATION_ERR);
+ break;
+ case RealtimeMediaSource::Type::Audio: {
+ for (auto& audioSource : m_audioSources) {
+ if (&audioSource->source() == ¤tTrack->source()) {
+ if (!audioSource->setSource(track->source())) {
+ promise.reject(INVALID_MODIFICATION_ERR);
+ return;
+ }
+ connection().enqueueReplaceTrackTask(sender, WTFMove(track), WTFMove(promise));
+ return;
+ }
+ }
+ promise.reject(INVALID_MODIFICATION_ERR);
+ break;
+ }
+ case RealtimeMediaSource::Type::Video: {
+ for (auto& videoSource : m_videoSources) {
+ if (&videoSource->source() == ¤tTrack->source()) {
+ if (!videoSource->setSource(track->source())) {
+ promise.reject(INVALID_MODIFICATION_ERR);
+ return;
+ }
+ connection().enqueueReplaceTrackTask(sender, WTFMove(track), WTFMove(promise));
+ return;
+ }
+ }
+ promise.reject(INVALID_MODIFICATION_ERR);
+ break;
+ }
+ }
+}
+
} // namespace WebCore
#endif // USE(LIBWEBRTC)
Modified: trunk/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h (214356 => 214357)
--- trunk/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h 2017-03-24 17:46:36 UTC (rev 214356)
+++ trunk/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h 2017-03-24 18:01:18 UTC (rev 214357)
@@ -69,8 +69,7 @@
RefPtr<RTCSessionDescription> currentRemoteDescription() const final;
RefPtr<RTCSessionDescription> pendingRemoteDescription() const final;
- // FIXME: API to implement for real
- void replaceTrack(RTCRtpSender&, Ref<MediaStreamTrack>&&, DOMPromise<void>&&) final { }
+ void replaceTrack(RTCRtpSender&, Ref<MediaStreamTrack>&&, DOMPromise<void>&&) final;
void emulatePlatformEvent(const String&) final { }
Modified: trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingAudioSource.cpp (214356 => 214357)
--- trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingAudioSource.cpp 2017-03-24 17:46:36 UTC (rev 214356)
+++ trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingAudioSource.cpp 2017-03-24 18:01:18 UTC (rev 214357)
@@ -51,6 +51,14 @@
m_audioSource->addObserver(*this);
}
+bool RealtimeOutgoingAudioSource::setSource(Ref<RealtimeMediaSource>&& newSource)
+{
+ m_audioSource->removeObserver(*this);
+ m_audioSource = WTFMove(newSource);
+ m_audioSource->addObserver(*this);
+ return true;
+}
+
void RealtimeOutgoingAudioSource::stop()
{
m_audioSource->removeObserver(*this);
Modified: trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingAudioSource.h (214356 => 214357)
--- trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingAudioSource.h 2017-03-24 17:46:36 UTC (rev 214356)
+++ trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingAudioSource.h 2017-03-24 18:01:18 UTC (rev 214357)
@@ -51,6 +51,9 @@
void setTrack(rtc::scoped_refptr<webrtc::AudioTrackInterface>&& track) { m_track = WTFMove(track); }
void stop();
+ bool setSource(Ref<RealtimeMediaSource>&&);
+ RealtimeMediaSource& source() const { return m_audioSource.get(); }
+
private:
explicit RealtimeOutgoingAudioSource(Ref<RealtimeMediaSource>&&);
Modified: trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingVideoSource.cpp (214356 => 214357)
--- trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingVideoSource.cpp 2017-03-24 17:46:36 UTC (rev 214356)
+++ trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingVideoSource.cpp 2017-03-24 18:01:18 UTC (rev 214357)
@@ -46,6 +46,22 @@
m_videoSource->addObserver(*this);
}
+bool RealtimeOutgoingVideoSource::setSource(Ref<RealtimeMediaSource>&& newSource)
+{
+ if (!m_initialSettings)
+ m_initialSettings = m_videoSource->settings();
+
+ auto newSettings = newSource->settings();
+
+ if (m_initialSettings->width() < newSettings.width() || m_initialSettings->height() < newSettings.height())
+ return false;
+
+ m_videoSource->removeObserver(*this);
+ m_videoSource = WTFMove(newSource);
+ m_videoSource->addObserver(*this);
+ return true;
+}
+
void RealtimeOutgoingVideoSource::stop()
{
m_videoSource->removeObserver(*this);
Modified: trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingVideoSource.h (214356 => 214357)
--- trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingVideoSource.h 2017-03-24 17:46:36 UTC (rev 214356)
+++ trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingVideoSource.h 2017-03-24 18:01:18 UTC (rev 214357)
@@ -36,6 +36,7 @@
#include <webrtc/base/optional.h>
#include <webrtc/common_video/include/i420_buffer_pool.h>
#include <webrtc/media/base/videosinkinterface.h>
+#include <wtf/Optional.h>
#include <wtf/ThreadSafeRefCounted.h>
namespace WebCore {
@@ -46,6 +47,8 @@
~RealtimeOutgoingVideoSource() { stop(); }
void stop();
+ bool setSource(Ref<RealtimeMediaSource>&&);
+ RealtimeMediaSource& source() const { return m_videoSource.get(); }
int AddRef() const final { ref(); return refCount(); }
int Release() const final { deref(); return refCount(); }
@@ -82,6 +85,7 @@
Ref<RealtimeMediaSource> m_videoSource;
bool m_enabled { true };
bool m_muted { false };
+ std::optional<RealtimeMediaSourceSettings> m_initialSettings;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp (214356 => 214357)
--- trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp 2017-03-24 17:46:36 UTC (rev 214356)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp 2017-03-24 18:01:18 UTC (rev 214357)
@@ -327,11 +327,11 @@
FloatPoint bipBopLocation(size.width() * .6, size.height() * .6);
unsigned frameMod = m_frameNumber % 60;
if (frameMod <= 15) {
- context.setFillColor(Color::gray);
+ context.setFillColor(Color::cyan);
String bip(ASCIILiteral("Bip"));
context.drawText(m_bipBopFont, TextRun(StringView(bip)), bipBopLocation);
} else if (frameMod > 30 && frameMod <= 45) {
- context.setFillColor(Color::white);
+ context.setFillColor(Color::yellow);
String bop(ASCIILiteral("Bop"));
context.drawText(m_bipBopFont, TextRun(StringView(bop)), bipBopLocation);
}
@@ -348,7 +348,7 @@
IntSize size = this->size();
FloatRect frameRect(FloatPoint(), size);
- context.fillRect(FloatRect(FloatPoint(), size), Color::black);
+ context.fillRect(FloatRect(FloatPoint(), size), facingMode() == RealtimeMediaSourceSettings::User ? Color::black : Color::gray);
if (!m_muted && m_enabled) {
drawText(context);