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