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