/work/obj-fuzz/dist/include/AudioStream.h
Line | Count | Source (jump to first uncovered line) |
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(AudioStream_h_) |
7 | | #define AudioStream_h_ |
8 | | |
9 | | #include "AudioSampleFormat.h" |
10 | | #include "CubebUtils.h" |
11 | | #include "MediaInfo.h" |
12 | | #include "mozilla/Monitor.h" |
13 | | #include "mozilla/RefPtr.h" |
14 | | #include "mozilla/TimeStamp.h" |
15 | | #include "mozilla/UniquePtr.h" |
16 | | #include "nsAutoPtr.h" |
17 | | #include "nsCOMPtr.h" |
18 | | #include "nsThreadUtils.h" |
19 | | #include "soundtouch/SoundTouchFactory.h" |
20 | | |
21 | | #if defined(XP_WIN) |
22 | | #include "mozilla/audio/AudioNotificationReceiver.h" |
23 | | #endif |
24 | | |
25 | | namespace mozilla { |
26 | | |
27 | | struct CubebDestroyPolicy |
28 | | { |
29 | | void operator()(cubeb_stream* aStream) const { |
30 | | cubeb_stream_destroy(aStream); |
31 | | } |
32 | | }; |
33 | | |
34 | | class AudioStream; |
35 | | class FrameHistory; |
36 | | class AudioConfig; |
37 | | class AudioConverter; |
38 | | |
39 | | class AudioClock |
40 | | { |
41 | | public: |
42 | | AudioClock(); |
43 | | |
44 | | // Initialize the clock with the current sampling rate. |
45 | | // Need to be called before querying the clock. |
46 | | void Init(uint32_t aRate); |
47 | | |
48 | | // Update the number of samples that has been written in the audio backend. |
49 | | // Called on the state machine thread. |
50 | | void UpdateFrameHistory(uint32_t aServiced, uint32_t aUnderrun); |
51 | | |
52 | | /** |
53 | | * @param aFrames The playback position in frames of the audio engine. |
54 | | * @return The playback position in frames of the stream, |
55 | | * adjusted by playback rate changes and underrun frames. |
56 | | */ |
57 | | int64_t GetPositionInFrames(int64_t aFrames) const; |
58 | | |
59 | | /** |
60 | | * @param frames The playback position in frames of the audio engine. |
61 | | * @return The playback position in microseconds of the stream, |
62 | | * adjusted by playback rate changes and underrun frames. |
63 | | */ |
64 | | int64_t GetPosition(int64_t frames) const; |
65 | | |
66 | | // Set the playback rate. |
67 | | // Called on the audio thread. |
68 | | void SetPlaybackRate(double aPlaybackRate); |
69 | | // Get the current playback rate. |
70 | | // Called on the audio thread. |
71 | | double GetPlaybackRate() const; |
72 | | // Set if we are preserving the pitch. |
73 | | // Called on the audio thread. |
74 | | void SetPreservesPitch(bool aPreservesPitch); |
75 | | // Get the current pitch preservation state. |
76 | | // Called on the audio thread. |
77 | | bool GetPreservesPitch() const; |
78 | | |
79 | | uint32_t GetInputRate() const { return mInRate; } |
80 | | uint32_t GetOutputRate() const { return mOutRate; } |
81 | | |
82 | | private: |
83 | | // Output rate in Hz (characteristic of the playback rate) |
84 | | uint32_t mOutRate; |
85 | | // Input rate in Hz (characteristic of the media being played) |
86 | | uint32_t mInRate; |
87 | | // True if the we are timestretching, false if we are resampling. |
88 | | bool mPreservesPitch; |
89 | | // The history of frames sent to the audio engine in each DataCallback. |
90 | | const nsAutoPtr<FrameHistory> mFrameHistory; |
91 | | }; |
92 | | |
93 | | /* |
94 | | * A bookkeeping class to track the read/write position of an audio buffer. |
95 | | */ |
96 | | class AudioBufferCursor { |
97 | | public: |
98 | | AudioBufferCursor(AudioDataValue* aPtr, uint32_t aChannels, uint32_t aFrames) |
99 | | : mPtr(aPtr), mChannels(aChannels), mFrames(aFrames) {} |
100 | | |
101 | | // Advance the cursor to account for frames that are consumed. |
102 | | uint32_t Advance(uint32_t aFrames) { |
103 | | MOZ_ASSERT(mFrames >= aFrames); |
104 | | mFrames -= aFrames; |
105 | | mPtr += mChannels * aFrames; |
106 | | return aFrames; |
107 | | } |
108 | | |
109 | | // The number of frames available for read/write in this buffer. |
110 | | uint32_t Available() const { return mFrames; } |
111 | | |
112 | | // Return a pointer where read/write should begin. |
113 | 0 | AudioDataValue* Ptr() const { return mPtr; } |
114 | | |
115 | | protected: |
116 | | AudioDataValue* mPtr; |
117 | | const uint32_t mChannels; |
118 | | uint32_t mFrames; |
119 | | }; |
120 | | |
121 | | /* |
122 | | * A helper class to encapsulate pointer arithmetic and provide means to modify |
123 | | * the underlying audio buffer. |
124 | | */ |
125 | | class AudioBufferWriter : private AudioBufferCursor { |
126 | | public: |
127 | | AudioBufferWriter(AudioDataValue* aPtr, uint32_t aChannels, uint32_t aFrames) |
128 | | : AudioBufferCursor(aPtr, aChannels, aFrames) {} |
129 | | |
130 | | uint32_t WriteZeros(uint32_t aFrames) { |
131 | | memset(mPtr, 0, sizeof(AudioDataValue) * mChannels * aFrames); |
132 | | return Advance(aFrames); |
133 | | } |
134 | | |
135 | | uint32_t Write(const AudioDataValue* aPtr, uint32_t aFrames) { |
136 | | memcpy(mPtr, aPtr, sizeof(AudioDataValue) * mChannels * aFrames); |
137 | | return Advance(aFrames); |
138 | | } |
139 | | |
140 | | // Provide a write fuction to update the audio buffer with the following |
141 | | // signature: uint32_t(const AudioDataValue* aPtr, uint32_t aFrames) |
142 | | // aPtr: Pointer to the audio buffer. |
143 | | // aFrames: The number of frames available in the buffer. |
144 | | // return: The number of frames actually written by the function. |
145 | | template <typename Function> |
146 | | uint32_t Write(const Function& aFunction, uint32_t aFrames) { |
147 | | return Advance(aFunction(mPtr, aFrames)); |
148 | | } |
149 | | |
150 | | using AudioBufferCursor::Available; |
151 | | }; |
152 | | |
153 | | // Access to a single instance of this class must be synchronized by |
154 | | // callers, or made from a single thread. One exception is that access to |
155 | | // GetPosition, GetPositionInFrames, SetVolume, and Get{Rate,Channels}, |
156 | | // SetMicrophoneActive is thread-safe without external synchronization. |
157 | | class AudioStream final |
158 | | #if defined(XP_WIN) |
159 | | : public audio::DeviceChangeListener |
160 | | #endif |
161 | | { |
162 | | virtual ~AudioStream(); |
163 | | |
164 | | public: |
165 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioStream) |
166 | | |
167 | | class Chunk { |
168 | | public: |
169 | | // Return a pointer to the audio data. |
170 | | virtual const AudioDataValue* Data() const = 0; |
171 | | // Return the number of frames in this chunk. |
172 | | virtual uint32_t Frames() const = 0; |
173 | | // Return the number of audio channels. |
174 | | virtual uint32_t Channels() const = 0; |
175 | | // Return the sample rate of this chunk. |
176 | | virtual uint32_t Rate() const = 0; |
177 | | // Return a writable pointer for downmixing. |
178 | | virtual AudioDataValue* GetWritable() const = 0; |
179 | 0 | virtual ~Chunk() {} |
180 | | }; |
181 | | |
182 | | class DataSource { |
183 | | public: |
184 | | // Return a chunk which contains at most aFrames frames or zero if no |
185 | | // frames in the source at all. |
186 | | virtual UniquePtr<Chunk> PopFrames(uint32_t aFrames) = 0; |
187 | | // Return true if no more data will be added to the source. |
188 | | virtual bool Ended() const = 0; |
189 | | // Notify that all data is drained by the AudioStream. |
190 | | virtual void Drained() = 0; |
191 | | protected: |
192 | 0 | virtual ~DataSource() {} |
193 | | }; |
194 | | |
195 | | explicit AudioStream(DataSource& aSource); |
196 | | |
197 | | // Initialize the audio stream. aNumChannels is the number of audio |
198 | | // channels (1 for mono, 2 for stereo, etc), aChannelMap is the indicator for |
199 | | // channel layout(mono, stereo, 5.1 or 7.1 ) and aRate is the sample rate |
200 | | // (22050Hz, 44100Hz, etc). |
201 | | nsresult Init(uint32_t aNumChannels, |
202 | | AudioConfig::ChannelLayout::ChannelMap aChannelMap, |
203 | | uint32_t aRate); |
204 | | |
205 | | // Closes the stream. All future use of the stream is an error. |
206 | | void Shutdown(); |
207 | | |
208 | | void Reset(); |
209 | | |
210 | | // Set the current volume of the audio playback. This is a value from |
211 | | // 0 (meaning muted) to 1 (meaning full volume). Thread-safe. |
212 | | void SetVolume(double aVolume); |
213 | | |
214 | | // Start the stream. |
215 | | void Start(); |
216 | | |
217 | | // Pause audio playback. |
218 | | void Pause(); |
219 | | |
220 | | // Resume audio playback. |
221 | | void Resume(); |
222 | | |
223 | | #if defined(XP_WIN) |
224 | | // Reset stream to the default device. |
225 | | void ResetDefaultDevice() override; |
226 | | #endif |
227 | | |
228 | | // Return the position in microseconds of the audio frame being played by |
229 | | // the audio hardware, compensated for playback rate change. Thread-safe. |
230 | | int64_t GetPosition(); |
231 | | |
232 | | // Return the position, measured in audio frames played since the stream |
233 | | // was opened, of the audio hardware. Thread-safe. |
234 | | int64_t GetPositionInFrames(); |
235 | | |
236 | | static uint32_t GetPreferredRate() |
237 | 0 | { |
238 | 0 | return CubebUtils::PreferredSampleRate(); |
239 | 0 | } |
240 | | |
241 | | uint32_t GetOutChannels() { return mOutChannels; } |
242 | | |
243 | | // Set playback rate as a multiple of the intrinsic playback rate. This is to |
244 | | // be called only with aPlaybackRate > 0.0. |
245 | | nsresult SetPlaybackRate(double aPlaybackRate); |
246 | | // Switch between resampling (if false) and time stretching (if true, default). |
247 | | nsresult SetPreservesPitch(bool aPreservesPitch); |
248 | | |
249 | | size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; |
250 | | |
251 | | protected: |
252 | | friend class AudioClock; |
253 | | |
254 | | // Return the position, measured in audio frames played since the stream was |
255 | | // opened, of the audio hardware, not adjusted for the changes of playback |
256 | | // rate or underrun frames. |
257 | | // Caller must own the monitor. |
258 | | int64_t GetPositionInFramesUnlocked(); |
259 | | |
260 | | private: |
261 | | nsresult OpenCubeb(cubeb* aContext, cubeb_stream_params& aParams, |
262 | | TimeStamp aStartTime, bool aIsFirst); |
263 | | |
264 | | static long DataCallback_S(cubeb_stream*, void* aThis, |
265 | | const void* /* aInputBuffer */, void* aOutputBuffer, |
266 | | long aFrames) |
267 | | { |
268 | | return static_cast<AudioStream*>(aThis)->DataCallback(aOutputBuffer, aFrames); |
269 | | } |
270 | | |
271 | | static void StateCallback_S(cubeb_stream*, void* aThis, cubeb_state aState) |
272 | | { |
273 | | static_cast<AudioStream*>(aThis)->StateCallback(aState); |
274 | | } |
275 | | |
276 | | |
277 | | long DataCallback(void* aBuffer, long aFrames); |
278 | | void StateCallback(cubeb_state aState); |
279 | | |
280 | | nsresult EnsureTimeStretcherInitializedUnlocked(); |
281 | | |
282 | | // Return true if audio frames are valid (correct sampling rate and valid |
283 | | // channel count) otherwise false. |
284 | | bool IsValidAudioFormat(Chunk* aChunk); |
285 | | |
286 | | void GetUnprocessed(AudioBufferWriter& aWriter); |
287 | | void GetTimeStretched(AudioBufferWriter& aWriter); |
288 | | |
289 | | template <typename Function, typename... Args> |
290 | | int InvokeCubeb(Function aFunction, Args&&... aArgs); |
291 | | |
292 | | // The monitor is held to protect all access to member variables. |
293 | | Monitor mMonitor; |
294 | | |
295 | | uint32_t mChannels; |
296 | | uint32_t mOutChannels; |
297 | | AudioClock mAudioClock; |
298 | | soundtouch::SoundTouch* mTimeStretcher; |
299 | | |
300 | | // Output file for dumping audio |
301 | | FILE* mDumpFile; |
302 | | |
303 | | // Owning reference to a cubeb_stream. |
304 | | UniquePtr<cubeb_stream, CubebDestroyPolicy> mCubebStream; |
305 | | |
306 | | enum StreamState { |
307 | | INITIALIZED, // Initialized, playback has not begun. |
308 | | STARTED, // cubeb started. |
309 | | STOPPED, // Stopped by a call to Pause(). |
310 | | DRAINED, // StateCallback has indicated that the drain is complete. |
311 | | ERRORED, // Stream disabled due to an internal error. |
312 | | SHUTDOWN // Shutdown has been called |
313 | | }; |
314 | | |
315 | | StreamState mState; |
316 | | |
317 | | DataSource& mDataSource; |
318 | | |
319 | | bool mPrefillQuirk; |
320 | | }; |
321 | | |
322 | | } // namespace mozilla |
323 | | |
324 | | #endif |