Video sometimes flickers when playing to AppleTV
[WebKit-https.git] / Source / WebCore / platform / audio / PlatformMediaSession.cpp
1 /*
2  * Copyright (C) 2014-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 "PlatformMediaSession.h"
28
29 #if ENABLE(VIDEO) || ENABLE(WEB_AUDIO)
30 #include "HTMLMediaElement.h"
31 #include "Logging.h"
32 #include "MediaPlayer.h"
33 #include "PlatformMediaSessionManager.h"
34 #include <wtf/CryptographicallyRandomNumber.h>
35
36 namespace WebCore {
37
38 static const Seconds clientDataBufferingTimerThrottleDelay { 100_ms };
39
40 #if !RELEASE_LOG_DISABLED
41 static uint64_t nextLogIdentifier()
42 {
43     static uint64_t logIdentifier = cryptographicallyRandomNumber();
44     return ++logIdentifier;
45 }
46
47 String convertEnumerationToString(PlatformMediaSession::State state)
48 {
49     static const NeverDestroyed<String> values[] = {
50         MAKE_STATIC_STRING_IMPL("Idle"),
51         MAKE_STATIC_STRING_IMPL("Autoplaying"),
52         MAKE_STATIC_STRING_IMPL("Playing"),
53         MAKE_STATIC_STRING_IMPL("Paused"),
54         MAKE_STATIC_STRING_IMPL("Interrupted"),
55     };
56     static_assert(!static_cast<size_t>(PlatformMediaSession::Idle), "PlatformMediaSession::Idle is not 0 as expected");
57     static_assert(static_cast<size_t>(PlatformMediaSession::Autoplaying == 1), "PlatformMediaSession::Autoplaying is not 1 as expected");
58     static_assert(static_cast<size_t>(PlatformMediaSession::Playing == 2), "PlatformMediaSession::Playing is not 2 as expected");
59     static_assert(static_cast<size_t>(PlatformMediaSession::Paused == 3), "PlatformMediaSession::Paused is not 3 as expected");
60     static_assert(static_cast<size_t>(PlatformMediaSession::Interrupted == 4), "PlatformMediaSession::Interrupted is not 4 as expected");
61     ASSERT(static_cast<size_t>(state) < WTF_ARRAY_LENGTH(values));
62     return values[static_cast<size_t>(state)];
63 }
64
65 String convertEnumerationToString(PlatformMediaSession::InterruptionType type)
66 {
67     static const NeverDestroyed<String> values[] = {
68         MAKE_STATIC_STRING_IMPL("NoInterruption"),
69         MAKE_STATIC_STRING_IMPL("SystemSleep"),
70         MAKE_STATIC_STRING_IMPL("EnteringBackground"),
71         MAKE_STATIC_STRING_IMPL("SystemInterruption"),
72         MAKE_STATIC_STRING_IMPL("SuspendedUnderLock"),
73         MAKE_STATIC_STRING_IMPL("InvisibleAutoplay"),
74         MAKE_STATIC_STRING_IMPL("ProcessInactive"),
75     };
76     static_assert(!static_cast<size_t>(PlatformMediaSession::NoInterruption), "PlatformMediaSession::NoInterruption is not 0 as expected");
77     static_assert(static_cast<size_t>(PlatformMediaSession::SystemSleep == 1), "PlatformMediaSession::SystemSleep is not 1 as expected");
78     static_assert(static_cast<size_t>(PlatformMediaSession::EnteringBackground == 2), "PlatformMediaSession::EnteringBackground is not 2 as expected");
79     static_assert(static_cast<size_t>(PlatformMediaSession::SystemInterruption == 3), "PlatformMediaSession::SystemInterruption is not 3 as expected");
80     static_assert(static_cast<size_t>(PlatformMediaSession::SuspendedUnderLock == 4), "PlatformMediaSession::SuspendedUnderLock is not 4 as expected");
81     static_assert(static_cast<size_t>(PlatformMediaSession::InvisibleAutoplay == 5), "PlatformMediaSession::InvisibleAutoplay is not 5 as expected");
82     static_assert(static_cast<size_t>(PlatformMediaSession::ProcessInactive == 6), "PlatformMediaSession::ProcessInactive is not 6 as expected");
83     ASSERT(static_cast<size_t>(type) < WTF_ARRAY_LENGTH(values));
84     return values[static_cast<size_t>(type)];
85 }
86
87 #endif
88
89 std::unique_ptr<PlatformMediaSession> PlatformMediaSession::create(PlatformMediaSessionClient& client)
90 {
91     return std::make_unique<PlatformMediaSession>(client);
92 }
93
94 PlatformMediaSession::PlatformMediaSession(PlatformMediaSessionClient& client)
95     : m_client(client)
96     , m_state(Idle)
97     , m_stateToRestore(Idle)
98     , m_notifyingClient(false)
99 #if !RELEASE_LOG_DISABLED
100     , m_logger(client.hostingDocument()->logger())
101     , m_logIdentifier(nextLogIdentifier())
102 #endif
103 {
104     ASSERT(m_client.mediaType() >= None && m_client.mediaType() <= MediaStreamCapturingAudio);
105     PlatformMediaSessionManager::sharedManager().addSession(*this);
106 }
107
108 PlatformMediaSession::~PlatformMediaSession()
109 {
110     PlatformMediaSessionManager::sharedManager().removeSession(*this);
111 }
112
113 void PlatformMediaSession::setState(State state)
114 {
115     if (state == m_state)
116         return;
117
118     INFO_LOG(LOGIDENTIFIER, state);
119     m_state = state;
120     PlatformMediaSessionManager::sharedManager().sessionStateChanged(*this);
121 }
122
123 void PlatformMediaSession::beginInterruption(InterruptionType type)
124 {
125     INFO_LOG(LOGIDENTIFIER, "state = ", m_state, ", interruption type = ", type, ", interruption count = ", m_interruptionCount);
126
127     // When interruptions are overridden, m_interruptionType doesn't get set.
128     // Give nested interruptions a chance when the previous interruptions were overridden.
129     if (++m_interruptionCount > 1 && m_interruptionType != NoInterruption)
130         return;
131
132     if (client().shouldOverrideBackgroundPlaybackRestriction(type)) {
133         INFO_LOG(LOGIDENTIFIER, "returning early because client says to override interruption");
134         return;
135     }
136
137     m_stateToRestore = state();
138     m_notifyingClient = true;
139     setState(Interrupted);
140     m_interruptionType = type;
141     client().suspendPlayback();
142     m_notifyingClient = false;
143 }
144
145 void PlatformMediaSession::endInterruption(EndInterruptionFlags flags)
146 {
147     INFO_LOG(LOGIDENTIFIER, "flags = ", (int)flags, ", stateToRestore = ", m_stateToRestore, ", interruption count = ", m_interruptionCount);
148
149     if (!m_interruptionCount) {
150         INFO_LOG(LOGIDENTIFIER, "!! ignoring spurious interruption end !!");
151         return;
152     }
153
154     if (--m_interruptionCount)
155         return;
156
157     if (m_interruptionType == NoInterruption)
158         return;
159
160     State stateToRestore = m_stateToRestore;
161     m_stateToRestore = Idle;
162     m_interruptionType = NoInterruption;
163     setState(stateToRestore);
164
165     if (stateToRestore == Autoplaying)
166         client().resumeAutoplaying();
167
168     bool shouldResume = flags & MayResumePlaying && stateToRestore == Playing;
169     client().mayResumePlayback(shouldResume);
170 }
171
172 void PlatformMediaSession::clientWillBeginAutoplaying()
173 {
174     if (m_notifyingClient)
175         return;
176
177     INFO_LOG(LOGIDENTIFIER, "state = ", m_state);
178     if (state() == Interrupted) {
179         m_stateToRestore = Autoplaying;
180         INFO_LOG(LOGIDENTIFIER, "      setting stateToRestore to \"Autoplaying\"");
181         return;
182     }
183
184     setState(Autoplaying);
185 }
186
187 bool PlatformMediaSession::clientWillBeginPlayback()
188 {
189     if (m_notifyingClient)
190         return true;
191
192     INFO_LOG(LOGIDENTIFIER, "state = ", m_state);
193
194     if (!PlatformMediaSessionManager::sharedManager().sessionWillBeginPlayback(*this)) {
195         if (state() == Interrupted)
196             m_stateToRestore = Playing;
197         return false;
198     }
199
200     setState(Playing);
201     return true;
202 }
203
204 bool PlatformMediaSession::clientWillPausePlayback()
205 {
206     if (m_notifyingClient)
207         return true;
208
209     INFO_LOG(LOGIDENTIFIER, "state = ", m_state);
210     if (state() == Interrupted) {
211         m_stateToRestore = Paused;
212         INFO_LOG(LOGIDENTIFIER, "      setting stateToRestore to \"Paused\"");
213         return false;
214     }
215     
216     setState(Paused);
217     PlatformMediaSessionManager::sharedManager().sessionWillEndPlayback(*this);
218     return true;
219 }
220
221 void PlatformMediaSession::pauseSession()
222 {
223     INFO_LOG(LOGIDENTIFIER);
224     m_client.suspendPlayback();
225 }
226
227 void PlatformMediaSession::stopSession()
228 {
229     INFO_LOG(LOGIDENTIFIER);
230     m_client.suspendPlayback();
231     PlatformMediaSessionManager::sharedManager().removeSession(*this);
232 }
233
234 PlatformMediaSession::MediaType PlatformMediaSession::mediaType() const
235 {
236     return m_client.mediaType();
237 }
238
239 PlatformMediaSession::MediaType PlatformMediaSession::presentationType() const
240 {
241     return m_client.presentationType();
242 }
243
244 PlatformMediaSession::CharacteristicsFlags PlatformMediaSession::characteristics() const
245 {
246     return m_client.characteristics();
247 }
248
249 #if ENABLE(VIDEO)
250 uint64_t PlatformMediaSession::uniqueIdentifier() const
251 {
252     return m_client.mediaSessionUniqueIdentifier();
253 }
254
255 String PlatformMediaSession::title() const
256 {
257     return m_client.mediaSessionTitle();
258 }
259
260 double PlatformMediaSession::duration() const
261 {
262     return m_client.mediaSessionDuration();
263 }
264
265 double PlatformMediaSession::currentTime() const
266 {
267     return m_client.mediaSessionCurrentTime();
268 }
269 #endif
270     
271 bool PlatformMediaSession::canReceiveRemoteControlCommands() const
272 {
273     return m_client.canReceiveRemoteControlCommands();
274 }
275
276 void PlatformMediaSession::didReceiveRemoteControlCommand(RemoteControlCommandType command, const PlatformMediaSession::RemoteCommandArgument* argument)
277 {
278     m_client.didReceiveRemoteControlCommand(command, argument);
279 }
280
281 bool PlatformMediaSession::supportsSeeking() const
282 {
283     return m_client.supportsSeeking();
284 }
285
286 String PlatformMediaSession::sourceApplicationIdentifier() const
287 {
288     return m_client.sourceApplicationIdentifier();
289 }
290
291 bool PlatformMediaSession::isSuspended() const
292 {
293     return m_client.isSuspended();
294 }
295
296 bool PlatformMediaSession::shouldOverrideBackgroundLoadingRestriction() const
297 {
298     return m_client.shouldOverrideBackgroundLoadingRestriction();
299 }
300
301 void PlatformMediaSession::isPlayingToWirelessPlaybackTargetChanged(bool isWireless)
302 {
303     if (isWireless == m_isPlayingToWirelessPlaybackTarget)
304         return;
305
306     m_isPlayingToWirelessPlaybackTarget = isWireless;
307
308     // Save and restore the interruption count so it doesn't get out of sync if beginInterruption is called because
309     // if we in the background.
310     int interruptionCount = m_interruptionCount;
311     PlatformMediaSessionManager::sharedManager().sessionIsPlayingToWirelessPlaybackTargetChanged(*this);
312     m_interruptionCount = interruptionCount;
313 }
314
315 PlatformMediaSession::DisplayType PlatformMediaSession::displayType() const
316 {
317     return m_client.displayType();
318 }
319
320 bool PlatformMediaSession::activeAudioSessionRequired()
321 {
322     if (mediaType() == PlatformMediaSession::None)
323         return false;
324     if (state() != PlatformMediaSession::State::Playing)
325         return false;
326     return canProduceAudio();
327 }
328
329 bool PlatformMediaSession::canProduceAudio() const
330 {
331     return m_client.canProduceAudio();
332 }
333
334 void PlatformMediaSession::canProduceAudioChanged()
335 {
336     PlatformMediaSessionManager::sharedManager().sessionCanProduceAudioChanged(*this);
337 }
338
339 #if ENABLE(VIDEO)
340 uint64_t PlatformMediaSessionClient::mediaSessionUniqueIdentifier() const
341 {
342     return 0;
343 }
344
345 String PlatformMediaSessionClient::mediaSessionTitle() const
346 {
347     return String();
348 }
349
350 double PlatformMediaSessionClient::mediaSessionDuration() const
351 {
352     return MediaPlayer::invalidTime();
353 }
354
355 double PlatformMediaSessionClient::mediaSessionCurrentTime() const
356 {
357     return MediaPlayer::invalidTime();
358 }
359 #endif
360
361 void PlatformMediaSession::clientCharacteristicsChanged()
362 {
363     PlatformMediaSessionManager::sharedManager().clientCharacteristicsChanged(*this);
364 }
365
366 #if !RELEASE_LOG_DISABLED
367 WTFLogChannel& PlatformMediaSession::logChannel() const
368 {
369     return LogMedia;
370 }
371 #endif
372
373 }
374
375 #endif