c96120728336f53736e31785735443c58d08cf0f
[WebKit-https.git] / Source / WebKit2 / WebProcess / cocoa / WebPlaybackSessionManager.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 "WebPlaybackSessionManager.h"
28
29 #if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
30
31 #import "Attachment.h"
32 #import "WebCoreArgumentCoders.h"
33 #import "WebPage.h"
34 #import "WebPlaybackSessionManagerMessages.h"
35 #import "WebPlaybackSessionManagerProxyMessages.h"
36 #import "WebProcess.h"
37 #import <WebCore/Color.h>
38 #import <WebCore/Event.h>
39 #import <WebCore/EventNames.h>
40 #import <WebCore/HTMLMediaElement.h>
41 #import <WebCore/Settings.h>
42 #import <WebCore/TimeRanges.h>
43 #import <WebCore/UserGestureIndicator.h>
44 #import <mach/mach_port.h>
45
46 using namespace WebCore;
47
48 namespace WebKit {
49
50 static uint64_t nextContextId()
51 {
52     static uint64_t contextId = 0;
53     return ++contextId;
54 }
55
56 #pragma mark - WebPlaybackSessionInterfaceContext
57
58 WebPlaybackSessionInterfaceContext::WebPlaybackSessionInterfaceContext(WebPlaybackSessionManager& manager, uint64_t contextId)
59     : m_manager(&manager)
60     , m_contextId(contextId)
61 {
62 }
63
64 WebPlaybackSessionInterfaceContext::~WebPlaybackSessionInterfaceContext()
65 {
66 }
67
68 void WebPlaybackSessionInterfaceContext::resetMediaState()
69 {
70     if (m_manager)
71         m_manager->resetMediaState(m_contextId);
72 }
73
74 void WebPlaybackSessionInterfaceContext::durationChanged(double duration)
75 {
76     if (m_manager)
77         m_manager->durationChanged(m_contextId, duration);
78 }
79
80 void WebPlaybackSessionInterfaceContext::currentTimeChanged(double currentTime, double anchorTime)
81 {
82     if (m_manager)
83         m_manager->currentTimeChanged(m_contextId, currentTime, anchorTime);
84 }
85
86 void WebPlaybackSessionInterfaceContext::bufferedTimeChanged(double bufferedTime)
87 {
88     if (m_manager)
89         m_manager->bufferedTimeChanged(m_contextId, bufferedTime);
90 }
91
92 void WebPlaybackSessionInterfaceContext::rateChanged(bool isPlaying, float playbackRate)
93 {
94     if (m_manager)
95         m_manager->rateChanged(m_contextId, isPlaying, playbackRate);
96 }
97
98 void WebPlaybackSessionInterfaceContext::playbackStartedTimeChanged(double playbackStartedTime)
99 {
100     if (m_manager)
101         m_manager->playbackStartedTimeChanged(m_contextId, playbackStartedTime);
102 }
103
104 void WebPlaybackSessionInterfaceContext::seekableRangesChanged(const WebCore::TimeRanges& ranges)
105 {
106     if (m_manager)
107         m_manager->seekableRangesChanged(m_contextId, ranges);
108 }
109
110 void WebPlaybackSessionInterfaceContext::canPlayFastReverseChanged(bool value)
111 {
112     if (m_manager)
113         m_manager->canPlayFastReverseChanged(m_contextId, value);
114 }
115
116 void WebPlaybackSessionInterfaceContext::audioMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
117 {
118     if (m_manager)
119         m_manager->audioMediaSelectionOptionsChanged(m_contextId, options, selectedIndex);
120 }
121
122 void WebPlaybackSessionInterfaceContext::legibleMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
123 {
124     if (m_manager)
125         m_manager->legibleMediaSelectionOptionsChanged(m_contextId, options, selectedIndex);
126 }
127
128 void WebPlaybackSessionInterfaceContext::audioMediaSelectionIndexChanged(uint64_t selectedIndex)
129 {
130     if (m_manager)
131         m_manager->audioMediaSelectionIndexChanged(m_contextId, selectedIndex);
132 }
133
134 void WebPlaybackSessionInterfaceContext::legibleMediaSelectionIndexChanged(uint64_t selectedIndex)
135 {
136     if (m_manager)
137         m_manager->legibleMediaSelectionIndexChanged(m_contextId, selectedIndex);
138 }
139
140 void WebPlaybackSessionInterfaceContext::externalPlaybackChanged(bool enabled, WebPlaybackSessionModel::ExternalPlaybackTargetType type, const String& localizedDeviceName)
141 {
142     if (m_manager)
143         m_manager->externalPlaybackChanged(m_contextId, enabled, type, localizedDeviceName);
144 }
145
146 void WebPlaybackSessionInterfaceContext::wirelessVideoPlaybackDisabledChanged(bool disabled)
147 {
148     if (m_manager)
149         m_manager->wirelessVideoPlaybackDisabledChanged(m_contextId, disabled);
150 }
151
152 #pragma mark - WebPlaybackSessionManager
153
154 Ref<WebPlaybackSessionManager> WebPlaybackSessionManager::create(WebPage& page)
155 {
156     return adoptRef(*new WebPlaybackSessionManager(page));
157 }
158
159 WebPlaybackSessionManager::WebPlaybackSessionManager(WebPage& page)
160     : m_page(&page)
161 {
162     WebProcess::singleton().addMessageReceiver(Messages::WebPlaybackSessionManager::messageReceiverName(), page.pageID(), *this);
163 }
164
165 WebPlaybackSessionManager::~WebPlaybackSessionManager()
166 {
167     for (auto& tuple : m_contextMap.values()) {
168         RefPtr<WebPlaybackSessionModelMediaElement> model;
169         RefPtr<WebPlaybackSessionInterfaceContext> interface;
170         std::tie(model, interface) = tuple;
171         model->removeClient(*interface);
172         model->setMediaElement(nullptr);
173
174         interface->invalidate();
175     }
176
177     m_contextMap.clear();
178     m_mediaElements.clear();
179     m_clientCounts.clear();
180
181     WebProcess::singleton().removeMessageReceiver(Messages::WebPlaybackSessionManager::messageReceiverName(), m_page->pageID());
182 }
183
184 WebPlaybackSessionManager::ModelInterfaceTuple WebPlaybackSessionManager::createModelAndInterface(uint64_t contextId)
185 {
186     RefPtr<WebPlaybackSessionModelMediaElement> model = WebPlaybackSessionModelMediaElement::create();
187     RefPtr<WebPlaybackSessionInterfaceContext> interface = WebPlaybackSessionInterfaceContext::create(*this, contextId);
188     model->addClient(*interface);
189
190     return std::make_tuple(WTFMove(model), WTFMove(interface));
191 }
192
193 WebPlaybackSessionManager::ModelInterfaceTuple& WebPlaybackSessionManager::ensureModelAndInterface(uint64_t contextId)
194 {
195     auto addResult = m_contextMap.add(contextId, ModelInterfaceTuple());
196     if (addResult.isNewEntry)
197         addResult.iterator->value = createModelAndInterface(contextId);
198     return addResult.iterator->value;
199 }
200
201 WebCore::WebPlaybackSessionModelMediaElement& WebPlaybackSessionManager::ensureModel(uint64_t contextId)
202 {
203     return *std::get<0>(ensureModelAndInterface(contextId));
204 }
205
206 WebPlaybackSessionInterfaceContext& WebPlaybackSessionManager::ensureInterface(uint64_t contextId)
207 {
208     return *std::get<1>(ensureModelAndInterface(contextId));
209 }
210
211 void WebPlaybackSessionManager::removeContext(uint64_t contextId)
212 {
213     RefPtr<WebPlaybackSessionModelMediaElement> model;
214     RefPtr<WebPlaybackSessionInterfaceContext> interface;
215     std::tie(model, interface) = ensureModelAndInterface(contextId);
216
217     RefPtr<HTMLMediaElement> mediaElement = model->mediaElement();
218     model->setMediaElement(nullptr);
219     model->removeClient(*interface);
220     interface->invalidate();
221     m_mediaElements.remove(mediaElement.get());
222     m_contextMap.remove(contextId);
223 }
224
225 void WebPlaybackSessionManager::addClientForContext(uint64_t contextId)
226 {
227     m_clientCounts.add(contextId);
228 }
229
230 void WebPlaybackSessionManager::removeClientForContext(uint64_t contextId)
231 {
232     ASSERT(m_clientCounts.contains(contextId));
233     if (m_clientCounts.remove(contextId))
234         removeContext(contextId);
235 }
236
237 void WebPlaybackSessionManager::setUpPlaybackControlsManager(WebCore::HTMLMediaElement& mediaElement)
238 {
239 #if PLATFORM(MAC)
240     auto foundIterator = m_mediaElements.find(&mediaElement);
241     if (foundIterator != m_mediaElements.end()) {
242         uint64_t contextId = foundIterator->value;
243         if (m_controlsManagerContextId == contextId)
244             return;
245
246         if (m_controlsManagerContextId)
247             removeClientForContext(m_controlsManagerContextId);
248         m_controlsManagerContextId = contextId;
249     } else {
250         auto addResult = m_mediaElements.ensure(&mediaElement, [&] { return nextContextId(); });
251         auto contextId = addResult.iterator->value;
252         if (m_controlsManagerContextId)
253             removeClientForContext(m_controlsManagerContextId);
254         m_controlsManagerContextId = contextId;
255         ensureModel(contextId).setMediaElement(&mediaElement);
256     }
257
258     addClientForContext(m_controlsManagerContextId);
259     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetUpPlaybackControlsManagerWithID(m_controlsManagerContextId), m_page->pageID());
260 #endif
261 }
262
263 void WebPlaybackSessionManager::clearPlaybackControlsManager()
264 {
265 #if PLATFORM(MAC)
266     if (!m_controlsManagerContextId)
267         return;
268
269     removeClientForContext(m_controlsManagerContextId);
270     m_controlsManagerContextId = 0;
271     m_page->send(Messages::WebPlaybackSessionManagerProxy::ClearPlaybackControlsManager(), m_page->pageID());
272 #endif
273 }
274
275 uint64_t WebPlaybackSessionManager::contextIdForMediaElement(WebCore::HTMLMediaElement& mediaElement)
276 {
277     auto addResult = m_mediaElements.ensure(&mediaElement, [&] { return nextContextId(); });
278     uint64_t contextId = addResult.iterator->value;
279     ensureModel(contextId).setMediaElement(&mediaElement);
280     return contextId;
281 }
282
283 #pragma mark Interface to WebPlaybackSessionInterfaceContext:
284
285 void WebPlaybackSessionManager::resetMediaState(uint64_t contextId)
286 {
287     m_page->send(Messages::WebPlaybackSessionManagerProxy::ResetMediaState(contextId), m_page->pageID());
288 }
289
290 void WebPlaybackSessionManager::durationChanged(uint64_t contextId, double duration)
291 {
292     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetDuration(contextId, duration), m_page->pageID());
293 }
294
295 void WebPlaybackSessionManager::currentTimeChanged(uint64_t contextId, double currentTime, double anchorTime)
296 {
297     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetCurrentTime(contextId, currentTime, anchorTime), m_page->pageID());
298 }
299
300 void WebPlaybackSessionManager::bufferedTimeChanged(uint64_t contextId, double bufferedTime)
301 {
302     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetBufferedTime(contextId, bufferedTime), m_page->pageID());
303 }
304
305 void WebPlaybackSessionManager::playbackStartedTimeChanged(uint64_t contextId, double playbackStartedTime)
306 {
307     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetPlaybackStartedTime(contextId, playbackStartedTime), m_page->pageID());
308 }
309
310 void WebPlaybackSessionManager::rateChanged(uint64_t contextId, bool isPlaying, float playbackRate)
311 {
312     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetRate(contextId, isPlaying, playbackRate), m_page->pageID());
313 }
314
315 void WebPlaybackSessionManager::seekableRangesChanged(uint64_t contextId, const WebCore::TimeRanges& timeRanges)
316 {
317     Vector<std::pair<double, double>> rangesVector;
318     for (unsigned i = 0; i < timeRanges.length(); i++) {
319         double start = timeRanges.ranges().start(i).toDouble();
320         double end = timeRanges.ranges().end(i).toDouble();
321         rangesVector.append({ start, end });
322     }
323     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetSeekableRangesVector(contextId, WTFMove(rangesVector)), m_page->pageID());
324 }
325
326 void WebPlaybackSessionManager::canPlayFastReverseChanged(uint64_t contextId, bool value)
327 {
328     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetCanPlayFastReverse(contextId, value), m_page->pageID());
329 }
330
331 void WebPlaybackSessionManager::audioMediaSelectionOptionsChanged(uint64_t contextId, const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
332 {
333     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetAudioMediaSelectionOptions(contextId, options, selectedIndex), m_page->pageID());
334 }
335
336 void WebPlaybackSessionManager::legibleMediaSelectionOptionsChanged(uint64_t contextId, const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
337 {
338     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetLegibleMediaSelectionOptions(contextId, options, selectedIndex), m_page->pageID());
339 }
340
341 void WebPlaybackSessionManager::externalPlaybackChanged(uint64_t contextId, bool enabled, WebPlaybackSessionModel::ExternalPlaybackTargetType targetType, String localizedDeviceName)
342 {
343     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetExternalPlaybackProperties(contextId, enabled, static_cast<uint32_t>(targetType), localizedDeviceName), m_page->pageID());
344 }
345
346 void WebPlaybackSessionManager::audioMediaSelectionIndexChanged(uint64_t contextId, uint64_t selectedIndex)
347 {
348     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetAudioMediaSelectionIndex(contextId, selectedIndex), m_page->pageID());
349 }
350
351 void WebPlaybackSessionManager::legibleMediaSelectionIndexChanged(uint64_t contextId, uint64_t selectedIndex)
352 {
353     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetLegibleMediaSelectionIndex(contextId, selectedIndex), m_page->pageID());
354 }
355
356 void WebPlaybackSessionManager::wirelessVideoPlaybackDisabledChanged(uint64_t contextId, bool disabled)
357 {
358     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetWirelessVideoPlaybackDisabled(contextId, disabled));
359 }
360
361 #pragma mark Messages from WebPlaybackSessionManagerProxy:
362
363 void WebPlaybackSessionManager::play(uint64_t contextId)
364 {
365     UserGestureIndicator indicator(ProcessingUserGesture);
366     ensureModel(contextId).play();
367 }
368
369 void WebPlaybackSessionManager::pause(uint64_t contextId)
370 {
371     UserGestureIndicator indicator(ProcessingUserGesture);
372     ensureModel(contextId).pause();
373 }
374
375 void WebPlaybackSessionManager::togglePlayState(uint64_t contextId)
376 {
377     UserGestureIndicator indicator(ProcessingUserGesture);
378     ensureModel(contextId).togglePlayState();
379 }
380
381 void WebPlaybackSessionManager::beginScrubbing(uint64_t contextId)
382 {
383     UserGestureIndicator indicator(ProcessingUserGesture);
384     ensureModel(contextId).beginScrubbing();
385 }
386
387 void WebPlaybackSessionManager::endScrubbing(uint64_t contextId)
388 {
389     UserGestureIndicator indicator(ProcessingUserGesture);
390     ensureModel(contextId).endScrubbing();
391 }
392
393 void WebPlaybackSessionManager::seekToTime(uint64_t contextId, double time)
394 {
395     UserGestureIndicator indicator(ProcessingUserGesture);
396     ensureModel(contextId).seekToTime(time);
397 }
398
399 void WebPlaybackSessionManager::fastSeek(uint64_t contextId, double time)
400 {
401     UserGestureIndicator indicator(ProcessingUserGesture);
402     ensureModel(contextId).fastSeek(time);
403 }
404
405 void WebPlaybackSessionManager::beginScanningForward(uint64_t contextId)
406 {
407     UserGestureIndicator indicator(ProcessingUserGesture);
408     ensureModel(contextId).beginScanningForward();
409 }
410
411 void WebPlaybackSessionManager::beginScanningBackward(uint64_t contextId)
412 {
413     UserGestureIndicator indicator(ProcessingUserGesture);
414     ensureModel(contextId).beginScanningBackward();
415 }
416
417 void WebPlaybackSessionManager::endScanning(uint64_t contextId)
418 {
419     UserGestureIndicator indicator(ProcessingUserGesture);
420     ensureModel(contextId).endScanning();
421 }
422
423 void WebPlaybackSessionManager::selectAudioMediaOption(uint64_t contextId, uint64_t index)
424 {
425     UserGestureIndicator indicator(ProcessingUserGesture);
426     ensureModel(contextId).selectAudioMediaOption(index);
427 }
428
429 void WebPlaybackSessionManager::selectLegibleMediaOption(uint64_t contextId, uint64_t index)
430 {
431     UserGestureIndicator indicator(ProcessingUserGesture);
432     ensureModel(contextId).selectLegibleMediaOption(index);
433 }
434
435 void WebPlaybackSessionManager::handleControlledElementIDRequest(uint64_t contextId)
436 {
437     auto element = ensureModel(contextId).mediaElement();
438     if (element)
439         m_page->send(Messages::WebPlaybackSessionManagerProxy::HandleControlledElementIDResponse(contextId, element->getIdAttribute()));
440 }
441
442 void WebPlaybackSessionManager::togglePictureInPicture(uint64_t contextId)
443 {
444     UserGestureIndicator indicator(ProcessingUserGesture);
445     ensureModel(contextId).togglePictureInPicture();
446 }
447
448 } // namespace WebKit
449
450 #endif // PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))