#include "config.h"
#include "core/html/HTMLMediaElement.h"
-#include <limits>
-#include "bindings/v8/ExceptionState.h"
-#include "bindings/v8/ExceptionStatePlaceholder.h"
-#include "bindings/v8/ScriptController.h"
-#include "bindings/v8/ScriptEventListener.h"
+#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/ExceptionStatePlaceholder.h"
+#include "bindings/core/v8/ScriptController.h"
+#include "bindings/core/v8/ScriptEventListener.h"
#include "core/HTMLNames.h"
#include "core/css/MediaList.h"
#include "core/dom/Attribute.h"
+#include "core/dom/ElementTraversal.h"
#include "core/dom/ExceptionCode.h"
#include "core/dom/FullscreenElementStack.h"
#include "core/dom/shadow/ShadowRoot.h"
#include "wtf/NonCopyingSort.h"
#include "wtf/Uint8Array.h"
#include "wtf/text/CString.h"
+#include <limits>
#if ENABLE(WEB_AUDIO)
#include "platform/audio/AudioSourceProvider.h"
using blink::WebMimeRegistry;
using blink::WebMediaPlayerClient;
-namespace WebCore {
+namespace blink {
#if !LOG_DISABLED
static String urlForLoggingMedia(const KURL& url)
RawPtrWillBeMember<HTMLMediaElement> m_mediaElement;
};
+class AudioSourceProviderClientLockScope {
+ STACK_ALLOCATED();
+public:
+#if ENABLE(WEB_AUDIO)
+ AudioSourceProviderClientLockScope(HTMLMediaElement& element)
+ : m_client(element.audioSourceNode())
+ {
+ if (m_client)
+ m_client->lock();
+ }
+ ~AudioSourceProviderClientLockScope()
+ {
+ if (m_client)
+ m_client->unlock();
+ }
+
+private:
+ RawPtrWillBeMember<AudioSourceProviderClient> m_client;
+#else
+ explicit AudioSourceProviderClientLockScope(HTMLMediaElement&) { }
+ ~AudioSourceProviderClientLockScope() { }
+#endif
+};
+
static const AtomicString& AudioKindToString(WebMediaPlayerClient::AudioTrackKind kind)
{
switch (kind) {
, m_processingPreferenceChange(false)
#if ENABLE(OILPAN)
, m_isFinalizing(false)
+ , m_closeMediaSourceWhenFinalizing(false)
#endif
, m_lastTextTrackUpdateTime(-1)
, m_audioTracks(AudioTrackList::create(*this))
}
#endif
+#if ENABLE(OILPAN)
+ if (m_closeMediaSourceWhenFinalizing)
+ closeMediaSource();
+#else
closeMediaSource();
-#if !ENABLE(OILPAN)
removeElementFromDocumentMap(this, &document());
#endif
m_isFinalizing = true;
#endif
- // The m_audioSourceNode is either dead already or it is dying together with
- // this HTMLMediaElement which it strongly keeps alive.
-#if ENABLE(WEB_AUDIO) && !ENABLE(OILPAN)
+ // m_audioSourceNode is explicitly cleared by AudioNode::dispose().
+ // Since AudioNode::dispose() is guaranteed to be always called before
+ // the AudioNode is destructed, m_audioSourceNode is explicitly cleared
+ // even if the AudioNode and the HTMLMediaElement die together.
+#if ENABLE(WEB_AUDIO)
ASSERT(!m_audioSourceNode);
#endif
clearMediaPlayerAndAudioSourceProviderClientWithoutLocking();
#endif
}
+#if ENABLE(OILPAN)
+void HTMLMediaElement::setCloseMediaSourceWhenFinalizing()
+{
+ ASSERT(!m_closeMediaSourceWhenFinalizing);
+ m_closeMediaSourceWhenFinalizing = true;
+}
+#endif
+
void HTMLMediaElement::didMoveToNewDocument(Document& oldDocument)
{
WTF_LOG(Media, "HTMLMediaElement::didMoveToNewDocument");
return false;
// If no controls specified, we should still be able to focus the element if it has tabIndex.
- return controls() || HTMLElement::supportsFocus();
+ return shouldShowControls() || HTMLElement::supportsFocus();
}
bool HTMLMediaElement::isMouseFocusable() const
bool HTMLMediaElement::rendererIsNeeded(const RenderStyle& style)
{
- return controls() ? HTMLElement::rendererIsNeeded(style) : false;
+ return shouldShowControls() && HTMLElement::rendererIsNeeded(style);
}
RenderObject* HTMLMediaElement::createRenderer(RenderStyle*)
// If the src attribute's value is the empty string ... jump down to the failed step below
KURL mediaURL = getNonEmptyURLAttribute(srcAttr);
if (mediaURL.isEmpty()) {
- mediaLoadingFailed(MediaPlayer::FormatError);
+ mediaLoadingFailed(WebMediaPlayer::NetworkStateFormatError);
WTF_LOG(Media, "HTMLMediaElement::selectMediaResource, empty 'src'");
return;
}
if (!isSafeToLoadURL(mediaURL, Complain)) {
- mediaLoadingFailed(MediaPlayer::FormatError);
+ mediaLoadingFailed(WebMediaPlayer::NetworkStateFormatError);
return;
}
LocalFrame* frame = document().frame();
if (!frame) {
- mediaLoadingFailed(MediaPlayer::FormatError);
+ mediaLoadingFailed(WebMediaPlayer::NetworkStateFormatError);
return;
}
startPlayerLoad();
}
} else {
- mediaLoadingFailed(MediaPlayer::FormatError);
+ mediaLoadingFailed(WebMediaPlayer::NetworkStateFormatError);
}
// If there is no poster to display, allow the media engine to render video frames as soon as
// element. (In the other cases, such as explicit seeks, relevant events get
// fired as part of the overall process of changing the current playback
// position.)
- if (!m_seeking && m_lastSeekTime <= lastTime)
+ if (!m_seeking && m_lastSeekTime < lastTime)
scheduleTimeupdateEvent(true);
// Explicitly cache vector sizes, as their content is constant from here.
// 8 - Let events be a list of tasks, initially empty. Each task in this
// list will be associated with a text track, a text track cue, and a time,
// which are used to sort the list before the tasks are queued.
- Vector<std::pair<double, TextTrackCue*> > eventTasks;
+ WillBeHeapVector<std::pair<double, RawPtrWillBeMember<TextTrackCue> > > eventTasks;
// 8 - Let affected tracks be a list of text tracks, initially empty.
- Vector<TextTrack*> affectedTracks;
+ WillBeHeapVector<RawPtrWillBeMember<TextTrack> > affectedTracks;
for (size_t i = 0; i < missedCuesSize; ++i) {
// 9 - For each text track cue in missed cues, prepare an event named enter
// simple event named cuechange at the track element as well.
if (affectedTracks[i]->trackType() == TextTrack::TrackElement) {
RefPtrWillBeRawPtr<Event> event = Event::create(EventTypeNames::cuechange);
- HTMLTrackElement* trackElement = static_cast<LoadableTextTrack*>(affectedTracks[i])->trackElement();
+ HTMLTrackElement* trackElement = static_cast<LoadableTextTrack*>(affectedTracks[i].get())->trackElement();
ASSERT(trackElement);
event->setTarget(trackElement);
void HTMLMediaElement::mediaEngineError(PassRefPtrWillBeRawPtr<MediaError> err)
{
+ ASSERT(m_readyState >= HAVE_METADATA);
WTF_LOG(Media, "HTMLMediaElement::mediaEngineError(%d)", static_cast<int>(err->code()));
// 1 - The user agent should cancel the fetching process.
// 3 - Queue a task to fire a simple event named error at the media element.
scheduleEvent(EventTypeNames::error);
- closeMediaSource();
-
- // 4 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a
- // task to fire a simple event called emptied at the element.
- m_networkState = NETWORK_EMPTY;
- scheduleEvent(EventTypeNames::emptied);
+ // 4 - Set the element's networkState attribute to the NETWORK_IDLE value.
+ m_networkState = NETWORK_IDLE;
// 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
setShouldDelayLoadEvent(false);
void HTMLMediaElement::mediaPlayerNetworkStateChanged()
{
- setNetworkState(m_player->networkState());
+ setNetworkState(webMediaPlayer()->networkState());
}
-void HTMLMediaElement::mediaLoadingFailed(MediaPlayer::NetworkState error)
+void HTMLMediaElement::mediaLoadingFailed(WebMediaPlayer::NetworkState error)
{
stopPeriodicTimers();
return;
}
- if (error == MediaPlayer::NetworkError && m_readyState >= HAVE_METADATA)
+ if (error == WebMediaPlayer::NetworkStateNetworkError && m_readyState >= HAVE_METADATA)
mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_NETWORK));
- else if (error == MediaPlayer::DecodeError)
+ else if (error == WebMediaPlayer::NetworkStateDecodeError)
mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_DECODE));
- else if ((error == MediaPlayer::FormatError || error == MediaPlayer::NetworkError) && m_loadState == LoadingFromSrcAttr)
+ else if ((error == WebMediaPlayer::NetworkStateFormatError
+ || error == WebMediaPlayer::NetworkStateNetworkError)
+ && m_loadState == LoadingFromSrcAttr)
noneSupported();
updateDisplayState();
mediaControls()->reset();
}
-void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
+void HTMLMediaElement::setNetworkState(WebMediaPlayer::NetworkState state)
{
WTF_LOG(Media, "HTMLMediaElement::setNetworkState(%d) - current state is %d", static_cast<int>(state), static_cast<int>(m_networkState));
- if (state == MediaPlayer::Empty) {
+ if (state == WebMediaPlayer::NetworkStateEmpty) {
// Just update the cached state and leave, we can't do anything.
m_networkState = NETWORK_EMPTY;
return;
}
- if (state == MediaPlayer::FormatError || state == MediaPlayer::NetworkError || state == MediaPlayer::DecodeError) {
+ if (state == WebMediaPlayer::NetworkStateFormatError
+ || state == WebMediaPlayer::NetworkStateNetworkError
+ || state == WebMediaPlayer::NetworkStateDecodeError) {
mediaLoadingFailed(state);
return;
}
- if (state == MediaPlayer::Idle) {
+ if (state == WebMediaPlayer::NetworkStateIdle) {
if (m_networkState > NETWORK_IDLE) {
changeNetworkStateFromLoadingToIdle();
setShouldDelayLoadEvent(false);
}
}
- if (state == MediaPlayer::Loading) {
+ if (state == WebMediaPlayer::NetworkStateLoading) {
if (m_networkState < NETWORK_LOADING || m_networkState == NETWORK_NO_SOURCE)
startProgressEventTimer();
m_networkState = NETWORK_LOADING;
}
- if (state == MediaPlayer::Loaded) {
+ if (state == WebMediaPlayer::NetworkStateLoaded) {
if (m_networkState != NETWORK_IDLE)
changeNetworkStateFromLoadingToIdle();
m_completelyLoaded = true;
// Schedule one last progress event so we guarantee that at least one is fired
// for files that load very quickly.
- if (m_player->didLoadingProgress())
+ if (webMediaPlayer() && webMediaPlayer()->didLoadingProgress())
scheduleEvent(EventTypeNames::progress);
scheduleEvent(EventTypeNames::suspend);
m_networkState = NETWORK_IDLE;
double time = WTF::currentTime();
double timedelta = time - m_previousProgressTime;
- if (m_player->didLoadingProgress()) {
+ if (webMediaPlayer() && webMediaPlayer()->didLoadingProgress()) {
scheduleEvent(EventTypeNames::progress);
m_previousProgressTime = time;
m_sentStalledEvent = false;
bool HTMLMediaElement::supportsSave() const
{
- return m_player ? m_player->supportsSave() : false;
+ return webMediaPlayer() && webMediaPlayer()->supportsSave();
}
void HTMLMediaElement::prepareToPlay()
// 4.8.10.9 Seeking
// 1 - If the media element's readyState is HAVE_NOTHING, then raise an InvalidStateError exception.
- if (m_readyState == HAVE_NOTHING || !m_player) {
+ if (m_readyState == HAVE_NOTHING) {
exceptionState.throwDOMException(InvalidStateError, "The element's readyState is HAVE_NOTHING.");
return;
}
// time scale, we will ask the media engine to "seek" to the current movie time, which may be a noop and
// not generate a timechanged callback. This means m_seeking will never be cleared and we will never
// fire a 'seeked' event.
-#if !LOG_DISABLED
- double mediaTime = m_player->mediaTimeForTimeValue(time);
- if (time != mediaTime)
+ double mediaTime = webMediaPlayer()->mediaTimeForTimeValue(time);
+ if (time != mediaTime) {
WTF_LOG(Media, "HTMLMediaElement::seek(%f) - media timeline equivalent is %f", time, mediaTime);
-#endif
- time = m_player->mediaTimeForTimeValue(time);
+ time = mediaTime;
+ }
// 7 - If the (possibly now changed) new playback position is not in one of the ranges given in the
// seekable attribute, then let it be the position in one of the ranges given in the seekable attribute
// that is the nearest to the new playback position. ... If there are no ranges given in the seekable
// attribute then set the seeking IDL attribute to false and abort these steps.
- RefPtr<TimeRanges> seekableRanges = seekable();
+ RefPtrWillBeRawPtr<TimeRanges> seekableRanges = seekable();
// Short circuit seeking to the current time by just firing the events if no seek is required.
// Don't skip calling the media engine if we are in poster mode because a seek should always
scheduleEvent(EventTypeNames::seeking);
// 9 - Set the current playback position to the given new playback position
- m_player->seek(time);
+ webMediaPlayer()->seek(time);
// 10-14 are handled, if necessary, when the engine signals a readystate change or otherwise
// satisfies seek completion and signals a time change.
void HTMLMediaElement::refreshCachedTime() const
{
- m_cachedTime = m_player->currentTime();
+ if (!webMediaPlayer())
+ return;
+
+ m_cachedTime = webMediaPlayer()->currentTime();
m_cachedTimeWallClockUpdateTime = WTF::currentTime();
}
static const double minCachedDeltaForWarning = 0.01;
#endif
- if (!m_player)
+ if (m_readyState == HAVE_NOTHING)
return 0;
if (m_seeking) {
if (m_cachedTime != MediaPlayer::invalidTime() && m_paused) {
#if LOG_CACHED_TIME_WARNINGS
- double delta = m_cachedTime - m_player->currentTime();
+ double delta = m_cachedTime - webMediaPlayer()->currentTime();
if (delta > minCachedDeltaForWarning)
WTF_LOG(Media, "HTMLMediaElement::currentTime - WARNING, cached time is %f seconds off of media time when paused", delta);
#endif
double HTMLMediaElement::duration() const
{
+ // FIXME: remove m_player check once we figure out how m_player is going
+ // out of sync with readystate. m_player is cleared but readystate is not set
+ // to HAVE_NOTHING
if (!m_player || m_readyState < HAVE_METADATA)
return std::numeric_limits<double>::quiet_NaN();
if (m_mediaSource)
return m_mediaSource->duration();
- return m_player->duration();
+ return webMediaPlayer()->duration();
}
bool HTMLMediaElement::paused() const
void HTMLMediaElement::updatePlaybackRate()
{
double effectiveRate = effectivePlaybackRate();
- if (m_player && potentiallyPlaying() && m_player->rate() != effectiveRate)
- m_player->setRate(effectiveRate);
+ if (m_player && potentiallyPlaying())
+ webMediaPlayer()->setRate(effectiveRate);
}
bool HTMLMediaElement::ended() const
setBooleanAttribute(loopAttr, b);
}
-bool HTMLMediaElement::controls() const
+bool HTMLMediaElement::shouldShowControls() const
{
LocalFrame* frame = document().frame();
return fastHasAttribute(controlsAttr);
}
-void HTMLMediaElement::setControls(bool b)
-{
- WTF_LOG(Media, "HTMLMediaElement::setControls(%s)", boolString(b));
- setBooleanAttribute(controlsAttr, b);
-}
-
double HTMLMediaElement::volume() const
{
return m_volume;
scheduleEvent(EventTypeNames::volumechange);
}
+void HTMLMediaElement::updateVolume()
+{
+ if (webMediaPlayer())
+ webMediaPlayer()->setVolume(effectiveMediaVolume());
+
+ if (hasMediaControls())
+ mediaControls()->updateVolume();
+}
+
+double HTMLMediaElement::effectiveMediaVolume() const
+{
+ if (m_muted)
+ return 0;
+
+ if (m_mediaController && m_mediaController->muted())
+ return 0;
+
+ double volume = m_volume;
+
+ if (m_mediaController)
+ volume *= m_mediaController->volume();
+
+ return volume;
+}
+
// The spec says to fire periodic timeupdate events (those sent while playing) every
// "15 to 250ms", we choose the slowest frequency
static const double maxTimeupdateEventFrequency = 0.25;
{
// 4.8.10.12.2 Sourcing in-band text tracks
// 1. Associate the relevant data with a new text track and its corresponding new TextTrack object.
- RefPtrWillBeRawPtr<InbandTextTrack> textTrack = InbandTextTrack::create(document(), webTrack);
+ RefPtrWillBeRawPtr<InbandTextTrack> textTrack = InbandTextTrack::create(webTrack);
// 2. Set the new text track's kind, label, and language based on the semantics of the relevant data,
// as defined by the relevant specification. If there is no label in that data, then the label must
// 5. Create a new text track corresponding to the new object, and set its text track kind to kind, its text
// track label to label, its text track language to language...
- RefPtrWillBeRawPtr<TextTrack> textTrack = TextTrack::create(document(), kind, label, language);
+ RefPtrWillBeRawPtr<TextTrack> textTrack = TextTrack::create(kind, label, language);
// Note, due to side effects when changing track parameters, we have to
// first append the track to the text track list.
if (m_nextChildNodeToConsider)
return;
+ if (m_loadState != WaitingForSource)
+ return;
+
// 4.8.9.5, resource selection algorithm, source elements section:
// 21. Wait until the node after pointer is a node other than the end of the list. (This step might wait forever.)
// 22. Asynchronously await a stable state...
invalidateCachedTime();
// 4.8.10.9 steps 12-14. Needed if no ReadyState change is associated with the seek.
- if (m_seeking && m_readyState >= HAVE_CURRENT_DATA && !m_player->seeking())
+ if (m_seeking && m_readyState >= HAVE_CURRENT_DATA && !webMediaPlayer()->seeking())
finishSeek();
// Always call scheduleTimeupdateEvent when the media engine reports a time discontinuity,
if (!m_player || m_pausedInternal)
return;
- if (m_player->paused())
+ if (webMediaPlayer()->paused())
pause();
else
playInternal();
renderer()->updateFromElement();
}
-PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const
+PassRefPtrWillBeRawPtr<TimeRanges> HTMLMediaElement::buffered() const
{
- if (!m_player)
- return TimeRanges::create();
-
if (m_mediaSource)
return m_mediaSource->buffered();
- return m_player->buffered();
+ if (!webMediaPlayer())
+ return TimeRanges::create();
+
+ return TimeRanges::create(webMediaPlayer()->buffered());
}
-PassRefPtr<TimeRanges> HTMLMediaElement::played()
+PassRefPtrWillBeRawPtr<TimeRanges> HTMLMediaElement::played()
{
if (m_playing) {
double time = currentTime();
return m_playedTimeRanges->copy();
}
-PassRefPtr<TimeRanges> HTMLMediaElement::seekable() const
+PassRefPtrWillBeRawPtr<TimeRanges> HTMLMediaElement::seekable() const
{
- if (m_player) {
- double maxTimeSeekable = m_player->maxTimeSeekable();
+ if (webMediaPlayer()) {
+ double maxTimeSeekable = webMediaPlayer()->maxTimeSeekable();
if (maxTimeSeekable)
return TimeRanges::create(0, maxTimeSeekable);
}
bool HTMLMediaElement::stoppedDueToErrors() const
{
if (m_readyState >= HAVE_METADATA && m_error) {
- RefPtr<TimeRanges> seekableRanges = seekable();
+ RefPtrWillBeRawPtr<TimeRanges> seekableRanges = seekable();
if (!seekableRanges->contain(currentTime()))
return true;
}
return false;
}
-void HTMLMediaElement::updateVolume()
-{
- if (webMediaPlayer())
- webMediaPlayer()->setVolume(playerVolume());
-
- if (hasMediaControls())
- mediaControls()->updateVolume();
-}
-
-double HTMLMediaElement::playerVolume() const
-{
- double volumeMultiplier = 1;
- bool shouldMute = m_muted;
-
- if (m_mediaController) {
- volumeMultiplier *= m_mediaController->volume();
- shouldMute = m_mediaController->muted();
- }
-
- return shouldMute ? 0 : m_volume * volumeMultiplier;
-}
-
void HTMLMediaElement::updatePlayState()
{
if (!m_player)
return;
+ bool isPlaying = webMediaPlayer() && !webMediaPlayer()->paused();
if (m_pausedInternal) {
- if (!m_player->paused())
- m_player->pause();
+ if (isPlaying)
+ webMediaPlayer()->pause();
refreshCachedTime();
m_playbackProgressTimer.stop();
if (hasMediaControls())
}
bool shouldBePlaying = potentiallyPlaying();
- bool playerPaused = m_player->paused();
- WTF_LOG(Media, "HTMLMediaElement::updatePlayState - shouldBePlaying = %s, playerPaused = %s",
- boolString(shouldBePlaying), boolString(playerPaused));
+ WTF_LOG(Media, "HTMLMediaElement::updatePlayState - shouldBePlaying = %s, isPlaying = %s",
+ boolString(shouldBePlaying), boolString(isPlaying));
if (shouldBePlaying) {
setDisplayMode(Video);
invalidateCachedTime();
- if (playerPaused) {
+ if (!isPlaying) {
// Set rate, muted before calling play in case they were set before the media engine was setup.
// The media engine should just stash the rate and muted values since it isn't already playing.
- m_player->setRate(effectivePlaybackRate());
+ webMediaPlayer()->setRate(effectivePlaybackRate());
updateVolume();
-
- m_player->play();
+ webMediaPlayer()->play();
}
if (hasMediaControls())
m_playing = true;
} else { // Should not be playing right now
- if (!playerPaused)
- m_player->pause();
+ if (isPlaying)
+ webMediaPlayer()->pause();
refreshCachedTime();
m_playbackProgressTimer.stop();
cancelDeferredLoad();
-#if ENABLE(WEB_AUDIO)
- if (m_audioSourceNode)
- m_audioSourceNode->lock();
-#endif
-
- clearMediaPlayerAndAudioSourceProviderClientWithoutLocking();
-
-#if ENABLE(WEB_AUDIO)
- if (m_audioSourceNode)
- m_audioSourceNode->unlock();
-#endif
+ {
+ AudioSourceProviderClientLockScope scope(*this);
+ clearMediaPlayerAndAudioSourceProviderClientWithoutLocking();
+ }
stopPeriodicTimers();
m_loadTimer.stop();
bool HTMLMediaElement::isFullscreen() const
{
- return FullscreenElementStack::isActiveFullScreenElement(this);
+ return FullscreenElementStack::isActiveFullScreenElement(*this);
}
void HTMLMediaElement::enterFullscreen()
{
WTF_LOG(Media, "HTMLMediaElement::enterFullscreen");
- FullscreenElementStack::from(document()).requestFullScreenForElement(this, 0, FullscreenElementStack::ExemptIFrameAllowFullScreenRequirement);
+ FullscreenElementStack::from(document()).requestFullscreen(*this, FullscreenElementStack::PrefixedVideoRequest);
}
void HTMLMediaElement::exitFullscreen()
{
WTF_LOG(Media, "HTMLMediaElement::exitFullscreen");
- FullscreenElementStack::from(document()).webkitCancelFullScreen();
+ FullscreenElementStack::from(document()).exitFullscreen();
}
void HTMLMediaElement::didBecomeFullscreenElement()
ensureUserAgentShadowRoot().appendChild(mediaControls);
- if (!controls() || !inDocument())
+ if (!shouldShowControls() || !inDocument())
mediaControls->hide();
return true;
void HTMLMediaElement::configureMediaControls()
{
- if (!controls() || !inDocument()) {
+ if (!shouldShowControls() || !inDocument()) {
if (hasMediaControls())
mediaControls()->hide();
return;
void HTMLMediaElement::createMediaPlayer()
{
-#if ENABLE(WEB_AUDIO)
- if (m_audioSourceNode)
- m_audioSourceNode->lock();
-#endif
+ AudioSourceProviderClientLockScope scope(*this);
closeMediaSource();
m_player = MediaPlayer::create(this);
#if ENABLE(WEB_AUDIO)
- if (m_audioSourceNode) {
+ if (m_audioSourceNode && audioSourceProvider()) {
// When creating the player, make sure its AudioSourceProvider knows about the client.
- if (audioSourceProvider())
- audioSourceProvider()->setClient(m_audioSourceNode);
-
- m_audioSourceNode->unlock();
+ audioSourceProvider()->setClient(m_audioSourceNode);
}
#endif
}
{
m_audioSourceNode = sourceNode;
- if (m_audioSourceNode)
- m_audioSourceNode->lock();
-
+ AudioSourceProviderClientLockScope scope(*this);
if (audioSourceProvider())
audioSourceProvider()->setClient(m_audioSourceNode);
-
- if (m_audioSourceNode)
- m_audioSourceNode->unlock();
}
AudioSourceProvider* HTMLMediaElement::audioSourceProvider()
void HTMLMediaElement::trace(Visitor* visitor)
{
+ visitor->trace(m_playedTimeRanges);
visitor->trace(m_asyncEventQueue);
visitor->trace(m_error);
visitor->trace(m_currentSourceNode);
visitor->trace(m_nextChildNodeToConsider);
+ visitor->trace(m_mediaSource);
visitor->trace(m_audioTracks);
visitor->trace(m_videoTracks);
visitor->trace(m_textTracks);