mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 16:55:40 +00:00
Bug 1262753
: P6. Perform downmixing in DecodeAudioDataSink. r=kinetik
Rather than performing the audio processing a few frames at a time, we perform the operation when popping the audio data block. The only downmixing task left to AudioStream is to handle the force mono preference. Resampling is currently disabled. MozReview-Commit-ID: GNQA1h0xcp7 --HG-- extra : rebase_source : c58aa4514a0dc4de06be6dc1da6a598742caa262
This commit is contained in:
parent
b382680a6a
commit
4132e3555b
@ -331,7 +331,7 @@ AudioStream::Init(uint32_t aNumChannels, uint32_t aRate,
|
||||
("%s channels: %d, rate: %d for %p", __FUNCTION__, aNumChannels, aRate, this));
|
||||
mInRate = mOutRate = aRate;
|
||||
mChannels = aNumChannels;
|
||||
mOutChannels = (aNumChannels > 2) ? 2 : aNumChannels;
|
||||
mOutChannels = mIsMonoAudioEnabled ? 1 : aNumChannels;
|
||||
|
||||
mDumpFile = OpenDumpFile(this);
|
||||
|
||||
@ -353,9 +353,11 @@ AudioStream::Init(uint32_t aNumChannels, uint32_t aRate,
|
||||
params.format = ToCubebFormat<AUDIO_OUTPUT_FORMAT>::value;
|
||||
mAudioClock.Init();
|
||||
|
||||
AudioConfig inConfig(mChannels, mInRate);
|
||||
AudioConfig outConfig(mOutChannels, mOutRate);
|
||||
mAudioConverter = MakeUnique<AudioConverter>(inConfig, outConfig);
|
||||
if (mIsMonoAudioEnabled) {
|
||||
AudioConfig inConfig(mChannels, mInRate);
|
||||
AudioConfig outConfig(mOutChannels, mOutRate);
|
||||
mAudioConverter = MakeUnique<AudioConverter>(inConfig, outConfig);
|
||||
}
|
||||
return OpenCubeb(params);
|
||||
}
|
||||
|
||||
@ -561,15 +563,10 @@ AudioStream::Downmix(Chunk* aChunk)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aChunk->Channels() > 2) {
|
||||
MOZ_ASSERT(mAudioConverter);
|
||||
if (mAudioConverter) {
|
||||
mAudioConverter->Process(aChunk->GetWritable(), aChunk->Frames());
|
||||
}
|
||||
|
||||
if (aChunk->Channels() >= 2 && mIsMonoAudioEnabled) {
|
||||
DownmixStereoToMono(aChunk->GetWritable(), aChunk->Frames());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "MediaQueue.h"
|
||||
#include "DecodedAudioDataSink.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "AudioConverter.h"
|
||||
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
@ -39,6 +40,9 @@ DecodedAudioDataSink::DecodedAudioDataSink(MediaQueue<MediaData>& aAudioQueue,
|
||||
, mChannel(aChannel)
|
||||
, mPlaying(true)
|
||||
, mPlaybackComplete(false)
|
||||
, mConverter(MakeUnique<AudioConverter>(
|
||||
AudioConfig(mInfo.mChannels, mInfo.mRate),
|
||||
AudioConfig(mInfo.mChannels > 2 ? 2 : mInfo.mChannels, mInfo.mRate)))
|
||||
{
|
||||
}
|
||||
|
||||
@ -136,7 +140,9 @@ nsresult
|
||||
DecodedAudioDataSink::InitializeAudioStream(const PlaybackParams& aParams)
|
||||
{
|
||||
mAudioStream = new AudioStream(*this);
|
||||
nsresult rv = mAudioStream->Init(mInfo.mChannels, mInfo.mRate, mChannel);
|
||||
nsresult rv = mAudioStream->Init(mConverter->OutputConfig().Channels(),
|
||||
mConverter->OutputConfig().Rate(),
|
||||
mChannel);
|
||||
if (NS_FAILED(rv)) {
|
||||
mAudioStream->Shutdown();
|
||||
mAudioStream = nullptr;
|
||||
@ -156,7 +162,8 @@ DecodedAudioDataSink::InitializeAudioStream(const PlaybackParams& aParams)
|
||||
int64_t
|
||||
DecodedAudioDataSink::GetEndTime() const
|
||||
{
|
||||
CheckedInt64 playedUsecs = FramesToUsecs(mWritten, mInfo.mRate) + mStartTime;
|
||||
CheckedInt64 playedUsecs =
|
||||
FramesToUsecs(mWritten, mConverter->OutputConfig().Rate()) + mStartTime;
|
||||
if (!playedUsecs.isValid()) {
|
||||
NS_WARNING("Int overflow calculating audio end time");
|
||||
return -1;
|
||||
@ -231,9 +238,11 @@ DecodedAudioDataSink::PopFrames(uint32_t aFrames)
|
||||
// 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(AudioQueue().PeekFront()->mTime, mInfo.mRate);
|
||||
CheckedInt64 sampleTime = UsecsToFrames(AudioQueue().PeekFront()->mTime,
|
||||
mConverter->OutputConfig().Rate());
|
||||
// Calculate the number of frames that have been pushed onto the audio hardware.
|
||||
CheckedInt64 playedFrames = UsecsToFrames(mStartTime, mInfo.mRate) +
|
||||
CheckedInt64 playedFrames = UsecsToFrames(mStartTime,
|
||||
mConverter->OutputConfig().Rate()) +
|
||||
static_cast<int64_t>(mWritten);
|
||||
CheckedInt64 missingFrames = sampleTime - playedFrames;
|
||||
|
||||
@ -243,6 +252,9 @@ DecodedAudioDataSink::PopFrames(uint32_t aFrames)
|
||||
return MakeUnique<Chunk>();
|
||||
}
|
||||
|
||||
const uint32_t rate = mConverter->OutputConfig().Rate();
|
||||
const uint32_t channels = mConverter->OutputConfig().Channels();
|
||||
|
||||
if (missingFrames.value() > AUDIO_FUZZ_FRAMES) {
|
||||
// The next audio chunk begins some time after the end of the last chunk
|
||||
// we pushed to the audio hardware. We must push silence into the audio
|
||||
@ -251,10 +263,26 @@ DecodedAudioDataSink::PopFrames(uint32_t aFrames)
|
||||
missingFrames = std::min<int64_t>(UINT32_MAX, missingFrames.value());
|
||||
auto framesToPop = std::min<uint32_t>(missingFrames.value(), aFrames);
|
||||
mWritten += framesToPop;
|
||||
return MakeUnique<SilentChunk>(framesToPop, mInfo.mChannels, mInfo.mRate);
|
||||
return MakeUnique<SilentChunk>(framesToPop, channels, rate);
|
||||
}
|
||||
|
||||
RefPtr<AudioData> data =
|
||||
dont_AddRef(AudioQueue().PopFront().take()->As<AudioData>());
|
||||
if (mConverter->InputConfig() != mConverter->OutputConfig()) {
|
||||
AlignedAudioBuffer convertedData =
|
||||
mConverter->Process(AudioSampleBuffer(Move(data->mAudioData))).Forget();
|
||||
mCurrentData =
|
||||
new AudioData(data->mOffset,
|
||||
data->mTime,
|
||||
data->mDuration,
|
||||
convertedData.Length() / channels,
|
||||
Move(convertedData),
|
||||
channels,
|
||||
rate);
|
||||
} else {
|
||||
mCurrentData = Move(data);
|
||||
}
|
||||
|
||||
mCurrentData = dont_AddRef(AudioQueue().PopFront().take()->As<AudioData>());
|
||||
mCursor = MakeUnique<AudioBufferCursor>(mCurrentData->mAudioData.get(),
|
||||
mCurrentData->mChannels,
|
||||
mCurrentData->mFrames);
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AudioConverter;
|
||||
|
||||
namespace media {
|
||||
|
||||
class DecodedAudioDataSink : public AudioSink,
|
||||
@ -97,13 +99,15 @@ private:
|
||||
*/
|
||||
// The AudioData at which AudioStream::DataSource is reading.
|
||||
RefPtr<AudioData> mCurrentData;
|
||||
// Keep track of the read positoin of mCurrentData.
|
||||
// Keep track of the read position of mCurrentData.
|
||||
UniquePtr<AudioBufferCursor> mCursor;
|
||||
// True if there is any error in processing audio data like overflow.
|
||||
bool mErrored = false;
|
||||
|
||||
// Set on the callback thread of cubeb once the stream has drained.
|
||||
Atomic<bool> mPlaybackComplete;
|
||||
|
||||
UniquePtr<AudioConverter> mConverter;
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
|
Loading…
Reference in New Issue
Block a user