1/*
2 * Copyright (C) 2011-2014 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#include "config.h"
27
28#if ENABLE(VIDEO) && USE(AVFOUNDATION)
29
30#include "MediaPlayerPrivateAVFoundation.h"
31
32#include "DocumentLoader.h"
33#include "FloatConversion.h"
34#include "Frame.h"
35#include "FrameView.h"
36#include "GraphicsContext.h"
37#include "InbandTextTrackPrivateAVF.h"
38#include "InbandTextTrackPrivateClient.h"
39#include "URL.h"
40#include "Logging.h"
41#include "PlatformLayer.h"
42#include "PlatformTimeRanges.h"
43#include "Settings.h"
44#include "SoftLinking.h"
45#include <CoreMedia/CoreMedia.h>
46#include <runtime/DataView.h>
47#include <runtime/Uint16Array.h>
48#include <wtf/MainThread.h>
49#include <wtf/text/CString.h>
50
51namespace WebCore {
52
53MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation(MediaPlayer* player)
54    : m_player(player)
55    , m_weakPtrFactory(this)
56    , m_queuedNotifications()
57    , m_queueMutex()
58    , m_networkState(MediaPlayer::Empty)
59    , m_readyState(MediaPlayer::HaveNothing)
60    , m_preload(MediaPlayer::Auto)
61    , m_cachedMaxTimeLoaded(0)
62    , m_cachedMaxTimeSeekable(0)
63    , m_cachedMinTimeSeekable(0)
64    , m_cachedDuration(MediaPlayer::invalidTime())
65    , m_reportedDuration(MediaPlayer::invalidTime())
66    , m_maxTimeLoadedAtLastDidLoadingProgress(MediaPlayer::invalidTime())
67    , m_requestedRate(1)
68    , m_delayCallbacks(0)
69    , m_delayCharacteristicsChangedNotification(0)
70    , m_mainThreadCallPending(false)
71    , m_assetIsPlayable(false)
72    , m_visible(false)
73    , m_loadingMetadata(false)
74    , m_isAllowedToRender(false)
75    , m_cachedHasAudio(false)
76    , m_cachedHasVideo(false)
77    , m_cachedHasCaptions(false)
78    , m_ignoreLoadStateChanges(false)
79    , m_haveReportedFirstVideoFrame(false)
80    , m_playWhenFramesAvailable(false)
81    , m_inbandTrackConfigurationPending(false)
82    , m_characteristicsChanged(false)
83    , m_shouldMaintainAspectRatio(true)
84    , m_seeking(false)
85{
86    LOG(Media, "MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation(%p)", this);
87}
88
89MediaPlayerPrivateAVFoundation::~MediaPlayerPrivateAVFoundation()
90{
91    LOG(Media, "MediaPlayerPrivateAVFoundation::~MediaPlayerPrivateAVFoundation(%p)", this);
92    setIgnoreLoadStateChanges(true);
93    cancelCallOnMainThread(mainThreadCallback, this);
94}
95
96MediaPlayerPrivateAVFoundation::MediaRenderingMode MediaPlayerPrivateAVFoundation::currentRenderingMode() const
97{
98    if (platformLayer())
99        return MediaRenderingToLayer;
100
101    if (hasContextRenderer())
102        return MediaRenderingToContext;
103
104    return MediaRenderingNone;
105}
106
107MediaPlayerPrivateAVFoundation::MediaRenderingMode MediaPlayerPrivateAVFoundation::preferredRenderingMode() const
108{
109    if (!m_player->visible() || !m_player->frameView() || assetStatus() == MediaPlayerAVAssetStatusUnknown)
110        return MediaRenderingNone;
111
112    if (supportsAcceleratedRendering() && m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player))
113        return MediaRenderingToLayer;
114
115    return MediaRenderingToContext;
116}
117
118void MediaPlayerPrivateAVFoundation::setUpVideoRendering()
119{
120    if (!isReadyForVideoSetup())
121        return;
122
123    MediaRenderingMode currentMode = currentRenderingMode();
124    MediaRenderingMode preferredMode = preferredRenderingMode();
125
126    if (preferredMode == MediaRenderingNone)
127        preferredMode = MediaRenderingToContext;
128
129    if (currentMode == preferredMode && currentMode != MediaRenderingNone)
130        return;
131
132    LOG(Media, "MediaPlayerPrivateAVFoundation::setUpVideoRendering(%p) - current mode = %d, preferred mode = %d",
133        this, static_cast<int>(currentMode), static_cast<int>(preferredMode));
134
135    if (currentMode != MediaRenderingNone)
136        tearDownVideoRendering();
137
138    switch (preferredMode) {
139    case MediaRenderingNone:
140    case MediaRenderingToContext:
141        createContextVideoRenderer();
142        break;
143
144    case MediaRenderingToLayer:
145        createVideoLayer();
146        break;
147    }
148
149    // If using a movie layer, inform the client so the compositing tree is updated.
150    if (currentMode == MediaRenderingToLayer || preferredMode == MediaRenderingToLayer) {
151        LOG(Media, "MediaPlayerPrivateAVFoundation::setUpVideoRendering(%p) - calling mediaPlayerRenderingModeChanged()", this);
152        m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
153    }
154}
155
156void MediaPlayerPrivateAVFoundation::tearDownVideoRendering()
157{
158    LOG(Media, "MediaPlayerPrivateAVFoundation::tearDownVideoRendering(%p)", this);
159
160    destroyContextVideoRenderer();
161
162    if (platformLayer())
163        destroyVideoLayer();
164}
165
166bool MediaPlayerPrivateAVFoundation::hasSetUpVideoRendering() const
167{
168    return hasLayerRenderer() || hasContextRenderer();
169}
170
171void MediaPlayerPrivateAVFoundation::load(const String& url)
172{
173    LOG(Media, "MediaPlayerPrivateAVFoundation::load(%p)", this);
174
175    if (m_networkState != MediaPlayer::Loading) {
176        m_networkState = MediaPlayer::Loading;
177        m_player->networkStateChanged();
178    }
179    if (m_readyState != MediaPlayer::HaveNothing) {
180        m_readyState = MediaPlayer::HaveNothing;
181        m_player->readyStateChanged();
182    }
183
184    m_assetURL = url;
185
186    // Don't do any more work if the url is empty.
187    if (!url.length())
188        return;
189
190    setPreload(m_preload);
191}
192
193#if ENABLE(MEDIA_SOURCE)
194void MediaPlayerPrivateAVFoundation::load(const String&, MediaSourcePrivateClient*)
195{
196    m_networkState = MediaPlayer::FormatError;
197    m_player->networkStateChanged();
198}
199#endif
200
201
202void MediaPlayerPrivateAVFoundation::playabilityKnown()
203{
204    LOG(Media, "MediaPlayerPrivateAVFoundation::playabilityKnown(%p)", this);
205
206    if (m_assetIsPlayable)
207        return;
208
209    // Nothing more to do if we already have all of the item's metadata.
210    if (assetStatus() > MediaPlayerAVAssetStatusLoading) {
211        LOG(Media, "MediaPlayerPrivateAVFoundation::playabilityKnown(%p) - all metadata loaded", this);
212        return;
213    }
214
215    // At this point we are supposed to load metadata. It is OK to ask the asset to load the same
216    // information multiple times, because if it has already been loaded the completion handler
217    // will just be called synchronously.
218    m_loadingMetadata = true;
219    beginLoadingMetadata();
220}
221
222void MediaPlayerPrivateAVFoundation::prepareToPlay()
223{
224    LOG(Media, "MediaPlayerPrivateAVFoundation::prepareToPlay(%p)", this);
225
226    setPreload(MediaPlayer::Auto);
227}
228
229void MediaPlayerPrivateAVFoundation::play()
230{
231    LOG(Media, "MediaPlayerPrivateAVFoundation::play(%p)", this);
232
233    // If the file has video, don't request playback until the first frame of video is ready to display
234    // or the audio may start playing before we can render video.
235    if (!m_cachedHasVideo || hasAvailableVideoFrame())
236        platformPlay();
237    else
238        m_playWhenFramesAvailable = true;
239}
240
241void MediaPlayerPrivateAVFoundation::pause()
242{
243    LOG(Media, "MediaPlayerPrivateAVFoundation::pause(%p)", this);
244    m_playWhenFramesAvailable = false;
245    platformPause();
246}
247
248float MediaPlayerPrivateAVFoundation::duration() const
249{
250    return narrowPrecisionToFloat(durationDouble());
251}
252
253double MediaPlayerPrivateAVFoundation::durationDouble() const
254{
255    if (m_cachedDuration != MediaPlayer::invalidTime())
256        return m_cachedDuration;
257
258    double duration = platformDuration();
259    if (!duration || duration == MediaPlayer::invalidTime())
260        return 0;
261
262    m_cachedDuration = duration;
263    LOG(Media, "MediaPlayerPrivateAVFoundation::duration(%p) - caching %g", this, m_cachedDuration);
264    return m_cachedDuration;
265}
266
267float MediaPlayerPrivateAVFoundation::currentTime() const
268{
269    return narrowPrecisionToFloat(currentTimeDouble());
270}
271
272void MediaPlayerPrivateAVFoundation::seek(float time)
273{
274    seekWithTolerance(time, 0, 0);
275}
276
277void MediaPlayerPrivateAVFoundation::seekWithTolerance(double time, double negativeTolerance, double positiveTolerance)
278{
279    if (m_seeking) {
280        LOG(Media, "MediaPlayerPrivateAVFoundation::seekWithTolerance(%p) - save pending seek", this);
281        m_pendingSeek = [this, time, negativeTolerance, positiveTolerance]() {
282            seekWithTolerance(time, negativeTolerance, positiveTolerance);
283        };
284        return;
285    }
286    m_seeking = true;
287
288    if (!metaDataAvailable())
289        return;
290
291    if (time > durationDouble())
292        time = durationDouble();
293
294    if (currentTimeDouble() == time)
295        return;
296
297    if (currentTextTrack())
298        currentTextTrack()->beginSeeking();
299
300    LOG(Media, "MediaPlayerPrivateAVFoundation::seek(%p) - seeking to %f", this, time);
301
302    seekToTime(time, negativeTolerance, positiveTolerance);
303}
304
305void MediaPlayerPrivateAVFoundation::setRate(float rate)
306{
307    LOG(Media, "MediaPlayerPrivateAVFoundation::setRate(%p) - seting to %f", this, rate);
308    m_requestedRate = rate;
309
310    updateRate();
311}
312
313bool MediaPlayerPrivateAVFoundation::paused() const
314{
315    if (!metaDataAvailable())
316        return true;
317
318    return rate() == 0;
319}
320
321bool MediaPlayerPrivateAVFoundation::seeking() const
322{
323    if (!metaDataAvailable())
324        return false;
325
326    return m_seeking;
327}
328
329IntSize MediaPlayerPrivateAVFoundation::naturalSize() const
330{
331    if (!metaDataAvailable())
332        return IntSize();
333
334    // In spite of the name of this method, return the natural size transformed by the
335    // initial movie scale because the spec says intrinsic size is:
336    //
337    //    ... the dimensions of the resource in CSS pixels after taking into account the resource's
338    //    dimensions, aspect ratio, clean aperture, resolution, and so forth, as defined for the
339    //    format used by the resource
340
341    return m_cachedNaturalSize;
342}
343
344void MediaPlayerPrivateAVFoundation::setNaturalSize(IntSize size)
345{
346    LOG(Media, "MediaPlayerPrivateAVFoundation:setNaturalSize(%p) - size = %d x %d", this, size.width(), size.height());
347
348    IntSize oldSize = m_cachedNaturalSize;
349    m_cachedNaturalSize = size;
350    if (oldSize != m_cachedNaturalSize)
351        m_player->sizeChanged();
352}
353
354void MediaPlayerPrivateAVFoundation::setHasVideo(bool b)
355{
356    if (m_cachedHasVideo != b) {
357        m_cachedHasVideo = b;
358        characteristicsChanged();
359    }
360}
361
362void MediaPlayerPrivateAVFoundation::setHasAudio(bool b)
363{
364    if (m_cachedHasAudio != b) {
365        m_cachedHasAudio = b;
366        characteristicsChanged();
367    }
368}
369
370void MediaPlayerPrivateAVFoundation::setHasClosedCaptions(bool b)
371{
372    if (m_cachedHasCaptions != b) {
373        m_cachedHasCaptions = b;
374        characteristicsChanged();
375    }
376}
377
378void MediaPlayerPrivateAVFoundation::characteristicsChanged()
379{
380    if (m_delayCharacteristicsChangedNotification) {
381        m_characteristicsChanged = true;
382        return;
383    }
384
385    m_characteristicsChanged = false;
386    m_player->characteristicChanged();
387}
388
389void MediaPlayerPrivateAVFoundation::setDelayCharacteristicsChangedNotification(bool delay)
390{
391    if (delay) {
392        m_delayCharacteristicsChangedNotification++;
393        return;
394    }
395
396    ASSERT(m_delayCharacteristicsChangedNotification);
397    m_delayCharacteristicsChangedNotification--;
398    if (!m_delayCharacteristicsChangedNotification && m_characteristicsChanged)
399        characteristicsChanged();
400}
401
402std::unique_ptr<PlatformTimeRanges> MediaPlayerPrivateAVFoundation::buffered() const
403{
404    if (!m_cachedLoadedTimeRanges)
405        m_cachedLoadedTimeRanges = platformBufferedTimeRanges();
406
407    return PlatformTimeRanges::create(*m_cachedLoadedTimeRanges);
408}
409
410double MediaPlayerPrivateAVFoundation::maxTimeSeekableDouble() const
411{
412    if (!metaDataAvailable())
413        return 0;
414
415    if (!m_cachedMaxTimeSeekable)
416        m_cachedMaxTimeSeekable = platformMaxTimeSeekable();
417
418    LOG(Media, "MediaPlayerPrivateAVFoundation::maxTimeSeekable(%p) - returning %f", this, m_cachedMaxTimeSeekable);
419    return m_cachedMaxTimeSeekable;
420}
421
422double MediaPlayerPrivateAVFoundation::minTimeSeekable() const
423{
424    if (!metaDataAvailable())
425        return 0;
426
427    if (!m_cachedMinTimeSeekable)
428        m_cachedMinTimeSeekable = platformMinTimeSeekable();
429
430    LOG(Media, "MediaPlayerPrivateAVFoundation::minTimeSeekable(%p) - returning %f", this, m_cachedMinTimeSeekable);
431    return m_cachedMinTimeSeekable;
432}
433
434float MediaPlayerPrivateAVFoundation::maxTimeLoaded() const
435{
436    if (!metaDataAvailable())
437        return 0;
438
439    if (!m_cachedMaxTimeLoaded)
440        m_cachedMaxTimeLoaded = platformMaxTimeLoaded();
441
442    return m_cachedMaxTimeLoaded;
443}
444
445bool MediaPlayerPrivateAVFoundation::didLoadingProgress() const
446{
447    if (!duration() || !totalBytes())
448        return false;
449    float currentMaxTimeLoaded = maxTimeLoaded();
450    bool didLoadingProgress = currentMaxTimeLoaded != m_maxTimeLoadedAtLastDidLoadingProgress;
451    m_maxTimeLoadedAtLastDidLoadingProgress = currentMaxTimeLoaded;
452
453    return didLoadingProgress;
454}
455
456bool MediaPlayerPrivateAVFoundation::isReadyForVideoSetup() const
457{
458    // AVFoundation will not return true for firstVideoFrameAvailable until
459    // an AVPlayerLayer has been added to the AVPlayerItem, so allow video setup
460    // here if a video track to trigger allocation of a AVPlayerLayer.
461    return (m_isAllowedToRender || m_cachedHasVideo) && m_readyState >= MediaPlayer::HaveMetadata && m_player->visible();
462}
463
464void MediaPlayerPrivateAVFoundation::prepareForRendering()
465{
466    if (m_isAllowedToRender)
467        return;
468    m_isAllowedToRender = true;
469
470    setUpVideoRendering();
471
472    if (currentRenderingMode() == MediaRenderingToLayer || preferredRenderingMode() == MediaRenderingToLayer)
473        m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
474}
475
476bool MediaPlayerPrivateAVFoundation::supportsFullscreen() const
477{
478#if ENABLE(FULLSCREEN_API)
479    return true;
480#else
481    // FIXME: WebVideoFullscreenController assumes a QTKit/QuickTime media engine
482#if PLATFORM(IOS)
483    if (Settings::avKitEnabled())
484        return true;
485#endif
486    return false;
487#endif
488}
489
490void MediaPlayerPrivateAVFoundation::updateStates()
491{
492    if (m_ignoreLoadStateChanges)
493        return;
494
495    MediaPlayer::NetworkState oldNetworkState = m_networkState;
496    MediaPlayer::ReadyState oldReadyState = m_readyState;
497
498    if (m_loadingMetadata)
499        m_networkState = MediaPlayer::Loading;
500    else {
501        // -loadValuesAsynchronouslyForKeys:completionHandler: has invoked its handler; test status of keys and determine state.
502        AssetStatus assetStatus = this->assetStatus();
503        ItemStatus itemStatus = playerItemStatus();
504
505        m_assetIsPlayable = (assetStatus == MediaPlayerAVAssetStatusPlayable);
506        if (m_readyState < MediaPlayer::HaveMetadata && assetStatus > MediaPlayerAVAssetStatusLoading) {
507            if (m_assetIsPlayable) {
508                if (assetStatus >= MediaPlayerAVAssetStatusLoaded)
509                    m_readyState = MediaPlayer::HaveMetadata;
510                if (itemStatus <= MediaPlayerAVPlayerItemStatusUnknown) {
511                    if (assetStatus == MediaPlayerAVAssetStatusFailed || m_preload > MediaPlayer::MetaData || isLiveStream()) {
512                        // The asset is playable but doesn't support inspection prior to playback (eg. streaming files),
513                        // or we are supposed to prepare for playback immediately, so create the player item now.
514                        m_networkState = MediaPlayer::Loading;
515                        prepareToPlay();
516                    } else
517                        m_networkState = MediaPlayer::Idle;
518                }
519            } else {
520                // FIX ME: fetch the error associated with the @"playable" key to distinguish between format
521                // and network errors.
522                m_networkState = MediaPlayer::FormatError;
523            }
524        }
525
526        if (assetStatus >= MediaPlayerAVAssetStatusLoaded && itemStatus > MediaPlayerAVPlayerItemStatusUnknown) {
527            switch (itemStatus) {
528            case MediaPlayerAVPlayerItemStatusDoesNotExist:
529            case MediaPlayerAVPlayerItemStatusUnknown:
530            case MediaPlayerAVPlayerItemStatusFailed:
531                break;
532
533            case MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp:
534            case MediaPlayerAVPlayerItemStatusPlaybackBufferFull:
535                // If the status becomes PlaybackBufferFull, loading stops and the status will not
536                // progress to LikelyToKeepUp. Set the readyState to  HAVE_ENOUGH_DATA, on the
537                // presumption that if the playback buffer is full, playback will probably not stall.
538                m_readyState = MediaPlayer::HaveEnoughData;
539                break;
540
541            case MediaPlayerAVPlayerItemStatusReadyToPlay:
542                // If the readyState is already HaveEnoughData, don't go lower because of this state change.
543                if (m_readyState == MediaPlayer::HaveEnoughData)
544                    break;
545                FALLTHROUGH;
546
547            case MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty:
548                if (maxTimeLoaded() > currentTime())
549                    m_readyState = MediaPlayer::HaveFutureData;
550                else
551                    m_readyState = MediaPlayer::HaveCurrentData;
552                break;
553            }
554
555            if (itemStatus == MediaPlayerAVPlayerItemStatusPlaybackBufferFull)
556                m_networkState = MediaPlayer::Idle;
557            else if (itemStatus == MediaPlayerAVPlayerItemStatusFailed)
558                m_networkState = MediaPlayer::DecodeError;
559            else if (itemStatus != MediaPlayerAVPlayerItemStatusPlaybackBufferFull && itemStatus >= MediaPlayerAVPlayerItemStatusReadyToPlay)
560                m_networkState = (maxTimeLoaded() == duration()) ? MediaPlayer::Loaded : MediaPlayer::Loading;
561        }
562    }
563
564    if (isReadyForVideoSetup() && currentRenderingMode() != preferredRenderingMode())
565        setUpVideoRendering();
566
567    if (!m_haveReportedFirstVideoFrame && m_cachedHasVideo && hasAvailableVideoFrame()) {
568        if (m_readyState < MediaPlayer::HaveCurrentData)
569            m_readyState = MediaPlayer::HaveCurrentData;
570        m_haveReportedFirstVideoFrame = true;
571        m_player->firstVideoFrameAvailable();
572    }
573
574    if (m_networkState != oldNetworkState)
575        m_player->networkStateChanged();
576
577    if (m_readyState != oldReadyState)
578        m_player->readyStateChanged();
579
580    if (m_playWhenFramesAvailable && hasAvailableVideoFrame()) {
581        m_playWhenFramesAvailable = false;
582        platformPlay();
583    }
584
585#if !LOG_DISABLED
586    if (m_networkState != oldNetworkState || oldReadyState != m_readyState) {
587        LOG(Media, "MediaPlayerPrivateAVFoundation::updateStates(%p) - entered with networkState = %i, readyState = %i,  exiting with networkState = %i, readyState = %i",
588            this, static_cast<int>(oldNetworkState), static_cast<int>(oldReadyState), static_cast<int>(m_networkState), static_cast<int>(m_readyState));
589    }
590#endif
591}
592
593void MediaPlayerPrivateAVFoundation::setSize(const IntSize&)
594{
595}
596
597void MediaPlayerPrivateAVFoundation::setVisible(bool visible)
598{
599    if (m_visible == visible)
600        return;
601
602    m_visible = visible;
603    if (visible)
604        setUpVideoRendering();
605
606    platformSetVisible(visible);
607}
608
609void MediaPlayerPrivateAVFoundation::acceleratedRenderingStateChanged()
610{
611    // Set up or change the rendering path if necessary.
612    setUpVideoRendering();
613}
614
615void MediaPlayerPrivateAVFoundation::setShouldMaintainAspectRatio(bool maintainAspectRatio)
616{
617    if (maintainAspectRatio == m_shouldMaintainAspectRatio)
618        return;
619
620    m_shouldMaintainAspectRatio = maintainAspectRatio;
621    updateVideoLayerGravity();
622}
623
624void MediaPlayerPrivateAVFoundation::metadataLoaded()
625{
626    m_loadingMetadata = false;
627    tracksChanged();
628}
629
630void MediaPlayerPrivateAVFoundation::rateChanged()
631{
632#if ENABLE(IOS_AIRPLAY)
633    if (isCurrentPlaybackTargetWireless())
634        m_player->handlePlaybackCommand(rate() ? MediaSession::PlayCommand : MediaSession::PauseCommand);
635#endif
636
637    m_player->rateChanged();
638}
639
640void MediaPlayerPrivateAVFoundation::loadedTimeRangesChanged()
641{
642    m_cachedLoadedTimeRanges = nullptr;
643    m_cachedMaxTimeLoaded = 0;
644    invalidateCachedDuration();
645}
646
647void MediaPlayerPrivateAVFoundation::seekableTimeRangesChanged()
648{
649    m_cachedMaxTimeSeekable = 0;
650    m_cachedMinTimeSeekable = 0;
651}
652
653void MediaPlayerPrivateAVFoundation::timeChanged(double time)
654{
655    LOG(Media, "MediaPlayerPrivateAVFoundation::timeChanged(%p) - time = %f", this, time);
656    UNUSED_PARAM(time);
657}
658
659void MediaPlayerPrivateAVFoundation::seekCompleted(bool finished)
660{
661    LOG(Media, "MediaPlayerPrivateAVFoundation::seekCompleted(%p) - finished = %d", this, finished);
662    UNUSED_PARAM(finished);
663
664    m_seeking = false;
665
666    std::function<void()> pendingSeek;
667    std::swap(pendingSeek, m_pendingSeek);
668
669    if (pendingSeek) {
670        LOG(Media, "MediaPlayerPrivateAVFoundation::seekCompleted(%p) - issuing pending seek", this);
671        pendingSeek();
672        return;
673    }
674
675    if (currentTextTrack())
676        currentTextTrack()->endSeeking();
677
678    updateStates();
679    m_player->timeChanged();
680}
681
682void MediaPlayerPrivateAVFoundation::didEnd()
683{
684    // Hang onto the current time and use it as duration from now on since we are definitely at
685    // the end of the movie. Do this because the initial duration is sometimes an estimate.
686    double now = currentTimeDouble();
687    if (now > 0)
688        m_cachedDuration = now;
689
690    updateStates();
691    m_player->timeChanged();
692}
693
694void MediaPlayerPrivateAVFoundation::invalidateCachedDuration()
695{
696    LOG(Media, "MediaPlayerPrivateAVFoundation::invalidateCachedDuration(%p)", this);
697
698    m_cachedDuration = MediaPlayer::invalidTime();
699
700    // For some media files, reported duration is estimated and updated as media is loaded
701    // so report duration changed when the estimate is upated.
702    float duration = this->duration();
703    if (duration != m_reportedDuration) {
704        if (m_reportedDuration != MediaPlayer::invalidTime())
705            m_player->durationChanged();
706        m_reportedDuration = duration;
707    }
708
709}
710
711void MediaPlayerPrivateAVFoundation::repaint()
712{
713    m_player->repaint();
714}
715
716MediaPlayer::MovieLoadType MediaPlayerPrivateAVFoundation::movieLoadType() const
717{
718    if (!metaDataAvailable() || assetStatus() == MediaPlayerAVAssetStatusUnknown)
719        return MediaPlayer::Unknown;
720
721    if (isLiveStream())
722        return MediaPlayer::LiveStream;
723
724    return MediaPlayer::Download;
725}
726
727void MediaPlayerPrivateAVFoundation::setPreload(MediaPlayer::Preload preload)
728{
729    m_preload = preload;
730    if (!m_assetURL.length())
731        return;
732
733    setDelayCallbacks(true);
734
735    if (m_preload >= MediaPlayer::MetaData && assetStatus() == MediaPlayerAVAssetStatusDoesNotExist) {
736        createAVAssetForURL(m_assetURL);
737        checkPlayability();
738    }
739
740    // Don't force creation of the player and player item unless we already know that the asset is playable. If we aren't
741    // there yet, or if we already know it is not playable, creating them now won't help.
742    if (m_preload == MediaPlayer::Auto && m_assetIsPlayable) {
743        createAVPlayerItem();
744        createAVPlayer();
745    }
746
747    setDelayCallbacks(false);
748}
749
750void MediaPlayerPrivateAVFoundation::setDelayCallbacks(bool delay) const
751{
752    MutexLocker lock(m_queueMutex);
753    if (delay)
754        ++m_delayCallbacks;
755    else {
756        ASSERT(m_delayCallbacks);
757        --m_delayCallbacks;
758    }
759}
760
761void MediaPlayerPrivateAVFoundation::mainThreadCallback(void* context)
762{
763    LOG(Media, "MediaPlayerPrivateAVFoundation::mainThreadCallback(%p)", context);
764    MediaPlayerPrivateAVFoundation* player = static_cast<MediaPlayerPrivateAVFoundation*>(context);
765    player->clearMainThreadPendingFlag();
766    player->dispatchNotification();
767}
768
769void MediaPlayerPrivateAVFoundation::clearMainThreadPendingFlag()
770{
771    MutexLocker lock(m_queueMutex);
772    m_mainThreadCallPending = false;
773}
774
775void MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(Notification::Type type, double time)
776{
777    scheduleMainThreadNotification(Notification(type, time));
778}
779
780void MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(Notification::Type type, bool finished)
781{
782    scheduleMainThreadNotification(Notification(type, finished));
783}
784
785#if !LOG_DISABLED
786static const char* notificationName(MediaPlayerPrivateAVFoundation::Notification& notification)
787{
788#define DEFINE_TYPE_STRING_CASE(type) case MediaPlayerPrivateAVFoundation::Notification::type: return #type;
789    switch (notification.type()) {
790    FOR_EACH_MEDIAPLAYERPRIVATEAVFOUNDATION_NOTIFICATION_TYPE(DEFINE_TYPE_STRING_CASE)
791    case MediaPlayerPrivateAVFoundation::Notification::FunctionType: return "FunctionType";
792    default: ASSERT_NOT_REACHED(); return "";
793    }
794#undef DEFINE_TYPE_STRING_CASE
795}
796#endif // !LOG_DISABLED
797
798
799void MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(Notification notification)
800{
801    LOG(Media, "MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(%p) - notification %s", this, notificationName(notification));
802    m_queueMutex.lock();
803
804    // It is important to always process the properties in the order that we are notified,
805    // so always go through the queue because notifications happen on different threads.
806    m_queuedNotifications.append(notification);
807
808#if OS(WINDOWS)
809    bool delayDispatch = true;
810#else
811    bool delayDispatch = m_delayCallbacks || !isMainThread();
812#endif
813    if (delayDispatch && !m_mainThreadCallPending) {
814        m_mainThreadCallPending = true;
815        callOnMainThread(mainThreadCallback, this);
816    }
817
818    m_queueMutex.unlock();
819
820    if (delayDispatch) {
821        LOG(Media, "MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(%p) - early return", this);
822        return;
823    }
824
825    dispatchNotification();
826}
827
828void MediaPlayerPrivateAVFoundation::dispatchNotification()
829{
830    ASSERT(isMainThread());
831
832    Notification notification = Notification();
833    {
834        MutexLocker lock(m_queueMutex);
835
836        if (m_queuedNotifications.isEmpty())
837            return;
838
839        if (!m_delayCallbacks) {
840            // Only dispatch one notification callback per invocation because they can cause recursion.
841            notification = m_queuedNotifications.first();
842            m_queuedNotifications.remove(0);
843        }
844
845        if (!m_queuedNotifications.isEmpty() && !m_mainThreadCallPending)
846            callOnMainThread(mainThreadCallback, this);
847
848        if (!notification.isValid())
849            return;
850    }
851
852    LOG(Media, "MediaPlayerPrivateAVFoundation::dispatchNotification(%p) - dispatching %s", this, notificationName(notification));
853
854    switch (notification.type()) {
855    case Notification::ItemDidPlayToEndTime:
856        didEnd();
857        break;
858    case Notification::ItemTracksChanged:
859        tracksChanged();
860        updateStates();
861        break;
862    case Notification::ItemStatusChanged:
863        updateStates();
864        break;
865    case Notification::ItemSeekableTimeRangesChanged:
866        seekableTimeRangesChanged();
867        updateStates();
868        break;
869    case Notification::ItemLoadedTimeRangesChanged:
870        loadedTimeRangesChanged();
871        updateStates();
872        break;
873    case Notification::ItemPresentationSizeChanged:
874        sizeChanged();
875        updateStates();
876        break;
877    case Notification::ItemIsPlaybackLikelyToKeepUpChanged:
878        updateStates();
879        break;
880    case Notification::ItemIsPlaybackBufferEmptyChanged:
881        updateStates();
882        break;
883    case Notification::ItemIsPlaybackBufferFullChanged:
884        updateStates();
885        break;
886    case Notification::PlayerRateChanged:
887        updateStates();
888        rateChanged();
889        break;
890    case Notification::PlayerTimeChanged:
891        timeChanged(notification.time());
892        break;
893    case Notification::SeekCompleted:
894        seekCompleted(notification.finished());
895        break;
896    case Notification::AssetMetadataLoaded:
897        metadataLoaded();
898        updateStates();
899        break;
900    case Notification::AssetPlayabilityKnown:
901        updateStates();
902        playabilityKnown();
903        break;
904    case Notification::DurationChanged:
905        invalidateCachedDuration();
906        break;
907    case Notification::ContentsNeedsDisplay:
908        contentsNeedsDisplay();
909        break;
910    case Notification::InbandTracksNeedConfiguration:
911        m_inbandTrackConfigurationPending = false;
912        configureInbandTracks();
913        break;
914    case Notification::FunctionType:
915        notification.function()();
916        break;
917    case Notification::TargetIsWirelessChanged:
918#if ENABLE(IOS_AIRPLAY)
919        playbackTargetIsWirelessChanged();
920#endif
921        break;
922
923    case Notification::None:
924        ASSERT_NOT_REACHED();
925        break;
926    }
927}
928
929void MediaPlayerPrivateAVFoundation::configureInbandTracks()
930{
931    RefPtr<InbandTextTrackPrivateAVF> trackToEnable;
932
933#if ENABLE(AVF_CAPTIONS)
934    synchronizeTextTrackState();
935#endif
936
937    // AVFoundation can only emit cues for one track at a time, so enable the first track that is showing, or the first that
938    // is hidden if none are showing. Otherwise disable all tracks.
939    for (unsigned i = 0; i < m_textTracks.size(); ++i) {
940        RefPtr<InbandTextTrackPrivateAVF> track = m_textTracks[i];
941        if (track->mode() == InbandTextTrackPrivate::Showing) {
942            trackToEnable = track;
943            break;
944        }
945        if (track->mode() == InbandTextTrackPrivate::Hidden)
946            trackToEnable = track;
947    }
948
949    setCurrentTextTrack(trackToEnable.get());
950}
951
952void MediaPlayerPrivateAVFoundation::trackModeChanged()
953{
954    if (m_inbandTrackConfigurationPending)
955        return;
956    m_inbandTrackConfigurationPending = true;
957    scheduleMainThreadNotification(Notification::InbandTracksNeedConfiguration);
958}
959
960size_t MediaPlayerPrivateAVFoundation::extraMemoryCost() const
961{
962    double duration = durationDouble();
963    if (!duration)
964        return 0;
965
966    unsigned long long extra = totalBytes() * buffered()->totalDuration().toDouble() / duration;
967    return static_cast<unsigned>(extra);
968}
969
970void MediaPlayerPrivateAVFoundation::clearTextTracks()
971{
972    for (unsigned i = 0; i < m_textTracks.size(); ++i) {
973        RefPtr<InbandTextTrackPrivateAVF> track = m_textTracks[i];
974        player()->removeTextTrack(track);
975        track->disconnect();
976    }
977    m_textTracks.clear();
978}
979
980void MediaPlayerPrivateAVFoundation::processNewAndRemovedTextTracks(const Vector<RefPtr<InbandTextTrackPrivateAVF>>& removedTextTracks)
981{
982    if (removedTextTracks.size()) {
983        for (unsigned i = 0; i < m_textTracks.size(); ++i) {
984            if (!removedTextTracks.contains(m_textTracks[i]))
985                continue;
986
987            player()->removeTextTrack(removedTextTracks[i].get());
988            m_textTracks.remove(i);
989        }
990    }
991
992    unsigned inBandCount = 0;
993    for (unsigned i = 0; i < m_textTracks.size(); ++i) {
994        RefPtr<InbandTextTrackPrivateAVF> track = m_textTracks[i];
995
996#if ENABLE(AVF_CAPTIONS)
997        if (track->textTrackCategory() == InbandTextTrackPrivateAVF::OutOfBand)
998            continue;
999#endif
1000
1001        track->setTextTrackIndex(inBandCount);
1002        ++inBandCount;
1003        if (track->hasBeenReported())
1004            continue;
1005
1006        track->setHasBeenReported(true);
1007        player()->addTextTrack(track.get());
1008    }
1009    LOG(Media, "MediaPlayerPrivateAVFoundation::processNewAndRemovedTextTracks(%p) - found %lu text tracks", this, m_textTracks.size());
1010}
1011
1012#if ENABLE(IOS_AIRPLAY)
1013void MediaPlayerPrivateAVFoundation::playbackTargetIsWirelessChanged()
1014{
1015    if (m_player)
1016        m_player->currentPlaybackTargetIsWirelessChanged();
1017}
1018#endif
1019
1020#if ENABLE(ENCRYPTED_MEDIA) || ENABLE(ENCRYPTED_MEDIA_V2)
1021bool MediaPlayerPrivateAVFoundation::extractKeyURIKeyIDAndCertificateFromInitData(Uint8Array* initData, String& keyURI, String& keyID, RefPtr<Uint8Array>& certificate)
1022{
1023    // initData should have the following layout:
1024    // [4 bytes: keyURI length][N bytes: keyURI][4 bytes: contentID length], [N bytes: contentID], [4 bytes: certificate length][N bytes: certificate]
1025    if (initData->byteLength() < 4)
1026        return false;
1027
1028    RefPtr<ArrayBuffer> initDataBuffer = initData->buffer();
1029
1030    // Use a DataView to read uint32 values from the buffer, as Uint32Array requires the reads be aligned on 4-byte boundaries.
1031    RefPtr<JSC::DataView> initDataView = JSC::DataView::create(initDataBuffer, 0, initDataBuffer->byteLength());
1032    uint32_t offset = 0;
1033    bool status = true;
1034
1035    uint32_t keyURILength = initDataView->get<uint32_t>(offset, true, &status);
1036    offset += 4;
1037    if (!status || offset + keyURILength > initData->length())
1038        return false;
1039
1040    RefPtr<Uint16Array> keyURIArray = Uint16Array::create(initDataBuffer, offset, keyURILength);
1041    if (!keyURIArray)
1042        return false;
1043
1044    keyURI = String(reinterpret_cast<UChar*>(keyURIArray->data()), keyURILength / sizeof(unsigned short));
1045    offset += keyURILength;
1046
1047    uint32_t keyIDLength = initDataView->get<uint32_t>(offset, true, &status);
1048    offset += 4;
1049    if (!status || offset + keyIDLength > initData->length())
1050        return false;
1051
1052    RefPtr<Uint16Array> keyIDArray = Uint16Array::create(initDataBuffer, offset, keyIDLength);
1053    if (!keyIDArray)
1054        return false;
1055
1056    keyID = String(reinterpret_cast<UChar*>(keyIDArray->data()), keyIDLength / sizeof(unsigned short));
1057    offset += keyIDLength;
1058
1059    uint32_t certificateLength = initDataView->get<uint32_t>(offset, true, &status);
1060    offset += 4;
1061    if (!status || offset + certificateLength > initData->length())
1062        return false;
1063
1064    certificate = Uint8Array::create(initDataBuffer, offset, certificateLength);
1065    if (!certificate)
1066        return false;
1067
1068    return true;
1069}
1070#endif
1071
1072} // namespace WebCore
1073
1074#endif
1075