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#ifndef PlatformMediaSession_h
27#define PlatformMediaSession_h
28
29#include "Timer.h"
30#include <wtf/LoggerHelper.h>
31#include <wtf/Noncopyable.h>
32#include <wtf/text/WTFString.h>
33
34#if ENABLE(WIRELESS_PLAYBACK_TARGET)
35#include "MediaPlaybackTargetClient.h"
36#endif
37
38namespace WebCore {
39
40class Document;
41class MediaPlaybackTarget;
42class PlatformMediaSessionClient;
43
44class PlatformMediaSession
45#if ENABLE(WIRELESS_PLAYBACK_TARGET)
46 : public MediaPlaybackTargetClient
47#endif
48#if !RELEASE_LOG_DISABLED
49 , private LoggerHelper
50#endif
51{
52 WTF_MAKE_FAST_ALLOCATED;
53public:
54 static std::unique_ptr<PlatformMediaSession> create(PlatformMediaSessionClient&);
55
56 PlatformMediaSession(PlatformMediaSessionClient&);
57 virtual ~PlatformMediaSession();
58
59 enum MediaType {
60 None = 0,
61 Video,
62 VideoAudio,
63 Audio,
64 WebAudio,
65 MediaStreamCapturingAudio,
66 };
67 MediaType mediaType() const;
68 MediaType presentationType() const;
69
70 enum State {
71 Idle,
72 Autoplaying,
73 Playing,
74 Paused,
75 Interrupted,
76 };
77 State state() const { return m_state; }
78 void setState(State);
79
80 enum InterruptionType {
81 NoInterruption,
82 SystemSleep,
83 EnteringBackground,
84 SystemInterruption,
85 SuspendedUnderLock,
86 InvisibleAutoplay,
87 ProcessInactive,
88 PlaybackSuspended,
89 };
90 InterruptionType interruptionType() const { return m_interruptionType; }
91
92 enum EndInterruptionFlags {
93 NoFlags = 0,
94 MayResumePlaying = 1 << 0,
95 };
96
97 enum Characteristics {
98 HasNothing = 0,
99 HasAudio = 1 << 0,
100 HasVideo = 1 << 1,
101 };
102 typedef unsigned CharacteristicsFlags;
103
104 CharacteristicsFlags characteristics() const;
105 void clientCharacteristicsChanged();
106
107 void beginInterruption(InterruptionType);
108 void endInterruption(EndInterruptionFlags);
109
110 virtual void clientWillBeginAutoplaying();
111 virtual bool clientWillBeginPlayback();
112 virtual bool clientWillPausePlayback();
113
114 void pauseSession();
115 void stopSession();
116
117 virtual void suspendBuffering() { }
118 virtual void resumeBuffering() { }
119
120#if ENABLE(VIDEO)
121 uint64_t uniqueIdentifier() const;
122 String title() const;
123 double duration() const;
124 double currentTime() const;
125#endif
126
127 typedef union {
128 double asDouble;
129 } RemoteCommandArgument;
130
131 enum RemoteControlCommandType {
132 NoCommand,
133 PlayCommand,
134 PauseCommand,
135 StopCommand,
136 TogglePlayPauseCommand,
137 BeginSeekingBackwardCommand,
138 EndSeekingBackwardCommand,
139 BeginSeekingForwardCommand,
140 EndSeekingForwardCommand,
141 SeekToPlaybackPositionCommand,
142 };
143 bool canReceiveRemoteControlCommands() const;
144 void didReceiveRemoteControlCommand(RemoteControlCommandType, const RemoteCommandArgument* argument = nullptr);
145 bool supportsSeeking() const;
146
147 enum DisplayType {
148 Normal,
149 Fullscreen,
150 Optimized,
151 };
152 DisplayType displayType() const;
153
154 bool isHidden() const;
155 bool isSuspended() const;
156
157 bool shouldOverrideBackgroundLoadingRestriction() const;
158
159 virtual bool isPlayingToWirelessPlaybackTarget() const { return m_isPlayingToWirelessPlaybackTarget; }
160 void isPlayingToWirelessPlaybackTargetChanged(bool);
161
162#if ENABLE(WIRELESS_PLAYBACK_TARGET)
163 // MediaPlaybackTargetClient
164 void setPlaybackTarget(Ref<MediaPlaybackTarget>&&) override { }
165 void externalOutputDeviceAvailableDidChange(bool) override { }
166 void setShouldPlayToPlaybackTarget(bool) override { }
167#endif
168
169#if PLATFORM(IOS_FAMILY)
170 virtual bool requiresPlaybackTargetRouteMonitoring() const { return false; }
171#endif
172
173 bool activeAudioSessionRequired();
174 bool canProduceAudio() const;
175 void canProduceAudioChanged();
176
177 virtual void resetPlaybackSessionState() { }
178 String sourceApplicationIdentifier() const;
179
180 virtual bool allowsNowPlayingControlsVisibility() const { return false; }
181
182 bool hasPlayedSinceLastInterruption() const { return m_hasPlayedSinceLastInterruption; }
183 void clearHasPlayedSinceLastInterruption() { m_hasPlayedSinceLastInterruption = false; }
184
185#if !RELEASE_LOG_DISABLED
186 const Logger& logger() const final { return m_logger.get(); }
187 const void* logIdentifier() const override { return m_logIdentifier; }
188 const char* logClassName() const override { return "PlatformMediaSession"; }
189 WTFLogChannel& logChannel() const final;
190#endif
191
192protected:
193 PlatformMediaSessionClient& client() const { return m_client; }
194
195private:
196 PlatformMediaSessionClient& m_client;
197 State m_state;
198 State m_stateToRestore;
199 InterruptionType m_interruptionType { NoInterruption };
200 int m_interruptionCount { 0 };
201 bool m_notifyingClient;
202 bool m_isPlayingToWirelessPlaybackTarget { false };
203 bool m_hasPlayedSinceLastInterruption { false };
204
205#if !RELEASE_LOG_DISABLED
206 Ref<const Logger> m_logger;
207 const void* m_logIdentifier;
208#endif
209
210 friend class PlatformMediaSessionManager;
211};
212
213class PlatformMediaSessionClient {
214 WTF_MAKE_NONCOPYABLE(PlatformMediaSessionClient);
215public:
216 PlatformMediaSessionClient() = default;
217
218 virtual PlatformMediaSession::MediaType mediaType() const = 0;
219 virtual PlatformMediaSession::MediaType presentationType() const = 0;
220 virtual PlatformMediaSession::DisplayType displayType() const { return PlatformMediaSession::Normal; }
221 virtual PlatformMediaSession::CharacteristicsFlags characteristics() const = 0;
222
223 virtual void resumeAutoplaying() { }
224 virtual void mayResumePlayback(bool shouldResume) = 0;
225 virtual void suspendPlayback() = 0;
226
227#if ENABLE(VIDEO)
228 virtual uint64_t mediaSessionUniqueIdentifier() const;
229 virtual String mediaSessionTitle() const;
230 virtual double mediaSessionDuration() const;
231 virtual double mediaSessionCurrentTime() const;
232#endif
233
234 virtual bool canReceiveRemoteControlCommands() const = 0;
235 virtual void didReceiveRemoteControlCommand(PlatformMediaSession::RemoteControlCommandType, const PlatformMediaSession::RemoteCommandArgument*) = 0;
236 virtual bool supportsSeeking() const = 0;
237
238 virtual bool canProduceAudio() const { return false; }
239 virtual bool isSuspended() const { return false; };
240
241 virtual bool shouldOverrideBackgroundPlaybackRestriction(PlatformMediaSession::InterruptionType) const = 0;
242 virtual bool shouldOverrideBackgroundLoadingRestriction() const { return false; }
243
244 virtual void wirelessRoutesAvailableDidChange() { }
245 virtual void setWirelessPlaybackTarget(Ref<MediaPlaybackTarget>&&) { }
246 virtual bool isPlayingToWirelessPlaybackTarget() const { return false; }
247 virtual void setShouldPlayToPlaybackTarget(bool) { }
248
249 virtual bool isPlayingOnSecondScreen() const { return false; }
250
251 virtual Document* hostingDocument() const = 0;
252 virtual String sourceApplicationIdentifier() const = 0;
253
254 virtual bool processingUserGestureForMedia() const = 0;
255
256protected:
257 virtual ~PlatformMediaSessionClient() = default;
258};
259
260String convertEnumerationToString(PlatformMediaSession::State);
261String convertEnumerationToString(PlatformMediaSession::InterruptionType);
262String convertEnumerationToString(PlatformMediaSession::RemoteControlCommandType);
263}
264
265namespace WTF {
266
267template<typename Type>
268struct LogArgument;
269
270template <>
271struct LogArgument<WebCore::PlatformMediaSession::State> {
272 static String toString(const WebCore::PlatformMediaSession::State state)
273 {
274 return convertEnumerationToString(state);
275 }
276};
277
278template <>
279struct LogArgument<WebCore::PlatformMediaSession::InterruptionType> {
280 static String toString(const WebCore::PlatformMediaSession::InterruptionType state)
281 {
282 return convertEnumerationToString(state);
283 }
284};
285
286template <>
287struct LogArgument<WebCore::PlatformMediaSession::RemoteControlCommandType> {
288 static String toString(const WebCore::PlatformMediaSession::RemoteControlCommandType command)
289 {
290 return convertEnumerationToString(command);
291 }
292};
293
294} // namespace WTF
295
296#endif // PlatformMediaSession_h
297