2 * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
28 #import "PlaybackSessionInterfaceAVKit.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>
44 #import <pal/cf/CoreMediaSoftLink.h>
46 SOFTLINK_AVKIT_FRAMEWORK()
47 SOFT_LINK_CLASS_OPTIONAL(AVKit, AVValueTiming)
52 PlaybackSessionInterfaceAVKit::PlaybackSessionInterfaceAVKit(PlaybackSessionModel& model)
53 : m_playerController(adoptNS([[WebAVPlayerController alloc] init]))
54 , m_playbackSessionModel(&model)
56 model.addClient(*this);
57 [m_playerController setPlaybackSessionInterface:this];
58 [m_playerController setDelegate:&model];
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());
72 PlaybackSessionInterfaceAVKit::~PlaybackSessionInterfaceAVKit()
74 [m_playerController setPlaybackSessionInterface:nullptr];
75 [m_playerController setExternalPlaybackActive:false];
80 void PlaybackSessionInterfaceAVKit::durationChanged(double duration)
82 WebAVPlayerController* playerController = m_playerController.get();
84 playerController.contentDuration = duration;
85 playerController.contentDurationWithinEndTimes = duration;
87 // FIXME: we take this as an indication that playback is ready.
88 playerController.canPlay = YES;
89 playerController.canPause = YES;
90 playerController.canTogglePlayback = YES;
91 playerController.hasEnabledAudio = YES;
92 playerController.canSeek = YES;
93 playerController.status = AVPlayerControllerStatusReadyToPlay;
96 void PlaybackSessionInterfaceAVKit::currentTimeChanged(double currentTime, double anchorTime)
98 NSTimeInterval anchorTimeStamp = ![m_playerController rate] ? NAN : anchorTime;
99 AVValueTiming *timing = [getAVValueTimingClass() valueTimingWithAnchorValue:currentTime
100 anchorTimeStamp:anchorTimeStamp rate:0];
102 [m_playerController setTiming:timing];
105 void PlaybackSessionInterfaceAVKit::bufferedTimeChanged(double bufferedTime)
107 WebAVPlayerController* playerController = m_playerController.get();
108 double duration = playerController.contentDuration;
109 double normalizedBufferedTime;
111 normalizedBufferedTime = 0;
113 normalizedBufferedTime = bufferedTime / duration;
114 playerController.loadedTimeRanges = @[@0, @(normalizedBufferedTime)];
117 void PlaybackSessionInterfaceAVKit::rateChanged(bool isPlaying, float playbackRate)
119 [m_playerController setRate:isPlaying ? playbackRate : 0.];
122 void PlaybackSessionInterfaceAVKit::seekableRangesChanged(const TimeRanges& timeRanges, double lastModifiedTime, double liveUpdateInterval)
124 RetainPtr<NSMutableArray> seekableRanges = adoptNS([[NSMutableArray alloc] init]);
126 #if !PLATFORM(WATCHOS)
127 for (unsigned i = 0; i < timeRanges.length(); i++) {
128 double start = timeRanges.start(i).releaseReturnValue();
129 double end = timeRanges.end(i).releaseReturnValue();
131 CMTimeRange range = CMTimeRangeMake(CMTimeMakeWithSeconds(start, 1000), CMTimeMakeWithSeconds(end-start, 1000));
132 [seekableRanges addObject:[NSValue valueWithCMTimeRange:range]];
135 UNUSED_PARAM(timeRanges);
138 [m_playerController setSeekableTimeRanges:seekableRanges.get()];
139 [m_playerController setSeekableTimeRangesLastModifiedTime: lastModifiedTime];
140 [m_playerController setLiveUpdateInterval:liveUpdateInterval];
143 void PlaybackSessionInterfaceAVKit::canPlayFastReverseChanged(bool canPlayFastReverse)
145 [m_playerController setCanScanBackward:canPlayFastReverse];
148 static RetainPtr<NSMutableArray> mediaSelectionOptions(const Vector<MediaSelectionOption>& options)
150 RetainPtr<NSMutableArray> webOptions = adoptNS([[NSMutableArray alloc] initWithCapacity:options.size()]);
151 for (auto& option : options) {
152 RetainPtr<WebAVMediaSelectionOption> webOption = adoptNS([[WebAVMediaSelectionOption alloc] init]);
153 [webOption setLocalizedDisplayName:option.displayName];
154 [webOptions addObject:webOption.get()];
159 void PlaybackSessionInterfaceAVKit::audioMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
161 RetainPtr<NSMutableArray> webOptions = mediaSelectionOptions(options);
162 [m_playerController setAudioMediaSelectionOptions:webOptions.get()];
163 if (selectedIndex < [webOptions count])
164 [m_playerController setCurrentAudioMediaSelectionOption:[webOptions objectAtIndex:static_cast<NSUInteger>(selectedIndex)]];
167 void PlaybackSessionInterfaceAVKit::legibleMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
169 RetainPtr<NSMutableArray> webOptions = mediaSelectionOptions(options);
170 [m_playerController setLegibleMediaSelectionOptions:webOptions.get()];
171 if (selectedIndex < [webOptions count])
172 [m_playerController setCurrentLegibleMediaSelectionOption:[webOptions objectAtIndex:static_cast<NSUInteger>(selectedIndex)]];
175 void PlaybackSessionInterfaceAVKit::externalPlaybackChanged(bool enabled, PlaybackSessionModel::ExternalPlaybackTargetType targetType, const String& localizedDeviceName)
177 AVPlayerControllerExternalPlaybackType externalPlaybackType = AVPlayerControllerExternalPlaybackTypeNone;
178 if (targetType == PlaybackSessionModel::TargetTypeAirPlay)
179 externalPlaybackType = AVPlayerControllerExternalPlaybackTypeAirPlay;
180 else if (targetType == PlaybackSessionModel::TargetTypeTVOut)
181 externalPlaybackType = AVPlayerControllerExternalPlaybackTypeTVOut;
183 WebAVPlayerController* playerController = m_playerController.get();
184 playerController.externalPlaybackAirPlayDeviceLocalizedName = localizedDeviceName;
185 playerController.externalPlaybackType = externalPlaybackType;
186 playerController.externalPlaybackActive = enabled;
189 void PlaybackSessionInterfaceAVKit::wirelessVideoPlaybackDisabledChanged(bool disabled)
191 [m_playerController setAllowsExternalPlayback:!disabled];
194 void PlaybackSessionInterfaceAVKit::mutedChanged(bool muted)
196 [m_playerController setMuted:muted];
199 void PlaybackSessionInterfaceAVKit::volumeChanged(double volume)
201 [m_playerController volumeChanged:volume];
204 void PlaybackSessionInterfaceAVKit::invalidate()
206 if (!m_playbackSessionModel)
209 [m_playerController setDelegate:nullptr];
210 m_playbackSessionModel->removeClient(*this);
211 m_playbackSessionModel = nullptr;
216 #endif // HAVE(AVKIT)
217 #endif // PLATFORM(IOS)