/* * Copyright (C) 2007-2021 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 ENABLE(VIDEO) #include "ActiveDOMObject.h" #include "AudioTrack.h" #include "AutoplayEvent.h" #include "CaptionUserPreferences.h" #include "HTMLElement.h" #include "HTMLMediaElementEnums.h" #include "MediaCanStartListener.h" #include "MediaControllerInterface.h" #include "MediaElementSession.h" #include "MediaPlayer.h" #include "MediaProducer.h" #include "MediaUniqueIdentifier.h" #include "TextTrack.h" #include "VideoTrack.h" #include "VisibilityChangeClient.h" #include #include #include #if USE(AUDIO_SESSION) && PLATFORM(MAC) #include "AudioSession.h" #endif #if ENABLE(ENCRYPTED_MEDIA) #include "CDMClient.h" #endif #ifndef NDEBUG #include #endif namespace WebCore { class AudioSourceProvider; class AudioTrackList; class AudioTrackPrivate; class Blob; class DOMException; class DOMWrapperWorld; class DeferredPromise; class Event; class HTMLSourceElement; class HTMLTrackElement; class InbandTextTrackPrivate; class JSDOMGlobalObject; class MediaController; class MediaControls; class MediaControlsHost; class MediaElementAudioSourceNode; class MediaError; class MediaKeys; class MediaResourceLoader; class MediaSession; class MediaSource; class MediaStream; class RenderMedia; class ScriptController; class ScriptExecutionContext; class SleepDisabler; class SourceBuffer; class TextTrackList; class TimeRanges; class VideoPlaybackQuality; class VideoTrackList; class VideoTrackPrivate; class WebKitMediaKeys; enum class DynamicRangeMode : uint8_t; template class DOMPromiseDeferred; template class PODInterval; #if ENABLE(WIRELESS_PLAYBACK_TARGET) class RemotePlayback; #endif using CueInterval = PODInterval; using CueList = Vector; using MediaProvider = std::optional, #endif #if ENABLE(MEDIA_SOURCE) RefPtr, #endif RefPtr>>; class HTMLMediaElement : public HTMLElement , public ActiveDOMObject , public MediaControllerInterface , public PlatformMediaSessionClient , private MediaCanStartListener , private MediaPlayerClient , private MediaProducer , private VisibilityChangeClient , private AudioTrackClient , private TextTrackClient , private VideoTrackClient #if USE(AUDIO_SESSION) && PLATFORM(MAC) , private AudioSession::ConfigurationChangeObserver #endif #if ENABLE(ENCRYPTED_MEDIA) , private CDMClient #endif #if !RELEASE_LOG_DISABLED , private LoggerHelper #endif , public CanMakeWeakPtr { WTF_MAKE_ISO_ALLOCATED(HTMLMediaElement); public: using WeakValueType = HTMLElement::WeakValueType; using HTMLElement::weakPtrFactory; RefPtr player() const { return m_player; } bool supportsAcceleratedRendering() const { return m_cachedSupportsAcceleratedRendering; } virtual bool isVideo() const { return false; } bool hasVideo() const override { return false; } bool hasAudio() const override; bool hasRenderer() const { return static_cast(renderer()); } WEBCORE_EXPORT static HashSet& allMediaElements(); WEBCORE_EXPORT static RefPtr bestMediaElementForRemoteControls(MediaElementSession::PlaybackControlsPurpose, const Document* = nullptr); WEBCORE_EXPORT void rewind(double timeDelta); WEBCORE_EXPORT void returnToRealtime() override; // Eventually overloaded in HTMLVideoElement bool supportsFullscreen(HTMLMediaElementEnums::VideoFullscreenMode) const override { return false; }; bool supportsScanning() const override; bool canSaveMediaData() const; bool doesHaveAttribute(const AtomString&, AtomString* value = nullptr) const override; PlatformLayer* platformLayer() const; bool isVideoLayerInline(); void setPreparedToReturnVideoLayerToInline(bool); void waitForPreparedForInlineThen(WTF::Function&& completionHandler = [] { }); #if ENABLE(VIDEO_PRESENTATION_MODE) RetainPtr createVideoFullscreenLayer(); WEBCORE_EXPORT void setVideoFullscreenLayer(PlatformLayer*, WTF::Function&& completionHandler = [] { }); #ifdef __OBJC__ PlatformLayer* videoFullscreenLayer() const { return m_videoFullscreenLayer.get(); } #endif virtual void setVideoFullscreenFrame(const FloatRect&); void setVideoFullscreenGravity(MediaPlayer::VideoGravity); MediaPlayer::VideoGravity videoFullscreenGravity() const { return m_videoFullscreenGravity; } #endif void scheduleCheckPlaybackTargetCompatability(); void checkPlaybackTargetCompatibility(); void scheduleResolvePendingPlayPromises(); void scheduleRejectPendingPlayPromises(Ref&&); using PlayPromiseVector = Vector>; void rejectPendingPlayPromises(PlayPromiseVector&&, Ref&&); void resolvePendingPlayPromises(PlayPromiseVector&&); void scheduleNotifyAboutPlaying(); void notifyAboutPlaying(PlayPromiseVector&&); MediaPlayer::MovieLoadType movieLoadType() const; bool inActiveDocument() const { return m_inActiveDocument; } MediaSessionGroupIdentifier mediaSessionGroupIdentifier() const final; // DOM API // error state WEBCORE_EXPORT MediaError* error() const; const URL& currentSrc() const { return m_currentSrc; } const MediaProvider& srcObject() const { return m_mediaProvider; } void setSrcObject(MediaProvider&&); WEBCORE_EXPORT void setCrossOrigin(const AtomString&); WEBCORE_EXPORT String crossOrigin() const; // network state using HTMLMediaElementEnums::NetworkState; WEBCORE_EXPORT NetworkState networkState() const; WEBCORE_EXPORT String preload() const; WEBCORE_EXPORT void setPreload(const String&); Ref buffered() const override; WEBCORE_EXPORT void load(); WEBCORE_EXPORT String canPlayType(const String& mimeType) const; // ready state using HTMLMediaElementEnums::ReadyState; ReadyState readyState() const override; WEBCORE_EXPORT bool seeking() const; // playback state WEBCORE_EXPORT double currentTime() const override; WEBCORE_EXPORT void setCurrentTime(double) override; void setCurrentTimeWithTolerance(double, double toleranceBefore, double toleranceAfter); double currentTimeForBindings() const { return currentTime(); } WEBCORE_EXPORT ExceptionOr setCurrentTimeForBindings(double); WEBCORE_EXPORT double getStartDate() const; WEBCORE_EXPORT double duration() const override; WEBCORE_EXPORT bool paused() const override; double defaultPlaybackRate() const override; void setDefaultPlaybackRate(double) override; WEBCORE_EXPORT double playbackRate() const override; void setPlaybackRate(double) override; // MediaTime versions of playback state MediaTime currentMediaTime() const; void setCurrentTime(const MediaTime&); MediaTime durationMediaTime() const; WEBCORE_EXPORT void fastSeek(const MediaTime&); void updatePlaybackRate(); WEBCORE_EXPORT bool webkitPreservesPitch() const; WEBCORE_EXPORT void setWebkitPreservesPitch(bool); Ref played() override; Ref seekable() const override; double seekableTimeRangesLastModifiedTime() const; double liveUpdateInterval() const; WEBCORE_EXPORT bool ended() const; bool autoplay() const; bool isAutoplaying() const { return m_autoplaying; } bool loop() const; void setLoop(bool b); void play(DOMPromiseDeferred&&); WEBCORE_EXPORT void play() override; WEBCORE_EXPORT void pause() override; WEBCORE_EXPORT void fastSeek(double); double minFastReverseRate() const; double maxFastForwardRate() const; #if ENABLE(MEDIA_STREAM) void setAudioOutputDevice(String&& deviceId, DOMPromiseDeferred&&); String audioOutputHashedDeviceId() const { return m_audioOutputHashedDeviceId; } #endif using HTMLMediaElementEnums::BufferingPolicy; void setBufferingPolicy(BufferingPolicy); WEBCORE_EXPORT BufferingPolicy bufferingPolicy() const; WEBCORE_EXPORT void purgeBufferedDataIfPossible(); // captions WEBCORE_EXPORT bool webkitHasClosedCaptions() const; WEBCORE_EXPORT bool webkitClosedCaptionsVisible() const; WEBCORE_EXPORT void setWebkitClosedCaptionsVisible(bool); bool elementIsHidden() const { return m_elementIsHidden; } #if ENABLE(MEDIA_STATISTICS) // Statistics unsigned webkitAudioDecodedByteCount() const; unsigned webkitVideoDecodedByteCount() const; #endif #if ENABLE(MEDIA_SOURCE) // Media Source. void detachMediaSource(); void incrementDroppedFrameCount() { ++m_droppedVideoFrames; } size_t maximumSourceBufferSize(const SourceBuffer&) const; #endif #if ENABLE(LEGACY_ENCRYPTED_MEDIA) WebKitMediaKeys* webkitKeys() const { return m_webKitMediaKeys.get(); } void webkitSetMediaKeys(WebKitMediaKeys*); void keyAdded(); #endif #if ENABLE(ENCRYPTED_MEDIA) MediaKeys* mediaKeys() const; void setMediaKeys(MediaKeys*, Ref&&); #endif // controls WEBCORE_EXPORT bool controls() const; WEBCORE_EXPORT void setControls(bool); WEBCORE_EXPORT double volume() const override; WEBCORE_EXPORT ExceptionOr setVolume(double) override; WEBCORE_EXPORT bool muted() const override; WEBCORE_EXPORT void setMuted(bool) override; WEBCORE_EXPORT void togglePlayState(); WEBCORE_EXPORT void beginScrubbing() override; WEBCORE_EXPORT void endScrubbing() override; void beginScanning(ScanDirection) override; void endScanning() override; double nextScanRate(); WEBCORE_EXPORT bool canPlay() const override; double percentLoaded() const; bool shouldForceControlsDisplay() const; ExceptionOr addTextTrack(const String& kind, const String& label, const String& language); AudioTrackList& ensureAudioTracks(); TextTrackList& ensureTextTracks(); VideoTrackList& ensureVideoTracks(); AudioTrackList* audioTracks() const { return m_audioTracks.get(); } TextTrackList* textTracks() const { return m_textTracks.get(); } VideoTrackList* videoTracks() const { return m_videoTracks.get(); } CueList currentlyActiveCues() const; void addAudioTrack(Ref&&); void addTextTrack(Ref&&); void addVideoTrack(Ref&&); void removeAudioTrack(Ref&&); void removeTextTrack(Ref&&, bool scheduleEvent = true); void removeVideoTrack(Ref&&); void forgetResourceSpecificTracks(); void closeCaptionTracksChanged(); void notifyMediaPlayerOfTextTrackChanges(); virtual void didAddTextTrack(HTMLTrackElement&); virtual void didRemoveTextTrack(HTMLTrackElement&); void mediaPlayerDidAddAudioTrack(AudioTrackPrivate&) final; void mediaPlayerDidAddTextTrack(InbandTextTrackPrivate&) final; void mediaPlayerDidAddVideoTrack(VideoTrackPrivate&) final; void mediaPlayerDidRemoveAudioTrack(AudioTrackPrivate&) final; void mediaPlayerDidRemoveTextTrack(InbandTextTrackPrivate&) final; void mediaPlayerDidRemoveVideoTrack(VideoTrackPrivate&) final; #if ENABLE(AVF_CAPTIONS) Vector> outOfBandTrackSources() final; #endif struct TrackGroup; void configureTextTrackGroupForLanguage(const TrackGroup&) const; void scheduleConfigureTextTracks(); void configureTextTracks(); void configureTextTrackGroup(const TrackGroup&); void setSelectedTextTrack(TextTrack*); // AudioTrackClient void audioTrackEnabledChanged(AudioTrack&) final; // TextTrackClient void textTrackKindChanged(TextTrack&) override; void textTrackModeChanged(TextTrack&) override; void textTrackAddCues(TextTrack&, const TextTrackCueList&) override; void textTrackRemoveCues(TextTrack&, const TextTrackCueList&) override; void textTrackAddCue(TextTrack&, TextTrackCue&) override; void textTrackRemoveCue(TextTrack&, TextTrackCue&) override; // VideoTrackClient void videoTrackSelectedChanged(VideoTrack&) final; bool requiresTextTrackRepresentation() const; void setTextTrackRepresentation(TextTrackRepresentation*); void syncTextTrackBounds(); void captionPreferencesChanged(); using HTMLMediaElementEnums::TextTrackVisibilityCheckType; void textTrackReadyStateChanged(TextTrack*); void updateTextTrackRepresentationImageIfNeeded(); bool addEventListener(const AtomString& eventType, Ref&&, const AddEventListenerOptions&) override; bool removeEventListener(const AtomString& eventType, EventListener&, const EventListenerOptions&) override; #if ENABLE(WIRELESS_PLAYBACK_TARGET) void webkitShowPlaybackTargetPicker(); void wirelessRoutesAvailableDidChange() override; void setWirelessPlaybackTarget(Ref&&) override; void setShouldPlayToPlaybackTarget(bool) override; void playbackTargetPickerWasDismissed() override; #endif bool isPlayingToWirelessPlaybackTarget() const override { return m_isPlayingToWirelessTarget; }; void setIsPlayingToWirelessTarget(bool); bool webkitCurrentPlaybackTargetIsWireless() const; void setPlayingOnSecondScreen(bool value); bool isPlayingOnSecondScreen() const override { return m_playingOnSecondScreen; } bool isPlayingToExternalTarget() const { return isPlayingToWirelessPlaybackTarget() || isPlayingOnSecondScreen(); } // EventTarget function. // Both Node (via HTMLElement) and ActiveDOMObject define this method, which // causes an ambiguity error at compile time. This class's constructor // ensures that both implementations return document, so return the result // of one of them here. using HTMLElement::scriptExecutionContext; bool hasSingleSecurityOrigin() const { return !m_player || m_player->hasSingleSecurityOrigin(); } bool didPassCORSAccessCheck() const { return m_player && m_player->didPassCORSAccessCheck(); } bool wouldTaintOrigin(const SecurityOrigin& origin) const { return m_player && m_player->wouldTaintOrigin(origin); } WEBCORE_EXPORT bool isFullscreen() const override; bool isStandardFullscreen() const; void toggleStandardFullscreenState(); using MediaPlayerEnums::VideoFullscreenMode; VideoFullscreenMode fullscreenMode() const { return m_videoFullscreenMode; } void enterFullscreen(VideoFullscreenMode); WEBCORE_EXPORT void enterFullscreen() override; WEBCORE_EXPORT void exitFullscreen(); WEBCORE_EXPORT void prepareForVideoFullscreenStandby(); WEBCORE_EXPORT void setVideoFullscreenStandby(bool); bool hasClosedCaptions() const override; bool closedCaptionsVisible() const override; void setClosedCaptionsVisible(bool) override; void sourceWasRemoved(HTMLSourceElement&); void sourceWasAdded(HTMLSourceElement&); // Media cache management. WEBCORE_EXPORT static void setMediaCacheDirectory(const String&); WEBCORE_EXPORT static const String& mediaCacheDirectory(); WEBCORE_EXPORT static HashSet originsInMediaCache(const String&); WEBCORE_EXPORT static void clearMediaCache(const String&, WallTime modifiedSince = { }); WEBCORE_EXPORT static void clearMediaCacheForOrigins(const String&, const HashSet&); static void resetMediaEngines(); bool isPlaying() const final { return m_playing; } #if ENABLE(WEB_AUDIO) MediaElementAudioSourceNode* audioSourceNode() { return m_audioSourceNode; } void setAudioSourceNode(MediaElementAudioSourceNode*); AudioSourceProvider* audioSourceProvider(); #endif using HTMLMediaElementEnums::InvalidURLAction; bool isSafeToLoadURL(const URL&, InvalidURLAction); const String& mediaGroup() const; void setMediaGroup(const String&); MediaController* controller() const; void setController(RefPtr&&); MediaController* controllerForBindings() const { return controller(); } void setControllerForBindings(MediaController*); void enteredOrExitedFullscreen() { configureMediaControls(); } unsigned long long fileSize() const; void mediaLoadingFailed(MediaPlayer::NetworkState); void mediaLoadingFailedFatally(MediaPlayer::NetworkState); RefPtr getVideoPlaybackQuality(); MediaPlayer::Preload preloadValue() const { return m_preload; } WEBCORE_EXPORT MediaElementSession& mediaSession() const; void pageScaleFactorChanged(); void userInterfaceLayoutDirectionChanged(); WEBCORE_EXPORT String getCurrentMediaControlsStatus(); WEBCORE_EXPORT void setMediaControlsMaximumRightContainerButtonCountOverride(size_t); WEBCORE_EXPORT void setMediaControlsHidePlaybackRates(bool); MediaControlsHost* mediaControlsHost() { return m_mediaControlsHost.get(); } bool isDisablingSleep() const { return m_sleepDisabler.get(); } double maxBufferedTime() const; MediaProducer::MediaStateFlags mediaState() const override; void layoutSizeChanged(); void visibilityDidChange(); void allowsMediaDocumentInlinePlaybackChanged(); void updateShouldPlay(); RenderMedia* renderer() const; void resetPlaybackSessionState(); bool isVisibleInViewport() const; bool hasEverNotifiedAboutPlaying() const; void setShouldDelayLoadEvent(bool); bool hasEverHadAudio() const { return m_hasEverHadAudio; } bool hasEverHadVideo() const { return m_hasEverHadVideo; } double playbackStartedTime() const { return m_playbackStartedTime; } bool isTemporarilyAllowingInlinePlaybackAfterFullscreen() const {return m_temporarilyAllowingInlinePlaybackAfterFullscreen; } void isVisibleInViewportChanged(); void updateRateChangeRestrictions(); WEBCORE_EXPORT const MediaResourceLoader* lastMediaResourceLoaderForTesting() const; #if ENABLE(MEDIA_STREAM) void mediaStreamCaptureStarted(); bool hasMediaStreamSrcObject() const { return m_mediaProvider && WTF::holds_alternative>(*m_mediaProvider); } #endif bool supportsSeeking() const override; #if !RELEASE_LOG_DISABLED const Logger& logger() const final { return *m_logger.get(); } const void* logIdentifier() const final { return m_logIdentifier; } const char* logClassName() const final { return "HTMLMediaElement"; } WTFLogChannel& logChannel() const final; #endif bool willLog(WTFLogLevel) const; bool isSuspended() const final; WEBCORE_EXPORT void didBecomeFullscreenElement() final; WEBCORE_EXPORT void willExitFullscreen(); WEBCORE_EXPORT void didStopBeingFullscreenElement() final; void scheduleEvent(Ref&&); enum class AutoplayEventPlaybackState { None, PreventedAutoplay, StartedWithUserGesture, StartedWithoutUserGesture }; #if ENABLE(WIRELESS_PLAYBACK_TARGET) RemotePlayback& remote() { return m_remote; } void remoteHasAvailabilityCallbacksChanged(); #endif void privateBrowsingStateDidChange(PAL::SessionID); void mediaVolumeDidChange(); void applicationWillResignActive(); void applicationDidBecomeActive(); MediaUniqueIdentifier mediaUniqueIdentifier() const; String mediaSessionTitle() const; String sourceApplicationIdentifier() const; WEBCORE_EXPORT void setOverridePreferredDynamicRangeMode(DynamicRangeMode); void setPreferredDynamicRangeMode(DynamicRangeMode); void didReceiveRemoteControlCommand(PlatformMediaSession::RemoteControlCommandType, const PlatformMediaSession::RemoteCommandArgument&) override; using EventTarget::dispatchEvent; void dispatchEvent(Event&) override; protected: HTMLMediaElement(const QualifiedName&, Document&, bool createdByParser); virtual ~HTMLMediaElement(); void parseAttribute(const QualifiedName&, const AtomString&) override; void finishParsingChildren() override; bool isURLAttribute(const Attribute&) const override; void willAttachRenderers() override; void didAttachRenderers() override; void willDetachRenderers() override; void didDetachRenderers() override; void didMoveToNewDocument(Document& oldDocument, Document& newDocument) override; bool isMediaElement() const final { return true; } RenderPtr createElementRenderer(RenderStyle&&, const RenderTreePosition&) override; SecurityOriginData documentSecurityOrigin() const final; String audioOutputDeviceId() const final { return m_audioOutputPersistentDeviceId; } String audioOutputDeviceIdOverride() const final { return m_audioOutputPersistentDeviceId; } bool mediaControlsDependOnPageScaleFactor() const { return m_mediaControlsDependOnPageScaleFactor; } void setMediaControlsDependOnPageScaleFactor(bool); void updateMediaControlsAfterPresentationModeChange(); void scheduleEvent(const AtomString&); template void scheduleEventOn(T& target, Ref&&); bool showPosterFlag() const { return m_showPoster; } void setShowPosterFlag(bool); void setChangingVideoFullscreenMode(bool value) { m_changingVideoFullscreenMode = value; } bool isChangingVideoFullscreenMode() const { return m_changingVideoFullscreenMode; } private: friend class Internals; void createMediaPlayer(); bool supportsFocus() const override; bool isMouseFocusable() const override; bool rendererIsNeeded(const RenderStyle&) override; bool childShouldCreateRenderer(const Node&) const override; InsertedIntoAncestorResult insertedIntoAncestor(InsertionType, ContainerNode&) override; void didFinishInsertingNode() override; void removedFromAncestor(RemovalType, ContainerNode&) override; void didRecalcStyle(Style::Change) override; bool isInteractiveContent() const override; void setFullscreenMode(VideoFullscreenMode); void willBecomeFullscreenElement() override; void willStopBeingFullscreenElement() override; // ActiveDOMObject API. const char* activeDOMObjectName() const override; void suspend(ReasonForSuspension) override; void resume() override; void stop() override; bool virtualHasPendingActivity() const override; void stopWithoutDestroyingMediaPlayer(); void contextDestroyed() override; void visibilityStateChanged() final; void setReadyState(MediaPlayer::ReadyState); void setNetworkState(MediaPlayer::NetworkState); WEBCORE_EXPORT double effectivePlaybackRate() const; double requestedPlaybackRate() const; void mediaPlayerNetworkStateChanged() final; void mediaPlayerReadyStateChanged() final; void mediaPlayerTimeChanged() final; void mediaPlayerVolumeChanged() final; void mediaPlayerMuteChanged() final; void mediaPlayerDurationChanged() final; void mediaPlayerRateChanged() final; void mediaPlayerPlaybackStateChanged() final; void mediaPlayerResourceNotSupported() final; void mediaPlayerRepaint() final; void mediaPlayerSizeChanged() final; bool mediaPlayerRenderingCanBeAccelerated() final; void mediaPlayerRenderingModeChanged() final; bool mediaPlayerAcceleratedCompositingEnabled() final; void mediaPlayerEngineUpdated() final; void mediaPlayerWillInitializeMediaEngine() final; void mediaPlayerDidInitializeMediaEngine() final; void mediaPlayerReloadAndResumePlaybackIfNeeded() final; void mediaPlayerQueueTaskOnEventLoop(Function&&) final; void scheduleMediaEngineWasUpdated(); void mediaEngineWasUpdated(); void mediaPlayerCharacteristicChanged() final; #if ENABLE(LEGACY_ENCRYPTED_MEDIA) RefPtr mediaPlayerCachedKeyForKeyId(const String& keyId) const final; void mediaPlayerKeyNeeded(Uint8Array*) final; String mediaPlayerMediaKeysStorageDirectory() const final; #endif #if ENABLE(ENCRYPTED_MEDIA) void mediaPlayerInitializationDataEncountered(const String&, RefPtr&&) final; void mediaPlayerWaitingForKeyChanged() final; void attemptToDecrypt(); void attemptToResumePlaybackIfNecessary(); // CDMClient void cdmClientAttemptToResumePlaybackIfNecessary() final; void cdmClientUnrequestedInitializationDataReceived(const String&, Ref&&) final; #endif #if ENABLE(LEGACY_ENCRYPTED_MEDIA) && ENABLE(ENCRYPTED_MEDIA) void updateShouldContinueAfterNeedKey(); #endif #if ENABLE(WIRELESS_PLAYBACK_TARGET) void mediaPlayerCurrentPlaybackTargetIsWirelessChanged(bool) final; void enqueuePlaybackTargetAvailabilityChangedEvent(); #endif String mediaPlayerReferrer() const override; String mediaPlayerUserAgent() const override; bool mediaPlayerIsFullscreen() const override; bool mediaPlayerIsFullscreenPermitted() const override; bool mediaPlayerIsVideo() const override; LayoutRect mediaPlayerContentBoxRect() const override; float mediaPlayerContentsScale() const override; bool mediaPlayerPlatformVolumeConfigurationRequired() const override; bool mediaPlayerIsLooping() const override; CachedResourceLoader* mediaPlayerCachedResourceLoader() override; RefPtr mediaPlayerCreateResourceLoader() override; bool mediaPlayerShouldUsePersistentCache() const override; const String& mediaPlayerMediaCacheDirectory() const override; #if PLATFORM(WIN) && USE(AVFOUNDATION) GraphicsDeviceAdapter* mediaPlayerGraphicsDeviceAdapter() const override; #endif void mediaPlayerActiveSourceBuffersChanged() override; String mediaPlayerSourceApplicationIdentifier() const override { return sourceApplicationIdentifier(); } Vector mediaPlayerPreferredAudioCharacteristics() const override; String mediaPlayerElementId() const override { return m_id; } #if PLATFORM(IOS_FAMILY) String mediaPlayerNetworkInterfaceName() const override; void mediaPlayerGetRawCookies(const URL&, MediaPlayerClient::GetRawCookiesCallback&&) const final; #endif void mediaPlayerEngineFailedToLoad() const final; double mediaPlayerRequestedPlaybackRate() const final; VideoFullscreenMode mediaPlayerFullscreenMode() const final { return fullscreenMode(); } bool mediaPlayerIsVideoFullscreenStandby() const final { return m_videoFullscreenStandby; } bool mediaPlayerShouldDisableSleep() const final { return shouldDisableSleep() == SleepType::Display; } bool mediaPlayerShouldCheckHardwareSupport() const final; const Vector& mediaContentTypesRequiringHardwareSupport() const final; void mediaPlayerBufferedTimeRangesChanged() final; #if USE(GSTREAMER) void requestInstallMissingPlugins(const String& details, const String& description, MediaPlayerRequestInstallMissingPluginsCallback&) final; #endif void pendingActionTimerFired(); void progressEventTimerFired(); void playbackProgressTimerFired(); void scanTimerFired(); void seekTask(); void startPlaybackProgressTimer(); void startProgressEventTimer(); void stopPeriodicTimers(); void cancelPendingTasks(); void closeTaskQueues(); void seek(const MediaTime&); void seekInternal(const MediaTime&); void seekWithTolerance(const MediaTime&, const MediaTime& negativeTolerance, const MediaTime& positiveTolerance, bool fromDOM); void finishSeek(); void clearSeeking(); void addPlayedRange(const MediaTime& start, const MediaTime& end); void scheduleTimeupdateEvent(bool periodicEvent); virtual void scheduleResizeEvent() { } virtual void scheduleResizeEventIfSizeChanged() { } void selectMediaResource(); void loadResource(const URL&, ContentType&, const String& keySystem); void scheduleNextSourceChild(); void loadNextSourceChild(); void userCancelledLoad(); void clearMediaPlayer(); bool havePotentialSourceChild(); void noneSupported(); void cancelPendingEventsAndCallbacks(); void waitForSourceChange(); void prepareToPlay(); URL selectNextSourceChild(ContentType*, String* keySystem, InvalidURLAction); bool ignoreTrackDisplayUpdateRequests() const; void beginIgnoringTrackDisplayUpdateRequests(); void endIgnoringTrackDisplayUpdateRequests(); void updateActiveTextTrackCues(const MediaTime&); HTMLTrackElement* showingTrackWithSameKind(HTMLTrackElement*) const; enum ReconfigureMode { Immediately, AfterDelay }; void markCaptionAndSubtitleTracksAsUnconfigured(ReconfigureMode); CaptionUserPreferences::CaptionDisplayMode captionDisplayMode(); bool textTracksAreReady() const; void configureTextTrackDisplay(TextTrackVisibilityCheckType = CheckTextTrackVisibility); void updateTextTrackDisplay(); // These "internal" functions do not check user gesture restrictions. void playInternal(); void pauseInternal(); void prepareForLoad(); void allowVideoRendering(); bool processingMediaPlayerCallback() const { return m_processingMediaPlayerCallback > 0; } void beginProcessingMediaPlayerCallback() { ++m_processingMediaPlayerCallback; } void endProcessingMediaPlayerCallback() { ASSERT(m_processingMediaPlayerCallback); --m_processingMediaPlayerCallback; } void scheduleUpdatePlayState(); void updatePlayState(); void updateVolume(); void setPlaying(bool); bool potentiallyPlaying() const; bool endedPlayback() const; bool stoppedDueToErrors() const; bool pausedForUserInteraction() const; bool couldPlayIfEnoughData() const; void dispatchPlayPauseEventsIfNeedsQuirks(); Expected canTransitionFromAutoplayToPlay() const; void setAutoplayEventPlaybackState(AutoplayEventPlaybackState); void userDidInterfereWithAutoplay(); void handleAutoplayEvent(AutoplayEvent); MediaTime minTimeSeekable() const; MediaTime maxTimeSeekable() const; // Pauses playback without changing any states or generating events void setPausedInternal(bool); void pauseAndUpdatePlayStateImmediately(); void setPlaybackRateInternal(double); void mediaCanStart(Document&) final; void invalidateCachedTime() const; void refreshCachedTime() const; void configureMediaControls(); void prepareMediaFragmentURI(); void applyMediaFragmentURI(); void changeNetworkStateFromLoadingToIdle(); void removeBehaviorRestrictionsAfterFirstUserGesture(MediaElementSession::BehaviorRestrictions mask = MediaElementSession::AllRestrictions); void updateMediaController(); bool isBlocked() const; bool isBlockedOnMediaController() const; void setCurrentSrc(const URL&); bool hasCurrentSrc() const override { return !m_currentSrc.isEmpty(); } bool isLiveStream() const override { return movieLoadType() == MovieLoadType::LiveStream; } void updateSleepDisabling(); enum class SleepType { None, Display, System }; SleepType shouldDisableSleep() const; void didAddUserAgentShadowRoot(ShadowRoot&) override; DOMWrapperWorld& ensureIsolatedWorld(); bool ensureMediaControlsInjectedScript(); PlatformMediaSession::MediaType mediaType() const override; PlatformMediaSession::MediaType presentationType() const override; PlatformMediaSession::DisplayType displayType() const override; void suspendPlayback() override; void resumeAutoplaying() override; void mayResumePlayback(bool shouldResume) override; bool canReceiveRemoteControlCommands() const override { return true; } bool shouldOverrideBackgroundPlaybackRestriction(PlatformMediaSession::InterruptionType) const override; bool shouldOverrideBackgroundLoadingRestriction() const override; bool canProduceAudio() const final; bool hasMediaStreamSource() const final; void processIsSuspendedChanged() final; bool shouldOverridePauseDuringRouteChange() const final; void pageMutedStateDidChange() override; #if USE(AUDIO_SESSION) && PLATFORM(MAC) void hardwareMutedStateDidChange(const AudioSession&) final; #endif bool processingUserGestureForMedia() const; bool effectiveMuted() const; double effectiveVolume() const; void registerWithDocument(Document&); void unregisterWithDocument(Document&); void initializeMediaSession(); void updateCaptionContainer(); void ensureMediaControlsShadowRoot(); using JSSetupFunction = WTF::Function; bool setupAndCallJS(const JSSetupFunction&); #if ENABLE(WIRELESS_PLAYBACK_TARGET) void prepareForDocumentSuspension() final; void resumeFromDocumentSuspension() final; void scheduleUpdateMediaState(); void updateMediaState(); bool hasPlaybackTargetAvailabilityListeners() const { return m_hasPlaybackTargetAvailabilityListeners; } #endif bool isVideoTooSmallForInlinePlayback(); void updateShouldAutoplay(); void pauseAfterDetachedTask(); void updatePlaybackControlsManager(); void schedulePlaybackControlsManagerUpdate(); void playbackControlsManagerBehaviorRestrictionsTimerFired(); void updateRenderer(); void updatePageScaleFactorJSProperty(); void updateUsesLTRUserInterfaceLayoutDirectionJSProperty(); void setControllerJSProperty(const char*, JSC::JSValue); void addBehaviorRestrictionsOnEndIfNecessary(); void handleSeekToPlaybackPosition(double); void seekToPlaybackPositionEndedTimerFired(); void setInActiveDocument(bool); void checkForAudioAndVideo(); bool hasLiveSource() const; void playPlayer(); void pausePlayer(); #if !RELEASE_LOG_DISABLED const void* mediaPlayerLogIdentifier() final { return logIdentifier(); } const Logger& mediaPlayerLogger() final { return logger(); } #endif Timer m_progressEventTimer; Timer m_playbackProgressTimer; Timer m_scanTimer; Timer m_playbackControlsManagerBehaviorRestrictionsTimer; Timer m_seekToPlaybackPositionEndedTimer; TaskCancellationGroup m_configureTextTracksTaskCancellationGroup; TaskCancellationGroup m_checkPlaybackTargetCompatibilityTaskCancellationGroup; TaskCancellationGroup m_updateMediaStateTaskCancellationGroup; TaskCancellationGroup m_mediaEngineUpdatedTaskCancellationGroup; TaskCancellationGroup m_updatePlayStateTaskCancellationGroup; TaskCancellationGroup m_resumeTaskCancellationGroup; TaskCancellationGroup m_seekTaskCancellationGroup; TaskCancellationGroup m_playbackControlsManagerBehaviorRestrictionsTaskCancellationGroup; TaskCancellationGroup m_bufferedTimeRangesChangedTaskCancellationGroup; TaskCancellationGroup m_resourceSelectionTaskCancellationGroup; RefPtr m_playedTimeRanges; TaskCancellationGroup m_asyncEventsCancellationGroup; #if PLATFORM(IOS_FAMILY) TaskCancellationGroup m_volumeRevertTaskCancellationGroup; #endif PlayPromiseVector m_pendingPlayPromises; double m_requestedPlaybackRate { 1 }; double m_reportedPlaybackRate { 1 }; double m_defaultPlaybackRate { 1 }; bool m_webkitPreservesPitch { true }; NetworkState m_networkState { NETWORK_EMPTY }; ReadyState m_readyState { HAVE_NOTHING }; ReadyState m_readyStateMaximum { HAVE_NOTHING }; URL m_currentSrc; MediaUniqueIdentifier m_currentIdentifier; RefPtr m_error; struct PendingSeek { WTF_MAKE_STRUCT_FAST_ALLOCATED; PendingSeek(const MediaTime& now, const MediaTime& targetTime, const MediaTime& negativeTolerance, const MediaTime& positiveTolerance) : now(now) , targetTime(targetTime) , negativeTolerance(negativeTolerance) , positiveTolerance(positiveTolerance) { } MediaTime now; MediaTime targetTime; MediaTime negativeTolerance; MediaTime positiveTolerance; }; std::unique_ptr m_pendingSeek; SeekType m_pendingSeekType { NoSeek }; double m_volume { 1 }; bool m_volumeInitialized { false }; MediaTime m_lastSeekTime; MonotonicTime m_previousProgressTime { MonotonicTime::infinity() }; double m_playbackStartedTime { 0 }; // The last time a timeupdate event was sent (based on monotonic clock). MonotonicTime m_clockTimeAtLastUpdateEvent; // The last time a timeupdate event was sent in movie time. MediaTime m_lastTimeUpdateEventMovieTime; // Loading state. enum LoadState { WaitingForSource, LoadingFromSrcAttr, LoadingFromSourceElement }; LoadState m_loadState { WaitingForSource }; RefPtr m_currentSourceNode; RefPtr m_nextChildNodeToConsider; VideoFullscreenMode m_videoFullscreenMode { VideoFullscreenModeNone }; bool m_videoFullscreenStandby { false }; bool m_preparedForInline; WTF::Function m_preparedForInlineCompletionHandler; bool m_temporarilyAllowingInlinePlaybackAfterFullscreen { false }; #if ENABLE(VIDEO_PRESENTATION_MODE) RetainPtr m_videoFullscreenLayer; FloatRect m_videoFullscreenFrame; MediaPlayer::VideoGravity m_videoFullscreenGravity { MediaPlayer::VideoGravity::ResizeAspect }; #endif RefPtr m_player; bool m_cachedSupportsAcceleratedRendering { false }; MediaPlayer::Preload m_preload { Preload::Auto }; // Counter incremented while processing a callback from the media player, so we can avoid // calling the media engine recursively. int m_processingMediaPlayerCallback { 0 }; #if ENABLE(MEDIA_SOURCE) RefPtr m_mediaSource; unsigned m_droppedVideoFrames { 0 }; #endif mutable MediaTime m_cachedTime; mutable MonotonicTime m_clockTimeAtLastCachedTimeUpdate; mutable MonotonicTime m_minimumClockTimeToUpdateCachedTime; MediaTime m_fragmentStartTime; MediaTime m_fragmentEndTime; using PendingActionFlags = unsigned; PendingActionFlags m_pendingActionFlags { 0 }; enum ActionAfterScanType { Nothing, Play, Pause }; ActionAfterScanType m_actionAfterScan { Nothing }; enum ScanType { Seek, Scan }; ScanType m_scanType { Scan }; ScanDirection m_scanDirection { Forward }; BufferingPolicy m_bufferingPolicy { BufferingPolicy::Default }; bool m_firstTimePlaying : 1; bool m_playing : 1; bool m_isWaitingUntilMediaCanStart : 1; bool m_shouldDelayLoadEvent : 1; bool m_haveFiredLoadedData : 1; bool m_inActiveDocument : 1; bool m_autoplaying : 1; bool m_muted : 1; bool m_explicitlyMuted : 1; bool m_initiallyMuted : 1; bool m_paused : 1; bool m_seeking : 1; bool m_seekRequested : 1; bool m_wasPlayingBeforeSeeking : 1; // data has not been loaded since sending a "stalled" event bool m_sentStalledEvent : 1; // time has not changed since sending an "ended" event bool m_sentEndEvent : 1; bool m_pausedInternal : 1; bool m_closedCaptionsVisible : 1; bool m_webkitLegacyClosedCaptionOverride : 1; bool m_completelyLoaded : 1; bool m_havePreparedToPlay : 1; bool m_parsingInProgress : 1; bool m_elementIsHidden : 1; bool m_elementWasRemovedFromDOM : 1; bool m_creatingControls : 1; bool m_receivedLayoutSizeChanged : 1; bool m_hasEverNotifiedAboutPlaying : 1; bool m_hasEverHadAudio : 1; bool m_hasEverHadVideo : 1; bool m_mediaControlsDependOnPageScaleFactor : 1; bool m_haveSetUpCaptionContainer : 1; bool m_isScrubbingRemotely : 1; bool m_waitingToEnterFullscreen : 1; bool m_changingVideoFullscreenMode : 1; bool m_showPoster : 1; bool m_tracksAreReady : 1; bool m_haveVisibleTextTrack : 1; bool m_processingPreferenceChange : 1; bool m_shouldAudioPlaybackRequireUserGesture : 1; bool m_shouldVideoPlaybackRequireUserGesture : 1; AutoplayEventPlaybackState m_autoplayEventPlaybackState { AutoplayEventPlaybackState::None }; String m_subtitleTrackLanguage; MediaTime m_lastTextTrackUpdateTime { -1, 1 }; std::optional m_captionDisplayMode; RefPtr m_audioTracks; RefPtr m_textTracks; RefPtr m_videoTracks; Vector> m_textTracksWhenResourceSelectionBegan; struct CueData; std::unique_ptr m_cueData; int m_ignoreTrackDisplayUpdate { 0 }; bool m_requireCaptionPreferencesChangedCallbacks { false }; #if ENABLE(WEB_AUDIO) // This is a weak reference, since m_audioSourceNode holds a reference to us. // The value is set just after the MediaElementAudioSourceNode is created. // The value is cleared in MediaElementAudioSourceNode::~MediaElementAudioSourceNode(). MediaElementAudioSourceNode* m_audioSourceNode { nullptr }; #endif String m_mediaGroup; friend class MediaController; RefPtr m_mediaController; std::unique_ptr m_sleepDisabler; WeakPtr m_lastMediaResourceLoaderForTesting; std::optional m_overrideDynamicRangeMode; friend class TrackDisplayUpdateScope; RefPtr m_blob; URL m_blobURLForReading; MediaProvider m_mediaProvider; #if ENABLE(LEGACY_ENCRYPTED_MEDIA) bool m_hasNeedkeyListener { false }; RefPtr m_webKitMediaKeys; #endif #if ENABLE(ENCRYPTED_MEDIA) RefPtr m_mediaKeys; bool m_attachingMediaKeys { false }; bool m_playbackBlockedWaitingForKey { false }; #endif #if ENABLE(WIRELESS_PLAYBACK_TARGET) Ref m_remote; #endif std::unique_ptr m_mediaSession; size_t m_reportedExtraMemoryCost { 0 }; #if !RELEASE_LOG_DISABLED RefPtr m_logger; const void* m_logIdentifier; #endif friend class MediaControlsHost; RefPtr m_mediaControlsHost; RefPtr m_isolatedWorld; #if ENABLE(MEDIA_STREAM) RefPtr m_mediaStreamSrcObject; bool m_settingMediaStreamSrcObject { false }; #endif #if ENABLE(WIRELESS_PLAYBACK_TARGET) MediaProducer::MediaStateFlags m_mediaState; MonotonicTime m_currentPlaybackTargetIsWirelessEventFiredTime; bool m_hasPlaybackTargetAvailabilityListeners { false }; bool m_failedToPlayToWirelessTarget { false }; #endif bool m_isPlayingToWirelessTarget { false }; bool m_playingOnSecondScreen { false }; bool m_removedBehaviorRestrictionsAfterFirstUserGesture { false }; String m_audioOutputPersistentDeviceId; #if ENABLE(MEDIA_STREAM) String m_audioOutputHashedDeviceId; #endif String m_id; }; String convertEnumerationToString(HTMLMediaElement::AutoplayEventPlaybackState); } // namespace WebCore namespace WTF { template<> struct LogArgument { static String toString(WebCore::HTMLMediaElement::AutoplayEventPlaybackState reason) { return convertEnumerationToString(reason); } }; } // namespace WTF SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::HTMLMediaElement) static bool isType(const WebCore::Element& element) { return element.isMediaElement(); } static bool isType(const WebCore::Node& node) { return is(node) && isType(downcast(node)); } SPECIALIZE_TYPE_TRAITS_END() #endif