1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "MediaEventSource.h"
9 #include "MediaUtils.h"
10 #include "mozilla/Maybe.h"
11 #include "mozilla/MozPromise.h"
12 #include "mozilla/ResultVariant.h"
13 #include "mozilla/SpinEventLoopUntil.h"
18 * Waits for an occurrence of aEvent on the current thread (by blocking it,
19 * except tasks added to the event loop may run) and returns the event's
20 * templated value, if it's non-void.
22 * The caller must be wary of eventloop issues, in
23 * particular cases where we rely on a stable state runnable, but there is never
24 * a task to trigger stable state. In such cases it is the responsibility of the
25 * caller to create the needed tasks, as JS would. A noteworthy API that relies
26 * on stable state is MediaTrackGraph::GetInstance.
29 T
WaitFor(MediaEventSource
<T
>& aEvent
) {
31 MediaEventListener listener
= aEvent
.Connect(
32 AbstractThread::GetCurrent(), [&](T aValue
) { value
= Some(aValue
); });
33 SpinEventLoopUntil
<ProcessFailureBehavior::IgnoreAndContinue
>(
34 "WaitFor(MediaEventSource<T>& aEvent)"_ns
,
35 [&] { return value
.isSome(); });
36 listener
.Disconnect();
41 * Specialization of WaitFor<T> for void.
43 void WaitFor(MediaEventSource
<void>& aEvent
);
46 * Variant of WaitFor that blocks the caller until a MozPromise has either been
47 * resolved or rejected.
49 template <typename R
, typename E
, bool Exc
>
50 Result
<R
, E
> WaitFor(const RefPtr
<MozPromise
<R
, E
, Exc
>>& aPromise
) {
54 GetCurrentSerialEventTarget(), __func__
,
55 [&](R aResult
) { success
= Some(aResult
); },
56 [&](E aError
) { error
= Some(aError
); });
57 SpinEventLoopUntil
<ProcessFailureBehavior::IgnoreAndContinue
>(
58 "WaitFor(const RefPtr<MozPromise<R, E, Exc>>& aPromise)"_ns
,
59 [&] { return success
.isSome() || error
.isSome(); });
60 if (success
.isSome()) {
61 return success
.extract();
63 return Err(error
.extract());
67 * A variation of WaitFor that takes a callback to be called each time aEvent is
68 * raised. Blocks the caller until the callback function returns true.
70 template <typename
... Args
, typename CallbackFunction
>
71 void WaitUntil(MediaEventSource
<Args
...>& aEvent
, CallbackFunction
&& aF
) {
73 MediaEventListener listener
=
74 aEvent
.Connect(AbstractThread::GetCurrent(), [&](Args
... aValue
) {
76 done
= aF(std::forward
<Args
>(aValue
)...);
79 SpinEventLoopUntil
<ProcessFailureBehavior::IgnoreAndContinue
>(
80 "WaitUntil(MediaEventSource<Args...>& aEvent, CallbackFunction&& aF)"_ns
,
81 [&] { return done
; });
82 listener
.Disconnect();
85 template <typename
... Args
>
86 using TakeNPromise
= MozPromise
<std::vector
<std::tuple
<Args
...>>, bool, true>;
88 template <ListenerPolicy Lp
, typename
... Args
>
89 auto TakeN(MediaEventSourceImpl
<Lp
, Args
...>& aEvent
, size_t aN
)
90 -> RefPtr
<TakeNPromise
<Args
...>> {
91 using Storage
= std::vector
<std::tuple
<Args
...>>;
92 using Promise
= TakeNPromise
<Args
...>;
93 using Values
= media::Refcountable
<Storage
>;
94 using Listener
= media::Refcountable
<MediaEventListener
>;
95 RefPtr
<Values
> values
= MakeRefPtr
<Values
>();
97 RefPtr
<Listener
> listener
= MakeRefPtr
<Listener
>();
98 auto promise
= InvokeAsync(
99 AbstractThread::GetCurrent(), __func__
, [values
, aN
]() mutable {
100 SpinEventLoopUntil
<ProcessFailureBehavior::IgnoreAndContinue
>(
101 "TakeN(MediaEventSourceImpl<Lp, Args...>& aEvent, size_t aN)"_ns
,
102 [&] { return values
->size() == aN
; });
103 return Promise::CreateAndResolve(std::move(*values
), __func__
);
105 *listener
= aEvent
.Connect(AbstractThread::GetCurrent(),
106 [values
, listener
, aN
](Args
... aValue
) {
107 values
->push_back({aValue
...});
108 if (values
->size() == aN
) {
109 listener
->Disconnect();
116 * Helper that, given that canonicals have just been updated on the current
117 * thread, will block its execution until mirrors and their watchers have
118 * executed on aTarget.
120 inline void WaitForMirrors(const RefPtr
<nsISerialEventTarget
>& aTarget
) {
121 Unused
<< WaitFor(InvokeAsync(aTarget
, __func__
, [] {
122 return GenericPromise::CreateAndResolve(true, "WaitForMirrors resolver");
127 * Short form of WaitForMirrors that assumes mirrors are on the current thread
130 inline void WaitForMirrors() { WaitForMirrors(GetCurrentSerialEventTarget()); }
132 } // namespace mozilla