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