// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "SAIAudioDevice.hpp"
using namespace bsp;
SAIAudioDevice::SAIAudioDevice(AudioDevice::audioCallback_t callback,
I2S_Type *base,
sai_edma_handle_t *rxHandle,
sai_edma_handle_t *txHandle)
: AudioDevice(callback), _base(base), rx(rxHandle), tx(txHandle)
{}
void SAIAudioDevice::initiateRxTransfer()
{
audio::Stream::Span dataSpan;
Source::_stream->reserve(dataSpan);
auto xfer = sai_transfer_t{.data = dataSpan.data, .dataSize = dataSpan.dataSize};
SAI_TransferReceiveEDMA(_base, rx, &xfer);
}
void SAIAudioDevice::initiateTxTransfer()
{
auto nullSpan = Sink::_stream->getNullSpan();
auto xfer = sai_transfer_t{.data = nullSpan.data, .dataSize = nullSpan.dataSize};
SAI_TransferSendEDMA(_base, tx, &xfer);
}
void SAIAudioDevice::onDataSend()
{
audio::Stream::Span dataSpan;
if (!txEnabled || !isSinkConnected()) {
return;
}
/// pop previous read and peek next
Sink::_stream->consume();
Sink::_stream->peek(dataSpan);
sai_transfer_t xfer{.data = dataSpan.data, .dataSize = dataSpan.dataSize};
SAI_TransferSendEDMA(_base, tx, &xfer);
}
void SAIAudioDevice::onDataReceive()
{
audio::Stream::Span dataSpan;
if (!rxEnabled || !isSourceConnected()) {
return;
}
/// reserve space for the next read commiting previously reserved block before
Source::_stream->commit();
Source::_stream->reserve(dataSpan);
sai_transfer_t xfer{.data = dataSpan.data, .dataSize = dataSpan.dataSize};
SAI_TransferReceiveEDMA(_base, rx, &xfer);
}
void SAIAudioDevice::enableInput()
{
if (!isSourceConnected()) {
LOG_FATAL("No output stream connected!");
return;
}
rxEnabled = true;
/// initiate first read
initiateRxTransfer();
}
void SAIAudioDevice::enableOutput()
{
if (!isSinkConnected()) {
LOG_FATAL("No input stream connected!");
return;
}
txEnabled = true;
/// initiate first write
initiateTxTransfer();
}
void SAIAudioDevice::disableInput()
{
rxEnabled = false;
}
void SAIAudioDevice::disableOutput()
{
txEnabled = false;
}