Bug 1264199: P2. Ensure the AudioStream only ever receive the same content format. r=kinetik
The audio is automatically converted to always match the format of the first processed sample.
This is a temporary approach, as it would be preferred to use a final sampling rate not causing too much quality loss.
MozReview-Commit-ID: Lo3827aon43
--- a/dom/media/mediasink/DecodedAudioDataSink.cpp
+++ b/dom/media/mediasink/DecodedAudioDataSink.cpp
@@ -51,20 +51,16 @@ DecodedAudioDataSink::DecodedAudioDataSi
, mFramesParsed(0)
, mLastEndTime(0)
{
bool resampling = gfxPrefs::AudioSinkResampling();
uint32_t resamplingRate = gfxPrefs::AudioSinkResampleRate();
mOutputRate = resampling ? resamplingRate : mInfo.mRate;
mOutputChannels = mInfo.mChannels > 2 && gfxPrefs::AudioSinkForceStereo()
? 2 : mInfo.mChannels;
- mConverter =
- MakeUnique<AudioConverter>(
- AudioConfig(mInfo.mChannels, mInfo.mRate),
- AudioConfig(mOutputChannels, mOutputRate));
}
DecodedAudioDataSink::~DecodedAudioDataSink()
{
}
RefPtr<GenericPromise>
DecodedAudioDataSink::Init(const PlaybackParams& aParams)
@@ -338,23 +334,43 @@ DecodedAudioDataSink::NotifyAudioNeeded(
RefPtr<AudioData> data =
dont_AddRef(AudioQueue().PopFront().take()->As<AudioData>());
// Ignore the element with 0 frames and try next.
if (!data->mFrames) {
continue;
}
- // Ignore invalid samples.
- if (data->mRate != mConverter->InputConfig().Rate() ||
- data->mChannels != mConverter->InputConfig().Channels()) {
- NS_WARNING(nsPrintfCString(
- "mismatched sample format, data=%p rate=%u channels=%u frames=%u",
- data->mAudioData.get(), data->mRate, data->mChannels, data->mFrames).get());
- continue;
+ if (!mConverter ||
+ (data->mRate != mConverter->InputConfig().Rate() ||
+ data->mChannels != mConverter->InputConfig().Channels())) {
+ SINK_LOG_V("Audio format changed from %u@%uHz to %u@%uHz",
+ mConverter? mConverter->InputConfig().Channels() : 0,
+ mConverter ? mConverter->InputConfig().Rate() : 0,
+ data->mChannels, data->mRate);
+
+ // mFramesParsed indicates the current playtime in frames at the current
+ // input sampling rate. Recalculate it per the new sampling rate.
+ if (mFramesParsed) {
+ // We minimize overflow.
+ uint32_t oldRate = mConverter->InputConfig().Rate();
+ uint32_t newRate = data->mRate;
+ CheckedInt64 result = SaferMultDiv(mFramesParsed, newRate, oldRate);
+ if (!result.isValid()) {
+ NS_WARNING("Int overflow in DecodedAudioDataSink");
+ mErrored = true;
+ return;
+ }
+ mFramesParsed = result.value();
+ }
+
+ mConverter =
+ MakeUnique<AudioConverter>(
+ AudioConfig(data->mChannels, data->mRate),
+ AudioConfig(mOutputChannels, mOutputRate));
}
// See if there's a gap in the audio. If there is, push silence into the
// audio hardware, so we can play across the gap.
// Calculate the timestamp of the next chunk of audio in numbers of
// samples.
CheckedInt64 sampleTime = UsecsToFrames(data->mTime - mStartTime,
data->mRate);