Files
MuditaOS/module-audio/Audio/decoder/DecoderWorker.cpp
Marcin Smoczyński 871b250d86 [EGD-4534] Change audio data path synchronization
Refactor audio data path to fix several synchronization issues and
excessive copy operations on large memory blocks. Introduce
audio::Stream data structure to allow connecting audio source and sink
with a zero-copy capability.

Introduce system mechanisms:
 - critical section guard lock needed for stream synchronization
 - non-cacheable memory allocator to allocate memory for DMA safe
   buffers

Update the Googletest CMake template to match the capabilities of the
Catch2 template.

Signed-off-by: Marcin Smoczyński <smoczynski.marcin@gmail.com>
Signed-off-by: Hubert Chrzaniuk <hubert.chrzaniuk@mudita.com>
2020-12-17 12:20:40 +01:00

77 lines
2.4 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 "DecoderWorker.hpp"
#include "Audio/decoder/Decoder.hpp"
audio::DecoderWorker::DecoderWorker(Stream &audioStreamOut, Decoder *decoder, EndOfFileCallback endOfFileCallback)
: sys::Worker(DecoderWorker::workerName, DecoderWorker::workerPriority), audioStreamOut(audioStreamOut),
decoder(decoder), endOfFileCallback(endOfFileCallback),
bufferSize(audioStreamOut.getBlockSize() / sizeof(BufferInternalType))
{}
audio::DecoderWorker::~DecoderWorker()
{
audioStreamOut.unregisterListeners(queueListener.get());
}
auto audio::DecoderWorker::init(std::list<sys::WorkerQueueInfo> queues) -> bool
{
std::list<sys::WorkerQueueInfo> list{
{listenerQueueName, StreamQueuedEventsListener::listenerElementSize, listenerQueueCapacity}};
auto isSuccessful = Worker::init(list);
queueListener = std::make_unique<StreamQueuedEventsListener>(getQueueByName(listenerQueueName));
if (!queueListener) {
return false;
}
audioStreamOut.registerListener(queueListener.get());
decoderBuffer = std::make_unique<BufferInternalType[]>(bufferSize);
if (!decoderBuffer) {
return false;
}
return isSuccessful;
}
bool audio::DecoderWorker::handleMessage(uint32_t queueID)
{
auto queue = queues[queueID];
if (queue->GetQueueName() == listenerQueueName && queueListener) {
auto event = queueListener->getEvent();
switch (event.second) {
case Stream::Event::StreamOverflow:
break;
case Stream::Event::StreamUnderFlow:
break;
case Stream::Event::NoEvent:
break;
case Stream::Event::StreamFull:
break;
case Stream::Event::StreamHalfUsed:
[[fallthrough]];
case Stream::Event::StreamEmpty:
auto samplesRead = 0;
while (!audioStreamOut.isFull()) {
samplesRead = decoder->decode(bufferSize, decoderBuffer.get());
if (samplesRead == 0) {
endOfFileCallback();
break;
}
if (!audioStreamOut.push(decoderBuffer.get(), samplesRead * sizeof(BufferInternalType))) {
LOG_FATAL("Decoder failed to push to stream.");
break;
}
}
}
}
return true;
}