diff options
Diffstat (limited to 'dom/media/webrtc/SineWaveGenerator.h')
-rw-r--r-- | dom/media/webrtc/SineWaveGenerator.h | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/dom/media/webrtc/SineWaveGenerator.h b/dom/media/webrtc/SineWaveGenerator.h new file mode 100644 index 0000000000..d30ccf448f --- /dev/null +++ b/dom/media/webrtc/SineWaveGenerator.h @@ -0,0 +1,83 @@ +/* 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 SINEWAVEGENERATOR_H_ +#define SINEWAVEGENERATOR_H_ + +#include "MediaSegment.h" + +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 = sizeof(Sample); + static const int millisecondsPerSecond = PR_MSEC_PER_SEC; + + /* If more than 1 channel, generated samples are interleaved. */ + SineWaveGenerator(uint32_t aSampleRate, uint32_t aFrequency, + uint32_t aChannels = 1) + : mTotalLength(aSampleRate * aChannels / aFrequency), mReadLength(0) { + MOZ_ASSERT(aChannels >= 1); + // If we allow arbitrary frequencies, there's no guarantee we won't get + // 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<Sample[]>(mTotalLength); + for (uint32_t i = 0; i < aSampleRate / aFrequency; ++i) { + for (uint32_t j = 0; j < aChannels; ++j) { + mAudioBuffer[i * aChannels + j] = + Amplitude() * sin(2 * M_PI * i * aChannels / mTotalLength); + } + } + } + + // NOTE: only safely called from a single thread (MTG callback) + void generate(Sample* aBuffer, TrackTicks aLengthInSamples) { + TrackTicks remaining = aLengthInSamples; + + while (remaining) { + TrackTicks processSamples = 0; + + if (mTotalLength - mReadLength >= remaining) { + processSamples = remaining; + } else { + processSamples = mTotalLength - mReadLength; + } + memcpy(aBuffer, &mAudioBuffer[mReadLength], + processSamples * bytesPerSample); + aBuffer += processSamples; + mReadLength += processSamples; + remaining -= processSamples; + if (mReadLength == mTotalLength) { + mReadLength = 0; + } + } + } + + 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<Sample[]> mAudioBuffer; + TrackTicks mTotalLength; + TrackTicks mReadLength; +}; + +} // namespace mozilla + +#endif /* SINEWAVEGENERATOR_H_ */ |