~aleteoryx/muditaos

9b7d5be07a1b1734cf18fb42ee829d8ba57bf827 — Lefucjusz 3 years ago 39482ff
[MOS-779] Fix music files extensions case sensitivity

Fix of the issue that only files with
extension in lowercase were detected
and listed in the music player's
library.
Additionally code cleanup.
M module-audio/Audio/Audio.cpp => module-audio/Audio/Audio.cpp +4 -4
@@ 59,12 59,12 @@ namespace audio

    audio::RetCode Audio::Start(Operation::Type op,
                                audio::Token token,
                                const char *fileName,
                                const std::string &filePath,
                                const audio::PlaybackType &playbackType)
    {

        try {
            auto ret = Operation::Create(op, fileName, playbackType, serviceCallback);
            auto ret = Operation::Create(op, filePath, playbackType, serviceCallback);
            switch (op) {
            case Operation::Type::Playback:
                currentState = State::Playback;


@@ 84,7 84,7 @@ namespace audio
        catch (const AudioInitException &audioException) {
            // If creating operation failed fallback to IdleOperation which is guaranteed to work
            LOG_ERROR(
                "Failed to create operation type %s, error message:\n%s", Operation::c_str(op), audioException.what());
                "Failed to create operation type %s, error message: %s", Operation::c_str(op), audioException.what());
            currentOperation = Operation::Create(Operation::Type::Idle);
            currentState     = State::Idle;
            return audioException.getErrorCode();


@@ 98,7 98,7 @@ namespace audio
        currentOperation->Stop();
        return Start(currentOperation->GetOperationType(),
                     currentOperation->GetToken(),
                     currentOperation->GetFilePath().c_str(),
                     currentOperation->GetFilePath(),
                     currentOperation->GetPlaybackType());
    }


M module-audio/Audio/Audio.hpp => module-audio/Audio/Audio.hpp +1 -1
@@ 98,7 98,7 @@ namespace audio
        // Operations
        virtual audio::RetCode Start(Operation::Type op,
                                     audio::Token token                      = audio::Token::MakeBadToken(),
                                     const char *fileName                    = "",
                                     const std::string &filePath             = "",
                                     const audio::PlaybackType &playbackType = audio::PlaybackType::None);

        virtual audio::RetCode Start();

M module-audio/Audio/Operation/IdleOperation.cpp => module-audio/Audio/Operation/IdleOperation.cpp +2 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "IdleOperation.hpp"


@@ 8,7 8,7 @@
namespace audio
{

    IdleOperation::IdleOperation([[maybe_unused]] const char *file) : Operation(nullptr)
    IdleOperation::IdleOperation([[maybe_unused]] const std::string &filePath) : Operation(nullptr)
    {
        supportedProfiles.emplace_back(Profile::Create(Profile::Type::Idle), true);
        currentProfile = supportedProfiles[0].profile;

M module-audio/Audio/Operation/IdleOperation.hpp => module-audio/Audio/Operation/IdleOperation.hpp +1 -3
@@ 4,8 4,6 @@
#pragma once

#include <memory>
#include <optional>
#include <functional>

#include "Operation.hpp"



@@ 15,7 13,7 @@ namespace audio
    class IdleOperation : public Operation
    {
      public:
        explicit IdleOperation([[maybe_unused]] const char *file);
        explicit IdleOperation([[maybe_unused]] const std::string &filePath);

        ~IdleOperation() = default;


M module-audio/Audio/Operation/Operation.cpp => module-audio/Audio/Operation/Operation.cpp +6 -6
@@ 16,7 16,7 @@
namespace audio
{
    std::unique_ptr<Operation> Operation::Create(Operation::Type t,
                                                 const char *fileName,
                                                 const std::string &filePath,
                                                 const audio::PlaybackType &playbackType,
                                                 AudioServiceMessage::Callback callback)
    {


@@ 24,21 24,21 @@ namespace audio

        switch (t) {
        case Type::Idle:
            inst = std::make_unique<IdleOperation>(fileName);
            inst = std::make_unique<IdleOperation>(filePath);
            break;
        case Type::Playback:
            inst = std::make_unique<PlaybackOperation>(fileName, playbackType, callback);
            inst = std::make_unique<PlaybackOperation>(filePath, playbackType, callback);
            break;
        case Type::Router:
            inst = std::make_unique<RouterOperation>(fileName, callback);
            inst = std::make_unique<RouterOperation>(filePath, callback);
            break;
        case Type::Recorder:
            inst = std::make_unique<RecorderOperation>(fileName, callback);
            inst = std::make_unique<RecorderOperation>(filePath, callback);
            break;
        }

        inst->opType   = t;
        inst->filePath = fileName;
        inst->filePath = filePath;
        return inst;
    }


M module-audio/Audio/Operation/Operation.hpp => module-audio/Audio/Operation/Operation.hpp +3 -4
@@ 11,7 11,6 @@
#include "Audio/AudioDeviceFactory.hpp"
#include "Audio/AudioPlatform.hpp"
#include "Audio/ServiceObserver.hpp"
#include "Audio/encoder/Encoder.hpp"
#include "Audio/Profiles/Profile.hpp"

namespace audio


@@ 21,7 20,7 @@ namespace audio
      public:
        explicit Operation(AudioServiceMessage::Callback callback,
                           const PlaybackType &playbackType = PlaybackType::None)
            : playbackType(playbackType), serviceCallback(callback), observer(serviceCallback)
            : playbackType(playbackType), serviceCallback(std::move(callback)), observer(serviceCallback)
        {
            factory = AudioPlatform::GetDeviceFactory();
            factory->setObserver(&observer);


@@ 60,7 59,7 @@ namespace audio
        virtual ~Operation() = default;

        static std::unique_ptr<Operation> Create(Type t,
                                                 const char *fileName                   = "",
                                                 const std::string &filePath            = "",
                                                 const audio::PlaybackType &operations  = audio::PlaybackType::None,
                                                 AudioServiceMessage::Callback callback = nullptr);



@@ 151,7 150,7 @@ namespace audio
        AudioServiceMessage::Callback serviceCallback;
        ServiceObserver observer;

        std::function<int32_t(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer)>
        std::function<std::int32_t(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer)>
            audioCallback = nullptr;

        void SetProfileAvailability(std::vector<Profile::Type> profiles, bool available);

M module-audio/Audio/Operation/PlaybackOperation.cpp => module-audio/Audio/Operation/PlaybackOperation.cpp +5 -3
@@ 16,7 16,9 @@ namespace audio

    using namespace AudioServiceMessage;

    PlaybackOperation::PlaybackOperation(const char *file, const audio::PlaybackType &playbackType, Callback callback)
    PlaybackOperation::PlaybackOperation(const std::string &filePath,
                                         const audio::PlaybackType &playbackType,
                                         Callback callback)
        : Operation(std::move(callback), playbackType), dec(nullptr)
    {
        // order defines priority


@@ 31,7 33,7 @@ namespace audio
            return std::string();
        };

        dec = Decoder::Create(file);
        dec = Decoder::Create(filePath);
        if (dec == nullptr) {
            throw AudioInitException("Error during initializing decoder", RetCode::FileDoesntExist);
        }


@@ 187,7 189,7 @@ namespace audio

        // adjust new profile with information from file's tags
        newProfile->SetSampleRate(dec->getSourceFormat().getSampleRate());
        newProfile->SetInOutFlags(static_cast<uint32_t>(audio::codec::Flags::OutputStereo));
        newProfile->SetInOutFlags(static_cast<std::uint32_t>(audio::codec::Flags::OutputStereo));

        /// profile change - (re)create output device; stop audio first by
        /// killing audio connection

M module-audio/Audio/Operation/PlaybackOperation.hpp => module-audio/Audio/Operation/PlaybackOperation.hpp +1 -1
@@ 23,7 23,7 @@ namespace audio
    class PlaybackOperation : public Operation
    {
      public:
        PlaybackOperation(const char *file,
        PlaybackOperation(const std::string &filePath,
                          const audio::PlaybackType &playbackType,
                          AudioServiceMessage::Callback callback = nullptr);


M module-audio/Audio/Operation/RecorderOperation.cpp => module-audio/Audio/Operation/RecorderOperation.cpp +12 -9
@@ 8,7 8,6 @@
#include "Audio/AudioCommon.hpp"

#include <log/log.hpp>
#include "FreeRTOS.h"

namespace audio
{


@@ 16,15 15,18 @@ namespace audio

#define PERF_STATS_ON 0

    RecorderOperation::RecorderOperation(const char *file, AudioServiceMessage::Callback callback) : Operation(callback)
    RecorderOperation::RecorderOperation(const std::string &filePath, AudioServiceMessage::Callback callback)
        : Operation(std::move(callback))
    {

        audioCallback = [this](const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer) -> int32_t {
        audioCallback = [this](const void *inputBuffer,
                               [[maybe_unused]] void *outputBuffer,
                               unsigned long framesPerBuffer) -> std::int32_t {

#if PERF_STATS_ON == 1
            auto tstamp = xTaskGetTickCount();
#endif
            auto ret = enc->Encode(framesPerBuffer, reinterpret_cast<int16_t *>(const_cast<void *>(inputBuffer)));
            auto ret = enc->Encode(framesPerBuffer, reinterpret_cast<std::int16_t *>(const_cast<void *>(inputBuffer)));
#if PERF_STATS_ON == 1
            LOG_DEBUG("Enc:%dms", xTaskGetTickCount() - tstamp);
            // LOG_DEBUG("Watermark:%lu",uxTaskGetStackHighWaterMark2(NULL));  M.P: left here on purpose, it's handy


@@ 49,16 51,17 @@ namespace audio
        }
        currentProfile = defaultProfile;

        uint32_t channels = 0;
        if ((currentProfile->GetInOutFlags() & static_cast<uint32_t>(audio::codec::Flags::InputLeft)) ||
            (currentProfile->GetInOutFlags() & static_cast<uint32_t>(audio::codec::Flags::InputRight))) {
        std::uint32_t channels = 0;
        if ((currentProfile->GetInOutFlags() & static_cast<std::uint32_t>(audio::codec::Flags::InputLeft)) ||
            (currentProfile->GetInOutFlags() & static_cast<std::uint32_t>(audio::codec::Flags::InputRight))) {
            channels = 1;
        }
        else if (currentProfile->GetInOutFlags() & static_cast<uint32_t>(audio::codec::Flags::InputStereo)) {
        else if (currentProfile->GetInOutFlags() & static_cast<std::uint32_t>(audio::codec::Flags::InputStereo)) {
            channels = 2;
        }

        enc = Encoder::Create(file, Encoder::Format{.chanNr = channels, .sampleRate = currentProfile->GetSampleRate()});
        enc = Encoder::Create(filePath,
                              Encoder::Format{.chanNr = channels, .sampleRate = currentProfile->GetSampleRate()});
        if (enc == nullptr) {
            throw AudioInitException("Error during initializing encoder", RetCode::InvalidFormat);
        }

M module-audio/Audio/Operation/RecorderOperation.hpp => module-audio/Audio/Operation/RecorderOperation.hpp +1 -1
@@ 12,7 12,7 @@ namespace audio
    class RecorderOperation : public Operation
    {
      public:
        RecorderOperation(const char *file, AudioServiceMessage::Callback callback);
        RecorderOperation(const std::string &filePath, AudioServiceMessage::Callback callback);

        audio::RetCode Start(audio::Token token) final;
        audio::RetCode Stop() final;

M module-audio/Audio/Operation/RouterOperation.cpp => module-audio/Audio/Operation/RouterOperation.cpp +3 -2
@@ 20,8 20,9 @@
namespace audio
{

    RouterOperation::RouterOperation([[maybe_unused]] const char *file, AudioServiceMessage::Callback callback)
        : Operation(callback)
    RouterOperation::RouterOperation([[maybe_unused]] const std::string &filePath,
                                     AudioServiceMessage::Callback callback)
        : Operation(std::move(callback))
    {
        // order defines priority
        AddProfile(Profile::Type::RoutingHeadphones, PlaybackType::None, false);

M module-audio/Audio/Operation/RouterOperation.hpp => module-audio/Audio/Operation/RouterOperation.hpp +1 -1
@@ 43,7 43,7 @@ namespace audio
        };

      public:
        RouterOperation(const char *file, AudioServiceMessage::Callback callback);
        RouterOperation(const std::string &filePath, AudioServiceMessage::Callback callback);
        ~RouterOperation();

        audio::RetCode Start(audio::Token token) final;

M module-audio/Audio/decoder/Decoder.cpp => module-audio/Audio/decoder/Decoder.cpp +20 -19
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <cstdio>


@@ 8,18 8,16 @@
#include "decoderFLAC.hpp"
#include "decoderWAV.hpp"

#include "fileref.h"
#include "tag.h"
#include "tfilestream.h"
#include <tags_fetcher/TagsFetcher.hpp>

namespace audio
{
    Decoder::Decoder(const char *fileName)
        : filePath(fileName), workerBuffer(std::make_unique<int16_t[]>(workerBufferSize))
    Decoder::Decoder(const std::string &path)
        : filePath(path), workerBuffer(std::make_unique<std::int16_t[]>(workerBufferSize))
    {
        fd = std::fopen(fileName, "r");
        if (fd == NULL) {
        fd = std::fopen(path.c_str(), "r");
        if (fd == nullptr) {
            return;
        }



@@ 40,7 38,7 @@ namespace audio
            audioWorker->close();
        }

        if (fd) {
        if (fd != nullptr) {
            std::fclose(fd);
        }
    }


@@ 50,17 48,21 @@ namespace audio
        return std::make_unique<tags::fetcher::Tags>(tags::fetcher::fetchTags(filePath));
    }

    std::unique_ptr<Decoder> Decoder::Create(const char *file)
    std::unique_ptr<Decoder> Decoder::Create(const std::string &filePath)
    {
        const auto extension          = std::filesystem::path(filePath).extension();
        const auto extensionLowercase = utils::stringToLowercase(extension);

        std::unique_ptr<Decoder> dec;
        if ((strstr(file, ".wav") != NULL) || (strstr(file, ".WAV") != NULL)) {
            dec = std::make_unique<decoderWAV>(file);

        if (extensionLowercase == ".wav") {
            dec = std::make_unique<decoderWAV>(filePath);
        }
        else if ((strstr(file, ".mp3") != NULL) || (strstr(file, ".MP3") != NULL)) {
            dec = std::make_unique<decoderMP3>(file);
        else if (extensionLowercase == ".mp3") {
            dec = std::make_unique<decoderMP3>(filePath);
        }
        else if ((strstr(file, ".flac") != NULL) || (strstr(file, ".FLAC") != NULL)) {
            dec = std::make_unique<decoderFLAC>(file);
        else if (extensionLowercase == ".flac") {
            dec = std::make_unique<decoderFLAC>(filePath);
        }
        else {
            return nullptr;


@@ 69,9 71,8 @@ namespace audio
        if (!dec->isInitialized) {
            return nullptr;
        }
        else {
            return dec;
        }

        return dec;
    }

    void Decoder::convertmono2stereo(int16_t *pcm, uint32_t samplecount)


@@ 88,7 89,7 @@ namespace audio
        memcpy(pcm, &workerBuffer[0], samplecount * 2 * sizeof(int16_t));
    }

    void Decoder::startDecodingWorker(DecoderWorker::EndOfFileCallback endOfFileCallback)
    void Decoder::startDecodingWorker(const DecoderWorker::EndOfFileCallback &endOfFileCallback)
    {
        assert(_stream != nullptr);
        if (!audioWorker) {

M module-audio/Audio/decoder/Decoder.hpp => module-audio/Audio/decoder/Decoder.hpp +13 -20
@@ 1,22 1,15 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "Audio/AudioCommon.hpp"
#include "Audio/Endpoint.hpp"
#include "Audio/Stream.hpp"
#include "DecoderWorker.hpp"

#include <log/log.hpp>

#include <memory>
#include <optional>
#include <string>
#include <vector>

#include <cstring>
#include <cstdint>
#include <tags_fetcher/TagsFetcher.hpp>

namespace audio


@@ 31,21 24,21 @@ namespace audio
    {

      public:
        Decoder(const char *fileName);
        Decoder(const std::string &path);

        virtual ~Decoder();

        virtual uint32_t decode(uint32_t samplesToRead, int16_t *pcmData) = 0;
        virtual std::uint32_t decode(std::uint32_t samplesToRead, std::int16_t *pcmData) = 0;

        // Range 0 - 1
        virtual void setPosition(float pos) = 0;

        uint32_t getSampleRate()
        std::uint32_t getSampleRate()
        {
            return sampleRate;
        }

        uint32_t getChannelNumber()
        std::uint32_t getChannelNumber()
        {
            return chanNumber;
        }


@@ 64,11 57,11 @@ namespace audio

        auto getTraits() const -> Endpoint::Traits override;

        void startDecodingWorker(DecoderWorker::EndOfFileCallback endOfFileCallback);
        void startDecodingWorker(const DecoderWorker::EndOfFileCallback &endOfFileCallback);
        void stopDecodingWorker();

        // Factory method
        static std::unique_ptr<Decoder> Create(const char *file);
        static std::unique_ptr<Decoder> Create(const std::string &path);

      protected:
        virtual auto getBitWidth() -> unsigned int


@@ 77,22 70,22 @@ namespace audio
        }
        virtual std::unique_ptr<tags::fetcher::Tags> fetchTags();

        void convertmono2stereo(int16_t *pcm, uint32_t samplecount);
        void convertmono2stereo(std::int16_t *pcm, std::uint32_t samplecount);

        static constexpr auto workerBufferSize        = 1024 * 8;
        static constexpr Endpoint::Traits decoderCaps = {.usesDMA = false};

        uint32_t sampleRate = 0;
        uint32_t chanNumber = 0;
        uint32_t bitsPerSample;
        std::uint32_t sampleRate = 0;
        std::uint32_t chanNumber = 0;
        std::uint32_t bitsPerSample;
        float position = 0;
        std::FILE *fd  = nullptr;
        std::unique_ptr<char[]> streamBuffer;
        uint32_t fileSize = 0;
        std::uint32_t fileSize = 0;
        std::string filePath;

        // Worker buffer used for converting mono stream to stereo
        std::unique_ptr<int16_t[]> workerBuffer;
        std::unique_ptr<std::int16_t[]> workerBuffer;
        std::unique_ptr<tags::fetcher::Tags> tags;
        bool isInitialized = false;


M module-audio/Audio/decoder/decoderFLAC.cpp => module-audio/Audio/decoder/decoderFLAC.cpp +21 -20
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <Utils.hpp>


@@ 15,15 15,15 @@
namespace audio
{

    decoderFLAC::decoderFLAC(const char *fileName) : Decoder(fileName)
    decoderFLAC::decoderFLAC(const std::string &filePath) : Decoder(filePath)
    {

        if (fileSize == 0) {
            return;
        }

        flac = drflac_open(drflac_read, drflac_seek, this, NULL);
        if (flac == NULL) {
        flac = drflac_open(drflac_read, drflac_seek, this, nullptr);
        if (flac == nullptr) {
            LOG_ERROR("Unable to initialize FLAC decoder");
            return;
        }



@@ 39,15 39,13 @@ namespace audio
        drflac_close(flac);
    }

    uint32_t decoderFLAC::decode(uint32_t samplesToRead, int16_t *pcmData)
    std::uint32_t decoderFLAC::decode(std::uint32_t samplesToRead, int16_t *pcmData)
    {

        uint32_t samples_read = 0;

        samples_read = drflac_read_pcm_frames_s16(flac, samplesToRead / chanNumber, (drflac_int16 *)pcmData);
        if (samples_read) {
        std::uint32_t samples_read =
            drflac_read_pcm_frames_s16(flac, samplesToRead / chanNumber, reinterpret_cast<drflac_int16 *>(pcmData));
        if (samples_read > 0) {
            /* Calculate frame duration in seconds */
            position += float(samples_read) / float(sampleRate);
            position += static_cast<float>(samples_read) / static_cast<float>(sampleRate);
        }

        return samples_read * chanNumber;


@@ 56,34 54,37 @@ namespace audio
    void decoderFLAC::setPosition(float pos)
    {
        if (!isInitialized) {
            LOG_ERROR("Wav decoder not initialized");
            LOG_ERROR("FLAC decoder not initialized");
            return;
        }
        drflac_seek_to_pcm_frame(flac, flac->totalPCMFrameCount * pos);

        // Calculate new position
        position = float(flac->totalPCMFrameCount) * pos / float(sampleRate);
        position = static_cast<float>(flac->totalPCMFrameCount) * pos / static_cast<float>(sampleRate);
    }

    /* Data encoded in UTF-8 */
    void decoderFLAC::flac_parse_text(uint8_t *in, uint32_t taglen, uint32_t datalen, uint8_t *out, uint32_t outlen)
    void decoderFLAC::flac_parse_text(
        std::uint8_t *in, std::uint32_t taglen, std::uint32_t datalen, std::uint8_t *out, std::uint32_t outlen)
    {
        /* Little Endian here. */
        uint32_t size = datalen - taglen > outlen - 1 ? outlen - 1 : datalen - taglen;
        std::uint32_t size = ((datalen - taglen) > (outlen - 1)) ? (outlen - 1) : (datalen - taglen);
        memcpy(out, in + taglen, size);
        out[size] = '\0';
    }

    size_t decoderFLAC::drflac_read(void *pUserData, void *pBufferOut, size_t bytesToRead)
    {
        decoderFLAC *userdata = (decoderFLAC *)pUserData;
        return std::fread(pBufferOut, 1, bytesToRead, userdata->fd);
        const auto decoderContext = reinterpret_cast<decoderFLAC *>(pUserData);
        return std::fread(pBufferOut, 1, bytesToRead, decoderContext->fd);
    }

    drflac_bool32 decoderFLAC::drflac_seek(void *pUserData, int offset, drflac_seek_origin origin)
    {
        decoderFLAC *userdata = (decoderFLAC *)pUserData;
        return !std::fseek(userdata->fd, offset, origin == drflac_seek_origin_start ? SEEK_SET : SEEK_CUR);
        const auto decoderContext = reinterpret_cast<decoderFLAC *>(pUserData);
        const int seekError =
            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 +2 -4
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 13,7 13,7 @@ namespace audio
    {

      public:
        decoderFLAC(const char *fileName);
        explicit decoderFLAC(const std::string &filePath);

        ~decoderFLAC();



@@ 24,8 24,6 @@ namespace audio
      private:
        drflac *flac = nullptr;

        uint32_t totalSamplesCount = 0;

        /* Data encoded in UTF-8 */
        void flac_parse_text(uint8_t *in, uint32_t taglen, uint32_t datalen, uint8_t *out, uint32_t outlen);


M module-audio/Audio/decoder/decoderMP3.cpp => module-audio/Audio/decoder/decoderMP3.cpp +20 -22
@@ 1,31 1,26 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#define DR_MP3_IMPLEMENTATION
#define DR_MP3_NO_STDIO

#include "decoderMP3.hpp"

#include <array>
#include <cstdio>

namespace audio
{

    decoderMP3::decoderMP3(const char *fileName) : Decoder(fileName)
    decoderMP3::decoderMP3(const std::string &filePath) : Decoder(filePath)
    {

        if (fileSize == 0) {
            return;
        }

        mp3 = std::make_unique<drmp3>();

        drmp3_init(mp3.get(), this->drmp3_read, this->drmp3_seek, this, NULL);
        if (mp3 == NULL) {
            LOG_ERROR("********************************** Unable to init mp3 decoder");
        drmp3_init(mp3.get(), drmp3_read, drmp3_seek, this, nullptr);
        if (mp3 == nullptr) {
            LOG_ERROR("Unable to initialize MP3 decoder");
            return;
            // Failed to open file
        }

        chanNumber = mp3->channels;


@@ 41,20 36,21 @@ namespace audio
    }
    void decoderMP3::setPosition(float pos)
    {
        if (!isInitialized) {
            LOG_ERROR("MP3 decoder not initialized");
            return;
        }
        auto totalFramesCount = drmp3_get_pcm_frame_count(mp3.get());
        drmp3_seek_to_pcm_frame(mp3.get(), totalFramesCount * pos);
        position = float(totalFramesCount) * pos / float(sampleRate);
        position = static_cast<float>(totalFramesCount) * pos / static_cast<float>(sampleRate);
    }

    uint32_t decoderMP3::decode(uint32_t samplesToRead, int16_t *pcmData)
    std::uint32_t decoderMP3::decode(std::uint32_t samplesToRead, std::int16_t *pcmData)
    {

        uint32_t samplesRead = 0;
        samplesRead =
        std::uint32_t samplesRead =
            drmp3_read_pcm_frames_s16(mp3.get(), samplesToRead / chanNumber, reinterpret_cast<drmp3_int16 *>(pcmData));

        if (samplesRead) {
            position += float(samplesRead) / float(sampleRate);
        if (samplesRead > 0) {
            position += static_cast<float>(samplesRead) / static_cast<float>(sampleRate);
        }

        return samplesRead * chanNumber;


@@ 62,14 58,16 @@ namespace audio

    size_t decoderMP3::drmp3_read(void *pUserData, void *pBufferOut, size_t bytesToRead)
    {
        auto *userdata = reinterpret_cast<decoderMP3 *>(pUserData);
        return std::fread(pBufferOut, 1, bytesToRead, userdata->fd);
        const auto decoderContext = reinterpret_cast<decoderMP3 *>(pUserData);
        return std::fread(pBufferOut, 1, bytesToRead, decoderContext->fd);
    }

    drmp3_bool32 decoderMP3::drmp3_seek(void *pUserData, int offset, drmp3_seek_origin origin)
    {
        auto *userdata = reinterpret_cast<decoderMP3 *>(pUserData);
        return !std::fseek(userdata->fd, offset, origin == drmp3_seek_origin_start ? SEEK_SET : SEEK_CUR);
        const auto decoderContext = reinterpret_cast<decoderMP3 *>(pUserData);
        const int seekError =
            std::fseek(decoderContext->fd, offset, origin == drmp3_seek_origin_start ? SEEK_SET : SEEK_CUR);
        return (seekError == 0) ? DRMP3_TRUE : DRMP3_FALSE;
    }

} // namespace audio

M module-audio/Audio/decoder/decoderMP3.hpp => module-audio/Audio/decoder/decoderMP3.hpp +4 -27
@@ 1,11 1,10 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "Decoder.hpp"
#include <src/dr_mp3.h>
#include <cstring>

extern "C"
{


@@ 19,22 18,16 @@ namespace audio
    {

      public:
        decoderMP3(const char *fileName);
        explicit decoderMP3(const std::string &filePath);

        ~decoderMP3();

        uint32_t decode(uint32_t samplesToRead, int16_t *pcmData) override;
        std::uint32_t decode(std::uint32_t samplesToRead, std::int16_t *pcmData) override;

        void setPosition(float pos) override;

      private:
        bool find_first_valid_frame();

        uint32_t get_frames_count();

        const uint32_t DECODER_BUFFER_SIZE = 1024 * 24;

        std::unique_ptr<drmp3> mp3;
        std::unique_ptr<drmp3> mp3 = nullptr;

        // Callback for when data needs to be read from the client.
        //


@@ 60,22 53,6 @@ namespace audio
        // determined by the "origin" parameter which will be either drflac_seek_origin_start or
        // drflac_seek_origin_current.
        static drmp3_bool32 drmp3_seek(void *pUserData, int offset, drmp3_seek_origin origin);
        //        std::unique_ptr<uint8_t[]> decoderBuffer = nullptr;
        //        uint32_t decoderBufferIdx                = 0;
        //
        //        std::unique_ptr<uint16_t[]> pcmsamplesbuffer = nullptr;
        //        uint32_t pcmsamplesbuffer_idx                = 0;
        //
        //        const size_t pcmsamplesbuffer_size = (8192 + MINIMP3_MAX_SAMPLES_PER_FRAME) * sizeof(int16_t);
        //
        //        uint32_t samplesPerFrame = 0;
        //
        //        // Variables below are used during decoding procedure
        //        uint32_t firstValidFrameByteSize   = 0;
        //        uint32_t firstValidFrameFileOffset = 0;
        //        bool lastRefill                    = false;
        //        bool decoderNotFirstRun            = false;
        //        uint32_t bytesAvailable            = 0;
    };

} // namespace audio

M module-audio/Audio/decoder/decoderWAV.cpp => module-audio/Audio/decoder/decoderWAV.cpp +7 -8
@@ 1,10 1,9 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "decoderWAV.hpp"
#include <log/log.hpp>
#include <memory>
#include "Audio/AudioCommon.hpp"

#define DR_WAV_IMPLEMENTATION
#include <src/dr_wav.h>


@@ 19,11 18,11 @@ namespace audio
        };
    } // namespace internal

    decoderWAV::decoderWAV(const char *fileName)
        : Decoder(fileName), decoderContext(std::make_unique<internal::wavContext>())
    decoderWAV::decoderWAV(const std::string &filePath)
        : Decoder(filePath), decoderContext(std::make_unique<internal::wavContext>())
    {
        auto dwav = &decoderContext->wav;
        if (!drwav_init_file(dwav, fileName, NULL)) {
        if (drwav_init_file(dwav, filePath.c_str(), nullptr) == DRWAV_FALSE) {
            LOG_ERROR("Unable to init wav decoder");
            return;
        }


@@ 43,7 42,7 @@ namespace audio
        }
    }

    uint32_t decoderWAV::decode(uint32_t samplesToRead, int16_t *pcmData)
    std::uint32_t decoderWAV::decode(std::uint32_t samplesToRead, std::int16_t *pcmData)
    {
        if (!isInitialized) {
            LOG_ERROR("Wav decoder not initialized");


@@ 53,7 52,7 @@ namespace audio
        const auto samples_read = drwav_read_pcm_frames_s16(dwav, samplesToRead / chanNumber, pcmData);
        if (samples_read) {
            /* Calculate frame duration in seconds */
            position += float(samplesToRead) / float(sampleRate);
            position += static_cast<float>(samplesToRead) / static_cast<float>(sampleRate);
        }
        return samples_read * chanNumber;
    }


@@ 68,6 67,6 @@ namespace audio
        drwav_seek_to_pcm_frame(dwav, dwav->totalPCMFrameCount * pos);

        // Calculate new position
        position = float(dwav->totalPCMFrameCount) * pos / float(sampleRate);
        position = static_cast<float>(dwav->totalPCMFrameCount) * pos / static_cast<float>(sampleRate);
    }
} // namespace audio

M module-audio/Audio/decoder/decoderWAV.hpp => module-audio/Audio/decoder/decoderWAV.hpp +3 -5
@@ 1,10 1,9 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "Decoder.hpp"
#include <vector>

namespace audio
{


@@ 15,15 14,14 @@ namespace audio
    class decoderWAV : public Decoder
    {
      public:
        explicit decoderWAV(const char *fileName);
        explicit decoderWAV(const std::string &filePath);
        virtual ~decoderWAV();

        uint32_t decode(uint32_t samplesToRead, int16_t *pcmData) override;
        std::uint32_t decode(std::uint32_t samplesToRead, std::int16_t *pcmData) override;

        void setPosition(float pos) override;

      private:
        std::vector<int32_t> pcmsamplesbuffer;
        std::unique_ptr<internal::wavContext> decoderContext;
    };


M module-audio/Audio/encoder/Encoder.cpp => module-audio/Audio/encoder/Encoder.cpp +16 -13
@@ 1,22 1,23 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "Encoder.hpp"
#include "EncoderWAV.hpp"

#include <stdint.h>
#include <Utils.hpp>

#include <string>
#include <memory>
#include <cstring>
#include <filesystem>

namespace audio
{

    Encoder::Encoder(const char *fileName, const Format &frmt) : format(frmt), filePath(fileName)
    Encoder::Encoder(const std::string &filePath, const Format &frmt) : format(frmt), filePath(filePath)
    {

        fd = std::fopen(fileName, "w");
        if (fd == NULL) {
        fd = std::fopen(filePath.c_str(), "w");
        if (fd == nullptr) {
            return;
        }
        constexpr size_t streamBufferSize = 6;


@@ 27,16 28,19 @@ namespace audio

    Encoder::~Encoder()
    {
        if (fd) {
        if (fd != nullptr) {
            std::fclose(fd);
        }
    }

    std::unique_ptr<Encoder> Encoder::Create(const char *file, const Format &frmt)
    std::unique_ptr<Encoder> Encoder::Create(const std::string &filePath, const Format &frmt)
    {
        const auto extension          = std::filesystem::path(filePath).extension();
        const auto extensionLowercase = utils::stringToLowercase(extension);

        std::unique_ptr<Encoder> enc;
        if ((strstr(file, ".wav") != NULL) || (strstr(file, ".WAV") != NULL)) {
            enc = std::make_unique<EncoderWAV>(file, frmt);
        if (extensionLowercase == ".wav") {
            enc = std::make_unique<EncoderWAV>(filePath, frmt);
        }
        else {
            return nullptr;


@@ 45,9 49,8 @@ namespace audio
        if (enc->isInitialized) {
            return enc;
        }
        else {
            return nullptr;
        }

        return nullptr;
    }

} // namespace audio

M module-audio/Audio/encoder/Encoder.hpp => module-audio/Audio/encoder/Encoder.hpp +8 -8
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 15,24 15,24 @@ namespace audio
      public:
        struct Format
        {
            uint32_t chanNr;
            uint32_t sampleRate;
            std::uint32_t chanNr;
            std::uint32_t sampleRate;
        };

        static std::unique_ptr<Encoder> Create(const char *file, const Format &frmt);
        static std::unique_ptr<Encoder> Create(const std::string &filePath, const Format &frmt);

        Encoder(const char *file, const Format &frmt);
        Encoder(const std::string &filePath, const Format &frmt);

        virtual ~Encoder();

        virtual uint32_t Encode(uint32_t samplesToWrite, int16_t *pcmData) = 0;
        virtual std::uint32_t Encode(std::uint32_t samplesToWrite, std::int16_t *pcmData) = 0;

        float getCurrentPosition()
        {
            return position;
        }

        uint32_t GetFileSize()
        std::uint32_t GetFileSize()
        {
            return fileSize;
        }


@@ 43,7 43,7 @@ namespace audio
        float position = 0;
        std::FILE *fd  = nullptr;
        std::unique_ptr<char[]> streamBuffer;
        uint32_t fileSize = 0;
        std::uint32_t fileSize = 0;
        std::string filePath;

        bool isInitialized = false;

M module-audio/Audio/encoder/EncoderWAV.cpp => module-audio/Audio/encoder/EncoderWAV.cpp +27 -38
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "EncoderWAV.hpp"


@@ 7,7 7,7 @@
namespace audio
{

    EncoderWAV::EncoderWAV(const char *fileName, const Encoder::Format &frmt) : Encoder(fileName, frmt)
    EncoderWAV::EncoderWAV(const std::string &filePath, const Encoder::Format &frmt) : Encoder(filePath, frmt)
    {

        WAVE_FormatTypeDef WaveFormat = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};


@@ 35,28 35,25 @@ namespace audio
        }
    }

    uint32_t EncoderWAV::Encode(uint32_t samplesToWrite, int16_t *pcmData)
    std::uint32_t EncoderWAV::Encode(std::uint32_t samplesToWrite, std::int16_t *pcmData)
    {
        /*
         * Write int16_t PCM samples to file.
         */
        auto byteswritten = std::fwrite(pcmData, sizeof(int16_t), samplesToWrite, fd);
        auto byteswritten = std::fwrite(pcmData, sizeof(std::int16_t), samplesToWrite, fd);
        if (byteswritten != samplesToWrite) {
            return 0;
        }

        /* Calculate frame duration in seconds */
        position += (float)((float)(samplesToWrite / format.chanNr) / (float)(format.sampleRate));
        position += static_cast<float>(samplesToWrite / format.chanNr) / static_cast<float>(format.sampleRate);
        return byteswritten;
    }

    void EncoderWAV::HeaderInit(const EncoderWAV::WAVE_FormatTypeDef &pWaveFormatStruct)
    {
        /* Write chunkID, must be 'RIFF'  ------------------------------------------*/
        pHeaderBuff[0] = 'R';
        pHeaderBuff[1] = 'I';
        pHeaderBuff[2] = 'F';
        pHeaderBuff[3] = 'F';
        memcpy(&pHeaderBuff[0], "RIFF", 4);

        /* Write the file length ---------------------------------------------------*/
        /* The sampling time: this value will be written back at the end of the


@@ 65,17 62,12 @@ namespace audio
        pHeaderBuff[5] = 0x4C;
        pHeaderBuff[6] = 0x1D;
        pHeaderBuff[7] = 0x00;

        /* Write the file format, must be 'WAVE' -----------------------------------*/
        pHeaderBuff[8]  = 'W';
        pHeaderBuff[9]  = 'A';
        pHeaderBuff[10] = 'V';
        pHeaderBuff[11] = 'E';
        memcpy(&pHeaderBuff[8], "WAVE", 4);

        /* Write the format chunk, must be'fmt ' -----------------------------------*/
        pHeaderBuff[12] = 'f';
        pHeaderBuff[13] = 'm';
        pHeaderBuff[14] = 't';
        pHeaderBuff[15] = ' ';
        /* Write the format chunk, must be 'fmt ' -----------------------------------*/
        memcpy(&pHeaderBuff[12], "fmt ", 4);

        /* Write the length of the 'fmt' data, must be 0x10 ------------------------*/
        pHeaderBuff[16] = 0x10;


@@ 93,16 85,16 @@ namespace audio

        /* Write the Sample Rate in Hz ---------------------------------------------*/
        /* Write Little Endian ie. 8000 = 0x00001F40 => byte[24]=0x40, byte[27]=0x00*/
        pHeaderBuff[24] = (uint8_t)((pWaveFormatStruct.SampleRate & 0xFF));
        pHeaderBuff[25] = (uint8_t)((pWaveFormatStruct.SampleRate >> 8) & 0xFF);
        pHeaderBuff[26] = (uint8_t)((pWaveFormatStruct.SampleRate >> 16) & 0xFF);
        pHeaderBuff[27] = (uint8_t)((pWaveFormatStruct.SampleRate >> 24) & 0xFF);
        pHeaderBuff[24] = (std::uint8_t)((pWaveFormatStruct.SampleRate & 0xFF));
        pHeaderBuff[25] = (std::uint8_t)((pWaveFormatStruct.SampleRate >> 8) & 0xFF);
        pHeaderBuff[26] = (std::uint8_t)((pWaveFormatStruct.SampleRate >> 16) & 0xFF);
        pHeaderBuff[27] = (std::uint8_t)((pWaveFormatStruct.SampleRate >> 24) & 0xFF);

        /* Write the Byte Rate -----------------------------------------------------*/
        pHeaderBuff[28] = (uint8_t)((pWaveFormatStruct.ByteRate & 0xFF));
        pHeaderBuff[29] = (uint8_t)((pWaveFormatStruct.ByteRate >> 8) & 0xFF);
        pHeaderBuff[30] = (uint8_t)((pWaveFormatStruct.ByteRate >> 16) & 0xFF);
        pHeaderBuff[31] = (uint8_t)((pWaveFormatStruct.ByteRate >> 24) & 0xFF);
        pHeaderBuff[28] = (std::uint8_t)((pWaveFormatStruct.ByteRate & 0xFF));
        pHeaderBuff[29] = (std::uint8_t)((pWaveFormatStruct.ByteRate >> 8) & 0xFF);
        pHeaderBuff[30] = (std::uint8_t)((pWaveFormatStruct.ByteRate >> 16) & 0xFF);
        pHeaderBuff[31] = (std::uint8_t)((pWaveFormatStruct.ByteRate >> 24) & 0xFF);

        /* Write the block alignment -----------------------------------------------*/
        pHeaderBuff[32] = pWaveFormatStruct.BlockAlign;


@@ 113,10 105,7 @@ namespace audio
        pHeaderBuff[35] = 0x00;

        /* Write the Data chunk, must be 'data' ------------------------------------*/
        pHeaderBuff[36] = 'd';
        pHeaderBuff[37] = 'a';
        pHeaderBuff[38] = 't';
        pHeaderBuff[39] = 'a';
        memcpy(&pHeaderBuff[36], "data", 4);

        /* Write the number of sample data -----------------------------------------*/
        /* This variable will be written back at the end of the recording operation */


@@ 131,17 120,17 @@ namespace audio
        /* Write the file length ---------------------------------------------------*/
        /* The sampling time: this value will be written back at the end of the
           recording operation.  Example: 661500 Btyes = 0x000A17FC, byte[7]=0x00, byte[4]=0xFC */
        pHeaderBuff[4] = (uint8_t)(fileSize);
        pHeaderBuff[5] = (uint8_t)(fileSize >> 8);
        pHeaderBuff[6] = (uint8_t)(fileSize >> 16);
        pHeaderBuff[7] = (uint8_t)(fileSize >> 24);
        pHeaderBuff[4] = (std::uint8_t)(fileSize);
        pHeaderBuff[5] = (std::uint8_t)(fileSize >> 8);
        pHeaderBuff[6] = (std::uint8_t)(fileSize >> 16);
        pHeaderBuff[7] = (std::uint8_t)(fileSize >> 24);
        /* Write the number of sample data -----------------------------------------*/
        /* This variable will be written back at the end of the recording operation */
        fileSize -= 44;
        pHeaderBuff[40] = (uint8_t)(fileSize);
        pHeaderBuff[41] = (uint8_t)(fileSize >> 8);
        pHeaderBuff[42] = (uint8_t)(fileSize >> 16);
        pHeaderBuff[43] = (uint8_t)(fileSize >> 24);
        pHeaderBuff[40] = (std::uint8_t)(fileSize);
        pHeaderBuff[41] = (std::uint8_t)(fileSize >> 8);
        pHeaderBuff[42] = (std::uint8_t)(fileSize >> 16);
        pHeaderBuff[43] = (std::uint8_t)(fileSize >> 24);
    }

} // namespace audio

M module-audio/Audio/encoder/EncoderWAV.hpp => module-audio/Audio/encoder/EncoderWAV.hpp +17 -17
@@ 11,36 11,36 @@ namespace audio
    class EncoderWAV : public Encoder
    {
      public:
        EncoderWAV(const char *fileName, const Encoder::Format &frmt);
        EncoderWAV(const std::string &filePath, const Encoder::Format &frmt);

        ~EncoderWAV();

        uint32_t Encode(uint32_t samplesToWrite, int16_t *pcmData) override final;
        std::uint32_t Encode(std::uint32_t samplesToWrite, std::int16_t *pcmData) override final;

      private:
        using WAVE_FormatTypeDef = struct
        {
            uint32_t ChunkID;       /* 0 */
            uint32_t FileSize;      /* 4 */
            uint32_t FileFormat;    /* 8 */
            uint32_t SubChunk1ID;   /* 12 */
            uint32_t SubChunk1Size; /* 16*/
            uint16_t AudioFormat;   /* 20 */
            uint16_t NbrChannels;   /* 22 */
            uint32_t SampleRate;    /* 24 */

            uint32_t ByteRate;      /* 28 */
            uint16_t BlockAlign;    /* 32 */
            uint16_t BitPerSample;  /* 34 */
            uint32_t SubChunk2ID;   /* 36 */
            uint32_t SubChunk2Size; /* 40 */
            std::uint32_t ChunkID;       /* 0 */
            std::uint32_t FileSize;      /* 4 */
            std::uint32_t FileFormat;    /* 8 */
            std::uint32_t SubChunk1ID;   /* 12 */
            std::uint32_t SubChunk1Size; /* 16*/
            std::uint16_t AudioFormat;   /* 20 */
            std::uint16_t NbrChannels;   /* 22 */
            std::uint32_t SampleRate;    /* 24 */

            std::uint32_t ByteRate;      /* 28 */
            std::uint16_t BlockAlign;    /* 32 */
            std::uint16_t BitPerSample;  /* 34 */
            std::uint32_t SubChunk2ID;   /* 36 */
            std::uint32_t SubChunk2Size; /* 40 */
        };

        void HeaderInit(const WAVE_FormatTypeDef &pWaveFormatStruct);

        void HeaderUpdate();

        uint8_t pHeaderBuff[44] = {0};
        std::uint8_t pHeaderBuff[44] = {0};
    };

} // namespace audio

M module-audio/Audio/test/unittest_audio.cpp => module-audio/Audio/test/unittest_audio.cpp +2 -1
@@ 184,7 184,8 @@ class MockRouterOperation : public RouterOperation

  public:
    /* value - volume and gain value */
    explicit MockRouterOperation(AudioServiceMessage::Callback callback) : RouterOperation(nullptr, callback)
    explicit MockRouterOperation(AudioServiceMessage::Callback callback)
        : RouterOperation(std::string(""), std::move(callback))
    {}

    std::optional<Profile::Type> getPriorityProfile() const

M module-services/service-audio/ServiceAudio.cpp => module-services/service-audio/ServiceAudio.cpp +1 -1
@@ 408,7 408,7 @@ std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleStart(const Operation:

            if (IsOperationEnabled(playbackType, opType)) {
                try {
                    retCode = (*input)->audio->Start(opType, retToken, fileName.c_str(), playbackType);
                    retCode = (*input)->audio->Start(opType, retToken, fileName, playbackType);
                }
                catch (const AudioInitException &audioException) {
                    retCode = audio::RetCode::FailedToAllocateMemory;

M module-services/service-fileindexer/InotifyHandler.cpp => module-services/service-fileindexer/InotifyHandler.cpp +9 -8
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <service-fileindexer/InotifyHandler.hpp>


@@ 13,6 13,7 @@
#include <purefs/fs/inotify.hpp>
#include <service-db/DBServiceAPI.hpp>
#include <tags_fetcher/TagsFetcher.hpp>
#include <Utils.hpp>

namespace service::detail
{


@@ 88,7 89,7 @@ namespace service::detail
    {
        std::string getMimeType(const fs::path &path)
        {
            auto extension = path.extension();
            const auto extension = utils::stringToLowercase(path.extension());

            if (extension == ".mp3") {
                return "audio/mpeg";


@@ 147,9 148,9 @@ namespace service::detail
            return;
        }

        auto ext = fs::path(path).extension();
        if (!isExtSupported(ext)) {
            LOG_WARN("Not supported ext - %s", ext.c_str());
        const auto extension = utils::stringToLowercase(fs::path(path).extension());
        if (!isExtSupported(extension)) {
            LOG_WARN("Not supported extension - %s", extension.c_str());
            return;
        }



@@ 172,9 173,9 @@ namespace service::detail
            return;
        }

        auto ext = fs::path(path).extension();
        if (!isExtSupported(ext)) {
            LOG_WARN("Not supported ext - %s", ext.c_str());
        const auto extension = utils::stringToLowercase(fs::path(path).extension());
        if (!isExtSupported(extension)) {
            LOG_WARN("Not supported extension - %s", extension.c_str());
            return;
        }


M module-utils/utility/Utils.cpp => module-utils/utility/Utils.cpp +1 -0
@@ 7,6 7,7 @@

#include <ctime>
#include <filesystem>
#include <random>

namespace utils::filesystem
{

M module-utils/utility/Utils.hpp => module-utils/utility/Utils.hpp +7 -2
@@ 6,11 6,9 @@
#include <log/log.hpp>
#include <magic_enum.hpp>

#include <algorithm> // std::find_if_not
#include <sstream>
#include <iomanip>
#include <cmath>
#include <chrono>
#include <random>
#include <tuple>
#include <type_traits>


@@ 312,6 310,13 @@ namespace utils
        findAndReplaceAll(data, {{toSearch, replaceStr}});
    }

    static inline std::string stringToLowercase(const std::string &inputString)
    {
        std::string outputString;
        std::for_each(inputString.begin(), inputString.end(), [&](char ch) { outputString += std::tolower(ch); });
        return outputString;
    }

    static inline std::tuple<uint8_t, uint8_t, uint8_t> floatingPointConverter(float value)
    {
        int32_t decimal = value * (1 << 20); // multiply by 2^20

M pure_changelog.md => pure_changelog.md +1 -0
@@ 8,6 8,7 @@
* Separated system volume from Bluetooth device volume for A2DP
* Made windows flow in SIM cards settings more robust
* Improve refreshing of the display.
* Fixed music files extension case sensitivity

### Fixed
* Fixed wrong time displayed on password locked screen with 'Quotes' or 'Logo' wallpaper