Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/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
0
  void operator()(cubeb_stream* aStream) const {
30
0
    cubeb_stream_destroy(aStream);
31
0
  }
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
0
  uint32_t GetInputRate() const { return mInRate; }
80
0
  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
0
    : mPtr(aPtr), mChannels(aChannels), mFrames(aFrames) {}
100
101
  // Advance the cursor to account for frames that are consumed.
102
0
  uint32_t Advance(uint32_t aFrames) {
103
0
    MOZ_ASSERT(mFrames >= aFrames);
104
0
    mFrames -= aFrames;
105
0
    mPtr += mChannels * aFrames;
106
0
    return aFrames;
107
0
  }
108
109
  // The number of frames available for read/write in this buffer.
110
0
  uint32_t Available() const { return mFrames; }
111
112
  // Return a pointer where read/write should begin.
113
  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
0
    : AudioBufferCursor(aPtr, aChannels, aFrames) {}
129
130
0
  uint32_t WriteZeros(uint32_t aFrames) {
131
0
    memset(mPtr, 0, sizeof(AudioDataValue) * mChannels * aFrames);
132
0
    return Advance(aFrames);
133
0
  }
134
135
0
  uint32_t Write(const AudioDataValue* aPtr, uint32_t aFrames) {
136
0
    memcpy(mPtr, aPtr, sizeof(AudioDataValue) * mChannels * aFrames);
137
0
    return Advance(aFrames);
138
0
  }
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
0
  uint32_t Write(const Function& aFunction, uint32_t aFrames) {
147
0
    return Advance(aFunction(mPtr, aFrames));
148
0
  }
Unexecuted instantiation: Unified_cpp_dom_media1.cpp:unsigned int mozilla::AudioBufferWriter::Write<mozilla::AudioStream::GetUnprocessed(mozilla::AudioBufferWriter&)::$_0>(mozilla::AudioStream::GetUnprocessed(mozilla::AudioBufferWriter&)::$_0 const&, unsigned int)
Unexecuted instantiation: Unified_cpp_dom_media1.cpp:unsigned int mozilla::AudioBufferWriter::Write<mozilla::AudioStream::GetTimeStretched(mozilla::AudioBufferWriter&)::$_1>(mozilla::AudioStream::GetTimeStretched(mozilla::AudioBufferWriter&)::$_1 const&, unsigned int)
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
    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
    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
  {
238
    return CubebUtils::PreferredSampleRate();
239
  }
240
241
0
  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
0
  {
268
0
    return static_cast<AudioStream*>(aThis)->DataCallback(aOutputBuffer, aFrames);
269
0
  }
270
271
  static void StateCallback_S(cubeb_stream*, void* aThis, cubeb_state aState)
272
0
  {
273
0
    static_cast<AudioStream*>(aThis)->StateCallback(aState);
274
0
  }
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