Repository: LadybirdBrowser/ladybird
File: Libraries/LibMedia/PlaybackManager.cpp (C++)

Code before:
        return DecoderError::with_description(DecoderErrorCategory::NotImplemented, "No supported video or audio tracks found"sv);

    auto preferred_video_track = demuxer->get_preferred_track_for_type(TrackType::Video).value_or({});
    if (preferred_video_track.has_value() && !supported_video_tracks.contains_slow(*preferred_video_track))
        preferred_video_track = {};
    auto preferred_audio_track = demuxer->get_preferred_track_for_type(TrackType::Audio).value_or({});
    if (preferred_audio_track.has_value() && !supported_audio_tracks.contains_slow(*preferred_audio_track))
        preferred_audio_track = {};

    auto duration = demuxer->total_duration().value_or(AK::Duration::zero());

    main_thread_event_loop.deferred_invoke([weak_playback_manager, on_complete = move(on_complete), video_tracks = move(supported_video_tracks), video_track_datas = move(supported_video_track_datas), preferred_video_track, audio_tracks = move(supported_audio_tracks), audio_track_datas = move(supported_audio_track_datas), preferred_audio_track, duration] mutable {
        auto playback_manager = weak_playback_manager->take_strong();
        if (!playback_manager)
            return;

        RefPtr<AudioMixingSink> audio_sink = nullptr;
        if (!audio_tracks.is_empty())
            audio_sink = AudioMixingSink::try_create().release_value_but_fixme_should_propagate_errors();

        // Create the time provider.
        auto time_provider = ([&] -> NonnullRefPtr<MediaTimeProvider> {
            if (audio_sink)
                return make_ref_counted<WrapperTimeProvider<AudioMixingSink>>(*audio_sink);
            return make_ref_counted<GenericTimeProvider>();
        })();

        playback_manager->m_time_provider = time_provider;
        playback_manager->m_audio_sink = audio_sink;

        playback_manager->m_video_tracks.extend(move(video_tracks));
        playback_manager->m_video_track_datas.extend(move(video_track_datas));
        playback_manager->m_audio_tracks.extend(move(audio_tracks));
        playback_manager->m_audio_track_datas.extend(move(audio_track_datas));
        playback_manager->m_duration = move(duration);

        playback_manager->set_up_error_handlers();

        on_complete(playback_manager->m_video_tracks, preferred_video_track, playback_manager->m_audio_tracks, preferred_audio_track, playback_manager->m_duration);
    });

    return {};
}

NonnullRefPtr<PlaybackManager> PlaybackManager::create(ReadonlyBytes data, OnCreateComplete on_complete, OnCreateError on_error)
{
    // Create the weak wrapper.
    auto weak_playback_manager = make_ref_counted<WeakPlaybackManager>();

    auto thread = Threading::Thread::construct([weak_playback_manager, data, on_complete = move(on_complete), on_error = move(on_error), &main_thread_event_loop = Core::EventLoop::current()] mutable -> int {
        auto playback_manager = weak_playback_manager->take_strong();

Review comment (suggestion):
We could potentially create a GenericTimeProvider by default when initializing the PlaybackManager, and then swap it out for an AudioMixingSink when we find an audio track, so we can keep the time provider field non-null and avoid some assertions.

I think it should suffice to do
```cpp
if (audio_sink) {
    auto current_time = playback_manager->current_time();
    playback_manager->m_time_provider = make_ref_counted<WrapperTimeProvider<AudioMixingSink>>(*audio_sink);
    playback_manager->m_time_provider->set_time(current_time);
}
```

Code after:
        return DecoderError::with_description(DecoderErrorCategory::NotImplemented, "No supported video or audio tracks found"sv);

    auto preferred_video_track = demuxer->get_preferred_track_for_type(TrackType::Video).value_or({});
    if (preferred_video_track.has_value() && !supported_video_tracks.contains_slow(*preferred_video_track))
        preferred_video_track = {};
    auto preferred_audio_track = demuxer->get_preferred_track_for_type(TrackType::Audio).value_or({});
    if (preferred_audio_track.has_value() && !supported_audio_tracks.contains_slow(*preferred_audio_track))
        preferred_audio_track = {};

    auto duration = demuxer->total_duration().value_or(AK::Duration::zero());

    main_thread_event_loop.deferred_invoke([playback_manager = NonnullRefPtr { *this }, video_tracks = move(supported_video_tracks), video_track_datas = move(supported_video_track_datas), preferred_video_track, audio_tracks = move(supported_audio_tracks), audio_track_datas = move(supported_audio_track_datas), preferred_audio_track, duration] mutable {
        playback_manager->m_video_tracks.extend(move(video_tracks));
        playback_manager->m_video_track_datas.extend(move(video_track_datas));
        playback_manager->m_audio_tracks.extend(move(audio_tracks));
        playback_manager->m_audio_track_datas.extend(move(audio_track_datas));
        playback_manager->m_preferred_video_track = preferred_video_track;
        playback_manager->m_preferred_audio_track = preferred_audio_track;
        playback_manager->m_duration = move(duration);

        playback_manager->set_up_error_handlers();

        if (!playback_manager->m_audio_tracks.is_empty()) {
            playback_manager->m_audio_sink = MUST(AudioMixingSink::try_create());
        }

        if (auto audio_sink = playback_manager->m_audio_sink) {
            VERIFY(playback_manager->current_time().is_zero());
            playback_manager->m_time_provider = make_ref_counted<WrapperTimeProvider<AudioMixingSink>>(*audio_sink);
        }

        if (playback_manager->on_track_added) {
            for (auto const& audio_track : playback_manager->m_audio_tracks)
                playback_manager->on_track_added(TrackType::Audio, audio_track);
            for (auto const& video_track : playback_manager->m_video_tracks)
                playback_manager->on_track_added(TrackType::Video, video_track);
        }

        if (playback_manager->on_metadata_parsed)
            playback_manager->on_metadata_parsed();
    });

    return {};
}

NonnullRefPtr<PlaybackManager> PlaybackManager::create()
{
    auto playback_manager = adopt_ref(*new (nothrow) PlaybackManager());
    playback_manager->m_handler = make<PausedStateHandler>(*playback_manager);
    return playback_manager;
}