Commit 69b65408 authored by mcasas's avatar mcasas Committed by Commit bot

MediaRecorder: fire onError if the amount of tracks of the MediaStream varies

MediaRecorder is supposed to fire an Error event if the amount
of tracks of the associated MediaStream varies. This CL adds
monitoring of said amount and Error firing.

There's no need to stop the MediaRecorder: adding a Track
would not start automatically recording it, and removing it
guarantees it would not be recorded not recording. Moreover,
the spec does not say if MRecorder should stop if the
#Tracks varies, and also instructs to throw an Exception,
which is not possible since the error is asynchronous.

Also this CL removes superfluous test variables.

BUG=545156

Review URL: https://codereview.chromium.org/1578973002

Cr-Commit-Position: refs/heads/master@{#369333}
parent d8a022e9
......@@ -76,8 +76,7 @@ IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, MediaRecorderResume) {
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest,
MediaRecorderNoResumeWhenRecorderInactive) {
MakeTypicalCall("testIllegalResumeThrowsDOMError();",
kMediaRecorderHtmlFile);
MakeTypicalCall("testIllegalResumeThrowsDOMError();", kMediaRecorderHtmlFile);
}
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest,
......@@ -98,7 +97,7 @@ IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest,
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest,
MediaRecorderPausePreventsDataavailableFromBeingFired) {
MakeTypicalCall("testPausePreventsDataavailableFromBeingFired();",
kMediaRecorderHtmlFile);
kMediaRecorderHtmlFile);
}
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest,
......@@ -113,26 +112,25 @@ IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest,
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest,
MediaRecorderIllegalStopThrowsDOMError) {
MakeTypicalCall("testIllegalStopThrowsDOMError();",
kMediaRecorderHtmlFile);
MakeTypicalCall("testIllegalStopThrowsDOMError();", kMediaRecorderHtmlFile);
}
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest,
MediaRecorderIllegalStartWhileRecordingThrowsDOMError) {
MakeTypicalCall("testIllegalStartInRecordingStateThrowsDOMError();",
kMediaRecorderHtmlFile);
kMediaRecorderHtmlFile);
}
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest,
MediaRecorderIllegalStartWhilePausedThrowsDOMError) {
MakeTypicalCall("testIllegalStartInPausedStateThrowsDOMError();",
kMediaRecorderHtmlFile);
kMediaRecorderHtmlFile);
}
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest,
MediaRecorderIllegalRequestDataThrowsDOMError) {
MakeTypicalCall("testIllegalRequestDataThrowsDOMError();",
kMediaRecorderHtmlFile);
kMediaRecorderHtmlFile);
}
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest,
......@@ -140,4 +138,16 @@ IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest,
MakeTypicalCall("testRecordRemotePeerConnection();", kMediaRecorderHtmlFile);
}
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest,
AddingTrackToMediaStreamFiresErrorEvent) {
MakeTypicalCall("testAddingTrackToMediaStreamFiresErrorEvent();",
kMediaRecorderHtmlFile);
}
IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest,
RemovingTrackFromMediaStreamFiresErrorEvent) {
MakeTypicalCall("testRemovingTrackFromMediaStreamFiresErrorEvent();",
kMediaRecorderHtmlFile);
}
} // namespace content
......@@ -109,21 +109,18 @@ function createMediaRecorder(stream, mimeType) {
// Tests that the MediaRecorder's start() function will cause the |state| to be
// 'recording' and that a 'start' event is fired.
function testStartAndRecorderState() {
var theRecorder;
var startEventReceived = false;
navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS)
.then(function(stream) {
return createMediaRecorder(stream, DEFAULT_RECORDER_MIME_TYPE);
})
.then(function(recorder) {
theRecorder = recorder;
theRecorder.onstart = function(event) {
recorder = recorder;
recorder.onstart = function(event) {
startEventReceived = true;
assertEquals('recording', theRecorder.state);
assertEquals('recording', recorder.state);
};
})
.then(function() {
theRecorder.start();
recorder.start();
})
.then(function() {
return waitFor('Make sure the start event was received',
......@@ -142,7 +139,6 @@ function testStartAndRecorderState() {
// Tests that the MediaRecorder's stop() function will effectively cause the
// |state| to be 'inactive' and that a 'stop' event is fired.
function testStartStopAndRecorderState() {
var theRecorder;
var stopEventReceived = false;
navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS)
.then(function(stream) {
......@@ -151,7 +147,7 @@ function testStartStopAndRecorderState() {
.then(function(recorder) {
recorder.onstop = function(event) {
stopEventReceived = true;
assertEquals('inactive', theRecorder.state);
assertEquals('inactive', recorder.state);
};
recorder.stop();
})
......@@ -295,7 +291,6 @@ function testIllegalResumeThrowsDOMError() {
// Tests that MediaRecorder sends data blobs when resume() is called.
function testResumeAndDataAvailable() {
var theRecorder;
var videoSize = 0;
var emptyBlobs = 0;
navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS)
......@@ -303,11 +298,8 @@ function testResumeAndDataAvailable() {
return createAndStartMediaRecorder(stream, DEFAULT_RECORDER_MIME_TYPE);
})
.then(function(recorder) {
theRecorder = recorder;
theRecorder.pause();
})
.then(function() {
theRecorder.ondataavailable = function(event) {
recorder.pause();
recorder.ondataavailable = function(event) {
if (event.data.size > 0) {
videoSize += event.data.size;
} else {
......@@ -315,9 +307,7 @@ function testResumeAndDataAvailable() {
emptyBlobs += 1;
}
};
})
.then(function() {
theRecorder.resume();
recorder.resume();
})
.then(function() {
return waitFor('Make sure the recording has data after resuming',
......@@ -341,19 +331,17 @@ function testResumeAndDataAvailable() {
// Tests that when paused the recorder will transition |state| to |paused| and
// then trigger a |pause| event.
function testPauseAndRecorderState() {
var theRecorder;
var pauseEventReceived = false;
navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS)
.then(function(stream) {
return createAndStartMediaRecorder(stream, DEFAULT_RECORDER_MIME_TYPE);
})
.then(function(recorder) {
theRecorder = recorder;
theRecorder.onpause = function(event) {
recorder.onpause = function(event) {
pauseEventReceived = true;
assertEquals('paused', theRecorder.state);
};
theRecorder.pause();
assertEquals('paused', recorder.state);
}
recorder.pause();
})
.then(function() {
return waitFor('Making sure the pause event has been received',
......@@ -372,20 +360,14 @@ function testPauseAndRecorderState() {
// Tests that is is possible to stop a paused MediaRecorder and that the |state|
// becomes 'inactive'.
function testPauseStopAndRecorderState() {
var theRecorder;
navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS)
.then(function(stream) {
return createAndStartMediaRecorder(stream, DEFAULT_RECORDER_MIME_TYPE);
})
.then(function(recorder) {
theRecorder = recorder;
theRecorder.pause();
})
.then(function() {
theRecorder.stop();
})
.then(function() {
assertEquals('inactive', theRecorder.state);
recorder.pause();
recorder.stop();
assertEquals('inactive', recorder.state);
})
.catch(function(err) {
return failTest(err.toString());
......@@ -398,17 +380,13 @@ function testPauseStopAndRecorderState() {
// Tests that no dataavailable event is fired after MediaRecorder's pause()
// function is called.
function testPausePreventsDataavailableFromBeingFired() {
var theRecorder;
navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS)
.then(function(stream) {
return createAndStartMediaRecorder(stream, DEFAULT_RECORDER_MIME_TYPE);
})
.then(function(recorder) {
theRecorder = recorder;
theRecorder.pause();
})
.then(function() {
theRecorder.ondataavailable = function(event) {
recorder.pause();
recorder.ondataavailable = function(event) {
failTest('Received unexpected data after pause!');
};
})
......@@ -556,6 +534,69 @@ function testIllegalRequestDataThrowsDOMError() {
});
}
// Tests that MediaRecorder fires an Error Event when the associated MediaStream
// gets a Track added.
function testAddingTrackToMediaStreamFiresErrorEvent() {
var theStream;
var errorEventReceived = false;
navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS)
.then(function(stream) {
theStream = stream;
return createMediaRecorder(stream);
})
.then(function(recorder) {
recorder.onerror = function(event) {
errorEventReceived = true;
};
recorder.start();
// Add a new track, copy of an existing one for simplicity.
theStream.addTrack(theStream.getTracks()[1].clone());
})
.then(function() {
return waitFor('Waiting for the Error Event',
function() {
return errorEventReceived;
});
})
.catch(function(err) {
return failTest(err.toString());
})
.then(function() {
reportTestSuccess();
});
}
// Tests that MediaRecorder fires an Error Event when the associated MediaStream
// gets a Track removed.
function testRemovingTrackFromMediaStreamFiresErrorEvent() {
var theStream;
var errorEventReceived = false;
navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS)
.then(function(stream) {
theStream = stream;
return createMediaRecorder(stream);
})
.then(function(recorder) {
recorder.onerror = function(event) {
errorEventReceived = true;
};
recorder.start();
theStream.removeTrack(theStream.getTracks()[1]);
})
.then(function() {
return waitFor('Waiting for the Error Event',
function() {
return errorEventReceived;
});
})
.catch(function(err) {
return failTest(err.toString());
})
.then(function() {
reportTestSuccess();
});
}
</script>
</body>
</html>
......@@ -55,6 +55,7 @@ MediaRecorder* MediaRecorder::create(ExecutionContext* context, MediaStream* str
MediaRecorder::MediaRecorder(ExecutionContext* context, MediaStream* stream, const MediaRecorderOptions& options, ExceptionState& exceptionState)
: ActiveDOMObject(context)
, m_stream(stream)
, m_streamAmountOfTracks(stream->getTracks().size())
, m_mimeType(options.mimeType())
, m_stopped(true)
, m_ignoreMutedMedia(true)
......@@ -205,6 +206,10 @@ void MediaRecorder::writeData(const char* data, size_t length, bool lastInSlice)
m_stopped = false;
scheduleDispatchEvent(Event::create(EventTypeNames::start));
}
if (m_stream && m_streamAmountOfTracks != m_stream->getTracks().size()) {
m_streamAmountOfTracks = m_stream->getTracks().size();
onError("Amount of tracks in MediaStream has changed.");
}
// TODO(mcasas): Act as |m_ignoredMutedMedia| instructs if |m_stream| track(s) is in muted() state.
......@@ -225,9 +230,6 @@ void MediaRecorder::onError(const WebString& message)
{
// TODO(mcasas): Beef up the Error Event and add the |message|, see https://github.com/w3c/mediacapture-record/issues/31
scheduleDispatchEvent(Event::create(EventTypeNames::error));
if (m_state == State::Recording)
stopRecording();
}
void MediaRecorder::createBlobEvent(Blob* blob)
......
......@@ -88,6 +88,7 @@ private:
void dispatchScheduledEvent();
Member<MediaStream> m_stream;
size_t m_streamAmountOfTracks;
String m_mimeType;
bool m_stopped;
bool m_ignoreMutedMedia;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment