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 #ifndef AudioSink_h__ 7 #define AudioSink_h__ 8 9 #include "AudioStream.h" 10 #include "AudibilityMonitor.h" 11 #include "MediaEventSource.h" 12 #include "MediaInfo.h" 13 #include "MediaQueue.h" 14 #include "MediaSink.h" 15 #include "mozilla/Atomics.h" 16 #include "mozilla/Maybe.h" 17 #include "mozilla/Monitor.h" 18 #include "mozilla/MozPromise.h" 19 #include "mozilla/RefPtr.h" 20 #include "mozilla/Result.h" 21 #include "nsISupportsImpl.h" 22 23 namespace mozilla { 24 25 class AudioConverter; 26 27 class AudioSink : private AudioStream::DataSource { 28 public: 29 struct PlaybackParams { PlaybackParamsPlaybackParams30 PlaybackParams(double aVolume, double aPlaybackRate, bool aPreservesPitch) 31 : mVolume(aVolume), 32 mPlaybackRate(aPlaybackRate), 33 mPreservesPitch(aPreservesPitch) {} 34 double mVolume; 35 double mPlaybackRate; 36 bool mPreservesPitch; 37 }; 38 39 AudioSink(AbstractThread* aThread, MediaQueue<AudioData>& aAudioQueue, 40 const media::TimeUnit& aStartTime, const AudioInfo& aInfo, 41 AudioDeviceInfo* aAudioDevice); 42 43 ~AudioSink(); 44 45 // Start audio playback and return a promise which will be resolved when the 46 // playback finishes, or return an error result if any error occurs. 47 Result<already_AddRefed<MediaSink::EndedPromise>, nsresult> Start( 48 const PlaybackParams& aParams); 49 50 /* 51 * All public functions are not thread-safe. 52 * Called on the task queue of MDSM only. 53 */ 54 media::TimeUnit GetPosition(); 55 media::TimeUnit GetEndTime() const; 56 57 // Check whether we've pushed more frames to the audio stream than it 58 // has played. 59 bool HasUnplayedFrames(); 60 61 // The duration of the buffered frames. 62 media::TimeUnit UnplayedDuration() const; 63 64 // Shut down the AudioSink's resources. 65 void Shutdown(); 66 67 void SetVolume(double aVolume); 68 void SetStreamName(const nsAString& aStreamName); 69 void SetPlaybackRate(double aPlaybackRate); 70 void SetPreservesPitch(bool aPreservesPitch); 71 void SetPlaying(bool aPlaying); 72 AudibleEvent()73 MediaEventSource<bool>& AudibleEvent() { return mAudibleEvent; } 74 75 void GetDebugInfo(dom::MediaSinkDebugInfo& aInfo); 76 AudioDevice()77 const RefPtr<AudioDeviceInfo>& AudioDevice() { return mAudioDevice; } 78 79 private: 80 // Allocate and initialize mAudioStream. Returns NS_OK on success. 81 nsresult InitializeAudioStream(const PlaybackParams& aParams); 82 83 // Interface of AudioStream::DataSource. 84 // Called on the callback thread of cubeb. Returns the number of frames that 85 // were available. 86 uint32_t PopFrames(AudioDataValue* aBuffer, uint32_t aFrames, 87 bool aAudioThreadChanged) override; 88 bool Ended() const override; 89 90 void CheckIsAudible(const Span<AudioDataValue>& aInterleaved, 91 size_t aChannel); 92 93 // The audio stream resource. Used on the task queue of MDSM only. 94 RefPtr<AudioStream> mAudioStream; 95 96 // The presentation time of the first audio frame that was played. 97 // We can add this to the audio stream position to determine 98 // the current audio time. 99 const media::TimeUnit mStartTime; 100 101 // Keep the last good position returned from the audio stream. Used to ensure 102 // position returned by GetPosition() is mono-increasing in spite of audio 103 // stream error. Used on the task queue of MDSM only. 104 media::TimeUnit mLastGoodPosition; 105 106 const AudioInfo mInfo; 107 108 // The output device this AudioSink is playing data to. The system's default 109 // device is used if this is null. 110 const RefPtr<AudioDeviceInfo> mAudioDevice; 111 112 // Used on the task queue of MDSM only. 113 bool mPlaying; 114 115 // PCM frames written to the stream so far. Written on the callback thread, 116 // read on the MDSM thread. 117 Atomic<int64_t> mWritten; 118 119 // True if there is any error in processing audio data like overflow. 120 Atomic<bool> mErrored; 121 122 const RefPtr<AbstractThread> mOwnerThread; 123 124 // Audio Processing objects and methods 125 void OnAudioPopped(); 126 void OnAudioPushed(const RefPtr<AudioData>& aSample); 127 void NotifyAudioNeeded(); 128 // Drain the converter and add the output to the processed audio queue. 129 // A maximum of aMaxFrames will be added. 130 uint32_t DrainConverter(uint32_t aMaxFrames = UINT32_MAX); 131 already_AddRefed<AudioData> CreateAudioFromBuffer( 132 AlignedAudioBuffer&& aBuffer, AudioData* aReference); 133 // Add data to the processsed queue return the number of frames added. 134 uint32_t PushProcessedAudio(AudioData* aData); 135 uint32_t AudioQueuedInRingBufferMS() const; 136 uint32_t SampleToFrame(uint32_t aSamples) const; 137 UniquePtr<AudioConverter> mConverter; 138 UniquePtr<SPSCQueue<AudioDataValue>> mProcessedSPSCQueue; 139 MediaEventListener mAudioQueueListener; 140 MediaEventListener mAudioQueueFinishListener; 141 MediaEventListener mProcessedQueueListener; 142 // Number of frames processed from mAudioQueue. Used to determine gaps in 143 // the input stream. It indicates the time in frames since playback started 144 // at the current input framerate. 145 int64_t mFramesParsed; 146 Maybe<RefPtr<AudioData>> mLastProcessedPacket; 147 media::TimeUnit mLastEndTime; 148 // Never modifed after construction. 149 uint32_t mOutputRate; 150 uint32_t mOutputChannels; 151 AudibilityMonitor mAudibilityMonitor; 152 bool mIsAudioDataAudible; 153 MediaEventProducer<bool> mAudibleEvent; 154 // Only signed on the real-time audio thread. 155 MediaEventProducer<void> mAudioPopped; 156 157 Atomic<bool> mProcessedQueueFinished; 158 MediaQueue<AudioData>& mAudioQueue; 159 const float mProcessedQueueThresholdMS; 160 }; 161 162 } // namespace mozilla 163 164 #endif // AudioSink_h__ 165