This file is indexed.

/usr/include/thunderbird/AudioStream.h is in thunderbird-dev 1:38.6.0+build1-0ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if !defined(AudioStream_h_)
#define AudioStream_h_

#include "AudioSampleFormat.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsThreadUtils.h"
#include "Latency.h"
#include "mozilla/dom/AudioChannelBinding.h"
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "CubebUtils.h"

namespace soundtouch {
class SoundTouch;
}

namespace mozilla {

struct DestroyPolicy
{
  void operator()(cubeb_stream* aStream) const {
    cubeb_stream_destroy(aStream);
  }
};

class AudioStream;
class FrameHistory;

class AudioClock
{
public:
  explicit AudioClock(AudioStream* aStream);
  // Initialize the clock with the current AudioStream. Need to be called
  // before querying the clock. Called on the audio thread.
  void Init();
  // Update the number of samples that has been written in the audio backend.
  // Called on the state machine thread.
  void UpdateFrameHistory(uint32_t aServiced, uint32_t aUnderrun);
  // Get the read position of the stream, in microseconds.
  // Called on the state machine thead.
  // Assumes the AudioStream lock is held and thus calls Unlocked versions
  // of AudioStream funcs.
  int64_t GetPositionUnlocked() const;
  // Get the read position of the stream, in frames.
  // Called on the state machine thead.
  int64_t GetPositionInFrames() const;
  // Set the playback rate.
  // Called on the audio thread.
  // Assumes the AudioStream lock is held and thus calls Unlocked versions
  // of AudioStream funcs.
  void SetPlaybackRateUnlocked(double aPlaybackRate);
  // Get the current playback rate.
  // Called on the audio thread.
  double GetPlaybackRate() const;
  // Set if we are preserving the pitch.
  // Called on the audio thread.
  void SetPreservesPitch(bool aPreservesPitch);
  // Get the current pitch preservation state.
  // Called on the audio thread.
  bool GetPreservesPitch() const;
private:
  // This AudioStream holds a strong reference to this AudioClock. This
  // pointer is garanteed to always be valid.
  AudioStream* const mAudioStream;
  // Output rate in Hz (characteristic of the playback rate)
  int mOutRate;
  // Input rate in Hz (characteristic of the media being played)
  int mInRate;
  // True if the we are timestretching, false if we are resampling.
  bool mPreservesPitch;
  // The history of frames sent to the audio engine in each Datacallback.
  const nsAutoPtr<FrameHistory> mFrameHistory;
};

class CircularByteBuffer
{
public:
  CircularByteBuffer()
    : mBuffer(nullptr), mCapacity(0), mStart(0), mCount(0)
  {}

  // Set the capacity of the buffer in bytes.  Must be called before any
  // call to append or pop elements.
  void SetCapacity(uint32_t aCapacity) {
    MOZ_ASSERT(!mBuffer, "Buffer allocated.");
    mCapacity = aCapacity;
    mBuffer = new uint8_t[mCapacity];
  }

  uint32_t Length() {
    return mCount;
  }

  uint32_t Capacity() {
    return mCapacity;
  }

  uint32_t Available() {
    return Capacity() - Length();
  }

  // Append aLength bytes from aSrc to the buffer.  Caller must check that
  // sufficient space is available.
  void AppendElements(const uint8_t* aSrc, uint32_t aLength) {
    MOZ_ASSERT(mBuffer && mCapacity, "Buffer not initialized.");
    MOZ_ASSERT(aLength <= Available(), "Buffer full.");

    uint32_t end = (mStart + mCount) % mCapacity;

    uint32_t toCopy = std::min(mCapacity - end, aLength);
    memcpy(&mBuffer[end], aSrc, toCopy);
    memcpy(&mBuffer[0], aSrc + toCopy, aLength - toCopy);
    mCount += aLength;
  }

  // Remove aSize bytes from the buffer.  Caller must check returned size in
  // aSize{1,2} before using the pointer returned in aData{1,2}.  Caller
  // must not specify an aSize larger than Length().
  void PopElements(uint32_t aSize, void** aData1, uint32_t* aSize1,
                   void** aData2, uint32_t* aSize2) {
    MOZ_ASSERT(mBuffer && mCapacity, "Buffer not initialized.");
    MOZ_ASSERT(aSize <= Length(), "Request too large.");

    *aData1 = &mBuffer[mStart];
    *aSize1 = std::min(mCapacity - mStart, aSize);
    *aData2 = &mBuffer[0];
    *aSize2 = aSize - *aSize1;
    mCount -= *aSize1 + *aSize2;
    mStart += *aSize1 + *aSize2;
    mStart %= mCapacity;
  }

  // Throw away all but aSize bytes from the buffer.  Returns new size, which
  // may be less than aSize
  uint32_t ContractTo(uint32_t aSize) {
    MOZ_ASSERT(mBuffer && mCapacity, "Buffer not initialized.");
    if (aSize >= mCount) {
      return mCount;
    }
    mStart += (mCount - aSize);
    mCount = aSize;
    mStart %= mCapacity;
    return mCount;
  }

  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
  {
    size_t amount = 0;
    amount += mBuffer.SizeOfExcludingThis(aMallocSizeOf);
    return amount;
  }

