M module-audio/Audio/Audio.cpp => module-audio/Audio/Audio.cpp +1 -3
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "Audio.hpp"
@@ 90,8 90,6 @@ namespace audio
break;
}
currentOperation = std::move(ret);
- currentOperation->SetDataStreams(&dataStreamOut, &dataStreamIn);
-
UpdateProfiles();
}
catch (const AudioInitException &audioException) {
M module-audio/Audio/Audio.hpp => module-audio/Audio/Audio.hpp +8 -20
@@ 1,19 1,18 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
-#include <memory>
-#include <optional>
-#include <functional>
-#include <bitset>
-
#include <service-bluetooth/ServiceBluetoothCommon.hpp>
#include "AudioCommon.hpp"
-#include "Stream.hpp"
-#include "Operation/Operation.hpp"
#include "decoder/Decoder.hpp"
+#include "Operation/Operation.hpp"
+
+#include <bitset>
+#include <functional>
+#include <memory>
+#include <optional>
namespace audio
{
@@ 96,17 95,14 @@ namespace audio
const audio::PlaybackType &playbackType = audio::PlaybackType::None);
virtual audio::RetCode Start();
-
virtual audio::RetCode Stop();
-
virtual audio::RetCode Pause();
-
virtual audio::RetCode Resume();
-
virtual audio::RetCode Mute();
private:
void UpdateProfiles();
+
AudioSinkState audioSinkState;
std::shared_ptr<BluetoothStreamData> btData;
@@ 115,14 111,6 @@ namespace audio
std::unique_ptr<Operation> currentOperation;
AudioServiceMessage::Callback serviceCallback;
-
- // for efficiency multiple of 24 and 32 (max audio samples size)
- static constexpr auto defaultAudioStreamBlockSize = 2048;
- StandardStreamAllocator allocatorOut;
- Stream dataStreamOut{allocatorOut, defaultAudioStreamBlockSize};
-
- StandardStreamAllocator allocatorIn;
- Stream dataStreamIn{allocatorIn, defaultAudioStreamBlockSize};
};
} // namespace audio
M module-audio/Audio/BluetoothProxyAudio.cpp => module-audio/Audio/BluetoothProxyAudio.cpp +2 -2
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "BluetoothProxyAudio.hpp"
@@ 10,7 10,7 @@ namespace bsp
audio::Stream &dataStreamOut,
audio::Stream &dataStreamIn,
AudioDevice::Format &format)
- : AudioDevice(nullptr), dataStreamOut(dataStreamOut), dataStreamIn(dataStreamIn), serviceCallback(callback),
+ : dataStreamOut(dataStreamOut), dataStreamIn(dataStreamIn), serviceCallback(std::move(callback)),
audioFormat(format)
{
LOG_DEBUG("BluetoothProxyAudio created.");
M module-audio/Audio/Endpoint.cpp => module-audio/Audio/Endpoint.cpp +10 -1
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "Endpoint.hpp"
@@ 32,6 32,15 @@ bool Endpoint::isConnected() const noexcept
return _stream != nullptr;
}
+Sink::Sink(const Capabilities &caps) : Endpoint(caps)
+{}
+
+Source::Source(const Capabilities &caps) : Endpoint(caps)
+{}
+
+IOProxy::IOProxy(const Capabilities &sourceCaps, const Capabilities &sinkCaps) : Source(sourceCaps), Sink(sinkCaps)
+{}
+
StreamConnection::StreamConnection(Source *source, Sink *sink, Stream *stream)
: _sink(sink), _source(source), _stream(stream)
{
M module-audio/Audio/Endpoint.hpp => module-audio/Audio/Endpoint.hpp +15 -3
@@ 1,10 1,12 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
#include "Stream.hpp"
+#include <cstdint>
+
namespace audio
{
class Endpoint
@@ 13,7 15,8 @@ namespace audio
struct Capabilities
{
bool usesDMA = false;
- std::size_t maxBlockSize = 0;
+ std::size_t minBlockSize = 1;
+ std::size_t maxBlockSize = SIZE_MAX;
};
Endpoint() = default;
@@ 33,6 36,9 @@ namespace audio
class Sink : public Endpoint
{
public:
+ Sink() = default;
+ explicit Sink(const Capabilities &caps);
+
virtual void onDataSend() = 0;
virtual void enableOutput() = 0;
virtual void disableOutput() = 0;
@@ 41,14 47,20 @@ namespace audio
class Source : public Endpoint
{
public:
+ Source() = default;
+ explicit Source(const Capabilities &caps);
+
virtual void onDataReceive() = 0;
virtual void enableInput() = 0;
virtual void disableInput() = 0;
};
- class IOProxy : public Sink, public Source
+ class IOProxy : public Source, public Sink
{
public:
+ IOProxy() = default;
+ IOProxy(const Capabilities &sourceCaps, const Capabilities &sinkCaps);
+
inline bool isSinkConnected() const noexcept
{
return Sink::isConnected();
M module-audio/Audio/Operation/Operation.cpp => module-audio/Audio/Operation/Operation.cpp +4 -9
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "Operation.hpp"
@@ 93,14 93,9 @@ namespace audio
supportedProfiles.emplace_back(Profile::Create(profile, nullptr, volume, gain), isAvailable);
}
- std::optional<std::unique_ptr<bsp::AudioDevice>> Operation::CreateDevice(bsp::AudioDevice::Type type,
- bsp::AudioDevice::audioCallback_t callback)
+
+ std::optional<std::unique_ptr<bsp::AudioDevice>> Operation::CreateDevice(bsp::AudioDevice::Type type)
{
- if (type == bsp::AudioDevice::Type::Bluetooth) {
- auto audioFormat = currentProfile->GetAudioFormat();
- return std::make_unique<bsp::BluetoothProxyAudio>(
- serviceCallback, *dataStreamOut, *dataStreamIn, audioFormat);
- }
- return bsp::AudioDevice::Create(type, callback).value_or(nullptr);
+ return bsp::AudioDevice::Create(type).value_or(nullptr);
}
} // namespace audio
M module-audio/Audio/Operation/Operation.hpp => module-audio/Audio/Operation/Operation.hpp +9 -20
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 8,7 8,6 @@
#include <functional>
#include <Audio/AudioCommon.hpp>
-#include <Audio/Stream.hpp>
#include <Audio/encoder/Encoder.hpp>
#include <Audio/Profiles/Profile.hpp>
@@ 60,13 59,13 @@ namespace audio
const audio::PlaybackType &operations = audio::PlaybackType::None,
AudioServiceMessage::Callback callback = nullptr);
- virtual audio::RetCode Start(audio::Token token) = 0;
- virtual audio::RetCode Stop() = 0;
- virtual audio::RetCode Pause() = 0;
- virtual audio::RetCode Resume() = 0;
- virtual audio::RetCode SendEvent(std::shared_ptr<Event> evt) = 0;
- virtual audio::RetCode SetOutputVolume(float vol) = 0;
- virtual audio::RetCode SetInputGain(float gain) = 0;
+ virtual audio::RetCode Start(audio::Token token) = 0;
+ virtual audio::RetCode Stop() = 0;
+ virtual audio::RetCode Pause() = 0;
+ virtual audio::RetCode Resume() = 0;
+ virtual audio::RetCode SendEvent(std::shared_ptr<Event> evt) = 0;
+ virtual audio::RetCode SetOutputVolume(float vol) = 0;
+ virtual audio::RetCode SetInputGain(float gain) = 0;
virtual Position GetPosition() = 0;
@@ 112,12 111,6 @@ namespace audio
audio::RetCode SwitchToPriorityProfile();
- void SetDataStreams(Stream *dStreamOut, Stream *dStreamIn)
- {
- dataStreamOut = dStreamOut;
- dataStreamIn = dStreamIn;
- }
-
protected:
struct SupportedProfile
{
@@ 129,9 122,6 @@ namespace audio
bool isAvailable;
};
- Stream *dataStreamOut = nullptr;
- Stream *dataStreamIn = nullptr;
-
std::shared_ptr<Profile> currentProfile;
std::unique_ptr<bsp::AudioDevice> audioDevice;
std::vector<SupportedProfile> supportedProfiles;
@@ 152,8 142,7 @@ namespace audio
virtual audio::RetCode SwitchProfile(const Profile::Type type) = 0;
std::shared_ptr<Profile> GetProfile(const Profile::Type type);
- std::optional<std::unique_ptr<bsp::AudioDevice>> CreateDevice(bsp::AudioDevice::Type type,
- bsp::AudioDevice::audioCallback_t callback);
+ std::optional<std::unique_ptr<bsp::AudioDevice>> CreateDevice(bsp::AudioDevice::Type type);
};
} // namespace audio
M module-audio/Audio/Operation/PlaybackOperation.cpp => module-audio/Audio/Operation/PlaybackOperation.cpp +11 -3
@@ 1,10 1,11 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "PlaybackOperation.hpp"
#include "Audio/decoder/Decoder.hpp"
#include "Audio/Profiles/Profile.hpp"
+#include "Audio/StreamFactory.hpp"
#include "Audio/AudioCommon.hpp"
@@ 55,8 56,12 @@ namespace audio
return RetCode::InvokedInIncorrectState;
}
+ // create stream
+ StreamFactory streamFactory(playbackCapabilities);
+ dataStreamOut = streamFactory.makeStream(*dec.get(), *audioDevice.get());
+
// create audio connection
- outputConnection = std::make_unique<StreamConnection>(dec.get(), audioDevice.get(), dataStreamOut);
+ outputConnection = std::make_unique<StreamConnection>(dec.get(), audioDevice.get(), dataStreamOut.get());
// decoder worker soft start - must be called after connection setup
dec->startDecodingWorker(endOfFileCallback);
@@ 82,6 87,7 @@ namespace audio
// stop playback by destroying audio connection
outputConnection.reset();
dec->stopDecodingWorker();
+ dataStreamOut.reset();
return GetDeviceError(audioDevice->Stop());
}
@@ 154,8 160,10 @@ namespace audio
/// profile change - (re)create output device; stop audio first by
/// killing audio connection
outputConnection.reset();
+ dec->stopDecodingWorker();
audioDevice.reset();
- audioDevice = CreateDevice(newProfile->GetAudioDeviceType(), audioCallback).value_or(nullptr);
+ dataStreamOut.reset();
+ audioDevice = CreateDevice(newProfile->GetAudioDeviceType()).value_or(nullptr);
if (audioDevice == nullptr) {
LOG_ERROR("Error creating AudioDevice");
return RetCode::Failed;
M module-audio/Audio/Operation/PlaybackOperation.hpp => module-audio/Audio/Operation/PlaybackOperation.hpp +8 -2
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 39,9 39,15 @@ namespace audio
Position GetPosition() final;
private:
+ static constexpr auto minimumBlockSize = 256U;
+ static constexpr auto maximumBlockSize = 2048U;
+ static constexpr Endpoint::Capabilities playbackCapabilities{.minBlockSize = minimumBlockSize,
+ .maxBlockSize = maximumBlockSize};
+
+ std::unique_ptr<Stream> dataStreamOut;
std::unique_ptr<Decoder> dec;
std::unique_ptr<Tags> tags;
- std::unique_ptr<StreamConnection> outputConnection = nullptr;
+ std::unique_ptr<StreamConnection> outputConnection;
DecoderWorker::EndOfFileCallback endOfFileCallback;
};
M module-audio/Audio/Operation/RecorderOperation.cpp => module-audio/Audio/Operation/RecorderOperation.cpp +5 -5
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "RecorderOperation.hpp"
@@ 37,7 37,7 @@ namespace audio
// during sf tests on hardware
#endif
if (ret == 0) {
- state = State::Idle;
+ state = State::Idle;
const auto req = AudioServiceMessage::FileSystemNoSpace(operationToken);
serviceCallback(&req);
}
@@ 82,7 82,7 @@ namespace audio
return RetCode::InvokedInIncorrectState;
}
operationToken = token;
- state = State::Active;
+ state = State::Active;
if (audioDevice->IsFormatSupported(currentProfile->GetAudioFormat())) {
auto ret = audioDevice->Start(currentProfile->GetAudioFormat());
@@ 122,7 122,7 @@ namespace audio
return RetCode::InvokedInIncorrectState;
}
- state = State::Active;
+ state = State::Active;
auto ret = audioDevice->Start(currentProfile->GetAudioFormat());
return GetDeviceError(ret);
}
@@ 157,7 157,7 @@ namespace audio
return RetCode::UnsupportedProfile;
}
- audioDevice = CreateDevice(currentProfile->GetAudioDeviceType(), audioCallback).value_or(nullptr);
+ audioDevice = CreateDevice(currentProfile->GetAudioDeviceType()).value_or(nullptr);
if (audioDevice == nullptr) {
LOG_ERROR("Error creating AudioDevice");
return RetCode::Failed;
M module-audio/Audio/Operation/RouterOperation.cpp => module-audio/Audio/Operation/RouterOperation.cpp +12 -6
@@ 1,10 1,11 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "RouterOperation.hpp"
#include <Audio/AudioCommon.hpp>
#include <Audio/Profiles/Profile.hpp>
+#include <Audio/StreamFactory.hpp>
#include <bsp_audio.hpp>
#include <log/log.hpp>
@@ 69,11 70,16 @@ namespace audio
return GetDeviceError(ret);
}
+ // create streams
+ StreamFactory streamFactory(routerCapabilities);
+ dataStreamIn = streamFactory.makeStream(*audioDevice.get(), *audioDeviceCellular.get());
+ dataStreamOut = streamFactory.makeStream(*audioDevice.get(), *audioDeviceCellular.get());
+
// create audio connections
inputConnection =
- std::make_unique<audio::StreamConnection>(audioDeviceCellular.get(), audioDevice.get(), dataStreamIn);
- outputConnection =
- std::make_unique<audio::StreamConnection>(audioDevice.get(), audioDeviceCellular.get(), dataStreamOut);
+ std::make_unique<audio::StreamConnection>(audioDeviceCellular.get(), audioDevice.get(), dataStreamIn.get());
+ outputConnection = std::make_unique<audio::StreamConnection>(
+ audioDevice.get(), audioDeviceCellular.get(), dataStreamOut.get());
// enable audio connections
inputConnection->enable();
@@ 174,13 180,13 @@ namespace audio
Stop();
}
- audioDevice = CreateDevice(newProfile->GetAudioDeviceType(), nullptr).value_or(nullptr);
+ audioDevice = CreateDevice(newProfile->GetAudioDeviceType()).value_or(nullptr);
if (audioDevice == nullptr) {
LOG_ERROR("Error creating AudioDevice");
return RetCode::Failed;
}
- audioDeviceCellular = CreateDevice(bsp::AudioDevice::Type::Cellular, nullptr).value_or(nullptr);
+ audioDeviceCellular = CreateDevice(bsp::AudioDevice::Type::Cellular).value_or(nullptr);
if (audioDeviceCellular == nullptr) {
LOG_ERROR("Error creating AudioDeviceCellular");
return RetCode::Failed;
M module-audio/Audio/Operation/RouterOperation.hpp => module-audio/Audio/Operation/RouterOperation.hpp +8 -1
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 43,9 43,16 @@ namespace audio
Position GetPosition() final;
private:
+ static constexpr auto minimumBlockSize = 64U;
+ static constexpr auto maximumBlockSize = 64U;
+ static constexpr Endpoint::Capabilities routerCapabilities{.minBlockSize = minimumBlockSize,
+ .maxBlockSize = maximumBlockSize};
+
bool Mute(bool enable);
bool muteEnable = false;
+ std::unique_ptr<Stream> dataStreamOut;
+ std::unique_ptr<Stream> dataStreamIn;
std::unique_ptr<Encoder> enc;
std::unique_ptr<bsp::AudioDevice> audioDeviceCellular;
std::unique_ptr<StreamConnection> outputConnection;
A module-audio/Audio/StreamFactory.cpp => module-audio/Audio/StreamFactory.cpp +55 -0
@@ 0,0 1,55 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "StreamFactory.hpp"
+#include "Endpoint.hpp"
+
+#include <math/Math.hpp>
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+#include <cassert>
+
+using namespace audio;
+
+StreamFactory::StreamFactory(Endpoint::Capabilities factoryCaps) : caps(std::move(factoryCaps))
+{}
+
+auto StreamFactory::makeStream(const Source &source, const Sink &sink) -> std::unique_ptr<Stream>
+{
+ auto negotiatedCaps = negotiateCaps({source, sink});
+
+ return std::make_unique<Stream>(getAllocator(negotiatedCaps.usesDMA), negotiatedCaps.maxBlockSize);
+}
+
+auto StreamFactory::negotiateCaps(std::vector<std::reference_wrapper<const Endpoint>> v) -> Endpoint::Capabilities
+{
+ auto negotiatedCaps = caps;
+
+ for (const auto &endpointRef : v) {
+ auto &endpointCaps = endpointRef.get().getCapabilities();
+
+ negotiatedCaps.maxBlockSize = std::min(negotiatedCaps.maxBlockSize, endpointCaps.maxBlockSize);
+ negotiatedCaps.minBlockSize = std::max(negotiatedCaps.minBlockSize, endpointCaps.minBlockSize);
+ negotiatedCaps.usesDMA = negotiatedCaps.usesDMA || endpointCaps.usesDMA;
+ }
+
+ negotiatedCaps.minBlockSize = binary::ceilPowerOfTwo(negotiatedCaps.minBlockSize);
+ negotiatedCaps.maxBlockSize = binary::floorPowerOfTwo(negotiatedCaps.maxBlockSize);
+
+ assert(negotiatedCaps.minBlockSize <= negotiatedCaps.maxBlockSize);
+
+ return negotiatedCaps;
+}
+
+auto StreamFactory::getAllocator(bool usesDMA) -> Stream::Allocator &
+{
+ if (usesDMA) {
+ return nonCacheableAlloc;
+ }
+ else {
+ return stdAlloc;
+ }
+}
A module-audio/Audio/StreamFactory.hpp => module-audio/Audio/StreamFactory.hpp +29 -0
@@ 0,0 1,29 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "Endpoint.hpp"
+
+#include <memory>
+#include <vector>
+
+namespace audio
+{
+
+ class StreamFactory
+ {
+ public:
+ explicit StreamFactory(Endpoint::Capabilities factoryCaps);
+ auto makeStream(const Source &source, const Sink &sink) -> std::unique_ptr<Stream>;
+
+ private:
+ auto negotiateCaps(std::vector<std::reference_wrapper<const Endpoint>> v) -> Endpoint::Capabilities;
+ auto getAllocator(bool usesDMA) -> Stream::Allocator &;
+
+ Endpoint::Capabilities caps;
+ StandardStreamAllocator stdAlloc;
+ NonCacheableStreamAllocator nonCacheableAlloc;
+ };
+
+} // namespace audio
M module-audio/Audio/decoder/Decoder.cpp => module-audio/Audio/decoder/Decoder.cpp +3 -2
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <cstdio>
@@ 16,7 16,8 @@ namespace audio
{
Decoder::Decoder(const char *fileName)
- : filePath(fileName), workerBuffer(std::make_unique<int16_t[]>(workerBufferSize)), tag(std::make_unique<Tags>())
+ : Source(Endpoint::Capabilities{.maxBlockSize = workerBufferSize * sizeof(int16_t)}), filePath(fileName),
+ workerBuffer(std::make_unique<int16_t[]>(workerBufferSize)), tag(std::make_unique<Tags>())
{
fd = std::fopen(fileName, "r");
M module-audio/Audio/decoder/Decoder.hpp => module-audio/Audio/decoder/Decoder.hpp +3 -2
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 115,7 115,8 @@ namespace audio
void convertmono2stereo(int16_t *pcm, uint32_t samplecount);
- const uint32_t workerBufferSize = 1024 * 8;
+ static constexpr auto workerBufferSize = 1024 * 8;
+ static constexpr Endpoint::Capabilities decoderCaps = {.usesDMA = false};
uint32_t sampleRate = 0;
uint32_t chanNumber = 0;
M module-audio/CMakeLists.txt => module-audio/CMakeLists.txt +1 -0
@@ 20,6 20,7 @@ set(SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/Audio/AudioCommon.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Audio/Endpoint.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Audio/Stream.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/Audio/StreamFactory.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Audio/StreamQueuedEventsListener.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Audio/BluetoothProxyAudio.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Audio/Operation/Operation.cpp"
M module-bsp/board/rt1051/bsp/audio/RT1051Audiocodec.cpp => module-bsp/board/rt1051/bsp/audio/RT1051Audiocodec.cpp +3 -3
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "RT1051Audiocodec.hpp"
@@ 25,8 25,8 @@ namespace bsp
sai_edma_handle_t RT1051Audiocodec::txHandle = {};
sai_edma_handle_t RT1051Audiocodec::rxHandle = {};
- RT1051Audiocodec::RT1051Audiocodec(bsp::AudioDevice::audioCallback_t callback)
- : SAIAudioDevice(callback, BOARD_AUDIOCODEC_SAIx, &rxHandle, &txHandle), saiInFormat{}, saiOutFormat{},
+ RT1051Audiocodec::RT1051Audiocodec()
+ : SAIAudioDevice(BOARD_AUDIOCODEC_SAIx, &rxHandle, &txHandle), saiInFormat{}, saiOutFormat{},
codecParams{}, codec{}
{
isInitialized = true;
M module-bsp/board/rt1051/bsp/audio/RT1051Audiocodec.hpp => module-bsp/board/rt1051/bsp/audio/RT1051Audiocodec.hpp +2 -2
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 34,7 34,7 @@ namespace bsp
friend void txAudioCodecCallback(I2S_Type *base, sai_edma_handle_t *handle, status_t status, void *userData);
friend void rxAudioCodecCallback(I2S_Type *base, sai_edma_handle_t *handle, status_t status, void *userData);
- RT1051Audiocodec(AudioDevice::audioCallback_t callback);
+ RT1051Audiocodec();
virtual ~RT1051Audiocodec();
AudioDevice::RetCode Start(const Format &format) override final;
M module-bsp/board/rt1051/bsp/audio/RT1051CellularAudio.cpp => module-bsp/board/rt1051/bsp/audio/RT1051CellularAudio.cpp +3 -4
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "RT1051CellularAudio.hpp"
@@ 18,9 18,8 @@ namespace bsp
sai_edma_handle_t RT1051CellularAudio::txHandle = {};
sai_edma_handle_t RT1051CellularAudio::rxHandle = {};
- RT1051CellularAudio::RT1051CellularAudio(bsp::AudioDevice::audioCallback_t callback)
- : SAIAudioDevice(callback, BOARD_CELLULAR_AUDIO_SAIx, &rxHandle, &txHandle), saiInFormat{},
- saiOutFormat{}, config{}
+ RT1051CellularAudio::RT1051CellularAudio()
+ : SAIAudioDevice(BOARD_CELLULAR_AUDIO_SAIx, &rxHandle, &txHandle), saiInFormat{}, saiOutFormat{}, config{}
{
isInitialized = true;
}
M module-bsp/board/rt1051/bsp/audio/RT1051CellularAudio.hpp => module-bsp/board/rt1051/bsp/audio/RT1051CellularAudio.hpp +2 -2
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#ifndef PUREPHONE_RT1051CELLULARAUDIO_HPP
@@ 30,7 30,7 @@ namespace bsp
friend void txCellularCallback(I2S_Type *base, sai_edma_handle_t *handle, status_t status, void *userData);
friend void rxCellularCallback(I2S_Type *base, sai_edma_handle_t *handle, status_t status, void *userData);
- RT1051CellularAudio(AudioDevice::audioCallback_t callback);
+ RT1051CellularAudio();
virtual ~RT1051CellularAudio();
AudioDevice::RetCode Start(const Format &format) override final;
M module-bsp/board/rt1051/bsp/audio/SAIAudioDevice.cpp => module-bsp/board/rt1051/bsp/audio/SAIAudioDevice.cpp +2 -5
@@ 5,11 5,8 @@
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)
+SAIAudioDevice::SAIAudioDevice(I2S_Type *base, sai_edma_handle_t *rxHandle, sai_edma_handle_t *txHandle)
+ : AudioDevice(saiCapabilities, saiCapabilities), _base(base), rx(rxHandle), tx(txHandle)
{}
void SAIAudioDevice::initiateRxTransfer()
M module-bsp/board/rt1051/bsp/audio/SAIAudioDevice.hpp => module-bsp/board/rt1051/bsp/audio/SAIAudioDevice.hpp +3 -4
@@ 13,10 13,7 @@ namespace bsp
class SAIAudioDevice : public bsp::AudioDevice
{
public:
- SAIAudioDevice(AudioDevice::audioCallback_t callback,
- I2S_Type *base,
- sai_edma_handle_t *rxHandle,
- sai_edma_handle_t *txHandle);
+ SAIAudioDevice(I2S_Type *base, sai_edma_handle_t *rxHandle, sai_edma_handle_t *txHandle);
void onDataSend() override;
void onDataReceive() override;
@@ 33,6 30,8 @@ namespace bsp
sai_edma_handle_t *tx = nullptr;
bool txEnabled = false;
bool rxEnabled = false;
+
+ static constexpr Capabilities saiCapabilities = {.usesDMA = true};
};
} // namespace bsp
M module-bsp/bsp/audio/bsp_audio.cpp => module-bsp/bsp/audio/bsp_audio.cpp +8 -24
@@ 5,22 5,16 @@
#include "board/rt1051/bsp/audio/RT1051Audiocodec.hpp"
#include "board/rt1051/bsp/audio/RT1051CellularAudio.hpp"
+#endif
+
#include <Audio/Stream.hpp>
#include <cassert>
-#elif defined(TARGET_Linux)
-#include "audio/linux_audiocodec.hpp"
-#include "audio/LinuxCellularAudio.hpp"
-#else
-#error "Unsupported target"
-#endif
-
namespace bsp
{
- std::optional<std::unique_ptr<AudioDevice>> AudioDevice::Create(bsp::AudioDevice::Type type,
- audioCallback_t callback)
+ std::optional<std::unique_ptr<AudioDevice>> AudioDevice::Create(bsp::AudioDevice::Type type)
{
std::unique_ptr<AudioDevice> inst;
@@ 28,33 22,23 @@ namespace bsp
case Type ::Audiocodec: {
#if defined(TARGET_RT1051)
- inst = std::make_unique<bsp::RT1051Audiocodec>(callback);
-#elif defined(TARGET_Linux)
- inst = std::make_unique<bsp::LinuxAudiocodec>(callback);
+ inst = std::make_unique<bsp::RT1051Audiocodec>();
#else
-#error "Unsupported target"
+ inst = nullptr;
#endif
} break;
case Type ::Bluetooth: {
-#if defined(TARGET_RT1051)
+ LOG_FATAL("Bluetooth audio is not yet supported");
inst = nullptr;
-
-#elif defined(TARGET_Linux)
-
-#else
-#error "Unsupported target"
-#endif
} break;
case Type::Cellular: {
#if defined(TARGET_RT1051)
- inst = std::make_unique<bsp::RT1051CellularAudio>(callback);
-#elif defined(TARGET_Linux)
- inst = std::make_unique<bsp::LinuxCellularAudio>(callback);
+ inst = std::make_unique<bsp::RT1051CellularAudio>();
#else
-#error "Unsupported target"
+ inst = nullptr;
#endif
} break;
}
M module-bsp/bsp/audio/bsp_audio.hpp => module-bsp/bsp/audio/bsp_audio.hpp +5 -35
@@ 67,39 67,15 @@ namespace bsp
OutputPath outputPath = OutputPath::None;
};
- /**
- * User defined callback.
- * It will be invoked when opened stream needs more frames to process( outputBuffer will be != NULL) or if
- * requested frames count are available to user( inputBuffer will be != NULL). From this callback you can safely
- * use file operations, system calls etc This is because audiostream callbacks are not invoked from IRQ context.
- *
- * If there is more data to process or read user should return:
- * 'AudiostreamCallbackContinue'
- * if there is no more data to process or read user should return:
- * 'AudiostreamCallbackComplete'
- * this will close stream and clean up all internally allocated resources.
- * In case of error return:
- * 'AudiostreamCallbackAbort'
- * this has the same effect as AudiostreamCallbackComplete.
- *
- * @param stream[in] - pointer to valid stream
- * @param inputBuffer[in] - pointer to buffer where user should copy PCM data
- * @param outputBuffer[out] - pointer to buffer containing valid PCM data
- * @param framesPerBuffer[in] - how many frames user should copy or read from buffer
- * @param userData[in] - user specified data
- * @return audiostream_callback_err_t
- */
- using audioCallback_t =
- std::function<int32_t(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer)>;
-
- explicit AudioDevice(audioCallback_t callback) : callback(callback)
+ AudioDevice() = default;
+ explicit AudioDevice(const audio::Endpoint::Capabilities &sourceCaps,
+ const audio::Endpoint::Capabilities &sinkCaps)
+ : IOProxy(sourceCaps, sinkCaps)
{}
- AudioDevice() = delete;
-
virtual ~AudioDevice() = default;
- static std::optional<std::unique_ptr<AudioDevice>> Create(Type type, audioCallback_t callback);
+ static std::optional<std::unique_ptr<AudioDevice>> Create(Type type);
virtual RetCode Start(const Format &format) = 0;
virtual RetCode Stop() = 0;
@@ 135,14 111,8 @@ namespace bsp
return currentFormat;
}
- audioCallback_t GetAudioCallback()
- {
- return callback;
- }
-
protected:
Format currentFormat;
- audioCallback_t callback = nullptr;
bool isInitialized = false;
};
M module-bsp/targets/Target_Linux.cmake => module-bsp/targets/Target_Linux.cmake +0 -3
@@ 14,9 14,6 @@ set(BOARD_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/board/linux/lpm/LinuxLPM.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/audio/linux_audiocodec.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/audio/LinuxCellularAudio.cpp"
-
"${CMAKE_CURRENT_SOURCE_DIR}/board/linux/bluetooth/Bluetooth.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/board/linux/usb_cdc/usb_cdc.cpp"
M module-utils/math/Math.hpp => module-utils/math/Math.hpp +39 -1
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 47,3 47,41 @@ namespace trigonometry
}
};
} // namespace trigonometry
+
+namespace binary
+{
+ constexpr static inline auto isPowerOfTwo(unsigned int x) -> bool
+ {
+ return x == 0 ? false : __builtin_popcount(x) == 1;
+ }
+
+ static inline auto floorPowerOfTwo(unsigned int x) -> unsigned int
+ {
+ constexpr auto xBitCount = sizeof(x) * 8;
+
+ if (x == 0) {
+ return 0;
+ }
+ else if (isPowerOfTwo(x)) {
+ return x;
+ }
+
+ return 1 << (xBitCount - __builtin_clz(x) - 1);
+ }
+
+ static inline auto ceilPowerOfTwo(unsigned int x) -> unsigned int
+ {
+ constexpr auto xBitCount = sizeof(x) * 8;
+ auto leadingZeroes = __builtin_clz(x);
+
+ if (leadingZeroes == 0 || x == 0) {
+ return 0;
+ }
+ else if (isPowerOfTwo(x)) {
+ return x;
+ }
+
+ return 1 << (xBitCount - leadingZeroes);
+ }
+
+} // namespace binary
M module-utils/test/test_math.cpp => module-utils/test/test_math.cpp +39 -1
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
@@ 7,7 7,10 @@
#include "math/Math.hpp"
+#include <climits>
+
using namespace trigonometry;
+using namespace binary;
TEST_CASE("Math")
{
@@ 47,4 50,39 @@ TEST_CASE("Math")
REQUIRE(OppositeSide::fromSine(std::sin(toRadians(60)), 6) == 5);
}
}
+
+ SECTION("Binary operations")
+ {
+ SECTION("Is number a power of two")
+ {
+ REQUIRE(isPowerOfTwo(0) == false);
+ REQUIRE(isPowerOfTwo(1) == true);
+ REQUIRE(isPowerOfTwo(2) == true);
+ REQUIRE(isPowerOfTwo(3) == false);
+ REQUIRE(isPowerOfTwo(64) == true);
+ REQUIRE(isPowerOfTwo(128) == true);
+ REQUIRE(isPowerOfTwo(64 + 128) == false);
+ }
+
+ SECTION("Find nearest power of two (floor)")
+ {
+ REQUIRE(floorPowerOfTwo(0) == 0);
+ REQUIRE(floorPowerOfTwo(1) == 1);
+ REQUIRE(floorPowerOfTwo(2) == 2);
+ REQUIRE(floorPowerOfTwo(3) == 2);
+ REQUIRE(floorPowerOfTwo(7) == 4);
+ REQUIRE(floorPowerOfTwo(0xffffffff) == 0x80000000);
+ }
+
+ SECTION("Find nearest power of two (ceil)")
+ {
+ REQUIRE(ceilPowerOfTwo(0) == 0);
+ REQUIRE(ceilPowerOfTwo(1) == 1);
+ REQUIRE(ceilPowerOfTwo(2) == 2);
+ REQUIRE(ceilPowerOfTwo(3) == 4);
+ REQUIRE(ceilPowerOfTwo(7) == 8);
+ REQUIRE(ceilPowerOfTwo(62) == 64);
+ REQUIRE(ceilPowerOfTwo(UINT_MAX) == 0);
+ }
+ }
}