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:
Willy R. Vasquez 2023-08-29 06:26:34 +00:00
parent 88e2f3bd9e
commit bb50d4a28b
17 changed files with 465 additions and 72 deletions

View File

@ -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

View File

@ -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

View File

@ -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;

View 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);
}

View 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

View 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

View File

@ -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);

View File

@ -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;

View File

@ -17,6 +17,7 @@ EXPORTS += [
]
LOCAL_INCLUDES += [
"!/security/rlbox",
"/dom/media",
]

View File

@ -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",

View File

@ -74,6 +74,7 @@ vendoring:
keep:
- AUTHORS
- clear-lf.sh
- src/RLBoxSoundTouchFactory.*
- src/SoundTouchFactory.*
- src/soundtouch_config.h
- src/soundtouch_perms.h

View 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(); }
}

View 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);
}

View File

@ -6,7 +6,7 @@
#include <soundtouch/SoundTouch.h>
namespace soundtouch
extern "C" namespace soundtouch
{
SOUNDTOUCH_API

View File

@ -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*

View File

@ -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

View 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)
]