mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 06:43:32 +00:00
Bug 1673285 - Retrofit AudioStream and AudioDecoderInputTrack to use RLBoxed SoundTouch. r=padenot,glandium
Combines previous Patches 1-4, adapted to the current codebase. Differential Revision: https://phabricator.services.mozilla.com/D183627
This commit is contained in:
parent
88e2f3bd9e
commit
bb50d4a28b
@ -211,7 +211,7 @@ endif
|
||||
|
||||
ifdef MOZ_USING_WASM_SANDBOXING
|
||||
security/rlbox/pre-compile: config/external/wasm2c_sandbox_compiler/host
|
||||
dom/media/ogg/target-objects extensions/spellcheck/hunspell/glue/target-objects gfx/thebes/target-objects parser/expat/target-objects parser/htmlparser/target-objects gfx/ots/src/target-objects: security/rlbox/pre-compile
|
||||
dom/media/ogg/target-objects extensions/spellcheck/hunspell/glue/target-objects gfx/thebes/target-objects parser/expat/target-objects parser/htmlparser/target-objects gfx/ots/src/target-objects dom/media/target-objects dom/media/mediasink/target-objects: security/rlbox/pre-compile
|
||||
endif
|
||||
|
||||
# Most things are built during compile (target/host), but some things happen during export
|
||||
|
@ -30,9 +30,7 @@
|
||||
#include "CallbackThreadRegistry.h"
|
||||
#include "mozilla/StaticPrefs_media.h"
|
||||
|
||||
// Use abort() instead of exception in SoundTouch.
|
||||
#define ST_NO_EXCEPTION_HANDLING 1
|
||||
#include "soundtouch/SoundTouchFactory.h"
|
||||
#include "RLBoxSoundTouch.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -170,7 +168,7 @@ size_t AudioStream::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
|
||||
nsresult AudioStream::EnsureTimeStretcherInitialized() {
|
||||
AssertIsOnAudioThread();
|
||||
if (!mTimeStretcher) {
|
||||
mTimeStretcher = soundtouch::createSoundTouchObj();
|
||||
mTimeStretcher = new RLBoxSoundTouch();
|
||||
mTimeStretcher->setSampleRate(mAudioClock.GetInputRate());
|
||||
mTimeStretcher->setChannels(mOutChannels);
|
||||
mTimeStretcher->setPitch(1.0);
|
||||
@ -407,7 +405,7 @@ void AudioStream::ShutDown() {
|
||||
// After `cubeb_stream_stop` has been called, there is no audio thread
|
||||
// anymore. We can delete the time stretcher.
|
||||
if (mTimeStretcher) {
|
||||
soundtouch::destroySoundTouchObj(mTimeStretcher);
|
||||
delete mTimeStretcher;
|
||||
mTimeStretcher = nullptr;
|
||||
}
|
||||
|
||||
@ -474,24 +472,33 @@ void AudioStream::GetUnprocessed(AudioBufferWriter& aWriter) {
|
||||
AssertIsOnAudioThread();
|
||||
// Flush the timestretcher pipeline, if we were playing using a playback rate
|
||||
// other than 1.0.
|
||||
if (mTimeStretcher && mTimeStretcher->numSamples()) {
|
||||
auto* timeStretcher = mTimeStretcher;
|
||||
aWriter.Write(
|
||||
[timeStretcher](AudioDataValue* aPtr, uint32_t aFrames) {
|
||||
return timeStretcher->receiveSamples(aPtr, aFrames);
|
||||
},
|
||||
aWriter.Available());
|
||||
if (mTimeStretcher) {
|
||||
// Get number of samples and based on this either receive samples or write
|
||||
// silence. At worst, the attacker can supply weird sound samples or
|
||||
// result in us writing silence.
|
||||
auto numSamples = mTimeStretcher->numSamples().unverified_safe_because(
|
||||
"We only use this to decide whether to receive samples or write "
|
||||
"silence.");
|
||||
if (numSamples) {
|
||||
RLBoxSoundTouch* timeStretcher = mTimeStretcher;
|
||||
aWriter.Write(
|
||||
[timeStretcher](AudioDataValue* aPtr, uint32_t aFrames) {
|
||||
return timeStretcher->receiveSamples(aPtr, aFrames);
|
||||
},
|
||||
aWriter.Available());
|
||||
|
||||
// TODO: There might be still unprocessed samples in the stretcher.
|
||||
// We should either remove or flush them so they won't be in the output
|
||||
// next time we switch a playback rate other than 1.0.
|
||||
NS_WARNING_ASSERTION(mTimeStretcher->numUnprocessedSamples() == 0,
|
||||
"no samples");
|
||||
} else if (mTimeStretcher) {
|
||||
// Don't need it anymore: playbackRate is 1.0, and the time stretcher has
|
||||
// been flushed.
|
||||
soundtouch::destroySoundTouchObj(mTimeStretcher);
|
||||
mTimeStretcher = nullptr;
|
||||
// TODO: There might be still unprocessed samples in the stretcher.
|
||||
// We should either remove or flush them so they won't be in the output
|
||||
// next time we switch a playback rate other than 1.0.
|
||||
mTimeStretcher->numUnprocessedSamples().copy_and_verify([](auto samples) {
|
||||
NS_WARNING_ASSERTION(samples == 0, "no samples");
|
||||
});
|
||||
} else {
|
||||
// Don't need it anymore: playbackRate is 1.0, and the time stretcher has
|
||||
// been flushed.
|
||||
delete mTimeStretcher;
|
||||
mTimeStretcher = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
while (aWriter.Available() > 0) {
|
||||
@ -514,7 +521,14 @@ void AudioStream::GetTimeStretched(AudioBufferWriter& aWriter) {
|
||||
uint32_t toPopFrames =
|
||||
ceil(aWriter.Available() * mAudioClock.GetPlaybackRate());
|
||||
|
||||
while (mTimeStretcher->numSamples() < aWriter.Available()) {
|
||||
// At each iteration, get number of samples and (based on this) write from
|
||||
// the data source or silence. At worst, if the number of samples is a lie
|
||||
// (i.e., under attacker control) we'll either not write anything or keep
|
||||
// writing noise. This is safe because all the memory operations within the
|
||||
// loop (and after) are checked.
|
||||
while (mTimeStretcher->numSamples().unverified_safe_because(
|
||||
"Only used to decide whether to put samples.") <
|
||||
aWriter.Available()) {
|
||||
// pop into a temp buffer, and put into the stretcher.
|
||||
AutoTArray<AudioDataValue, 1000> buf;
|
||||
auto size = CheckedUint32(mOutChannels) * toPopFrames;
|
||||
@ -629,7 +643,7 @@ long AudioStream::DataCallback(void* aBuffer, long aFrames) {
|
||||
// No more new data in the data source, and the drain has completed. We
|
||||
// don't need the time stretcher anymore at this point.
|
||||
if (mTimeStretcher && writer.Available()) {
|
||||
soundtouch::destroySoundTouchObj(mTimeStretcher);
|
||||
delete mTimeStretcher;
|
||||
mTimeStretcher = nullptr;
|
||||
}
|
||||
#ifndef XP_MACOSX
|
||||
|
@ -23,10 +23,6 @@
|
||||
# include "nsThreadUtils.h"
|
||||
# include "WavDumper.h"
|
||||
|
||||
namespace soundtouch {
|
||||
class MOZ_EXPORT SoundTouch;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
struct CubebDestroyPolicy {
|
||||
@ -38,6 +34,7 @@ struct CubebDestroyPolicy {
|
||||
class AudioStream;
|
||||
class FrameHistory;
|
||||
class AudioConfig;
|
||||
class RLBoxSoundTouch;
|
||||
|
||||
// A struct that contains the number of frames serviced or underrun by a
|
||||
// callback, alongside the sample-rate for this callback (in case of playback
|
||||
@ -328,8 +325,7 @@ class AudioStream final {
|
||||
bool CheckThreadIdChanged();
|
||||
void AssertIsOnAudioThread() const;
|
||||
|
||||
soundtouch::SoundTouch* mTimeStretcher;
|
||||
|
||||
RLBoxSoundTouch* mTimeStretcher;
|
||||
AudioClock mAudioClock;
|
||||
|
||||
WavDumper mDumpFile;
|
||||
|
148
dom/media/RLBoxSoundTouch.cpp
Normal file
148
dom/media/RLBoxSoundTouch.cpp
Normal file
@ -0,0 +1,148 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "RLBoxSoundTouch.h"
|
||||
|
||||
using namespace rlbox;
|
||||
using namespace mozilla;
|
||||
using namespace soundtouch;
|
||||
|
||||
RLBoxSoundTouch::RLBoxSoundTouch() {
|
||||
#ifdef MOZ_WASM_SANDBOXING_SOUNDTOUCH
|
||||
mSandbox.create_sandbox(false /* infallible */);
|
||||
#else
|
||||
mSandbox.create_sandbox();
|
||||
#endif
|
||||
mTimeStretcher = mSandbox.invoke_sandbox_function(createSoundTouchObj);
|
||||
|
||||
// Allocate buffer in sandbox to receive samples.
|
||||
mSampleBuffer = mSandbox.malloc_in_sandbox<AudioDataValue>(mSampleBufferSize);
|
||||
MOZ_RELEASE_ASSERT(mSampleBuffer);
|
||||
}
|
||||
|
||||
RLBoxSoundTouch::~RLBoxSoundTouch() {
|
||||
mSandbox.free_in_sandbox(mSampleBuffer);
|
||||
mSandbox.invoke_sandbox_function(destroySoundTouchObj, mTimeStretcher);
|
||||
mTimeStretcher = nullptr;
|
||||
mSandbox.destroy_sandbox();
|
||||
}
|
||||
|
||||
void RLBoxSoundTouch::setSampleRate(uint aRate) {
|
||||
mSandbox.invoke_sandbox_function(SetSampleRate, mTimeStretcher, aRate);
|
||||
}
|
||||
|
||||
void RLBoxSoundTouch::setChannels(uint aChannels) {
|
||||
mChannels = aChannels;
|
||||
mSandbox.invoke_sandbox_function(SetChannels, mTimeStretcher, aChannels);
|
||||
}
|
||||
|
||||
void RLBoxSoundTouch::setPitch(double aPitch) {
|
||||
mSandbox.invoke_sandbox_function(SetPitch, mTimeStretcher, aPitch);
|
||||
}
|
||||
|
||||
void RLBoxSoundTouch::setSetting(int aSettingId, int aValue) {
|
||||
mSandbox.invoke_sandbox_function(SetSetting, mTimeStretcher, aSettingId,
|
||||
aValue);
|
||||
}
|
||||
|
||||
void RLBoxSoundTouch::setTempo(double aTempo) {
|
||||
mSandbox.invoke_sandbox_function(SetTempo, mTimeStretcher, aTempo);
|
||||
}
|
||||
|
||||
void RLBoxSoundTouch::setRate(double aRate) {
|
||||
mSandbox.invoke_sandbox_function(SetRate, mTimeStretcher, aRate);
|
||||
}
|
||||
|
||||
uint RLBoxSoundTouch::numChannels() {
|
||||
auto numChannels = mChannels;
|
||||
mSandbox.invoke_sandbox_function(NumChannels, mTimeStretcher)
|
||||
.copy_and_verify([numChannels](auto ch) {
|
||||
MOZ_RELEASE_ASSERT(ch == numChannels, "Number of channels changed");
|
||||
});
|
||||
return mChannels;
|
||||
}
|
||||
|
||||
tainted_soundtouch<uint> RLBoxSoundTouch::numSamples() {
|
||||
return mSandbox.invoke_sandbox_function(NumSamples, mTimeStretcher);
|
||||
}
|
||||
|
||||
tainted_soundtouch<uint> RLBoxSoundTouch::numUnprocessedSamples() {
|
||||
return mSandbox.invoke_sandbox_function(NumUnprocessedSamples,
|
||||
mTimeStretcher);
|
||||
}
|
||||
|
||||
void RLBoxSoundTouch::putSamples(const AudioDataValue* aSamples,
|
||||
uint aNumSamples) {
|
||||
const CheckedInt<size_t> nrTotalSamples = numChannels() * aNumSamples;
|
||||
MOZ_RELEASE_ASSERT(nrTotalSamples.isValid(), "Input buffer size overflow");
|
||||
|
||||
bool copied = false;
|
||||
auto t_aSamples = copy_memory_or_grant_access(
|
||||
mSandbox, aSamples, nrTotalSamples.value(), false, copied);
|
||||
|
||||
mSandbox.invoke_sandbox_function(PutSamples, mTimeStretcher, t_aSamples,
|
||||
aNumSamples);
|
||||
|
||||
if (copied) {
|
||||
mSandbox.free_in_sandbox(t_aSamples);
|
||||
}
|
||||
}
|
||||
|
||||
uint RLBoxSoundTouch::receiveSamples(AudioDataValue* aOutput,
|
||||
uint aMaxSamples) {
|
||||
// Check number of channels.
|
||||
const CheckedInt<uint> channels = numChannels();
|
||||
// Sanity check max samples.
|
||||
const CheckedInt<uint> maxElements = channels * aMaxSamples;
|
||||
MOZ_RELEASE_ASSERT(maxElements.isValid(), "Max number of elements overflow");
|
||||
|
||||
// Check mSampleBuffer size, and resize if required.
|
||||
if (mSampleBufferSize < maxElements.value()) {
|
||||
resizeSampleBuffer(maxElements.value());
|
||||
}
|
||||
|
||||
auto numWrittenSamples =
|
||||
mSandbox
|
||||
.invoke_sandbox_function(ReceiveSamples, mTimeStretcher,
|
||||
mSampleBuffer, aMaxSamples)
|
||||
.copy_and_verify([aMaxSamples](uint written) {
|
||||
MOZ_RELEASE_ASSERT(written <= aMaxSamples,
|
||||
"Number of samples exceeds max samples");
|
||||
return written;
|
||||
});
|
||||
|
||||
// Copy received elements from sandbox.
|
||||
if (numWrittenSamples > 0) {
|
||||
const CheckedInt<uint> numCopyElements = channels * numWrittenSamples;
|
||||
|
||||
MOZ_RELEASE_ASSERT(numCopyElements.isValid() &&
|
||||
numCopyElements.value() <= maxElements.value(),
|
||||
"Bad number of written elements");
|
||||
|
||||
// Get pointer to mSampleBuffer. RLBox ensures that we have at least
|
||||
// numCopyElements elements. We are just copying data values out. These
|
||||
// values are untrusted but should only be interpreted as sound samples --
|
||||
// so should, at worst, just sound weird.
|
||||
auto* mSampleBuffer_ptr = mSampleBuffer.unverified_safe_pointer_because(
|
||||
numCopyElements.value(),
|
||||
"Pointer to buffer is within sandbox and has at least numCopyElements "
|
||||
"elements.");
|
||||
PodCopy(aOutput, mSampleBuffer_ptr, numCopyElements.value());
|
||||
}
|
||||
|
||||
return numWrittenSamples;
|
||||
}
|
||||
|
||||
void RLBoxSoundTouch::flush() {
|
||||
return mSandbox.invoke_sandbox_function(Flush, mTimeStretcher);
|
||||
}
|
||||
|
||||
void RLBoxSoundTouch::resizeSampleBuffer(uint aNewSize) {
|
||||
mSandbox.free_in_sandbox(mSampleBuffer);
|
||||
mSampleBufferSize = aNewSize;
|
||||
mSampleBuffer = mSandbox.malloc_in_sandbox<AudioDataValue>(aNewSize);
|
||||
MOZ_RELEASE_ASSERT(mSampleBuffer);
|
||||
}
|
63
dom/media/RLBoxSoundTouch.h
Normal file
63
dom/media/RLBoxSoundTouch.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef RLBOXSOUNDTOUCH_H_
|
||||
#define RLBOXSOUNDTOUCH_H_
|
||||
|
||||
#include "RLBoxSoundTouchTypes.h"
|
||||
|
||||
// Load general firefox configuration of RLBox
|
||||
#include "mozilla/rlbox/rlbox_config.h"
|
||||
|
||||
#ifdef MOZ_WASM_SANDBOXING_SOUNDTOUCH
|
||||
// Include the generated header file so that we are able to resolve the symbols
|
||||
// in the wasm binary
|
||||
# include "rlbox.wasm.h"
|
||||
# define RLBOX_USE_STATIC_CALLS() rlbox_wasm2c_sandbox_lookup_symbol
|
||||
# include "mozilla/rlbox/rlbox_wasm2c_sandbox.hpp"
|
||||
#else
|
||||
// Extra configuration for no-op sandbox
|
||||
# define RLBOX_USE_STATIC_CALLS() rlbox_noop_sandbox_lookup_symbol
|
||||
# include "mozilla/rlbox/rlbox_noop_sandbox.hpp"
|
||||
#endif
|
||||
|
||||
#include "mozilla/rlbox/rlbox.hpp"
|
||||
#include "AudioStream.h"
|
||||
// Use abort() instead of exception in SoundTouch.
|
||||
#define ST_NO_EXCEPTION_HANDLING 1
|
||||
#include "soundtouch/SoundTouchFactory.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class RLBoxSoundTouch {
|
||||
public:
|
||||
RLBoxSoundTouch();
|
||||
~RLBoxSoundTouch();
|
||||
|
||||
void setSampleRate(uint aRate);
|
||||
void setChannels(uint aChannels);
|
||||
void setPitch(double aPitch);
|
||||
void setSetting(int aSettingId, int aValue);
|
||||
void setTempo(double aTempo);
|
||||
uint numChannels();
|
||||
tainted_soundtouch<uint> numSamples();
|
||||
tainted_soundtouch<uint> numUnprocessedSamples();
|
||||
void setRate(double aRate);
|
||||
void putSamples(const mozilla::AudioDataValue* aSamples, uint aNumSamples);
|
||||
uint receiveSamples(mozilla::AudioDataValue* aOutput, uint aMaxSamples);
|
||||
void flush();
|
||||
|
||||
private:
|
||||
uint mChannels{0};
|
||||
rlbox_sandbox_soundtouch mSandbox;
|
||||
tainted_soundtouch<mozilla::AudioDataValue*> mSampleBuffer{nullptr};
|
||||
uint mSampleBufferSize{1};
|
||||
tainted_soundtouch<soundtouch::SoundTouch*> mTimeStretcher{nullptr};
|
||||
|
||||
void resizeSampleBuffer(uint aNewSize);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
#endif
|
35
dom/media/RLBoxSoundTouchTypes.h
Normal file
35
dom/media/RLBoxSoundTouchTypes.h
Normal file
@ -0,0 +1,35 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef RLBOXSOUNDTOUCHTYPES_H_
|
||||
#define RLBOXSOUNDTOUCHTYPES_H_
|
||||
|
||||
#include "mozilla/rlbox/rlbox_types.hpp"
|
||||
|
||||
#ifdef MOZ_WASM_SANDBOXING_SOUNDTOUCH
|
||||
namespace rlbox {
|
||||
class rlbox_wasm2c_sandbox;
|
||||
}
|
||||
using rlbox_soundtouch_sandbox_type = rlbox::rlbox_wasm2c_sandbox;
|
||||
#else
|
||||
using rlbox_soundtouch_sandbox_type = rlbox::rlbox_noop_sandbox;
|
||||
#endif
|
||||
|
||||
using rlbox_sandbox_soundtouch =
|
||||
rlbox::rlbox_sandbox<rlbox_soundtouch_sandbox_type>;
|
||||
template <typename T>
|
||||
using sandbox_callback_soundtouch =
|
||||
rlbox::sandbox_callback<T, rlbox_soundtouch_sandbox_type>;
|
||||
template <typename T>
|
||||
using tainted_soundtouch = rlbox::tainted<T, rlbox_soundtouch_sandbox_type>;
|
||||
template <typename T>
|
||||
using tainted_opaque_soundtouch =
|
||||
rlbox::tainted_opaque<T, rlbox_soundtouch_sandbox_type>;
|
||||
template <typename T>
|
||||
using tainted_volatile_soundtouch =
|
||||
rlbox::tainted_volatile<T, rlbox_soundtouch_sandbox_type>;
|
||||
using rlbox::tainted_boolean_hint;
|
||||
|
||||
#endif
|
@ -9,9 +9,7 @@
|
||||
#include "mozilla/StaticPrefs_media.h"
|
||||
#include "Tracing.h"
|
||||
|
||||
// Use abort() instead of exception in SoundTouch.
|
||||
#define ST_NO_EXCEPTION_HANDLING 1
|
||||
#include "soundtouch/SoundTouchFactory.h"
|
||||
#include "RLBoxSoundTouch.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -332,7 +330,8 @@ void AudioDecoderInputTrack::DestroyImpl() {
|
||||
AssertOnGraphThreadOrNotRunning();
|
||||
mBufferedData.Clear();
|
||||
if (mTimeStretcher) {
|
||||
soundtouch::destroySoundTouchObj(mTimeStretcher);
|
||||
delete mTimeStretcher;
|
||||
mTimeStretcher = nullptr;
|
||||
}
|
||||
ProcessedMediaTrack::DestroyImpl();
|
||||
}
|
||||
@ -434,10 +433,16 @@ TrackTime AudioDecoderInputTrack::AppendBufferedDataToOutput(
|
||||
ApplyTrackDisabling(&outputSegment);
|
||||
mSegment->AppendFrom(&outputSegment);
|
||||
|
||||
unsigned int numSamples = 0;
|
||||
if (mTimeStretcher) {
|
||||
numSamples = mTimeStretcher->numSamples().unverified_safe_because(
|
||||
"Only used for logging.");
|
||||
}
|
||||
|
||||
LOG("Appended %" PRId64 ", consumed %" PRId64
|
||||
", remaining raw buffered %" PRId64 ", remaining time-stretched %u",
|
||||
appendedDuration, consumedDuration, mBufferedData.GetDuration(),
|
||||
mTimeStretcher ? mTimeStretcher->numSamples() : 0);
|
||||
numSamples);
|
||||
if (auto gap = aExpectedDuration - appendedDuration; gap > 0) {
|
||||
LOG("Audio underrun, fill silence %" PRId64, gap);
|
||||
MOZ_ASSERT(mBufferedData.IsEmpty());
|
||||
@ -460,9 +465,14 @@ TrackTime AudioDecoderInputTrack::AppendTimeStretchedDataToSegment(
|
||||
// into the time stretcher until the amount of samples that time stretcher
|
||||
// finishes processed reaches or exceeds the expected duration.
|
||||
TrackTime consumedDuration = 0;
|
||||
if (mTimeStretcher->numSamples() < aExpectedDuration) {
|
||||
consumedDuration = FillDataToTimeStretcher(aExpectedDuration);
|
||||
}
|
||||
mTimeStretcher->numSamples().copy_and_verify([&](auto numSamples) {
|
||||
// Attacker controlled soundtouch can return a bogus numSamples, which
|
||||
// can result in filling data into the time stretcher (or not). This is
|
||||
// safe as long as filling (and getting) data is checked.
|
||||
if (numSamples < aExpectedDuration) {
|
||||
consumedDuration = FillDataToTimeStretcher(aExpectedDuration);
|
||||
}
|
||||
});
|
||||
MOZ_ASSERT(consumedDuration >= 0);
|
||||
Unused << GetDataFromTimeStretcher(aExpectedDuration, aOutput);
|
||||
return consumedDuration;
|
||||
@ -511,7 +521,13 @@ TrackTime AudioDecoderInputTrack::FillDataToTimeStretcher(
|
||||
mTimeStretcher->putSamples(mInterleavedBuffer.Elements(),
|
||||
aChunk->GetDuration());
|
||||
consumedDuration += aChunk->GetDuration();
|
||||
return mTimeStretcher->numSamples() >= aExpectedDuration;
|
||||
return mTimeStretcher->numSamples().copy_and_verify(
|
||||
[&aExpectedDuration](auto numSamples) {
|
||||
// Attacker controlled soundtouch can return a bogus numSamples to
|
||||
// return early or force additional iterations. This is safe
|
||||
// as long as all the writes in the lambda are checked.
|
||||
return numSamples >= aExpectedDuration;
|
||||
});
|
||||
});
|
||||
mBufferedData.RemoveLeading(consumedDuration);
|
||||
return consumedDuration;
|
||||
@ -543,7 +559,9 @@ TrackTime AudioDecoderInputTrack::DrainStretchedDataIfNeeded(
|
||||
if (!mTimeStretcher) {
|
||||
return 0;
|
||||
}
|
||||
if (mTimeStretcher->numSamples() == 0) {
|
||||
auto numSamples = mTimeStretcher->numSamples().unverified_safe_because(
|
||||
"Bogus numSamples can result in draining the stretched data (or not).");
|
||||
if (numSamples == 0) {
|
||||
return 0;
|
||||
}
|
||||
return GetDataFromTimeStretcher(aExpectedDuration, aOutput);
|
||||
@ -555,14 +573,22 @@ TrackTime AudioDecoderInputTrack::GetDataFromTimeStretcher(
|
||||
MOZ_ASSERT(mTimeStretcher);
|
||||
MOZ_ASSERT(aExpectedDuration >= 0);
|
||||
|
||||
if (HasSentAllData() && mTimeStretcher->numUnprocessedSamples()) {
|
||||
mTimeStretcher->flush();
|
||||
LOG("Flush %u frames from the time stretcher",
|
||||
mTimeStretcher->numSamples());
|
||||
}
|
||||
auto numSamples =
|
||||
mTimeStretcher->numSamples().unverified_safe_because("Used for logging");
|
||||
|
||||
mTimeStretcher->numUnprocessedSamples().copy_and_verify([&](auto samples) {
|
||||
if (HasSentAllData() && samples) {
|
||||
mTimeStretcher->flush();
|
||||
LOG("Flush %u frames from the time stretcher", numSamples);
|
||||
}
|
||||
});
|
||||
|
||||
// Flushing may have change the number of samples
|
||||
numSamples = mTimeStretcher->numSamples().unverified_safe_because(
|
||||
"Used to decide to flush (or not), which is checked.");
|
||||
|
||||
const TrackTime available =
|
||||
std::min((TrackTime)mTimeStretcher->numSamples(), aExpectedDuration);
|
||||
std::min((TrackTime)numSamples, aExpectedDuration);
|
||||
if (available == 0) {
|
||||
// Either running out of stretched data, or the raw data we filled into
|
||||
// the time stretcher were not enough for producing stretched data.
|
||||
@ -627,7 +653,7 @@ uint32_t AudioDecoderInputTrack::NumberOfChannels() const {
|
||||
void AudioDecoderInputTrack::EnsureTimeStretcher() {
|
||||
AssertOnGraphThread();
|
||||
if (!mTimeStretcher) {
|
||||
mTimeStretcher = soundtouch::createSoundTouchObj();
|
||||
mTimeStretcher = new RLBoxSoundTouch();
|
||||
mTimeStretcher->setSampleRate(GraphImpl()->GraphRate());
|
||||
mTimeStretcher->setChannels(GetChannelCountForTimeStretcher());
|
||||
mTimeStretcher->setPitch(1.0);
|
||||
|
@ -15,13 +15,10 @@
|
||||
#include "mozilla/StateMirroring.h"
|
||||
#include "nsISerialEventTarget.h"
|
||||
|
||||
namespace soundtouch {
|
||||
class MOZ_EXPORT SoundTouch;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AudioData;
|
||||
class RLBoxSoundTouch;
|
||||
|
||||
/**
|
||||
* AudioDecoderInputTrack is used as a source for the audio decoder data, which
|
||||
@ -231,7 +228,7 @@ class AudioDecoderInputTrack final : public ProcessedMediaTrack {
|
||||
bool mSentAllData = false;
|
||||
|
||||
// This is used to adjust the playback rate and pitch.
|
||||
soundtouch::SoundTouch* mTimeStretcher = nullptr;
|
||||
RLBoxSoundTouch* mTimeStretcher = nullptr;
|
||||
|
||||
// Buffers that would be used for the time stretching.
|
||||
AutoTArray<AudioDataValue, 2> mInterleavedBuffer;
|
||||
|
@ -17,6 +17,7 @@ EXPORTS += [
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
"!/security/rlbox",
|
||||
"/dom/media",
|
||||
]
|
||||
|
||||
|
@ -195,6 +195,8 @@ EXPORTS += [
|
||||
"PrincipalHandle.h",
|
||||
"QueueObject.h",
|
||||
"ReaderProxy.h",
|
||||
"RLBoxSoundTouch.h",
|
||||
"RLBoxSoundTouchTypes.h",
|
||||
"SeekJob.h",
|
||||
"SeekTarget.h",
|
||||
"SelfRef.h",
|
||||
@ -308,6 +310,7 @@ UNIFIED_SOURCES += [
|
||||
"MemoryBlockCache.cpp",
|
||||
"QueueObject.cpp",
|
||||
"ReaderProxy.cpp",
|
||||
"RLBoxSoundTouch.cpp",
|
||||
"SeekJob.cpp",
|
||||
"TimeUnits.cpp",
|
||||
"Tracing.cpp",
|
||||
@ -355,6 +358,7 @@ EXTRA_JS_MODULES.media += [
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
"!/security/rlbox",
|
||||
"/caps",
|
||||
"/docshell/base",
|
||||
"/dom/base",
|
||||
|
@ -74,6 +74,7 @@ vendoring:
|
||||
keep:
|
||||
- AUTHORS
|
||||
- clear-lf.sh
|
||||
- src/RLBoxSoundTouchFactory.*
|
||||
- src/SoundTouchFactory.*
|
||||
- src/soundtouch_config.h
|
||||
- src/soundtouch_perms.h
|
||||
|
62
media/libsoundtouch/src/RLBoxSoundTouchFactory.cpp
Normal file
62
media/libsoundtouch/src/RLBoxSoundTouchFactory.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "RLBoxSoundTouchFactory.h"
|
||||
|
||||
// Exposed C API that is used by RLBox
|
||||
|
||||
using namespace soundtouch;
|
||||
|
||||
extern "C" {
|
||||
|
||||
void SetSampleRate(SoundTouch* mTimeStretcher, uint srate) {
|
||||
mTimeStretcher->setSampleRate(srate);
|
||||
}
|
||||
|
||||
void SetChannels(SoundTouch* mTimeStretcher, uint numChannels) {
|
||||
mTimeStretcher->setChannels(numChannels);
|
||||
}
|
||||
|
||||
void SetPitch(SoundTouch* mTimeStretcher, double newPitch) {
|
||||
mTimeStretcher->setPitch(newPitch);
|
||||
}
|
||||
|
||||
void SetSetting(SoundTouch* mTimeStretcher, int settingId, int value) {
|
||||
mTimeStretcher->setSetting(settingId, value);
|
||||
}
|
||||
|
||||
void SetTempo(SoundTouch* mTimeStretcher, double newTempo) {
|
||||
mTimeStretcher->setTempo(newTempo);
|
||||
}
|
||||
|
||||
void SetRate(SoundTouch* mTimeStretcher, double newRate) {
|
||||
mTimeStretcher->setRate(newRate);
|
||||
}
|
||||
|
||||
uint NumChannels(SoundTouch* mTimeStretcher) {
|
||||
return mTimeStretcher->numChannels();
|
||||
}
|
||||
|
||||
uint NumSamples(SoundTouch* mTimeStretcher) {
|
||||
return mTimeStretcher->numSamples();
|
||||
}
|
||||
|
||||
uint NumUnprocessedSamples(SoundTouch* mTimeStretcher) {
|
||||
return mTimeStretcher->numUnprocessedSamples();
|
||||
}
|
||||
|
||||
void PutSamples(SoundTouch* mTimeStretcher, const SAMPLETYPE* samples,
|
||||
uint numSamples) {
|
||||
mTimeStretcher->putSamples(samples, numSamples);
|
||||
}
|
||||
|
||||
uint ReceiveSamples(SoundTouch* mTimeStretcher, SAMPLETYPE* output,
|
||||
uint maxSamples) {
|
||||
return mTimeStretcher->receiveSamples(output, maxSamples);
|
||||
}
|
||||
|
||||
void Flush(SoundTouch* mTimeStretcher) { return mTimeStretcher->flush(); }
|
||||
}
|
28
media/libsoundtouch/src/RLBoxSoundTouchFactory.h
Normal file
28
media/libsoundtouch/src/RLBoxSoundTouchFactory.h
Normal file
@ -0,0 +1,28 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SoundTouch.h"
|
||||
|
||||
// Exposed C API that is used by RLBox
|
||||
|
||||
extern "C" {
|
||||
|
||||
void SetSampleRate(soundtouch::SoundTouch* mTimeStretcher, uint srate);
|
||||
void SetChannels(soundtouch::SoundTouch* mTimeStretcher, uint numChannels);
|
||||
void SetPitch(soundtouch::SoundTouch* mTimeStretcher, double newPitch);
|
||||
void SetSetting(soundtouch::SoundTouch* mTimeStretcher, int settingId,
|
||||
int value);
|
||||
void SetTempo(soundtouch::SoundTouch* mTimeStretcher, double newTempo);
|
||||
void SetRate(soundtouch::SoundTouch* mTimeStretcher, double newRate);
|
||||
uint NumChannels(soundtouch::SoundTouch* mTimeStretcher);
|
||||
uint NumSamples(soundtouch::SoundTouch* mTimeStretcher);
|
||||
uint NumUnprocessedSamples(soundtouch::SoundTouch* mTimeStretcher);
|
||||
void PutSamples(soundtouch::SoundTouch* mTimeStretcher,
|
||||
const soundtouch::SAMPLETYPE* samples, uint numSamples);
|
||||
uint ReceiveSamples(soundtouch::SoundTouch* mTimeStretcher,
|
||||
soundtouch::SAMPLETYPE* output, uint maxSamples);
|
||||
void Flush(soundtouch::SoundTouch* mTimeStretcher);
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include <soundtouch/SoundTouch.h>
|
||||
|
||||
namespace soundtouch
|
||||
extern "C" namespace soundtouch
|
||||
{
|
||||
|
||||
SOUNDTOUCH_API
|
||||
|
@ -9,8 +9,9 @@
|
||||
|
||||
#include <soundtouch/STTypes.h>
|
||||
#include <soundtouch/SoundTouch.h>
|
||||
#include <soundtouch/RLBoxSoundTouchFactory.h>
|
||||
|
||||
namespace soundtouch
|
||||
extern "C" namespace soundtouch
|
||||
{
|
||||
SOUNDTOUCH_API
|
||||
soundtouch::SoundTouch*
|
||||
|
@ -4,27 +4,20 @@
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
include("sources.mozbuild")
|
||||
|
||||
EXPORTS.soundtouch += [
|
||||
'FIFOSamplePipe.h',
|
||||
'RLBoxSoundTouchFactory.h',
|
||||
'SoundTouch.h',
|
||||
'soundtouch_config.h',
|
||||
'SoundTouchFactory.h',
|
||||
'STTypes.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AAFilter.cpp',
|
||||
'cpu_detect_x86.cpp',
|
||||
'FIFOSampleBuffer.cpp',
|
||||
'FIRFilter.cpp',
|
||||
'InterpolateCubic.cpp',
|
||||
'InterpolateLinear.cpp',
|
||||
'InterpolateShannon.cpp',
|
||||
'RateTransposer.cpp',
|
||||
'SoundTouch.cpp',
|
||||
'SoundTouchFactory.cpp',
|
||||
'TDStretch.cpp',
|
||||
]
|
||||
UNIFIED_SOURCES += soundtouch_sources
|
||||
|
||||
LOCAL_INCLUDES += ["!/security/rlbox"]
|
||||
|
||||
if CONFIG['INTEL_ARCHITECTURE']:
|
||||
if CONFIG['MOZ_SAMPLE_TYPE_FLOAT32']:
|
||||
@ -42,12 +35,10 @@ else:
|
||||
# Windows need alloca renamed to _alloca
|
||||
DEFINES['alloca'] = '_alloca'
|
||||
|
||||
DEFINES['BUILDING_SOUNDTOUCH'] = 1
|
||||
for k, v in soundtouch_defines:
|
||||
DEFINES[k] = v
|
||||
|
||||
# We allow warnings for third-party code that can be updated from upstream.
|
||||
AllowCompilerWarnings()
|
||||
|
||||
FINAL_LIBRARY = 'lgpllibs'
|
||||
|
||||
# Use abort() instead of exception in SoundTouch.
|
||||
DEFINES['ST_NO_EXCEPTION_HANDLING'] = 1
|
||||
|
26
media/libsoundtouch/src/sources.mozbuild
Normal file
26
media/libsoundtouch/src/sources.mozbuild
Normal file
@ -0,0 +1,26 @@
|
||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
soundtouch_sources = [
|
||||
'AAFilter.cpp',
|
||||
'cpu_detect_x86.cpp',
|
||||
'FIFOSampleBuffer.cpp',
|
||||
'FIRFilter.cpp',
|
||||
'InterpolateCubic.cpp',
|
||||
'InterpolateLinear.cpp',
|
||||
'InterpolateShannon.cpp',
|
||||
'RateTransposer.cpp',
|
||||
'RLBoxSoundTouchFactory.cpp',
|
||||
'SoundTouch.cpp',
|
||||
'SoundTouchFactory.cpp',
|
||||
'TDStretch.cpp',
|
||||
]
|
||||
|
||||
soundtouch_defines = [
|
||||
('BUILDING_SOUNDTOUCH', 1),
|
||||
# Use abort() instead of exception in SoundTouch.
|
||||
('ST_NO_EXCEPTION_HANDLING', 1)
|
||||
]
|
Loading…
Reference in New Issue
Block a user