// 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 #include #include "Decoder.hpp" #include "DecoderMP3.hpp" #include "DecoderFLAC.hpp" #include "DecoderWAV.hpp" #include "tag.h" #include namespace audio { Decoder::Decoder(const std::string &path) : filePath(path) { fd = std::fopen(path.c_str(), "rb"); if (fd == nullptr) { return; } constexpr std::size_t streamBufferSize = 16 * 1024; streamBuffer = std::make_unique(streamBufferSize); setvbuf(fd, streamBuffer.get(), _IOFBF, streamBufferSize); std::fseek(fd, 0, SEEK_END); fileSize = std::ftell(fd); std::rewind(fd); tags = fetchTags(); } Decoder::~Decoder() { if (audioWorker) { audioWorker->close(); } if (fd != nullptr) { std::fclose(fd); } } auto Decoder::fetchTags() -> std::unique_ptr { return std::make_unique(tags::fetcher::fetchTags(filePath)); } auto Decoder::Create(const std::string &filePath) -> std::unique_ptr { const auto extension = std::filesystem::path(filePath).extension(); const auto extensionLowercase = utils::stringToLowercase(extension); std::unique_ptr dec; if (extensionLowercase == ".wav") { dec = std::make_unique(filePath); } else if (extensionLowercase == ".mp3") { dec = std::make_unique(filePath); } else if (extensionLowercase == ".flac") { dec = std::make_unique(filePath); } else { return nullptr; } if (!dec->isInitialized) { return nullptr; } return dec; } 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; audioWorker = std::make_unique(_stream, this, endOfFileCallback, fileDeletedCallback, channelMode); audioWorker->init(); audioWorker->run(); } else { LOG_DEBUG("AudioWorker already running."); } } auto Decoder::stopDecodingWorker() -> void { if (audioWorker) { audioWorker->close(); } audioWorker = nullptr; } auto Decoder::onDataReceive() -> void { audioWorker->enablePlayback(); } auto Decoder::enableInput() -> void { audioWorker->enablePlayback(); } auto Decoder::disableInput() -> void { audioWorker->disablePlayback(); } auto Decoder::getSourceFormat() -> AudioFormat { auto bitWidth = getBitWidth(); // this is a decoder mono to stereo hack, will be removed when proper // transcoding implementation is added auto channels = (tags->num_channel == 1) ? 2U : tags->num_channel; return AudioFormat{tags->sample_rate, bitWidth, channels}; } auto Decoder::getSupportedFormats() -> std::vector { return std::vector{getSourceFormat()}; } auto Decoder::getTraits() const -> Endpoint::Traits { return Endpoint::Traits{}; } } // namespace audio