/* -*- Mode: C++; tab-width: 2; 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 "AudioMixer.h" #include "gtest/gtest.h" using mozilla::AudioDataValue; using mozilla::AudioSampleFormat; namespace audio_mixer { struct MixerConsumer : public mozilla::MixerCallbackReceiver { /* In this test, the different audio stream and channels are always created to * cancel each other. */ void MixerCallback(mozilla::AudioChunk* aMixedBuffer, uint32_t aSampleRate) { bool silent = true; ASSERT_EQ(aMixedBuffer->mBufferFormat, mozilla::AUDIO_FORMAT_FLOAT32); for (uint32_t c = 0; c < aMixedBuffer->ChannelCount(); c++) { const float* channelData = aMixedBuffer->ChannelData()[c]; for (uint32_t i = 0; i < aMixedBuffer->mDuration; i++) { if (channelData[i] != 0.0) { fprintf(stderr, "Sample at %d in channel %c is not silent: %f\n", i, c, channelData[i]); silent = false; } } } ASSERT_TRUE(silent); } }; /* Helper function to give us the maximum and minimum value that don't clip, * for a given sample format (integer or floating-point). */ template T GetLowValue(); template T GetHighValue(); template <> float GetLowValue() { return -1.0; } template <> short GetLowValue() { return -INT16_MAX; } template <> float GetHighValue() { return 1.0; } template <> short GetHighValue() { return INT16_MAX; } void FillBuffer(AudioDataValue* aBuffer, uint32_t aLength, AudioDataValue aValue) { AudioDataValue* end = aBuffer + aLength; while (aBuffer != end) { *aBuffer++ = aValue; } } TEST(AudioMixer, Test) { const uint32_t CHANNEL_LENGTH = 256; const uint32_t AUDIO_RATE = 44100; MixerConsumer consumer; AudioDataValue a[CHANNEL_LENGTH * 2]; AudioDataValue b[CHANNEL_LENGTH * 2]; FillBuffer(a, CHANNEL_LENGTH, GetLowValue()); FillBuffer(a + CHANNEL_LENGTH, CHANNEL_LENGTH, GetHighValue()); FillBuffer(b, CHANNEL_LENGTH, GetHighValue()); FillBuffer(b + CHANNEL_LENGTH, CHANNEL_LENGTH, GetLowValue()); { int iterations = 2; mozilla::AudioMixer mixer; fprintf(stderr, "Test AudioMixer constant buffer length.\n"); while (iterations--) { mixer.StartMixing(); mixer.Mix(a, 2, CHANNEL_LENGTH, AUDIO_RATE); mixer.Mix(b, 2, CHANNEL_LENGTH, AUDIO_RATE); consumer.MixerCallback(mixer.MixedChunk(), AUDIO_RATE); } } { mozilla::AudioMixer mixer; fprintf(stderr, "Test AudioMixer variable buffer length.\n"); FillBuffer(a, CHANNEL_LENGTH / 2, GetLowValue()); FillBuffer(a + CHANNEL_LENGTH / 2, CHANNEL_LENGTH / 2, GetLowValue()); FillBuffer(b, CHANNEL_LENGTH / 2, GetHighValue()); FillBuffer(b + CHANNEL_LENGTH / 2, CHANNEL_LENGTH / 2, GetHighValue()); mixer.StartMixing(); mixer.Mix(a, 2, CHANNEL_LENGTH / 2, AUDIO_RATE); mixer.Mix(b, 2, CHANNEL_LENGTH / 2, AUDIO_RATE); consumer.MixerCallback(mixer.MixedChunk(), AUDIO_RATE); FillBuffer(a, CHANNEL_LENGTH, GetLowValue()); FillBuffer(a + CHANNEL_LENGTH, CHANNEL_LENGTH, GetHighValue()); FillBuffer(b, CHANNEL_LENGTH, GetHighValue()); FillBuffer(b + CHANNEL_LENGTH, CHANNEL_LENGTH, GetLowValue()); mixer.StartMixing(); mixer.Mix(a, 2, CHANNEL_LENGTH, AUDIO_RATE); mixer.Mix(b, 2, CHANNEL_LENGTH, AUDIO_RATE); consumer.MixerCallback(mixer.MixedChunk(), AUDIO_RATE); FillBuffer(a, CHANNEL_LENGTH / 2, GetLowValue()); FillBuffer(a + CHANNEL_LENGTH / 2, CHANNEL_LENGTH / 2, GetLowValue()); FillBuffer(b, CHANNEL_LENGTH / 2, GetHighValue()); FillBuffer(b + CHANNEL_LENGTH / 2, CHANNEL_LENGTH / 2, GetHighValue()); mixer.StartMixing(); mixer.Mix(a, 2, CHANNEL_LENGTH / 2, AUDIO_RATE); mixer.Mix(b, 2, CHANNEL_LENGTH / 2, AUDIO_RATE); consumer.MixerCallback(mixer.MixedChunk(), AUDIO_RATE); } FillBuffer(a, CHANNEL_LENGTH, GetLowValue()); FillBuffer(b, CHANNEL_LENGTH, GetHighValue()); { mozilla::AudioMixer mixer; fprintf(stderr, "Test AudioMixer variable channel count.\n"); mixer.StartMixing(); mixer.Mix(a, 1, CHANNEL_LENGTH, AUDIO_RATE); mixer.Mix(b, 1, CHANNEL_LENGTH, AUDIO_RATE); consumer.MixerCallback(mixer.MixedChunk(), AUDIO_RATE); mixer.StartMixing(); mixer.Mix(a, 1, CHANNEL_LENGTH, AUDIO_RATE); mixer.Mix(b, 1, CHANNEL_LENGTH, AUDIO_RATE); consumer.MixerCallback(mixer.MixedChunk(), AUDIO_RATE); mixer.StartMixing(); mixer.Mix(a, 1, CHANNEL_LENGTH, AUDIO_RATE); mixer.Mix(b, 1, CHANNEL_LENGTH, AUDIO_RATE); consumer.MixerCallback(mixer.MixedChunk(), AUDIO_RATE); } { mozilla::AudioMixer mixer; fprintf(stderr, "Test AudioMixer variable stream count.\n"); mixer.StartMixing(); mixer.Mix(a, 2, CHANNEL_LENGTH, AUDIO_RATE); mixer.Mix(b, 2, CHANNEL_LENGTH, AUDIO_RATE); consumer.MixerCallback(mixer.MixedChunk(), AUDIO_RATE); mixer.StartMixing(); mixer.Mix(a, 2, CHANNEL_LENGTH, AUDIO_RATE); mixer.Mix(b, 2, CHANNEL_LENGTH, AUDIO_RATE); mixer.Mix(a, 2, CHANNEL_LENGTH, AUDIO_RATE); mixer.Mix(b, 2, CHANNEL_LENGTH, AUDIO_RATE); consumer.MixerCallback(mixer.MixedChunk(), AUDIO_RATE); mixer.StartMixing(); mixer.Mix(a, 2, CHANNEL_LENGTH, AUDIO_RATE); mixer.Mix(b, 2, CHANNEL_LENGTH, AUDIO_RATE); consumer.MixerCallback(mixer.MixedChunk(), AUDIO_RATE); } } } // namespace audio_mixer