Bug 1656438 - Generalize AudioGenerator and SineWaveGenerator to support AudioToneGenerator's use cases. r=padenot

Depends on D85552

Differential Revision: https://phabricator.services.mozilla.com/D89738
This commit is contained in:
Andreas Pehrson 2020-09-15 11:52:06 +00:00
parent bd90aec1ed
commit 4da0ed94ab
6 changed files with 67 additions and 51 deletions

View File

@ -1,28 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 https://mozilla.org/MPL/2.0/. */
#include "AudioGenerator.h"
#include "AudioSegment.h"
using namespace mozilla;
AudioGenerator::AudioGenerator(int32_t aChannels, int32_t aSampleRate)
: mGenerator(aSampleRate, 1000), mChannels(aChannels) {}
void AudioGenerator::Generate(AudioSegment& aSegment, const int32_t& aSamples) {
CheckedInt<size_t> bufferSize(sizeof(int16_t));
bufferSize *= aSamples;
RefPtr<SharedBuffer> buffer = SharedBuffer::Create(bufferSize);
int16_t* dest = static_cast<int16_t*>(buffer->Data());
mGenerator.generate(dest, aSamples);
AutoTArray<const int16_t*, 1> channels;
for (int32_t i = 0; i < mChannels; i++) {
channels.AppendElement(dest);
}
aSegment.AppendFrames(buffer.forget(), channels, aSamples,
PRINCIPAL_HANDLE_NONE);
}

View File

@ -7,21 +7,50 @@
#ifndef DOM_MEDIA_GTEST_AUDIO_GENERATOR_H_
#define DOM_MEDIA_GTEST_AUDIO_GENERATOR_H_
#include "AudioSegment.h"
#include "prtime.h"
#include "SineWaveGenerator.h"
namespace mozilla {
class AudioSegment;
}
template <typename Sample>
class AudioGenerator {
public:
AudioGenerator(int32_t aChannels, int32_t aSampleRate);
void Generate(mozilla::AudioSegment& aSegment, const int32_t& aSamples);
AudioGenerator(uint32_t aChannels, uint32_t aSampleRate,
uint32_t aFrequency = 1000)
: mChannels(aChannels),
mSampleRate(aSampleRate),
mFrequency(aFrequency),
mGenerator(aSampleRate, aFrequency) {}
void Generate(mozilla::AudioSegment& aSegment, const uint32_t& aSamples) {
CheckedInt<size_t> bufferSize(sizeof(Sample));
bufferSize *= aSamples;
RefPtr<SharedBuffer> buffer = SharedBuffer::Create(bufferSize);
Sample* dest = static_cast<Sample*>(buffer->Data());
mGenerator.generate(dest, aSamples);
AutoTArray<const Sample*, 1> channels;
for (uint32_t i = 0; i < mChannels; ++i) {
channels.AppendElement(dest);
}
aSegment.AppendFrames(buffer.forget(), channels, aSamples,
PRINCIPAL_HANDLE_NONE);
}
void SetOffset(TrackTicks aFrames) { mGenerator.SetOffset(aFrames); }
TrackTicks Offset() const { return mGenerator.Offset(); }
static float Amplitude() { return SineWaveGenerator<Sample>::Amplitude(); }
const uint32_t mChannels;
const uint32_t mSampleRate;
const uint32_t mFrequency;
private:
mozilla::SineWaveGenerator mGenerator;
const int32_t mChannels;
mozilla::SineWaveGenerator<Sample> mGenerator;
};
} // namespace mozilla
#endif // DOM_MEDIA_GTEST_AUDIO_GENERATOR_H_

View File

