blob: 24d1358de9b24b33bb0dc9cbee9cf0184ebcd157 [file] [log] [blame]
/*
* Copyright (C) 2014-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#if PLATFORM(IOS_FAMILY) && ENABLE(VIDEO_PRESENTATION_MODE)
#include "EventListener.h"
#include "HTMLMediaElementEnums.h"
#include "PlatformLayer.h"
#include "PlaybackSessionInterfaceAVKit.h"
#include "VideoFullscreenModel.h"
#include <objc/objc.h>
#include <wtf/Forward.h>
#include <wtf/Function.h>
#include <wtf/RetainPtr.h>
#include <wtf/RunLoop.h>
#include <wtf/ThreadSafeRefCounted.h>
#include <wtf/WeakPtr.h>
OBJC_CLASS UIViewController;
OBJC_CLASS UIWindow;
OBJC_CLASS UIView;
OBJC_CLASS CALayer;
OBJC_CLASS WebAVPlayerController;
OBJC_CLASS WebAVPlayerLayerView;
OBJC_CLASS WebAVPlayerLayer;
OBJC_CLASS WebAVPlayerViewController;
OBJC_CLASS WebAVPlayerViewControllerDelegate;
OBJC_CLASS NSError;
namespace WebCore {
class IntRect;
class FloatSize;
class VideoFullscreenModel;
class VideoFullscreenChangeObserver;
class VideoFullscreenInterfaceAVKit final
: public VideoFullscreenModelClient
, public PlaybackSessionModelClient
, public ThreadSafeRefCounted<VideoFullscreenInterfaceAVKit, WTF::DestructionThread::MainRunLoop>
, public CanMakeWeakPtr<VideoFullscreenInterfaceAVKit> {
public:
WEBCORE_EXPORT static Ref<VideoFullscreenInterfaceAVKit> create(PlaybackSessionInterfaceAVKit&);
virtual ~VideoFullscreenInterfaceAVKit();
WEBCORE_EXPORT void setVideoFullscreenModel(VideoFullscreenModel*);
WEBCORE_EXPORT void setVideoFullscreenChangeObserver(VideoFullscreenChangeObserver*);
PlaybackSessionInterfaceAVKit& playbackSessionInterface() const { return m_playbackSessionInterface.get(); }
PlaybackSessionModel* playbackSessionModel() const { return m_playbackSessionInterface->playbackSessionModel(); }
// VideoFullscreenModelClient
WEBCORE_EXPORT void hasVideoChanged(bool) final;
WEBCORE_EXPORT void videoDimensionsChanged(const FloatSize&) final;
WEBCORE_EXPORT void modelDestroyed() final;
// PlaybackSessionModelClient
WEBCORE_EXPORT void externalPlaybackChanged(bool enabled, PlaybackSessionModel::ExternalPlaybackTargetType, const String& localizedDeviceName) final;
WEBCORE_EXPORT void setupFullscreen(UIView& videoView, const IntRect& initialRect, const FloatSize& videoDimensions, UIView* parentView, HTMLMediaElementEnums::VideoFullscreenMode, bool allowsPictureInPicturePlayback, bool standby);
WEBCORE_EXPORT void enterFullscreen();
WEBCORE_EXPORT void exitFullscreen(const IntRect& finalRect);
WEBCORE_EXPORT void cleanupFullscreen();
WEBCORE_EXPORT void invalidate();
WEBCORE_EXPORT void requestHideAndExitFullscreen();
WEBCORE_EXPORT void preparedToReturnToInline(bool visible, const IntRect& inlineRect);
WEBCORE_EXPORT void preparedToExitFullscreen();
WEBCORE_EXPORT void setHasVideoContentLayer(bool);
WEBCORE_EXPORT void setInlineRect(const IntRect&, bool visible);
enum class ExitFullScreenReason {
DoneButtonTapped,
FullScreenButtonTapped,
PinchGestureHandled,
RemoteControlStopEventReceived,
PictureInPictureStarted
};
class Mode {
HTMLMediaElementEnums::VideoFullscreenMode m_mode { HTMLMediaElementEnums::VideoFullscreenModeNone };
public:
Mode() = default;
Mode(const Mode&) = default;
Mode(HTMLMediaElementEnums::VideoFullscreenMode mode) : m_mode(mode) { }
void operator=(HTMLMediaElementEnums::VideoFullscreenMode mode) { m_mode = mode; }
HTMLMediaElementEnums::VideoFullscreenMode mode() const { return m_mode; }
void setModeValue(HTMLMediaElementEnums::VideoFullscreenMode mode, bool value) { value ? setMode(mode) : clearMode(mode); }
void setMode(HTMLMediaElementEnums::VideoFullscreenMode mode) { m_mode |= mode; }
void clearMode(HTMLMediaElementEnums::VideoFullscreenMode mode) { m_mode &= ~mode; }
bool hasMode(HTMLMediaElementEnums::VideoFullscreenMode mode) const { return m_mode & mode; }
bool isPictureInPicture() const { return m_mode == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture; }
bool isFullscreen() const { return m_mode == HTMLMediaElementEnums::VideoFullscreenModeStandard; }
void setPictureInPicture(bool value) { setModeValue(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture, value); }
void setFullscreen(bool value) { setModeValue(HTMLMediaElementEnums::VideoFullscreenModeStandard, value); }
bool hasFullscreen() const { return hasMode(HTMLMediaElementEnums::VideoFullscreenModeStandard); }
bool hasPictureInPicture() const { return hasMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture); }
bool hasVideo() const { return m_mode & (HTMLMediaElementEnums::VideoFullscreenModeStandard | HTMLMediaElementEnums::VideoFullscreenModePictureInPicture); }
};
Mode m_currentMode;
Mode m_targetMode;
VideoFullscreenModel* videoFullscreenModel() const { return m_videoFullscreenModel; }
bool shouldExitFullscreenWithReason(ExitFullScreenReason);
HTMLMediaElementEnums::VideoFullscreenMode mode() const { return m_currentMode.mode(); }
bool allowsPictureInPicturePlayback() const { return m_allowsPictureInPicturePlayback; }
WEBCORE_EXPORT bool mayAutomaticallyShowVideoPictureInPicture() const;
void fullscreenMayReturnToInline(WTF::Function<void(bool)>&& callback);
bool wirelessVideoPlaybackDisabled() const;
WEBCORE_EXPORT void applicationDidBecomeActive();
void willStartPictureInPicture();
void didStartPictureInPicture();
void failedToStartPictureInPicture();
void willStopPictureInPicture();
void didStopPictureInPicture();
void prepareForPictureInPictureStopWithCompletionHandler(void (^)(BOOL));
void exitFullscreenHandler(BOOL success, NSError *);
void enterFullscreenHandler(BOOL success, NSError *);
bool isPlayingVideoInEnhancedFullscreen() const;
WEBCORE_EXPORT void setMode(HTMLMediaElementEnums::VideoFullscreenMode);
void clearMode(HTMLMediaElementEnums::VideoFullscreenMode);
bool hasMode(HTMLMediaElementEnums::VideoFullscreenMode mode) const { return m_currentMode.hasMode(mode); }
#if PLATFORM(IOS_FAMILY)
UIViewController *presentingViewController();
UIViewController *fullscreenViewController() const { return m_viewController.get(); }
WebAVPlayerLayerView* playerLayerView() const { return m_playerLayerView.get(); }
WEBCORE_EXPORT bool pictureInPictureWasStartedWhenEnteringBackground() const;
#endif
protected:
WEBCORE_EXPORT VideoFullscreenInterfaceAVKit(PlaybackSessionInterfaceAVKit&);
void doSetup();
void finalizeSetup();
void doExitFullscreen();
void returnToStandby();
void doEnterFullscreen();
void watchdogTimerFired();
WebAVPlayerController *playerController() const;
Ref<PlaybackSessionInterfaceAVKit> m_playbackSessionInterface;
RetainPtr<WebAVPlayerViewControllerDelegate> m_playerViewControllerDelegate;
RetainPtr<WebAVPlayerViewController> m_playerViewController;
VideoFullscreenModel* m_videoFullscreenModel { nullptr };
VideoFullscreenChangeObserver* m_fullscreenChangeObserver { nullptr };
// These are only used when fullscreen is presented in a separate window.
RetainPtr<UIWindow> m_window;
RetainPtr<UIViewController> m_viewController;
RetainPtr<UIView> m_videoView;
RetainPtr<UIView> m_parentView;
RetainPtr<UIWindow> m_parentWindow;
RetainPtr<WebAVPlayerLayerView> m_playerLayerView;
WTF::Function<void(bool)> m_prepareToInlineCallback;
RunLoop::Timer<VideoFullscreenInterfaceAVKit> m_watchdogTimer;
FloatRect m_inlineRect;
RouteSharingPolicy m_routeSharingPolicy { RouteSharingPolicy::Default };
String m_routingContextUID;
bool m_allowsPictureInPicturePlayback { false };
bool m_wirelessVideoPlaybackDisabled { true };
bool m_shouldReturnToFullscreenWhenStoppingPiP { false };
bool m_restoringFullscreenForPictureInPictureStop { false };
bool m_setupNeedsInlineRect { false };
bool m_exitFullscreenNeedInlineRect { false };
bool m_finalizeSetupNeedsVideoContentLayer { false };
bool m_cleanupNeedsReturnVideoContentLayer { false };
bool m_returnToStandbyNeedsReturnVideoContentLayer { false };
bool m_finalizeSetupNeedsReturnVideoContentLayer { false };
bool m_exitFullscreenNeedsExitFullscreen { false };
bool m_exitFullscreenNeedsExitPictureInPicture { false };
bool m_exitFullscreenNeedsReturnContentLayer { false };
bool m_enterFullscreenNeedsEnterFullscreen { false };
bool m_enterFullscreenNeedsExitFullscreen { false };
bool m_enterFullscreenNeedsEnterPictureInPicture { false };
bool m_enterFullscreenNeedsExitPictureInPicture { false };
bool m_hasVideoContentLayer { false };
bool m_hasUpdatedInlineRect { false };
bool m_inlineIsVisible { false };
bool m_standby { false };
bool m_targetStandby { false };
bool m_waitingForPreparedToExit { false };
bool m_shouldIgnoreAVKitCallbackAboutExitFullscreenReason { false };
bool m_enteringPictureInPicture { false };
};
}
#endif // PLATFORM(IOS_FAMILY)