1 | /* |
2 | * Copyright (C) 2011, 2012 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_TRACK) |
29 | |
30 | #include "TrackListBase.h" |
31 | |
32 | #include "EventNames.h" |
33 | #include "HTMLMediaElement.h" |
34 | #include "ScriptExecutionContext.h" |
35 | #include "TrackEvent.h" |
36 | #include <wtf/IsoMallocInlines.h> |
37 | |
38 | namespace WebCore { |
39 | |
40 | WTF_MAKE_ISO_ALLOCATED_IMPL(TrackListBase); |
41 | |
42 | TrackListBase::TrackListBase(HTMLMediaElement* element, ScriptExecutionContext* context) |
43 | : ActiveDOMObject(context) |
44 | , m_element(element) |
45 | , m_asyncEventQueue(*this) |
46 | { |
47 | ASSERT(!context || is<Document>(context)); |
48 | suspendIfNeeded(); |
49 | } |
50 | |
51 | TrackListBase::~TrackListBase() |
52 | { |
53 | clearElement(); |
54 | } |
55 | |
56 | void TrackListBase::clearElement() |
57 | { |
58 | m_element = nullptr; |
59 | for (auto& track : m_inbandTracks) { |
60 | track->setMediaElement(nullptr); |
61 | track->clearClient(); |
62 | } |
63 | } |
64 | |
65 | Element* TrackListBase::element() const |
66 | { |
67 | return m_element; |
68 | } |
69 | |
70 | unsigned TrackListBase::length() const |
71 | { |
72 | return m_inbandTracks.size(); |
73 | } |
74 | |
75 | void TrackListBase::remove(TrackBase& track, bool scheduleEvent) |
76 | { |
77 | size_t index = m_inbandTracks.find(&track); |
78 | if (index == notFound) |
79 | return; |
80 | |
81 | if (track.mediaElement()) { |
82 | ASSERT(track.mediaElement() == m_element); |
83 | track.setMediaElement(nullptr); |
84 | } |
85 | |
86 | Ref<TrackBase> trackRef = *m_inbandTracks[index]; |
87 | |
88 | m_inbandTracks.remove(index); |
89 | |
90 | if (scheduleEvent) |
91 | scheduleRemoveTrackEvent(WTFMove(trackRef)); |
92 | } |
93 | |
94 | bool TrackListBase::contains(TrackBase& track) const |
95 | { |
96 | return m_inbandTracks.find(&track) != notFound; |
97 | } |
98 | |
99 | void TrackListBase::scheduleTrackEvent(const AtomicString& eventName, Ref<TrackBase>&& track) |
100 | { |
101 | m_asyncEventQueue.enqueueEvent(TrackEvent::create(eventName, Event::CanBubble::No, Event::IsCancelable::No, WTFMove(track))); |
102 | } |
103 | |
104 | void TrackListBase::scheduleAddTrackEvent(Ref<TrackBase>&& track) |
105 | { |
106 | // 4.8.10.5 Loading the media resource |
107 | // ... |
108 | // Fire a trusted event with the name addtrack, that does not bubble and is |
109 | // not cancelable, and that uses the TrackEvent interface, with the track |
110 | // attribute initialized to the new AudioTrack object, at this |
111 | // AudioTrackList object. |
112 | // ... |
113 | // Fire a trusted event with the name addtrack, that does not bubble and is |
114 | // not cancelable, and that uses the TrackEvent interface, with the track |
115 | // attribute initialized to the new VideoTrack object, at this |
116 | // VideoTrackList object. |
117 | |
118 | // 4.8.10.12.3 Sourcing out-of-band text tracks |
119 | // 4.8.10.12.4 Text track API |
120 | // ... then queue a task to fire an event with the name addtrack, that does not |
121 | // bubble and is not cancelable, and that uses the TrackEvent interface, with |
122 | // the track attribute initialized to the text track's TextTrack object, at |
123 | // the media element's textTracks attribute's TextTrackList object. |
124 | scheduleTrackEvent(eventNames().addtrackEvent, WTFMove(track)); |
125 | } |
126 | |
127 | void TrackListBase::scheduleRemoveTrackEvent(Ref<TrackBase>&& track) |
128 | { |
129 | // 4.8.10.6 Offsets into the media resource |
130 | // If at any time the user agent learns that an audio or video track has |
131 | // ended and all media data relating to that track corresponds to parts of |
132 | // the media timeline that are before the earliest possible position, the |
133 | // user agent may queue a task to remove the track from the audioTracks |
134 | // attribute's AudioTrackList object or the videoTracks attribute's |
135 | // VideoTrackList object as appropriate and then fire a trusted event |
136 | // with the name removetrack, that does not bubble and is not cancelable, |
137 | // and that uses the TrackEvent interface, with the track attribute |
138 | // initialized to the AudioTrack or VideoTrack object representing the |
139 | // track, at the media element's aforementioned AudioTrackList or |
140 | // VideoTrackList object. |
141 | |
142 | // 4.8.10.12.3 Sourcing out-of-band text tracks |
143 | // When a track element's parent element changes and the old parent was a |
144 | // media element, then the user agent must remove the track element's |
145 | // corresponding text track from the media element's list of text tracks, |
146 | // and then queue a task to fire a trusted event with the name removetrack, |
147 | // that does not bubble and is not cancelable, and that uses the TrackEvent |
148 | // interface, with the track attribute initialized to the text track's |
149 | // TextTrack object, at the media element's textTracks attribute's |
150 | // TextTrackList object. |
151 | scheduleTrackEvent(eventNames().removetrackEvent, WTFMove(track)); |
152 | } |
153 | |
154 | void TrackListBase::scheduleChangeEvent() |
155 | { |
156 | // 4.8.10.6 Offsets into the media resource |
157 | // Whenever an audio track in an AudioTrackList is enabled or disabled, the |
158 | // user agent must queue a task to fire a simple event named change at the |
159 | // AudioTrackList object. |
160 | // ... |
161 | // Whenever a track in a VideoTrackList that was previously not selected is |
162 | // selected, the user agent must queue a task to fire a simple event named |
163 | // change at the VideoTrackList object. |
164 | m_asyncEventQueue.enqueueEvent(Event::create(eventNames().changeEvent, Event::CanBubble::No, Event::IsCancelable::No)); |
165 | } |
166 | |
167 | bool TrackListBase::isChangeEventScheduled() const |
168 | { |
169 | return m_asyncEventQueue.hasPendingEventsOfType(eventNames().changeEvent); |
170 | } |
171 | |
172 | bool TrackListBase::isAnyTrackEnabled() const |
173 | { |
174 | for (auto& track : m_inbandTracks) { |
175 | if (track->enabled()) |
176 | return true; |
177 | } |
178 | return false; |
179 | } |
180 | |
181 | bool TrackListBase::canSuspendForDocumentSuspension() const |
182 | { |
183 | return !m_asyncEventQueue.hasPendingEvents(); |
184 | } |
185 | |
186 | void TrackListBase::suspend(ReasonForSuspension reason) |
187 | { |
188 | switch (reason) { |
189 | case ReasonForSuspension::PageCache: |
190 | case ReasonForSuspension::PageWillBeSuspended: |
191 | m_asyncEventQueue.suspend(); |
192 | break; |
193 | case ReasonForSuspension::JavaScriptDebuggerPaused: |
194 | case ReasonForSuspension::WillDeferLoading: |
195 | // Do nothing, we don't pause media playback in these cases. |
196 | break; |
197 | } |
198 | } |
199 | |
200 | void TrackListBase::resume() |
201 | { |
202 | m_asyncEventQueue.resume(); |
203 | } |
204 | |
205 | void TrackListBase::stop() |
206 | { |
207 | m_asyncEventQueue.close(); |
208 | } |
209 | |
210 | } // namespace WebCore |
211 | |
212 | #endif |
213 | |