diff options
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.cc | 305 |
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 |