  void Reset()
  {
    mBuffer = nullptr;
    mCapacity = 0;
    mStart = 0;
    mCount = 0;
  }

private:
  nsAutoArrayPtr<uint8_t> mBuffer;
  uint32_t mCapacity;
  uint32_t mStart;
  uint32_t mCount;
};

class AudioInitTask;

// Access to a single instance of this class must be synchronized by
// callers, or made from a single thread.  One exception is that access to
// GetPosition, GetPositionInFrames, SetVolume, and Get{Rate,Channels},
// SetMicrophoneActive is thread-safe without external synchronization.
class AudioStream final
{
  virtual ~AudioStream();

public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioStream)
  AudioStream();

  enum LatencyRequest {
    HighLatency,
    LowLatency
  };

  // Initialize the audio stream. aNumChannels is the number of audio
  // channels (1 for mono, 2 for stereo, etc) and aRate is the sample rate
  // (22050Hz, 44100Hz, etc).
  nsresult Init(int32_t aNumChannels, int32_t aRate,
                const dom::AudioChannel aAudioStreamChannel,
                LatencyRequest aLatencyRequest);

  // Closes the stream. All future use of the stream is an error.
  void Shutdown();

  void Reset();

  // Write audio data to the audio hardware.  aBuf is an array of AudioDataValues
  // AudioDataValue of length aFrames*mChannels.  If aFrames is larger
  // than the result of Available(), the write will block until sufficient
  // buffer space is available.  aTime is the time in ms associated with the first sample
  // for latency calculations
  nsresult Write(const AudioDataValue* aBuf, uint32_t aFrames, TimeStamp* aTime = nullptr);

  // Return the number of audio frames that can be written without blocking.
  uint32_t Available();

  // Set the current volume of the audio playback. This is a value from
  // 0 (meaning muted) to 1 (meaning full volume).  Thread-safe.
  void SetVolume(double aVolume);

  // Informs the AudioStream that a microphone is being used by someone in the
  // application.
  void SetMicrophoneActive(bool aActive);
  void PanOutputIfNeeded(bool aMicrophoneActive);
  void ResetStreamIfNeeded();

  // Block until buffered audio data has been consumed.
  void Drain();

  // Break any blocking operation and set the stream to shutdown.
  void Cancel();

  // Start the stream.
  void Start();

  // Return the number of frames written so far in the stream. This allow the
  // caller to check if it is safe to start the stream, if needed.
  int64_t GetWritten();

  // Pause audio playback.
  void Pause();

  // Resume audio playback.
  void Resume();

  // Return the position in microseconds of the audio frame being played by
  // the audio hardware, compensated for playback rate change. Thread-safe.
  int64_t GetPosition();

  // Return the position, measured in audio frames played since the stream
  // was opened, of the audio hardware.  Thread-safe.
  int64_t GetPositionInFrames();

  // Returns true when the audio stream is paused.
  bool IsPaused();

  int GetRate() { return mOutRate; }
  int GetChannels() { return mChannels; }
  int GetOutChannels() { return mOutChannels; }

  // Set playback rate as a multiple of the intrinsic playback rate. This is to
  // be called only with aPlaybackRate > 0.0.
  nsresult SetPlaybackRate(double aPlaybackRate);
  // Switch between resampling (if false) and time stretching (if true, default).
  nsresult SetPreservesPitch(bool aPreservesPitch);

  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;

protected:
  friend class AudioClock;

  // Return the position, measured in audio frames played since the stream was
  // opened, of the audio hardware, not adjusted for the changes of playback
  // rate or underrun frames.
  // Caller must own the monitor.
  int64_t GetPositionInFramesUnlocked();

private:
  friend class AudioInitTask;

  // So we can call it asynchronously from AudioInitTask
  nsresult OpenCubeb(cubeb_stream_params &aParams,
                     LatencyRequest aLatencyRequest);
  void AudioInitTaskFinished();

  void CheckForStart();

  static long DataCallback_S(cubeb_stream*, void* aThis, void* aBuffer, long aFrames)
  {
    return static_cast<AudioStream*>(aThis)->DataCallback(aBuffer, aFrames);
  }

  static void StateCallback_S(cubeb_stream*, void* aThis, cubeb_state aState)
  {
    static_cast<AudioStream*>(aThis)->StateCallback(aState);
  }


  static void DeviceChangedCallback_s(void * aThis) {
    static_cast<AudioStream*>(aThis)->DeviceChangedCallback();
  }

  long DataCallback(void* aBuffer, long aFrames);
  void StateCallback(cubeb_state aState);
  void DeviceChangedCallback();

  nsresult EnsureTimeStretcherInitializedUnlocked();

  // aTime is the time in ms the samples were inserted into MediaStreamGraph
  long GetUnprocessed(void* aBuffer, long aFrames, int64_t &aTime);
  long GetTimeStretched(void* aBuffer, long aFrames, int64_t &aTime);
  long GetUnprocessedWithSilencePadding(void* aBuffer, long aFrames, int64_t &aTime);

