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 // Extracts elements from the queue into aResult, in order.
128 // Elements whose start time is before aTime are ignored.
129 void GetElementsAfter(int64_t aTime
, nsTArray
<RefPtr
<T
>>* aResult
) {
130 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
131 if (GetSize() == 0) return;
133 for (i
= GetSize() - 1; i
> 0; --i
) {
134 T
* v
= nsRefPtrDeque
<T
>::ObjectAt(i
);
135 if (v
->GetEndTime().ToMicroseconds() < aTime
) break;
137 // Elements less than i have a end time before aTime. It's also possible
138 // that the element at i has a end time before aTime, but that's OK.
139 for (; i
< GetSize(); ++i
) {
140 RefPtr
<T
> elem
= nsRefPtrDeque
<T
>::ObjectAt(i
);
141 aResult
->AppendElement(elem
);
145 void GetElementsAfter(const media::TimeUnit
& aTime
,
146 nsTArray
<RefPtr
<T
>>* aResult
) {
147 GetElementsAfter(aTime
.ToMicroseconds(), aResult
);
150 void GetFirstElements(uint32_t aMaxElements
, nsTArray
<RefPtr
<T
>>* aResult
) {
151 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
152 for (size_t i
= 0; i
< aMaxElements
&& i
< GetSize(); ++i
) {
153 *aResult
->AppendElement() = nsRefPtrDeque
<T
>::ObjectAt(i
);
157 uint32_t AudioFramesCount() {
158 static_assert(std::is_same_v
<T
, AudioData
>,
159 "Only usable with MediaQueue<AudioData>");
160 RecursiveMutexAutoLock
lock(mRecursiveMutex
);
162 for (size_t i
= 0; i
< GetSize(); ++i
) {
163 T
* v
= nsRefPtrDeque
<T
>::ObjectAt(i
);
164 frames
+= v
->Frames();
169 MediaEventSource
<RefPtr
<T
>>& PopFrontEvent() { return mPopFrontEvent
; }
171 MediaEventSource
<RefPtr
<T
>>& PushEvent() { return mPushEvent
; }
173 MediaEventSource
<void>& FinishEvent() { return mFinishEvent
; }
176 mutable RecursiveMutex mRecursiveMutex
;
177 MediaEventProducer
<RefPtr
<T
>> mPopFrontEvent
;
178 MediaEventProducer
<RefPtr
<T
>> mPushEvent
;
179 MediaEventProducer
<void> mFinishEvent
;
180 // True when we've decoded the last frame of data in the
181 // bitstream for which we're queueing frame data.
185 } // namespace mozilla