M harmony_changelog.md => harmony_changelog.md +1 -0
@@ 3,6 3,7 @@
## Unreleased
### Fixed
+* Fixed crash in Relaxation when playing large MP3 file
### Added
M module-audio/Audio/Operation/PlaybackOperation.cpp => module-audio/Audio/Operation/PlaybackOperation.cpp +21 -22
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#include "PlaybackOperation.hpp"
@@ 16,8 16,8 @@ namespace audio
using namespace AudioServiceMessage;
PlaybackOperation::PlaybackOperation(const std::string &filePath,
- const audio::PlaybackType &playbackType,
- const audio::PlaybackMode &playbackMode,
+ const PlaybackType &playbackType,
+ const PlaybackMode &playbackMode,
Callback callback)
: Operation(std::move(callback), playbackType), playbackMode(playbackMode), dec(nullptr)
{
@@ 27,13 27,13 @@ namespace audio
AddProfile(Profile::Type::PlaybackLoudspeaker, playbackType, true);
endOfFileCallback = [this]() {
- if (this->playbackMode == audio::PlaybackMode::Single) {
+ if (this->playbackMode == PlaybackMode::Single) {
state = State::Idle;
const auto msg = AudioServiceMessage::EndOfFile(operationToken);
serviceCallback(&msg);
}
else {
- dec->setPosition(playbackStartPosition);
+ dec->rewind();
}
};
@@ 56,7 56,7 @@ namespace audio
}
}
- audio::RetCode PlaybackOperation::Start(audio::Token token)
+ RetCode PlaybackOperation::Start(Token token)
{
if (state == State::Active || (state == State::Paused && outputConnection != nullptr)) {
return RetCode::InvokedInIncorrectState;
@@ 69,7 69,7 @@ namespace audio
}
catch (std::invalid_argument &e) {
LOG_FATAL("Cannot create audio stream: %s", e.what());
- return audio::RetCode::Failed;
+ return RetCode::Failed;
}
// create audio connection
@@ 89,11 89,11 @@ namespace audio
return GetDeviceError(ret);
}
- audio::RetCode PlaybackOperation::Stop()
+ RetCode PlaybackOperation::Stop()
{
state = State::Idle;
if (!audioDevice) {
- return audio::RetCode::DeviceFailure;
+ return RetCode::DeviceFailure;
}
// stop playback by destroying audio connection
@@ 104,20 104,20 @@ namespace audio
return GetDeviceError(audioDevice->Stop());
}
- audio::RetCode PlaybackOperation::Pause()
+ RetCode PlaybackOperation::Pause()
{
if (state == State::Paused || state == State::Idle || outputConnection == nullptr) {
return RetCode::InvokedInIncorrectState;
}
const auto retCode = GetDeviceError(audioDevice->Pause());
- if (retCode == audio::RetCode::Success) {
+ if (retCode == RetCode::Success) {
state = State::Paused;
outputConnection->disable();
}
return retCode;
}
- audio::RetCode PlaybackOperation::Resume()
+ RetCode PlaybackOperation::Resume()
{
if (state == State::Active || state == State::Idle) {
return RetCode::InvokedInIncorrectState;
@@ 132,14 132,14 @@ namespace audio
return GetDeviceError(audioDevice->Resume());
}
- audio::RetCode PlaybackOperation::SetOutputVolume(float vol)
+ RetCode PlaybackOperation::SetOutputVolume(float vol)
{
currentProfile->SetOutputVolume(vol);
auto ret = audioDevice->setOutputVolume(vol);
return GetDeviceError(ret);
}
- audio::RetCode PlaybackOperation::SetInputGain(float gain)
+ RetCode PlaybackOperation::SetInputGain(float gain)
{
currentProfile->SetInputGain(gain);
auto ret = audioDevice->setInputGain(gain);
@@ 151,22 151,21 @@ namespace audio
return dec->getCurrentPosition();
}
- audio::RetCode PlaybackOperation::SwitchToPriorityProfile(audio::PlaybackType playbackType)
+ RetCode PlaybackOperation::SwitchToPriorityProfile(PlaybackType playbackType)
{
for (const auto &p : supportedProfiles) {
const auto profileType = p.profile->GetType();
- if (profileType == audio::Profile::Type::PlaybackBluetoothA2DP &&
- playbackType == audio::PlaybackType::CallRingtone) {
+ if (profileType == Profile::Type::PlaybackBluetoothA2DP && playbackType == PlaybackType::CallRingtone) {
continue;
}
if (p.isAvailable) {
return SwitchProfile(profileType);
}
}
- return audio::RetCode::ProfileNotSet;
+ return RetCode::ProfileNotSet;
}
- audio::RetCode PlaybackOperation::SendEvent(std::shared_ptr<Event> evt)
+ RetCode PlaybackOperation::SendEvent(std::shared_ptr<Event> evt)
{
const auto isAvailable = evt->getDeviceState() == Event::DeviceState::Connected;
switch (evt->getType()) {
@@ 185,7 184,7 @@ namespace audio
return RetCode::Success;
}
- audio::RetCode PlaybackOperation::SwitchProfile(const Profile::Type type)
+ RetCode PlaybackOperation::SwitchProfile(const Profile::Type type)
{
auto newProfile = GetProfile(type);
if (newProfile == nullptr) {
@@ 199,7 198,7 @@ namespace audio
// adjust new profile with information from file's tags
newProfile->SetSampleRate(dec->getSourceFormat().getSampleRate());
- newProfile->SetInOutFlags(static_cast<std::uint32_t>(audio::codec::Flags::OutputStereo));
+ newProfile->SetInOutFlags(static_cast<std::uint32_t>(codec::Flags::OutputStereo));
/// profile change - (re)create output device; stop audio first by
/// killing audio connection
@@ 228,7 227,7 @@ namespace audio
Start(operationToken);
}
- return audio::RetCode::Success;
+ return RetCode::Success;
}
PlaybackOperation::~PlaybackOperation()
M module-audio/Audio/Operation/PlaybackOperation.hpp => module-audio/Audio/Operation/PlaybackOperation.hpp +13 -14
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#pragma once
@@ 19,28 19,27 @@ namespace audio
{
public:
PlaybackOperation(const std::string &filePath,
- const audio::PlaybackType &playbackType,
- const audio::PlaybackMode &playbackMode,
+ const PlaybackType &playbackType,
+ const PlaybackMode &playbackMode,
AudioServiceMessage::Callback callback = nullptr);
~PlaybackOperation() override;
- audio::RetCode Start(audio::Token token) final;
- audio::RetCode Stop() final;
- audio::RetCode Pause() final;
- audio::RetCode Resume() final;
- audio::RetCode SendEvent(std::shared_ptr<Event> evt) final;
- audio::RetCode SwitchProfile(const Profile::Type type) final;
- audio::RetCode SetOutputVolume(float vol) final;
- audio::RetCode SetInputGain(float gain) final;
+ RetCode Start(Token token) final;
+ RetCode Stop() final;
+ RetCode Pause() final;
+ RetCode Resume() final;
+ RetCode SendEvent(std::shared_ptr<Event> evt) final;
+ RetCode SwitchProfile(const Profile::Type type) final;
+ RetCode SetOutputVolume(float vol) final;
+ RetCode SetInputGain(float gain) final;
Position GetPosition() final;
- audio::RetCode SwitchToPriorityProfile(audio::PlaybackType playbackType) final;
+ RetCode SwitchToPriorityProfile(PlaybackType playbackType) final;
private:
static constexpr auto playbackTimeConstraint = 10ms;
- static constexpr auto playbackStartPosition = 0U;
- audio::PlaybackMode playbackMode = audio::PlaybackMode::Single;
+ PlaybackMode playbackMode = PlaybackMode::Single;
std::unique_ptr<Stream> dataStreamOut;
std::unique_ptr<Decoder> dec;
M module-audio/Audio/decoder/Decoder.cpp => module-audio/Audio/decoder/Decoder.cpp +10 -9
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#include <cstdio>
@@ 42,12 42,12 @@ namespace audio
}
}
- std::unique_ptr<tags::fetcher::Tags> Decoder::fetchTags()
+ auto Decoder::fetchTags() -> std::unique_ptr<tags::fetcher::Tags>
{
return std::make_unique<tags::fetcher::Tags>(tags::fetcher::fetchTags(filePath));
}
- std::unique_ptr<Decoder> Decoder::Create(const std::string &filePath)
+ auto Decoder::Create(const std::string &filePath) -> std::unique_ptr<Decoder>
{
const auto extension = std::filesystem::path(filePath).extension();
const auto extensionLowercase = utils::stringToLowercase(extension);
@@ 74,10 74,11 @@ namespace audio
return dec;
}
- void Decoder::startDecodingWorker(const DecoderWorker::EndOfFileCallback &endOfFileCallback,
- const DecoderWorker::FileDeletedCallback &fileDeletedCallback)
+ auto Decoder::startDecodingWorker(const DecoderWorker::EndOfFileCallback &endOfFileCallback,
+ const DecoderWorker::FileDeletedCallback &fileDeletedCallback) -> void
{
assert(_stream != nullptr);
+
if (audioWorker == nullptr) {
const auto channelMode = (tags->num_channel == 1) ? DecoderWorker::ChannelMode::ForceStereo
: DecoderWorker::ChannelMode::NoConversion;
@@ 92,7 93,7 @@ namespace audio
}
}
- void Decoder::stopDecodingWorker()
+ auto Decoder::stopDecodingWorker() -> void
{
if (audioWorker) {
audioWorker->close();
@@ 100,17 101,17 @@ namespace audio
audioWorker = nullptr;
}
- void Decoder::onDataReceive()
+ auto Decoder::onDataReceive() -> void
{
audioWorker->enablePlayback();
}
- void Decoder::enableInput()
+ auto Decoder::enableInput() -> void
{
audioWorker->enablePlayback();
}
- void Decoder::disableInput()
+ auto Decoder::disableInput() -> void
{
audioWorker->disablePlayback();
}
M module-audio/Audio/decoder/Decoder.hpp => module-audio/Audio/decoder/Decoder.hpp +18 -15
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#pragma once
@@ 28,49 28,52 @@ namespace audio
explicit Decoder(const std::string &path);
virtual ~Decoder();
- virtual std::int32_t decode(std::uint32_t samplesToRead, std::int16_t *pcmData) = 0;
+ virtual auto decode(std::uint32_t samplesToRead, std::int16_t *pcmData) -> std::int32_t = 0;
// Range 0 - 1
- virtual void setPosition(float pos) = 0;
+ virtual auto setPosition(float pos) -> void = 0;
- std::uint32_t getSampleRate()
+ // Rewind to first audio sample
+ virtual auto rewind() -> void = 0;
+
+ [[nodiscard]] auto getSampleRate() const noexcept -> std::uint32_t
{
return sampleRate;
}
- std::uint32_t getChannelCount()
+ [[nodiscard]] auto getChannelCount() const noexcept -> std::uint32_t
{
return channelCount;
}
- float getCurrentPosition()
+ [[nodiscard]] auto getCurrentPosition() const noexcept -> float
{
return position;
}
- void onDataReceive() override;
- void enableInput() override;
- void disableInput() override;
+ auto onDataReceive() -> void override;
+ auto enableInput() -> void override;
+ auto disableInput() -> void override;
auto getSourceFormat() -> AudioFormat override;
auto getSupportedFormats() -> std::vector<AudioFormat> override;
auto getTraits() const -> Endpoint::Traits override;
- void startDecodingWorker(const DecoderWorker::EndOfFileCallback &endOfFileCallback,
- const DecoderWorker::FileDeletedCallback &fileDeletedCallback);
- void stopDecodingWorker();
+ auto startDecodingWorker(const DecoderWorker::EndOfFileCallback &endOfFileCallback,
+ const DecoderWorker::FileDeletedCallback &fileDeletedCallback) -> void;
+ auto stopDecodingWorker() -> void;
// Factory method
- static std::unique_ptr<Decoder> Create(const std::string &path);
+ static auto Create(const std::string &path) -> std::unique_ptr<Decoder>;
protected:
- virtual auto getBitWidth() -> unsigned int
+ [[nodiscard]] virtual auto getBitWidth() -> unsigned int
{
return bitsPerSample;
}
- virtual std::unique_ptr<tags::fetcher::Tags> fetchTags();
+ virtual auto fetchTags() -> std::unique_ptr<tags::fetcher::Tags>;
static constexpr Endpoint::Traits decoderCaps = {.usesDMA = false};
M module-audio/Audio/decoder/DecoderFLAC.cpp => module-audio/Audio/decoder/DecoderFLAC.cpp +21 -22
@@ 1,9 1,8 @@
-// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#include "DecoderFLAC.hpp"
#include "DecoderCommon.hpp"
-#include "flac/flacfile.h"
#define DR_FLAC_IMPLEMENTATION
#define DR_FLAC_NO_STDIO
@@ 39,13 38,13 @@ namespace audio
drflac_close(flac);
}
- std::int32_t DecoderFLAC::decode(std::uint32_t samplesToRead, std::int16_t *pcmData)
+ auto DecoderFLAC::decode(std::uint32_t samplesToRead, std::int16_t *pcmData) -> std::int32_t
{
- const auto samplesRead =
+ const auto framesRead =
drflac_read_pcm_frames_s16(flac, samplesToRead / channelCount, reinterpret_cast<drflac_int16 *>(pcmData));
- if (samplesRead > 0) {
+ if (framesRead > 0) {
/* Calculate frame duration in seconds */
- position += static_cast<float>(samplesRead) / static_cast<float>(sampleRate);
+ position += static_cast<float>(framesRead) / static_cast<float>(sampleRate);
}
else if (!fileExists(fd)) {
/* Unfortunately this second check of file existence is needed
@@ 54,34 53,34 @@ namespace audio
LOG_WARN("File '%s' was deleted during playback!", filePath.c_str());
return fileDeletedRetCode;
}
- return samplesRead * channelCount;
+ return framesRead * channelCount;
}
- void DecoderFLAC::setPosition(float pos)
+ auto DecoderFLAC::setPosition(float pos) -> void
{
if (!isInitialized) {
LOG_ERROR("FLAC decoder not initialized");
return;
}
- drflac_seek_to_pcm_frame(flac, flac->totalPCMFrameCount * pos);
+
+ const auto frameToSeek = static_cast<std::uint64_t>(flac->totalPCMFrameCount * pos);
+ const auto status = drflac_seek_to_pcm_frame(flac, frameToSeek);
+ if (status == DRFLAC_FALSE) {
+ LOG_ERROR("Failed to seek to frame %" PRIu64 " in file '%s'!", frameToSeek, filePath.c_str());
+ }
// Calculate new position
- position = static_cast<float>(flac->totalPCMFrameCount) * pos / static_cast<float>(sampleRate);
+ position = frameToSeek / static_cast<float>(sampleRate);
}
- /* Data encoded in UTF-8 */
- void DecoderFLAC::parseText(
- std::uint8_t *in, std::uint32_t taglen, std::uint32_t datalen, std::uint8_t *out, std::uint32_t outlen)
+ auto DecoderFLAC::rewind() -> void
{
- /* Little Endian here */
- const auto size = std::min(datalen - taglen, outlen - 1);
- memcpy(out, in + taglen, size);
- out[size] = '\0';
+ setPosition(0.0f);
}
- std::size_t DecoderFLAC::drflacRead(void *pUserData, void *pBufferOut, std::size_t bytesToRead)
+ auto DecoderFLAC::drflacRead(void *pUserData, void *pBufferOut, std::size_t bytesToRead) -> std::size_t
{
- const auto decoderContext = reinterpret_cast<DecoderFLAC *>(pUserData);
+ const auto decoderContext = static_cast<DecoderFLAC *>(pUserData);
/* Check if the file exists - std::fread happily returns bytesToRead if
* requested to read from deleted file, what causes decoding library
@@ 92,11 91,11 @@ namespace audio
return std::fread(pBufferOut, 1, bytesToRead, decoderContext->fd);
}
- drflac_bool32 DecoderFLAC::drflacSeek(void *pUserData, int offset, drflac_seek_origin origin)
+ auto DecoderFLAC::drflacSeek(void *pUserData, int offset, drflac_seek_origin origin) -> drflac_bool32
{
- const auto decoderContext = reinterpret_cast<DecoderFLAC *>(pUserData);
+ const auto decoderContext = static_cast<DecoderFLAC *>(pUserData);
const auto seekError =
- std::fseek(decoderContext->fd, offset, origin == drflac_seek_origin_start ? SEEK_SET : SEEK_CUR);
+ std::fseek(decoderContext->fd, offset, (origin == drflac_seek_origin_start) ? SEEK_SET : SEEK_CUR);
return (seekError == 0) ? DRFLAC_TRUE : DRFLAC_FALSE;
}
} // namespace audio
M module-audio/Audio/decoder/DecoderFLAC.hpp => module-audio/Audio/decoder/DecoderFLAC.hpp +7 -10
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#pragma once
@@ 12,19 12,16 @@ namespace audio
{
public:
explicit DecoderFLAC(const std::string &filePath);
- ~DecoderFLAC();
+ ~DecoderFLAC() override;
- std::int32_t decode(std::uint32_t samplesToRead, std::int16_t *pcmData) override;
+ auto decode(std::uint32_t samplesToRead, std::int16_t *pcmData) -> std::int32_t override;
- void setPosition(float pos) override;
+ auto setPosition(float pos) -> void override;
+ auto rewind() -> void override;
private:
drflac *flac = nullptr;
- /* Data encoded in UTF-8 */
- void parseText(
- std::uint8_t *in, std::uint32_t taglen, std::uint32_t datalen, std::uint8_t *out, std::uint32_t outlen);
-
// Callback for when data needs to be read from the client.
//
// pUserData [in] The user data that was passed to drflac_open() and family.
@@ 35,7 32,7 @@ namespace audio
//
// A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback
// until either the entire bytesToRead is filled or you have reached the end of the stream.
- static std::size_t drflacRead(void *pUserData, void *pBufferOut, std::size_t bytesToRead);
+ static auto drflacRead(void *pUserData, void *pBufferOut, std::size_t bytesToRead) -> std::size_t;
// Callback for when data needs to be seeked.
//
@@ 48,6 45,6 @@ namespace audio
// The offset will never be negative. Whether it is relative to the beginning or current position is
// determined by the "origin" parameter which will be either drflac_seek_origin_start or
// drflac_seek_origin_current.
- static drflac_bool32 drflacSeek(void *pUserData, int offset, drflac_seek_origin origin);
+ static auto drflacSeek(void *pUserData, int offset, drflac_seek_origin origin) -> drflac_bool32;
};
} // namespace audio
M module-audio/Audio/decoder/DecoderMP3.cpp => module-audio/Audio/decoder/DecoderMP3.cpp +25 -11
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#define MINIMP3_IMPLEMENTATION
@@ 25,7 25,7 @@ namespace audio
const auto decoderStatus = mp3dec_ex_open_cb(dec.get(), dec->io, MP3D_SEEK_TO_SAMPLE | MP3D_DO_NOT_SCAN);
if (decoderStatus != 0) {
- LOG_ERROR("Failed to open minimp3, error: %d", decoderStatus);
+ LOG_ERROR("Failed to open minimp3, error %d", decoderStatus);
return;
}
@@ 45,22 45,36 @@ namespace audio
isInitialized = false;
}
- void DecoderMP3::setPosition(float pos)
+ auto DecoderMP3::setPosition(float pos) -> void
{
if (!isInitialized) {
LOG_ERROR("MP3 decoder not initialized");
return;
}
- mp3dec_ex_seek(dec.get(), pos);
+
+ const auto sampleToSeek = static_cast<std::uint64_t>(dec->samples * pos);
+ const auto frameToSeek = sampleToSeek / channelCount;
+ const auto status = mp3dec_ex_seek(dec.get(), sampleToSeek);
+ if (status != 0) {
+ LOG_ERROR(
+ "Failed to seek to frame %" PRIu64 " in file '%s', error %d!", frameToSeek, filePath.c_str(), status);
+ }
+
+ position = frameToSeek / static_cast<float>(sampleRate);
+ }
+
+ auto DecoderMP3::rewind() -> void
+ {
+ setPosition(0.0f);
}
- std::int32_t DecoderMP3::decode(std::uint32_t samplesToRead, std::int16_t *pcmData)
+ auto DecoderMP3::decode(std::uint32_t samplesToRead, std::int16_t *pcmData) -> std::int32_t
{
const auto samplesRead = mp3dec_ex_read(dec.get(), reinterpret_cast<mp3d_sample_t *>(pcmData), samplesToRead);
if (samplesRead > 0) {
/* Calculate frame duration in seconds */
- const auto samplesPerChannel = static_cast<float>(samplesRead) / static_cast<float>(channelCount);
- position += samplesPerChannel / static_cast<float>(sampleRate);
+ const auto framesRead = static_cast<float>(samplesRead) / static_cast<float>(channelCount);
+ position += framesRead / static_cast<float>(sampleRate);
}
else if (!fileExists(fd)) {
/* Unfortunately this second check of file existence is needed
@@ 72,9 86,9 @@ namespace audio
return samplesRead;
}
- std::size_t DecoderMP3::mp3Read(void *pBufferOut, std::size_t bytesToRead, void *pUserData)
+ auto DecoderMP3::mp3Read(void *pBufferOut, std::size_t bytesToRead, void *pUserData) -> std::size_t
{
- const auto decoderContext = reinterpret_cast<DecoderMP3 *>(pUserData);
+ const auto decoderContext = static_cast<DecoderMP3 *>(pUserData);
/* Check if the file exists - std::fread happily returns bytesToRead if
* requested to read from deleted file, what causes decoding library
@@ 85,9 99,9 @@ namespace audio
return std::fread(pBufferOut, 1, bytesToRead, decoderContext->fd);
}
- int DecoderMP3::mp3Seek(std::uint64_t offset, void *pUserData)
+ auto DecoderMP3::mp3Seek(std::uint64_t offset, void *pUserData) -> int
{
- const auto decoderContext = reinterpret_cast<DecoderMP3 *>(pUserData);
+ const auto decoderContext = static_cast<DecoderMP3 *>(pUserData);
return std::fseek(decoderContext->fd, offset, SEEK_SET);
}
} // namespace audio
M module-audio/Audio/decoder/DecoderMP3.hpp => module-audio/Audio/decoder/DecoderMP3.hpp +7 -6
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#pragma once
@@ 12,11 12,12 @@ namespace audio
{
public:
explicit DecoderMP3(const std::string &filePath);
- ~DecoderMP3();
+ ~DecoderMP3() override;
- std::int32_t decode(std::uint32_t samplesToRead, std::int16_t *pcmData) override;
+ auto decode(std::uint32_t samplesToRead, std::int16_t *pcmData) -> std::int32_t override;
- void setPosition(float pos) override;
+ auto setPosition(float pos) -> void override;
+ auto rewind() -> void override;
private:
std::unique_ptr<mp3dec_ex_t> dec;
@@ 32,7 33,7 @@ namespace audio
//
// A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback
// until either the entire bytesToRead is filled or you have reached the end of the stream.
- static std::size_t mp3Read(void *pBufferOut, std::size_t bytesToRead, void *pUserData);
+ static auto mp3Read(void *pBufferOut, std::size_t bytesToRead, void *pUserData) -> std::size_t;
// Callback for when data needs to be seeked.
//
@@ 42,6 43,6 @@ namespace audio
// Returns whether the seek was successful.
//
// The offset will never be negative. It relates to the beginning position.
- static int mp3Seek(std::uint64_t offset, void *pUserData);
+ static auto mp3Seek(std::uint64_t offset, void *pUserData) -> int;
};
} // namespace audio
M module-audio/Audio/decoder/DecoderWAV.cpp => module-audio/Audio/decoder/DecoderWAV.cpp +24 -14
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#include "DecoderWAV.hpp"
@@ 38,29 38,39 @@ namespace audio
}
}
- void DecoderWAV::setPosition(float pos)
+ auto DecoderWAV::setPosition(float pos) -> void
{
if (!isInitialized) {
LOG_ERROR("WAV decoder not initialized");
return;
}
- drwav_seek_to_pcm_frame(wav.get(), wav->totalPCMFrameCount * pos);
+
+ const auto frameToSeek = static_cast<std::uint64_t>(wav->totalPCMFrameCount * pos);
+ const auto status = drwav_seek_to_pcm_frame(wav.get(), frameToSeek);
+ if (status == DRWAV_FALSE) {
+ LOG_ERROR("Failed to seek to frame %" PRIu64 " in file '%s'!", frameToSeek, filePath.c_str());
+ }
/* Calculate new position */
- position = static_cast<float>(wav->totalPCMFrameCount) * pos / static_cast<float>(sampleRate);
+ position = frameToSeek / static_cast<float>(sampleRate);
+ }
+
+ auto DecoderWAV::rewind() -> void
+ {
+ setPosition(0.0f);
}
- std::int32_t DecoderWAV::decode(std::uint32_t samplesToRead, std::int16_t *pcmData)
+ auto DecoderWAV::decode(std::uint32_t samplesToRead, std::int16_t *pcmData) -> std::int32_t
{
if (!isInitialized) {
LOG_ERROR("WAV decoder not initialized");
return 0;
}
- const auto samplesRead = drwav_read_pcm_frames_s16(wav.get(), samplesToRead / channelCount, pcmData);
- if (samplesRead > 0) {
+ const auto framesRead = drwav_read_pcm_frames_s16(wav.get(), samplesToRead / channelCount, pcmData);
+ if (framesRead > 0) {
/* Calculate frame duration in seconds */
- position += static_cast<float>(samplesRead) / static_cast<float>(sampleRate);
+ position += static_cast<float>(framesRead) / static_cast<float>(sampleRate);
}
else if (!fileExists(fd)) {
/* Unfortunately this second check of file existence is needed
@@ 69,12 79,12 @@ namespace audio
LOG_WARN("File '%s' was deleted during playback!", filePath.c_str());
return fileDeletedRetCode;
}
- return samplesRead * channelCount;
+ return framesRead * channelCount;
}
- std::size_t DecoderWAV::drwavRead(void *pUserData, void *pBufferOut, std::size_t bytesToRead)
+ auto DecoderWAV::drwavRead(void *pUserData, void *pBufferOut, std::size_t bytesToRead) -> std::size_t
{
- const auto decoderContext = reinterpret_cast<DecoderWAV *>(pUserData);
+ const auto decoderContext = static_cast<DecoderWAV *>(pUserData);
/* Check if the file exists - std::fread happily returns bytesToRead if
* requested to read from deleted file, what causes decoding library
@@ 85,11 95,11 @@ namespace audio
return std::fread(pBufferOut, 1, bytesToRead, decoderContext->fd);
}
- drwav_bool32 DecoderWAV::drwavSeek(void *pUserData, int offset, drwav_seek_origin origin)
+ auto DecoderWAV::drwavSeek(void *pUserData, int offset, drwav_seek_origin origin) -> drwav_bool32
{
- const auto decoderContext = reinterpret_cast<DecoderWAV *>(pUserData);
+ const auto decoderContext = static_cast<DecoderWAV *>(pUserData);
const auto seekError =
- std::fseek(decoderContext->fd, offset, origin == drwav_seek_origin_start ? SEEK_SET : SEEK_CUR);
+ std::fseek(decoderContext->fd, offset, (origin == drwav_seek_origin_start) ? SEEK_SET : SEEK_CUR);
return (seekError == 0) ? DRWAV_TRUE : DRWAV_FALSE;
}
} // namespace audio
M module-audio/Audio/decoder/DecoderWAV.hpp => module-audio/Audio/decoder/DecoderWAV.hpp +7 -6
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#pragma once
@@ 12,11 12,12 @@ namespace audio
{
public:
explicit DecoderWAV(const std::string &filePath);
- ~DecoderWAV();
+ ~DecoderWAV() override;
- std::int32_t decode(std::uint32_t samplesToRead, std::int16_t *pcmData) override;
+ auto decode(std::uint32_t samplesToRead, std::int16_t *pcmData) -> std::int32_t override;
- void setPosition(float pos) override;
+ auto setPosition(float pos) -> void override;
+ auto rewind() -> void override;
private:
std::unique_ptr<drwav> wav;
@@ 31,7 32,7 @@ namespace audio
//
// A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback
// until either the entire bytesToRead is filled or you have reached the end of the stream.
- static std::size_t drwavRead(void *pUserData, void *pBufferOut, std::size_t bytesToRead);
+ static auto drwavRead(void *pUserData, void *pBufferOut, std::size_t bytesToRead) -> std::size_t;
// Callback for when data needs to be seeked.
//
@@ 44,6 45,6 @@ namespace audio
// The offset will never be negative. Whether it is relative to the beginning or current position is
// determined by the "origin" parameter which will be either drwav_seek_origin_start or
// drwav_seek_origin_current.
- static drwav_bool32 drwavSeek(void *pUserData, int offset, drwav_seek_origin origin);
+ static auto drwavSeek(void *pUserData, int offset, drwav_seek_origin origin) -> drwav_bool32;
};
} // namespace audio
M third-party/minimp3/minimp3 => third-party/minimp3/minimp3 +1 -1
@@ 1,1 1,1 @@
-Subproject commit e7202154493fb9dd8ca8c93f432003c4f191c5ae
+Subproject commit 3fd4dc273c4a5a19d12b4183220eaf0168b725bf