28c7ee9c8079b88f2cc6bca9b29a5c4ade164349
[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 void WebPlaybackSessionInterfaceContext::mutedChanged(bool muted)
153 {
154     if (m_manager)
155         m_manager->mutedChanged(m_contextId, muted);
156 }
157
158 #pragma mark - WebPlaybackSessionManager
159
160 Ref<WebPlaybackSessionManager> WebPlaybackSessionManager::create(WebPage& page)
161 {
162     return adoptRef(*new WebPlaybackSessionManager(page));
163 }
164
165 WebPlaybackSessionManager::WebPlaybackSessionManager(WebPage& page)
166     : m_page(&page)
167 {
168     WebProcess::singleton().addMessageReceiver(Messages::WebPlaybackSessionManager::messageReceiverName(), page.pageID(), *this);
169 }
170
171 WebPlaybackSessionManager::~WebPlaybackSessionManager()
172 {
173     for (auto& tuple : m_contextMap.values()) {
174         RefPtr<WebPlaybackSessionModelMediaElement> model;
175         RefPtr<WebPlaybackSessionInterfaceContext> interface;
176         std::tie(model, interface) = tuple;
177         model->removeClient(*interface);
178         model->setMediaElement(nullptr);
179
180         interface->invalidate();
181     }
182
183     m_contextMap.clear();
184     m_mediaElements.clear();
185     m_clientCounts.clear();
186
187     WebProcess::singleton().removeMessageReceiver(Messages::WebPlaybackSessionManager::messageReceiverName(), m_page->pageID());
188 }
189
190 WebPlaybackSessionManager::ModelInterfaceTuple WebPlaybackSessionManager::createModelAndInterface(uint64_t contextId)
191 {
192     RefPtr<WebPlaybackSessionModelMediaElement> model = WebPlaybackSessionModelMediaElement::create();
193     RefPtr<WebPlaybackSessionInterfaceContext> interface = WebPlaybackSessionInterfaceContext::create(*this, contextId);
194     model->addClient(*interface);
195
196     return std::make_tuple(WTFMove(model), WTFMove(interface));
197 }
198
199 WebPlaybackSessionManager::ModelInterfaceTuple& WebPlaybackSessionManager::ensureModelAndInterface(uint64_t contextId)
200 {
201     auto addResult = m_contextMap.add(contextId, ModelInterfaceTuple());
202     if (addResult.isNewEntry)
203         addResult.iterator->value = createModelAndInterface(contextId);
204     return addResult.iterator->value;
205 }
206
207 WebCore::WebPlaybackSessionModelMediaElement& WebPlaybackSessionManager::ensureModel(uint64_t contextId)
208 {
209     return *std::get<0>(ensureModelAndInterface(contextId));
210 }
211
212 WebPlaybackSessionInterfaceContext& WebPlaybackSessionManager::ensureInterface(uint64_t contextId)
213 {
214     return *std::get<1>(ensureModelAndInterface(contextId));
215 }
216
217 void WebPlaybackSessionManager::removeContext(uint64_t contextId)
218 {
219     RefPtr<WebPlaybackSessionModelMediaElement> model;
220     RefPtr<WebPlaybackSessionInterfaceContext> interface;
221     std::tie(model, interface) = ensureModelAndInterface(contextId);
222
223     RefPtr<HTMLMediaElement> mediaElement = model->mediaElement();
224     model->setMediaElement(nullptr);
225     model->removeClient(*interface);
226     interface->invalidate();
227     m_mediaElements.remove(mediaElement.get());
228     m_contextMap.remove(contextId);
229 }
230
231 void WebPlaybackSessionManager::addClientForContext(uint64_t contextId)
232 {
233     m_clientCounts.add(contextId);
234 }
235
236 void WebPlaybackSessionManager::removeClientForContext(uint64_t contextId)
237 {
238     ASSERT(m_clientCounts.contains(contextId));
239     if (m_clientCounts.remove(contextId))
240         removeContext(contextId);
241 }
242
243 void WebPlaybackSessionManager::setUpPlaybackControlsManager(WebCore::HTMLMediaElement& mediaElement)
244 {
245 #if PLATFORM(MAC)
246     auto foundIterator = m_mediaElements.find(&mediaElement);
247     if (foundIterator != m_mediaElements.end()) {
248         uint64_t contextId = foundIterator->value;
249         if (m_controlsManagerContextId == contextId)
250             return;
251
252         if (m_controlsManagerContextId)
253             removeClientForContext(m_controlsManagerContextId);
254         m_controlsManagerContextId = contextId;
255     } else {
256         auto addResult = m_mediaElements.ensure(&mediaElement, [&] { return nextContextId(); });
257         auto contextId = addResult.iterator->value;
258         if (m_controlsManagerContextId)
259             removeClientForContext(m_controlsManagerContextId);
260         m_controlsManagerContextId = contextId;
261         ensureModel(contextId).setMediaElement(&mediaElement);
262     }
263
264     addClientForContext(m_controlsManagerContextId);
265     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetUpPlaybackControlsManagerWithID(m_controlsManagerContextId), m_page->pageID());
266 #endif
267 }
268
269 void WebPlaybackSessionManager::clearPlaybackControlsManager()
270 {
271 #if PLATFORM(MAC)
272     if (!m_controlsManagerContextId)
273         return;
274
275     removeClientForContext(m_controlsManagerContextId);
276     m_controlsManagerContextId = 0;
277     m_page->send(Messages::WebPlaybackSessionManagerProxy::ClearPlaybackControlsManager(), m_page->pageID());
278 #endif
279 }
280
281 uint64_t WebPlaybackSessionManager::contextIdForMediaElement(WebCore::HTMLMediaElement& mediaElement)
282 {
283     auto addResult = m_mediaElements.ensure(&mediaElement, [&] { return nextContextId(); });
284     uint64_t contextId = addResult.iterator->value;
285     ensureModel(contextId).setMediaElement(&mediaElement);
286     return contextId;
287 }
288
289 #pragma mark Interface to WebPlaybackSessionInterfaceContext:
290
291 void WebPlaybackSessionManager::resetMediaState(uint64_t contextId)
292 {
293     m_page->send(Messages::WebPlaybackSessionManagerProxy::ResetMediaState(contextId), m_page->pageID());
294 }
295
296 void WebPlaybackSessionManager::durationChanged(uint64_t contextId, double duration)
297 {
298     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetDuration(contextId, duration), m_page->pageID());
299 }
300
301 void WebPlaybackSessionManager::currentTimeChanged(uint64_t contextId, double currentTime, double anchorTime)
302 {
303     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetCurrentTime(contextId, currentTime, anchorTime), m_page->pageID());
304 }
305
306 void WebPlaybackSessionManager::bufferedTimeChanged(uint64_t contextId, double bufferedTime)
307 {
308     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetBufferedTime(contextId, bufferedTime), m_page->pageID());
309 }
310
311 void WebPlaybackSessionManager::playbackStartedTimeChanged(uint64_t contextId, double playbackStartedTime)
312 {
313     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetPlaybackStartedTime(contextId, playbackStartedTime), m_page->pageID());
314 }
315
316 void WebPlaybackSessionManager::rateChanged(uint64_t contextId, bool isPlaying, float playbackRate)
317 {
318     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetRate(contextId, isPlaying, playbackRate), m_page->pageID());
319 }
320
321 void WebPlaybackSessionManager::seekableRangesChanged(uint64_t contextId, const WebCore::TimeRanges& timeRanges)
322 {
323     Vector<std::pair<double, double>> rangesVector;
324     for (unsigned i = 0; i < timeRanges.length(); i++) {
325         double start = timeRanges.ranges().start(i).toDouble();
326         double end = timeRanges.ranges().end(i).toDouble();
327         rangesVector.append({ start, end });
328     }
329     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetSeekableRangesVector(contextId, WTFMove(rangesVector)), m_page->pageID());
330 }
331
332 void WebPlaybackSessionManager::canPlayFastReverseChanged(uint64_t contextId, bool value)
333 {
334     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetCanPlayFastReverse(contextId, value), m_page->pageID());
335 }
336
337 void WebPlaybackSessionManager::audioMediaSelectionOptionsChanged(uint64_t contextId, const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
338 {
339     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetAudioMediaSelectionOptions(contextId, options, selectedIndex), m_page->pageID());
340 }
341
342 void WebPlaybackSessionManager::legibleMediaSelectionOptionsChanged(uint64_t contextId, const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
343 {
344     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetLegibleMediaSelectionOptions(contextId, options, selectedIndex), m_page->pageID());
345 }
346
347 void WebPlaybackSessionManager::externalPlaybackChanged(uint64_t contextId, bool enabled, WebPlaybackSessionModel::ExternalPlaybackTargetType targetType, String localizedDeviceName)
348 {
349     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetExternalPlaybackProperties(contextId, enabled, static_cast<uint32_t>(targetType), localizedDeviceName), m_page->pageID());
350 }
351
352 void WebPlaybackSessionManager::audioMediaSelectionIndexChanged(uint64_t contextId, uint64_t selectedIndex)
353 {
354     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetAudioMediaSelectionIndex(contextId, selectedIndex), m_page->pageID());
355 }
356
357 void WebPlaybackSessionManager::legibleMediaSelectionIndexChanged(uint64_t contextId, uint64_t selectedIndex)
358 {
359     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetLegibleMediaSelectionIndex(contextId, selectedIndex), m_page->pageID());
360 }
361
362 void WebPlaybackSessionManager::wirelessVideoPlaybackDisabledChanged(uint64_t contextId, bool disabled)
363 {
364     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetWirelessVideoPlaybackDisabled(contextId, disabled));
365 }
366
367 void WebPlaybackSessionManager::mutedChanged(uint64_t contextId, bool muted)
368 {
369     m_page->send(Messages::WebPlaybackSessionManagerProxy::SetMuted(contextId, muted));
370 }
371
372 #pragma mark Messages from WebPlaybackSessionManagerProxy:
373
374 void WebPlaybackSessionManager::play(uint64_t contextId)
375 {
376     UserGestureIndicator indicator(ProcessingUserGesture);
377     ensureModel(contextId).play();
378 }
379
380 void WebPlaybackSessionManager::pause(uint64_t contextId)
381 {
382     UserGestureIndicator indicator(ProcessingUserGesture);
383     ensureModel(contextId).pause();
384 }
385
386 void WebPlaybackSessionManager::togglePlayState(uint64_t contextId)
387 {
388     UserGestureIndicator indicator(ProcessingUserGesture);
389     ensureModel(contextId).togglePlayState();
390 }
391
392 void WebPlaybackSessionManager::beginScrubbing(uint64_t contextId)
393 {
394     UserGestureIndicator indicator(ProcessingUserGesture);
395     ensureModel(contextId).beginScrubbing();
396 }
397
398 void WebPlaybackSessionManager::endScrubbing(uint64_t contextId)
399 {
400     UserGestureIndicator indicator(ProcessingUserGesture);
401     ensureModel(contextId).endScrubbing();
402 }
403
404 void WebPlaybackSessionManager::seekToTime(uint64_t contextId, double time)
405 {
406     UserGestureIndicator indicator(ProcessingUserGesture);
407     ensureModel(contextId).seekToTime(time);
408 }
409
410 void WebPlaybackSessionManager::fastSeek(uint64_t contextId, double time)
411 {
412     UserGestureIndicator indicator(ProcessingUserGesture);
413     ensureModel(contextId).fastSeek(time);
414 }
415
416 void WebPlaybackSessionManager::beginScanningForward(uint64_t contextId)
417 {
418     UserGestureIndicator indicator(ProcessingUserGesture);
419     ensureModel(contextId).beginScanningForward();
420 }
421
422 void WebPlaybackSessionManager::beginScanningBackward(uint64_t contextId)
423 {
424     UserGestureIndicator indicator(ProcessingUserGesture);
425     ensureModel(contextId).beginScanningBackward();
426 }
427
428 void WebPlaybackSessionManager::endScanning(uint64_t contextId)
429 {
430     UserGestureIndicator indicator(ProcessingUserGesture);
431     ensureModel(contextId).endScanning();
432 }
433
434 void WebPlaybackSessionManager::selectAudioMediaOption(uint64_t contextId, uint64_t index)
435 {
436     UserGestureIndicator indicator(ProcessingUserGesture);
437     ensureModel(contextId).selectAudioMediaOption(index);
438 }
439
440 void WebPlaybackSessionManager::selectLegibleMediaOption(uint64_t contextId, uint64_t index)
441 {
442     UserGestureIndicator indicator(ProcessingUserGesture);
443     ensureModel(contextId).selectLegibleMediaOption(index);
444 }
445
446 void WebPlaybackSessionManager::handleControlledElementIDRequest(uint64_t contextId)
447 {
448     auto element = ensureModel(contextId).mediaElement();
449     if (element)
450         m_page->send(Messages::WebPlaybackSessionManagerProxy::HandleControlledElementIDResponse(contextId, element->getIdAttribute()));
451 }
452
453 void WebPlaybackSessionManager::togglePictureInPicture(uint64_t contextId)
454 {
455     UserGestureIndicator indicator(ProcessingUserGesture);
456     ensureModel(contextId).togglePictureInPicture();
457 }
458
459 void WebPlaybackSessionManager::toggleMuted(uint64_t contextId)
460 {
461     UserGestureIndicator indicator(ProcessingUserGesture);
462     ensureModel(contextId).toggleMuted();
463 }
464
465 } // namespace WebKit
466
467 #endif // PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))