chromium/third_party/blink/renderer/core/exported/web_media_player_impl_unittest.cc

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/platform/media/web_media_player_impl.h"

#include <stdint.h>

#include <memory>
#include <string>
#include <utility>

#include "base/command_line.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "base/trace_event/memory_dump_manager.h"
#include "build/build_config.h"
#include "cc/layers/layer.h"
#include "components/viz/test/test_context_provider.h"
#include "media/base/decoder_buffer.h"
#include "media/base/key_systems_impl.h"
#include "media/base/media_content_type.h"
#include "media/base/media_log.h"
#include "media/base/media_observer.h"
#include "media/base/media_switches.h"
#include "media/base/memory_dump_provider_proxy.h"
#include "media/base/mock_audio_renderer_sink.h"
#include "media/base/mock_filters.h"
#include "media/base/mock_media_log.h"
#include "media/base/test_data_util.h"
#include "media/base/test_helpers.h"
#include "media/cdm/clear_key_cdm_common.h"
#include "media/filters/pipeline_controller.h"
#include "media/mojo/services/media_metrics_provider.h"
#include "media/mojo/services/video_decode_stats_recorder.h"
#include "media/mojo/services/watch_time_recorder.h"
#include "media/renderers/default_decoder_factory.h"
#include "media/renderers/renderer_impl_factory.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/platform/media/web_media_player_builder.h"
#include "third_party/blink/public/platform/media/web_media_player_delegate.h"
#include "third_party/blink/public/platform/web_fullscreen_video_status.h"
#include "third_party/blink/public/platform/web_media_player.h"
#include "third_party/blink/public/platform/web_media_player_client.h"
#include "third_party/blink/public/platform/web_media_player_encrypted_media_client.h"
#include "third_party/blink/public/platform/web_media_player_source.h"
#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/public/platform/web_surface_layer_bridge.h"
#include "third_party/blink/public/platform/web_url_response.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_local_frame_client.h"
#include "third_party/blink/public/web/web_testing_support.h"
#include "third_party/blink/public/web/web_view.h"
#include "third_party/blink/public/web/web_widget.h"
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
#include "third_party/blink/renderer/platform/media/buffered_data_source_host_impl.h"
#include "third_party/blink/renderer/platform/media/power_status_helper.h"
#include "third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.h"
#include "third_party/blink/renderer/platform/media/testing/mock_resource_fetch_context.h"
#include "third_party/blink/renderer/platform/media/testing/mock_web_associated_url_loader.h"
#include "third_party/blink/renderer/platform/media/video_decode_stats_reporter.h"
#include "third_party/blink/renderer/platform/media/web_audio_source_provider_client.h"
#include "third_party/blink/renderer/platform/media/web_content_decryption_module_impl.h"
#include "third_party/blink/renderer/platform/testing/task_environment.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "ui/gfx/geometry/size.h"

