2256461a74a2557f7cace4acc99c97a8b4b4da03
[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)
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)
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->mediaType() != PlatformMediaSession::None && session->state() == PlatformMediaSession::State::Playing)
84             return true;
85     }
86     
87     return false;
88 }
89
90 int PlatformMediaSessionManager::count(PlatformMediaSession::MediaType type) const
91 {
92     ASSERT(type >= PlatformMediaSession::None && type <= PlatformMediaSession::WebAudio);
93
94     int count = 0;
95     for (auto* session : m_sessions) {
96         if (session->mediaType() == type)
97             ++count;
98     }
99
100     return count;
101 }
102
103 void PlatformMediaSessionManager::beginInterruption(PlatformMediaSession::InterruptionType type)
104 {
105     LOG(Media, "PlatformMediaSessionManager::beginInterruption");
106
107     m_interrupted = true;
108     Vector<PlatformMediaSession*> sessions = m_sessions;
109     for (auto* session : sessions)
110         session->beginInterruption(type);
111     updateSessionState();
112 }
113
114 void PlatformMediaSessionManager::endInterruption(PlatformMediaSession::EndInterruptionFlags flags)
115 {
116     LOG(Media, "PlatformMediaSessionManager::endInterruption");
117
118     m_interrupted = false;
119     Vector<PlatformMediaSession*> sessions = m_sessions;
120     for (auto* session : sessions)
121         session->endInterruption(flags);
122 }
123
124 void PlatformMediaSessionManager::addSession(PlatformMediaSession& session)
125 {
126     LOG(Media, "PlatformMediaSessionManager::addSession - %p", &session);
127     
128     m_sessions.append(&session);
129     if (m_interrupted)
130         session.setState(PlatformMediaSession::Interrupted);
131
132     if (!m_remoteCommandListener)
133         m_remoteCommandListener = RemoteCommandListener::create(*this);
134
135     if (!m_audioHardwareListener)
136         m_audioHardwareListener = AudioHardwareListener::create(*this);
137
138     updateSessionState();
139 }
140
141 void PlatformMediaSessionManager::removeSession(PlatformMediaSession& session)
142 {
143     LOG(Media, "PlatformMediaSessionManager::removeSession - %p", &session);
144     
145     size_t index = m_sessions.find(&session);
146     ASSERT(index != notFound);
147     if (index == notFound)
148         return;
149     
150     m_sessions.remove(index);
151
152     if (m_sessions.isEmpty()) {
153         m_remoteCommandListener = nullptr;
154         m_audioHardwareListener = nullptr;
155     }
156
157     updateSessionState();
158 }
159
160 void PlatformMediaSessionManager::addRestriction(PlatformMediaSession::MediaType type, SessionRestrictions restriction)
161 {
162     ASSERT(type > PlatformMediaSession::None && type <= PlatformMediaSession::WebAudio);
163     m_restrictions[type] |= restriction;
164 }
165
166 void PlatformMediaSessionManager::removeRestriction(PlatformMediaSession::MediaType type, SessionRestrictions restriction)
167 {
168     ASSERT(type > PlatformMediaSession::None && type <= PlatformMediaSession::WebAudio);
169     m_restrictions[type] &= ~restriction;
170 }
171
172 PlatformMediaSessionManager::SessionRestrictions PlatformMediaSessionManager::restrictions(PlatformMediaSession::MediaType type)
173 {
174     ASSERT(type > PlatformMediaSession::None && type <= PlatformMediaSession::WebAudio);
175     return m_restrictions[type];
176 }
177
178 bool PlatformMediaSessionManager::sessionWillBeginPlayback(PlatformMediaSession& session)
179 {
180     LOG(Media, "PlatformMediaSessionManager::sessionWillBeginPlayback - %p", &session);
181     
182     setCurrentSession(session);
183
184     PlatformMediaSession::MediaType sessionType = session.mediaType();
185     SessionRestrictions restrictions = m_restrictions[sessionType];
186     if (session.state() == PlatformMediaSession::Interrupted && restrictions & InterruptedPlaybackNotPermitted)
187         return false;
188
189 #if USE(AUDIO_SESSION)
190     if (activeAudioSessionRequired() && !AudioSession::sharedSession().tryToSetActive(true))
191         return false;
192 #endif
193
194     if (m_interrupted)
195         endInterruption(PlatformMediaSession::NoFlags);
196
197     Vector<PlatformMediaSession*> sessions = m_sessions;
198     for (auto* oneSession : sessions) {
199         if (oneSession == &session)
200             continue;
201         if (oneSession->mediaType() == sessionType && restrictions & ConcurrentPlaybackNotPermitted)
202             oneSession->pauseSession();
203     }
204
205     updateSessionState();
206     return true;
207 }
208     
209 void PlatformMediaSessionManager::sessionWillEndPlayback(PlatformMediaSession& session)
210 {
211     LOG(Media, "PlatformMediaSessionManager::sessionWillEndPlayback - %p", &session);
212     
213     if (m_sessions.size() < 2)
214         return;
215     
216     size_t pausingSessionIndex = notFound;
217     size_t lastPlayingSessionIndex = notFound;
218     for (size_t i = 0; i < m_sessions.size(); ++i) {
219         PlatformMediaSession* oneSession = m_sessions[i];
220         
221         if (oneSession == &session) {
222             pausingSessionIndex = i;
223             continue;
224         }
225         if (oneSession->state() == PlatformMediaSession::Playing) {
226             lastPlayingSessionIndex = i;
227             continue;
228         }
229         if (oneSession->state() != PlatformMediaSession::Playing)
230             break;
231     }
232     if (lastPlayingSessionIndex == notFound || pausingSessionIndex == notFound)
233         return;
234     
235     if (pausingSessionIndex > lastPlayingSessionIndex)
236         return;
237     
238     m_sessions.remove(pausingSessionIndex);
239     m_sessions.insert(lastPlayingSessionIndex, &session);
240     
241     LOG(Media, "PlatformMediaSessionManager::sessionWillEndPlayback - session moved from index %zu to %zu", pausingSessionIndex, lastPlayingSessionIndex);
242 }
243
244 void PlatformMediaSessionManager::setCurrentSession(PlatformMediaSession& session)
245 {
246     LOG(Media, "PlatformMediaSessionManager::setCurrentSession - %p", &session);
247     
248     if (m_sessions.size() < 2)
249         return;
250     
251     size_t index = m_sessions.find(&session);
252     ASSERT(index != notFound);
253     if (!index || index == notFound)
254         return;
255
256     m_sessions.remove(index);
257     m_sessions.insert(0, &session);
258     
259     LOG(Media, "PlatformMediaSessionManager::setCurrentSession - session moved from index %zu to 0", index);
260 }
261     
262 PlatformMediaSession* PlatformMediaSessionManager::currentSession()
263 {
264     if (!m_sessions.size())
265         return nullptr;
266
267     return m_sessions[0];
268 }
269     
270 bool PlatformMediaSessionManager::sessionCanLoadMedia(const PlatformMediaSession& session) const
271 {
272     return session.state() == PlatformMediaSession::Playing || !session.isHidden() || session.isPlayingToWirelessPlaybackTarget();
273 }
274
275 void PlatformMediaSessionManager::applicationWillEnterBackground() const
276 {
277     LOG(Media, "PlatformMediaSessionManager::applicationWillEnterBackground");
278     Vector<PlatformMediaSession*> sessions = m_sessions;
279     for (auto* session : sessions) {
280         if (m_restrictions[session->mediaType()] & BackgroundProcessPlaybackRestricted)
281             session->beginInterruption(PlatformMediaSession::EnteringBackground);
282     }
283 }
284
285 void PlatformMediaSessionManager::applicationDidEnterBackground(bool isSuspendedUnderLock) const
286 {
287     LOG(Media, "PlatformMediaSessionManager::applicationDidEnterBackground");
288
289     if (!isSuspendedUnderLock)
290         return;
291
292     Vector<PlatformMediaSession*> sessions = m_sessions;
293     for (auto* session : sessions) {
294         if (m_restrictions[session->mediaType()] & BackgroundProcessPlaybackRestricted)
295             session->forceInterruption(PlatformMediaSession::EnteringBackground);
296     }
297 }
298
299 void PlatformMediaSessionManager::applicationWillEnterForeground() const
300 {
301     LOG(Media, "PlatformMediaSessionManager::applicationWillEnterForeground");
302     Vector<PlatformMediaSession*> sessions = m_sessions;
303     for (auto* session : sessions) {
304         if (m_restrictions[session->mediaType()] & BackgroundProcessPlaybackRestricted)
305             session->endInterruption(PlatformMediaSession::MayResumePlaying);
306     }
307 }
308
309 #if !PLATFORM(COCOA)
310 void PlatformMediaSessionManager::updateSessionState()
311 {
312 }
313 #endif
314
315 void PlatformMediaSessionManager::didReceiveRemoteControlCommand(PlatformMediaSession::RemoteControlCommandType command)
316 {
317     PlatformMediaSession* activeSession = currentSession();
318     if (!activeSession || !activeSession->canReceiveRemoteControlCommands())
319         return;
320     activeSession->didReceiveRemoteControlCommand(command);
321 }
322
323 void PlatformMediaSessionManager::systemWillSleep()
324 {
325     if (m_interrupted)
326         return;
327
328     for (auto session : m_sessions)
329         session->beginInterruption(PlatformMediaSession::SystemSleep);
330 }
331
332 void PlatformMediaSessionManager::systemDidWake()
333 {
334     if (m_interrupted)
335         return;
336
337     for (auto session : m_sessions)
338         session->endInterruption(PlatformMediaSession::MayResumePlaying);
339 }
340
341 void PlatformMediaSessionManager::audioOutputDeviceChanged()
342 {
343     updateSessionState();
344 }
345
346 void PlatformMediaSessionManager::stopAllMediaPlaybackForDocument(const Document* document)
347 {
348     Vector<PlatformMediaSession*> sessions = m_sessions;
349     for (auto* session : sessions) {
350         if (session->client().hostingDocument() == document)
351             session->pauseSession();
352     }
353 }
354
355 void PlatformMediaSessionManager::stopAllMediaPlaybackForProcess()
356 {
357     Vector<PlatformMediaSession*> sessions = m_sessions;
358     for (auto* session : sessions)
359         session->pauseSession();
360 }
361
362 }
363
364 #endif