blob: eb8d83046f3eb9b218a9328a0750f1a50aad18bc [file] [log] [blame]
/*
* Copyright (C) 2019-2020 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. AND ITS CONTRIBUTORS ``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 ITS 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.
*/
#include "config.h"
#include "RemoteMediaPlayerProxy.h"
#if ENABLE(GPU_PROCESS)
#include "DataReference.h"
#include "GPUConnectionToWebProcess.h"
#include "LayerHostingContext.h"
#include "Logging.h"
#include "MediaPlayerPrivateRemoteMessages.h"
#include "RemoteAudioSourceProviderProxy.h"
#include "RemoteAudioTrackProxy.h"
#include "RemoteLegacyCDMFactoryProxy.h"
#include "RemoteLegacyCDMSessionProxy.h"
#include "RemoteMediaPlayerManagerProxy.h"
#include "RemoteMediaPlayerProxyConfiguration.h"
#include "RemoteMediaResource.h"
#include "RemoteMediaResourceIdentifier.h"
#include "RemoteMediaResourceLoader.h"
#include "RemoteMediaResourceManager.h"
#include "RemoteTextTrackProxy.h"
#include "RemoteVideoTrackProxy.h"
#include "TextTrackPrivateRemoteConfiguration.h"
#include "TrackPrivateRemoteConfiguration.h"
#include "WebCoreArgumentCoders.h"
#include <JavaScriptCore/Uint8Array.h>
#include <WebCore/LayoutRect.h>
#include <WebCore/MediaPlayer.h>
#include <WebCore/MediaPlayerPrivate.h>
#include <WebCore/NotImplemented.h>
#include <WebCore/SecurityOrigin.h>
#if ENABLE(ENCRYPTED_MEDIA)
#include "RemoteCDMFactoryProxy.h"
#endif
#if ENABLE(WIRELESS_PLAYBACK_TARGET)
#include <WebCore/MediaPlaybackTargetCocoa.h>
#include <WebCore/MediaPlaybackTargetContext.h>
#include <WebCore/MediaPlaybackTargetMock.h>
#endif
#if PLATFORM(COCOA)
#include <WebCore/AudioSourceProviderAVFObjC.h>
#endif
namespace WebKit {
using namespace WebCore;
RemoteMediaPlayerProxy::RemoteMediaPlayerProxy(RemoteMediaPlayerManagerProxy& manager, MediaPlayerIdentifier identifier, Ref<IPC::Connection>&& connection, MediaPlayerEnums::MediaEngineIdentifier engineIdentifier, RemoteMediaPlayerProxyConfiguration&& configuration)
: m_id(identifier)
, m_webProcessConnection(WTFMove(connection))
, m_manager(manager)
, m_engineIdentifier(engineIdentifier)
, m_updateCachedStateMessageTimer(RunLoop::main(), this, &RemoteMediaPlayerProxy::timerFired)
, m_configuration(configuration)
, m_renderingResourcesRequest(ScopedRenderingResourcesRequest::acquire())
#if !RELEASE_LOG_DISABLED
, m_logger(manager.logger())
#endif
{
m_typesRequiringHardwareSupport = m_configuration.mediaContentTypesRequiringHardwareSupport;
m_renderingCanBeAccelerated = m_configuration.renderingCanBeAccelerated;
m_player = MediaPlayer::create(*this, m_engineIdentifier);
}
RemoteMediaPlayerProxy::~RemoteMediaPlayerProxy()
{
if (m_performTaskAtMediaTimeCompletionHandler)
m_performTaskAtMediaTimeCompletionHandler(std::nullopt, std::nullopt);
setShouldEnableAudioSourceProvider(false);
}
void RemoteMediaPlayerProxy::invalidate()
{
m_updateCachedStateMessageTimer.stop();
m_player->invalidate();
if (m_sandboxExtension) {
m_sandboxExtension->revoke();
m_sandboxExtension = nullptr;
}
m_renderingResourcesRequest = { };
#if USE(AVFOUNDATION)
m_pixelBufferForCurrentTime = nullptr;
#endif
}
void RemoteMediaPlayerProxy::getConfiguration(RemoteMediaPlayerConfiguration& configuration)
{
configuration.engineDescription = m_player->engineDescription();
auto maxDuration = m_player->maximumDurationToCacheMediaTime();
configuration.maximumDurationToCacheMediaTime = maxDuration ? maxDuration : 0.2;
configuration.supportsScanning = m_player->supportsScanning();
configuration.supportsFullscreen = m_player->supportsFullscreen();
configuration.supportsPictureInPicture = m_player->supportsPictureInPicture();
configuration.supportsAcceleratedRendering = m_player->supportsAcceleratedRendering();
configuration.supportsPlayAtHostTime = m_player->supportsPlayAtHostTime();
configuration.supportsPauseAtHostTime = m_player->supportsPauseAtHostTime();
#if ENABLE(WIRELESS_PLAYBACK_TARGET)
configuration.canPlayToWirelessPlaybackTarget = m_player->canPlayToWirelessPlaybackTarget();
#endif
configuration.shouldIgnoreIntrinsicSize = m_player->shouldIgnoreIntrinsicSize();
m_observingTimeChanges = m_player->setCurrentTimeDidChangeCallback([this, weakThis = WeakPtr { *this }] (auto currentTime) mutable {
if (!weakThis)
return;
currentTimeChanged(currentTime);
});
}
void RemoteMediaPlayerProxy::load(URL&& url, std::optional<SandboxExtension::Handle>&& sandboxExtensionHandle, const ContentType& contentType, const String& keySystem, CompletionHandler<void(RemoteMediaPlayerConfiguration&&)>&& completionHandler)
{
RemoteMediaPlayerConfiguration configuration;
if (sandboxExtensionHandle) {
m_sandboxExtension = SandboxExtension::create(WTFMove(sandboxExtensionHandle.value()));
if (m_sandboxExtension)
m_sandboxExtension->consume();
else
WTFLogAlways("Unable to create sandbox extension for media url.\n");
}
m_player->load(url, contentType, keySystem);
getConfiguration(configuration);
completionHandler(WTFMove(configuration));
}
#if ENABLE(MEDIA_SOURCE)
void RemoteMediaPlayerProxy::loadMediaSource(URL&& url, const WebCore::ContentType& contentType, bool webMParserEnabled, RemoteMediaSourceIdentifier mediaSourceIdentifier, CompletionHandler<void(RemoteMediaPlayerConfiguration&&)>&& completionHandler)
{
ASSERT(m_manager && m_manager->gpuConnectionToWebProcess());
RemoteMediaPlayerConfiguration configuration;
if (!m_manager || !m_manager->gpuConnectionToWebProcess()) {
completionHandler(WTFMove(configuration));
return;
}
m_mediaSourceProxy = adoptRef(*new RemoteMediaSourceProxy(*m_manager->gpuConnectionToWebProcess(), mediaSourceIdentifier, webMParserEnabled, *this));
m_player->load(url, contentType, m_mediaSourceProxy.get());
getConfiguration(configuration);
completionHandler(WTFMove(configuration));
}
#endif
void RemoteMediaPlayerProxy::cancelLoad()
{
m_updateCachedStateMessageTimer.stop();
m_player->cancelLoad();
}
void RemoteMediaPlayerProxy::prepareToPlay()
{
ALWAYS_LOG(LOGIDENTIFIER);
m_player->prepareToPlay();
}
void RemoteMediaPlayerProxy::play()
{
if (m_player->movieLoadType() != WebCore::MediaPlayerEnums::MovieLoadType::LiveStream)
startUpdateCachedStateMessageTimer();
m_player->play();
sendCachedState();
}
void RemoteMediaPlayerProxy::pause()
{
m_updateCachedStateMessageTimer.stop();
updateCachedVideoMetrics();
m_player->pause();
sendCachedState();
}
void RemoteMediaPlayerProxy::seek(const MediaTime& time)
{
m_player->seek(time);
}
void RemoteMediaPlayerProxy::seekWithTolerance(const MediaTime& time, const MediaTime& negativeTolerance, const MediaTime& positiveTolerance)
{
m_player->seekWithTolerance(time, negativeTolerance, positiveTolerance);
}
void RemoteMediaPlayerProxy::setVolume(double volume)
{
m_player->setVolume(volume);
}
void RemoteMediaPlayerProxy::setMuted(bool muted)
{
m_player->setMuted(muted);
}
void RemoteMediaPlayerProxy::setPreload(WebCore::MediaPlayerEnums::Preload preload)
{
m_player->setPreload(preload);
}
void RemoteMediaPlayerProxy::setPrivateBrowsingMode(bool privateMode)
{
m_player->setPrivateBrowsingMode(privateMode);
}
void RemoteMediaPlayerProxy::setPreservesPitch(bool preservesPitch)
{
m_player->setPreservesPitch(preservesPitch);
}
void RemoteMediaPlayerProxy::setPitchCorrectionAlgorithm(WebCore::MediaPlayer::PitchCorrectionAlgorithm algorithm)
{
m_player->setPitchCorrectionAlgorithm(algorithm);
}
void RemoteMediaPlayerProxy::prepareForRendering()
{
ALWAYS_LOG(LOGIDENTIFIER);
m_player->prepareForRendering();
}
void RemoteMediaPlayerProxy::setPageIsVisible(bool visible)
{
ALWAYS_LOG(LOGIDENTIFIER, visible);
m_player->setPageIsVisible(visible);
}
void RemoteMediaPlayerProxy::setShouldMaintainAspectRatio(bool maintainRatio)
{
m_player->setShouldMaintainAspectRatio(maintainRatio);
}
#if ENABLE(VIDEO_PRESENTATION_MODE)
void RemoteMediaPlayerProxy::setVideoFullscreenGravity(WebCore::MediaPlayerEnums::VideoGravity gravity)
{
m_player->setVideoFullscreenGravity(gravity);
}
#endif
void RemoteMediaPlayerProxy::acceleratedRenderingStateChanged(bool renderingCanBeAccelerated)
{
ALWAYS_LOG(LOGIDENTIFIER, renderingCanBeAccelerated);
m_renderingCanBeAccelerated = renderingCanBeAccelerated;
m_player->acceleratedRenderingStateChanged();
}
void RemoteMediaPlayerProxy::setShouldDisableSleep(bool disable)
{
m_player->setShouldDisableSleep(disable);
}
void RemoteMediaPlayerProxy::setRate(double rate)
{
m_player->setRate(rate);
}
void RemoteMediaPlayerProxy::didLoadingProgress(CompletionHandler<void(bool)>&& completionHandler)
{
m_player->didLoadingProgress(WTFMove(completionHandler));
}
RefPtr<PlatformMediaResource> RemoteMediaPlayerProxy::requestResource(ResourceRequest&& request, PlatformMediaResourceLoader::LoadOptions options)
{
ASSERT(m_manager && m_manager->gpuConnectionToWebProcess());
if (!m_manager || !m_manager->gpuConnectionToWebProcess())
return nullptr;
auto& remoteMediaResourceManager = m_manager->gpuConnectionToWebProcess()->remoteMediaResourceManager();
auto remoteMediaResourceIdentifier = RemoteMediaResourceIdentifier::generate();
auto remoteMediaResource = RemoteMediaResource::create(remoteMediaResourceManager, *this, remoteMediaResourceIdentifier);
remoteMediaResourceManager.addMediaResource(remoteMediaResourceIdentifier, remoteMediaResource);
m_webProcessConnection->sendWithAsyncReply(Messages::MediaPlayerPrivateRemote::RequestResource(remoteMediaResourceIdentifier, request, options), [remoteMediaResource]() {
remoteMediaResource->setReady(true);
}, m_id);
return remoteMediaResource;
}
void RemoteMediaPlayerProxy::sendH2Ping(const URL& url, CompletionHandler<void(Expected<WTF::Seconds, WebCore::ResourceError>&&)>&& completionHandler)
{
m_webProcessConnection->sendWithAsyncReply(Messages::MediaPlayerPrivateRemote::SendH2Ping(url), WTFMove(completionHandler), m_id);
}
void RemoteMediaPlayerProxy::removeResource(RemoteMediaResourceIdentifier remoteMediaResourceIdentifier)
{
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::RemoveResource(remoteMediaResourceIdentifier), m_id);
}
// MediaPlayerClient
#if ENABLE(VIDEO_PRESENTATION_MODE)
void RemoteMediaPlayerProxy::updateVideoFullscreenInlineImage()
{
m_player->updateVideoFullscreenInlineImage();
}
void RemoteMediaPlayerProxy::setVideoFullscreenMode(MediaPlayer::VideoFullscreenMode mode)
{
m_player->setVideoFullscreenMode(mode);
}
void RemoteMediaPlayerProxy::videoFullscreenStandbyChanged()
{
m_player->videoFullscreenStandbyChanged();
}
#endif
void RemoteMediaPlayerProxy::setBufferingPolicy(MediaPlayer::BufferingPolicy policy)
{
m_player->setBufferingPolicy(policy);
}
#if PLATFORM(IOS_FAMILY)
void RemoteMediaPlayerProxy::accessLog(CompletionHandler<void(String)>&& completionHandler)
{
completionHandler(m_player->accessLog());
}
void RemoteMediaPlayerProxy::errorLog(CompletionHandler<void(String)>&& completionHandler)
{
completionHandler(m_player->errorLog());
}
#endif
void RemoteMediaPlayerProxy::mediaPlayerNetworkStateChanged()
{
updateCachedState(true);
m_cachedState.readyState = m_player->readyState();
m_cachedState.networkState = m_player->networkState();
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::NetworkStateChanged(m_cachedState), m_id);
}
void RemoteMediaPlayerProxy::mediaPlayerReadyStateChanged()
{
auto newReadyState = m_player->readyState();
ALWAYS_LOG(LOGIDENTIFIER, newReadyState);
updateCachedVideoMetrics();
updateCachedState(true);
m_cachedState.readyState = newReadyState;
m_cachedState.networkState = m_player->networkState();
m_cachedState.duration = m_player->duration();
m_cachedState.movieLoadType = m_player->movieLoadType();
m_cachedState.minTimeSeekable = m_player->minTimeSeekable();
m_cachedState.maxTimeSeekable = m_player->maxTimeSeekable();
m_cachedState.startDate = m_player->getStartDate();
m_cachedState.startTime = m_player->startTime();
m_cachedState.naturalSize = m_player->naturalSize();
m_cachedState.maxFastForwardRate = m_player->maxFastForwardRate();
m_cachedState.minFastReverseRate = m_player->minFastReverseRate();
m_cachedState.seekableTimeRangesLastModifiedTime = m_player->seekableTimeRangesLastModifiedTime();
m_cachedState.liveUpdateInterval = m_player->liveUpdateInterval();
m_cachedState.hasAvailableVideoFrame = m_player->hasAvailableVideoFrame();
#if ENABLE(WIRELESS_PLAYBACK_TARGET)
m_cachedState.wirelessVideoPlaybackDisabled = m_player->wirelessVideoPlaybackDisabled();
#endif
m_cachedState.canSaveMediaData = m_player->canSaveMediaData();
m_cachedState.hasSingleSecurityOrigin = m_player->hasSingleSecurityOrigin();
m_cachedState.didPassCORSAccessCheck = m_player->didPassCORSAccessCheck();
m_cachedState.wouldTaintDocumentSecurityOrigin = m_player->wouldTaintOrigin(m_configuration.documentSecurityOrigin.securityOrigin());
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::ReadyStateChanged(m_cachedState), m_id);
}
void RemoteMediaPlayerProxy::mediaPlayerVolumeChanged()
{
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::VolumeChanged(m_player->volume()), m_id);
}
void RemoteMediaPlayerProxy::mediaPlayerMuteChanged()
{
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::MuteChanged(m_player->muted()), m_id);
}
void RemoteMediaPlayerProxy::mediaPlayerTimeChanged()
{
updateCachedState(true);
m_cachedState.duration = m_player->duration();
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::TimeChanged(m_cachedState), m_id);
}
void RemoteMediaPlayerProxy::mediaPlayerDurationChanged()
{
updateCachedState(true);
m_cachedState.duration = m_player->duration();
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::DurationChanged(m_cachedState), m_id);
}
void RemoteMediaPlayerProxy::mediaPlayerRateChanged()
{
updateCachedVideoMetrics();
sendCachedState();
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::RateChanged(m_player->effectiveRate()), m_id);
}
void RemoteMediaPlayerProxy::mediaPlayerEngineFailedToLoad() const
{
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::EngineFailedToLoad(m_player->platformErrorCode()), m_id);
}
#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
String RemoteMediaPlayerProxy::mediaPlayerMediaKeysStorageDirectory() const
{
ASSERT(m_manager && m_manager->gpuConnectionToWebProcess());
if (!m_manager || !m_manager->gpuConnectionToWebProcess())
return emptyString();
return m_manager->gpuConnectionToWebProcess()->mediaKeysStorageDirectory();
}
#endif
String RemoteMediaPlayerProxy::mediaPlayerReferrer() const
{
return m_configuration.referrer;
}
String RemoteMediaPlayerProxy::mediaPlayerUserAgent() const
{
return m_configuration.userAgent;
}
String RemoteMediaPlayerProxy::mediaPlayerSourceApplicationIdentifier() const
{
return m_configuration.sourceApplicationIdentifier;
}
#if PLATFORM(IOS_FAMILY)
String RemoteMediaPlayerProxy::mediaPlayerNetworkInterfaceName() const
{
return m_configuration.networkInterfaceName;
}
void RemoteMediaPlayerProxy::mediaPlayerGetRawCookies(const URL& url, WebCore::MediaPlayerClient::GetRawCookiesCallback&& completionHandler) const
{
m_webProcessConnection->sendWithAsyncReply(Messages::MediaPlayerPrivateRemote::GetRawCookies(url), WTFMove(completionHandler), m_id);
}
#endif
const String& RemoteMediaPlayerProxy::mediaPlayerMediaCacheDirectory() const
{
ASSERT(m_manager && m_manager->gpuConnectionToWebProcess());
if (!m_manager || !m_manager->gpuConnectionToWebProcess())
return emptyString();
return m_manager->gpuConnectionToWebProcess()->mediaCacheDirectory();
}
const Vector<WebCore::ContentType>& RemoteMediaPlayerProxy::mediaContentTypesRequiringHardwareSupport() const
{
return m_typesRequiringHardwareSupport;
}
Vector<String> RemoteMediaPlayerProxy::mediaPlayerPreferredAudioCharacteristics() const
{
return m_configuration.preferredAudioCharacteristics;
}
bool RemoteMediaPlayerProxy::mediaPlayerShouldUsePersistentCache() const
{
return m_configuration.shouldUsePersistentCache;
}
bool RemoteMediaPlayerProxy::mediaPlayerIsVideo() const
{
return m_configuration.isVideo;
}
void RemoteMediaPlayerProxy::mediaPlayerPlaybackStateChanged()
{
m_cachedState.paused = m_player->paused();
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::PlaybackStateChanged(m_cachedState.paused, m_player->currentTime(), MonotonicTime::now()), m_id);
}
void RemoteMediaPlayerProxy::mediaPlayerBufferedTimeRangesChanged()
{
m_bufferedChanged = true;
}
void RemoteMediaPlayerProxy::mediaPlayerSeekableTimeRangesChanged()
{
m_cachedState.minTimeSeekable = m_player->minTimeSeekable();
m_cachedState.maxTimeSeekable = m_player->maxTimeSeekable();
m_cachedState.seekableTimeRangesLastModifiedTime = m_player->seekableTimeRangesLastModifiedTime();
m_cachedState.liveUpdateInterval = m_player->liveUpdateInterval();
if (!m_updateCachedStateMessageTimer.isActive())
sendCachedState();
}
void RemoteMediaPlayerProxy::mediaPlayerCharacteristicChanged()
{
updateCachedVideoMetrics();
updateCachedState();
m_cachedState.hasAudio = m_player->hasAudio();
m_cachedState.hasVideo = m_player->hasVideo();
m_cachedState.hasClosedCaptions = m_player->hasClosedCaptions();
m_cachedState.languageOfPrimaryAudioTrack = m_player->languageOfPrimaryAudioTrack();
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::CharacteristicChanged(m_cachedState), m_id);
}
bool RemoteMediaPlayerProxy::mediaPlayerRenderingCanBeAccelerated()
{
return m_renderingCanBeAccelerated;
}
#if !PLATFORM(COCOA)
void RemoteMediaPlayerProxy::mediaPlayerRenderingModeChanged()
{
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::RenderingModeChanged(), m_id);
}
#endif
TrackPrivateRemoteIdentifier RemoteMediaPlayerProxy::addRemoteAudioTrackProxy(WebCore::AudioTrackPrivate& track)
{
#if !RELEASE_LOG_DISABLED
track.setLogger(mediaPlayerLogger(), mediaPlayerLogIdentifier());
#endif
ASSERT(m_manager && m_manager->gpuConnectionToWebProcess());
if (!m_manager || !m_manager->gpuConnectionToWebProcess())
return { };
auto identifier = TrackPrivateRemoteIdentifier::generate();
m_audioTracks.set(&track, RemoteAudioTrackProxy::create(*m_manager->gpuConnectionToWebProcess(), identifier, track, m_id));
return identifier;
}
void RemoteMediaPlayerProxy::audioTrackSetEnabled(const TrackPrivateRemoteIdentifier& identifier, bool enabled)
{
for (auto& track : m_audioTracks.values()) {
if (track->identifier() == identifier) {
track->setEnabled(enabled);
return;
}
}
}
TrackPrivateRemoteIdentifier RemoteMediaPlayerProxy::addRemoteVideoTrackProxy(WebCore::VideoTrackPrivate& track)
{
#if !RELEASE_LOG_DISABLED
track.setLogger(mediaPlayerLogger(), mediaPlayerLogIdentifier());
#endif
ASSERT(m_manager);
ASSERT(m_manager->gpuConnectionToWebProcess());
if (!m_manager || !m_manager->gpuConnectionToWebProcess())
return { };
auto identifier = TrackPrivateRemoteIdentifier::generate();
m_videoTracks.set(&track, RemoteVideoTrackProxy::create(*m_manager->gpuConnectionToWebProcess(), identifier, track, m_id));
return identifier;
}
void RemoteMediaPlayerProxy::videoTrackSetSelected(const TrackPrivateRemoteIdentifier& identifier, bool selected)
{
for (auto& track : m_videoTracks.values()) {
if (track->identifier() == identifier) {
track->setSelected(selected);
return;
}
}
}
TrackPrivateRemoteIdentifier RemoteMediaPlayerProxy::addRemoteTextTrackProxy(WebCore::InbandTextTrackPrivate& track)
{
#if !RELEASE_LOG_DISABLED
track.setLogger(mediaPlayerLogger(), mediaPlayerLogIdentifier());
#endif
ASSERT(m_manager && m_manager->gpuConnectionToWebProcess());
if (!m_manager || !m_manager->gpuConnectionToWebProcess())
return { };
auto identifier = TrackPrivateRemoteIdentifier::generate();
m_textTracks.set(&track, RemoteTextTrackProxy::create(*m_manager->gpuConnectionToWebProcess(), identifier, track, m_id));
return identifier;
}
void RemoteMediaPlayerProxy::textTrackSetMode(const TrackPrivateRemoteIdentifier& identifier, WebCore::InbandTextTrackPrivate::Mode mode)
{
for (auto& track : m_textTracks.values()) {
if (track->identifier() == identifier) {
track->setMode(mode);
return;
}
}
}
void RemoteMediaPlayerProxy::mediaPlayerDidAddAudioTrack(WebCore::AudioTrackPrivate& track)
{
addRemoteAudioTrackProxy(track);
}
void RemoteMediaPlayerProxy::mediaPlayerDidRemoveAudioTrack(WebCore::AudioTrackPrivate& track)
{
ASSERT(m_audioTracks.contains(&track));
if (!m_audioTracks.contains(&track))
return;
auto audioTrack = m_audioTracks.get(&track);
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::RemoveRemoteAudioTrack(audioTrack->identifier()), m_id);
m_audioTracks.remove(&track);
}
void RemoteMediaPlayerProxy::mediaPlayerDidAddVideoTrack(WebCore::VideoTrackPrivate& track)
{
addRemoteVideoTrackProxy(track);
}
void RemoteMediaPlayerProxy::mediaPlayerDidRemoveVideoTrack(WebCore::VideoTrackPrivate& track)
{
ASSERT(m_videoTracks.contains(&track));
if (!m_videoTracks.contains(&track))
return;
auto videoTrack = m_videoTracks.get(&track);
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::RemoveRemoteVideoTrack(videoTrack->identifier()), m_id);
m_videoTracks.remove(&track);
}
void RemoteMediaPlayerProxy::mediaPlayerDidAddTextTrack(WebCore::InbandTextTrackPrivate& track)
{
addRemoteTextTrackProxy(track);
}
void RemoteMediaPlayerProxy::mediaPlayerDidRemoveTextTrack(WebCore::InbandTextTrackPrivate& track)
{
ASSERT(m_textTracks.contains(&track));
if (!m_textTracks.contains(&track))
return;
auto textTrack = m_textTracks.get(&track);
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::RemoveRemoteTextTrack(textTrack->identifier()), m_id);
m_textTracks.remove(&track);
}
void RemoteMediaPlayerProxy::textTrackRepresentationBoundsChanged(const IntRect&)
{
notImplemented();
}
void RemoteMediaPlayerProxy::mediaPlayerResourceNotSupported()
{
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::ResourceNotSupported(), m_id);
}
void RemoteMediaPlayerProxy::mediaPlayerSizeChanged()
{
m_cachedState.naturalSize = m_player->naturalSize();
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::SizeChanged(m_cachedState.naturalSize), m_id);
}
void RemoteMediaPlayerProxy::mediaPlayerActiveSourceBuffersChanged()
{
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::ActiveSourceBuffersChanged(), m_id);
}
#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
RefPtr<ArrayBuffer> RemoteMediaPlayerProxy::mediaPlayerCachedKeyForKeyId(const String& keyId) const
{
ASSERT(m_manager && m_manager->gpuConnectionToWebProcess());
if (!m_manager || !m_manager->gpuConnectionToWebProcess())
return nullptr;
if (!m_legacySession)
return nullptr;
if (auto cdmSession = m_manager->gpuConnectionToWebProcess()->legacyCdmFactoryProxy().getSession(*m_legacySession))
return cdmSession->getCachedKeyForKeyId(keyId);
return nullptr;
}
void RemoteMediaPlayerProxy::mediaPlayerKeyNeeded(Uint8Array* message)
{
IPC::DataReference messageReference;
if (message)
messageReference = { message->data(), message->byteLength() };
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::MediaPlayerKeyNeeded(WTFMove(messageReference)), m_id);
}
#endif
#if ENABLE(ENCRYPTED_MEDIA)
void RemoteMediaPlayerProxy::mediaPlayerInitializationDataEncountered(const String& initDataType, RefPtr<ArrayBuffer>&& initData)
{
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::InitializationDataEncountered(initDataType, IPC::DataReference(static_cast<uint8_t*>(initData->data()), initData->byteLength())), m_id);
}
void RemoteMediaPlayerProxy::mediaPlayerWaitingForKeyChanged()
{
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::WaitingForKeyChanged(m_player->waitingForKey()), m_id);
}
#endif
#if ENABLE(WIRELESS_PLAYBACK_TARGET)
void RemoteMediaPlayerProxy::mediaPlayerCurrentPlaybackTargetIsWirelessChanged(bool isCurrentPlaybackTargetWireless)
{
m_cachedState.wirelessPlaybackTargetName = m_player->wirelessPlaybackTargetName();
m_cachedState.wirelessPlaybackTargetType = m_player->wirelessPlaybackTargetType();
sendCachedState();
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::CurrentPlaybackTargetIsWirelessChanged(isCurrentPlaybackTargetWireless), m_id);
}
void RemoteMediaPlayerProxy::setWirelessVideoPlaybackDisabled(bool disabled)
{
m_player->setWirelessVideoPlaybackDisabled(disabled);
m_cachedState.wirelessVideoPlaybackDisabled = m_player->wirelessVideoPlaybackDisabled();
}
void RemoteMediaPlayerProxy::setShouldPlayToPlaybackTarget(bool shouldPlay)
{
m_player->setShouldPlayToPlaybackTarget(shouldPlay);
}
void RemoteMediaPlayerProxy::setWirelessPlaybackTarget(MediaPlaybackTargetContext&& targetContext)
{
switch (targetContext.type()) {
case MediaPlaybackTargetContext::Type::SerializedAVOutputContext: {
if (targetContext.deserializeOutputContext())
m_player->setWirelessPlaybackTarget(MediaPlaybackTargetCocoa::create(WTFMove(targetContext)));
break;
}
case MediaPlaybackTargetContext::Type::Mock:
#if PLATFORM(MAC)
m_player->setWirelessPlaybackTarget(MediaPlaybackTargetMock::create(targetContext.deviceName(), targetContext.mockState()));
break;
#endif
case MediaPlaybackTargetContext::Type::AVOutputContext:
case MediaPlaybackTargetContext::Type::None:
ASSERT_NOT_REACHED();
break;
}
}
#endif
bool RemoteMediaPlayerProxy::mediaPlayerIsFullscreen() const
{
return false;
}
bool RemoteMediaPlayerProxy::mediaPlayerIsFullscreenPermitted() const
{
notImplemented();
return false;
}
float RemoteMediaPlayerProxy::mediaPlayerContentsScale() const
{
return m_videoContentScale;
}
bool RemoteMediaPlayerProxy::mediaPlayerPlatformVolumeConfigurationRequired() const
{
notImplemented();
return false;
}
CachedResourceLoader* RemoteMediaPlayerProxy::mediaPlayerCachedResourceLoader()
{
notImplemented();
return nullptr;
}
RefPtr<PlatformMediaResourceLoader> RemoteMediaPlayerProxy::mediaPlayerCreateResourceLoader()
{
return adoptRef(*new RemoteMediaResourceLoader(*this));
}
bool RemoteMediaPlayerProxy::doesHaveAttribute(const AtomString&, AtomString*) const
{
notImplemented();
return false;
}
#if ENABLE(AVF_CAPTIONS)
Vector<RefPtr<PlatformTextTrack>> RemoteMediaPlayerProxy::outOfBandTrackSources()
{
Vector<RefPtr<PlatformTextTrack>> sources;
for (auto& data : m_configuration.outOfBandTrackData)
sources.append(PlatformTextTrack::create(WTFMove(data)));
return sources;
}
#endif
double RemoteMediaPlayerProxy::mediaPlayerRequestedPlaybackRate() const
{
notImplemented();
return 0;
}
#if ENABLE(VIDEO_PRESENTATION_MODE)
MediaPlayerEnums::VideoFullscreenMode RemoteMediaPlayerProxy::mediaPlayerFullscreenMode() const
{
notImplemented();
return MediaPlayerEnums::VideoFullscreenModeNone;
}
bool RemoteMediaPlayerProxy::mediaPlayerIsVideoFullscreenStandby() const
{
notImplemented();
return false;
}
#endif
bool RemoteMediaPlayerProxy::mediaPlayerShouldDisableSleep() const
{
notImplemented();
return false;
}
bool RemoteMediaPlayerProxy::mediaPlayerShouldCheckHardwareSupport() const
{
notImplemented();
return false;
}
void RemoteMediaPlayerProxy::startUpdateCachedStateMessageTimer()
{
static const Seconds lessFrequentTimeupdateEventFrequency { 2000_ms };
static const Seconds moreFrequentTimeupdateEventFrequency { 250_ms };
if (m_updateCachedStateMessageTimer.isActive())
return;
auto frequency = m_observingTimeChanges ? lessFrequentTimeupdateEventFrequency : moreFrequentTimeupdateEventFrequency;
m_updateCachedStateMessageTimer.startRepeating(frequency);
}
void RemoteMediaPlayerProxy::timerFired()
{
sendCachedState();
}
bool RemoteMediaPlayerProxy::mediaPlayerPausedOrStalled() const
{
return m_player->paused() || m_player->readyState() < MediaPlayer::ReadyState::HaveFutureData;
}
void RemoteMediaPlayerProxy::currentTimeChanged(const MediaTime& mediaTime)
{
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::CurrentTimeChanged(mediaTime, MonotonicTime::now(), !mediaPlayerPausedOrStalled()), m_id);
}
void RemoteMediaPlayerProxy::updateCachedState(bool forceCurrentTimeUpdate)
{
if (!m_observingTimeChanges || forceCurrentTimeUpdate)
currentTimeChanged(m_player->currentTime());
m_cachedState.paused = m_player->paused();
maybeUpdateCachedVideoMetrics();
if (m_bufferedChanged) {
m_bufferedChanged = false;
if (m_engineIdentifier != MediaPlayerEnums::MediaEngineIdentifier::AVFoundationMSE)
m_cachedState.bufferedRanges = *m_player->buffered();
}
}
void RemoteMediaPlayerProxy::sendCachedState()
{
updateCachedState();
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::UpdateCachedState(m_cachedState), m_id);
m_cachedState.bufferedRanges.clear();
}
#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
void RemoteMediaPlayerProxy::setLegacyCDMSession(std::optional<RemoteLegacyCDMSessionIdentifier>&& instanceId)
{
ASSERT(m_manager && m_manager->gpuConnectionToWebProcess());
if (!m_manager || !m_manager->gpuConnectionToWebProcess())
return;
if (m_legacySession == instanceId)
return;
if (m_legacySession) {
if (auto cdmSession = m_manager->gpuConnectionToWebProcess()->legacyCdmFactoryProxy().getSession(*m_legacySession)) {
m_player->setCDMSession(nullptr);
cdmSession->setPlayer(nullptr);
}
}
m_legacySession = instanceId;
if (m_legacySession) {
if (auto cdmSession = m_manager->gpuConnectionToWebProcess()->legacyCdmFactoryProxy().getSession(*m_legacySession)) {
m_player->setCDMSession(cdmSession->session());
cdmSession->setPlayer(*this);
}
}
}
void RemoteMediaPlayerProxy::keyAdded()
{
m_player->keyAdded();
}
#endif
#if ENABLE(ENCRYPTED_MEDIA)
void RemoteMediaPlayerProxy::cdmInstanceAttached(RemoteCDMInstanceIdentifier&& instanceId)
{
ASSERT(m_manager && m_manager->gpuConnectionToWebProcess());
if (!m_manager || !m_manager->gpuConnectionToWebProcess())
return;
if (auto* instanceProxy = m_manager->gpuConnectionToWebProcess()->cdmFactoryProxy().getInstance(instanceId))
m_player->cdmInstanceAttached(instanceProxy->instance());
}
void RemoteMediaPlayerProxy::cdmInstanceDetached(RemoteCDMInstanceIdentifier&& instanceId)
{
ASSERT(m_manager && m_manager->gpuConnectionToWebProcess());
if (!m_manager || !m_manager->gpuConnectionToWebProcess())
return;
if (auto* instanceProxy = m_manager->gpuConnectionToWebProcess()->cdmFactoryProxy().getInstance(instanceId))
m_player->cdmInstanceDetached(instanceProxy->instance());
}
void RemoteMediaPlayerProxy::attemptToDecryptWithInstance(RemoteCDMInstanceIdentifier&& instanceId)
{
ASSERT(m_manager && m_manager->gpuConnectionToWebProcess());
if (!m_manager || !m_manager->gpuConnectionToWebProcess())
return;
if (auto* instanceProxy = m_manager->gpuConnectionToWebProcess()->cdmFactoryProxy().getInstance(instanceId))
m_player->attemptToDecryptWithInstance(instanceProxy->instance());
}
#endif
#if ENABLE(LEGACY_ENCRYPTED_MEDIA) && ENABLE(ENCRYPTED_MEDIA)
void RemoteMediaPlayerProxy::setShouldContinueAfterKeyNeeded(bool should)
{
m_player->setShouldContinueAfterKeyNeeded(should);
}
#endif
void RemoteMediaPlayerProxy::beginSimulatedHDCPError()
{
m_player->beginSimulatedHDCPError();
}
void RemoteMediaPlayerProxy::endSimulatedHDCPError()
{
m_player->endSimulatedHDCPError();
}
void RemoteMediaPlayerProxy::notifyActiveSourceBuffersChanged()
{
m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::ActiveSourceBuffersChanged(), m_id);
}
void RemoteMediaPlayerProxy::applicationWillResignActive()
{
m_player->applicationWillResignActive();
}
void RemoteMediaPlayerProxy::applicationDidBecomeActive()
{
m_player->applicationDidBecomeActive();
}
void RemoteMediaPlayerProxy::notifyTrackModeChanged()
{
#if ENABLE(AVF_CAPTIONS)
m_player->notifyTrackModeChanged();
#endif
}
void RemoteMediaPlayerProxy::tracksChanged()
{
m_player->tracksChanged();
}
void RemoteMediaPlayerProxy::performTaskAtMediaTime(const MediaTime& taskTime, MonotonicTime messageTime, PerformTaskAtMediaTimeCompletionHandler&& completionHandler)
{
if (m_performTaskAtMediaTimeCompletionHandler) {
// A media player is only expected to track one pending task-at-time at once (e.g. see
// MediaPlayerPrivateAVFoundationObjC::performTaskAtMediaTime), so cancel the existing
// CompletionHandler.
auto handler = WTFMove(m_performTaskAtMediaTimeCompletionHandler);
handler(std::nullopt, std::nullopt);
}
auto now = MonotonicTime::now();
auto transmissionTime = MediaTime::createWithDouble((now - messageTime).value(), 1);
auto adjustedTaskTime = taskTime - transmissionTime;
auto currentTime = m_player->currentTime();
if (adjustedTaskTime <= currentTime) {
completionHandler(currentTime, now);
return;
}
m_performTaskAtMediaTimeCompletionHandler = WTFMove(completionHandler);
m_player->performTaskAtMediaTime([this, weakThis = WeakPtr { *this }]() mutable {
if (!weakThis || !m_performTaskAtMediaTimeCompletionHandler)
return;
auto completionHandler = WTFMove(m_performTaskAtMediaTimeCompletionHandler);
completionHandler(m_player->currentTime(), MonotonicTime::now());
}, adjustedTaskTime);
}
void RemoteMediaPlayerProxy::wouldTaintOrigin(struct WebCore::SecurityOriginData originData, CompletionHandler<void(std::optional<bool>)>&& completionHandler)
{
completionHandler(m_player->wouldTaintOrigin(originData.securityOrigin()));
}
void RemoteMediaPlayerProxy::setVideoPlaybackMetricsUpdateInterval(double interval)
{
static const Seconds metricsAdvanceUpdate = 0.25_s;
ALWAYS_LOG(LOGIDENTIFIER, interval);
updateCachedVideoMetrics();
m_videoPlaybackMetricsUpdateInterval = Seconds(interval);
m_nextPlaybackQualityMetricsUpdateTime = MonotonicTime::now() + Seconds(interval) - metricsAdvanceUpdate;
}
void RemoteMediaPlayerProxy::maybeUpdateCachedVideoMetrics()
{
if (m_cachedState.paused || !m_videoPlaybackMetricsUpdateInterval || MonotonicTime::now() < m_nextPlaybackQualityMetricsUpdateTime)
return;
updateCachedVideoMetrics();
}
void RemoteMediaPlayerProxy::updateCachedVideoMetrics()
{
ALWAYS_LOG(LOGIDENTIFIER);
m_nextPlaybackQualityMetricsUpdateTime = MonotonicTime::now() + m_videoPlaybackMetricsUpdateInterval;
m_cachedState.videoMetrics = m_player->videoPlaybackQualityMetrics();
}
void RemoteMediaPlayerProxy::setPreferredDynamicRangeMode(DynamicRangeMode mode)
{
if (m_player)
m_player->setPreferredDynamicRangeMode(mode);
}
void RemoteMediaPlayerProxy::createAudioSourceProvider()
{
#if ENABLE(WEB_AUDIO) && PLATFORM(COCOA)
if (!m_player)
return;
auto* provider = m_player->audioSourceProvider();
if (!provider || !is<AudioSourceProviderAVFObjC>(provider))
return;
m_remoteAudioSourceProvider = RemoteAudioSourceProviderProxy::create(m_id, m_webProcessConnection.copyRef(), downcast<AudioSourceProviderAVFObjC>(*provider));
#endif
}
void RemoteMediaPlayerProxy::setShouldEnableAudioSourceProvider(bool shouldEnable)
{
#if ENABLE(WEB_AUDIO) && PLATFORM(COCOA)
if (auto* provider = m_player->audioSourceProvider())
provider->setClient(shouldEnable ? m_remoteAudioSourceProvider.get() : nullptr);
#endif
}
void RemoteMediaPlayerProxy::playAtHostTime(MonotonicTime time)
{
if (m_player)
m_player->playAtHostTime(time);
}
void RemoteMediaPlayerProxy::pauseAtHostTime(MonotonicTime time)
{
if (m_player)
m_player->pauseAtHostTime(time);
}
#if !RELEASE_LOG_DISABLED
WTFLogChannel& RemoteMediaPlayerProxy::logChannel() const
{
return JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, Media);
}
#endif
} // namespace WebKit
#endif // ENABLE(GPU_PROCESS)