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/. */
7 #include "MediaTrack.h"
8 #include "MediaTrackList.h"
9 #include "mozilla/AsyncEventDispatcher.h"
10 #include "mozilla/dom/HTMLMediaElement.h"
11 #include "mozilla/dom/AudioTrack.h"
12 #include "mozilla/dom/VideoTrack.h"
13 #include "mozilla/dom/TrackEvent.h"
14 #include "nsThreadUtils.h"
16 namespace mozilla::dom
{
18 MediaTrackList::MediaTrackList(nsIGlobalObject
* aOwnerObject
,
19 HTMLMediaElement
* aMediaElement
)
20 : DOMEventTargetHelper(aOwnerObject
), mMediaElement(aMediaElement
) {}
22 MediaTrackList::~MediaTrackList() = default;
24 NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaTrackList
, DOMEventTargetHelper
,
25 mTracks
, mMediaElement
)
27 NS_IMPL_ADDREF_INHERITED(MediaTrackList
, DOMEventTargetHelper
)
28 NS_IMPL_RELEASE_INHERITED(MediaTrackList
, DOMEventTargetHelper
)
29 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaTrackList
)
30 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper
)
32 MediaTrack
* MediaTrackList::operator[](uint32_t aIndex
) {
33 return mTracks
.ElementAt(aIndex
);
36 MediaTrack
* MediaTrackList::IndexedGetter(uint32_t aIndex
, bool& aFound
) {
37 aFound
= aIndex
< mTracks
.Length();
41 return mTracks
[aIndex
];
44 MediaTrack
* MediaTrackList::GetTrackById(const nsAString
& aId
) {
45 for (uint32_t i
= 0; i
< mTracks
.Length(); ++i
) {
46 if (aId
.Equals(mTracks
[i
]->GetId())) {
53 void MediaTrackList::AddTrack(MediaTrack
* aTrack
) {
54 MOZ_ASSERT(aTrack
->GetOwnerGlobal() == GetOwnerGlobal(),
55 "Where is this track from?");
56 mTracks
.AppendElement(aTrack
);
57 aTrack
->SetTrackList(this);
58 CreateAndDispatchTrackEventRunner(aTrack
, u
"addtrack"_ns
);
60 if (HTMLMediaElement
* element
= GetMediaElement()) {
61 element
->NotifyMediaTrackAdded(aTrack
);
64 if ((!aTrack
->AsAudioTrack() || !aTrack
->AsAudioTrack()->Enabled()) &&
65 (!aTrack
->AsVideoTrack() || !aTrack
->AsVideoTrack()->Selected())) {
66 // Track not enabled, no need to notify media element.
70 if (HTMLMediaElement
* element
= GetMediaElement()) {
71 element
->NotifyMediaTrackEnabled(aTrack
);
75 void MediaTrackList::RemoveTrack(const RefPtr
<MediaTrack
>& aTrack
) {
76 mTracks
.RemoveElement(aTrack
);
77 aTrack
->SetEnabledInternal(false, MediaTrack::FIRE_NO_EVENTS
);
78 aTrack
->SetTrackList(nullptr);
79 CreateAndDispatchTrackEventRunner(aTrack
, u
"removetrack"_ns
);
80 if (HTMLMediaElement
* element
= GetMediaElement()) {
81 element
->NotifyMediaTrackRemoved(aTrack
);
85 void MediaTrackList::RemoveTracks() {
86 while (!mTracks
.IsEmpty()) {
87 RefPtr
<MediaTrack
> track
= mTracks
.LastElement();
92 already_AddRefed
<AudioTrack
> MediaTrackList::CreateAudioTrack(
93 nsIGlobalObject
* aOwnerGlobal
, const nsAString
& aId
, const nsAString
& aKind
,
94 const nsAString
& aLabel
, const nsAString
& aLanguage
, bool aEnabled
,
95 AudioStreamTrack
* aAudioTrack
) {
96 RefPtr
<AudioTrack
> track
= new AudioTrack(aOwnerGlobal
, aId
, aKind
, aLabel
,
97 aLanguage
, aEnabled
, aAudioTrack
);
98 return track
.forget();
101 already_AddRefed
<VideoTrack
> MediaTrackList::CreateVideoTrack(
102 nsIGlobalObject
* aOwnerGlobal
, const nsAString
& aId
, const nsAString
& aKind
,
103 const nsAString
& aLabel
, const nsAString
& aLanguage
,
104 VideoStreamTrack
* aVideoTrack
) {
105 RefPtr
<VideoTrack
> track
=
106 new VideoTrack(aOwnerGlobal
, aId
, aKind
, aLabel
, aLanguage
, aVideoTrack
);
107 return track
.forget();
110 void MediaTrackList::EmptyTracks() {
111 for (uint32_t i
= 0; i
< mTracks
.Length(); ++i
) {
112 mTracks
[i
]->SetEnabledInternal(false, MediaTrack::FIRE_NO_EVENTS
);
113 mTracks
[i
]->SetTrackList(nullptr);
118 void MediaTrackList::CreateAndDispatchChangeEvent() {
119 RefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
120 new AsyncEventDispatcher(this, u
"change"_ns
, CanBubble::eNo
);
121 asyncDispatcher
->PostDOMEvent();
124 void MediaTrackList::CreateAndDispatchTrackEventRunner(
125 MediaTrack
* aTrack
, const nsAString
& aEventName
) {
126 TrackEventInit eventInit
;
128 if (aTrack
->AsAudioTrack()) {
129 eventInit
.mTrack
.SetValue().SetAsAudioTrack() = aTrack
->AsAudioTrack();
130 } else if (aTrack
->AsVideoTrack()) {
131 eventInit
.mTrack
.SetValue().SetAsVideoTrack() = aTrack
->AsVideoTrack();
134 RefPtr
<TrackEvent
> event
=
135 TrackEvent::Constructor(this, aEventName
, eventInit
);
137 RefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
138 new AsyncEventDispatcher(this, event
);
139 asyncDispatcher
->PostDOMEvent();
142 } // namespace mozilla::dom