summaryrefslogtreecommitdiffstats
path: root/dom/media/webrtc/SineWaveGenerator.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/webrtc/SineWaveGenerator.h')
-rw-r--r--dom/media/webrtc/SineWaveGenerator.h83
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_ */