2 * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
27 #import "PlaybackSessionInterfaceMac.h"
29 #if PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)
32 #import "MediaSelectionOption.h"
33 #import "PlaybackSessionModel.h"
34 #import "TimeRanges.h"
35 #import "WebPlaybackControlsManager.h"
36 #import <AVFoundation/AVTime.h>
37 #import <pal/avfoundation/MediaTimeAVFoundation.h>
38 #import <pal/spi/cocoa/AVKitSPI.h>
40 #import <pal/cf/CoreMediaSoftLink.h>
42 SOFTLINK_AVKIT_FRAMEWORK()
43 SOFT_LINK_CLASS_OPTIONAL(AVKit, AVValueTiming)
47 Ref<PlaybackSessionInterfaceMac> PlaybackSessionInterfaceMac::create(PlaybackSessionModel& model)
49 auto interface = adoptRef(*new PlaybackSessionInterfaceMac(model));
50 model.addClient(interface);
54 PlaybackSessionInterfaceMac::PlaybackSessionInterfaceMac(PlaybackSessionModel& model)
55 : m_playbackSessionModel(&model)
59 PlaybackSessionInterfaceMac::~PlaybackSessionInterfaceMac()
64 PlaybackSessionModel* PlaybackSessionInterfaceMac::playbackSessionModel() const
66 return m_playbackSessionModel;
69 void PlaybackSessionInterfaceMac::resetMediaState()
73 void PlaybackSessionInterfaceMac::durationChanged(double duration)
75 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
76 WebPlaybackControlsManager* controlsManager = playBackControlsManager();
78 controlsManager.contentDuration = duration;
80 // FIXME: We take this as an indication that playback is ready, but that is not necessarily true.
81 controlsManager.hasEnabledAudio = YES;
82 controlsManager.hasEnabledVideo = YES;
84 UNUSED_PARAM(duration);
88 void PlaybackSessionInterfaceMac::currentTimeChanged(double currentTime, double anchorTime)
90 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
91 WebPlaybackControlsManager* controlsManager = playBackControlsManager();
92 updatePlaybackControlsManagerTiming(currentTime, anchorTime, controlsManager.rate, controlsManager.playing);
94 UNUSED_PARAM(currentTime);
95 UNUSED_PARAM(anchorTime);
99 void PlaybackSessionInterfaceMac::rateChanged(bool isPlaying, float playbackRate)
101 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
102 WebPlaybackControlsManager* controlsManager = playBackControlsManager();
103 [controlsManager setRate:isPlaying ? playbackRate : 0.];
104 [controlsManager setPlaying:isPlaying];
105 updatePlaybackControlsManagerTiming(m_playbackSessionModel ? m_playbackSessionModel->currentTime() : 0, [[NSProcessInfo processInfo] systemUptime], playbackRate, isPlaying);
107 UNUSED_PARAM(isPlaying);
108 UNUSED_PARAM(playbackRate);
112 void PlaybackSessionInterfaceMac::beginScrubbing()
114 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
115 updatePlaybackControlsManagerTiming(m_playbackSessionModel ? m_playbackSessionModel->currentTime() : 0, [[NSProcessInfo processInfo] systemUptime], 0, false);
117 playbackSessionModel()->beginScrubbing();
120 void PlaybackSessionInterfaceMac::endScrubbing()
122 playbackSessionModel()->endScrubbing();
125 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
126 static RetainPtr<NSMutableArray> timeRangesToArray(const TimeRanges& timeRanges)
128 RetainPtr<NSMutableArray> rangeArray = adoptNS([[NSMutableArray alloc] init]);
130 for (unsigned i = 0; i < timeRanges.length(); i++) {
131 const PlatformTimeRanges& ranges = timeRanges.ranges();
132 CMTimeRange range = PAL::CMTimeRangeMake(PAL::toCMTime(ranges.start(i)), PAL::toCMTime(ranges.end(i)));
133 [rangeArray addObject:[NSValue valueWithCMTimeRange:range]];
140 void PlaybackSessionInterfaceMac::seekableRangesChanged(const TimeRanges& timeRanges, double, double)
142 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
143 [playBackControlsManager() setSeekableTimeRanges:timeRangesToArray(timeRanges).get()];
145 UNUSED_PARAM(timeRanges);
149 void PlaybackSessionInterfaceMac::audioMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
151 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
152 [playBackControlsManager() setAudioMediaSelectionOptions:options withSelectedIndex:static_cast<NSUInteger>(selectedIndex)];
154 UNUSED_PARAM(options);
155 UNUSED_PARAM(selectedIndex);
159 void PlaybackSessionInterfaceMac::legibleMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
161 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
162 [playBackControlsManager() setLegibleMediaSelectionOptions:options withSelectedIndex:static_cast<NSUInteger>(selectedIndex)];
164 UNUSED_PARAM(options);
165 UNUSED_PARAM(selectedIndex);
169 void PlaybackSessionInterfaceMac::audioMediaSelectionIndexChanged(uint64_t selectedIndex)
171 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
172 [playBackControlsManager() setAudioMediaSelectionIndex:selectedIndex];
174 UNUSED_PARAM(selectedIndex);
178 void PlaybackSessionInterfaceMac::legibleMediaSelectionIndexChanged(uint64_t selectedIndex)
180 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
181 [playBackControlsManager() setLegibleMediaSelectionIndex:selectedIndex];
183 UNUSED_PARAM(selectedIndex);
187 void PlaybackSessionInterfaceMac::isPictureInPictureSupportedChanged(bool)
189 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
190 updatePlaybackControlsManagerCanTogglePictureInPicture();
194 void PlaybackSessionInterfaceMac::externalPlaybackChanged(bool, PlaybackSessionModel::ExternalPlaybackTargetType, const String&)
196 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
197 updatePlaybackControlsManagerCanTogglePictureInPicture();
201 void PlaybackSessionInterfaceMac::invalidate()
203 if (!m_playbackSessionModel)
206 m_playbackSessionModel->removeClient(*this);
207 m_playbackSessionModel = nullptr;
210 void PlaybackSessionInterfaceMac::ensureControlsManager()
212 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
213 playBackControlsManager();
217 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
219 WebPlaybackControlsManager *PlaybackSessionInterfaceMac::playBackControlsManager()
221 return m_playbackControlsManager;
224 void PlaybackSessionInterfaceMac::setPlayBackControlsManager(WebPlaybackControlsManager *manager)
226 m_playbackControlsManager = manager;
228 if (!manager || !m_playbackSessionModel)
231 NSTimeInterval anchorTimeStamp = ![manager rate] ? NAN : [[NSProcessInfo processInfo] systemUptime];
232 manager.timing = [getAVValueTimingClass() valueTimingWithAnchorValue:m_playbackSessionModel->currentTime() anchorTimeStamp:anchorTimeStamp rate:0];
233 double duration = m_playbackSessionModel->duration();
234 manager.contentDuration = duration;
235 manager.hasEnabledAudio = duration > 0;
236 manager.hasEnabledVideo = duration > 0;
237 manager.rate = m_playbackSessionModel->isPlaying() ? m_playbackSessionModel->playbackRate() : 0.;
238 manager.seekableTimeRanges = timeRangesToArray(m_playbackSessionModel->seekableRanges()).get();
239 manager.canTogglePlayback = YES;
240 manager.playing = m_playbackSessionModel->isPlaying();
241 [manager setAudioMediaSelectionOptions:m_playbackSessionModel->audioMediaSelectionOptions() withSelectedIndex:static_cast<NSUInteger>(m_playbackSessionModel->audioMediaSelectedIndex())];
242 [manager setLegibleMediaSelectionOptions:m_playbackSessionModel->legibleMediaSelectionOptions() withSelectedIndex:static_cast<NSUInteger>(m_playbackSessionModel->legibleMediaSelectedIndex())];
245 void PlaybackSessionInterfaceMac::updatePlaybackControlsManagerCanTogglePictureInPicture()
247 PlaybackSessionModel* model = playbackSessionModel();
249 [playBackControlsManager() setCanTogglePictureInPicture:NO];
253 [playBackControlsManager() setCanTogglePictureInPicture:model->isPictureInPictureSupported() && !model->externalPlaybackEnabled()];
256 void PlaybackSessionInterfaceMac::updatePlaybackControlsManagerTiming(double currentTime, double anchorTime, double playbackRate, bool isPlaying)
258 WebPlaybackControlsManager *manager = playBackControlsManager();
262 PlaybackSessionModel *model = playbackSessionModel();
266 double effectiveAnchorTime = playbackRate ? anchorTime : NAN;
267 double effectivePlaybackRate = playbackRate;
269 || model->isScrubbing()
270 || (manager.rate > 0 && model->playbackStartedTime() >= currentTime)
271 || (manager.rate < 0 && model->playbackStartedTime() <= currentTime))
272 effectivePlaybackRate = 0;
274 manager.timing = [getAVValueTimingClass() valueTimingWithAnchorValue:currentTime anchorTimeStamp:effectiveAnchorTime rate:effectivePlaybackRate];
277 #endif // ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
281 #endif // PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)