MediaRecorder.start() Method is Ignoring the "timeslice" Parameter
authoryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 26 Jun 2020 16:49:50 +0000 (16:49 +0000)
committeryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 26 Jun 2020 16:49:50 +0000 (16:49 +0000)
https://bugs.webkit.org/show_bug.cgi?id=202233
<rdar://problem/55720555>

Reviewed by Eric Carlson.

Source/WebCore:

Use a timer to implement timeSlice parameter.
Schedule timer either when start is called or as part of requestData callback.
This should ensure that, if requestData is called by the application, the timer will be rescheduled appropriately.

Test: http/wpt/mediarecorder/MediaRecorder-start-timeSlice.html

* Modules/mediarecorder/MediaRecorder.cpp:
(WebCore::MediaRecorder::MediaRecorder):
(WebCore::MediaRecorder::startRecording):
(WebCore::MediaRecorder::requestData):
* Modules/mediarecorder/MediaRecorder.h:

LayoutTests:

* http/wpt/mediarecorder/MediaRecorder-start-timeSlice-expected.txt: Added.
* http/wpt/mediarecorder/MediaRecorder-start-timeSlice.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/http/wpt/mediarecorder/MediaRecorder-start-timeSlice-expected.txt [new file with mode: 0644]
LayoutTests/http/wpt/mediarecorder/MediaRecorder-start-timeSlice.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/mediarecorder/MediaRecorder.cpp
Source/WebCore/Modules/mediarecorder/MediaRecorder.h

index a43ee74..dbf1c3a 100644 (file)
@@ -1,3 +1,14 @@
+2020-06-26  Youenn Fablet  <youenn@apple.com>
+
+        MediaRecorder.start() Method is Ignoring the "timeslice" Parameter
+        https://bugs.webkit.org/show_bug.cgi?id=202233
+        <rdar://problem/55720555>
+
+        Reviewed by Eric Carlson.
+
+        * http/wpt/mediarecorder/MediaRecorder-start-timeSlice-expected.txt: Added.
+        * http/wpt/mediarecorder/MediaRecorder-start-timeSlice.html: Added.
+
 2020-06-26  Jack Lee  <shihchieh_lee@apple.com>
 
         ASSERTION FAILED: (it != m_map.end()) in TreeScopeOrderedMap::remove
diff --git a/LayoutTests/http/wpt/mediarecorder/MediaRecorder-start-timeSlice-expected.txt b/LayoutTests/http/wpt/mediarecorder/MediaRecorder-start-timeSlice-expected.txt
new file mode 100644 (file)
index 0000000..8c06b54
--- /dev/null
@@ -0,0 +1,3 @@
+
+PASS Make sure that MediaRecorder timeSlice triggers regular ondataavailable events 
+
diff --git a/LayoutTests/http/wpt/mediarecorder/MediaRecorder-start-timeSlice.html b/LayoutTests/http/wpt/mediarecorder/MediaRecorder-start-timeSlice.html
new file mode 100644 (file)
index 0000000..8111a45
--- /dev/null
@@ -0,0 +1,28 @@
+<!doctype html>
+<html>
+<head>
+    <title>MediaRecorder start timeSlice option</title>
+    <link rel="help" href="https://w3c.github.io/mediacapture-record/MediaRecorder.html#mediarecorder">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="200" height="200">
+</canvas>
+<script>
+    promise_test(async t => {
+        const video = await navigator.mediaDevices.getUserMedia({ audio : true, video : true });
+        const recorder = new MediaRecorder(video);
+
+        assert_equals(recorder.stream, video);
+
+        let promise = new Promise(resolve => recorder.ondataavailable = resolve);
+        recorder.start(100);
+        await promise;
+
+        promise = new Promise(resolve => recorder.ondataavailable = resolve);
+        await promise;
+    }, 'Make sure that MediaRecorder timeSlice triggers regular ondataavailable events');
+</script>
+</body>
+</html>
index 735732c..0e20d40 100644 (file)
@@ -1,3 +1,23 @@
+2020-06-26  Youenn Fablet  <youenn@apple.com>
+
+        MediaRecorder.start() Method is Ignoring the "timeslice" Parameter
+        https://bugs.webkit.org/show_bug.cgi?id=202233
+        <rdar://problem/55720555>
+
+        Reviewed by Eric Carlson.
+
+        Use a timer to implement timeSlice parameter.
+        Schedule timer either when start is called or as part of requestData callback.
+        This should ensure that, if requestData is called by the application, the timer will be rescheduled appropriately.
+
+        Test: http/wpt/mediarecorder/MediaRecorder-start-timeSlice.html
+
+        * Modules/mediarecorder/MediaRecorder.cpp:
+        (WebCore::MediaRecorder::MediaRecorder):
+        (WebCore::MediaRecorder::startRecording):
+        (WebCore::MediaRecorder::requestData):
+        * Modules/mediarecorder/MediaRecorder.h:
+
 2020-06-26  Jack Lee  <shihchieh_lee@apple.com>
 
         ASSERTION FAILED: (it != m_map.end()) in TreeScopeOrderedMap::remove
