eeba15a05d8041835f276d1bfac1cbb74a6a9795
[WebKit-https.git] / Source / WebCore / platform / audio / PlatformMediaSessionManager.cpp
1 /*
2  * Copyright (C) 2013-2015 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 #include "config.h"
27 #include "PlatformMediaSessionManager.h"
28
29 #if ENABLE(VIDEO) || ENABLE(WEB_AUDIO)
30
31 #include "AudioSession.h"
32 #include "Document.h"
33 #include "Logging.h"
34 #include "NotImplemented.h"
35 #include "PlatformMediaSession.h"
36
37 namespace WebCore {
38
39 #if !PLATFORM(IOS) && !PLATFORM(MAC)
40 static PlatformMediaSessionManager* platformMediaSessionManager = nullptr;
41
42 PlatformMediaSessionManager& PlatformMediaSessionManager::sharedManager()
43 {
44     if (!platformMediaSessionManager)
45         platformMediaSessionManager = new PlatformMediaSessionManager;
46     return *platformMediaSessionManager;
47 }
48
49 PlatformMediaSessionManager* PlatformMediaSessionManager::sharedManagerIfExists()
50 {
51     return platformMediaSessionManager;
52 }
53 #endif
54
55 PlatformMediaSessionManager::PlatformMediaSessionManager()
56     : m_systemSleepListener(SystemSleepListener::create(*this))
57 {
58     resetRestrictions();
59 }
60
61 void PlatformMediaSessionManager::resetRestrictions()
62 {
63     m_restrictions[PlatformMediaSession::Video] = NoRestrictions;
64     m_restrictions[PlatformMediaSession::Audio] = NoRestrictions;
65     m_restrictions[PlatformMediaSession::WebAudio] = NoRestrictions;
66 }
67
68 bool PlatformMediaSessionManager::has(PlatformMediaSession::MediaType type) const
69 {
70     ASSERT(type >= PlatformMediaSession::None && type <= PlatformMediaSession::WebAudio);
71
72     for (auto* session : m_sessions) {
73         if (session->mediaType() == type)
74             return true;
75     }
76
77     return false;
78 }
79
80 bool PlatformMediaSessionManager::activeAudioSessionRequired() const
81 {
82     for (auto* session : m_sessions) {
83         if (session->activeAudioSessionRequired())
84             return true;
85     }
86     
87     return false;
88 }
89
90 bool PlatformMediaSessionManager::canProduceAudio() const
91 {
92     for (auto* session : m_sessions) {
93         if (session->canProduceAudio())
94             return true;
95     }
96
97     return false;
98 }
99
100 int PlatformMediaSessionManager::count(PlatformMediaSession::MediaType type) const
101 {
102     ASSERT(type >= PlatformMediaSession::None && type <= PlatformMediaSession::WebAudio);
103
104     int count = 0;
105     for (auto* session : m_sessions) {
106         if (session->mediaType() == type)
107             ++count;
108     }
109
110     return count;
111 }
112
113 void PlatformMediaSessionManager::beginInterruption(PlatformMediaSession::InterruptionType type)
114 {
115     LOG(Media, "PlatformMediaSessionManager::beginInterruption");
116
117     m_interrupted = true;
118     Vector<PlatformMediaSession*> sessions = m_sessions;
119     for (auto* session : sessions)
120         session->beginInterruption(type);
121     updateSessionState();
122 }
123
124 void PlatformMediaSessionManager::endInterruption(PlatformMediaSession::EndInterruptionFlags flags)
125 {
126     LOG(Media, "PlatformMediaSessionManager::endInterruption");
127
128     m_interrupted = false;
129     Vector<PlatformMediaSession*> sessions = m_sessions;
130     for (auto* session : sessions)
131         session->endInterruption(flags);
132 }
133
134 void PlatformMediaSessionManager::addSession(PlatformMediaSession& session)
135 {
136     LOG(Media, "PlatformMediaSessionManager::addSession - %p", &session);
137     
138     m_sessions.append(&session);
139     if (m_interrupted)
140         session.setState(PlatformMediaSession::Interrupted);
141
142     if (!m_remoteCommandListener)
143         m_remoteCommandListener = RemoteCommandListener::create(*this);
144
145     if (!m_audioHardwareListener)
146         m_audioHardwareListener = AudioHardwareListener::create(*this);
147
148     updateSessionState();
149 }
150
151 void PlatformMediaSessionManager::removeSession(PlatformMediaSession& session)
152 {
153     LOG(Media, "PlatformMediaSessionManager::removeSession - %p", &session);
154     
155     size_t index = m_sessions.find(&session);
156     if (index == notFound)
157         return;
158     
159     m_sessions.remove(index);
160
161     if (m_sessions.isEmpty()) {
162         m_remoteCommandListener = nullptr;
163         m_audioHardwareListener = nullptr;
164     }
165
166     updateSessionState();
167 }
168
169 void PlatformMediaSessionManager::addRestriction(PlatformMediaSession::MediaType type, SessionRestrictions restriction)
170 {
171     ASSERT(type > PlatformMediaSession::None && type <= PlatformMediaSession::WebAudio);
172     m_restrictions[type] |= restriction;
173 }
174
175 void PlatformMediaSessionManager::removeRestriction(PlatformMediaSession::MediaType type, SessionRestrictions restriction)
176 {
177     ASSERT(type > PlatformMediaSession::None && type <= PlatformMediaSession::WebAudio);
178     m_restrictions[type] &= ~restriction;
179 }
180
181 PlatformMediaSessionManager::SessionRestrictions PlatformMediaSessionManager::restrictions(PlatformMediaSession::MediaType type)
182 {
183     ASSERT(type > PlatformMediaSession::None && type <= PlatformMediaSession::WebAudio);
184     return m_restrictions[type];
185 }
186
187 bool PlatformMediaSessionManager::sessionWillBeginPlayback(PlatformMediaSession& session)
188 {
189     LOG(Media, "PlatformMediaSessionManager::sessionWillBeginPlayback - %p", &session);
190     
191     setCurrentSession(session);
192
193     PlatformMediaSession::MediaType sessionType = session.mediaType();
194     SessionRestrictions restrictions = m_restrictions[sessionType];
195     if (session.state() == PlatformMediaSession::Interrupted && restrictions & InterruptedPlaybackNotPermitted)
196         return false;
197
198 #if USE(AUDIO_SESSION)
199     if (activeAudioSessionRequired() && !AudioSession::sharedSession().tryToSetActive(true))
200         return false;
201 #endif
202
203     if (m_interrupted)
204         endInterruption(PlatformMediaSession::NoFlags);
205
206     Vector<PlatformMediaSession*> sessions = m_sessions;
207     for (auto* oneSession : sessions) {
208         if (oneSession == &session)
209             continue;
210         if (oneSession->mediaType() == sessionType
211             && restrictions & ConcurrentPlaybackNotPermitted
212             && oneSession->state() == PlatformMediaSession::Playing)
213             oneSession->pauseSession();
214     }
215
216     updateSessionState();
217     return true;
218 }
219     
220 void PlatformMediaSessionManager::sessionWillEndPlayback(PlatformMediaSession& session)
221 {
222     LOG(Media, "PlatformMediaSessionManager::sessionWillEndPlayback - %p", &session);
223     
224     if (m_sessions.size() < 2)
225         return;
226     
227     size_t pausingSessionIndex = notFound;
228     size_t lastPlayingSessionIndex = notFound;
229     for (size_t i = 0; i < m_sessions.size(); ++i) {
230         PlatformMediaSession* oneSession = m_sessions[i];
231         
232         if (oneSession == &session) {
233             pausingSessionIndex = i;
234             continue;
235         }
236         if (oneSession->state() == PlatformMediaSession::Playing) {
237             lastPlayingSessionIndex = i;
238             continue;
239         }
240         if (oneSession->state() != PlatformMediaSession::Playing)
241             break;
242     }
243     if (lastPlayingSessionIndex == notFound || pausingSessionIndex == notFound)
244         return;
245     
246     if (pausingSessionIndex > lastPlayingSessionIndex)
247         return;
248     
249     m_sessions.remove(pausingSessionIndex);
250     m_sessions.insert(lastPlayingSessionIndex, &session);
251     
252     LOG(Media, "PlatformMediaSessionManager::sessionWillEndPlayback - session moved from index %zu to %zu", pausingSessionIndex, lastPlayingSessionIndex);
253 }
254
255 void PlatformMediaSessionManager::setCurrentSession(PlatformMediaSession& session)
256 {
257     LOG(Media, "PlatformMediaSessionManager::setCurrentSession - %p", &session);
258     
259     if (m_sessions.size() < 2)
260         return;
261     
262     size_t index = m_sessions.find(&session);
263     ASSERT(index != notFound);
264     if (!index || index == notFound)
265         return;
266
267     m_sessions.remove(index);
268     m_sessions.insert(0, &session);
269     if (m_remoteCommandListener)
270         m_remoteCommandListener->updateSupportedCommands();
271     
272     LOG(Media, "PlatformMediaSessionManager::setCurrentSession - session moved from index %zu to 0", index);
273 }
274     
275 PlatformMediaSession* PlatformMediaSessionManager::currentSession() const
276 {
277     if (!m_sessions.size())
278         return nullptr;
279
280     return m_sessions[0];
281 }
282
283 PlatformMediaSession* PlatformMediaSessionManager::currentSessionMatching(std::function<bool(const PlatformMediaSession &)> filter)
284 {
285     for (auto& session : m_sessions) {
286         if (filter(*session))
287             return session;
288     }
289     return nullptr;
290 }
291     
292 bool PlatformMediaSessionManager::sessionCanLoadMedia(const PlatformMediaSession& session) const
293 {
294     return session.state() == PlatformMediaSession::Playing || !session.isHidden() || session.shouldOverrideBackgroundLoadingRestriction();
295 }
296
297 void PlatformMediaSessionManager::applicationWillEnterBackground() const
298 {
299     LOG(Media, "PlatformMediaSessionManager::applicationWillEnterBackground");
300
301     if (m_isApplicationInBackground)
302         return;
303
304     m_isApplicationInBackground = true;
305     
306     Vector<PlatformMediaSession*> sessions = m_sessions;
307     for (auto* session : sessions) {
308         if (m_restrictions[session->mediaType()] & BackgroundProcessPlaybackRestricted)
309             session->beginInterruption(PlatformMediaSession::EnteringBackground);
310     }
311 }
312
313 void PlatformMediaSessionManager::applicationDidEnterForeground() const
314 {
315     LOG(Media, "PlatformMediaSessionManager::applicationDidEnterForeground");
316
317     if (!m_isApplicationInBackground)
318         return;
319
320     m_isApplicationInBackground = false;
321
322     Vector<PlatformMediaSession*> sessions = m_sessions;
323     for (auto* session : sessions) {
324         if (m_restrictions[session->mediaType()] & BackgroundProcessPlaybackRestricted)
325             session->endInterruption(PlatformMediaSession::MayResumePlaying);
326     }
327 }
328
329 void PlatformMediaSessionManager::sessionIsPlayingToWirelessPlaybackTargetChanged(PlatformMediaSession& session)
330 {
331     if (!m_isApplicationInBackground || !(m_restrictions[session.mediaType()] & BackgroundProcessPlaybackRestricted))
332         return;
333
334     if (session.state() != PlatformMediaSession::Interrupted)
335         session.beginInterruption(PlatformMediaSession::EnteringBackground);
336 }
337
338 void PlatformMediaSessionManager::sessionCanProduceAudioChanged(PlatformMediaSession&)
339 {
340     updateSessionState();
341 }
342
343 #if !PLATFORM(COCOA)
344 void PlatformMediaSessionManager::updateSessionState()
345 {
346 }
347 #endif
348
349 void PlatformMediaSessionManager::didReceiveRemoteControlCommand(PlatformMediaSession::RemoteControlCommandType command, const PlatformMediaSession::RemoteCommandArgument* argument)
350 {
351     PlatformMediaSession* activeSession = currentSession();
352     if (!activeSession || !activeSession->canReceiveRemoteControlCommands())
353         return;
354     activeSession->didReceiveRemoteControlCommand(command, argument);
355 }
356
357 bool PlatformMediaSessionManager::supportsSeeking() const
358 {
359     PlatformMediaSession* activeSession = currentSession();
360     if (!activeSession)
361         return false;
362     return activeSession->supportsSeeking();
363 }
364
365 void PlatformMediaSessionManager::systemWillSleep()
366 {
367     if (m_interrupted)
368         return;
369
370     for (auto* session : m_sessions)
371         session->beginInterruption(PlatformMediaSession::SystemSleep);
372 }
373
374 void PlatformMediaSessionManager::systemDidWake()
375 {
376     if (m_interrupted)
377         return;
378
379     for (auto* session : m_sessions)
380         session->endInterruption(PlatformMediaSession::MayResumePlaying);
381 }
382
383 void PlatformMediaSessionManager::audioOutputDeviceChanged()
384 {
385     updateSessionState();
386 }
387
388 void PlatformMediaSessionManager::stopAllMediaPlaybackForDocument(const Document* document)
389 {
390     Vector<PlatformMediaSession*> sessions = m_sessions;
391     for (auto* session : sessions) {
392         if (session->client().hostingDocument() == document)
393             session->pauseSession();
394     }
395 }
396
397 void PlatformMediaSessionManager::stopAllMediaPlaybackForProcess()
398 {
399     Vector<PlatformMediaSession*> sessions = m_sessions;
400     for (auto* session : sessions)
401         session->stopSession();
402 }
403
404 }
405
406 #endif