mirror of
https://github.com/mudita/MuditaOS.git
synced 2026-01-17 18:37:53 -05:00
Fix of the heap fragmentation issue that caused phone crash when trying to play music files while connecting USB cable in a certain order. Audio stream buffering length was slightly reduced, so that smaller contiguous block of heap is required to store audio buffer.
579 lines
18 KiB
C++
579 lines
18 KiB
C++
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
|
|
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
|
|
|
#include <gtest/gtest.h>
|
|
#include <gmock/gmock.h>
|
|
|
|
#include <Audio/Stream.hpp>
|
|
#include <Audio/AudioFormat.hpp>
|
|
#include <Audio/StreamProxy.hpp>
|
|
#include <Audio/StreamFactory.hpp>
|
|
#include <Audio/transcode/BasicDecimator.hpp>
|
|
|
|
#include "MockEndpoint.hpp"
|
|
#include "MockStream.hpp"
|
|
|
|
#include <memory>
|
|
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
|
|
using audio::NonCacheableStreamAllocator;
|
|
using audio::StandardStreamAllocator;
|
|
using audio::Stream;
|
|
using testing::Return;
|
|
using testing::audio::MockStream;
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
constexpr std::size_t defaultBlockSize = 64U;
|
|
constexpr std::size_t defaultBuffering = 24U;
|
|
constexpr audio::AudioFormat format = audio::AudioFormat(44100, 16, 2);
|
|
|
|
static std::uint8_t testData[defaultBuffering][defaultBlockSize];
|
|
static std::uint8_t emptyBlock[defaultBlockSize];
|
|
|
|
static void initTestData()
|
|
{
|
|
auto fillbuf = [](std::uint8_t *b, std::size_t s, unsigned step) {
|
|
std::uint8_t v = 0;
|
|
for (unsigned int i = 0; i < s; ++i, v += step) {
|
|
b[i] = v; // & (UINT8_MAX - 1);
|
|
}
|
|
};
|
|
|
|
fillbuf(testData[0], defaultBlockSize, 1);
|
|
fillbuf(testData[1], defaultBlockSize, 3);
|
|
fillbuf(testData[2], defaultBlockSize, 7);
|
|
fillbuf(testData[3], defaultBlockSize, 13);
|
|
fillbuf(emptyBlock, defaultBlockSize, 0);
|
|
}
|
|
|
|
static void printBuf(std::uint8_t *buf, std::size_t s)
|
|
{
|
|
for (unsigned int i = 0; i < s; i++) {
|
|
std::cout << static_cast<unsigned int>(buf[i]) << " ";
|
|
}
|
|
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
[[maybe_unused]] static void printBuf(Stream::Span s)
|
|
{
|
|
printBuf(s.data, s.dataSize);
|
|
}
|
|
|
|
TEST(Stream, Init)
|
|
{
|
|
StandardStreamAllocator a;
|
|
constexpr auto bufferingSize = 2U;
|
|
Stream s(format, a, defaultBlockSize, bufferingSize);
|
|
|
|
EXPECT_EQ(s.getBlockCount(), bufferingSize);
|
|
EXPECT_EQ(s.getInputTraits().blockSize, defaultBlockSize);
|
|
EXPECT_EQ(s.getOutputTraits().blockSize, defaultBlockSize);
|
|
EXPECT_EQ(s.getUsedBlockCount(), 0);
|
|
}
|
|
|
|
TEST(Stream, DefaultBuffering)
|
|
{
|
|
StandardStreamAllocator allocator;
|
|
Stream stream(format, allocator, defaultBlockSize);
|
|
EXPECT_EQ(stream.getBlockCount(), defaultBuffering);
|
|
}
|
|
|
|
TEST(Stream, EmptyFull)
|
|
{
|
|
StandardStreamAllocator a;
|
|
constexpr auto bufferingSize = 2U;
|
|
Stream s(format, a, defaultBlockSize, bufferingSize);
|
|
|
|
EXPECT_TRUE(s.isEmpty());
|
|
EXPECT_TRUE(s.blocksAvailable());
|
|
EXPECT_FALSE(s.isFull());
|
|
|
|
s.push();
|
|
|
|
EXPECT_FALSE(s.isEmpty());
|
|
EXPECT_TRUE(s.blocksAvailable());
|
|
EXPECT_FALSE(s.isFull());
|
|
|
|
s.push();
|
|
|
|
EXPECT_FALSE(s.isEmpty());
|
|
EXPECT_FALSE(s.blocksAvailable());
|
|
EXPECT_TRUE(s.isFull());
|
|
}
|
|
|
|
TEST(Stream, Allocator)
|
|
{
|
|
NonCacheableStreamAllocator a;
|
|
EXPECT_NO_THROW(Stream(format, a, defaultBlockSize));
|
|
}
|
|
|
|
TEST(Stream, Listeners)
|
|
{
|
|
testing::audio::MockStreamEventListener listener;
|
|
StandardStreamAllocator a;
|
|
Stream s(format, a, defaultBlockSize);
|
|
Stream::Span span;
|
|
|
|
s.registerListener(&listener);
|
|
|
|
// does not take effect
|
|
s.unregisterListeners(nullptr);
|
|
|
|
EXPECT_CALL(listener, onEvent(&s, ::audio::AbstractStream::Event::StreamUnderFlow)).Times(1);
|
|
s.peek(span);
|
|
|
|
s.unregisterListeners(&listener);
|
|
|
|
// no second onEvent call - listener is unregistered
|
|
s.peek(span);
|
|
}
|
|
|
|
TEST(Stream, Push)
|
|
{
|
|
StandardStreamAllocator a;
|
|
Stream s(format, a, defaultBlockSize);
|
|
auto block = testData[0];
|
|
|
|
for (std::size_t i = 0; i < defaultBuffering; i++) {
|
|
EXPECT_TRUE(s.push(block, defaultBlockSize));
|
|
}
|
|
EXPECT_EQ(s.getUsedBlockCount(), defaultBuffering);
|
|
EXPECT_FALSE(s.push(block, defaultBlockSize));
|
|
}
|
|
|
|
TEST(Stream, InvalidPushPop)
|
|
{
|
|
StandardStreamAllocator a;
|
|
std::uint8_t buf[defaultBlockSize];
|
|
Stream s(format, a, defaultBlockSize);
|
|
Stream::Span span{.data = buf, .dataSize = 63};
|
|
|
|
EXPECT_FALSE(s.push(span));
|
|
span.dataSize = defaultBlockSize;
|
|
|
|
// push and peek null data
|
|
EXPECT_TRUE(s.push());
|
|
EXPECT_TRUE(s.peek(span));
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
ASSERT_EQ(span.dataSize, defaultBlockSize);
|
|
EXPECT_EQ(memcmp(span.data, buf, span.dataSize), 0);
|
|
|
|
// peek in progress - push is not allowed
|
|
EXPECT_FALSE(s.pop(span));
|
|
|
|
// push is not allowed when using zero copy write
|
|
EXPECT_TRUE(s.reserve(span));
|
|
EXPECT_FALSE(s.push(span));
|
|
}
|
|
|
|
TEST(Stream, PushPop)
|
|
{
|
|
StandardStreamAllocator a;
|
|
Stream s(format, a, defaultBlockSize);
|
|
|
|
initTestData();
|
|
|
|
EXPECT_TRUE(s.push(testData[0], defaultBlockSize));
|
|
EXPECT_EQ(s.getUsedBlockCount(), 1);
|
|
|
|
{
|
|
std::uint8_t buf[defaultBlockSize];
|
|
Stream::Span popped = {.data = buf, .dataSize = defaultBlockSize};
|
|
EXPECT_TRUE(s.pop(popped));
|
|
ASSERT_EQ(popped.dataSize, defaultBlockSize);
|
|
ASSERT_EQ(popped.data, buf);
|
|
ASSERT_EQ(memcmp(popped.data, testData[0], defaultBlockSize), 0);
|
|
}
|
|
|
|
{
|
|
std::uint8_t buf[defaultBlockSize];
|
|
Stream::Span popped = {.data = buf, .dataSize = defaultBlockSize};
|
|
EXPECT_FALSE(s.pop(popped));
|
|
ASSERT_EQ(popped.dataSize, defaultBlockSize);
|
|
ASSERT_NE(popped.data, buf);
|
|
ASSERT_EQ(memcmp(popped.data, emptyBlock, defaultBlockSize), 0);
|
|
}
|
|
|
|
{
|
|
for (unsigned int i = 0; i < s.getBlockCount(); ++i) {
|
|
ASSERT_TRUE(s.push(testData[i], defaultBlockSize));
|
|
}
|
|
|
|
for (unsigned int i = 0; i < s.getBlockCount(); ++i) {
|
|
std::uint8_t buf[defaultBlockSize];
|
|
Stream::Span popped = {.data = buf, .dataSize = defaultBlockSize};
|
|
EXPECT_TRUE(s.pop(popped));
|
|
ASSERT_EQ(popped.dataSize, defaultBlockSize);
|
|
ASSERT_EQ(popped.data, buf);
|
|
ASSERT_EQ(memcmp(popped.data, testData[i], defaultBlockSize), 0);
|
|
}
|
|
}
|
|
|
|
ASSERT_EQ(s.getUsedBlockCount(), 0);
|
|
}
|
|
|
|
TEST(Stream, Peek)
|
|
{
|
|
StandardStreamAllocator a;
|
|
Stream s(format, a, defaultBlockSize);
|
|
|
|
initTestData();
|
|
|
|
{
|
|
Stream::Span span;
|
|
|
|
EXPECT_FALSE(s.peek(span));
|
|
ASSERT_EQ(memcmp(span.data, emptyBlock, span.dataSize), 0);
|
|
}
|
|
|
|
{
|
|
Stream::Span span;
|
|
Stream::Span popped;
|
|
|
|
EXPECT_TRUE(s.push(testData[0], defaultBlockSize));
|
|
ASSERT_EQ(s.getPeekedCount(), 0);
|
|
ASSERT_EQ(s.getUsedBlockCount(), 1);
|
|
EXPECT_TRUE(s.peek(span));
|
|
ASSERT_EQ(memcmp(span.data, testData[0], defaultBlockSize), 0);
|
|
EXPECT_EQ(s.getUsedBlockCount(), 1);
|
|
EXPECT_FALSE(s.pop(popped));
|
|
EXPECT_EQ(s.getUsedBlockCount(), 1);
|
|
|
|
s.unpeek();
|
|
EXPECT_TRUE(s.peek(span));
|
|
ASSERT_EQ(memcmp(span.data, testData[0], defaultBlockSize), 0);
|
|
s.consume();
|
|
EXPECT_EQ(s.getUsedBlockCount(), 0);
|
|
}
|
|
}
|
|
|
|
TEST(Stream, GreedyPeek)
|
|
{
|
|
StandardStreamAllocator a;
|
|
Stream s(format, a, defaultBlockSize);
|
|
Stream::Span span;
|
|
|
|
initTestData();
|
|
|
|
for (unsigned int i = 0; i < s.getBlockCount(); ++i) {
|
|
ASSERT_TRUE(s.push(testData[i], defaultBlockSize));
|
|
}
|
|
|
|
ASSERT_EQ(s.getUsedBlockCount(), defaultBuffering);
|
|
|
|
for (unsigned int i = 0; i < s.getBlockCount(); ++i) {
|
|
EXPECT_EQ(s.getPeekedCount(), i);
|
|
EXPECT_TRUE(s.peek(span));
|
|
EXPECT_EQ(s.getPeekedCount(), i + 1);
|
|
ASSERT_EQ(span.dataSize, defaultBlockSize);
|
|
ASSERT_EQ(memcmp(span.data, testData[i], defaultBlockSize), 0);
|
|
}
|
|
|
|
ASSERT_FALSE(s.peek(span));
|
|
}
|
|
|
|
TEST(Stream, Reserve)
|
|
{
|
|
StandardStreamAllocator a;
|
|
Stream s(format, a, defaultBlockSize);
|
|
Stream::Span span;
|
|
|
|
EXPECT_EQ(s.getReservedCount(), 0);
|
|
EXPECT_TRUE(s.reserve(span));
|
|
EXPECT_EQ(s.getReservedCount(), 1);
|
|
EXPECT_EQ(s.getUsedBlockCount(), 0);
|
|
|
|
s.release();
|
|
EXPECT_EQ(s.getReservedCount(), 0);
|
|
EXPECT_EQ(s.getUsedBlockCount(), 0);
|
|
|
|
for (unsigned int i = 0; i < s.getBlockCount(); ++i) {
|
|
EXPECT_EQ(s.getReservedCount(), i);
|
|
EXPECT_TRUE(s.reserve(span));
|
|
EXPECT_EQ(s.getReservedCount(), i + 1);
|
|
}
|
|
|
|
EXPECT_FALSE(s.reserve(span));
|
|
|
|
s.commit();
|
|
EXPECT_EQ(s.getUsedBlockCount(), 1);
|
|
}
|
|
|
|
TEST(Stream, Iterator)
|
|
{
|
|
std::uint8_t buf[defaultBlockSize * 2];
|
|
|
|
Stream::RawBlockIterator it(buf, sizeof(buf), buf, 64);
|
|
|
|
it++;
|
|
auto data = *it;
|
|
EXPECT_EQ(data.data, &buf[defaultBlockSize]);
|
|
EXPECT_EQ(data.dataSize, defaultBlockSize);
|
|
|
|
it++;
|
|
data = *it;
|
|
EXPECT_EQ(data.data, buf);
|
|
EXPECT_EQ(data.dataSize, defaultBlockSize);
|
|
|
|
it--;
|
|
data = *it;
|
|
EXPECT_EQ(data.data, &buf[defaultBlockSize]);
|
|
EXPECT_EQ(data.dataSize, defaultBlockSize);
|
|
|
|
it--;
|
|
data = *it;
|
|
EXPECT_EQ(data.data, buf);
|
|
EXPECT_EQ(data.dataSize, defaultBlockSize);
|
|
}
|
|
|
|
TEST(Stream, Reset)
|
|
{
|
|
StandardStreamAllocator a;
|
|
Stream s(format, a, defaultBlockSize);
|
|
|
|
s.push();
|
|
ASSERT_FALSE(s.isEmpty());
|
|
|
|
s.reset();
|
|
EXPECT_TRUE(s.isEmpty());
|
|
}
|
|
|
|
TEST(Stream, spanEquality)
|
|
{
|
|
std::uint8_t buf[defaultBlockSize];
|
|
auto span = Stream::Span{.data = buf, .dataSize = defaultBlockSize};
|
|
auto span2 = span;
|
|
EXPECT_TRUE(span == span2);
|
|
EXPECT_FALSE(span != span2);
|
|
|
|
span2.data = &buf[1];
|
|
EXPECT_FALSE(span == span2);
|
|
EXPECT_TRUE(span != span2);
|
|
|
|
span2 = span;
|
|
span2.dataSize = defaultBlockSize - 1;
|
|
EXPECT_FALSE(span == span2);
|
|
EXPECT_TRUE(span != span2);
|
|
}
|
|
|
|
TEST(Proxy, Write)
|
|
{
|
|
auto mock = std::make_shared<MockStream>();
|
|
auto proxy = ::audio::StreamProxy(std::static_pointer_cast<::audio::AbstractStream>(mock));
|
|
::audio::AbstractStream::Span span{.data = reinterpret_cast<uint8_t *>(0xdeadbeef), .dataSize = 0xc00f33b4d};
|
|
|
|
EXPECT_CALL(*mock, push(span)).Times(1).WillOnce(Return(true));
|
|
EXPECT_CALL(*mock, push(nullptr, 128)).WillOnce(Return(false));
|
|
EXPECT_CALL(*mock, push()).WillOnce(Return(true));
|
|
|
|
EXPECT_TRUE(proxy.push(span));
|
|
EXPECT_FALSE(proxy.push(nullptr, 128));
|
|
EXPECT_TRUE(proxy.push());
|
|
|
|
EXPECT_CALL(*mock, reserve).Times(1);
|
|
EXPECT_CALL(*mock, commit).Times(1);
|
|
EXPECT_CALL(*mock, release).Times(1);
|
|
|
|
proxy.reserve(span);
|
|
proxy.commit();
|
|
proxy.release();
|
|
}
|
|
|
|
TEST(Proxy, Read)
|
|
{
|
|
auto mock = std::make_shared<MockStream>();
|
|
auto proxy = ::audio::StreamProxy(std::static_pointer_cast<::audio::AbstractStream>(mock));
|
|
::audio::AbstractStream::Span span{.data = reinterpret_cast<uint8_t *>(0xdeadbeef), .dataSize = 0xc00f33b4d};
|
|
|
|
EXPECT_CALL(*mock, pop(span)).Times(1).WillOnce(Return(true));
|
|
EXPECT_TRUE(proxy.pop(span));
|
|
|
|
EXPECT_CALL(*mock, peek(span)).Times(2).WillOnce(Return(true)).WillOnce(Return(false));
|
|
EXPECT_CALL(*mock, consume());
|
|
EXPECT_CALL(*mock, unpeek());
|
|
|
|
EXPECT_TRUE(proxy.peek(span));
|
|
EXPECT_FALSE(proxy.peek(span));
|
|
|
|
proxy.consume();
|
|
proxy.unpeek();
|
|
}
|
|
|
|
TEST(Proxy, Misc)
|
|
{
|
|
auto mock = std::make_shared<MockStream>();
|
|
auto proxy = ::audio::StreamProxy(std::static_pointer_cast<::audio::AbstractStream>(mock));
|
|
|
|
EXPECT_CALL(*mock, reset).Times(1);
|
|
EXPECT_CALL(*mock, isEmpty).Times(1).WillOnce(Return(true));
|
|
EXPECT_CALL(*mock, isFull).Times(1).WillOnce(Return(false));
|
|
|
|
proxy.reset();
|
|
EXPECT_TRUE(proxy.isEmpty());
|
|
EXPECT_FALSE(proxy.isFull());
|
|
}
|
|
|
|
TEST(Factory, BlockSizeConstraints)
|
|
{
|
|
testing::audio::MockSink mockSink;
|
|
testing::audio::MockSource mockSource;
|
|
::audio::StreamFactory factory(2ms);
|
|
|
|
EXPECT_CALL(mockSink, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{.blockSizeConstraint = 512U}));
|
|
EXPECT_CALL(mockSource, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{}));
|
|
|
|
auto stream = factory.makeStream(mockSource, mockSink, format);
|
|
|
|
EXPECT_EQ(stream->getOutputTraits().blockSize, 512U);
|
|
EXPECT_EQ(stream->getInputTraits().blockSize, 512U);
|
|
|
|
EXPECT_CALL(mockSink, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{.blockSizeConstraint = 512U}));
|
|
EXPECT_CALL(mockSource, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{.blockSizeConstraint = 512U}));
|
|
|
|
stream = factory.makeStream(mockSource, mockSink, format);
|
|
|
|
EXPECT_EQ(stream->getOutputTraits().blockSize, 512U);
|
|
EXPECT_EQ(stream->getInputTraits().blockSize, 512U);
|
|
}
|
|
|
|
TEST(Factory, BlockSizeErrors)
|
|
{
|
|
testing::audio::MockSink mockSink;
|
|
testing::audio::MockSource mockSource;
|
|
::audio::StreamFactory factory(2ms);
|
|
|
|
EXPECT_CALL(mockSource, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{.blockSizeConstraint = 128U}));
|
|
EXPECT_CALL(mockSink, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{.blockSizeConstraint = 300U}));
|
|
EXPECT_THROW(factory.makeStream(mockSource, mockSink, format), std::invalid_argument);
|
|
|
|
EXPECT_CALL(mockSource, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{.blockSizeConstraint = 128U}));
|
|
EXPECT_CALL(mockSink, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{.blockSizeConstraint = 0}));
|
|
EXPECT_THROW(factory.makeStream(mockSource, mockSink, format), std::invalid_argument);
|
|
}
|
|
|
|
TEST(Factory, TimeContraintsError)
|
|
{
|
|
testing::audio::MockSink mockSink;
|
|
testing::audio::MockSource mockSource;
|
|
::audio::StreamFactory factory;
|
|
|
|
EXPECT_CALL(mockSource, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{}));
|
|
EXPECT_CALL(mockSink, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{}));
|
|
|
|
EXPECT_THROW(factory.makeStream(mockSource, mockSink, format), std::invalid_argument);
|
|
}
|
|
|
|
TEST(Factory, NoSourceFormat)
|
|
{
|
|
testing::audio::MockSink mockSink;
|
|
testing::audio::MockSource mockSource;
|
|
::audio::StreamFactory factory;
|
|
|
|
EXPECT_CALL(mockSource, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{}));
|
|
EXPECT_CALL(mockSink, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{}));
|
|
EXPECT_THROW(factory.makeStream(mockSource, mockSink, ::audio::nullFormat), std::invalid_argument);
|
|
}
|
|
|
|
TEST(Factory, TimeConstraints)
|
|
{
|
|
testing::audio::MockSink mockSink;
|
|
testing::audio::MockSource mockSource;
|
|
::audio::StreamFactory factory(10ms);
|
|
|
|
EXPECT_CALL(mockSource, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{}));
|
|
EXPECT_CALL(mockSink, getTraits)
|
|
.WillRepeatedly(Return(::audio::Endpoint::Traits{.blockSizeConstraint = 512U, .timeConstraint = 10ms}));
|
|
|
|
auto stream = factory.makeStream(mockSource, mockSink, ::audio::AudioFormat(44100, 16, 2));
|
|
|
|
EXPECT_EQ(stream->getBlockCount(), defaultBuffering * 4);
|
|
EXPECT_EQ(stream->getOutputTraits().blockSize, 512);
|
|
}
|
|
|
|
TEST(Factory, TimeBlockConstraints)
|
|
{
|
|
testing::audio::MockSink mockSink;
|
|
testing::audio::MockSource mockSource;
|
|
::audio::StreamFactory factory(2ms);
|
|
|
|
EXPECT_CALL(mockSource, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{}));
|
|
EXPECT_CALL(mockSink, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{.blockSizeConstraint = 60U}));
|
|
|
|
auto stream = factory.makeStream(mockSource, mockSink, ::audio::AudioFormat(8000, 16, 1));
|
|
|
|
EXPECT_EQ(stream->getBlockCount(), defaultBuffering);
|
|
EXPECT_EQ(stream->getOutputTraits().blockSize, 60);
|
|
}
|
|
|
|
TEST(Factory, NoConstraints)
|
|
{
|
|
testing::audio::MockSink mockSink;
|
|
testing::audio::MockSource mockSource;
|
|
::audio::StreamFactory factory(2ms);
|
|
|
|
EXPECT_CALL(mockSource, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{}));
|
|
EXPECT_CALL(mockSink, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{}));
|
|
|
|
auto stream = factory.makeStream(mockSource, mockSink, ::audio::AudioFormat(16000, 16, 1));
|
|
|
|
EXPECT_EQ(stream->getBlockCount(), defaultBuffering);
|
|
EXPECT_EQ(stream->getOutputTraits().blockSize, 64);
|
|
}
|
|
|
|
TEST(Factory, TranscodingStreamSinkTraits)
|
|
{
|
|
testing::audio::MockSink mockSink;
|
|
testing::audio::MockSource mockSource;
|
|
::audio::StreamFactory factory(2ms);
|
|
auto format = ::audio::AudioFormat(8000, 16, 1);
|
|
|
|
EXPECT_CALL(mockSource, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{}));
|
|
EXPECT_CALL(mockSink, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{.blockSizeConstraint = 60U}));
|
|
|
|
auto stream = factory.makeStream(mockSource, mockSink, format);
|
|
|
|
EXPECT_EQ(stream->getBlockCount(), defaultBuffering);
|
|
EXPECT_EQ(stream->getOutputTraits().blockSize, 60);
|
|
|
|
auto decimatorTransform = std::make_shared<::audio::transcode::BasicDecimator<std::uint16_t, 1, 2>>();
|
|
auto transcodingStream = factory.makeInputTranscodingStream(
|
|
mockSource, mockSink, format, std::static_pointer_cast<::audio::transcode::Transform>(decimatorTransform));
|
|
|
|
EXPECT_EQ(transcodingStream->getInputTraits().blockSize, 120);
|
|
EXPECT_EQ(transcodingStream->getOutputTraits().blockSize, 60);
|
|
}
|
|
|
|
TEST(Factory, TranscodingStreamSourceTraits)
|
|
{
|
|
testing::audio::MockSink mockSink;
|
|
testing::audio::MockSource mockSource;
|
|
::audio::StreamFactory factory(2ms);
|
|
auto format = ::audio::AudioFormat(8000, 16, 1);
|
|
|
|
EXPECT_CALL(mockSource, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{.blockSizeConstraint = 60U}));
|
|
EXPECT_CALL(mockSink, getTraits).WillRepeatedly(Return(::audio::Endpoint::Traits{}));
|
|
|
|
auto stream = factory.makeStream(mockSource, mockSink, format);
|
|
|
|
EXPECT_EQ(stream->getBlockCount(), defaultBuffering);
|
|
EXPECT_EQ(stream->getOutputTraits().blockSize, 60);
|
|
|
|
auto decimatorTransform = std::make_shared<::audio::transcode::BasicDecimator<std::uint16_t, 1, 2>>();
|
|
auto transcodingStream = factory.makeInputTranscodingStream(
|
|
mockSource, mockSink, format, std::static_pointer_cast<::audio::transcode::Transform>(decimatorTransform));
|
|
|
|
EXPECT_EQ(transcodingStream->getInputTraits().blockSize, 60);
|
|
EXPECT_EQ(transcodingStream->getOutputTraits().blockSize, 30);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|