0a28548b7f5951619534432da9a0007ddb9ae864
[WebKit-https.git] / Source / WebCore / platform / ios / PlaybackSessionInterfaceAVKit.mm
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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26
27 #import "config.h"
28 #import "PlaybackSessionInterfaceAVKit.h"
29
30 #if PLATFORM(IOS)
31 #if HAVE(AVKIT)
32
33 #import "Logging.h"
34 #import "MediaSelectionOption.h"
35 #import "PlaybackSessionModel.h"
36 #import "TimeRanges.h"
37 #import "WebAVPlayerController.h"
38 #import <AVFoundation/AVTime.h>
39 #import <pal/spi/cocoa/AVKitSPI.h>
40 #import <wtf/RetainPtr.h>
41 #import <wtf/text/CString.h>
42 #import <wtf/text/WTFString.h>
43
44 #import <pal/cf/CoreMediaSoftLink.h>
45
46 SOFTLINK_AVKIT_FRAMEWORK()
47 SOFT_LINK_CLASS_OPTIONAL(AVKit, AVValueTiming)
48
49 namespace WebCore {
50 using namespace PAL;
51
52 PlaybackSessionInterfaceAVKit::PlaybackSessionInterfaceAVKit(PlaybackSessionModel& model)
53     : m_playerController(adoptNS([[WebAVPlayerController alloc] init]))
54     , m_playbackSessionModel(&model)
55 {
56     model.addClient(*this);
57     [m_playerController setPlaybackSessionInterface:this];
58     [m_playerController setDelegate:&model];
59
60     durationChanged(model.duration());
61     currentTimeChanged(model.currentTime(), [[NSProcessInfo processInfo] systemUptime]);
62     bufferedTimeChanged(model.bufferedTime());
63     rateChanged(model.isPlaying(), model.playbackRate());
64     seekableRangesChanged(model.seekableRanges(), model.seekableTimeRangesLastModifiedTime(), model.liveUpdateInterval());
65     canPlayFastReverseChanged(model.canPlayFastReverse());
66     audioMediaSelectionOptionsChanged(model.audioMediaSelectionOptions(), model.audioMediaSelectedIndex());
67     legibleMediaSelectionOptionsChanged(model.legibleMediaSelectionOptions(), model.legibleMediaSelectedIndex());
68     externalPlaybackChanged(model.externalPlaybackEnabled(), model.externalPlaybackTargetType(), model.externalPlaybackLocalizedDeviceName());
69     wirelessVideoPlaybackDisabledChanged(model.wirelessVideoPlaybackDisabled());
70 }
71
72 PlaybackSessionInterfaceAVKit::~PlaybackSessionInterfaceAVKit()
73 {
74     [m_playerController setPlaybackSessionInterface:nullptr];
75     [m_playerController setExternalPlaybackActive:false];
76
77     invalidate();
78 }
79
80 void PlaybackSessionInterfaceAVKit::resetMediaState()
81 {
82     [m_playerController resetMediaState];
83 }
84
85 void PlaybackSessionInterfaceAVKit::durationChanged(double duration)
86 {
87     WebAVPlayerController* playerController = m_playerController.get();
88
89     playerController.contentDuration = duration;
90     playerController.contentDurationWithinEndTimes = duration;
91
92     // FIXME: we take this as an indication that playback is ready.
93     playerController.canPlay = YES;
94     playerController.canPause = YES;
95     playerController.canTogglePlayback = YES;
96     playerController.hasEnabledAudio = YES;
97     playerController.canSeek = YES;
98     playerController.status = AVPlayerControllerStatusReadyToPlay;
99 }
100
101 void PlaybackSessionInterfaceAVKit::currentTimeChanged(double currentTime, double anchorTime)
102 {
103     NSTimeInterval anchorTimeStamp = ![m_playerController rate] ? NAN : anchorTime;
104     AVValueTiming *timing = [getAVValueTimingClass() valueTimingWithAnchorValue:currentTime
105         anchorTimeStamp:anchorTimeStamp rate:0];
106
107     [m_playerController setTiming:timing];
108 }
109
110 void PlaybackSessionInterfaceAVKit::bufferedTimeChanged(double bufferedTime)
111 {
112     WebAVPlayerController* playerController = m_playerController.get();
113     double duration = playerController.contentDuration;
114     double normalizedBufferedTime;
115     if (!duration)
116         normalizedBufferedTime = 0;
117     else
118         normalizedBufferedTime = bufferedTime / duration;
119     playerController.loadedTimeRanges = @[@0, @(normalizedBufferedTime)];
120 }
121
122 void PlaybackSessionInterfaceAVKit::rateChanged(bool isPlaying, float playbackRate)
123 {
124     [m_playerController setRate:isPlaying ? playbackRate : 0.];
125 }
126
127 void PlaybackSessionInterfaceAVKit::seekableRangesChanged(const TimeRanges& timeRanges, double lastModifiedTime, double liveUpdateInterval)
128 {
129     RetainPtr<NSMutableArray> seekableRanges = adoptNS([[NSMutableArray alloc] init]);
130
131 #if !PLATFORM(WATCHOS)
132     for (unsigned i = 0; i < timeRanges.length(); i++) {
133         double start = timeRanges.start(i).releaseReturnValue();
134         double end = timeRanges.end(i).releaseReturnValue();
135
136         CMTimeRange range = CMTimeRangeMake(CMTimeMakeWithSeconds(start, 1000), CMTimeMakeWithSeconds(end-start, 1000));
137         [seekableRanges addObject:[NSValue valueWithCMTimeRange:range]];
138     }
139 #else
140     UNUSED_PARAM(timeRanges);
141 #endif
142
143     [m_playerController setSeekableTimeRanges:seekableRanges.get()];
144     [m_playerController setSeekableTimeRangesLastModifiedTime: lastModifiedTime];
145     [m_playerController setLiveUpdateInterval:liveUpdateInterval];
146 }
147
148 void PlaybackSessionInterfaceAVKit::canPlayFastReverseChanged(bool canPlayFastReverse)
149 {
150     [m_playerController setCanScanBackward:canPlayFastReverse];
151 }
152
153 static RetainPtr<NSMutableArray> mediaSelectionOptions(const Vector<MediaSelectionOption>& options)
154 {
155     RetainPtr<NSMutableArray> webOptions = adoptNS([[NSMutableArray alloc] initWithCapacity:options.size()]);
156     for (auto& option : options) {
157         RetainPtr<WebAVMediaSelectionOption> webOption = adoptNS([[WebAVMediaSelectionOption alloc] init]);
158         [webOption setLocalizedDisplayName:option.displayName];
159         [webOptions addObject:webOption.get()];
160     }
161     return webOptions;
162 }
163
164 void PlaybackSessionInterfaceAVKit::audioMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
165 {
166     RetainPtr<NSMutableArray> webOptions = mediaSelectionOptions(options);
167     [m_playerController setAudioMediaSelectionOptions:webOptions.get()];
168     if (selectedIndex < [webOptions count])
169         [m_playerController setCurrentAudioMediaSelectionOption:[webOptions objectAtIndex:static_cast<NSUInteger>(selectedIndex)]];
170 }
171
172 void PlaybackSessionInterfaceAVKit::legibleMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
173 {
174     RetainPtr<NSMutableArray> webOptions = mediaSelectionOptions(options);
175     [m_playerController setLegibleMediaSelectionOptions:webOptions.get()];
176     if (selectedIndex < [webOptions count])
177         [m_playerController setCurrentLegibleMediaSelectionOption:[webOptions objectAtIndex:static_cast<NSUInteger>(selectedIndex)]];
178 }
179
180 void PlaybackSessionInterfaceAVKit::externalPlaybackChanged(bool enabled, PlaybackSessionModel::ExternalPlaybackTargetType targetType, const String& localizedDeviceName)
181 {
182     AVPlayerControllerExternalPlaybackType externalPlaybackType = AVPlayerControllerExternalPlaybackTypeNone;
183     if (targetType == PlaybackSessionModel::TargetTypeAirPlay)
184         externalPlaybackType = AVPlayerControllerExternalPlaybackTypeAirPlay;
185     else if (targetType == PlaybackSessionModel::TargetTypeTVOut)
186         externalPlaybackType = AVPlayerControllerExternalPlaybackTypeTVOut;
187
188     WebAVPlayerController* playerController = m_playerController.get();
189     playerController.externalPlaybackAirPlayDeviceLocalizedName = localizedDeviceName;
190     playerController.externalPlaybackType = externalPlaybackType;
191     playerController.externalPlaybackActive = enabled;
192 }
193
194 void PlaybackSessionInterfaceAVKit::wirelessVideoPlaybackDisabledChanged(bool disabled)
195 {
196     [m_playerController setAllowsExternalPlayback:!disabled];
197 }
198
199 void PlaybackSessionInterfaceAVKit::mutedChanged(bool muted)
200 {
201     [m_playerController setMuted:muted];
202 }
203
204 void PlaybackSessionInterfaceAVKit::volumeChanged(double volume)
205 {
206     [m_playerController volumeChanged:volume];
207 }
208
209 void PlaybackSessionInterfaceAVKit::invalidate()
210 {
211     if (!m_playbackSessionModel)
212         return;
213
214     [m_playerController setDelegate:nullptr];
215     m_playbackSessionModel->removeClient(*this);
216     m_playbackSessionModel = nullptr;
217 }
218
219 }
220
221 #endif // HAVE(AVKIT)
222 #endif // PLATFORM(IOS)