From a3e512a89b698b4d8a8f8046521c327ab2eec147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Smoczy=C5=84ski?= Date: Tue, 4 May 2021 14:51:05 +0200 Subject: [PATCH] [EGD-6674] Change negotiation of audio block size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace faulty implementation which produced ambiguous results with one which is suited for both phone calls and music playback requirements, including A2DP and HSP Bluetooth profiles. Signed-off-by: Marcin SmoczyƄski --- module-audio/Audio/AudioDevice.hpp | 26 ++-- module-audio/Audio/AudioFormat.cpp | 17 +++ module-audio/Audio/AudioFormat.hpp | 4 + module-audio/Audio/Endpoint.cpp | 32 ++--- module-audio/Audio/Endpoint.hpp | 48 ++++---- .../Audio/Operation/PlaybackOperation.cpp | 12 +- .../Audio/Operation/PlaybackOperation.hpp | 10 +- .../Audio/Operation/RecorderOperation.cpp | 6 +- .../Audio/Operation/RouterOperation.cpp | 23 ++-- .../Audio/Operation/RouterOperation.hpp | 13 +- module-audio/Audio/Profiles/Profile.cpp | 16 +-- module-audio/Audio/Profiles/Profile.hpp | 31 +++-- module-audio/Audio/Profiles/ProfileIdle.hpp | 2 +- .../Profiles/ProfilePlaybackBluetoothA2DP.hpp | 14 +-- .../Profiles/ProfilePlaybackHeadphones.hpp | 14 +-- .../Profiles/ProfilePlaybackLoudspeaker.hpp | 14 +-- .../Profiles/ProfileRecordingBluetoothHSP.hpp | 17 +-- .../Profiles/ProfileRecordingHeadphones.hpp | 17 +-- .../Profiles/ProfileRecordingOnBoardMic.hpp | 17 +-- .../Profiles/ProfileRoutingBluetoothHSP.hpp | 26 ++-- .../Profiles/ProfileRoutingEarspeaker.hpp | 26 ++-- .../Profiles/ProfileRoutingHeadphones.hpp | 26 ++-- .../Profiles/ProfileRoutingLoudspeaker.hpp | 26 ++-- module-audio/Audio/StreamFactory.cpp | 97 +++++++++++---- module-audio/Audio/StreamFactory.hpp | 23 ++-- module-audio/Audio/decoder/Decoder.cpp | 9 +- module-audio/Audio/decoder/Decoder.hpp | 6 +- module-audio/Audio/test/MockEndpoint.hpp | 33 ++++++ module-audio/Audio/test/TestEndpoint.cpp | 10 ++ module-audio/Audio/test/TestEndpoint.hpp | 4 + module-audio/Audio/test/unittest_format.cpp | 16 +++ module-audio/Audio/test/unittest_stream.cpp | 112 ++++++++++++++++++ .../board/rt1051/RT1051AudioCodec.cpp | 13 +- .../board/rt1051/RT1051AudioCodec.hpp | 9 +- .../board/rt1051/RT1051CellularAudio.cpp | 9 +- .../board/rt1051/RT1051CellularAudio.hpp | 5 +- module-audio/board/rt1051/SAIAudioDevice.cpp | 2 +- module-audio/board/rt1051/SAIAudioDevice.hpp | 2 - .../Bluetooth/audio/BluetoothAudioDevice.cpp | 14 ++- .../Bluetooth/audio/BluetoothAudioDevice.hpp | 7 +- 40 files changed, 543 insertions(+), 265 deletions(-) create mode 100644 module-audio/Audio/test/MockEndpoint.hpp diff --git a/module-audio/Audio/AudioDevice.hpp b/module-audio/Audio/AudioDevice.hpp index dc9cfac92906533f59b189e7921df4d1bee72621..0923f34df9ab39f1e7c9cb9b3f26fb9c53e3534b 100644 --- a/module-audio/Audio/AudioDevice.hpp +++ b/module-audio/Audio/AudioDevice.hpp @@ -54,7 +54,7 @@ namespace audio None }; - using Format = struct + using Configuration = struct { uint32_t sampleRate_Hz = 0; /*!< Sample rate of audio data */ uint32_t bitWidth = 0; /*!< Data length of audio data, usually 8/16/24/32 bits */ @@ -65,22 +65,16 @@ namespace audio OutputPath outputPath = OutputPath::None; }; - AudioDevice() = default; - explicit AudioDevice(const audio::Endpoint::Capabilities &sourceCaps, - const audio::Endpoint::Capabilities &sinkCaps) - : IOProxy(sourceCaps, sinkCaps) - {} - virtual ~AudioDevice() = default; - virtual RetCode Start(const Format &format) = 0; - virtual RetCode Stop() = 0; + virtual RetCode Start(const Configuration &format) = 0; + virtual RetCode Stop() = 0; - virtual RetCode OutputVolumeCtrl(float vol) = 0; - virtual RetCode InputGainCtrl(float gain) = 0; - virtual RetCode OutputPathCtrl(OutputPath outputPath) = 0; - virtual RetCode InputPathCtrl(InputPath inputPath) = 0; - virtual bool IsFormatSupported(const Format &format) = 0; + virtual RetCode OutputVolumeCtrl(float vol) = 0; + virtual RetCode InputGainCtrl(float gain) = 0; + virtual RetCode OutputPathCtrl(OutputPath outputPath) = 0; + virtual RetCode InputPathCtrl(InputPath inputPath) = 0; + virtual bool IsFormatSupported(const Configuration &format) = 0; float GetOutputVolume() const noexcept { @@ -102,13 +96,13 @@ namespace audio return currentFormat.inputPath; } - Format GetCurrentFormat() const noexcept + Configuration GetCurrentFormat() const noexcept { return currentFormat; } protected: - Format currentFormat; + Configuration currentFormat; bool isInitialized = false; }; diff --git a/module-audio/Audio/AudioFormat.cpp b/module-audio/Audio/AudioFormat.cpp index df6526a8b382d494e07c37a7343eacb28e48cdf8..32ed7d9e8d7ab44102b341698bc36c12b68039e4 100644 --- a/module-audio/Audio/AudioFormat.cpp +++ b/module-audio/Audio/AudioFormat.cpp @@ -3,6 +3,8 @@ #include "AudioFormat.hpp" +#include + using audio::AudioFormat; auto AudioFormat::getSampleRate() const noexcept -> unsigned int @@ -87,3 +89,18 @@ auto AudioFormat::isNull() const noexcept -> bool { return operator==(audio::nullFormat); } + +auto AudioFormat::bytesToMicroseconds(unsigned int bytes) const noexcept -> std::chrono::microseconds +{ + auto bytesPerSecond = getBitrate() / utils::integer::BitsInByte; + auto duration = std::chrono::duration(static_cast(bytes) / bytesPerSecond); + + return std::chrono::duration_cast(duration); +} + +auto AudioFormat::microsecondsToBytes(std::chrono::microseconds duration) const noexcept -> unsigned int +{ + auto bytesPerSecond = getBitrate() / utils::integer::BitsInByte; + auto seconds = std::chrono::duration(duration).count(); + return static_cast(seconds * bytesPerSecond); +} diff --git a/module-audio/Audio/AudioFormat.hpp b/module-audio/Audio/AudioFormat.hpp index f83cc36b8bf8f4940b431a90e88f25af6a9b5b5b..e8e10afb27a19dcbe05b47ea1c6a59e1f0d5ca06 100644 --- a/module-audio/Audio/AudioFormat.hpp +++ b/module-audio/Audio/AudioFormat.hpp @@ -3,6 +3,7 @@ #pragma once +#include #include #include #include @@ -30,6 +31,9 @@ namespace audio auto getBitrate() const noexcept -> unsigned long int; auto toString() const -> std::string; + auto bytesToMicroseconds(unsigned int bytes) const noexcept -> std::chrono::microseconds; + auto microsecondsToBytes(std::chrono::microseconds duration) const noexcept -> unsigned int; + auto operator==(const AudioFormat &other) const -> bool; auto operator!=(const AudioFormat &other) const -> bool; auto operator>(const AudioFormat &other) const -> bool; diff --git a/module-audio/Audio/Endpoint.cpp b/module-audio/Audio/Endpoint.cpp index aca7969e11601c44727b413d87eeb718b43f5253..9999f3f227d131fad7a337cf1d80df6e77deaf41 100644 --- a/module-audio/Audio/Endpoint.cpp +++ b/module-audio/Audio/Endpoint.cpp @@ -8,17 +8,14 @@ #include // assert -using namespace audio; - -Endpoint::Endpoint(const Capabilities &caps) : _caps(caps) -{} - -const Endpoint::Capabilities &Endpoint::getCapabilities() const noexcept -{ - return _caps; -} - -void Endpoint::connectStream(Stream &stream) +using audio::AbstractStream; +using audio::Endpoint; +using audio::IOProxy; +using audio::Sink; +using audio::Source; +using audio::StreamConnection; + +void Endpoint::connectStream(AbstractStream &stream) { assert(_stream == nullptr); _stream = &stream; @@ -41,16 +38,7 @@ auto Endpoint::isFormatSupported(const AudioFormat &format) -> bool return std::find(std::begin(formats), std::end(formats), format) != std::end(formats); } -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) +StreamConnection::StreamConnection(Source *source, Sink *sink, AbstractStream *stream) : _sink(sink), _source(source), _stream(stream) { assert(_sink != nullptr); @@ -114,7 +102,7 @@ Sink *StreamConnection::getSink() const noexcept return _sink; } -Stream *StreamConnection::getStream() const noexcept +AbstractStream *StreamConnection::getStream() const noexcept { return _stream; } diff --git a/module-audio/Audio/Endpoint.hpp b/module-audio/Audio/Endpoint.hpp index be8944731c3a6697727c97a346013b9cb2b809e9..1d8c4add9844f6e70d7c2094eae57202eb5560fd 100644 --- a/module-audio/Audio/Endpoint.hpp +++ b/module-audio/Audio/Endpoint.hpp @@ -3,9 +3,11 @@ #pragma once -#include "Stream.hpp" +#include "AbstractStream.hpp" #include "AudioFormat.hpp" +#include +#include #include #include @@ -15,36 +17,33 @@ namespace audio class Endpoint { public: - struct Capabilities + struct Traits { - bool usesDMA = false; - std::size_t minBlockSize = 1; - std::size_t maxBlockSize = SIZE_MAX; + bool usesDMA = false; + + // optional constraints + std::optional blockSizeConstraint = std::nullopt; + std::optional timeConstraint = std::nullopt; }; Endpoint() = default; - Endpoint(const Capabilities &caps); - void connectStream(Stream &stream); + void connectStream(AbstractStream &stream); void disconnectStream(); bool isConnected() const noexcept; - [[nodiscard]] const Capabilities &getCapabilities() const noexcept; + [[nodiscard]] virtual auto getTraits() const -> Traits = 0; auto isFormatSupported(const AudioFormat &format) -> bool; virtual auto getSupportedFormats() -> const std::vector & = 0; protected: - Capabilities _caps; - Stream *_stream = nullptr; + AbstractStream *_stream = nullptr; }; class Sink : public Endpoint { public: - Sink() = default; - explicit Sink(const Capabilities &caps); - virtual void onDataSend() = 0; virtual void enableOutput() = 0; virtual void disableOutput() = 0; @@ -53,9 +52,6 @@ namespace audio class Source : public Endpoint { public: - Source() = default; - explicit Source(const Capabilities &caps); - virtual auto getSourceFormat() -> AudioFormat; virtual void onDataReceive() = 0; virtual void enableInput() = 0; @@ -65,9 +61,6 @@ namespace audio class IOProxy : public Source, public Sink { public: - IOProxy() = default; - IOProxy(const Capabilities &sourceCaps, const Capabilities &sinkCaps); - inline bool isSinkConnected() const noexcept { return Sink::isConnected(); @@ -78,12 +71,12 @@ namespace audio return Source::isConnected(); } - inline void connectOutputStream(Stream &stream) + inline void connectOutputStream(AbstractStream &stream) { Sink::connectStream(stream); } - inline void connectInputStream(Stream &stream) + inline void connectInputStream(AbstractStream &stream) { Source::connectStream(stream); } @@ -103,7 +96,7 @@ namespace audio { public: StreamConnection() = default; - StreamConnection(Source *source, Sink *sink, Stream *stream); + StreamConnection(Source *source, Sink *sink, AbstractStream *stream); ~StreamConnection(); void enable(); @@ -112,14 +105,13 @@ namespace audio [[nodiscard]] Source *getSource() const noexcept; [[nodiscard]] Sink *getSink() const noexcept; - [[nodiscard]] Stream *getStream() const noexcept; - + [[nodiscard]] AbstractStream *getStream() const noexcept; [[nodiscard]] bool isEnabled() const noexcept; private: - bool enabled = false; - Sink *_sink = nullptr; - Source *_source = nullptr; - Stream *_stream = nullptr; + bool enabled = false; + Sink *_sink = nullptr; + Source *_source = nullptr; + AbstractStream *_stream = nullptr; }; }; // namespace audio diff --git a/module-audio/Audio/Operation/PlaybackOperation.cpp b/module-audio/Audio/Operation/PlaybackOperation.cpp index 70b502fced39e4806069e64004b037fab803edd1..96315f1988cb8991d055b7d32c68b7f8288d6861 100644 --- a/module-audio/Audio/Operation/PlaybackOperation.cpp +++ b/module-audio/Audio/Operation/PlaybackOperation.cpp @@ -53,8 +53,14 @@ namespace audio } // create stream - StreamFactory streamFactory(playbackCapabilities, playbackBufferingSize); - dataStreamOut = streamFactory.makeStream(*dec.get(), *audioDevice.get()); + StreamFactory streamFactory(playbackTimeConstraint); + try { + dataStreamOut = streamFactory.makeStream(*dec, *audioDevice, currentProfile->getAudioFormat()); + } + catch (std::invalid_argument &e) { + LOG_FATAL("Cannot create audio stream: %s", e.what()); + return audio::RetCode::Failed; + } // create audio connection outputConnection = std::make_unique(dec.get(), audioDevice.get(), dataStreamOut.get()); @@ -63,7 +69,7 @@ namespace audio dec->startDecodingWorker(endOfFileCallback); // start output device and enable audio connection - auto ret = audioDevice->Start(currentProfile->GetAudioFormat()); + auto ret = audioDevice->Start(currentProfile->GetAudioConfiguration()); outputConnection->enable(); // update state and token diff --git a/module-audio/Audio/Operation/PlaybackOperation.hpp b/module-audio/Audio/Operation/PlaybackOperation.hpp index 22bfc9d5da90f12b28d645fa1580593092bf7a0b..85fd90718c8ff9cbb6ae295803b2c59dd538150a 100644 --- a/module-audio/Audio/Operation/PlaybackOperation.hpp +++ b/module-audio/Audio/Operation/PlaybackOperation.hpp @@ -10,6 +10,9 @@ #include "Audio/StreamQueuedEventsListener.hpp" #include "Audio/decoder/Decoder.hpp" +#include +using namespace std::chrono_literals; + namespace audio::playbackDefaults { constexpr audio::Volume defaultLoudspeakerVolume = 10; @@ -39,12 +42,7 @@ namespace audio Position GetPosition() final; private: - // these values are tightly connected to the Bluetooth A2DP update interval - static constexpr auto playbackBufferingSize = 8U; - static constexpr auto minimumBlockSize = 512U; - static constexpr auto maximumBlockSize = 512U; - static constexpr Endpoint::Capabilities playbackCapabilities{.minBlockSize = minimumBlockSize, - .maxBlockSize = maximumBlockSize}; + static constexpr auto playbackTimeConstraint = 10ms; std::unique_ptr dataStreamOut; std::unique_ptr dec; diff --git a/module-audio/Audio/Operation/RecorderOperation.cpp b/module-audio/Audio/Operation/RecorderOperation.cpp index d0b72736bf2e0d621ad50dbd0c85ad2a123a6a19..fb08ddb44248fe35f8a35bae2c5aa379011e2e65 100644 --- a/module-audio/Audio/Operation/RecorderOperation.cpp +++ b/module-audio/Audio/Operation/RecorderOperation.cpp @@ -85,8 +85,8 @@ namespace audio operationToken = token; state = State::Active; - if (audioDevice->IsFormatSupported(currentProfile->GetAudioFormat())) { - auto ret = audioDevice->Start(currentProfile->GetAudioFormat()); + if (audioDevice->IsFormatSupported(currentProfile->GetAudioConfiguration())) { + auto ret = audioDevice->Start(currentProfile->GetAudioConfiguration()); return GetDeviceError(ret); } else { @@ -124,7 +124,7 @@ namespace audio } state = State::Active; - auto ret = audioDevice->Start(currentProfile->GetAudioFormat()); + auto ret = audioDevice->Start(currentProfile->GetAudioConfiguration()); return GetDeviceError(ret); } diff --git a/module-audio/Audio/Operation/RouterOperation.cpp b/module-audio/Audio/Operation/RouterOperation.cpp index 07f7542d5094313f29f0849ff6b6e216d92a795b..6b4d5cc74f56f6e07c05b77db7d43a6c45f9477f 100644 --- a/module-audio/Audio/Operation/RouterOperation.cpp +++ b/module-audio/Audio/Operation/RouterOperation.cpp @@ -51,28 +51,37 @@ namespace audio state = State::Active; // check if audio devices support desired audio format - if (!audioDevice->IsFormatSupported(currentProfile->GetAudioFormat())) { + if (!audioDevice->IsFormatSupported(currentProfile->GetAudioConfiguration())) { return RetCode::InvalidFormat; } - if (!audioDeviceCellular->IsFormatSupported(currentProfile->GetAudioFormat())) { + if (!audioDeviceCellular->IsFormatSupported(currentProfile->GetAudioConfiguration())) { return RetCode::InvalidFormat; } // try to run devices with the format - if (auto ret = audioDevice->Start(currentProfile->GetAudioFormat()); ret != AudioDevice::RetCode::Success) { + if (auto ret = audioDevice->Start(currentProfile->GetAudioConfiguration()); + ret != AudioDevice::RetCode::Success) { return GetDeviceError(ret); } - if (auto ret = audioDeviceCellular->Start(currentProfile->GetAudioFormat()); + if (auto ret = audioDeviceCellular->Start(currentProfile->GetAudioConfiguration()); ret != AudioDevice::RetCode::Success) { return GetDeviceError(ret); } // create streams - StreamFactory streamFactory(routerCapabilities); - dataStreamIn = streamFactory.makeStream(*audioDevice.get(), *audioDeviceCellular.get()); - dataStreamOut = streamFactory.makeStream(*audioDevice.get(), *audioDeviceCellular.get()); + StreamFactory streamFactory(callTimeConstraint); + try { + dataStreamIn = + streamFactory.makeStream(*audioDevice, *audioDeviceCellular, currentProfile->getAudioFormat()); + dataStreamOut = + streamFactory.makeStream(*audioDevice, *audioDeviceCellular, currentProfile->getAudioFormat()); + } + catch (std::invalid_argument &e) { + LOG_FATAL("Cannot create audio stream: %s", e.what()); + return audio::RetCode::Failed; + } // create audio connections inputConnection = diff --git a/module-audio/Audio/Operation/RouterOperation.hpp b/module-audio/Audio/Operation/RouterOperation.hpp index 0d2b41e1f68d0d755a5bab6081342167db762b53..ab8f218800f4bdcdb518f0bdfd13b7ab768583ce 100644 --- a/module-audio/Audio/Operation/RouterOperation.hpp +++ b/module-audio/Audio/Operation/RouterOperation.hpp @@ -14,13 +14,16 @@ #include -#include +#include #include +#include #include #include #include +using namespace std::chrono_literals; + namespace audio { class RouterOperation : public Operation @@ -56,11 +59,9 @@ 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}; - Mute mute = Mute::Disabled; + static constexpr auto callTimeConstraint = 2ms; + + Mute mute = Mute::Disabled; JackState jackState = JackState::Unplugged; void Mute(); diff --git a/module-audio/Audio/Profiles/Profile.cpp b/module-audio/Audio/Profiles/Profile.cpp index d9c1e58ff556fc17ace46ea265a920e051cedb0b..4c69eb589c0e0a0b5146625c3af5fba018541d99 100644 --- a/module-audio/Audio/Profiles/Profile.cpp +++ b/module-audio/Audio/Profiles/Profile.cpp @@ -79,39 +79,39 @@ namespace audio Profile::Profile(const std::string &name, const Type type, - const AudioDevice::Format &fmt, + const AudioDevice::Configuration &fmt, AudioDevice::Type devType) - : audioFormat(fmt), audioDeviceType(devType), name(name), type(type) + : audioConfiguration(fmt), audioDeviceType(devType), name(name), type(type) {} void Profile::SetInputGain(Gain gain) { - audioFormat.inputGain = gain; + audioConfiguration.inputGain = gain; } void Profile::SetOutputVolume(Volume vol) { - audioFormat.outputVolume = vol; + audioConfiguration.outputVolume = vol; } void Profile::SetInputPath(AudioDevice::InputPath path) { - audioFormat.inputPath = path; + audioConfiguration.inputPath = path; } void Profile::SetOutputPath(AudioDevice::OutputPath path) { - audioFormat.outputPath = path; + audioConfiguration.outputPath = path; } void Profile::SetInOutFlags(uint32_t flags) { - audioFormat.flags = flags; + audioConfiguration.flags = flags; } void Profile::SetSampleRate(uint32_t samplerate) { - audioFormat.sampleRate_Hz = samplerate; + audioConfiguration.sampleRate_Hz = samplerate; } const std::string str(const Profile::Type &profileType) diff --git a/module-audio/Audio/Profiles/Profile.hpp b/module-audio/Audio/Profiles/Profile.hpp index fddd65e8710da53ff7987e967d6953c580f4b502..1a2b9e12f363d0418f626119ad67102c70691ed8 100644 --- a/module-audio/Audio/Profiles/Profile.hpp +++ b/module-audio/Audio/Profiles/Profile.hpp @@ -60,32 +60,32 @@ namespace audio Volume GetOutputVolume() const { - return audioFormat.outputVolume; + return audioConfiguration.outputVolume; } Gain GetInputGain() const { - return audioFormat.inputGain; + return audioConfiguration.inputGain; } uint32_t GetSampleRate() { - return audioFormat.sampleRate_Hz; + return audioConfiguration.sampleRate_Hz; } uint32_t GetInOutFlags() { - return audioFormat.flags; + return audioConfiguration.flags; } AudioDevice::OutputPath GetOutputPath() const { - return audioFormat.outputPath; + return audioConfiguration.outputPath; } AudioDevice::InputPath GetInputPath() const { - return audioFormat.inputPath; + return audioConfiguration.inputPath; } AudioDevice::Type GetAudioDeviceType() const @@ -93,9 +93,17 @@ namespace audio return audioDeviceType; } - AudioDevice::Format GetAudioFormat() + [[deprecated]] AudioDevice::Configuration GetAudioConfiguration() { - return audioFormat; + return audioConfiguration; + } + + auto getAudioFormat() const noexcept + { + auto isStereo = (audioConfiguration.flags & static_cast(AudioDevice::Flags::OutputStereo)) != 0 || + (audioConfiguration.flags & static_cast(AudioDevice::Flags::InputStereo)) != 0; + auto channels = isStereo ? 2U : 1U; + return AudioFormat(audioConfiguration.sampleRate_Hz, audioConfiguration.bitWidth, channels); } const std::string &GetName() const @@ -109,9 +117,12 @@ namespace audio } protected: - Profile(const std::string &name, const Type type, const AudioDevice::Format &fmt, AudioDevice::Type devType); + Profile(const std::string &name, + const Type type, + const AudioDevice::Configuration &fmt, + AudioDevice::Type devType); - AudioDevice::Format audioFormat{}; + AudioDevice::Configuration audioConfiguration{}; AudioDevice::Type audioDeviceType = AudioDevice::Type::Audiocodec; std::string name; diff --git a/module-audio/Audio/Profiles/ProfileIdle.hpp b/module-audio/Audio/Profiles/ProfileIdle.hpp index 437af7359b28dec7480b75c36b96edaff6a1233e..d96ed26e54146763488232f878b45f773d574653 100644 --- a/module-audio/Audio/Profiles/ProfileIdle.hpp +++ b/module-audio/Audio/Profiles/ProfileIdle.hpp @@ -11,7 +11,7 @@ namespace audio class ProfileIdle : public Profile { public: - ProfileIdle() : Profile("Idle", Type::Idle, AudioDevice::Format{}, AudioDevice::Type::None) + ProfileIdle() : Profile("Idle", Type::Idle, AudioDevice::Configuration{}, AudioDevice::Type::None) {} }; diff --git a/module-audio/Audio/Profiles/ProfilePlaybackBluetoothA2DP.hpp b/module-audio/Audio/Profiles/ProfilePlaybackBluetoothA2DP.hpp index 1fc9ed424757446dfded0784f1956c67a0b6a61d..1a8eb64ca35d3e5a190ffe2da2f8106984e03ea2 100644 --- a/module-audio/Audio/Profiles/ProfilePlaybackBluetoothA2DP.hpp +++ b/module-audio/Audio/Profiles/ProfilePlaybackBluetoothA2DP.hpp @@ -14,13 +14,13 @@ namespace audio ProfilePlaybackBluetoothA2DP(Volume volume) : Profile("Playback Bluetooth A2DP", Type::PlaybackBluetoothA2DP, - AudioDevice::Format{.sampleRate_Hz = 44100, - .bitWidth = 16, - .flags = 0, - .outputVolume = static_cast(volume), - .inputGain = 0, - .inputPath = AudioDevice::InputPath::None, - .outputPath = AudioDevice::OutputPath::None}, + AudioDevice::Configuration{.sampleRate_Hz = 44100, + .bitWidth = 16, + .flags = 0, + .outputVolume = static_cast(volume), + .inputGain = 0, + .inputPath = AudioDevice::InputPath::None, + .outputPath = AudioDevice::OutputPath::None}, AudioDevice::Type::Bluetooth) {} }; diff --git a/module-audio/Audio/Profiles/ProfilePlaybackHeadphones.hpp b/module-audio/Audio/Profiles/ProfilePlaybackHeadphones.hpp index 72f7e751d91953fa618da7d9129c831dd5b6f8b4..3f5a2dbbff7136a7fefde6c2ba0bf4cc6b5fb9c4 100644 --- a/module-audio/Audio/Profiles/ProfilePlaybackHeadphones.hpp +++ b/module-audio/Audio/Profiles/ProfilePlaybackHeadphones.hpp @@ -13,13 +13,13 @@ namespace audio ProfilePlaybackHeadphones(Volume volume) : Profile("Playback Headphones", Type::PlaybackHeadphones, - AudioDevice::Format{.sampleRate_Hz = 0, - .bitWidth = 16, - .flags = 0, - .outputVolume = static_cast(volume), - .inputGain = 0, - .inputPath = AudioDevice::InputPath::None, - .outputPath = AudioDevice::OutputPath::Headphones}, + AudioDevice::Configuration{.sampleRate_Hz = 0, + .bitWidth = 16, + .flags = 0, + .outputVolume = static_cast(volume), + .inputGain = 0, + .inputPath = AudioDevice::InputPath::None, + .outputPath = AudioDevice::OutputPath::Headphones}, AudioDevice::Type::Audiocodec) {} }; diff --git a/module-audio/Audio/Profiles/ProfilePlaybackLoudspeaker.hpp b/module-audio/Audio/Profiles/ProfilePlaybackLoudspeaker.hpp index a684fa0b2b15b7f154a37af1b9273974a8cb39e2..e5dda138882cd050c620627cefb113abf5fb9830 100644 --- a/module-audio/Audio/Profiles/ProfilePlaybackLoudspeaker.hpp +++ b/module-audio/Audio/Profiles/ProfilePlaybackLoudspeaker.hpp @@ -14,13 +14,13 @@ namespace audio ProfilePlaybackLoudspeaker(Volume volume) : Profile("Playback Loudspeaker", Type::PlaybackLoudspeaker, - AudioDevice::Format{.sampleRate_Hz = 0, - .bitWidth = 16, - .flags = 0, - .outputVolume = static_cast(volume), - .inputGain = 0, - .inputPath = AudioDevice::InputPath::None, - .outputPath = AudioDevice::OutputPath::Loudspeaker}, + AudioDevice::Configuration{.sampleRate_Hz = 0, + .bitWidth = 16, + .flags = 0, + .outputVolume = static_cast(volume), + .inputGain = 0, + .inputPath = AudioDevice::InputPath::None, + .outputPath = AudioDevice::OutputPath::Loudspeaker}, AudioDevice::Type::Audiocodec) {} }; diff --git a/module-audio/Audio/Profiles/ProfileRecordingBluetoothHSP.hpp b/module-audio/Audio/Profiles/ProfileRecordingBluetoothHSP.hpp index f99b18434f3f99d2c22e5d0135105487b956bea4..108f9c20bfa72c197c36c73aa24fd14ac60bb3bc 100644 --- a/module-audio/Audio/Profiles/ProfileRecordingBluetoothHSP.hpp +++ b/module-audio/Audio/Profiles/ProfileRecordingBluetoothHSP.hpp @@ -14,14 +14,15 @@ namespace audio ProfileRecordingBluetoothHSP(Gain gain) : Profile("Recording Bluetooth HSP", Type::RecordingHeadphones, - AudioDevice::Format{.sampleRate_Hz = 8000, - .bitWidth = 16, - .flags = static_cast( - AudioDevice::Flags::InputLeft), // microphone use left audio channel - .outputVolume = 0, - .inputGain = static_cast(gain), - .inputPath = AudioDevice::InputPath::None, - .outputPath = AudioDevice::OutputPath::None}, + AudioDevice::Configuration{ + .sampleRate_Hz = 8000, + .bitWidth = 16, + .flags = + static_cast(AudioDevice::Flags::InputLeft), // microphone use left audio channel + .outputVolume = 0, + .inputGain = static_cast(gain), + .inputPath = AudioDevice::InputPath::None, + .outputPath = AudioDevice::OutputPath::None}, AudioDevice::Type::Bluetooth) {} }; diff --git a/module-audio/Audio/Profiles/ProfileRecordingHeadphones.hpp b/module-audio/Audio/Profiles/ProfileRecordingHeadphones.hpp index a6b943099ae11708aaa1f47b1dcfe7ddc1412b76..f7b85a74e95bdc571894f80305174d839dc5481b 100644 --- a/module-audio/Audio/Profiles/ProfileRecordingHeadphones.hpp +++ b/module-audio/Audio/Profiles/ProfileRecordingHeadphones.hpp @@ -13,14 +13,15 @@ namespace audio ProfileRecordingHeadphones(Gain gain) : Profile("Recording Headset", Type::RecordingHeadphones, - AudioDevice::Format{.sampleRate_Hz = 44100, - .bitWidth = 16, - .flags = static_cast( - AudioDevice::Flags::InputLeft), // microphone use left audio channel - .outputVolume = 0, - .inputGain = static_cast(gain), - .inputPath = AudioDevice::InputPath::Headphones, - .outputPath = AudioDevice::OutputPath::None}, + AudioDevice::Configuration{ + .sampleRate_Hz = 44100, + .bitWidth = 16, + .flags = + static_cast(AudioDevice::Flags::InputLeft), // microphone use left audio channel + .outputVolume = 0, + .inputGain = static_cast(gain), + .inputPath = AudioDevice::InputPath::Headphones, + .outputPath = AudioDevice::OutputPath::None}, AudioDevice::Type::Audiocodec) {} }; diff --git a/module-audio/Audio/Profiles/ProfileRecordingOnBoardMic.hpp b/module-audio/Audio/Profiles/ProfileRecordingOnBoardMic.hpp index 1d01b2e2ddb7c5db655e7a6a71c6e53d0382552a..6d054bd2443127b030c2a1145cc425f11d2a4e80 100644 --- a/module-audio/Audio/Profiles/ProfileRecordingOnBoardMic.hpp +++ b/module-audio/Audio/Profiles/ProfileRecordingOnBoardMic.hpp @@ -13,14 +13,15 @@ namespace audio ProfileRecordingOnBoardMic(Gain gain) : Profile("Recording On Board Microphone", Type::RecordingBuiltInMic, - AudioDevice::Format{.sampleRate_Hz = 44100, - .bitWidth = 16, - .flags = static_cast( - AudioDevice::Flags::InputLeft), // microphone use left audio channel - .outputVolume = 0, - .inputGain = static_cast(gain), - .inputPath = AudioDevice::InputPath::Microphone, - .outputPath = AudioDevice::OutputPath::None}, + AudioDevice::Configuration{ + .sampleRate_Hz = 44100, + .bitWidth = 16, + .flags = + static_cast(AudioDevice::Flags::InputLeft), // microphone use left audio channel + .outputVolume = 0, + .inputGain = static_cast(gain), + .inputPath = AudioDevice::InputPath::Microphone, + .outputPath = AudioDevice::OutputPath::None}, AudioDevice::Type::Audiocodec) {} }; diff --git a/module-audio/Audio/Profiles/ProfileRoutingBluetoothHSP.hpp b/module-audio/Audio/Profiles/ProfileRoutingBluetoothHSP.hpp index 46e0378c89bf96bccb24da12548bbff3c39f4971..4d8e86d092294a7f80fb0d2cde092f145c3fef53 100644 --- a/module-audio/Audio/Profiles/ProfileRoutingBluetoothHSP.hpp +++ b/module-audio/Audio/Profiles/ProfileRoutingBluetoothHSP.hpp @@ -11,19 +11,19 @@ namespace audio { public: ProfileRoutingBluetoothHSP(Volume volume, Gain gain) - : Profile( - "Routing Bluetooth HSP", - Type::RoutingBluetoothHSP, - AudioDevice::Format{.sampleRate_Hz = 8000, - .bitWidth = 16, - .flags = static_cast( - AudioDevice::Flags::InputLeft) | // microphone use left audio channel - static_cast(AudioDevice::Flags::OutputMono), - .outputVolume = static_cast(volume), - .inputGain = static_cast(gain), - .inputPath = AudioDevice::InputPath::None, - .outputPath = AudioDevice::OutputPath::None}, - AudioDevice::Type::Bluetooth) + : Profile("Routing Bluetooth HSP", + Type::RoutingBluetoothHSP, + AudioDevice::Configuration{ + .sampleRate_Hz = 8000, + .bitWidth = 16, + .flags = static_cast( + AudioDevice::Flags::InputLeft) | // microphone use left audio channel + static_cast(AudioDevice::Flags::OutputMono), + .outputVolume = static_cast(volume), + .inputGain = static_cast(gain), + .inputPath = AudioDevice::InputPath::None, + .outputPath = AudioDevice::OutputPath::None}, + AudioDevice::Type::Bluetooth) {} }; diff --git a/module-audio/Audio/Profiles/ProfileRoutingEarspeaker.hpp b/module-audio/Audio/Profiles/ProfileRoutingEarspeaker.hpp index 1124ed5ed4f0768b562122b4843b5a14c65b7516..3d50e0ffd69599aa43c5ccab15a634c30c76152e 100644 --- a/module-audio/Audio/Profiles/ProfileRoutingEarspeaker.hpp +++ b/module-audio/Audio/Profiles/ProfileRoutingEarspeaker.hpp @@ -11,19 +11,19 @@ namespace audio { public: ProfileRoutingEarspeaker(Volume volume, Gain gain) - : Profile( - "Routing Earspeaker", - Type::RoutingEarspeaker, - AudioDevice::Format{.sampleRate_Hz = 16000, - .bitWidth = 16, - .flags = static_cast( - AudioDevice::Flags::InputLeft) | // microphone use left audio channel - static_cast(AudioDevice::Flags::OutputMono), - .outputVolume = static_cast(volume), - .inputGain = static_cast(gain), - .inputPath = AudioDevice::InputPath::Microphone, - .outputPath = AudioDevice::OutputPath::Earspeaker}, - AudioDevice::Type::Audiocodec) + : Profile("Routing Earspeaker", + Type::RoutingEarspeaker, + AudioDevice::Configuration{ + .sampleRate_Hz = 16000, + .bitWidth = 16, + .flags = static_cast( + AudioDevice::Flags::InputLeft) | // microphone use left audio channel + static_cast(AudioDevice::Flags::OutputMono), + .outputVolume = static_cast(volume), + .inputGain = static_cast(gain), + .inputPath = AudioDevice::InputPath::Microphone, + .outputPath = AudioDevice::OutputPath::Earspeaker}, + AudioDevice::Type::Audiocodec) {} }; diff --git a/module-audio/Audio/Profiles/ProfileRoutingHeadphones.hpp b/module-audio/Audio/Profiles/ProfileRoutingHeadphones.hpp index 06c34ff265f88f4c1ebc3c5b29cb50c5a77ae943..f2faeb9a7da89b0928d3e6fa3b077232742f307a 100644 --- a/module-audio/Audio/Profiles/ProfileRoutingHeadphones.hpp +++ b/module-audio/Audio/Profiles/ProfileRoutingHeadphones.hpp @@ -11,19 +11,19 @@ namespace audio { public: ProfileRoutingHeadphones(Volume volume, Gain gain) - : Profile( - "Routing Headset", - Type::RoutingHeadphones, - AudioDevice::Format{.sampleRate_Hz = 16000, - .bitWidth = 16, - .flags = static_cast( - AudioDevice::Flags::InputLeft) | // microphone use left audio channel - static_cast(AudioDevice::Flags::OutputMono), - .outputVolume = static_cast(volume), - .inputGain = static_cast(gain), - .inputPath = AudioDevice::InputPath::Headphones, - .outputPath = AudioDevice::OutputPath::Headphones}, - AudioDevice::Type::Audiocodec) + : Profile("Routing Headset", + Type::RoutingHeadphones, + AudioDevice::Configuration{ + .sampleRate_Hz = 16000, + .bitWidth = 16, + .flags = static_cast( + AudioDevice::Flags::InputLeft) | // microphone use left audio channel + static_cast(AudioDevice::Flags::OutputMono), + .outputVolume = static_cast(volume), + .inputGain = static_cast(gain), + .inputPath = AudioDevice::InputPath::Headphones, + .outputPath = AudioDevice::OutputPath::Headphones}, + AudioDevice::Type::Audiocodec) {} }; diff --git a/module-audio/Audio/Profiles/ProfileRoutingLoudspeaker.hpp b/module-audio/Audio/Profiles/ProfileRoutingLoudspeaker.hpp index e9c74b6c7ff0838c8758d97b936ab042b7e06f58..a511946d631db87e952a6f13b04385479cb53951 100644 --- a/module-audio/Audio/Profiles/ProfileRoutingLoudspeaker.hpp +++ b/module-audio/Audio/Profiles/ProfileRoutingLoudspeaker.hpp @@ -11,19 +11,19 @@ namespace audio { public: ProfileRoutingLoudspeaker(Volume volume, Gain gain) - : Profile( - "Routing Speakerphone", - Type::RoutingLoudspeaker, - AudioDevice::Format{.sampleRate_Hz = 16000, - .bitWidth = 16, - .flags = static_cast( - AudioDevice::Flags::InputLeft) | // microphone use left audio channel - static_cast(AudioDevice::Flags::OutputMono), - .outputVolume = static_cast(volume), - .inputGain = static_cast(gain), - .inputPath = AudioDevice::InputPath::Microphone, - .outputPath = AudioDevice::OutputPath::Loudspeaker}, - AudioDevice::Type::Audiocodec) + : Profile("Routing Speakerphone", + Type::RoutingLoudspeaker, + AudioDevice::Configuration{ + .sampleRate_Hz = 16000, + .bitWidth = 16, + .flags = static_cast( + AudioDevice::Flags::InputLeft) | // microphone use left audio channel + static_cast(AudioDevice::Flags::OutputMono), + .outputVolume = static_cast(volume), + .inputGain = static_cast(gain), + .inputPath = AudioDevice::InputPath::Microphone, + .outputPath = AudioDevice::OutputPath::Loudspeaker}, + AudioDevice::Type::Audiocodec) {} }; diff --git a/module-audio/Audio/StreamFactory.cpp b/module-audio/Audio/StreamFactory.cpp index 00682d19164ae6e4328d66dbfa6cd392a1747a57..7511983c878244cfa580ae32b540f850bd0831e3 100644 --- a/module-audio/Audio/StreamFactory.cpp +++ b/module-audio/Audio/StreamFactory.cpp @@ -7,52 +7,105 @@ #include #include +#include +#include #include -#include +#include #include +#include -using namespace audio; +using audio::Sink; +using audio::Source; +using audio::Stream; +using audio::StreamFactory; +using namespace std::chrono_literals; -StreamFactory::StreamFactory(Endpoint::Capabilities factoryCaps, unsigned int bufferingSize) - : caps(std::move(factoryCaps)), bufferingSize(bufferingSize) +StreamFactory::StreamFactory(std::chrono::milliseconds operationPeriodRequirement) + : periodRequirement(operationPeriodRequirement) {} -auto StreamFactory::makeStream(Source &source, Sink &sink) -> std::unique_ptr +auto StreamFactory::makeStream(Source &source, Sink &sink, AudioFormat streamFormat) -> std::unique_ptr { - auto negotiatedCaps = negotiateCaps({source, sink}); - auto format = source.getSourceFormat(); + auto streamBuffering = defaultBuffering; + auto endpointsTraits = {source.getTraits(), sink.getTraits()}; + auto blockSizeConstraint = getBlockSizeConstraint(endpointsTraits); + auto &streamAllocator = negotiateAllocator(endpointsTraits); + auto timingConstraint = getTimingConstraints(std::initializer_list>{ + sink.getTraits().timeConstraint, source.getTraits().timeConstraint, periodRequirement}); - return std::make_unique( - format, getAllocator(negotiatedCaps.usesDMA), negotiatedCaps.maxBlockSize, bufferingSize); + if (streamFormat == audio::nullFormat) { + throw std::invalid_argument("No source format provided"); + } + + if (!blockSizeConstraint.has_value()) { + blockSizeConstraint = binary::ceilPowerOfTwo(streamFormat.microsecondsToBytes(timingConstraint)); + } + + auto blockTransferDuration = + std::chrono::duration(streamFormat.bytesToMicroseconds(blockSizeConstraint.value())); + streamBuffering = static_cast(std::ceil(timingConstraint / blockTransferDuration)) * defaultBuffering; + + LOG_DEBUG("Creating audio stream: block size = %lu; buffering = %u", + static_cast(blockSizeConstraint.value()), + streamBuffering); + + return std::make_unique(streamFormat, streamAllocator, blockSizeConstraint.value(), streamBuffering); } -auto StreamFactory::negotiateCaps(std::vector> v) -> Endpoint::Capabilities +auto StreamFactory::getBlockSizeConstraint(std::initializer_list traitsList) const + -> std::optional { - auto negotiatedCaps = caps; + std::optional blockSize = std::nullopt; - for (const auto &endpointRef : v) { - auto &endpointCaps = endpointRef.get().getCapabilities(); + for (const auto &traits : traitsList) { + if (!traits.blockSizeConstraint.has_value()) { + continue; + } - negotiatedCaps.maxBlockSize = std::min(negotiatedCaps.maxBlockSize, endpointCaps.maxBlockSize); - negotiatedCaps.minBlockSize = std::max(negotiatedCaps.minBlockSize, endpointCaps.minBlockSize); - negotiatedCaps.usesDMA = negotiatedCaps.usesDMA || endpointCaps.usesDMA; + auto blockSizeCandidate = traits.blockSizeConstraint.value(); + if (blockSizeCandidate == 0) { + throw std::invalid_argument("Invalid stream block size"); + } + + if (!blockSize.has_value()) { + blockSize = blockSizeCandidate; + } + else if (blockSize != blockSizeCandidate) { + throw std::invalid_argument("Block size mismatch"); + } } - negotiatedCaps.minBlockSize = binary::ceilPowerOfTwo(negotiatedCaps.minBlockSize); - negotiatedCaps.maxBlockSize = binary::floorPowerOfTwo(negotiatedCaps.maxBlockSize); + return blockSize; +} - assert(negotiatedCaps.minBlockSize <= negotiatedCaps.maxBlockSize); +auto StreamFactory::getTimingConstraints( + std::initializer_list> timingConstraints) const + -> std::chrono::milliseconds +{ + auto constraint = std::max(timingConstraints, [](const auto &left, const auto &right) { + return right.value_or(std::chrono::milliseconds(0)).count() > + left.value_or(std::chrono::milliseconds(0)).count(); + }); + + if (!constraint.has_value()) { + throw std::invalid_argument("At least one timing constraint must be provided"); + } - return negotiatedCaps; + return constraint.value(); } -auto StreamFactory::getAllocator(bool usesDMA) -> Stream::Allocator & +auto StreamFactory::negotiateAllocator(std::initializer_list traitsList) noexcept + -> Stream::Allocator & { - if (usesDMA) { + auto mustUseDMA = + std::any_of(std::begin(traitsList), std::end(traitsList), [](const auto &trait) { return trait.usesDMA; }); + if (mustUseDMA) { + LOG_DEBUG("Using fast memory allocator for audio streaming"); return nonCacheableAlloc; } else { + LOG_DEBUG("Using standard allocator for audio streaming"); return stdAlloc; } } diff --git a/module-audio/Audio/StreamFactory.hpp b/module-audio/Audio/StreamFactory.hpp index 91b1b834368e2ef76c8c418d2ff754274f33e9e3..c1f25c542c27761043e1aa384a91ed3f33097a79 100644 --- a/module-audio/Audio/StreamFactory.hpp +++ b/module-audio/Audio/StreamFactory.hpp @@ -6,8 +6,9 @@ #include "Endpoint.hpp" #include "Stream.hpp" +#include +#include #include -#include namespace audio { @@ -15,18 +16,24 @@ namespace audio class StreamFactory { public: - explicit StreamFactory(Endpoint::Capabilities factoryCaps, - unsigned int bufferingSize = Stream::defaultBufferingSize); - auto makeStream(Source &source, Sink &sink) -> std::unique_ptr; + StreamFactory() = default; + explicit StreamFactory(std::chrono::milliseconds operationPeriodRequirement); + auto makeStream(Source &source, Sink &sink, AudioFormat streamFormat) -> std::unique_ptr; private: - auto negotiateCaps(std::vector> v) -> Endpoint::Capabilities; - auto getAllocator(bool usesDMA) -> Stream::Allocator &; + static constexpr auto defaultBuffering = 2U; + + auto getBlockSizeConstraint(std::initializer_list traitsList) const + -> std::optional; + auto getTimingConstraints(std::initializer_list> timingConstraints) + const -> std::chrono::milliseconds; + auto negotiateAllocator(std::initializer_list traitsList) noexcept + -> Stream::Allocator &; + + std::optional periodRequirement = std::nullopt; - Endpoint::Capabilities caps; StandardStreamAllocator stdAlloc; NonCacheableStreamAllocator nonCacheableAlloc; - unsigned int bufferingSize; }; } // namespace audio diff --git a/module-audio/Audio/decoder/Decoder.cpp b/module-audio/Audio/decoder/Decoder.cpp index b4f44a4989624b6c588c1ebd061501f566d3868b..2ed85603ba066910cfa9a6bdf351619df6cdefd5 100644 --- a/module-audio/Audio/decoder/Decoder.cpp +++ b/module-audio/Audio/decoder/Decoder.cpp @@ -14,10 +14,8 @@ namespace audio { - Decoder::Decoder(const char *fileName) - : Source(Endpoint::Capabilities{.maxBlockSize = workerBufferSize * sizeof(int16_t)}), filePath(fileName), - workerBuffer(std::make_unique(workerBufferSize)), tag(std::make_unique()) + : filePath(fileName), workerBuffer(std::make_unique(workerBufferSize)), tag(std::make_unique()) { fd = std::fopen(fileName, "r"); @@ -183,4 +181,9 @@ namespace audio return formats; } + auto Decoder::getTraits() const -> Endpoint::Traits + { + return Endpoint::Traits{}; + } + } // namespace audio diff --git a/module-audio/Audio/decoder/Decoder.hpp b/module-audio/Audio/decoder/Decoder.hpp index c71480c8956f27d13c6c6742bdf68eeeecf58376..8b296ef93e1a8bf1b4270554aae1333dff70abfd 100644 --- a/module-audio/Audio/decoder/Decoder.hpp +++ b/module-audio/Audio/decoder/Decoder.hpp @@ -110,6 +110,8 @@ namespace audio auto getSourceFormat() -> AudioFormat override; auto getSupportedFormats() -> const std::vector & override; + auto getTraits() const -> Endpoint::Traits override; + void startDecodingWorker(DecoderWorker::EndOfFileCallback endOfFileCallback); void stopDecodingWorker(); @@ -122,8 +124,8 @@ namespace audio void convertmono2stereo(int16_t *pcm, uint32_t samplecount); - static constexpr auto workerBufferSize = 1024 * 8; - static constexpr Endpoint::Capabilities decoderCaps = {.usesDMA = false}; + static constexpr auto workerBufferSize = 1024 * 8; + static constexpr Endpoint::Traits decoderCaps = {.usesDMA = false}; uint32_t sampleRate = 0; uint32_t chanNumber = 0; diff --git a/module-audio/Audio/test/MockEndpoint.hpp b/module-audio/Audio/test/MockEndpoint.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4ef8eb50ca0964b0e2829f5eea605a4b361d872d --- /dev/null +++ b/module-audio/Audio/test/MockEndpoint.hpp @@ -0,0 +1,33 @@ +// 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