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