summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor_test.cc')
-rw-r--r--chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor_test.cc305
1 files changed, 270 insertions, 35 deletions
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor_test.cc
index 69a54b631ac..94d83150b5d 100644
--- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor_test.cc
+++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track_processor_test.cc
@@ -13,14 +13,22 @@
#include "third_party/blink/public/web/web_heap.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_signal.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h"
#include "third_party/blink/renderer/core/streams/readable_stream_default_reader.h"
+#include "third_party/blink/renderer/core/streams/writable_stream.h"
+#include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_track_generator.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track_generator_init.h"
#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
+#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.h"
#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.h"
#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h"
+#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.h"
#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h"
+#include "third_party/blink/renderer/modules/mediastream/stream_test_utils.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h"
#include "third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h"
@@ -33,6 +41,13 @@ namespace blink {
namespace {
+std::unique_ptr<PushableMediaStreamAudioSource> CreatePushableAudioSource() {
+ // Use the IO thread for testing purposes.
+ return std::make_unique<PushableMediaStreamAudioSource>(
+ Thread::MainThread()->GetTaskRunner(),
+ Platform::Current()->GetIOTaskRunner());
+}
+
PushableMediaStreamVideoSource* CreatePushableVideoSource() {
PushableMediaStreamVideoSource* pushable_video_source =
new PushableMediaStreamVideoSource();
@@ -45,32 +60,51 @@ PushableMediaStreamVideoSource* CreatePushableVideoSource() {
return pushable_video_source;
}
-MediaStreamTrack* CreateVideoMediaStreamTrack(ExecutionContext* context,
- MediaStreamVideoSource* source) {
- return MakeGarbageCollected<MediaStreamTrack>(
- context, MediaStreamVideoTrack::CreateVideoTrack(
- source, MediaStreamVideoSource::ConstraintsOnceCallback(),
- /*enabled=*/true));
-}
+MediaStreamTrack* CreateAudioMediaStreamTrack(
+ ExecutionContext* context,
+ std::unique_ptr<MediaStreamAudioSource> source) {
+ auto* source_ptr = source.get();
-MediaStreamTrack* CreateAudioMediaStreamTrack(ExecutionContext* context) {
- std::unique_ptr<MediaStreamAudioSource> audio_source =
- std::make_unique<MediaStreamAudioSource>(
- blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
- /*is_local_source=*/false);
MediaStreamSource* media_stream_source =
MakeGarbageCollected<MediaStreamSource>(
"source_id", MediaStreamSource::kTypeAudio, "source_name",
- /*is_remote=*/false);
- media_stream_source->SetPlatformSource(std::move(audio_source));
- std::unique_ptr<MediaStreamAudioTrack> audio_track =
- std::make_unique<MediaStreamAudioTrack>(/*is_local_track=*/false);
+ /*remote=*/false);
+ media_stream_source->SetPlatformSource(std::move(source));
+
MediaStreamComponent* component =
MakeGarbageCollected<MediaStreamComponent>(media_stream_source);
- component->SetPlatformTrack(std::move(audio_track));
+
+ source_ptr->ConnectToTrack(component);
+
return MakeGarbageCollected<MediaStreamTrack>(context, component);
}
+ScriptValue CreateRequestFrameChunk(ScriptState* script_state) {
+ MediaStreamTrackSignal* signal = MediaStreamTrackSignal::Create();
+ signal->setSignalType("request-frame");
+ return ScriptValue(script_state->GetIsolate(),
+ ToV8(signal, script_state->GetContext()->Global(),
+ script_state->GetIsolate()));
+}
+
+ScriptValue CreateSetMinFrameRateChunk(ScriptState* script_state,
+ double frame_rate) {
+ MediaStreamTrackSignal* signal = MediaStreamTrackSignal::Create();
+ signal->setSignalType("set-min-frame-rate");
+ signal->setFrameRate(frame_rate);
+ return ScriptValue(script_state->GetIsolate(),
+ ToV8(signal, script_state->GetContext()->Global(),
+ script_state->GetIsolate()));
+}
+
+ScriptValue CreateInvalidSignalChunk(ScriptState* script_state) {
+ MediaStreamTrackSignal* signal = MediaStreamTrackSignal::Create();
+ signal->setSignalType("set-min-frame-rate");
+ return ScriptValue(script_state->GetIsolate(),
+ ToV8(signal, script_state->GetContext()->Global(),
+ script_state->GetIsolate()));
+}
+
} // namespace
class MediaStreamTrackProcessorTest : public testing::Test {
@@ -97,12 +131,13 @@ TEST_F(MediaStreamTrackProcessorTest, VideoFramesAreExposed) {
pushable_video_source),
exception_state);
EXPECT_FALSE(exception_state.HadException());
- EXPECT_EQ(track_processor->input_track()->Source()->GetPlatformSource(),
- pushable_video_source);
+ EXPECT_EQ(
+ track_processor->InputTrack()->Component()->Source()->GetPlatformSource(),
+ pushable_video_source);
MockMediaStreamVideoSink mock_video_sink;
mock_video_sink.ConnectToTrack(
- WebMediaStreamTrack(track_processor->input_track()));
+ WebMediaStreamTrack(track_processor->InputTrack()->Component()));
EXPECT_EQ(mock_video_sink.number_of_frames(), 0);
EXPECT_EQ(mock_video_sink.last_frame(), nullptr);
@@ -131,6 +166,127 @@ TEST_F(MediaStreamTrackProcessorTest, VideoFramesAreExposed) {
EXPECT_EQ(mock_video_sink.last_frame(), frame);
}
+TEST_F(MediaStreamTrackProcessorTest, AudioFramesAreExposed) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ ExceptionState& exception_state = v8_scope.GetExceptionState();
+ std::unique_ptr<PushableMediaStreamAudioSource> pushable_audio_source =
+ CreatePushableAudioSource();
+ auto* pushable_source_ptr = pushable_audio_source.get();
+ MediaStreamTrackProcessor* track_processor =
+ MediaStreamTrackProcessor::Create(
+ script_state,
+ CreateAudioMediaStreamTrack(v8_scope.GetExecutionContext(),
+ std::move(pushable_audio_source)),
+ exception_state);
+ EXPECT_FALSE(exception_state.HadException());
+ MediaStreamComponent* component = track_processor->InputTrack()->Component();
+ EXPECT_EQ(component->Source()->GetPlatformSource(), pushable_source_ptr);
+
+ MockMediaStreamAudioSink mock_audio_sink;
+ WebMediaStreamAudioSink::AddToAudioTrack(&mock_audio_sink,
+ WebMediaStreamTrack(component));
+
+ auto* reader =
+ track_processor->readable(script_state)
+ ->GetDefaultReaderForTesting(script_state, exception_state);
+ EXPECT_FALSE(exception_state.HadException());
+
+ // Deliver a frame.
+ base::RunLoop sink_loop;
+ EXPECT_CALL(mock_audio_sink, OnData(_, _))
+ .WillOnce(base::test::RunOnceClosure(sink_loop.QuitClosure()));
+ pushable_source_ptr->PushAudioData(AudioFrameSerializationData::Wrap(
+ media::AudioBus::Create(/*channels=*/2, /*frames=*/100),
+ /*sample_rate=*/8000, base::TimeDelta::FromSeconds(1)));
+
+ ScriptPromiseTester read_tester(script_state,
+ reader->read(script_state, exception_state));
+ EXPECT_FALSE(read_tester.IsFulfilled());
+ read_tester.WaitUntilSettled();
+ EXPECT_FALSE(exception_state.HadException());
+ EXPECT_TRUE(read_tester.IsFulfilled());
+ EXPECT_TRUE(read_tester.Value().IsObject());
+ sink_loop.Run();
+
+ WebMediaStreamAudioSink::RemoveFromAudioTrack(&mock_audio_sink,
+ WebMediaStreamTrack(component));
+}
+
+TEST_F(MediaStreamTrackProcessorTest, VideoControlSignalsAreForwarded) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ ExceptionState& exception_state = v8_scope.GetExceptionState();
+ MockMediaStreamVideoSource* mock_video_source = CreateMockVideoSource();
+ MediaStreamTrackProcessor* track_processor =
+ MediaStreamTrackProcessor::Create(
+ script_state,
+ CreateVideoMediaStreamTrack(v8_scope.GetExecutionContext(),
+ mock_video_source),
+ exception_state);
+ EXPECT_FALSE(exception_state.HadException());
+ EXPECT_EQ(
+ track_processor->InputTrack()->Component()->Source()->GetPlatformSource(),
+ mock_video_source);
+ mock_video_source->StartMockedSource();
+
+ EXPECT_CALL(*mock_video_source, OnRequestRefreshFrame());
+ auto* writer = track_processor->writableControl(script_state)
+ ->getWriter(script_state, exception_state);
+ ScriptPromiseTester request_frame_tester(
+ script_state,
+ writer->write(script_state, CreateRequestFrameChunk(script_state),
+ exception_state));
+ request_frame_tester.WaitUntilSettled();
+ EXPECT_TRUE(request_frame_tester.IsFulfilled());
+ EXPECT_FALSE(exception_state.HadException());
+
+ MediaStreamVideoTrack* platform_track =
+ MediaStreamVideoTrack::From(track_processor->InputTrack()->Component());
+ EXPECT_FALSE(platform_track->min_frame_rate().has_value());
+ const double min_frame_rate = 15.0;
+ ScriptPromiseTester set_min_frame_rate_tester(
+ script_state,
+ writer->write(script_state,
+ CreateSetMinFrameRateChunk(script_state, min_frame_rate),
+ exception_state));
+ set_min_frame_rate_tester.WaitUntilSettled();
+ EXPECT_TRUE(set_min_frame_rate_tester.IsFulfilled());
+ EXPECT_FALSE(exception_state.HadException());
+ EXPECT_TRUE(platform_track->min_frame_rate().has_value());
+ EXPECT_EQ(platform_track->min_frame_rate().value(), min_frame_rate);
+
+ ScriptPromiseTester invalid_signal_tester(
+ script_state,
+ writer->write(script_state, CreateInvalidSignalChunk(script_state),
+ exception_state));
+ invalid_signal_tester.WaitUntilSettled();
+ EXPECT_TRUE(invalid_signal_tester.IsRejected());
+}
+
+TEST_F(MediaStreamTrackProcessorTest, AudioControlSignalsAreRejected) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ ExceptionState& exception_state = v8_scope.GetExceptionState();
+ MediaStreamTrackProcessor* track_processor =
+ MediaStreamTrackProcessor::Create(
+ script_state,
+ CreateAudioMediaStreamTrack(v8_scope.GetExecutionContext(),
+ std::make_unique<MediaStreamAudioSource>(
+ Thread::MainThread()->GetTaskRunner(),
+ /*is_local=*/true)),
+ exception_state);
+
+ auto* writer = track_processor->writableControl(script_state)
+ ->getWriter(script_state, exception_state);
+ ScriptPromiseTester tester(
+ script_state,
+ writer->write(script_state, CreateRequestFrameChunk(script_state),
+ exception_state));
+ tester.WaitUntilSettled();
+ EXPECT_TRUE(tester.IsRejected());
+}
+
TEST_F(MediaStreamTrackProcessorTest, CanceledReadableDisconnects) {
V8TestingScope v8_scope;
ScriptState* script_state = v8_scope.GetScriptState();
@@ -146,12 +302,12 @@ TEST_F(MediaStreamTrackProcessorTest, CanceledReadableDisconnects) {
// Initially the track has no sinks.
MediaStreamVideoTrack* video_track =
- MediaStreamVideoTrack::From(track_processor->input_track());
+ MediaStreamVideoTrack::From(track_processor->InputTrack()->Component());
EXPECT_EQ(video_track->CountSinks(), 0u);
MockMediaStreamVideoSink mock_video_sink;
mock_video_sink.ConnectToTrack(
- WebMediaStreamTrack(track_processor->input_track()));
+ WebMediaStreamTrack(track_processor->InputTrack()->Component()));
EXPECT_EQ(mock_video_sink.number_of_frames(), 0);
EXPECT_EQ(mock_video_sink.last_frame(), nullptr);
EXPECT_EQ(video_track->CountSinks(), 1u);
@@ -196,9 +352,10 @@ TEST_F(MediaStreamTrackProcessorTest, ProcessorConnectsToGenerator) {
exception_state);
// Create generator and connect it to a mock sink.
+ MediaStreamTrackGeneratorInit* init = MediaStreamTrackGeneratorInit::Create();
+ init->setKind("video");
MediaStreamTrackGenerator* track_generator =
- MakeGarbageCollected<MediaStreamTrackGenerator>(
- script_state, MediaStreamSource::kTypeVideo, "track_id");
+ MediaStreamTrackGenerator::Create(script_state, init, exception_state);
MockMediaStreamVideoSink mock_video_sink;
mock_video_sink.ConnectToTrack(
WebMediaStreamTrack(track_generator->Component()));
@@ -228,30 +385,108 @@ TEST_F(MediaStreamTrackProcessorTest, NullInputTrack) {
V8TestingScope v8_scope;
ScriptState* script_state = v8_scope.GetScriptState();
ExceptionState& exception_state = v8_scope.GetExceptionState();
+ MediaStreamTrack* track = nullptr;
MediaStreamTrackProcessor* track_processor =
- MediaStreamTrackProcessor::Create(script_state, nullptr, exception_state);
+ MediaStreamTrackProcessor::Create(script_state, track, exception_state);
EXPECT_EQ(track_processor, nullptr);
EXPECT_TRUE(exception_state.HadException());
- EXPECT_EQ(static_cast<DOMExceptionCode>(v8_scope.GetExceptionState().Code()),
- DOMExceptionCode::kOperationError);
+ EXPECT_EQ(static_cast<ESErrorType>(v8_scope.GetExceptionState().Code()),
+ ESErrorType::kTypeError);
}
-// TODO(crbug.com/1142955): Add support for audio.
-TEST_F(MediaStreamTrackProcessorTest, Audio) {
+TEST_F(MediaStreamTrackProcessorTest, EndedTrack) {
V8TestingScope v8_scope;
ScriptState* script_state = v8_scope.GetScriptState();
ExceptionState& exception_state = v8_scope.GetExceptionState();
- MediaStreamTrack* media_stream_track =
- CreateAudioMediaStreamTrack(v8_scope.GetExecutionContext());
+ PushableMediaStreamVideoSource* pushable_video_source =
+ CreatePushableVideoSource();
+ MediaStreamTrack* track = CreateVideoMediaStreamTrack(
+ v8_scope.GetExecutionContext(), pushable_video_source);
+ track->stopTrack(v8_scope.GetExecutionContext());
MediaStreamTrackProcessor* track_processor =
- MediaStreamTrackProcessor::Create(script_state, media_stream_track,
- exception_state);
+ MediaStreamTrackProcessor::Create(script_state, track, exception_state);
EXPECT_EQ(track_processor, nullptr);
EXPECT_TRUE(exception_state.HadException());
- EXPECT_EQ(static_cast<DOMExceptionCode>(v8_scope.GetExceptionState().Code()),
- DOMExceptionCode::kNotSupportedError);
+ EXPECT_EQ(static_cast<ESErrorType>(v8_scope.GetExceptionState().Code()),
+ ESErrorType::kTypeError);
+}
+
+TEST_F(MediaStreamTrackProcessorTest, VideoCloseOnTrackEnd) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ ExceptionState& exception_state = v8_scope.GetExceptionState();
+ PushableMediaStreamVideoSource* pushable_video_source =
+ CreatePushableVideoSource();
+ MediaStreamTrack* track = CreateVideoMediaStreamTrack(
+ v8_scope.GetExecutionContext(), pushable_video_source);
+
+ MediaStreamTrackProcessor* track_processor =
+ MediaStreamTrackProcessor::Create(script_state, track, exception_state);
+ ReadableStream* readable = track_processor->readable(script_state);
+ EXPECT_FALSE(readable->IsClosed());
+
+ track->stopTrack(v8_scope.GetExecutionContext());
+
+ EXPECT_TRUE(readable->IsClosed());
+}
+
+TEST_F(MediaStreamTrackProcessorTest, VideoNoCloseOnTrackDisable) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ ExceptionState& exception_state = v8_scope.GetExceptionState();
+ PushableMediaStreamVideoSource* pushable_video_source =
+ CreatePushableVideoSource();
+ MediaStreamTrack* track = CreateVideoMediaStreamTrack(
+ v8_scope.GetExecutionContext(), pushable_video_source);
+
+ MediaStreamTrackProcessor* track_processor =
+ MediaStreamTrackProcessor::Create(script_state, track, exception_state);
+ ReadableStream* readable = track_processor->readable(script_state);
+ EXPECT_FALSE(readable->IsClosed());
+
+ track->setEnabled(false);
+
+ EXPECT_FALSE(readable->IsClosed());
+}
+
+TEST_F(MediaStreamTrackProcessorTest, AudioCloseOnTrackEnd) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ ExceptionState& exception_state = v8_scope.GetExceptionState();
+ std::unique_ptr<PushableMediaStreamAudioSource> pushable_audio_source =
+ CreatePushableAudioSource();
+ MediaStreamTrack* track = CreateAudioMediaStreamTrack(
+ v8_scope.GetExecutionContext(), std::move(pushable_audio_source));
+
+ MediaStreamTrackProcessor* track_processor =
+ MediaStreamTrackProcessor::Create(script_state, track, exception_state);
+ ReadableStream* readable = track_processor->readable(script_state);
+ EXPECT_FALSE(readable->IsClosed());
+
+ track->stopTrack(v8_scope.GetExecutionContext());
+
+ EXPECT_TRUE(readable->IsClosed());
+}
+
+TEST_F(MediaStreamTrackProcessorTest, AudioNoCloseOnTrackDisable) {
+ V8TestingScope v8_scope;
+ ScriptState* script_state = v8_scope.GetScriptState();
+ ExceptionState& exception_state = v8_scope.GetExceptionState();
+ std::unique_ptr<PushableMediaStreamAudioSource> pushable_audio_source =
+ CreatePushableAudioSource();
+ MediaStreamTrack* track = CreateAudioMediaStreamTrack(
+ v8_scope.GetExecutionContext(), std::move(pushable_audio_source));
+
+ MediaStreamTrackProcessor* track_processor =
+ MediaStreamTrackProcessor::Create(script_state, track, exception_state);
+ ReadableStream* readable = track_processor->readable(script_state);
+ EXPECT_FALSE(readable->IsClosed());
+
+ track->setEnabled(false);
+
+ EXPECT_FALSE(readable->IsClosed());
}
} // namespace blink