mirror of
https://github.com/mudita/MuditaOS.git
synced 2026-06-27 09:47:18 -04:00
Due to an error in the stream's block reservation, when the stream was full, SAI was trying to read data to an unitialized data span randomly disabling audio channel. Fix the problem by overwriting data after the peek position, always returning valid data span. Signed-off-by: Marcin Smoczyński <smoczynski.marcin@gmail.com>
214 lines
5.7 KiB
C++
214 lines
5.7 KiB
C++
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
|
|
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <Audio/Stream.hpp>
|
|
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
|
|
constexpr std::size_t defaultBlockSize = 64U;
|
|
constexpr std::size_t defaultBuffering = 4U;
|
|
|
|
using namespace audio;
|
|
|
|
static std::uint8_t testData[defaultBuffering][defaultBlockSize];
|
|
static std::uint8_t emptyBlock[defaultBlockSize];
|
|
|
|
#include <iostream>
|
|
|
|
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(a, defaultBlockSize, bufferingSize);
|
|
|
|
EXPECT_EQ(s.getBlockCount(), bufferingSize);
|
|
EXPECT_EQ(s.getBlockSize(), defaultBlockSize);
|
|
EXPECT_EQ(s.getUsedBlockCount(), 0);
|
|
}
|
|
|
|
TEST(Stream, Push)
|
|
{
|
|
StandardStreamAllocator a;
|
|
Stream s(a, defaultBlockSize);
|
|
auto block = testData[0];
|
|
|
|
EXPECT_TRUE(s.push(block, defaultBlockSize));
|
|
EXPECT_TRUE(s.push(block, defaultBlockSize));
|
|
EXPECT_TRUE(s.push(block, defaultBlockSize));
|
|
EXPECT_TRUE(s.push(block, defaultBlockSize));
|
|
EXPECT_EQ(s.getUsedBlockCount(), 4);
|
|
EXPECT_FALSE(s.push(block, defaultBlockSize));
|
|
}
|
|
|
|
TEST(Stream, PushPop)
|
|
{
|
|
StandardStreamAllocator a;
|
|
Stream s(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(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(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(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);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|