MediaTrackList.cpp (4848B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 et tw=78: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "MediaTrackList.h" 8 9 #include "MediaTrack.h" 10 #include "mozilla/AsyncEventDispatcher.h" 11 #include "mozilla/dom/AudioTrack.h" 12 #include "mozilla/dom/HTMLMediaElement.h" 13 #include "mozilla/dom/TrackEvent.h" 14 #include "mozilla/dom/VideoTrack.h" 15 #include "nsThreadUtils.h" 16 17 namespace mozilla::dom { 18 19 MediaTrackList::MediaTrackList(nsIGlobalObject* aOwnerObject, 20 HTMLMediaElement* aMediaElement) 21 : DOMEventTargetHelper(aOwnerObject), mMediaElement(aMediaElement) {} 22 23 MediaTrackList::~MediaTrackList() = default; 24 25 NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaTrackList, DOMEventTargetHelper, 26 mTracks, mMediaElement) 27 28 NS_IMPL_ADDREF_INHERITED(MediaTrackList, DOMEventTargetHelper) 29 NS_IMPL_RELEASE_INHERITED(MediaTrackList, DOMEventTargetHelper) 30 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaTrackList) 31 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) 32 33 MediaTrack* MediaTrackList::operator[](uint32_t aIndex) { 34 return mTracks.ElementAt(aIndex); 35 } 36 37 MediaTrack* MediaTrackList::IndexedGetter(uint32_t aIndex, bool& aFound) { 38 aFound = aIndex < mTracks.Length(); 39 if (!aFound) { 40 return nullptr; 41 } 42 return mTracks[aIndex]; 43 } 44 45 MediaTrack* MediaTrackList::GetTrackById(const nsAString& aId) { 46 for (uint32_t i = 0; i < mTracks.Length(); ++i) { 47 if (aId.Equals(mTracks[i]->GetId())) { 48 return mTracks[i]; 49 } 50 } 51 return nullptr; 52 } 53 54 void MediaTrackList::AddTrack(MediaTrack* aTrack) { 55 MOZ_ASSERT(aTrack->GetOwnerGlobal() == GetOwnerGlobal(), 56 "Where is this track from?"); 57 mTracks.AppendElement(aTrack); 58 aTrack->SetTrackList(this); 59 CreateAndDispatchTrackEventRunner(aTrack, u"addtrack"_ns); 60 61 if (HTMLMediaElement* element = GetMediaElement()) { 62 element->NotifyMediaTrackAdded(aTrack); 63 } 64 65 if ((!aTrack->AsAudioTrack() || !aTrack->AsAudioTrack()->Enabled()) && 66 (!aTrack->AsVideoTrack() || !aTrack->AsVideoTrack()->Selected())) { 67 // Track not enabled, no need to notify media element. 68 return; 69 } 70 71 if (HTMLMediaElement* element = GetMediaElement()) { 72 element->NotifyMediaTrackEnabled(aTrack); 73 } 74 } 75 76 void MediaTrackList::RemoveTrack(const RefPtr<MediaTrack>& aTrack) { 77 mTracks.RemoveElement(aTrack); 78 aTrack->SetEnabledInternal(false, MediaTrack::FIRE_NO_EVENTS); 79 aTrack->SetTrackList(nullptr); 80 CreateAndDispatchTrackEventRunner(aTrack, u"removetrack"_ns); 81 if (HTMLMediaElement* element = GetMediaElement()) { 82 element->NotifyMediaTrackRemoved(aTrack); 83 } 84 } 85 86 void MediaTrackList::RemoveTracks() { 87 while (!mTracks.IsEmpty()) { 88 RefPtr<MediaTrack> track = mTracks.LastElement(); 89 RemoveTrack(track); 90 } 91 } 92 93 already_AddRefed<AudioTrack> MediaTrackList::CreateAudioTrack( 94 nsIGlobalObject* aOwnerGlobal, const nsAString& aId, const nsAString& aKind, 95 const nsAString& aLabel, const nsAString& aLanguage, bool aEnabled, 96 AudioStreamTrack* aAudioTrack) { 97 RefPtr<AudioTrack> track = new AudioTrack(aOwnerGlobal, aId, aKind, aLabel, 98 aLanguage, aEnabled, aAudioTrack); 99 return track.forget(); 100 } 101 102 already_AddRefed<VideoTrack> MediaTrackList::CreateVideoTrack( 103 nsIGlobalObject* aOwnerGlobal, const nsAString& aId, const nsAString& aKind, 104 const nsAString& aLabel, const nsAString& aLanguage, 105 VideoStreamTrack* aVideoTrack) { 106 RefPtr<VideoTrack> track = 107 new VideoTrack(aOwnerGlobal, aId, aKind, aLabel, aLanguage, aVideoTrack); 108 return track.forget(); 109 } 110 111 void MediaTrackList::EmptyTracks() { 112 for (uint32_t i = 0; i < mTracks.Length(); ++i) { 113 mTracks[i]->SetEnabledInternal(false, MediaTrack::FIRE_NO_EVENTS); 114 mTracks[i]->SetTrackList(nullptr); 115 } 116 mTracks.Clear(); 117 } 118 119 void MediaTrackList::CreateAndDispatchChangeEvent() { 120 RefPtr<AsyncEventDispatcher> asyncDispatcher = 121 new AsyncEventDispatcher(this, u"change"_ns, CanBubble::eNo); 122 asyncDispatcher->PostDOMEvent(); 123 } 124 125 void MediaTrackList::CreateAndDispatchTrackEventRunner( 126 MediaTrack* aTrack, const nsAString& aEventName) { 127 TrackEventInit eventInit; 128 129 if (aTrack->AsAudioTrack()) { 130 eventInit.mTrack.SetValue().SetAsAudioTrack() = aTrack->AsAudioTrack(); 131 } else if (aTrack->AsVideoTrack()) { 132 eventInit.mTrack.SetValue().SetAsVideoTrack() = aTrack->AsVideoTrack(); 133 } 134 135 RefPtr<TrackEvent> event = 136 TrackEvent::Constructor(this, aEventName, eventInit); 137 138 RefPtr<AsyncEventDispatcher> asyncDispatcher = 139 new AsyncEventDispatcher(this, event.forget()); 140 asyncDispatcher->PostDOMEvent(); 141 } 142 143 } // namespace mozilla::dom