namespace blink {

namespace {

RunClosure;
RunOnceCallback;
TestAudioConfig;
TestVideoConfig;
_;
AnyNumber;
DoAll;
Eq;
Gt;
InSequence;
Invoke;
NiceMock;
NotNull;
Return;
ReturnRef;
StrictMock;
WithArg;
WithoutArgs;

constexpr char kAudioOnlyTestFile[] =;
constexpr char kVideoOnlyTestFile[] =;
constexpr char kVideoAudioTestFile[] =;
constexpr char kEncryptedVideoOnlyTestFile[] =;

constexpr base::TimeDelta kAudioOnlyTestFileDuration =;

enum class BackgroundBehaviorType {};

MATCHER(WmpiDestroyed, "") {}

MATCHER_P2(PlaybackRateChanged, old_rate_string, new_rate_string, "") {}

class MockMediaObserver : public media::MediaObserver {};

class MockWebMediaPlayerClient : public WebMediaPlayerClient {};

class MockWebMediaPlayerEncryptedMediaClient
    : public WebMediaPlayerEncryptedMediaClient {};

class MockWebMediaPlayerDelegate : public WebMediaPlayerDelegate {};

class MockSurfaceLayerBridge : public WebSurfaceLayerBridge {};

class MockVideoFrameCompositor : public VideoFrameCompositor {};

}  // namespace

class WebMediaPlayerImplTest
    : public testing::Test,
      private WebTestingSupport::WebScopedMockScrollbars {};

TEST_F(WebMediaPlayerImplTest, ConstructAndDestroy) {}

// Verify LoadAndWaitForCurrentData() functions without issue.
TEST_F(WebMediaPlayerImplTest, LoadAndDestroy) {}

// Verify LoadAndWaitForCurrentData() functions without issue.
TEST_F(WebMediaPlayerImplTest, LoadAndDestroyDataUrl) {}

// Verify that preload=metadata suspend works properly.
TEST_F(WebMediaPlayerImplTest, LoadPreloadMetadataSuspend) {}

// Verify that Play() before kReadyStateHaveEnough doesn't increase buffer size.
TEST_F(WebMediaPlayerImplTest, NoBufferSizeIncreaseUntilHaveEnough) {}

// Verify that preload=metadata suspend works properly for streaming sources.
TEST_F(WebMediaPlayerImplTest, LoadPreloadMetadataSuspendNoStreaming) {}

// Verify that lazy load for preload=metadata works properly.
TEST_F(WebMediaPlayerImplTest, LazyLoadPreloadMetadataSuspend) {}

// Verify that lazy load is skipped when rVFC has been requested.
TEST_F(WebMediaPlayerImplTest, LazyLoadSkippedForRVFC) {}

// Verify that preload=metadata suspend video w/ poster uses zero video memory.
TEST_F(WebMediaPlayerImplTest, LoadPreloadMetadataSuspendNoVideoMemoryUsage) {}

// Verify that preload=metadata suspend is aborted if we know the element will
// play as soon as we reach kReadyStateHaveFutureData.
TEST_F(WebMediaPlayerImplTest, LoadPreloadMetadataSuspendCouldPlay) {}

TEST_F(WebMediaPlayerImplTest, IdleSuspendBeforeLoadingBegins) {}

TEST_F(WebMediaPlayerImplTest,
       IdleSuspendIsDisabledIfLoadingProgressedRecently) {}

TEST_F(WebMediaPlayerImplTest, IdleSuspendIsEnabledIfLoadingHasStalled) {}

TEST_F(WebMediaPlayerImplTest, DidLoadingProgressTriggersResume) {}

TEST_F(WebMediaPlayerImplTest, RequestVideoFrameCallback) {}

TEST_F(WebMediaPlayerImplTest, UpdateFrameIfStale) {}

TEST_F(WebMediaPlayerImplTest, GetVideoFramePresentationMetadata) {}

TEST_F(WebMediaPlayerImplTest, OnNewFramePresentedCallback) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_Constructed) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_HaveMetadata) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_HaveFutureData) {}

// Ensure memory reporting is not running after an error.
TEST_F(WebMediaPlayerImplTest, ComputePlayState_PlayingError) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_Playing) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_PlayingVideoOnly) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_Underflow) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_FrameHidden) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_FrameHiddenAudioOnly) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_FrameHiddenVideoOnly) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_FrameHiddenSuspendNoResume) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_FrameHiddenSuspendWithResume) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_FrameClosed) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_PausedSeek) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_Ended) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_DoesNotStaySuspended) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_StaysSuspended) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_ResumeForNeedFirstFrame) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_Flinging) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_Fullscreen) {}

TEST_F(WebMediaPlayerImplTest, ComputePlayState_Streaming) {}

TEST_F(WebMediaPlayerImplTest, IsStreamingIfDemuxerDoesntSupportSeeking) {}

TEST_F(WebMediaPlayerImplTest, IsNotStreamingIfDemuxerSupportsSeeking) {}

TEST_F(WebMediaPlayerImplTest, ResumeEnded) {}

TEST_F(WebMediaPlayerImplTest, AutoplayMuted) {}

TEST_F(WebMediaPlayerImplTest, MediaPositionState_Playing) {}

TEST_F(WebMediaPlayerImplTest, MediaPositionState_Paused) {}

TEST_F(WebMediaPlayerImplTest, MediaPositionState_PositionChange) {}

TEST_F(WebMediaPlayerImplTest, MediaPositionState_EndOfMedia) {}

TEST_F(WebMediaPlayerImplTest, MediaPositionState_Underflow) {}

// It's possible for current time to be infinite if the page seeks to
// |media::kInfiniteDuration| (2**64 - 1) when duration is infinite.
TEST_F(WebMediaPlayerImplTest, MediaPositionState_InfiniteCurrentTime) {}

TEST_F(WebMediaPlayerImplTest, NoStreams) {}

TEST_F(WebMediaPlayerImplTest, Encrypted) {}

TEST_F(WebMediaPlayerImplTest, Waiting_NoDecryptionKey) {}

TEST_F(WebMediaPlayerImplTest, Waiting_SecureSurfaceLost) {}

ACTION(ReportHaveEnough) {}

ACTION(ReportHardwareContextReset) {}

#if BUILDFLAG(IS_WIN)

