975fc50e2fa32b7324fe571403e11f621cbd9556
[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 Vector<PlatformMediaSession*> PlatformMediaSessionManager::currentSessionsMatching(std::function<bool(const PlatformMediaSession &)> filter)
284 {
285     Vector<PlatformMediaSession*> matchingSessions;
286     for (auto& session : m_sessions) {
287         if (filter(*session))
288             matchingSessions.append(session);
289     }
290     return matchingSessions;
291 }
292     
293 bool PlatformMediaSessionManager::sessionCanLoadMedia(const PlatformMediaSession& session) const
294 {
295     return session.state() == PlatformMediaSession::Playing || !session.isHidden() || session.shouldOverrideBackgroundLoadingRestriction();
296 }
297
298 void PlatformMediaSessionManager::applicationWillEnterBackground() const
299 {
300     LOG(Media, "PlatformMediaSessionManager::applicationWillEnterBackground");
301
302     if (m_isApplicationInBackground)
303         return;
304
305     m_isApplicationInBackground = true;
306     
307     Vector<PlatformMediaSession*> sessions = m_sessions;
308     for (auto* session : sessions) {
309         if (m_restrictions[session->mediaType()] & BackgroundProcessPlaybackRestricted)
310             session->beginInterruption(PlatformMediaSession::EnteringBackground);
311     }
312 }
313
314 void PlatformMediaSessionManager::applicationDidEnterForeground() const
315 {
316     LOG(Media, "PlatformMediaSessionManager::applicationDidEnterForeground");
317
318     if (!m_isApplicationInBackground)
319         return;
320
321     m_isApplicationInBackground = false;
322
323     Vector<PlatformMediaSession*> sessions = m_sessions;
324     for (auto* session : sessions) {
325         if (m_restrictions[session->mediaType()] & BackgroundProcessPlaybackRestricted)
326             session->endInterruption(PlatformMediaSession::MayResumePlaying);
327     }
328 }
329
330 void PlatformMediaSessionManager::sessionIsPlayingToWirelessPlaybackTargetChanged(PlatformMediaSession& session)
331 {
332     if (!m_isApplicationInBackground || !(m_restrictions[session.mediaType()] & BackgroundProcessPlaybackRestricted))
333         return;
334
335     if (session.state() != PlatformMediaSession::Interrupted)
336         session.beginInterruption(PlatformMediaSession::EnteringBackground);
337 }
338
339 void PlatformMediaSessionManager::sessionCanProduceAudioChanged(PlatformMediaSession&)
340 {
341     updateSessionState();
342 }
343
344 #if !PLATFORM(COCOA)
345 void PlatformMediaSessionManager::updateSessionState()
346 {
347 }
348 #endif
349
350 void PlatformMediaSessionManager::didReceiveRemoteControlCommand(PlatformMediaSession::RemoteControlCommandType command, const PlatformMediaSession::RemoteCommandArgument* argument)
351 {
352     PlatformMediaSession* activeSession = currentSession();
353     if (!activeSession || !activeSession->canReceiveRemoteControlCommands())
354         return;
355     activeSession->didReceiveRemoteControlCommand(command, argument);
356 }
357
358 bool PlatformMediaSessionManager::supportsSeeking() const
359 {
360     PlatformMediaSession* activeSession = currentSession();
361     if (!activeSession)
362         return false;
363     return activeSession->supportsSeeking();
364 }
365
366 void PlatformMediaSessionManager::systemWillSleep()
367 {
368     if (m_interrupted)
369         return;
370
371     for (auto* session : m_sessions)
372         session->beginInterruption(PlatformMediaSession::SystemSleep);
373 }
374
375 void PlatformMediaSessionManager::systemDidWake()
376 {
377     if (m_interrupted)
378         return;
379
380     for (auto* session : m_sessions)
381         session->endInterruption(PlatformMediaSession::MayResumePlaying);
382 }
383
384 void PlatformMediaSessionManager::audioOutputDeviceChanged()
385 {
386     updateSessionState();
387 }
388
389 void PlatformMediaSessionManager::stopAllMediaPlaybackForDocument(const Document* document)
390 {
391     Vector<PlatformMediaSession*> sessions = m_sessions;
392     for (auto* session : sessions) {
393         if (session->client().hostingDocument() == document)
394             session->pauseSession();
395     }
396 }
397
398 void PlatformMediaSessionManager::stopAllMediaPlaybackForProcess()
399 {
400     Vector<PlatformMediaSession*> sessions = m_sessions;
401     for (auto* session : sessions)
402         session->stopSession();
403 }
404
405 }
406
407 #endif