1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #ifndef AudioDecoderInputTrack_h
6 #define AudioDecoderInputTrack_h
8 #include "AudioSegment.h"
9 #include "MediaEventSource.h"
10 #include "MediaTimer.h"
11 #include "MediaTrackGraph.h"
12 #include "MediaSegment.h"
13 #include "TimeUnits.h"
14 #include "mozilla/SPSCQueue.h"
15 #include "mozilla/StateMirroring.h"
16 #include "mozilla/TimeStamp.h"
17 #include "nsISerialEventTarget.h"
23 class RLBoxSoundTouch
;
26 * AudioDecoderInputTrack is used as a source for the audio decoder data, which
27 * supports adjusting playback rate and preserve pitch.
28 * The owner of this track would be responsible to push audio data via
29 * `AppendData()` into a SPSC queue, which is a thread-safe queue between the
30 * decoder thread (producer) and the graph thread (consumer). MediaTrackGraph
31 * requires data via `ProcessInput()`, then AudioDecoderInputTrack would convert
32 * (based on sample rate and playback rate) and append the amount of needed
33 * audio frames onto the output segment that would be used by MediaTrackGraph.
35 class AudioDecoderInputTrack final
: public ProcessedMediaTrack
{
37 static AudioDecoderInputTrack
* Create(MediaTrackGraph
* aGraph
,
38 nsISerialEventTarget
* aDecoderThread
,
39 const AudioInfo
& aInfo
,
40 float aPlaybackRate
, float aVolume
,
41 bool aPreservesPitch
);
43 // SPSCData suppports filling different supported type variants, and is used
44 // to achieve a thread-safe information exchange between the decoder thread
45 // and the graph thread.
46 struct SPSCData final
{
48 struct ClearFutureData
{};
51 : mStartTime(media::TimeUnit::Invalid()),
52 mEndTime(media::TimeUnit::Invalid()) {}
53 DecodedData(DecodedData
&& aDecodedData
)
54 : mSegment(std::move(aDecodedData
.mSegment
)) {
55 mStartTime
= aDecodedData
.mStartTime
;
56 mEndTime
= aDecodedData
.mEndTime
;
59 DecodedData(media::TimeUnit aStartTime
, media::TimeUnit aEndTime
)
60 : mStartTime(aStartTime
), mEndTime(aEndTime
) {}
61 DecodedData(const DecodedData
&) = delete;
62 DecodedData
& operator=(const DecodedData
&) = delete;
65 mStartTime
= media::TimeUnit::Invalid();
66 mEndTime
= media::TimeUnit::Invalid();
68 AudioSegment mSegment
;
69 media::TimeUnit mStartTime
;
70 media::TimeUnit mEndTime
;
74 SPSCData() : mData(Empty()) {};
75 explicit SPSCData(ClearFutureData
&& aArg
) : mData(std::move(aArg
)) {};
76 explicit SPSCData(DecodedData
&& aArg
) : mData(std::move(aArg
)) {};
77 explicit SPSCData(EOS
&& aArg
) : mData(std::move(aArg
)) {};
79 bool HasData() const { return !mData
.is
<Empty
>(); }
80 bool IsClearFutureData() const { return mData
.is
<ClearFutureData
>(); }
81 bool IsDecodedData() const { return mData
.is
<DecodedData
>(); }
82 bool IsEOS() const { return mData
.is
<EOS
>(); }
84 DecodedData
* AsDecodedData() {
85 return IsDecodedData() ? &mData
.as
<DecodedData
>() : nullptr;
88 Variant
<Empty
, ClearFutureData
, DecodedData
, EOS
> mData
;
92 void AppendData(AudioData
* aAudio
, const PrincipalHandle
& aPrincipalHandle
);
93 void AppendData(nsTArray
<RefPtr
<AudioData
>>& aAudioArray
,
94 const PrincipalHandle
& aPrincipalHandle
);
95 void NotifyEndOfStream();
96 void ClearFutureData();
97 void SetVolume(float aVolume
);
98 void SetPlaybackRate(float aPlaybackRate
);
99 void SetPreservesPitch(bool aPreservesPitch
);
100 // After calling this, the track are not expected to receive any new data.
102 bool HasBatchedData() const;
104 MediaEventSource
<int64_t>& OnOutput() { return mOnOutput
; }
105 MediaEventSource
<void>& OnEnd() { return mOnEnd
; }
108 void DestroyImpl() override
;
109 void ProcessInput(GraphTime aFrom
, GraphTime aTo
, uint32_t aFlags
) override
;
110 uint32_t NumberOfChannels() const override
;
112 // The functions below are only used for testing.
113 TrackTime
WrittenFrames() const {
114 AssertOnGraphThread();
115 return mWrittenFrames
;
117 float Volume() const {
118 AssertOnGraphThread();
121 float PlaybackRate() const {
122 AssertOnGraphThread();
123 return mPlaybackRate
;
127 ~AudioDecoderInputTrack();
130 AudioDecoderInputTrack(nsISerialEventTarget
* aDecoderThread
,
131 TrackRate aGraphRate
, const AudioInfo
& aInfo
,
132 float aPlaybackRate
, float aVolume
,
133 bool aPreservesPitch
);
135 // Return false if the converted segment contains zero duration.
136 bool ConvertAudioDataToSegment(AudioData
* aAudio
, AudioSegment
& aSegment
,
137 const PrincipalHandle
& aPrincipalHandle
);
139 void HandleSPSCData(SPSCData
& aData
);
141 // These methods would return the total frames that we consumed from
143 TrackTime
AppendBufferedDataToOutput(TrackTime aExpectedDuration
);
144 TrackTime
FillDataToTimeStretcher(TrackTime aExpectedDuration
);
145 TrackTime
AppendTimeStretchedDataToSegment(TrackTime aExpectedDuration
,
146 AudioSegment
& aOutput
);
147 TrackTime
AppendUnstretchedDataToSegment(TrackTime aExpectedDuration
,
148 AudioSegment
& aOutput
);
150 // Return the total frames that we retrieve from the time stretcher.
151 TrackTime
DrainStretchedDataIfNeeded(TrackTime aExpectedDuration
,
152 AudioSegment
& aOutput
);
153 TrackTime
GetDataFromTimeStretcher(TrackTime aExpectedDuration
,
154 AudioSegment
& aOutput
);
155 void NotifyInTheEndOfProcessInput(TrackTime aFillDuration
);
157 bool HasSentAllData() const;
159 bool ShouldBatchData() const;
160 void BatchData(AudioData
* aAudio
, const PrincipalHandle
& aPrincipalHandle
);
161 void DispatchPushBatchedDataIfNeeded();
162 void PushBatchedDataIfNeeded();
163 void PushDataToSPSCQueue(SPSCData
& data
);
165 void SetVolumeImpl(float aVolume
);
166 void SetPlaybackRateImpl(float aPlaybackRate
);
167 void SetPreservesPitchImpl(bool aPreservesPitch
);
169 void EnsureTimeStretcher();
170 void SetTempoAndRateForTimeStretcher();
171 uint32_t GetChannelCountForTimeStretcher() const;
173 inline void AssertOnDecoderThread() const {
174 MOZ_ASSERT(mDecoderThread
->IsOnCurrentThread());
177 const RefPtr
<nsISerialEventTarget
> mDecoderThread
;
179 // Notify the amount of audio frames which have been sent to the track.
180 MediaEventProducer
<int64_t> mOnOutput
;
181 // Notify when the track is ended.
182 MediaEventProducer
<void> mOnEnd
;
184 // These variables are ONLY used in the decoder thread.
185 nsAutoRef
<SpeexResamplerState
> mResampler
;
186 uint32_t mResamplerChannelCount
;
187 const uint32_t mInitialInputChannels
;
188 TrackRate mInputSampleRate
;
189 DelayedScheduler
<TimeStamp
> mDelayedScheduler
;
190 bool mShutdownSPSCQueue
= false;
192 // These attributes are ONLY used in the graph thread.
193 bool mReceivedEOS
= false;
194 TrackTime mWrittenFrames
= 0;
197 bool mPreservesPitch
;
199 // A thread-safe queue shared by the decoder thread and the graph thread.
200 // The decoder thread is the producer side, and the graph thread is the
201 // consumer side. This queue should NEVER get full. In order to achieve that,
202 // we would batch input samples when SPSC queue doesn't have many available
204 // In addition, as the media track isn't guaranteed to be destroyed on the
205 // graph thread (it could be destroyed on the main thread as well) so we might
206 // not clear all data in SPSC queue when the track's `DestroyImpl()` gets
207 // called. We leave to destroy the queue later when the track gets destroyed.
208 SPSCQueue
<SPSCData
> mSPSCQueue
{40};
210 // When the graph requires the less amount of audio frames than the amount of
211 // frames an audio data has, then the remaining part of frames would be stored
212 // and used in next iteration.
213 // This is ONLY used in the graph thread.
214 AudioSegment mBufferedData
;
216 // In order to prevent SPSC queue from being full, we want to batch multiple
217 // data into one to control the density of SPSC queue, the length of batched
218 // data would be dynamically adjusted by queue's available capacity.
219 // This is ONLY used in the decoder thread.
220 SPSCData::DecodedData mBatchedData
;
222 // True if we've sent all data to the graph, then the track will be marked as
223 // ended in the next iteration.
224 bool mSentAllData
= false;
226 // This is used to adjust the playback rate and pitch.
227 RLBoxSoundTouch
* mTimeStretcher
= nullptr;
229 // Buffers that would be used for the time stretching.
230 AutoTArray
<AudioDataValue
, 2> mInterleavedBuffer
;
233 } // namespace mozilla
235 #endif // AudioDecoderInputTrack_h