diff --git a/Libraries/LibIPC/AttachmentMachPort.cpp b/Libraries/LibIPC/AttachmentMachPort.cpp index b0388c49f835f..26c754c15dd7c 100644 --- a/Libraries/LibIPC/AttachmentMachPort.cpp +++ b/Libraries/LibIPC/AttachmentMachPort.cpp @@ -8,6 +8,7 @@ #include #include #include +#include // fileport_makeport() and fileport_makefd() are private macOS APIs that convert // between file descriptors and Mach port rights. Since Mach messages can only @@ -51,7 +52,10 @@ int Attachment::to_fd() { VERIFY(MACH_PORT_VALID(m_port.port())); int fd = fileport_makefd(m_port.port()); - VERIFY(fd >= 0); + if (fd < 0) { + dbgln("IPC::Attachment: Failed to obtain a file descriptor from a file port: {}", Error::from_errno(errno)); + return -1; + } mach_port_deallocate(mach_task_self(), m_port.release()); return fd; } diff --git a/Libraries/LibIPC/Connection.cpp b/Libraries/LibIPC/Connection.cpp index 69d8757201d91..7d09dfd4a3850 100644 --- a/Libraries/LibIPC/Connection.cpp +++ b/Libraries/LibIPC/Connection.cpp @@ -109,7 +109,7 @@ ConnectionBase::PeerEOF ConnectionBase::drain_messages_from_peer() }); if (parse_error) { - dbgln("IPC::ConnectionBase ({:p}): Disconnecting misbehaving peer due to malformed message", this); + dbgln("IPC::ConnectionBase ({:p}): Disconnecting peer after failing to parse a message", this); schedule_shutdown = Transport::ShouldShutdown::Yes; } diff --git a/Libraries/LibMedia/PlaybackManager.cpp b/Libraries/LibMedia/PlaybackManager.cpp index f4c40ec04ba5f..3bfe91b442619 100644 --- a/Libraries/LibMedia/PlaybackManager.cpp +++ b/Libraries/LibMedia/PlaybackManager.cpp @@ -491,7 +491,7 @@ void PlaybackManager::set_video_sink_ticking(VideoSinkHandle handle, bool tickin manager->update_pipeline_state(); } -void PlaybackManager::detach_lost_video_sink(VideoSinkHandle handle) +void PlaybackManager::detach_video_sink(VideoSinkHandle handle) { auto* track_data = find_video_data_for_handle(handle); if (!track_data) @@ -541,12 +541,15 @@ RefPtr PlaybackManager::current_presented_frame(VideoSinkHandle hand return track_data.video_sink->current_frame(); } -void PlaybackManager::release_video_edge(VideoSinkHandle handle) +void PlaybackManager::release_video_edge(VideoSinkHandle handle, VideoSink const& released_sink) { auto* manager = video_sink_registrations().get(handle).value_or(nullptr); if (!manager) return; - manager->disable_video_sink_by_handle(handle); + auto* track_data = manager->find_video_data_for_handle(handle); + if (!track_data || track_data->video_sink != &released_sink) + return; + manager->detach_video_sink(handle); } void PlaybackManager::enable_an_audio_track(Track const& track) diff --git a/Libraries/LibMedia/PlaybackManager.h b/Libraries/LibMedia/PlaybackManager.h index 2d4f71ab184fd..32dac94152e66 100644 --- a/Libraries/LibMedia/PlaybackManager.h +++ b/Libraries/LibMedia/PlaybackManager.h @@ -73,7 +73,7 @@ class MEDIA_API PlaybackManager final { VideoSinkHandle reserve_video_sink_handle(Track const&); void disable_video_sink_by_handle(VideoSinkHandle); static void set_video_sink_ticking(VideoSinkHandle, bool); - void detach_lost_video_sink(VideoSinkHandle); + void detach_video_sink(VideoSinkHandle); void set_video_resize_handler(VideoSinkHandle, Function)>); void enable_an_audio_track(Track const&); @@ -114,7 +114,7 @@ class MEDIA_API PlaybackManager final { static ErrorOr create_video_edge(VideoSinkHandle, RemoteVideoSink::Delegates); static void attach_video_edge(VideoSinkHandle, NonnullRefPtr const&); static RefPtr current_presented_frame(VideoSinkHandle); - static void release_video_edge(VideoSinkHandle); + static void release_video_edge(VideoSinkHandle, VideoSink const& released_sink); private: struct VideoTrackData { diff --git a/Libraries/LibMedia/VideoPresentation/VideoPresentationServerConnection.cpp b/Libraries/LibMedia/VideoPresentation/VideoPresentationServerConnection.cpp index 5d057e9f43f23..811b3bd71caf5 100644 --- a/Libraries/LibMedia/VideoPresentation/VideoPresentationServerConnection.cpp +++ b/Libraries/LibMedia/VideoPresentation/VideoPresentationServerConnection.cpp @@ -25,7 +25,7 @@ void VideoPresentationServerConnection::die() { revoke_weak_refs(); for (auto& entry : m_edge_states) - PlaybackManager::release_video_edge(entry.value.handle); + PlaybackManager::release_video_edge(entry.value.handle, *entry.value.pump); m_edge_states.clear(); } @@ -97,8 +97,9 @@ void VideoPresentationServerConnection::release_video_edge(u64 edge_id) if (it == m_edge_states.end()) return; auto handle = it->value.handle; + auto pump = it->value.pump; m_edge_states.remove(it); - PlaybackManager::release_video_edge(handle); + PlaybackManager::release_video_edge(handle, *pump); } void VideoPresentationServerConnection::request_start(u64 edge_id) diff --git a/Libraries/LibWeb/HTML/HTMLMediaElement.cpp b/Libraries/LibWeb/HTML/HTMLMediaElement.cpp index 8439947e788ab..0b15aca6b406f 100644 --- a/Libraries/LibWeb/HTML/HTMLMediaElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLMediaElement.cpp @@ -167,6 +167,8 @@ void HTMLMediaElement::initialize_element() m_remote_fetch_data->fetch_controller->stop_fetch(); m_remote_fetch_data->fetch_controller = nullptr; } + + detach_video_sink_edge(); }); m_document_observer->set_document_became_active([this]() { @@ -176,6 +178,8 @@ void HTMLMediaElement::initialize_element() if (m_remote_fetch_data->stream->next_chunk_start() != m_remote_fetch_data->stream->expected_size()) load_remote_resource(UntilEnd { m_remote_fetch_data->stream->next_chunk_start() }); } + + add_current_video_sink(); }); m_document_observer->set_document_visibility_state_observer([this](VisibilityState) { @@ -1811,14 +1815,14 @@ void HTMLMediaElement::add_current_video_sink() add_current_video_sink(*handle); } -void HTMLMediaElement::detach_video_sink_after_compositor_lost() +void HTMLMediaElement::detach_video_sink_edge() { auto handle = video_sink_handle(); if (!m_playback_manager || !handle.has_value()) return; if (m_active_video_sink) m_active_video_sink->unregister(); - m_playback_manager->detach_lost_video_sink(*handle); + m_playback_manager->detach_video_sink(*handle); } void HTMLMediaElement::release_active_video_sink() diff --git a/Libraries/LibWeb/HTML/HTMLMediaElement.h b/Libraries/LibWeb/HTML/HTMLMediaElement.h index f826809b4f409..950d6676329e9 100644 --- a/Libraries/LibWeb/HTML/HTMLMediaElement.h +++ b/Libraries/LibWeb/HTML/HTMLMediaElement.h @@ -167,7 +167,7 @@ class HTMLMediaElement : public HTMLElement { void set_selected_video_track(Badge, GC::Ptr video_track); void add_current_video_sink(); - void detach_video_sink_after_compositor_lost(); + void detach_video_sink_edge(); GC::Ref add_text_track(Bindings::TextTrackKind kind, Utf16View label, Utf16View language); diff --git a/Libraries/LibWeb/Page/Page.cpp b/Libraries/LibWeb/Page/Page.cpp index cec5c13e5ef69..d297366848843 100644 --- a/Libraries/LibWeb/Page/Page.cpp +++ b/Libraries/LibWeb/Page/Page.cpp @@ -808,7 +808,7 @@ void Page::restore_all_media_element_video_sinks() void Page::detach_all_media_element_video_sinks_after_compositor_lost() { for_each_media_element([&](auto& media_element) { - media_element.detach_video_sink_after_compositor_lost(); + media_element.detach_video_sink_edge(); }); } diff --git a/Services/Compositor/CompositorState.cpp b/Services/Compositor/CompositorState.cpp index d353ffbbf907f..cf10d984a2e38 100644 --- a/Services/Compositor/CompositorState.cpp +++ b/Services/Compositor/CompositorState.cpp @@ -149,9 +149,19 @@ void CompositorState::update_display_list(Web::Compositor::CompositorContextId c context->apply_display_list_resource_transaction(move(resource_transaction)); context->install_display_list_update(move(display_list), move(visual_context_tree), move(scroll_state_snapshot)); resolve_video_sinks(*context); + note_display_list_installed_for_video_sinks(context->web_content_client()); update_video_sink_ticking_states(); } +void CompositorState::note_display_list_installed_for_video_sinks(CompositorStateWebContentClient& client) +{ + auto client_sinks = m_video_sink_states.get(&client); + if (!client_sinks.has_value()) + return; + for (auto& sink_entry : *client_sinks) + sink_entry.value.display_list_installed_since_registration = true; +} + void CompositorState::update_image_frame_resources(Web::Compositor::CompositorContextId context_id, Vector image_frames) { auto* context = context_if_present(context_id); @@ -222,6 +232,15 @@ bool CompositorState::video_sink_updates_are_admitted(VideoSinkState const& sink return has_flag(sink_state.update_flags, Web::Compositor::VideoUpdateFlags::Visible) && painted; } +bool CompositorState::video_sink_ticking_state_is_determined(VideoSinkState const& sink_state, bool client_can_paint) +{ + if (!has_flag(sink_state.update_flags, Web::Compositor::VideoUpdateFlags::Visible)) + return true; + if (!client_can_paint) + return true; + return sink_state.sink != nullptr && sink_state.display_list_installed_since_registration; +} + void CompositorState::on_video_sink_ready(CompositorStateWebContentClient& client, Media::VideoSinkHandle handle, NonnullRefPtr const& sink) { auto* sink_state = video_sink_state(client, handle); @@ -250,6 +269,10 @@ void CompositorState::update_video_sink_ticking_states() auto is_painted = client_painted.has_value() && client_painted->contains(sink_entry.key); auto ticking = video_sink_updates_are_admitted(sink_state, is_painted); any_unpainted_sink_admits_updates |= ticking && !is_painted; + + if (!video_sink_ticking_state_is_determined(sink_state, client_painted.has_value())) + continue; + if (ticking == sink_state.ticking) continue; sink_state.ticking = ticking; diff --git a/Services/Compositor/CompositorState.h b/Services/Compositor/CompositorState.h index 9a3f914c31a61..5965a13c5138b 100644 --- a/Services/Compositor/CompositorState.h +++ b/Services/Compositor/CompositorState.h @@ -192,9 +192,12 @@ class CompositorState final : public RefCounted { // notification is only sent once this diverges from it. bool ticking { true }; bool requires_updates { false }; + bool display_list_installed_since_registration { false }; }; VideoSinkState* video_sink_state(CompositorStateWebContentClient&, Media::VideoSinkHandle); static bool video_sink_updates_are_admitted(VideoSinkState const&, bool painted); + static bool video_sink_ticking_state_is_determined(VideoSinkState const&, bool client_can_paint); + void note_display_list_installed_for_video_sinks(CompositorStateWebContentClient&); void update_video_sink_ticking_states(); HashMap> m_video_sink_states; RefPtr m_unpainted_video_update_timer; diff --git a/Tests/LibWeb/Text/expected/HTML/HTMLVideoElement-sink-reattached-after-inactive-document.txt b/Tests/LibWeb/Text/expected/HTML/HTMLVideoElement-sink-reattached-after-inactive-document.txt new file mode 100644 index 0000000000000..20f8944b07c74 --- /dev/null +++ b/Tests/LibWeb/Text/expected/HTML/HTMLVideoElement-sink-reattached-after-inactive-document.txt @@ -0,0 +1 @@ +presented after reattachment: 640x480 diff --git a/Tests/LibWeb/Text/input/HTML/HTMLVideoElement-sink-reattached-after-inactive-document.html b/Tests/LibWeb/Text/input/HTML/HTMLVideoElement-sink-reattached-after-inactive-document.html new file mode 100644 index 0000000000000..1fdb172593f96 --- /dev/null +++ b/Tests/LibWeb/Text/input/HTML/HTMLVideoElement-sink-reattached-after-inactive-document.html @@ -0,0 +1,27 @@ + + + +