1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
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 #if !defined(MediaQueue_h_)
9 # include <type_traits>
11 # include "mozilla/RecursiveMutex.h"
12 # include "mozilla/TaskQueue.h"
15 # include "MediaEventSource.h"
16 # include "TimeUnits.h"
23 class MediaQueue
: private nsRefPtrDeque
<T
> {
27 mRecursiveMutex("mediaqueue"),
28 mEndOfStream(false) {}
30 ~MediaQueue() { Reset(); }
32 inline size_t GetSize() const {
33 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
34 return nsRefPtrDeque
<T
>::GetSize();
37 inline void Push(T
* aItem
) {
38 MOZ_DIAGNOSTIC_ASSERT(aItem
);
39 Push(do_AddRef(aItem
));
42 inline void Push(already_AddRefed
<T
> aItem
) {
43 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
44 T
* item
= aItem
.take();
46 MOZ_DIAGNOSTIC_ASSERT(item
);
47 MOZ_DIAGNOSTIC_ASSERT(item
->GetEndTime() >= item
->mTime
);
48 nsRefPtrDeque
<T
>::Push(dont_AddRef(item
));
49 mPushEvent
.Notify(RefPtr
<T
>(item
));
51 // Pushing new data after queue has ended means that the stream is active
52 // again, so we should not mark it as ended.
58 inline already_AddRefed
<T
> PopFront() {
59 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
60 RefPtr
<T
> rv
= nsRefPtrDeque
<T
>::PopFront();
62 MOZ_DIAGNOSTIC_ASSERT(rv
->GetEndTime() >= rv
->mTime
);
63 mPopFrontEvent
.Notify(RefPtr
<T
>(rv
));
68 inline already_AddRefed
<T
> PopBack() {
69 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
70 return nsRefPtrDeque
<T
>::Pop();
73 inline RefPtr
<T
> PeekFront() const {
74 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
75 return nsRefPtrDeque
<T
>::PeekFront();
78 inline RefPtr
<T
> PeekBack() const {
79 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
80 return nsRefPtrDeque
<T
>::Peek();
84 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
85 nsRefPtrDeque
<T
>::Erase();
89 bool AtEndOfStream() const {
90 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
91 return GetSize() == 0 && mEndOfStream
;
94 // Returns true if the media queue has had its last item added to it.
95 // This happens when the media stream has been completely decoded. Note this
96 // does not mean that the corresponding stream has finished playback.
97 bool IsFinished() const {
98 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
102 // Informs the media queue that it won't be receiving any more items.
104 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
107 mFinishEvent
.Notify();
111 // Returns the approximate number of microseconds of items in the queue.
113 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
114 if (GetSize() == 0) {
117 T
* last
= nsRefPtrDeque
<T
>::Peek();
118 T
* first
= nsRefPtrDeque
<T
>::PeekFront();
119 return (last
->GetEndTime() - first
->mTime
).ToMicroseconds();
122 void LockedForEach(nsDequeFunctor
<T
>& aFunctor
) const {
123 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
124 nsRefPtrDeque
<T
>::ForEach(aFunctor
);
127 // Fill aResult with the elements which end later than the given time aTime.
128 void GetElementsAfter(const media::TimeUnit
& aTime
,
129 nsTArray
<RefPtr
<T
>>* aResult
) {
130 GetElementsAfterStrict(aTime
.ToMicroseconds(), aResult
);
133 void GetFirstElements(uint32_t aMaxElements
, nsTArray
<RefPtr
<T
>>* aResult
) {
134 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
135 for (size_t i
= 0; i
< aMaxElements
&& i
< GetSize(); ++i
) {
136 *aResult
->AppendElement() = nsRefPtrDeque
<T
>::ObjectAt(i
);
140 uint32_t AudioFramesCount() {
141 static_assert(std::is_same_v
<T
, AudioData
>,
142 "Only usable with MediaQueue<AudioData>");
143 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
145 for (size_t i
= 0; i
< GetSize(); ++i
) {
146 T
* v
= nsRefPtrDeque
<T
>::ObjectAt(i
);
147 frames
+= v
->Frames();
152 MediaEventSource
<RefPtr
<T
>>& PopFrontEvent() { return mPopFrontEvent
; }
154 MediaEventSource
<RefPtr
<T
>>& PushEvent() { return mPushEvent
; }
156 MediaEventSource
<void>& FinishEvent() { return mFinishEvent
; }
159 // Extracts elements from the queue into aResult, in order.
160 // Elements whose end time is before or equal to aTime are ignored.
161 void GetElementsAfterStrict(int64_t aTime
, nsTArray
<RefPtr
<T
>>* aResult
) {
162 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
163 if (GetSize() == 0) return;
165 for (i
= GetSize() - 1; i
> 0; --i
) {
166 T
* v
= nsRefPtrDeque
<T
>::ObjectAt(i
);
167 if (v
->GetEndTime().ToMicroseconds() < aTime
) break;
169 for (; i
< GetSize(); ++i
) {
170 RefPtr
<T
> elem
= nsRefPtrDeque
<T
>::ObjectAt(i
);
171 if (elem
->GetEndTime().ToMicroseconds() > aTime
) {
172 aResult
->AppendElement(elem
);
177 mutable RecursiveMutex mRecursiveMutex
;
178 MediaEventProducer
<RefPtr
<T
>> mPopFrontEvent
;
179 MediaEventProducer
<RefPtr
<T
>> mPushEvent
;
180 MediaEventProducer
<void> mFinishEvent
;
181 // True when we've decoded the last frame of data in the
182 // bitstream for which we're queueing frame data.
186 } // namespace mozilla