// Tests that for encrypted media, when a CDM is attached that requires
// MediaFoundationRenderer, the pipeline will fallback to create a new Renderer
// for RendererType::kMediaFoundation.
TEST_F(WebMediaPlayerImplTest, FallbackToMediaFoundationRenderer) {
  InitializeWebMediaPlayerImpl();
  // To avoid PreloadMetadataLazyLoad.
  wmpi_->SetPreload(WebMediaPlayer::kPreloadAuto);

  // Use MockRendererFactory for kMediaFoundation where the created Renderer
  // will take the CDM, complete Renderer initialization and report HAVE_ENOUGH
  // so that WMPI can reach kReadyStateHaveCurrentData.
  auto mock_renderer_factory = std::make_unique<media::MockRendererFactory>();
  EXPECT_CALL(*mock_renderer_factory, CreateRenderer(_, _, _, _, _, _))
      .WillOnce(testing::WithoutArgs(Invoke([]() {
        auto mock_renderer = std::make_unique<NiceMock<media::MockRenderer>>();
        EXPECT_CALL(*mock_renderer, OnSetCdm(_, _))
            .WillOnce(RunOnceCallback<1>(true));
        EXPECT_CALL(*mock_renderer, OnInitialize(_, _, _))
            .WillOnce(DoAll(RunOnceCallback<2>(media::PIPELINE_OK),
                            WithArg<1>(ReportHaveEnough())));
        return mock_renderer;
      })));

  renderer_factory_selector_->AddFactory(media::RendererType::kMediaFoundation,
                                         std::move(mock_renderer_factory));

  // Create and set CDM. The CDM doesn't support a Decryptor and requires Media
  // Foundation Renderer.
  EXPECT_CALL(mock_cdm_context_, GetDecryptor())
      .WillRepeatedly(Return(nullptr));
  EXPECT_CALL(mock_cdm_context_, RequiresMediaFoundationRenderer())
      .WillRepeatedly(Return(true));

  CreateCdm();
  SetCdm();

  // Load encrypted media and expect encrypted event.
  EXPECT_CALL(encrypted_client_,
              Encrypted(media::EmeInitDataType::WEBM, NotNull(), Gt(0u)));

  base::RunLoop run_loop;
  // MediaFoundationRenderer doesn't use AudioService.
  EXPECT_CALL(client_, DidUseAudioServiceChange(/*uses_audio_service=*/false))
      .WillOnce(RunClosure(run_loop.QuitClosure()));
  Load(kEncryptedVideoOnlyTestFile);
  run_loop.Run();
}

// Tests that when PIPELINE_ERROR_HARDWARE_CONTEXT_RESET happens, the pipeline
// will suspend/resume the pipeline, which will create a new Renderer.
TEST_F(WebMediaPlayerImplTest, PipelineErrorHardwareContextReset) {
  InitializeWebMediaPlayerImpl();
  // To avoid PreloadMetadataLazyLoad.
  wmpi_->SetPreload(WebMediaPlayer::kPreloadAuto);

  base::RunLoop run_loop;

  // Use MockRendererFactory which will create two Renderers. The first will
  // report a PIPELINE_ERROR_HARDWARE_CONTEXT_RESET after initialization. The
  // second one will initialize normally and quit the loop to complete the test.
  auto mock_renderer_factory = std::make_unique<media::MockRendererFactory>();
  EXPECT_CALL(*mock_renderer_factory, CreateRenderer(_, _, _, _, _, _))
      .WillOnce(testing::WithoutArgs(Invoke([]() {
        auto mock_renderer = std::make_unique<NiceMock<media::MockRenderer>>();
        EXPECT_CALL(*mock_renderer, OnInitialize(_, _, _))
            .WillOnce(DoAll(RunOnceCallback<2>(media::PIPELINE_OK),
                            WithArg<1>(ReportHardwareContextReset())));
        return mock_renderer;
      })))
      .WillOnce(testing::WithoutArgs(Invoke([&]() {
        auto mock_renderer = std::make_unique<NiceMock<media::MockRenderer>>();
        EXPECT_CALL(*mock_renderer, OnInitialize(_, _, _))
            .WillOnce(DoAll(RunOnceCallback<2>(media::PIPELINE_OK),
                            RunClosure(run_loop.QuitClosure())));
        return mock_renderer;
      })));

  renderer_factory_selector_->AddFactory(media::RendererType::kTest,
                                         std::move(mock_renderer_factory));
  renderer_factory_selector_->SetBaseRendererType(media::RendererType::kTest);

  Load(kVideoOnlyTestFile);
  run_loop.Run();
}