index 19b96ce..b56c5de 100644 (file)
@@ -83,6 +83,7 @@ MediaRecorder::MediaRecorder(Document& document, Ref<MediaStream>&& stream, Opti
     : ActiveDOMObject(document)
     , m_options(WTFMove(option))
     , m_stream(WTFMove(stream))
+    , m_timeSliceTimer([this] { requestData(); })
 {
     m_tracks = WTF::map(m_stream->getTracks(), [] (auto&& track) -> Ref<MediaStreamTrackPrivate> {
         return track->privateTrack();
@@ -125,9 +126,8 @@ const char* MediaRecorder::activeDOMObjectName() const
     return "MediaRecorder";
 }
 
-ExceptionOr<void> MediaRecorder::startRecording(Optional<int> timeslice)
+ExceptionOr<void> MediaRecorder::startRecording(Optional<int> timeSlice)
 {
-    UNUSED_PARAM(timeslice);
     if (!m_isActive)
         return Exception { InvalidStateError, "The MediaRecorder is not active"_s };
 
@@ -152,6 +152,9 @@ ExceptionOr<void> MediaRecorder::startRecording(Optional<int> timeslice)
         track->addObserver(*this);
 
     m_state = RecordingState::Recording;
+    m_timeSlice = timeSlice;
+    if (m_timeSlice)
+        m_timeSliceTimer.startOneShot(Seconds::fromMilliseconds(*m_timeSlice));
     return { };
 }
 
@@ -181,12 +184,17 @@ ExceptionOr<void> MediaRecorder::requestData()
     if (state() == RecordingState::Inactive)
         return Exception { InvalidStateError, "The MediaRecorder's state cannot be inactive"_s };
 
+    if (m_timeSliceTimer.isActive())
+        m_timeSliceTimer.stop();
     m_private->fetchData([this, pendingActivity = makePendingActivity(*this)](auto&& buffer, auto& mimeType) {
         queueTaskKeepingObjectAlive(*this, TaskSource::Networking, [this, buffer = WTFMove(buffer), mimeType]() mutable {
             if (!m_isActive)
                 return;
 
             dispatchEvent(BlobEvent::create(eventNames().dataavailableEvent, Event::CanBubble::No, Event::IsCancelable::No, buffer ? Blob::create(buffer.releaseNonNull(), mimeType) : Blob::create()));
+
+            if (m_timeSlice)
+                m_timeSliceTimer.startOneShot(Seconds::fromMilliseconds(*m_timeSlice));
         });
     });
     return { };
index 8f6634c..fc79e86 100644 (file)
@@ -30,6 +30,7 @@
 #include "EventTarget.h"
 #include "MediaStream.h"
 #include "MediaStreamTrackPrivate.h"
+#include "Timer.h"
 #include <wtf/UniqueRef.h>
 
 namespace WebCore {
@@ -116,6 +117,8 @@ private:
     std::unique_ptr<MediaRecorderPrivate> m_private;
     RecordingState m_state { RecordingState::Inactive };
     Vector<Ref<MediaStreamTrackPrivate>> m_tracks;
+    Optional<int> m_timeSlice;
+    Timer m_timeSliceTimer;
     
     bool m_isActive { true };
 };