blob: cfb9b8b63835978c689376eced266c85ad0b1ddf [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/gpu/android_video_surface_chooser_impl.h"
#include <stdint.h>
#include <memory>
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "media/base/android/mock_android_overlay.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::NiceMock;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::StrictMock;
namespace {
using ::media::AndroidOverlay;
using ::media::MockAndroidOverlay;
class MockClient {
public:
MOCK_METHOD1(UseOverlay, void(AndroidOverlay*));
void UseOverlayImpl(std::unique_ptr<AndroidOverlay> overlay) {
UseOverlay(overlay.get());
// Also take ownership of the overlay, so that it's not destroyed.
overlay_ = std::move(overlay);
}
// Note that this won't clear |overlay_|, which is helpful.
MOCK_METHOD0(UseSurfaceTexture, void(void));
private:
std::unique_ptr<AndroidOverlay> overlay_;
};
} // namespace
namespace media {
// Unit tests for AndroidVideoSurfaceChooserImpl
class AndroidVideoSurfaceChooserImplTest : public testing::Test {
public:
~AndroidVideoSurfaceChooserImplTest() override {}
void SetUp() override {
chooser_ = base::MakeUnique<AndroidVideoSurfaceChooserImpl>();
overlay_ = base::MakeUnique<MockAndroidOverlay>();
// We create a destruction observer. By default, the overlay must not be
// destroyed until the test completes. Of course, the test may ask the
// observer to expect something else.
destruction_observer_ = overlay_->CreateDestructionObserver();
destruction_observer_->DoNotAllowDestruction();
overlay_callbacks_ = overlay_->GetCallbacks();
}
void TearDown() override {
// If we get this far, the assume that whatever |destruction_observer_|
// was looking for should have already happened. We don't want the
// lifetime of the observer to matter with respect to the overlay when
// checking expectations.
// Note that it might already be null.
destruction_observer_ = nullptr;
}
// Start the chooser, providing |factory| as the initial factory.
void StartChooser(AndroidOverlayFactoryCB factory) {
chooser_->Initialize(
base::Bind(&MockClient::UseOverlayImpl, base::Unretained(&client_)),
base::Bind(&MockClient::UseSurfaceTexture, base::Unretained(&client_)),
std::move(factory));
}
// AndroidOverlayFactoryCB is a RepeatingCallback, so we can't just bind
// something that uses unique_ptr. RepeatingCallback needs to copy it.
class Factory {
public:
Factory(std::unique_ptr<MockAndroidOverlay> overlay,
base::RepeatingCallback<void()> create_overlay_cb)
: overlay_(std::move(overlay)),
create_overlay_cb_(std::move(create_overlay_cb)) {}
// Return whatever overlay we're given. This is used to construct factory
// callbacks for the chooser.
std::unique_ptr<AndroidOverlay> ReturnOverlay(AndroidOverlayConfig config) {
// Notify the mock.
create_overlay_cb_.Run();
if (overlay_)
overlay_->SetConfig(std::move(config));
return std::move(overlay_);
}
private:
std::unique_ptr<MockAndroidOverlay> overlay_;
base::RepeatingCallback<void()> create_overlay_cb_;
};
// Create a factory that will return |overlay| when run.
AndroidOverlayFactoryCB FactoryFor(
std::unique_ptr<MockAndroidOverlay> overlay) {
Factory* factory = new Factory(
std::move(overlay),
base::Bind(&AndroidVideoSurfaceChooserImplTest::MockOnOverlayCreated,
base::Unretained(this)));
// Leaky!
return base::Bind(&Factory::ReturnOverlay, base::Unretained(factory));
}
// Called by the factory when it's run.
MOCK_METHOD0(MockOnOverlayCreated, void());
std::unique_ptr<AndroidVideoSurfaceChooserImpl> chooser_;
StrictMock<MockClient> client_;
std::unique_ptr<MockAndroidOverlay> overlay_;
// Callbacks to control the overlay that will be vended by |factory_|
MockAndroidOverlay::Callbacks overlay_callbacks_;
std::unique_ptr<MockAndroidOverlay::DestructionObserver>
destruction_observer_;
};
TEST_F(AndroidVideoSurfaceChooserImplTest,
InitializeWithoutFactoryUsesSurfaceTexture) {
// Calling Initialize() with no factory should result in a callback to use
// surface texture.
EXPECT_CALL(client_, UseSurfaceTexture());
StartChooser(AndroidOverlayFactoryCB());
}
TEST_F(AndroidVideoSurfaceChooserImplTest, ProvideInitialOverlaySuccessfully) {
// Providing a factory at startup should result in a switch to overlay. It
// should not switch to SurfaceTexture initially, since pre-M requires it.
// Note that post-M (especially DS), it might be fine to start with ST. We
// just don't differentiate those cases yet in the impl.
EXPECT_CALL(client_, UseSurfaceTexture()).Times(0);
StartChooser(FactoryFor(std::move(overlay_)));
// Notify the chooser that the overlay is ready. Expect that |client_| will
// be told to use it.
EXPECT_CALL(client_, UseOverlay(NotNull()));
overlay_callbacks_.OverlayReady.Run();
}
TEST_F(AndroidVideoSurfaceChooserImplTest,
InitializingWithFactoryCreatesOverlay) {
// Providing a factory at startup should result in a switch to overlay. It
// should not switch to SurfaceTexture initially, since pre-M requires it.
// Note that post-M (especially DS), it might be fine to start with ST. We
// just don't differentiate those cases yet in the impl.
// Initially, there should be no callback into |client_|, since we haven't
// told |chooser_| that the overlay is ready. It should, however, request the
// overlay from |factory_|.
EXPECT_CALL(*this, MockOnOverlayCreated());
StartChooser(FactoryFor(std::move(overlay_)));
}
TEST_F(AndroidVideoSurfaceChooserImplTest,
NullInitialOverlayUsesSurfaceTexture) {
// If we provide a factory, but it fails to create an overlay, then |client_|
// should be notified to use a surface texture.
EXPECT_CALL(*this, MockOnOverlayCreated());
EXPECT_CALL(client_, UseSurfaceTexture());
StartChooser(FactoryFor(nullptr));
}
TEST_F(AndroidVideoSurfaceChooserImplTest,
FailedInitialOverlayUsesSurfaceTexture) {
// If we provide a factory, but the overlay that it provides returns 'failed',
// then |client_| should use surface texture.
EXPECT_CALL(*this, MockOnOverlayCreated());
StartChooser(FactoryFor(std::move(overlay_)));
testing::Mock::VerifyAndClearExpectations(&client_);
testing::Mock::VerifyAndClearExpectations(this);
// The overlay may be destroyed at any time after we send OverlayFailed. It
// doesn't have to be destroyed. We just care that it hasn't been destroyed
// before now.
destruction_observer_ = nullptr;
EXPECT_CALL(client_, UseSurfaceTexture());
overlay_callbacks_.OverlayFailed.Run();
}
TEST_F(AndroidVideoSurfaceChooserImplTest, NullLaterOverlayUsesSurfaceTexture) {
// If an overlay factory is provided after startup that returns a null overlay
// from CreateOverlay, |chooser_| should, at most, notify |client_| to use
// SurfaceTexture zero or more times.
// Start with SurfaceTexture.
EXPECT_CALL(client_, UseSurfaceTexture());
StartChooser(AndroidOverlayFactoryCB());
testing::Mock::VerifyAndClearExpectations(&client_);
// Provide a factory that will return a null overlay.
EXPECT_CALL(*this, MockOnOverlayCreated());
EXPECT_CALL(client_, UseSurfaceTexture()).Times(AnyNumber());
chooser_->ReplaceOverlayFactory(FactoryFor(nullptr));
}
TEST_F(AndroidVideoSurfaceChooserImplTest, FailedLaterOverlayDoesNothing) {
// If we send an overlay factory that returns an overlay, and that overlay
// fails, then the client should not be notified except for zero or more
// callbacks to switch to surface texture.
// Start with SurfaceTexture.
EXPECT_CALL(client_, UseSurfaceTexture());
StartChooser(AndroidOverlayFactoryCB());
testing::Mock::VerifyAndClearExpectations(&client_);
// Provide a factory.
EXPECT_CALL(*this, MockOnOverlayCreated());
EXPECT_CALL(client_, UseSurfaceTexture()).Times(AnyNumber());
chooser_->ReplaceOverlayFactory(FactoryFor(std::move(overlay_)));
testing::Mock::VerifyAndClearExpectations(&client_);
// Fail the overlay. We don't care if it's destroyed after that, as long as
// it hasn't been destroyed yet.
destruction_observer_ = nullptr;
overlay_callbacks_.OverlayFailed.Run();
}
TEST_F(AndroidVideoSurfaceChooserImplTest,
SuccessfulLaterOverlayNotifiesClient) {
// |client_| is notified if we provide a factory that gets an overlay.
// Start with SurfaceTexture.
EXPECT_CALL(client_, UseSurfaceTexture());
StartChooser(AndroidOverlayFactoryCB());
testing::Mock::VerifyAndClearExpectations(&client_);
// Provide a factory. |chooser_| should try to create an overlay. We don't
// care if a call to UseSurfaceTexture is elided or not. Note that AVDA will
// ignore duplicate calls anyway (MultipleSurfaceTextureCallbacksAreIgnored).
EXPECT_CALL(*this, MockOnOverlayCreated());
EXPECT_CALL(client_, UseSurfaceTexture()).Times(AnyNumber());
chooser_->ReplaceOverlayFactory(FactoryFor(std::move(overlay_)));
testing::Mock::VerifyAndClearExpectations(&client_);
testing::Mock::VerifyAndClearExpectations(this);
// Notify |chooser_| that the overlay is ready.
EXPECT_CALL(client_, UseOverlay(NotNull()));
overlay_callbacks_.OverlayReady.Run();
}
} // namespace media