Make Remote Control commands testable
[WebKit-https.git] / Source / WebCore / platform / audio / MediaSessionManager.cpp
1 /*
2  * Copyright (C) 2013-2014 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 "MediaSessionManager.h"
28
29 #include "Logging.h"
30 #include "MediaSession.h"
31
32 namespace WebCore {
33
34 #if !PLATFORM(IOS)
35 MediaSessionManager& MediaSessionManager::sharedManager()
36 {
37     DEPRECATED_DEFINE_STATIC_LOCAL(MediaSessionManager, manager, ());
38     return manager;
39 }
40 #endif
41
42 MediaSessionManager::MediaSessionManager()
43     : m_interrupted(false)
44 {
45     resetRestrictions();
46 }
47
48 void MediaSessionManager::resetRestrictions()
49 {
50     m_restrictions[MediaSession::Video] = NoRestrictions;
51     m_restrictions[MediaSession::Audio] = NoRestrictions;
52     m_restrictions[MediaSession::WebAudio] = NoRestrictions;
53 }
54
55 bool MediaSessionManager::has(MediaSession::MediaType type) const
56 {
57     ASSERT(type >= MediaSession::None && type <= MediaSession::WebAudio);
58
59     for (auto* session : m_sessions) {
60         if (session->mediaType() == type)
61             return true;
62     }
63
64     return false;
65 }
66
67 int MediaSessionManager::count(MediaSession::MediaType type) const
68 {
69     ASSERT(type >= MediaSession::None && type <= MediaSession::WebAudio);
70
71     int count = 0;
72     for (auto* session : m_sessions) {
73         if (session->mediaType() == type)
74             ++count;
75     }
76
77     return count;
78 }
79
80 void MediaSessionManager::beginInterruption()
81 {
82     LOG(Media, "MediaSessionManager::beginInterruption");
83
84     m_interrupted = true;
85     Vector<MediaSession*> sessions = m_sessions;
86     for (auto* session : sessions)
87         session->beginInterruption();
88 }
89
90 void MediaSessionManager::endInterruption(MediaSession::EndInterruptionFlags flags)
91 {
92     LOG(Media, "MediaSessionManager::endInterruption");
93
94     m_interrupted = false;
95     Vector<MediaSession*> sessions = m_sessions;
96     for (auto* session : sessions)
97         session->endInterruption(flags);
98 }
99
100 void MediaSessionManager::addSession(MediaSession& session)
101 {
102     LOG(Media, "MediaSessionManager::addSession - %p", &session);
103     
104     m_sessions.append(&session);
105     if (m_interrupted)
106         session.setState(MediaSession::Interrupted);
107     updateSessionState();
108
109     if (!m_remoteCommandListener)
110         m_remoteCommandListener = RemoteCommandListener::create(*this);
111
112     if (m_clients.isEmpty() || !(session.mediaType() == MediaSession::Video || session.mediaType() == MediaSession::Audio))
113         return;
114
115     for (auto& client : m_clients)
116         client->startListeningForRemoteControlCommands();
117 }
118
119 void MediaSessionManager::removeSession(MediaSession& session)
120 {
121     LOG(Media, "MediaSessionManager::removeSession - %p", &session);
122     
123     size_t index = m_sessions.find(&session);
124     ASSERT(index != notFound);
125     if (index == notFound)
126         return;
127     
128     m_sessions.remove(index);
129     updateSessionState();
130
131     if (m_sessions.isEmpty())
132         m_remoteCommandListener = nullptr;
133
134     if (m_clients.isEmpty() || !(session.mediaType() == MediaSession::Video || session.mediaType() == MediaSession::Audio))
135         return;
136
137     for (auto& client : m_clients)
138         client->startListeningForRemoteControlCommands();
139 }
140
141 void MediaSessionManager::addRestriction(MediaSession::MediaType type, SessionRestrictions restriction)
142 {
143     ASSERT(type > MediaSession::None && type <= MediaSession::WebAudio);
144     m_restrictions[type] |= restriction;
145 }
146
147 void MediaSessionManager::removeRestriction(MediaSession::MediaType type, SessionRestrictions restriction)
148 {
149     ASSERT(type > MediaSession::None && type <= MediaSession::WebAudio);
150     m_restrictions[type] &= ~restriction;
151 }
152
153 MediaSessionManager::SessionRestrictions MediaSessionManager::restrictions(MediaSession::MediaType type)
154 {
155     ASSERT(type > MediaSession::None && type <= MediaSession::WebAudio);
156     return m_restrictions[type];
157 }
158
159 void MediaSessionManager::sessionWillBeginPlayback(MediaSession& session)
160 {
161     LOG(Media, "MediaSessionManager::sessionWillBeginPlayback - %p", &session);
162     
163     setCurrentSession(session);
164
165     if (!m_clients.isEmpty() && (session.mediaType() == MediaSession::Video || session.mediaType() == MediaSession::Audio)) {
166         for (auto& client : m_clients)
167             client->didBeginPlayback();
168     }
169
170     MediaSession::MediaType sessionType = session.mediaType();
171     SessionRestrictions restrictions = m_restrictions[sessionType];
172     if (!restrictions & ConcurrentPlaybackNotPermitted)
173         return;
174
175     Vector<MediaSession*> sessions = m_sessions;
176     for (auto* oneSession : sessions) {
177         if (oneSession == &session)
178             continue;
179         if (oneSession->mediaType() != sessionType)
180             continue;
181         if (restrictions & ConcurrentPlaybackNotPermitted)
182             oneSession->pauseSession();
183     }
184 }
185     
186 void MediaSessionManager::sessionWillEndPlayback(MediaSession& session)
187 {
188     LOG(Media, "MediaSessionManager::sessionWillEndPlayback - %p", &session);
189     
190     if (m_sessions.size() < 2)
191         return;
192     
193     size_t pausingSessionIndex = notFound;
194     size_t lastPlayingSessionIndex = notFound;
195     for (size_t i = 0; i < m_sessions.size(); ++i) {
196         MediaSession* oneSession = m_sessions[i];
197         
198         if (oneSession == &session) {
199             pausingSessionIndex = i;
200             continue;
201         }
202         if (oneSession->state() == MediaSession::Playing) {
203             lastPlayingSessionIndex = i;
204             continue;
205         }
206         if (oneSession->state() != MediaSession::Playing)
207             break;
208     }
209     if (lastPlayingSessionIndex == notFound || pausingSessionIndex == notFound)
210         return;
211     
212     if (pausingSessionIndex > lastPlayingSessionIndex)
213         return;
214     
215     m_sessions.remove(pausingSessionIndex);
216     m_sessions.insert(lastPlayingSessionIndex, &session);
217     
218     LOG(Media, "MediaSessionManager::sessionWillEndPlayback - session moved from index %zu to %zu", pausingSessionIndex, lastPlayingSessionIndex);
219 }
220
221 void MediaSessionManager::setCurrentSession(MediaSession& session)
222 {
223     LOG(Media, "MediaSessionManager::setCurrentSession - %p", &session);
224     
225     if (m_sessions.size() < 2)
226         return;
227     
228     size_t index = m_sessions.find(&session);
229     ASSERT(index != notFound);
230     if (!index || index == notFound)
231         return;
232
233     m_sessions.remove(index);
234     m_sessions.insert(0, &session);
235     
236     LOG(Media, "MediaSessionManager::setCurrentSession - session moved from index %zu to 0", index);
237 }
238     
239 MediaSession* MediaSessionManager::currentSession()
240 {
241     if (!m_sessions.size())
242         return nullptr;
243
244     return m_sessions[0];
245 }
246     
247 bool MediaSessionManager::sessionRestrictsInlineVideoPlayback(const MediaSession& session) const
248 {
249     MediaSession::MediaType sessionType = session.mediaType();
250     if (sessionType != MediaSession::Video)
251         return false;
252
253     return m_restrictions[sessionType] & InlineVideoPlaybackRestricted;
254 }
255
256 void MediaSessionManager::applicationWillEnterBackground() const
257 {
258     LOG(Media, "MediaSessionManager::applicationWillEnterBackground");
259     Vector<MediaSession*> sessions = m_sessions;
260     for (auto* session : sessions) {
261         if (m_restrictions[session->mediaType()] & BackgroundPlaybackNotPermitted)
262             session->beginInterruption();
263     }
264 }
265
266 void MediaSessionManager::applicationWillEnterForeground() const
267 {
268     LOG(Media, "MediaSessionManager::applicationWillEnterForeground");
269     Vector<MediaSession*> sessions = m_sessions;
270     for (auto* session : sessions) {
271         if (m_restrictions[session->mediaType()] & BackgroundPlaybackNotPermitted)
272             session->endInterruption(MediaSession::MayResumePlaying);
273     }
274 }
275
276 #if !PLATFORM(COCOA)
277 void MediaSessionManager::updateSessionState()
278 {
279 }
280 #endif
281
282 void MediaSessionManager::didReceiveRemoteControlCommand(MediaSession::RemoteControlCommandType command)
283 {
284     MediaSession* activeSession = currentSession();
285     if (!activeSession || !activeSession->canReceiveRemoteControlCommands())
286         return;
287     activeSession->didReceiveRemoteControlCommand(command);
288 }
289
290 void MediaSessionManager::addClient(MediaSessionManagerClient* client)
291 {
292     ASSERT(!m_clients.contains(client));
293     m_clients.append(client);
294 }
295
296 void MediaSessionManager::removeClient(MediaSessionManagerClient* client)
297 {
298     ASSERT(m_clients.contains(client));
299     m_clients.remove(m_clients.find(client));
300 }
301
302 }