/* -*- 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 <stdint.h> #include <math.h> #include "../AudioPacketizer.h" #include "gtest/gtest.h" using namespace mozilla; template<typename T> class AutoBuffer { public: explicit AutoBuffer(size_t aLength) { mStorage = new T[aLength]; } ~AutoBuffer() { delete [] mStorage; } T* Get() { return mStorage; } private: T* mStorage; }; int16_t Sequence(int16_t* aBuffer, uint32_t aSize, uint32_t aStart = 0) { uint32_t i; for (i = 0; i < aSize; i++) { aBuffer[i] = aStart + i; } return aStart + i; } void IsSequence(int16_t* aBuffer, uint32_t aSize, uint32_t aStart = 0) { for (uint32_t i = 0; i < aSize; i++) { ASSERT_TRUE(aBuffer[i] == static_cast<int64_t>(aStart + i)) << "Buffer is not a sequence at offset " << i << std::endl; } // Buffer is a sequence. } void Zero(int16_t* aBuffer, uint32_t aSize) { for (uint32_t i = 0; i < aSize; i++) { ASSERT_TRUE(aBuffer[i] == 0) << "Buffer is not null at offset " << i << std::endl; } } double sine(uint32_t aPhase) { return sin(aPhase * 2 * M_PI * 440 / 44100); } TEST(AudioPacketizer, Test) { for (int16_t channels = 1; channels < 2; channels++) { // Test that the packetizer returns zero on underrun { AudioPacketizer<int16_t, int16_t> ap(441, channels); for (int16_t i = 0; i < 10; i++) { int16_t* out = ap.Output(); Zero(out, 441); delete[] out; } } // Simple test, with input/output buffer size aligned on the packet size, // alternating Input and Output calls. { AudioPacketizer<int16_t, int16_t> ap(441, channels); int16_t seqEnd = 0; for (int16_t i = 0; i < 10; i++) { AutoBuffer<int16_t> b(441 * channels); int16_t prevEnd = seqEnd; seqEnd = Sequence(b.Get(), channels * 441, prevEnd); ap.Input(b.Get(), 441); int16_t* out = ap.Output(); IsSequence(out, 441 * channels, prevEnd); delete[] out; } } // Simple test, with input/output buffer size aligned on the packet size, // alternating two Input and Output calls. { AudioPacketizer<int16_t, int16_t> ap(441, channels); int16_t seqEnd = 0; for (int16_t i = 0; i < 10; i++) { AutoBuffer<int16_t> b(441 * channels); AutoBuffer<int16_t> b1(441 * channels); int16_t prevEnd0 = seqEnd; seqEnd = Sequence(b.Get(), 441 * channels, prevEnd0); int16_t prevEnd1 = seqEnd; seqEnd = Sequence(b1.Get(), 441 * channels, seqEnd); ap.Input(b.Get(), 441); ap.Input(b1.Get(), 441); int16_t* out = ap.Output(); int16_t* out2 = ap.Output(); IsSequence(out, 441 * channels, prevEnd0); IsSequence(out2, 441 * channels, prevEnd1); delete[] out; delete[] out2; } } // Input/output buffer size not aligned on the packet size, // alternating two Input and Output calls. { AudioPacketizer<int16_t, int16_t> ap(441, channels); int16_t prevEnd = 0; int16_t prevSeq = 0; for (int16_t i = 0; i < 10; i++) { AutoBuffer<int16_t> b(480 * channels); AutoBuffer<int16_t> b1(480 * channels); prevSeq = Sequence(b.Get(), 480 * channels, prevSeq); prevSeq = Sequence(b1.Get(), 480 * channels, prevSeq); ap.Input(b.Get(), 480); ap.Input(b1.Get(), 480); int16_t* out = ap.Output(); int16_t* out2 = ap.Output(); IsSequence(out, 441 * channels, prevEnd); prevEnd += 441 * channels; IsSequence(out2, 441 * channels, prevEnd); prevEnd += 441 * channels; delete[] out; delete[] out2; } printf("Available: %d\n", ap.PacketsAvailable()); } // "Real-life" test case: streaming a sine wave through a packetizer, and // checking that we have the right output. // 128 is, for example, the size of a Web Audio API block, and 441 is the // size of a webrtc.org packet when the sample rate is 44100 (10ms) { AudioPacketizer<int16_t, int16_t> ap(441, channels); AutoBuffer<int16_t> b(128 * channels); uint32_t phase = 0; uint32_t outPhase = 0; for (int16_t i = 0; i < 1000; i++) { for (int32_t j = 0; j < 128; j++) { for (int32_t c = 0; c < channels; c++) { // int16_t sinewave at 440Hz/44100Hz sample rate b.Get()[j * channels + c] = (2 << 14) * sine(phase); } phase++; } ap.Input(b.Get(), 128); while (ap.PacketsAvailable()) { int16_t* packet = ap.Output(); for (uint32_t k = 0; k < ap.PacketSize(); k++) { for (int32_t c = 0; c < channels; c++) { ASSERT_TRUE(packet[k * channels + c] == static_cast<int16_t>(((2 << 14) * sine(outPhase)))); } outPhase++; } delete [] packet; } } } } }