// Same as above, but tests that when PIPELINE_ERROR_HARDWARE_CONTEXT_RESET
// happens twice, the pipeline will always suspend/resume the pipeline, which
// will create new Renderers. See https://crbug.com/1454226 for the context.
TEST_F(WebMediaPlayerImplTest, PipelineErrorHardwareContextReset_Twice) {
  InitializeWebMediaPlayerImpl();
  // To avoid PreloadMetadataLazyLoad.
  wmpi_->SetPreload(WebMediaPlayer::kPreloadAuto);

  base::RunLoop run_loop;

  // Use MockRendererFactory which will create three Renderers. The first two
  // will report a PIPELINE_ERROR_HARDWARE_CONTEXT_RESET after initialization.
  // The third one will initialize normally and quit the loop to complete the
  // test.
  auto mock_renderer_factory = std::make_unique<media::MockRendererFactory>();
  EXPECT_CALL(*mock_renderer_factory, CreateRenderer(_, _, _, _, _, _))
      .WillOnce(testing::WithoutArgs(Invoke([]() {
        auto mock_renderer = std::make_unique<NiceMock<media::MockRenderer>>();
        EXPECT_CALL(*mock_renderer, OnInitialize(_, _, _))
            .WillOnce(DoAll(RunOnceCallback<2>(media::PIPELINE_OK),
                            WithArg<1>(ReportHardwareContextReset())));
        return mock_renderer;
      })))
      .WillOnce(testing::WithoutArgs(Invoke([]() {
        auto mock_renderer = std::make_unique<NiceMock<media::MockRenderer>>();
        EXPECT_CALL(*mock_renderer, OnInitialize(_, _, _))
            .WillOnce(DoAll(RunOnceCallback<2>(media::PIPELINE_OK),
                            WithArg<1>(ReportHardwareContextReset())));
        return mock_renderer;
      })))
      .WillOnce(testing::WithoutArgs(Invoke([&]() {
        auto mock_renderer = std::make_unique<NiceMock<media::MockRenderer>>();
        EXPECT_CALL(*mock_renderer, OnInitialize(_, _, _))
            .WillOnce(DoAll(RunOnceCallback<2>(media::PIPELINE_OK),
                            RunClosure(run_loop.QuitClosure())));
        return mock_renderer;
      })));

  renderer_factory_selector_->AddFactory(media::RendererType::kTest,
                                         std::move(mock_renderer_factory));
  renderer_factory_selector_->SetBaseRendererType(media::RendererType::kTest);

  Load(kVideoOnlyTestFile);
  run_loop.Run();
}

#endif  // BUILDFLAG(IS_WIN)

TEST_F(WebMediaPlayerImplTest, VideoConfigChange) {}

TEST_F(WebMediaPlayerImplTest, NaturalSizeChange) {}

TEST_F(WebMediaPlayerImplTest, NaturalSizeChange_Rotated) {}

TEST_F(WebMediaPlayerImplTest, VideoLockedWhenPausedWhenHidden) {}

TEST_F(WebMediaPlayerImplTest, NotifiesObserverWhenFrozen) {}

TEST_F(WebMediaPlayerImplTest, BackgroundIdlePauseTimerDependsOnAudio) {}

// Verifies that an infinite duration doesn't muck up GetCurrentTimeInternal.
TEST_F(WebMediaPlayerImplTest, InfiniteDuration) {}

TEST_F(WebMediaPlayerImplTest, SetContentsLayerGetsWebLayerFromBridge) {}

TEST_F(WebMediaPlayerImplTest, PlaybackRateChangeMediaLogs) {}

// Tests that updating the surface id calls OnPictureInPictureStateChange.
TEST_F(WebMediaPlayerImplTest, PictureInPictureStateChange) {}

// Test that OnPictureInPictureStateChange is not called for audio elements.
// This test explicitly sets display type to picture in picture, for an audio
// element, for testing purposes only (See crbug.com/1403547 for reference).
TEST_F(WebMediaPlayerImplTest, OnPictureInPictureStateChangeNotCalled) {}

TEST_F(WebMediaPlayerImplTest, DisplayTypeChange) {}

TEST_F(WebMediaPlayerImplTest, RegisterFrameSinkHierarchy) {}

TEST_F(WebMediaPlayerImplTest, OnProgressClearsStale) {}

TEST_F(WebMediaPlayerImplTest, MemDumpProvidersRegistration) {}

TEST_F(WebMediaPlayerImplTest, MemDumpReporting) {}

// Verify that a demuxer override is used when specified.
// TODO(https://crbug.com/1084476): This test is flaky.
TEST_F(WebMediaPlayerImplTest, DISABLED_DemuxerOverride) {}

class WebMediaPlayerImplBackgroundBehaviorTest
    : public WebMediaPlayerImplTest,
      public WebAudioSourceProviderClient,
      public ::testing::WithParamInterface<
          std::tuple<bool, int, int, bool, bool, bool, bool, bool, bool>> {};

TEST_P(WebMediaPlayerImplBackgroundBehaviorTest, AudioOnly) {}

TEST_P(WebMediaPlayerImplBackgroundBehaviorTest, VideoOnly) {}

TEST_P(WebMediaPlayerImplBackgroundBehaviorTest, AudioVideo) {}

INSTANTIATE_TEST_SUITE_P();

}  // namespace blink