tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

AudioSinkWrapper.h (7065B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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 
      7 #ifndef AudioSinkWrapper_h_
      8 #define AudioSinkWrapper_h_
      9 
     10 #include "AudioSink.h"
     11 #include "MediaSink.h"
     12 #include "mozilla/AbstractThread.h"
     13 #include "mozilla/EventTargetCapability.h"
     14 #include "mozilla/RefPtr.h"
     15 #include "mozilla/TimeStamp.h"
     16 #include "mozilla/UniquePtr.h"
     17 
     18 namespace mozilla {
     19 class MediaData;
     20 template <class T>
     21 class MediaQueue;
     22 
     23 /**
     24 * A wrapper around AudioSink to provide the interface of MediaSink.
     25 */
     26 class AudioSinkWrapper : public MediaSink {
     27  using PlaybackParams = AudioSink::PlaybackParams;
     28  using SinkCreator = std::function<UniquePtr<AudioSink>()>;
     29 
     30 public:
     31  AudioSinkWrapper(AbstractThread* aOwnerThread,
     32                   MediaQueue<AudioData>& aAudioQueue, SinkCreator aFunc,
     33                   double aVolume, double aPlaybackRate, bool aPreservesPitch,
     34                   RefPtr<AudioDeviceInfo> aAudioDevice)
     35      : mOwnerThread(aOwnerThread),
     36        mAsyncInitTaskQueue(CreateAsyncInitTaskQueue()),
     37        mSinkCreator(std::move(aFunc)),
     38        mAudioDevice(std::move(aAudioDevice)),
     39        mParams(aVolume, aPlaybackRate, aPreservesPitch),
     40        mAudioQueue(aAudioQueue),
     41        mRetrySinkTime(TimeStamp::Now()) {
     42    MOZ_ASSERT(mAsyncInitTaskQueue);
     43  }
     44 
     45  RefPtr<EndedPromise> OnEnded(TrackType aType) override;
     46  media::TimeUnit GetEndTime(TrackType aType) const override;
     47  media::TimeUnit GetPosition(TimeStamp* aTimeStamp = nullptr) override;
     48  bool HasUnplayedFrames(TrackType aType) const override;
     49  media::TimeUnit UnplayedDuration(TrackType aType) const override;
     50  void DropAudioPacketsIfNeeded(const media::TimeUnit& aMediaPosition);
     51 
     52  void SetVolume(double aVolume) override;
     53  void SetStreamName(const nsAString& aStreamName) override;
     54  void SetPlaybackRate(double aPlaybackRate) override;
     55  void SetPreservesPitch(bool aPreservesPitch) override;
     56  void SetPlaying(bool aPlaying) override;
     57  RefPtr<GenericPromise> SetAudioDevice(
     58      RefPtr<AudioDeviceInfo> aDevice) override;
     59 
     60  double PlaybackRate() const override;
     61 
     62  nsresult Start(const media::TimeUnit& aStartTime,
     63                 const MediaInfo& aInfo) override;
     64  void Stop() override;
     65  bool IsStarted() const override;
     66  bool IsPlaying() const override;
     67 
     68  void Shutdown() override;
     69 
     70  void GetDebugInfo(dom::MediaSinkDebugInfo& aInfo) override;
     71 
     72 private:
     73  // The clock that was in use for the previous position query, allowing to
     74  // detect clock switches.
     75  enum class ClockSource {
     76    // The clock comes from an underlying system-level audio stream.
     77    AudioStream,
     78    // The clock comes from the system clock.
     79    SystemClock,
     80    // The stream is paused, a constant time is reported.
     81    Paused
     82  } mLastClockSource = ClockSource::Paused;
     83  static already_AddRefed<TaskQueue> CreateAsyncInitTaskQueue();
     84  bool IsMuted() const;
     85  void OnMuted(bool aMuted);
     86  virtual ~AudioSinkWrapper();
     87 
     88  void AssertOwnerThread() const MOZ_ASSERT_CAPABILITY(mOwnerThread) {
     89    mOwnerThread.AssertOnCurrentThread();
     90  }
     91 
     92  bool NeedAudioSink();
     93  void StartAudioSink(UniquePtr<AudioSink> aAudioSink,
     94                      const media::TimeUnit& aStartTime);
     95  void ShutDownAudioSink();
     96  // Create and start mAudioSink.
     97  // An AudioSink can be started synchronously from the MDSM thread, or
     98  // asynchronously.
     99  // In synchronous mode, the clock doesn't advance until the sink has been
    100  // created, initialized and started. This is useful for the initial startup,
    101  // and when seeking.
    102  // In asynchronous mode, the clock will keep going forward (using the system
    103  // clock) until the AudioSink is started, at which point the clock will use
    104  // the AudioSink clock. This is used when unmuting a media element or
    105  // switching audio output devices. The promise is resolved when the
    106  // previous device is no longer in use and an attempt to open the new device
    107  // completes (successfully or not) or is deemed unnecessary because the
    108  // device is not required for output at this time.
    109  nsresult SyncCreateAudioSink(const media::TimeUnit& aStartTime);
    110  RefPtr<GenericPromise> MaybeAsyncCreateAudioSink(
    111      RefPtr<AudioDeviceInfo> aDevice);
    112  void ScheduleRetrySink();
    113 
    114  // Get the current media position using the system clock. This is used when
    115  // the audio is muted, or when the media has no audio track. Otherwise, the
    116  // media's position is based on the clock of the AudioStream.
    117  media::TimeUnit GetSystemClockPosition(TimeStamp aNow) const;
    118  bool CheckIfEnded() const;
    119 
    120  void OnAudioEnded(const EndedPromise::ResolveOrRejectValue& aValue);
    121 
    122  bool IsAudioSourceEnded(const MediaInfo& aInfo) const;
    123 
    124  const EventTargetCapability<AbstractThread> mOwnerThread;
    125  const RefPtr<TaskQueue> mAsyncInitTaskQueue;
    126  SinkCreator mSinkCreator;
    127  UniquePtr<AudioSink> mAudioSink;
    128  // The output device this AudioSink is playing data to. The system's default
    129  // device is used if this is null.
    130  RefPtr<AudioDeviceInfo> mAudioDevice;
    131  // Will only exist when media has an audio track.
    132  RefPtr<EndedPromise> mEndedPromise;
    133  MozPromiseHolder<EndedPromise> mEndedPromiseHolder;
    134  // true between Start() and Stop()
    135  bool mIsStarted = false;
    136  PlaybackParams MOZ_GUARDED_BY(mOwnerThread) mParams;
    137  // mClockStartTime is null before Start(), after Stop(), and between
    138  // SetPlaying(false) and SetPlaying(true).  When the system time is used for
    139  // the clock, this is the time corresponding to mPositionAtClockStart.  When
    140  // an AudioStream is used for the clock, non-null values don't have specific
    141  // meaning beyond indicating that the clock is advancing.
    142  TimeStamp mClockStartTime;
    143  // The media position at the clock datum.  If the clock is not advancing,
    144  // then this is the media position from which to resume playback.  The value
    145  // is Invalid() before Start() to facilitate debug.
    146  media::TimeUnit mPositionAtClockStart = media::TimeUnit::Invalid();
    147  // End time of last packet played or dropped.
    148  // Only up-to-date when there is no AudioSink.
    149  media::TimeUnit mLastPacketEndTime;
    150 
    151  bool mAudioEnded = true;
    152  // mAudioSinkEndedRequest is connected when and only when mAudioSink is set
    153  // and not ended.
    154  MozPromiseRequestHolder<EndedPromise> mAudioSinkEndedRequest;
    155  MediaQueue<AudioData>& mAudioQueue;
    156 
    157  // Time when next to re-try AudioSink creation.
    158  // Set to a useful value only when another sink is needed.  At other times
    159  // it needs to be non-null for a comparison where the result will be
    160  // irrelevant.
    161  // This is checked in GetPosition() which is triggered periodically during
    162  // playback by MediaDecoderStateMachine::UpdatePlaybackPositionPeriodically()
    163  TimeStamp mRetrySinkTime;
    164  // Number of async AudioSink creation tasks in flight
    165  uint32_t mAsyncCreateCount = 0;
    166 };
    167 
    168 }  // namespace mozilla
    169 
    170 #endif  // AudioSinkWrapper_h_