b86266d4e33d007bfd78a6fe533c7f5386d3939e
[WebKit-https.git] / Source / WebCore / platform / mac / PlaybackSessionInterfaceMac.mm
1 /*
2  * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  */
25
26 #import "config.h"
27 #import "PlaybackSessionInterfaceMac.h"
28
29 #if PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)
30
31 #import "IntRect.h"
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>
39
40 #import <pal/cf/CoreMediaSoftLink.h>
41
42 SOFTLINK_AVKIT_FRAMEWORK()
43 SOFT_LINK_CLASS_OPTIONAL(AVKit, AVValueTiming)
44
45 namespace WebCore {
46
47 Ref<PlaybackSessionInterfaceMac> PlaybackSessionInterfaceMac::create(PlaybackSessionModel& model)
48 {
49     auto interface = adoptRef(*new PlaybackSessionInterfaceMac(model));
50     model.addClient(interface);
51     return interface;
52 }
53
54 PlaybackSessionInterfaceMac::PlaybackSessionInterfaceMac(PlaybackSessionModel& model)
55     : m_playbackSessionModel(&model)
56 {
57 }
58
59 PlaybackSessionInterfaceMac::~PlaybackSessionInterfaceMac()
60 {
61     invalidate();
62 }
63
64 PlaybackSessionModel* PlaybackSessionInterfaceMac::playbackSessionModel() const
65 {
66     return m_playbackSessionModel;
67 }
68
69 void PlaybackSessionInterfaceMac::resetMediaState()
70 {
71 }
72
73 void PlaybackSessionInterfaceMac::durationChanged(double duration)
74 {
75 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
76     WebPlaybackControlsManager* controlsManager = playBackControlsManager();
77
78     controlsManager.contentDuration = duration;
79
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;
83 #else
84     UNUSED_PARAM(duration);
85 #endif
86 }
87
88 void PlaybackSessionInterfaceMac::currentTimeChanged(double currentTime, double anchorTime)
89 {
90 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
91     WebPlaybackControlsManager* controlsManager = playBackControlsManager();
92     updatePlaybackControlsManagerTiming(currentTime, anchorTime, controlsManager.rate, controlsManager.playing);
93 #else
94     UNUSED_PARAM(currentTime);
95     UNUSED_PARAM(anchorTime);
96 #endif
97 }
98
99 void PlaybackSessionInterfaceMac::rateChanged(bool isPlaying, float playbackRate)
100 {
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);
106 #else
107     UNUSED_PARAM(isPlaying);
108     UNUSED_PARAM(playbackRate);
109 #endif
110 }
111
112 void PlaybackSessionInterfaceMac::beginScrubbing()
113 {
114 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
115     updatePlaybackControlsManagerTiming(m_playbackSessionModel ? m_playbackSessionModel->currentTime() : 0, [[NSProcessInfo processInfo] systemUptime], 0, false);
116 #endif
117     playbackSessionModel()->beginScrubbing();
118 }
119
120 void PlaybackSessionInterfaceMac::endScrubbing()
121 {
122     playbackSessionModel()->endScrubbing();
123 }
124
125 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
126 static RetainPtr<NSMutableArray> timeRangesToArray(const TimeRanges& timeRanges)
127 {
128     RetainPtr<NSMutableArray> rangeArray = adoptNS([[NSMutableArray alloc] init]);
129
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]];
134     }
135
136     return rangeArray;
137 }
138 #endif
139
140 void PlaybackSessionInterfaceMac::seekableRangesChanged(const TimeRanges& timeRanges, double, double)
141 {
142 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
143     [playBackControlsManager() setSeekableTimeRanges:timeRangesToArray(timeRanges).get()];
144 #else
145     UNUSED_PARAM(timeRanges);
146 #endif
147 }
148
149 void PlaybackSessionInterfaceMac::audioMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
150 {
151 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
152     [playBackControlsManager() setAudioMediaSelectionOptions:options withSelectedIndex:static_cast<NSUInteger>(selectedIndex)];
153 #else
154     UNUSED_PARAM(options);
155     UNUSED_PARAM(selectedIndex);
156 #endif
157 }
158
159 void PlaybackSessionInterfaceMac::legibleMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
160 {
161 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
162     [playBackControlsManager() setLegibleMediaSelectionOptions:options withSelectedIndex:static_cast<NSUInteger>(selectedIndex)];
163 #else
164     UNUSED_PARAM(options);
165     UNUSED_PARAM(selectedIndex);
166 #endif
167 }
168
169 void PlaybackSessionInterfaceMac::audioMediaSelectionIndexChanged(uint64_t selectedIndex)
170 {
171 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
172     [playBackControlsManager() setAudioMediaSelectionIndex:selectedIndex];
173 #else
174     UNUSED_PARAM(selectedIndex);
175 #endif
176 }
177
178 void PlaybackSessionInterfaceMac::legibleMediaSelectionIndexChanged(uint64_t selectedIndex)
179 {
180 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
181     [playBackControlsManager() setLegibleMediaSelectionIndex:selectedIndex];
182 #else
183     UNUSED_PARAM(selectedIndex);
184 #endif
185 }
186
187 void PlaybackSessionInterfaceMac::isPictureInPictureSupportedChanged(bool)
188 {
189 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
190     updatePlaybackControlsManagerCanTogglePictureInPicture();
191 #endif
192 }
193
194 void PlaybackSessionInterfaceMac::externalPlaybackChanged(bool, PlaybackSessionModel::ExternalPlaybackTargetType, const String&)
195 {
196 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
197     updatePlaybackControlsManagerCanTogglePictureInPicture();
198 #endif
199 }
200
201 void PlaybackSessionInterfaceMac::invalidate()
202 {
203     if (!m_playbackSessionModel)
204         return;
205
206     m_playbackSessionModel->removeClient(*this);
207     m_playbackSessionModel = nullptr;
208 }
209
210 void PlaybackSessionInterfaceMac::ensureControlsManager()
211 {
212 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
213     playBackControlsManager();
214 #endif
215 }
216
217 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
218
219 WebPlaybackControlsManager *PlaybackSessionInterfaceMac::playBackControlsManager()
220 {
221     return m_playbackControlsManager;
222 }
223
224 void PlaybackSessionInterfaceMac::setPlayBackControlsManager(WebPlaybackControlsManager *manager)
225 {
226     m_playbackControlsManager = manager;
227
228     if (!manager || !m_playbackSessionModel)
229         return;
230
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())];
243 }
244
245 void PlaybackSessionInterfaceMac::updatePlaybackControlsManagerCanTogglePictureInPicture()
246 {
247     PlaybackSessionModel* model = playbackSessionModel();
248     if (!model) {
249         [playBackControlsManager() setCanTogglePictureInPicture:NO];
250         return;
251     }
252
253     [playBackControlsManager() setCanTogglePictureInPicture:model->isPictureInPictureSupported() && !model->externalPlaybackEnabled()];
254 }
255
256 void PlaybackSessionInterfaceMac::updatePlaybackControlsManagerTiming(double currentTime, double anchorTime, double playbackRate, bool isPlaying)
257 {
258     WebPlaybackControlsManager *manager = playBackControlsManager();
259     if (!manager)
260         return;
261
262     PlaybackSessionModel *model = playbackSessionModel();
263     if (!model)
264         return;
265
266     double effectiveAnchorTime = playbackRate ? anchorTime : NAN;
267     double effectivePlaybackRate = playbackRate;
268     if (!isPlaying
269         || model->isScrubbing()
270         || (manager.rate > 0 && model->playbackStartedTime() >= currentTime)
271         || (manager.rate < 0 && model->playbackStartedTime() <= currentTime))
272         effectivePlaybackRate = 0;
273
274     manager.timing = [getAVValueTimingClass() valueTimingWithAnchorValue:currentTime anchorTimeStamp:effectiveAnchorTime rate:effectivePlaybackRate];
275 }
276
277 #endif // ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
278
279 }
280
281 #endif // PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)