1 /*
2  * Copyright (C) 2012, Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
23  * DAMAGE.
24  */
25 
26 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_OFFLINE_AUDIO_CONTEXT_H_
27 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_OFFLINE_AUDIO_CONTEXT_H_
28 
29 #include "third_party/blink/renderer/modules/modules_export.h"
30 #include "third_party/blink/renderer/modules/webaudio/base_audio_context.h"
31 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
32 
33 namespace blink {
34 
35 class ExceptionState;
36 class OfflineAudioContextOptions;
37 class OfflineAudioDestinationHandler;
38 
39 class MODULES_EXPORT OfflineAudioContext final : public BaseAudioContext {
40   DEFINE_WRAPPERTYPEINFO();
41 
42  public:
43   static OfflineAudioContext* Create(ExecutionContext*,
44                                      unsigned number_of_channels,
45                                      unsigned number_of_frames,
46                                      float sample_rate,
47                                      ExceptionState&);
48 
49   static OfflineAudioContext* Create(ExecutionContext*,
50                                      const OfflineAudioContextOptions*,
51                                      ExceptionState&);
52 
53   OfflineAudioContext(Document*,
54                       unsigned number_of_channels,
55                       uint32_t number_of_frames,
56                       float sample_rate,
57                       ExceptionState&);
58   ~OfflineAudioContext() override;
59 
60   void Trace(Visitor*) override;
61 
length()62   uint32_t length() const { return total_render_frames_; }
63 
64   ScriptPromise startOfflineRendering(ScriptState*, ExceptionState&);
65 
66   ScriptPromise suspendContext(ScriptState*, double);
67   ScriptPromise resumeContext(ScriptState*);
68 
69   void RejectPendingResolvers() override;
70 
HasRealtimeConstraint()71   bool HasRealtimeConstraint() final { return false; }
72 
73   bool IsPullingAudioGraph() const final;
74 
75   DEFINE_ATTRIBUTE_EVENT_LISTENER(complete, kComplete)
76 
77   // Fire completion event when the rendering is finished.
78   void FireCompletionEvent();
79 
80   bool HandlePreRenderTasks(const AudioIOPosition* output_position,
81                             const AudioCallbackMetric* metric) final;
82   void HandlePostRenderTasks() final;
83 
84   // Resolve a suspend scheduled at the specified frame. With this specified
85   // frame as a unique key, the associated promise resolver can be retrieved
86   // from the map (m_scheduledSuspends) and resolved.
87   void ResolveSuspendOnMainThread(size_t);
88 
89   // OfflineAudioContext is not affected by Autoplay, so this MUST do nothing.
NotifySourceNodeStart()90   void NotifySourceNodeStart() final {}
91 
92   // The HashMap with 'zero' key is needed because |currentSampleFrame| can be
93   // zero.
94   using SuspendMap = HeapHashMap<size_t,
95                                  Member<ScriptPromiseResolver>,
96                                  DefaultHash<size_t>::Hash,
97                                  WTF::UnsignedWithZeroKeyHashTraits<size_t>>;
98 
99   using OfflineGraphAutoLocker = DeferredTaskHandler::OfflineGraphAutoLocker;
100 
101   // Document notification
102   bool HasPendingActivity() const final;
103 
104  private:
105   // Fetch directly the destination handler.
106   OfflineAudioDestinationHandler& DestinationHandler();
107 
108   // Check if the rendering needs to be suspended.
109   bool ShouldSuspend();
110 
111   // This map is to store the timing of scheduled suspends (frame) and the
112   // associated promise resolver. This storage can only be modified by the
113   // main thread and accessed by the audio thread with the graph lock.
114   //
115   // The map consists of key-value pairs of:
116   // { size_t quantizedFrame: ScriptPromiseResolver resolver }
117   //
118   // Note that |quantizedFrame| is a unique key, since you can have only one
119   // suspend scheduled for a certain frame. Accessing to this must be
120   // protected by the offline context lock.
121   SuspendMap scheduled_suspends_;
122 
123   Member<ScriptPromiseResolver> complete_resolver_;
124 
125   // This flag is necessary to indicate the rendering has actually started or
126   // running. Note that initial state of context is 'Suspended', which is the
127   // same state when the context is suspended, so we cannot utilize it for this
128   // purpose.
129   bool is_rendering_started_;
130 
131   // Total render sample length.
132   uint32_t total_render_frames_;
133 };
134 
135 }  // namespace blink
136 
137 #endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_OFFLINE_AUDIO_CONTEXT_H_
138