@ -7,6 +7,7 @@
#include "OpusTrackEncoder.h"
#include "AudioGenerator.h"
#include "AudioSampleFormat.h"
using namespace mozilla;
@ -102,7 +103,7 @@ TEST(OpusAudioTrackEncoder, Init)
// For non-null segments we should init immediately
OpusTrackEncoder encoder(48000);
AudioSegment segment;
AudioGenerator generator(2, 48000);
AudioGenerator<AudioDataValue> generator(2, 48000);
generator.Generate(segment, 1);
encoder.TryInit(segment, segment.GetDuration());
EXPECT_TRUE(encoder.IsInitialized());
@ -112,7 +113,7 @@ TEST(OpusAudioTrackEncoder, Init)
// Test low sample rate bound
OpusTrackEncoder encoder(7999);
AudioSegment segment;
AudioGenerator generator(2, 7999);
AudioGenerator<AudioDataValue> generator(2, 7999);
generator.Generate(segment, 1);
encoder.TryInit(segment, segment.GetDuration());
EXPECT_FALSE(encoder.IsInitialized());
@ -122,7 +123,7 @@ TEST(OpusAudioTrackEncoder, Init)
// Test low sample rate bound
OpusTrackEncoder encoder(8000);
AudioSegment segment;
AudioGenerator generator(2, 8000);
AudioGenerator<AudioDataValue> generator(2, 8000);
generator.Generate(segment, 1);
encoder.TryInit(segment, segment.GetDuration());
EXPECT_TRUE(encoder.IsInitialized());
@ -132,7 +133,7 @@ TEST(OpusAudioTrackEncoder, Init)
// Test high sample rate bound
OpusTrackEncoder encoder(192001);
AudioSegment segment;
AudioGenerator generator(2, 192001);
AudioGenerator<AudioDataValue> generator(2, 192001);
generator.Generate(segment, 1);
encoder.TryInit(segment, segment.GetDuration());
EXPECT_FALSE(encoder.IsInitialized());
@ -142,7 +143,7 @@ TEST(OpusAudioTrackEncoder, Init)
// Test high sample rate bound
OpusTrackEncoder encoder(192000);
AudioSegment segment;
AudioGenerator generator(2, 192000);
AudioGenerator<AudioDataValue> generator(2, 192000);
generator.Generate(segment, 1);
encoder.TryInit(segment, segment.GetDuration());
EXPECT_TRUE(encoder.IsInitialized());
@ -194,7 +195,7 @@ TEST(OpusAudioTrackEncoder, FrameEncode)
EXPECT_TRUE(encoder.TestOpusRawCreation(channels, sampleRate));
// Generate five seconds of raw audio data.
AudioGenerator generator(channels, sampleRate);
AudioGenerator<AudioDataValue> generator(channels, sampleRate);
AudioSegment segment;
const int32_t samples = sampleRate * 5;
generator.Generate(segment, samples);

View File

@ -15,7 +15,6 @@ LOCAL_INCLUDES += [
]
UNIFIED_SOURCES += [
'AudioGenerator.cpp',
'MockMediaResource.cpp',
'TestAudioBuffers.cpp',
'TestAudioCallbackDriver.cpp',

View File

@ -358,8 +358,8 @@ class AudioSourcePullListener : public MediaTrackListener {
uint32_t aFrequency)
: mTrack(std::move(aTrack)),
mPrincipalHandle(aPrincipalHandle),
mSineGenerator(
MakeUnique<SineWaveGenerator>(mTrack->mSampleRate, aFrequency)) {
mSineGenerator(MakeUnique<SineWaveGenerator<int16_t>>(
mTrack->mSampleRate, aFrequency)) {
MOZ_COUNT_CTOR(AudioSourcePullListener);
}
@ -370,7 +370,7 @@ class AudioSourcePullListener : public MediaTrackListener {
const RefPtr<SourceMediaTrack> mTrack;
const PrincipalHandle mPrincipalHandle;
const UniquePtr<SineWaveGenerator> mSineGenerator;
const UniquePtr<SineWaveGenerator<int16_t>> mSineGenerator;
};
/**

View File

@ -10,9 +10,13 @@
namespace mozilla {
// generate 1k sine wave per second
template <typename Sample>
class SineWaveGenerator {
static_assert(std::is_same<Sample, int16_t>::value ||
std::is_same<Sample, float>::value);
public:
static const int bytesPerSample = 2;
static const int bytesPerSample = sizeof(Sample);
static const int millisecondsPerSecond = PR_MSEC_PER_SEC;
explicit SineWaveGenerator(uint32_t aSampleRate, uint32_t aFrequency)
@ -21,15 +25,14 @@ class SineWaveGenerator {
// rounded here We could include an error term and adjust for it in
// generation; not worth the trouble
// MOZ_ASSERT(mTotalLength * aFrequency == aSampleRate);
mAudioBuffer = MakeUnique<int16_t[]>(mTotalLength);
for (int i = 0; i < mTotalLength; i++) {
// Set volume to -20db. It's from 32768.0 * 10^(-20/20) = 3276.8
mAudioBuffer[i] = (3276.8f * sin(2 * M_PI * i / mTotalLength));
mAudioBuffer = MakeUnique<Sample[]>(mTotalLength);
for (uint32_t i = 0; i < mTotalLength; ++i) {
mAudioBuffer[i] = Amplitude() * sin(2 * M_PI * i / mTotalLength);
}
}
// NOTE: only safely called from a single thread (MTG callback)
void generate(int16_t* aBuffer, TrackTicks aLengthInSamples) {
void generate(Sample* aBuffer, TrackTicks aLengthInSamples) {
TrackTicks remaining = aLengthInSamples;
while (remaining) {
@ -51,8 +54,20 @@ class SineWaveGenerator {
}
}
void SetOffset(TrackTicks aFrames) { mReadLength = aFrames % mTotalLength; }
TrackTicks Offset() const { return mReadLength; }
static float Amplitude() {
// Set volume to -20db.
if (std::is_same<Sample, int16_t>::value) {
return 3276.8; // 32768.0 * 10^(-20/20) = 3276.8
}
return 0.1f; // 1.0 * 10^(-20/20) = 0.1
}
private:
UniquePtr<int16_t[]> mAudioBuffer;
UniquePtr<Sample[]> mAudioBuffer;
TrackTicks mTotalLength;
TrackTicks mReadLength;
};