  int64_t GetLatencyInFrames();
  void GetBufferInsertTime(int64_t &aTimeMs);

  void StartUnlocked();

  // The monitor is held to protect all access to member variables.  Write()
  // waits while mBuffer is full; DataCallback() notifies as it consumes
  // data from mBuffer.  Drain() waits while mState is DRAINING;
  // StateCallback() notifies when mState is DRAINED.
  Monitor mMonitor;

  // Input rate in Hz (characteristic of the media being played)
  int mInRate;
  // Output rate in Hz (characteristic of the playback rate)
  int mOutRate;
  int mChannels;
  int mOutChannels;
#if defined(__ANDROID__)
  dom::AudioChannel mAudioChannel;
#endif
  // Number of frames written to the buffers.
  int64_t mWritten;
  AudioClock mAudioClock;
  nsAutoPtr<soundtouch::SoundTouch> mTimeStretcher;
  nsRefPtr<AsyncLatencyLogger> mLatencyLog;

  // copy of Latency logger's starting time for offset calculations
  TimeStamp mStartTime;
  // Whether we are playing a low latency stream, or a normal stream.
  LatencyRequest mLatencyRequest;
  // Where in the current mInserts[0] block cubeb has read to
  int64_t mReadPoint;
  // Keep track of each inserted block of samples and the time it was inserted
  // so we can estimate the clock time for a specific sample's insertion (for when
  // we send data to cubeb).  Blocks are aged out as needed.
  struct Inserts {
    int64_t mTimeMs;
    int64_t mFrames;
  };
  nsAutoTArray<Inserts, 8> mInserts;

  // Output file for dumping audio
  FILE* mDumpFile;

  // Temporary audio buffer.  Filled by Write() and consumed by
  // DataCallback().  Once mBuffer is full, Write() blocks until sufficient
  // space becomes available in mBuffer.  mBuffer is sized in bytes, not
  // frames.
  CircularByteBuffer mBuffer;

  // Owning reference to a cubeb_stream.
  UniquePtr<cubeb_stream, DestroyPolicy> mCubebStream;

  uint32_t mBytesPerFrame;

  uint32_t BytesToFrames(uint32_t aBytes) {
    NS_ASSERTION(aBytes % mBytesPerFrame == 0,
                 "Byte count not aligned on frames size.");
    return aBytes / mBytesPerFrame;
  }

  uint32_t FramesToBytes(uint32_t aFrames) {
    return aFrames * mBytesPerFrame;
  }

  enum StreamState {
    INITIALIZED, // Initialized, playback has not begun.
    STARTED,     // cubeb started, but callbacks haven't started
    RUNNING,     // DataCallbacks have started after STARTED, or after Resume().
    STOPPED,     // Stopped by a call to Pause().
    DRAINING,    // Drain requested.  DataCallback will indicate end of stream
                 // once the remaining contents of mBuffer are requested by
                 // cubeb, after which StateCallback will indicate drain
                 // completion.
    DRAINED,     // StateCallback has indicated that the drain is complete.
    ERRORED,     // Stream disabled due to an internal error.
    SHUTDOWN     // Shutdown has been called
  };

  StreamState mState;
  bool mNeedsStart; // needed in case Start() is called before cubeb is open
  bool mIsFirst;
  // True if a microphone is active.
  bool mMicrophoneActive;
  // When we are in the process of changing the output device, and the callback
  // is not going to be called for a little while, simply drop incoming frames.
  // This is only on OSX for now, because other systems handle this gracefully.
  bool mShouldDropFrames;
  // True if there is a pending AudioInitTask. Shutdown() will wait until the
  // pending AudioInitTask is finished.
  bool mPendingAudioInitTask;
  // The last good position returned by cubeb_stream_get_position(). Used to
  // check if the cubeb position is going backward.
  uint64_t mLastGoodPosition;
};

class AudioInitTask : public nsRunnable
{
public:
  AudioInitTask(AudioStream *aStream,
                AudioStream::LatencyRequest aLatencyRequest,
                const cubeb_stream_params &aParams)
    : mAudioStream(aStream)
    , mLatencyRequest(aLatencyRequest)
    , mParams(aParams)
  {}

  nsresult Dispatch()
  {
    // Can't add 'this' as the event to run, since mThread may not be set yet
    nsresult rv = NS_NewNamedThread("CubebInit", getter_AddRefs(mThread));
    if (NS_SUCCEEDED(rv)) {
      // Note: event must not null out mThread!
      rv = mThread->Dispatch(this, NS_DISPATCH_NORMAL);
    }
    return rv;
  }

protected:
  virtual ~AudioInitTask() {};

private:
  NS_IMETHOD Run() override final;

  RefPtr<AudioStream> mAudioStream;
  AudioStream::LatencyRequest mLatencyRequest;
  cubeb_stream_params mParams;

  nsCOMPtr<nsIThread> mThread;
};

} // namespace mozilla

#endif