~aleteoryx/muditaos

b64f8283a7342b5362fded7c68706ea5ea961ee5 — Przemyslaw Brudny 4 years ago cd700b7 + e00b5ef
Merge remote-tracking branch 'origin/stable'
83 files changed, 1288 insertions(+), 568 deletions(-)

M board/rt1051/crashdump/crashcatcher_impl.cpp
D board/rt1051/crashdump/crashdumpwriter.hpp
M board/rt1051/crashdump/crashdumpwriter_vfs.cpp
M board/rt1051/crashdump/crashdumpwriter_vfs.hpp
M image/user/db/settings_bell_002.sql
M module-apps/apps-common/widgets/ProgressTimer.cpp
M module-audio/Audio/AudioCommon.hpp
M module-audio/Audio/AudioMux.cpp
M module-audio/board/rt1051/bellpx/BellPxAudioCodec.cpp
M module-bsp/board/rt1051/bellpx/bsp/audio/AW8898driver.cpp
M module-bsp/board/rt1051/bellpx/bsp/audio/CodecAW8898.cpp
M module-bsp/board/rt1051/bellpx/bsp/audio/CodecAW8898.hpp
M module-bsp/board/rt1051/bellpx/bsp/switches/switches.cpp
M module-vfs/drivers/src/purefs/fs/filesystem_ext4.cpp
M module-vfs/drivers/src/thirdparty/lwext4/ext4_bdev.cpp
M products/BellHybrid/BellHybridMain.cpp
M products/BellHybrid/CMakeLists.txt
M products/BellHybrid/alarms/CMakeLists.txt
M products/BellHybrid/alarms/include/BellAlarmHandler.hpp
M products/BellHybrid/alarms/src/actions/PlayAudioActions.cpp
M products/BellHybrid/alarms/src/actions/PlayAudioActions.hpp
M products/BellHybrid/apps/application-bell-background-sounds/ApplicationBellBackgroundSounds.cpp
M products/BellHybrid/apps/application-bell-background-sounds/CMakeLists.txt
M products/BellHybrid/apps/application-bell-background-sounds/data/BGSoundsCommon.hpp
M products/BellHybrid/apps/application-bell-background-sounds/include/application-bell-background-sounds/ApplicationBellBackgroundSounds.hpp
M products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsProgressPresenter.cpp
M products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsProgressPresenter.hpp
M products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsTimerSelectPresenter.hpp
M products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsVolumePresenter.cpp
M products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsVolumePresenter.hpp
M products/BellHybrid/apps/application-bell-background-sounds/widgets/BGSoundsPlayer.cpp
M products/BellHybrid/apps/application-bell-background-sounds/widgets/BGSoundsPlayer.hpp
M products/BellHybrid/apps/application-bell-background-sounds/windows/BGSoundsProgressWindow.cpp
M products/BellHybrid/apps/application-bell-background-sounds/windows/BGSoundsVolumeWindow.cpp
M products/BellHybrid/apps/application-bell-background-sounds/windows/BGSoundsVolumeWindow.hpp
M products/BellHybrid/apps/application-bell-bedtime/ApplicationBellBedtime.cpp
M products/BellHybrid/apps/application-bell-main/ApplicationBellMain.cpp
M products/BellHybrid/apps/application-bell-meditation-timer/CMakeLists.txt
M products/BellHybrid/apps/application-bell-meditation-timer/windows/MeditationRunningWindow.cpp
M products/BellHybrid/apps/application-bell-powernap/ApplicationBellPowerNap.cpp
M products/BellHybrid/apps/application-bell-powernap/presenter/PowerNapProgressPresenter.cpp
M products/BellHybrid/apps/application-bell-powernap/presenter/PowerNapProgressPresenter.hpp
M products/BellHybrid/apps/application-bell-settings/ApplicationBellSettings.cpp
M products/BellHybrid/apps/application-bell-settings/CMakeLists.txt
M products/BellHybrid/apps/application-bell-settings/models/advanced/FrontlightModel.cpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AlarmSettingsModel.cpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AlarmSettingsModel.hpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.cpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.hpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeSettingsModel.cpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeSettingsModel.hpp
M products/BellHybrid/apps/application-bell-settings/presenter/BedtimeSettingsPresenter.cpp
M products/BellHybrid/apps/application-bell-settings/presenter/BedtimeSettingsPresenter.hpp
M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/AlarmSettingsPresenter.cpp
M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/AlarmSettingsPresenter.hpp
M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/PrewakeUpPresenter.cpp
M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/PrewakeUpPresenter.hpp
M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/SnoozePresenter.cpp
M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/SnoozePresenter.hpp
M products/BellHybrid/apps/application-bell-settings/windows/BellSettingsBedtimeToneWindow.cpp
M products/BellHybrid/apps/application-bell-settings/windows/alarm_settings/BellSettingsAlarmSettingsSnoozeWindow.cpp
M products/BellHybrid/apps/application-bell-settings/windows/alarm_settings/BellSettingsAlarmSettingsWindow.cpp
M products/BellHybrid/apps/application-bell-settings/windows/alarm_settings/BellSettingsPrewakeUpWindow.cpp
M products/BellHybrid/apps/common/CMakeLists.txt
M products/BellHybrid/apps/common/include/common/models/AbstractAudioModel.hpp
M products/BellHybrid/apps/common/include/common/models/AbstractSettingsModel.hpp
M products/BellHybrid/apps/common/include/common/models/AudioModel.hpp
M products/BellHybrid/apps/common/include/common/models/BedtimeModel.hpp
M products/BellHybrid/apps/common/src/AudioModel.cpp
M products/BellHybrid/apps/common/src/models/BedtimeModel.cpp
M products/BellHybrid/apps/common/src/popups/BedtimeNotificationWindow.cpp
M products/BellHybrid/services/CMakeLists.txt
A products/BellHybrid/services/audio/CMakeLists.txt
A products/BellHybrid/services/audio/ServiceAudio.cpp
A products/BellHybrid/services/audio/include/audio/AudioMessage.hpp
A products/BellHybrid/services/audio/include/audio/ServiceAudio.hpp
M products/BellHybrid/services/db/include/db/SystemSettings.hpp
M products/BellHybrid/services/evtmgr/CMakeLists.txt
M products/BellHybrid/services/evtmgr/EventManager.cpp
M products/BellHybrid/services/evtmgr/WorkerEvent.cpp
M products/BellHybrid/services/evtmgr/include/evtmgr/EventManager.hpp
A products/BellHybrid/services/evtmgr/include/evtmgr/user-activity-handler/UserActivityHandler.hpp
A products/BellHybrid/services/evtmgr/user-activity-handler/UserActivityHandler.cpp
M board/rt1051/crashdump/crashcatcher_impl.cpp => board/rt1051/crashdump/crashcatcher_impl.cpp +15 -15
@@ 7,24 7,25 @@

#include <log/log.hpp>
#include <date/date.h>
#include "crashdumpwriter.hpp"
#include "crashdumpwriter_vfs.hpp"
#include "consoledump.hpp"

namespace
{
    crashdump::CrashDumpWriterVFS cwrite;
}

const CrashCatcherMemoryRegion *CrashCatcher_GetMemoryRegions(void)
{
    // board/rt1051/ldscripts/memory.ld
    /* board/rt1051/ldscripts/memory.ld
     * NOTE: Text section and stacks sections are intentionally ommited
     * because can cause throubles in the running system
     */
    static const CrashCatcherMemoryRegion regions[] = {
        // SRAM_OC
        {0x20200000, 0x20210000, CRASH_CATCHER_BYTE},
        // SRAM_DTC
        {0x20000000, 0x20070000, CRASH_CATCHER_BYTE},
    // intentionally skip text section
    // BOARD_SDRAM_HEAP
#if defined(HW_SDRAM_64_MB) && (HW_SDRAM_64_MB == 1)
        {0x80620000, 0x84000000, CRASH_CATCHER_BYTE},
#else
        {0x80620000, 0x81000000, CRASH_CATCHER_BYTE},
#endif
        // end tag
        {0xFFFFFFFF, 0xFFFFFFFF, CRASH_CATCHER_BYTE},
    };


@@ 35,28 36,27 @@ const CrashCatcherMemoryRegion *CrashCatcher_GetMemoryRegions(void)
void CrashCatcher_DumpStart(const CrashCatcherInfo *pInfo)
{
    crashdump::printCrashInfo(pInfo);
    crashdump::CrashDumpWriter::instance().openDump();
    cwrite.openDump();
}

void CrashCatcher_DumpMemory(const void *pvMemory, CrashCatcherElementSizes elementSize, size_t elementCount)
{
    switch (elementSize) {
    case CRASH_CATCHER_BYTE:
        crashdump::CrashDumpWriter::instance().writeBytes(static_cast<const std::uint8_t *>(pvMemory), elementCount);
        cwrite.writeBytes(static_cast<const std::uint8_t *>(pvMemory), elementCount);
        break;
    case CRASH_CATCHER_HALFWORD:
        crashdump::CrashDumpWriter::instance().writeHalfWords(static_cast<const std::uint16_t *>(pvMemory),
                                                              elementCount);
        cwrite.writeHalfWords(static_cast<const std::uint16_t *>(pvMemory), elementCount);
        break;
    case CRASH_CATCHER_WORD:
        crashdump::CrashDumpWriter::instance().writeWords(static_cast<const std::uint32_t *>(pvMemory), elementCount);
        cwrite.writeWords(static_cast<const std::uint32_t *>(pvMemory), elementCount);
        break;
    }
}

CrashCatcherReturnCodes CrashCatcher_DumpEnd(void)
{
    crashdump::CrashDumpWriter::instance().saveDump();
    cwrite.saveDump();
    abort();
    return CRASH_CATCHER_EXIT;
}

D board/rt1051/crashdump/crashdumpwriter.hpp => board/rt1051/crashdump/crashdumpwriter.hpp +0 -25
@@ 1,25 0,0 @@
// 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 <cstdint>

namespace crashdump
{
    class CrashDumpWriter
    {
      public:
        static CrashDumpWriter &instance();

        virtual ~CrashDumpWriter() = default;

        virtual void openDump() = 0;
        virtual void saveDump() = 0;

        virtual void writeBytes(const std::uint8_t *buff, std::size_t size)      = 0;
        virtual void writeHalfWords(const std::uint16_t *buff, std::size_t size) = 0;
        virtual void writeWords(const std::uint32_t *buff, std::size_t size)     = 0;
    };

} // namespace crashdump

M board/rt1051/crashdump/crashdumpwriter_vfs.cpp => board/rt1051/crashdump/crashdumpwriter_vfs.cpp +24 -19
@@ 3,12 3,15 @@

#include "crashdumpwriter_vfs.hpp"

#include <cstdio>
#include <log/log.hpp>
#include <fcntl.h>
#include "purefs/vfs_subsystem.hpp"
#include <purefs/filesystem_paths.hpp>

#include <filesystem>
#include <stdint.h>
#include <unistd.h>

namespace crashdump
{


@@ 16,47 19,49 @@ namespace crashdump

    void CrashDumpWriterVFS::openDump()
    {
        vfs                          = purefs::subsystem::vfs_core();
        const auto crashDumpFilePath = purefs::dir::getCrashDumpsPath() / crashDumpFileName;

        LOG_INFO("Crash dump %s preparing ...", crashDumpFilePath.c_str());
        if (!rotator.rotateFile(crashDumpFilePath)) {
            LOG_FATAL("Failed to rotate crash dumps.");
            LOG_FATAL("Failed to rotate crash dumps errno: %i", errno);
            std::abort();
        }
        dumpFd = vfs->open(crashDumpFilePath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);

        if (dumpFd < 0) {
            LOG_FATAL("Failed to open crash dump file. Won't be able to save crash info.");
        file = std::fopen(crashDumpFilePath.c_str(), "w");
        if (!file) {
            LOG_FATAL("Failed to open crash dump file errno %i", errno);
            std::abort();
        }
    }

    void CrashDumpWriterVFS::saveDump()
    {
        vfs->close(dumpFd);
        LOG_INFO("Crash dump create finished.");
        fflush(file);
        fsync(fileno(file));
        std::fclose(file);
    }

    void CrashDumpWriterVFS::writeBytes(const uint8_t *buff, std::size_t size)
    {
        vfs->write(dumpFd, reinterpret_cast<const char *>(buff), size);
        if (std::fwrite(buff, sizeof(*buff), size, file) != size) {
            LOG_FATAL("Unable to write crash dump errno: %i", errno);
            std::abort();
        }
    }

    void CrashDumpWriterVFS::writeHalfWords(const uint16_t *buff, std::size_t size)
    {
        for (std::size_t n = 0; n < size; ++n) {
            writeBytes(reinterpret_cast<const uint8_t *>(buff + n), sizeof(uint16_t));
        if (std::fwrite(buff, sizeof(*buff), size, file) != size) {
            LOG_FATAL("Unable to write crash dump");
            std::abort();
        }
    }

    void CrashDumpWriterVFS::writeWords(const uint32_t *buff, std::size_t size)
    {
        for (std::size_t n = 0; n < size; ++n) {
            writeBytes(reinterpret_cast<const uint8_t *>(buff + n), sizeof(uint32_t));
        if (std::fwrite(buff, sizeof(*buff), size, file) != size) {
            LOG_FATAL("Unable to write crash dump");
            std::abort();
        }
    }

    CrashDumpWriter &CrashDumpWriter::instance()
    {
        static CrashDumpWriterVFS writer;
        return writer;
    }

} // namespace crashdump

M board/rt1051/crashdump/crashdumpwriter_vfs.hpp => board/rt1051/crashdump/crashdumpwriter_vfs.hpp +8 -10
@@ 3,12 3,12 @@

#pragma once

#include "crashdumpwriter.hpp"
#include <rotator/Rotator.hpp>

#include <array>
#include <ctime>
#include <memory>
#include <cstdio>

namespace purefs::fs
{


@@ 18,23 18,21 @@ namespace purefs::fs
namespace crashdump
{
    constexpr inline auto maxRotationFilesCount = 5;
    class CrashDumpWriterVFS : public CrashDumpWriter
    class CrashDumpWriterVFS
    {
      public:
        CrashDumpWriterVFS() : rotator{".hex"}
        {}
        void openDump() override;
        void saveDump() override;
        void openDump();
        void saveDump();

        void writeBytes(const std::uint8_t *buff, std::size_t size) override;
        void writeHalfWords(const std::uint16_t *buff, std::size_t size) override;
        void writeWords(const std::uint32_t *buff, std::size_t size) override;
        void writeBytes(const std::uint8_t *buff, std::size_t size);
        void writeHalfWords(const std::uint16_t *buff, std::size_t size);
        void writeWords(const std::uint32_t *buff, std::size_t size);

      private:
        utils::Rotator<maxRotationFilesCount> rotator;
        int dumpFd{-1};

        std::shared_ptr<purefs::fs::filesystem> vfs;
        std::FILE *file{};
    };

} // namespace crashdump

M image/user/db/settings_bell_002.sql => image/user/db/settings_bell_002.sql +0 -4
@@ 35,20 35,16 @@ INSERT OR IGNORE INTO settings_tab (path, value) VALUES
    ('snooze_length','10'),
    ('snooze_interval','1'),
    ('snooze_tone','Gentle Chime'),
    ('snooze_volume','5'),
    ('prewake_up_duration', '10'),
    ('prewake_up_tone','Joyful Awakening'),
    ('prewake_up_volume','5'),
    ('prewake_up_light_duration','10'),
    ('alarm_tone','Gentle Daybreak'),
    ('alarm_volume','5'),
    ('alarm_light_active','1'),
    ('alarm_duration','10000'),
    ('bedtime_active','0'),
    ('bedtime_time','21:00'),
    ('bedtime_tone','Evening Horizon'),
    ('bedtime_duration','5'),
    ('bedtime_volume','1'),
    ('\ServiceEink\\display_inverted_mode', '0');



M module-apps/apps-common/widgets/ProgressTimer.cpp => module-apps/apps-common/widgets/ProgressTimer.cpp +1 -1
@@ 54,6 54,7 @@ namespace app

    auto ProgressTimer::onTimerTimeout(sys::Timer &task) -> bool
    {
        ++elapsed;
        if (isStopped() || isFinished()) {
            task.stop();
            if (isFinished() && onFinishedCallback != nullptr) {


@@ 62,7 63,6 @@ namespace app
            return true;
        }

        ++elapsed;
        if ((intervalReached() || isFinished()) && onIntervalCallback != nullptr) {
            onIntervalCallback();
        }

M module-audio/Audio/AudioCommon.hpp => module-audio/Audio/AudioCommon.hpp +5 -2
@@ 66,7 66,10 @@ namespace audio
        TextMessageRingtone,
        Meditation,
        Alarm,
        Last = Alarm,
        PreWakeUp,
        Snooze,
        Bedtime,
        Last = Bedtime,
    };

    /// Used to describe audio operations


@@ 174,7 177,7 @@ namespace audio
        std::bitset<magic_enum::enum_count<EventType>()> audioSinkState;
    };

    enum class RetCode
    enum class RetCode : std::uint8_t
    {
        Success = 0,
        InvokedInIncorrectState,

M module-audio/Audio/AudioMux.cpp => module-audio/Audio/AudioMux.cpp +3 -6
@@ 163,20 163,17 @@ namespace audio
    {
        switch (type) {
        case PlaybackType::None:
            [[fallthrough]];
        case PlaybackType::Notifications:
            [[fallthrough]];
        case PlaybackType::KeypadSound:
            [[fallthrough]];
        case PlaybackType::TextMessageRingtone:
            return true;
        case PlaybackType::CallRingtone:
            [[fallthrough]];
        case PlaybackType::Meditation:
            [[fallthrough]];
        case PlaybackType::Alarm:
            [[fallthrough]];
        case PlaybackType::Multimedia:
        case PlaybackType::Bedtime:
        case PlaybackType::PreWakeUp:
        case PlaybackType::Snooze:
            return false;
        }
        return false;

M module-audio/board/rt1051/bellpx/BellPxAudioCodec.cpp => module-audio/board/rt1051/bellpx/BellPxAudioCodec.cpp +2 -3
@@ 3,7 3,6 @@

#include "BellPxAudioCodec.hpp"
#include "board.h"
#include "dma_config.h"
#include <log/log.hpp>

#include "board/BoardDefinitions.hpp"


@@ 104,7 103,7 @@ namespace audio
    AudioDevice::RetCode BellPxAudioCodec::setOutputVolume(float vol)
    {
        currentFormat.outputVolume = vol;
        CodecParams params;
        CodecParamsAW8898 params;
        params.outVolume = vol;
        params.opCmd     = CodecParams::Cmd::SetOutVolume;
        codec.Ioctrl(params);


@@ 114,7 113,7 @@ namespace audio
    AudioDevice::RetCode BellPxAudioCodec::setInputGain(float gain)
    {
        currentFormat.inputGain = gain;
        CodecParams params;
        CodecParamsAW8898 params;
        params.inGain = gain;
        params.opCmd  = CodecParams::Cmd::SetInGain;
        codec.Ioctrl(params);

M module-bsp/board/rt1051/bellpx/bsp/audio/AW8898driver.cpp => module-bsp/board/rt1051/bellpx/bsp/audio/AW8898driver.cpp +2 -2
@@ 469,7 469,7 @@ namespace bsp::audio::AW8898
        return res;
    }

    status_t GetVolume(std::uint8_t *gian)
    status_t GetVolume(std::uint8_t *gain)
    {
        status_t res      = kStatus_Success;
        std::uint16_t reg = 0;


@@ 480,7 480,7 @@ namespace bsp::audio::AW8898
            return res;
        }

        *gian = reg >> 8;
        *gain = reg >> 8;
        return res;
    }


M module-bsp/board/rt1051/bellpx/bsp/audio/CodecAW8898.cpp => module-bsp/board/rt1051/bellpx/bsp/audio/CodecAW8898.cpp +23 -18
@@ 21,10 21,23 @@ using namespace bsp::audio;

namespace
{
    constexpr auto ReadStatusRetries  = 5;
    constexpr auto OneByteAddressing  = 1;
    constexpr auto PositiveLogic      = 0;
    constexpr auto defaultVolumeLevel = 3.0f;
    constexpr auto ReadStatusRetries = 5;
    constexpr auto OneByteAddressing = 1;
    constexpr auto PositiveLogic     = 0;
    constexpr auto maxInVolume       = 10;
    constexpr auto minInVolume       = 0;

    /// Higher layers operate using 0-10 range. Here we are transforming it into more usable one.
    /// Anything above 9 is going to distort the speaker and values below 5 are too quiet.
    constexpr float transformVolumeLvl(float value)
    {
        constexpr auto maxOutVolume = 9;
        constexpr auto minOutVolume = 5;
        constexpr auto inputRange   = std::make_pair(minInVolume, maxInVolume);
        constexpr auto outputRange  = std::make_pair(minOutVolume, maxOutVolume);
        constexpr float slope = 1.0 * (outputRange.second - outputRange.first) / (inputRange.second - inputRange.first);
        return outputRange.first + slope * (value - inputRange.first);
    }
} // namespace

CodecAW8898::CodecAW8898()


@@ 83,10 96,7 @@ CodecRetCode CodecAW8898::Start(const CodecParams &param)
    // Store param configuration
    currentParams = params;

    auto currVol = currentParams.outVolume;
    // remove this once volume control in application is working
    currVol = defaultVolumeLevel;
    SetOutputVolume(currVol);
    SetOutputVolume(currentParams.outVolume);

    AW8898::ReadAllReg();



@@ 115,10 125,8 @@ CodecRetCode CodecAW8898::Stop()

CodecRetCode CodecAW8898::Ioctrl(const CodecParams &param)
{

    const CodecParamsAW8898 &params = static_cast<const CodecParamsAW8898 &>(param);

    CodecRetCode ret = CodecRetCode::Success;
    CodecRetCode ret                = CodecRetCode::Success;

    switch (params.opCmd) {
    case CodecParamsAW8898::Cmd::SetOutVolume:


@@ 152,14 160,13 @@ CodecRetCode CodecAW8898::Ioctrl(const CodecParams &param)

std::uint8_t CodecAW8898::VolumeTo8Bit(const float vol)
{
    static constexpr auto maxVolumeLevel  = 10.0f;
    static constexpr auto conversionRatio = static_cast<float>(UINT8_MAX) / maxVolumeLevel;
    static constexpr auto conversionRatio = static_cast<float>(UINT8_MAX) / maxInVolume;

    if (vol < 0) {
        return 0;
    }

    if (vol > maxVolumeLevel) {
    if (vol > maxInVolume) {
        return UINT8_MAX;
    }



@@ 168,12 175,10 @@ std::uint8_t CodecAW8898::VolumeTo8Bit(const float vol)

CodecRetCode CodecAW8898::SetOutputVolume(const float vol)
{
    uint8_t mute = 0;

    // If volume set to 0 then mute output
    AW8898::RunMute(vol == 0); //(PWMCTRL.HMUTE=0) - disable mute

    AW8898::SetVolume(VolumeTo8Bit(vol));
    // AW8898 has "negative" gain control - higher the absolute value, lower the volume
    AW8898::SetVolume(UINT8_MAX - VolumeTo8Bit(transformVolumeLvl(vol)));
    currentParams.outVolume = vol;
    return CodecRetCode::Success;
}

M module-bsp/board/rt1051/bellpx/bsp/audio/CodecAW8898.hpp => module-bsp/board/rt1051/bellpx/bsp/audio/CodecAW8898.hpp +0 -26
@@ 17,29 17,6 @@ extern "C"
class CodecParamsAW8898 : public CodecParams
{
  public:
    enum class Cmd
    {
        SetOutVolume,
        SetInGain,
        SetMute,
        SetOutput,
        SetInput,
        Reset,
        MicBiasCtrl,
        None
    };

    enum class SampleRate
    {
        Rate8KHz   = 8000,
        Rate16KHz  = 16000,
        Rate44K1Hz = 44100,
        Rate48KHz  = 48000,
        Rate32KHz  = 32000,
        Rate96KHz  = 96000,
        Invalid
    };

    enum class MonoStereo
    {
        Left,


@@ 97,10 74,7 @@ class CodecParamsAW8898 : public CodecParams
        }
    }

    Cmd opCmd             = Cmd::None;
    float outVolume       = 0;
    MonoStereo monoStereo = MonoStereo::Mono;
    SampleRate sampleRate = SampleRate ::Rate44K1Hz;
};

class CodecAW8898 : public Codec

M module-bsp/board/rt1051/bellpx/bsp/switches/switches.cpp => module-bsp/board/rt1051/bellpx/bsp/switches/switches.cpp +24 -15
@@ 67,22 67,22 @@ namespace bsp::bell_switches
      private:
        static constexpr std::chrono::milliseconds latchPressEventTimeout = 1000ms;
        cpp_freertos::MutexStandard latchFlagMutex;
        std::chrono::time_point<std::chrono::system_clock> timeOfLastLatchEvent = std::chrono::system_clock::now();
        bool pressed                                                            = false;
        bool pressed    = false;
        bool changeFlag = false;

      public:
        void setPressed()
        {
            cpp_freertos::LockGuard lock(latchFlagMutex);
            pressed              = true;
            timeOfLastLatchEvent = std::chrono::system_clock::now();
            pressed    = true;
            changeFlag = true;
        }

        void setReleased()
        {
            cpp_freertos::LockGuard lock(latchFlagMutex);
            pressed              = false;
            timeOfLastLatchEvent = std::chrono::system_clock::now();
            pressed    = false;
            changeFlag = true;
        }

        bool isPressed()


@@ 91,12 91,16 @@ namespace bsp::bell_switches
            return pressed;
        }

        bool wasJustPressed()
        bool wasMarkedChanged()
        {
            cpp_freertos::LockGuard lock(latchFlagMutex);
            auto ret = ((std::chrono::duration_cast<std::chrono::milliseconds>(
                            std::chrono::system_clock::now() - timeOfLastLatchEvent)) <= latchPressEventTimeout);
            return ret;
            return changeFlag;
        }

        void clearChangedMark()
        {
            cpp_freertos::LockGuard lock(latchFlagMutex);
            changeFlag = false;
        }

    } latchEventFlag;


@@ 122,7 126,7 @@ namespace bsp::bell_switches
                    latchEventFlag.setPressed();
                }
                auto val = static_cast<std::uint16_t>(timerState->notificationSource);
                xQueueSendFromISR(qHandleIrq, &val, &xHigherPriorityTaskWoken);
                xQueueSend(qHandleIrq, &val, 0);
                timerState->lastState = KeyEvents::Released;
            }
            else {


@@ 149,7 153,7 @@ namespace bsp::bell_switches
                default:
                    break;
                }
                xQueueSendFromISR(qHandleIrq, &val, &xHigherPriorityTaskWoken);
                xQueueSend(qHandleIrq, &val, 0);
                timerState->lastState = KeyEvents::Pressed;
            }
        }


@@ 163,9 167,14 @@ namespace bsp::bell_switches
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        xTimerStop(timerState->timer, 0);

        if (!latchEventFlag.wasJustPressed() && qHandleIrq != nullptr) {
            auto val = static_cast<std::uint16_t>(timerState->notificationSource);
            xQueueSendFromISR(qHandleIrq, &val, &xHigherPriorityTaskWoken);
        if (qHandleIrq != nullptr) {
            if (latchEventFlag.wasMarkedChanged()) {
                latchEventFlag.clearChangedMark();
            }
            else {
                auto val = static_cast<std::uint16_t>(timerState->notificationSource);
                xQueueSend(qHandleIrq, &val, 0);
            }
        }

        timerState->gpio->ClearPortInterrupts(1U << static_cast<uint32_t>(timerState->pin));

M module-vfs/drivers/src/purefs/fs/filesystem_ext4.cpp => module-vfs/drivers/src/purefs/fs/filesystem_ext4.cpp +6 -2
@@ 130,8 130,12 @@ namespace purefs::fs::drivers
            LOG_ERROR("Unable to append volume err: %i", err);
            return err;
        }
        // Test only
        ext4_dmask_set(DEBUG_ALL);
        /** If verbosed lwext4 debug is required please uncomment
         * this line. It may cause to print a lot of messages
         * especially when the ext4 journal is recovered
         * on the log output device so it is disabled by default
         */
        // ext4_dmask_set(DEBUG_ALL);
        err = ext4_device_register(bd, disk->name().c_str());
        if (err) {
            LOG_ERROR("Unable to register device with err: %i", err);

M module-vfs/drivers/src/thirdparty/lwext4/ext4_bdev.cpp => module-vfs/drivers/src/thirdparty/lwext4/ext4_bdev.cpp +9 -2
@@ 5,6 5,7 @@
#include <ext4_config.h>
#include <ext4_blockdev.h>
#include <ext4_errno.h>
#include <stdint.h>
#include <unordered_map>
#include <log/log.hpp>
#include <mutex.hpp>


@@ 47,29 48,34 @@ namespace purefs::fs::drivers::ext4::internal
                if (!ctx) {
                    return -EIO;
                }
                cpp_freertos::LockGuard _lck(ctx->mutex);
                auto diskmm = ctx->disk.lock();
                if (!diskmm) {
                    return -EIO;
                }
                const auto err = diskmm->write(ctx->disk_h, buf, blk_id, blk_cnt);
                if (err) {
                    LOG_ERROR("Sector write error errno: %i", err);
                    LOG_ERROR(
                        "Sector write error errno: %i on block: %u cnt: %u", err, unsigned(blk_id), unsigned(blk_cnt));
                }
                return -err;
            }

            int read(struct ext4_blockdev *bdev, void *buf, uint64_t blk_id, uint32_t blk_cnt)
            {
                auto ctx = reinterpret_cast<context *>(bdev->bdif->p_user);
                if (!ctx) {
                    return -EIO;
                }
                cpp_freertos::LockGuard _lck(ctx->mutex);
                auto diskmm = ctx->disk.lock();
                if (!diskmm) {
                    return -EIO;
                }
                const auto err = diskmm->read(ctx->disk_h, buf, blk_id, blk_cnt);
                if (err) {
                    LOG_ERROR("Sector read error errno: %i", err);
                    LOG_ERROR(
                        "Sector read error errno: %i on block: %u cnt: %u", err, unsigned(blk_id), unsigned(blk_cnt));
                }
                return -err;
            }


@@ 78,6 84,7 @@ namespace purefs::fs::drivers::ext4::internal
            {
                return 0;
            }

            int close(struct ext4_blockdev *bdev)
            {
                return 0;

M products/BellHybrid/BellHybridMain.cpp => products/BellHybrid/BellHybridMain.cpp +2 -2
@@ 19,11 19,11 @@

// services
#include <appmgr/ApplicationManager.hpp>
#include <audio/ServiceAudio.hpp>
#include <db/ServiceDB.hpp>
#include <evtmgr/EventManager.hpp>
#include <Service/ServiceCreator.hpp>
#include <service-appmgr/Constants.hpp>
#include <service-audio/ServiceAudio.hpp>
#include <service-desktop/ServiceDesktop.hpp>
#include <service-eink/ServiceEink.hpp>
#include <service-gui/ServiceGUI.hpp>


@@ 68,7 68,7 @@ int main()
    std::vector<std::unique_ptr<sys::BaseServiceCreator>> systemServices;
    systemServices.emplace_back(sys::CreatorFor<EventManager>());
    systemServices.emplace_back(sys::CreatorFor<ServiceDB>());
    systemServices.emplace_back(sys::CreatorFor<ServiceAudio>());
    systemServices.emplace_back(sys::CreatorFor<service::Audio>());
    systemServices.emplace_back(sys::CreatorFor<ServiceDesktop>());
    systemServices.emplace_back(sys::CreatorFor<stm::ServiceTime>(std::make_shared<alarms::AlarmOperationsFactory>()));
    systemServices.emplace_back(sys::CreatorFor<service::eink::ServiceEink>(service::eink::ExitAction::None));

M products/BellHybrid/CMakeLists.txt => products/BellHybrid/CMakeLists.txt +2 -2
@@ 48,12 48,12 @@ target_link_libraries(BellHybrid
        bell::app-powernap
        bell::app-settings
        bell::db
        evtmgr
        bell::audio
        bell::evtmgr
        log
        messagetype
        module-bsp
        module-vfs
        service-audio
        service-desktop
        service-time
        sys

M products/BellHybrid/alarms/CMakeLists.txt => products/BellHybrid/alarms/CMakeLists.txt +1 -1
@@ 33,12 33,12 @@ target_include_directories(alarms

target_link_libraries(alarms
   PRIVATE
        module-audio
        module-vfs
        bell::db
        bell::appmgr
        bell::app-common
        bell::evtmgr
        bell::audio
        apps-common
   PUBLIC
        module-db

M products/BellHybrid/alarms/include/BellAlarmHandler.hpp => products/BellHybrid/alarms/include/BellAlarmHandler.hpp +0 -1
@@ 4,7 4,6 @@
#pragma once

#include "AbstractAlarmAction.hpp"
#include <service-audio/AudioServiceAPI.hpp>
#include <service-time/AlarmHandler.hpp>
#include <Service/Service.hpp>


M products/BellHybrid/alarms/src/actions/PlayAudioActions.cpp => products/BellHybrid/alarms/src/actions/PlayAudioActions.cpp +8 -6
@@ 4,7 4,7 @@
#include "AlarmSoundPaths.hpp"
#include "PlayAudioActions.hpp"

#include <service-time/ServiceTime.hpp>
#include <audio/AudioMessage.hpp>
#include <db/SystemSettings.hpp>
#include <Timers/TimerFactory.hpp>



@@ 24,14 24,16 @@ namespace alarms
        if (duration != InfiniteDuration) {
            spawnTimer(duration);
        }
        return AudioServiceAPI::PlaybackStart(&service, playbackType, path);
        return service.bus.sendUnicast(std::make_shared<service::AudioStartPlaybackRequest>(path, playbackType),
                                       service::audioServiceName);
    }

    bool PlayAudioAction::turnOff()
    {
        detachTimer();
        auto stopPlaybackVec = std::vector<audio::PlaybackType>({playbackType});
        return AudioServiceAPI::Stop(&service, stopPlaybackVec);
        const auto msg       = std::make_shared<service::AudioStopRequest>(stopPlaybackVec);
        return service.bus.sendUnicast(msg, service::audioServiceName);
    }
    bool PlayAudioAction::execute()
    {


@@ 66,7 68,7 @@ namespace alarms
                                                     paths::getPreWakeUpChimesDir(),
                                                     bell::settings::PrewakeUp::tone,
                                                     bell::settings::PrewakeUp::duration,
                                                     audio::PlaybackType::Multimedia);
                                                     audio::PlaybackType::PreWakeUp);
        }

        std::unique_ptr<PlayAudioAction> createSnoozeChimeAction(sys::Service &service)


@@ 75,7 77,7 @@ namespace alarms
                                                     paths::getSnoozeChimesDir(),
                                                     bell::settings::Snooze::tone,
                                                     bell::settings::Snooze::length,
                                                     audio::PlaybackType::Multimedia);
                                                     audio::PlaybackType::Snooze);
        }
        std::unique_ptr<PlayAudioAction> createAlarmToneAction(sys::Service &service)
        {


@@ 88,7 90,7 @@ namespace alarms
                                                     paths::getBedtimeReminderChimesDir(),
                                                     bell::settings::Bedtime::tone,
                                                     bell::settings::Bedtime::duration,
                                                     audio::PlaybackType::Multimedia);
                                                     audio::PlaybackType::Bedtime);
        }
    } // namespace factory
} // namespace alarms

M products/BellHybrid/alarms/src/actions/PlayAudioActions.hpp => products/BellHybrid/alarms/src/actions/PlayAudioActions.hpp +1 -2
@@ 4,9 4,8 @@
#pragma once

#include "AbstractAlarmAction.hpp"
#include <audio/AudioMessage.hpp>
#include <common/SoundsRepository.hpp>
#include <service-audio/AudioServiceAPI.hpp>
#include <module-audio/Audio/AudioCommon.hpp>
#include <service-db/Settings.hpp>
#include <Timers/TimerHandle.hpp>
#include <Service/Service.hpp>

M products/BellHybrid/apps/application-bell-background-sounds/ApplicationBellBackgroundSounds.cpp => products/BellHybrid/apps/application-bell-background-sounds/ApplicationBellBackgroundSounds.cpp +11 -8
@@ 15,7 15,8 @@
#include "widgets/BGSoundsPlayer.hpp"
#include <apps-common/messages/AppMessage.hpp>
#include <common/models/TimeModel.hpp>
#include <service-audio/AudioMessage.hpp>
#include <common/models/AudioModel.hpp>
#include <audio/AudioMessage.hpp>

#include <log/log.hpp>
namespace app


@@ 26,11 27,12 @@ namespace app
                                                                     StartInBackground startInBackground,
                                                                     uint32_t stackDepth)
        : Application(std::move(name), std::move(parent), statusIndicators, startInBackground, stackDepth),
          player{std::make_unique<bgSounds::BGSoundsPlayer>(this)}
          audioModel{std::make_unique<AudioModel>(this)}, player{
                                                              std::make_unique<bgSounds::BGSoundsPlayer>(*audioModel)}
    {
        bus.channels.push_back(sys::BusChannel::ServiceAudioNotifications);
        connect(typeid(AudioEOFNotification), [&](sys::Message *msg) -> sys::MessagePointer {
            auto notification = static_cast<AudioEOFNotification *>(msg);
        connect(typeid(service::AudioEOFNotification), [&](sys::Message *msg) -> sys::MessagePointer {
            auto notification = static_cast<service::AudioEOFNotification *>(msg);
            return player->handle(notification);
        });
    }


@@ 71,10 73,11 @@ namespace app
            return std::make_unique<gui::BGSoundsPausedWindow>(app);
        });

        windowsFactory.attach(gui::popup::window::volume_window, [](ApplicationCommon *app, const std::string &name) {
            auto presenter = std::make_unique<bgSounds::BGSoundsVolumePresenter>(*app);
            return std::make_unique<gui::BGSoundsVolumeWindow>(app, std::move(presenter));
        });
        windowsFactory.attach(gui::popup::window::volume_window,
                              [this](ApplicationCommon *app, const std::string &name) {
                                  auto presenter = std::make_unique<bgSounds::BGSoundsVolumePresenter>(*audioModel);
                                  return std::make_unique<gui::BGSoundsVolumeWindow>(app, std::move(presenter));
                              });

        attachPopups({gui::popup::ID::AlarmActivated,
                      gui::popup::ID::AlarmDeactivated,

M products/BellHybrid/apps/application-bell-background-sounds/CMakeLists.txt => products/BellHybrid/apps/application-bell-background-sounds/CMakeLists.txt +1 -1
@@ 47,8 47,8 @@ target_sources(application-bell-background-sounds

target_link_libraries(application-bell-background-sounds
    PRIVATE
        app
        apps-common
        bell::audio

    PUBLIC
        module-gui

M products/BellHybrid/apps/application-bell-background-sounds/data/BGSoundsCommon.hpp => products/BellHybrid/apps/application-bell-background-sounds/data/BGSoundsCommon.hpp +0 -1
@@ 6,5 6,4 @@
namespace app::bgSounds
{
    constexpr auto timerValueDBRecordName = "BGSoundsTimerValue";
    constexpr auto soundsVolumeDBRecordName = "BGSoundsVolume";
}

M products/BellHybrid/apps/application-bell-background-sounds/include/application-bell-background-sounds/ApplicationBellBackgroundSounds.hpp => products/BellHybrid/apps/application-bell-background-sounds/include/application-bell-background-sounds/ApplicationBellBackgroundSounds.hpp +2 -0
@@ 4,6 4,7 @@
#pragma once

#include <Application.hpp>
#include <common/models/AbstractAudioModel.hpp>

namespace gui::window::name
{


@@ 21,6 22,7 @@ namespace app

    class ApplicationBellBackgroundSounds : public Application
    {
        std::unique_ptr<AbstractAudioModel> audioModel;
        std::unique_ptr<bgSounds::BGSoundsPlayer> player;

        sys::MessagePointer handleSwitchWindow(sys::Message *msgl) override;

M products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsProgressPresenter.cpp => products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsProgressPresenter.cpp +4 -1
@@ 20,7 20,6 @@ namespace app::bgSounds
                                                         std::unique_ptr<AbstractTimeModel> timeModel)
        : settings{settings}, player{player}, timeModel{std::move(timeModel)}
    {}
    BGSoundsProgressPresenter::~BGSoundsProgressPresenter() = default;

    void BGSoundsProgressPresenter::setTimer(std::unique_ptr<app::TimerWithCallbacks> &&_timer)
    {


@@ 89,4 88,8 @@ namespace app::bgSounds
    {
        getView()->setTime(timeModel->getCurrentTime());
    }
    bool BGSoundsProgressPresenter::isPaused()
    {
        return player.isPaused();
    }
} // namespace app::bgSounds

M products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsProgressPresenter.hpp => products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsProgressPresenter.hpp +5 -4
@@ 30,9 30,9 @@ namespace app::bgSounds
        class View
        {
          public:
            ~View()                   = default;
            virtual void onFinished() = 0;
            virtual void onPaused()   = 0;
            virtual ~View()                                                 = default;
            virtual void onFinished()                                       = 0;
            virtual void onPaused()                                         = 0;
            virtual void setTime(std::time_t newTime)                       = 0;
            virtual void setTimeFormat(utils::time::Locale::TimeFormat fmt) = 0;
        };


@@ 46,6 46,7 @@ namespace app::bgSounds
            virtual void resume()                                                   = 0;
            virtual void setTimer(std::unique_ptr<app::TimerWithCallbacks> &&timer) = 0;
            virtual void handleUpdateTimeEvent()                                    = 0;
            virtual bool isPaused()                                                 = 0;
        };
    };



@@ 64,6 65,7 @@ namespace app::bgSounds
        void resume() override;
        void setTimer(std::unique_ptr<app::TimerWithCallbacks> &&_timer) override;
        void handleUpdateTimeEvent() override;
        bool isPaused() override;

        void onFinished();



@@ 71,6 73,5 @@ namespace app::bgSounds
        BGSoundsProgressPresenter(settings::Settings *settings,
                                  AbstractBGSoundsPlayer &player,
                                  std::unique_ptr<AbstractTimeModel> timeModel);
        ~BGSoundsProgressPresenter();
    };
} // namespace app::bgSounds

M products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsTimerSelectPresenter.hpp => products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsTimerSelectPresenter.hpp +2 -1
@@ 30,12 30,13 @@ namespace app::bgSounds
        class View
        {
          public:
            ~View() = default;
            virtual ~View() = default;
        };

        class Presenter : public BasePresenter<BGSoundsTimerSelectContract::View>
        {
          public:
            virtual ~Presenter()                                      = default;
            virtual const Range &getTimerValuesRange() const noexcept = 0;
            virtual std::chrono::minutes getCurrentTimerValue() const = 0;
            virtual void setTimerValue(std::chrono::minutes)          = 0;

M products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsVolumePresenter.cpp => products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsVolumePresenter.cpp +5 -14
@@ 2,11 2,10 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "BGSoundsVolumePresenter.hpp"
#include <Application.hpp>

namespace app::bgSounds
{
    BGSoundsVolumePresenter::BGSoundsVolumePresenter(app::ApplicationCommon &app) : app{app}
    BGSoundsVolumePresenter::BGSoundsVolumePresenter(AbstractAudioModel &audioModel) : audioModel{audioModel}
    {}

    VolumeData BGSoundsVolumePresenter::getVolumeData()


@@ 14,20 13,12 @@ namespace app::bgSounds
        return volumeData;
    }

    audio::Volume BGSoundsVolumePresenter::getDefaultVolume()
    void BGSoundsVolumePresenter::setVolume(AbstractAudioModel::Volume volume)
    {
        return audio::defaultVolume;
        audioModel.setVolume(volume, AbstractAudioModel::PlaybackType::Multimedia, {});
    }

    void BGSoundsVolumePresenter::increaseVolume()
    {
        app.increaseCurrentVolume();
    }

    void BGSoundsVolumePresenter::decreaseVolume()
    AbstractAudioModel::Volume BGSoundsVolumePresenter::getVolume()
    {
        if (getView()->getCurrentVolume() != minVolume) {
            app.decreaseCurrentVolume();
        }
        return audioModel.getVolume(AbstractAudioModel::PlaybackType::Multimedia).value_or(defaultVolume);
    }
} // namespace app::bgSounds

M products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsVolumePresenter.hpp => products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsVolumePresenter.hpp +17 -28
@@ 3,8 3,7 @@

#pragma once

#include <apps-common/BasePresenter.hpp>
#include <module-audio/Audio/AudioCommon.hpp>
#include <common/models/AbstractAudioModel.hpp>

namespace app
{


@@ 12,47 11,37 @@ namespace app
}
namespace app::bgSounds
{
    constexpr audio::Volume minVolume = 1u;
    using VolumeData = struct VolumeData
    {
        audio::Volume min;
        audio::Volume max;
        audio::Volume step;
        AbstractAudioModel::Volume min;
        AbstractAudioModel::Volume max;
        AbstractAudioModel::Volume step;
    };

    class BGSoundsVolumeContract
    class AbstractBGSoundsVolumePresenter
    {
      public:
        class View
        {
          public:
            virtual ~View() = default;
            virtual audio::Volume getCurrentVolume() const noexcept = 0;
        };
        class Presenter : public BasePresenter<BGSoundsVolumeContract::View>
        {
          public:
            virtual VolumeData getVolumeData()       = 0;
            virtual audio::Volume getDefaultVolume() = 0;
            virtual void increaseVolume()            = 0;
            virtual void decreaseVolume()            = 0;
        };
        virtual ~AbstractBGSoundsVolumePresenter()                = default;
        virtual VolumeData getVolumeData()                        = 0;
        virtual void setVolume(AbstractAudioModel::Volume volume) = 0;
        virtual AbstractAudioModel::Volume getVolume()            = 0;
    };

    class BGSoundsVolumePresenter : public BGSoundsVolumeContract::Presenter
    class BGSoundsVolumePresenter : public AbstractBGSoundsVolumePresenter
    {
        app::ApplicationCommon &app;
        constexpr static struct VolumeData volumeData
        {
            bgSounds::minVolume, audio::maxVolume, audio::defaultVolumeStep
            AbstractAudioModel::minVolume, AbstractAudioModel::maxVolume, 1
        };
        static constexpr AbstractAudioModel::Volume defaultVolume = 5;

        AbstractAudioModel &audioModel;

        VolumeData getVolumeData() override;
        audio::Volume getDefaultVolume() override;
        void increaseVolume() override;
        void decreaseVolume() override;
        void setVolume(AbstractAudioModel::Volume volume) override;
        AbstractAudioModel::Volume getVolume() override;

      public:
        explicit BGSoundsVolumePresenter(app::ApplicationCommon &app);
        explicit BGSoundsVolumePresenter(AbstractAudioModel &audioModel);
    };
} // namespace app::bgSounds

M products/BellHybrid/apps/application-bell-background-sounds/widgets/BGSoundsPlayer.cpp => products/BellHybrid/apps/application-bell-background-sounds/widgets/BGSoundsPlayer.cpp +29 -85
@@ 2,104 2,48 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "BGSoundsPlayer.hpp"
#include <service-audio/AudioMessage.hpp>
#include <service-audio/AudioServiceName.hpp>
#include <audio/AudioMessage.hpp>

namespace app::bgSounds
{
    BGSoundsPlayer::BGSoundsPlayer(app::ApplicationCommon *app) : app::AsyncCallbackReceiver{app}, app{app}
    {}
    void BGSoundsPlayer::start(const std::string &filePath, PlaybackMode mode, OnStateChangeCallback callback)
    auto BGSoundsPlayer::handle(service::AudioEOFNotification *msg) -> std::shared_ptr<sys::Message>
    {
        auto msg  = std::make_unique<AudioStartPlaybackRequest>(filePath, audio::PlaybackType::Multimedia);
        auto task = app::AsyncRequest::createFromMessage(std::move(msg), service::name::audio);
        auto cb   = [this, _callback = std::move(callback), filePath, mode](auto response) {
            auto result = dynamic_cast<AudioStartPlaybackResponse *>(response);
            if (result == nullptr) {
                return false;
            }
            token          = result->token;
            recentFilePath = std::move(filePath);
            playbackMode   = mode;
            if (_callback) {
                _callback(result->retCode);
            }
            return true;
        };
        task->execute(app, this, std::move(cb));
        if (playbackMode == PlaybackMode::Looped) {
            audioModel.play(recentFilePath, AbstractAudioModel::PlaybackType::Multimedia, {});
        }
        return sys::msgHandled();
    }
    void BGSoundsPlayer::stop(OnStateChangeCallback callback)
    AbstractBGSoundsPlayer::PlaybackMode BGSoundsPlayer::getCurrentMode() const noexcept
    {
        if (token.IsValid()) {
            auto msg  = std::make_unique<AudioStopRequest>(token);
            auto task = app::AsyncRequest::createFromMessage(std::move(msg), service::name::audio);
            auto cb   = [_callback = std::move(callback)](auto response) {
                auto result = dynamic_cast<AudioStopResponse *>(response);
                if (result == nullptr) {
                    return false;
                }
                if (_callback) {
                    _callback(result->retCode);
                }
                return true;
            };
            task->execute(app, this, std::move(cb));
        }
        return playbackMode;
    }
    void BGSoundsPlayer::pause(OnStateChangeCallback callback)
    BGSoundsPlayer::BGSoundsPlayer(AbstractAudioModel &audioModel) : audioModel{audioModel}
    {}
    void BGSoundsPlayer::start(const std::string &filePath,
                               AbstractBGSoundsPlayer::PlaybackMode mode,
                               AbstractAudioModel::OnStateChangeCallback &&callback)
    {
        if (token.IsValid()) {
            auto msg  = std::make_unique<AudioPauseRequest>(token);
            auto task = app::AsyncRequest::createFromMessage(std::move(msg), service::name::audio);
            auto cb   = [_callback = std::move(callback)](auto response) {
                auto result = dynamic_cast<AudioPauseResponse *>(response);
                if (result == nullptr) {
                    return false;
                }
                if (_callback) {
                    _callback(result->retCode);
                }
                return true;
            };
            task->execute(app, this, std::move(cb));
        }
        recentFilePath = filePath;
        playbackMode   = mode;
        audioModel.play(filePath, AbstractAudioModel::PlaybackType::Multimedia, std::move(callback));
    }
    void BGSoundsPlayer::resume(OnStateChangeCallback callback)
    void BGSoundsPlayer::stop(AbstractAudioModel::OnStateChangeCallback &&callback)
    {
        auto msg  = std::make_unique<AudioResumeRequest>(token);
        auto task = app::AsyncRequest::createFromMessage(std::move(msg), service::name::audio);
        auto cb   = [_callback = std::move(callback)](auto response) {
            auto result = dynamic_cast<AudioResumeResponse *>(response);
            if (result == nullptr) {
                return false;
            }
            if (_callback) {
                _callback(result->retCode);
            }
            return true;
        };
        task->execute(app, this, std::move(cb));
        paused = false;
        audioModel.stop(std::move(callback));
    }

    auto BGSoundsPlayer::handle(AudioEOFNotification *msg) -> std::shared_ptr<sys::Message>
    void BGSoundsPlayer::pause(AbstractAudioModel::OnStateChangeCallback &&callback)
    {
        if (token == msg->token && playbackMode == PlaybackMode::Looped) {
            auto msg  = std::make_unique<AudioStartPlaybackRequest>(recentFilePath, audio::PlaybackType::Multimedia);
            auto task = app::AsyncRequest::createFromMessage(std::move(msg), service::name::audio);
            auto cb   = [this](auto response) {
                auto result = dynamic_cast<AudioStartPlaybackResponse *>(response);
                if (result == nullptr) {
                    return false;
                }
                token = result->token;
                return true;
            };
            task->execute(app, this, std::move(cb));
        }
        return sys::msgHandled();
        paused = true;
        audioModel.pause(std::move(callback));
    }
    AbstractBGSoundsPlayer::PlaybackMode BGSoundsPlayer::getCurrentMode() const noexcept
    void BGSoundsPlayer::resume(AbstractAudioModel::OnStateChangeCallback &&callback)
    {
        return playbackMode;
        paused = false;
        audioModel.resume(std::move(callback));
    }
    bool BGSoundsPlayer::isPaused()
    {
        return paused;
    }
} // namespace app::bgSounds

M products/BellHybrid/apps/application-bell-background-sounds/widgets/BGSoundsPlayer.hpp => products/BellHybrid/apps/application-bell-background-sounds/widgets/BGSoundsPlayer.hpp +33 -24
@@ 2,14 2,18 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
#include <module-audio/Audio/AudioCommon.hpp>
#include <AsyncTask.hpp>

#include <common/models/AbstractAudioModel.hpp>

namespace app
{
    class ApplicationCommon;
}
class AudioEOFNotification;
namespace service
{
    class AudioEOFNotification;
}

namespace app::bgSounds
{
    class AbstractBGSoundsPlayer


@@ 21,32 25,37 @@ namespace app::bgSounds
            SingleShot
        };

        virtual ~AbstractBGSoundsPlayer() = default;

        using OnStateChangeCallback = std::function<void(audio::RetCode retCode)>;
        virtual void start(const std::string &filePath, PlaybackMode mode, OnStateChangeCallback callback) = 0;
        virtual void stop(OnStateChangeCallback callback)                                                  = 0;
        virtual void pause(OnStateChangeCallback callback)                                                 = 0;
        virtual void resume(OnStateChangeCallback callback)                                                = 0;
        virtual PlaybackMode getCurrentMode() const noexcept                                               = 0;
        virtual ~AbstractBGSoundsPlayer()                                         = default;
        virtual void start(const std::string &filePath,
                           PlaybackMode mode,
                           AbstractAudioModel::OnStateChangeCallback &&callback)  = 0;
        virtual void stop(AbstractAudioModel::OnStateChangeCallback &&callback)   = 0;
        virtual void pause(AbstractAudioModel::OnStateChangeCallback &&callback)  = 0;
        virtual void resume(AbstractAudioModel::OnStateChangeCallback &&callback) = 0;
        virtual PlaybackMode getCurrentMode() const noexcept                      = 0;
        virtual bool isPaused()                                                   = 0;
    };

    class BGSoundsPlayer : public AbstractBGSoundsPlayer, public app::AsyncCallbackReceiver
    class BGSoundsPlayer : public AbstractBGSoundsPlayer
    {
        app::ApplicationCommon *app{};
        audio::Token token;
        std::string recentFilePath;
        PlaybackMode playbackMode = PlaybackMode::SingleShot;
      public:
        explicit BGSoundsPlayer(AbstractAudioModel &audioModel);

        void start(const std::string &filePath, PlaybackMode mode, OnStateChangeCallback callback) override;
        void stop(OnStateChangeCallback callback) override;
        void pause(OnStateChangeCallback callback) override;
        void resume(OnStateChangeCallback callback) override;
        PlaybackMode getCurrentMode() const noexcept override;
        auto handle(service::AudioEOFNotification *msg) -> std::shared_ptr<sys::Message>;

      public:
        explicit BGSoundsPlayer(app::ApplicationCommon *app);
      private:
        void start(const std::string &filePath,
                   PlaybackMode mode,
                   AbstractAudioModel::OnStateChangeCallback &&callback) override;
        void stop(AbstractAudioModel::OnStateChangeCallback &&callback) override;
        void pause(AbstractAudioModel::OnStateChangeCallback &&callback) override;
        void resume(AbstractAudioModel::OnStateChangeCallback &&callback) override;
        PlaybackMode getCurrentMode() const noexcept override;
        bool isPaused() override;

        auto handle(AudioEOFNotification *msg) -> std::shared_ptr<sys::Message>;
        AbstractAudioModel &audioModel;
        std::string recentFilePath;
        PlaybackMode playbackMode = PlaybackMode::SingleShot;
        bool paused{false};
    };
} // namespace app::bgSounds

M products/BellHybrid/apps/application-bell-background-sounds/windows/BGSoundsProgressWindow.cpp => products/BellHybrid/apps/application-bell-background-sounds/windows/BGSoundsProgressWindow.cpp +4 -8
@@ 12,7 12,7 @@
#include <time/dateCommon.hpp>
namespace
{
    inline constexpr auto bgSoundsTimerName     = "BGSoundsProgressTimer";
    inline constexpr auto bgSoundsTimerName = "BGSoundsProgressTimer";
    inline constexpr std::chrono::seconds timerTick{1};

    void decorateProgressItem(gui::Rect *item, gui::Alignment::Vertical alignment)


@@ 75,7 75,7 @@ namespace gui

    void BGSoundsProgressWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        if (mode == ShowMode::GUI_SHOW_RETURN) {
        if (mode == ShowMode::GUI_SHOW_RETURN && presenter->isPaused()) {
            presenter->resume();
            return;
        }


@@ 133,12 133,8 @@ namespace gui
                presenter->pause();
                return true;
            }
            else if (inputEvent.is(KeyCode::KEY_DOWN)) {
                application->decreaseCurrentVolume();
                return true;
            }
            else if (inputEvent.is(KeyCode::KEY_UP)) {
                application->increaseCurrentVolume();
            else if (inputEvent.is(KeyCode::KEY_DOWN) || inputEvent.is(KeyCode::KEY_UP)) {
                application->switchWindow(gui::popup::window::volume_window);
                return true;
            }
        }

M products/BellHybrid/apps/application-bell-background-sounds/windows/BGSoundsVolumeWindow.cpp => products/BellHybrid/apps/application-bell-background-sounds/windows/BGSoundsVolumeWindow.cpp +15 -36
@@ 10,11 10,10 @@
namespace gui
{
    BGSoundsVolumeWindow::BGSoundsVolumeWindow(
        app::ApplicationCommon *app, std::unique_ptr<app::bgSounds::BGSoundsVolumeContract::Presenter> &&presenter)
        app::ApplicationCommon *app, std::unique_ptr<app::bgSounds::AbstractBGSoundsVolumePresenter> &&presenter)
        : WindowWithTimer(app, gui::popup::window::volume_window), presenter{std::move(presenter)}
    {
        buildInterface();
        this->presenter->attach(this);
    }

    void BGSoundsVolumeWindow::buildInterface()


@@ 45,47 44,27 @@ namespace gui
        spinner->setFont(bgSoundsStyle::valumeValueFont);
        spinner->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center));
        spinner->setFocusEdges(RectangleEdge::None);
        spinner->setCurrentValue(static_cast<UIntegerSpinner::Type>(presenter->getDefaultVolume()));
        spinner->setCurrentValue(static_cast<UIntegerSpinner::Type>(presenter->getVolume()));
        body->getCenterBox()->addWidget(spinner);

        setFocusItem(spinner);
        spinner->onValueChanged = [this](const auto &value) { presenter->setVolume(value); };
        body->setMinMaxArrowsVisibility(spinner->getCurrentValue() == data.min, spinner->getCurrentValue() == data.max);

        setFocusItem(body);
        body->resize();
    }

    bool BGSoundsVolumeWindow::onInput(const gui::InputEvent &inputEvent)
    bool BGSoundsVolumeWindow::onInput(const InputEvent &inputEvent)
    {
        resetTimer();

        if (inputEvent.isShortRelease(KeyCode::KEY_DOWN)) {
            presenter->decreaseVolume();
        if (inputEvent.isShortRelease(KeyCode::KEY_ENTER) || inputEvent.isShortRelease(KeyCode::KEY_RF)) {
            application->returnToPreviousWindow();
            return true;
        }
        else if (inputEvent.isShortRelease(KeyCode::KEY_UP)) {
            presenter->increaseVolume();
            return true;
        }
        return WindowWithTimer::onInput(inputEvent);
    }

    void BGSoundsVolumeWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        WindowWithTimer::onBeforeShow(mode, data);
        const auto popupData = dynamic_cast<VolumePopupData *>(data);
        if (popupData) {
            volume       = popupData->getVolume();
            audioContext = popupData->getAudioContext();
            spinner->setCurrentValue(static_cast<UIntegerSpinner::Type>(volume));
            auto currentVolume = spinner->getCurrentValue();

            auto isMax = currentVolume == presenter->getVolumeData().max;
            auto isMin = currentVolume == presenter->getVolumeData().min;
            body->setArrowVisible(BellBaseLayout::Arrow::Left, not isMin);
            body->setArrowVisible(BellBaseLayout::Arrow::Right, not isMax);
        }
    }

    audio::Volume BGSoundsVolumeWindow::getCurrentVolume() const noexcept
    {
        return spinner->getCurrentValue();
        resetTimer();
        auto data              = presenter->getVolumeData();
        const auto ret         = body->onInput(inputEvent);
        const auto selectedVal = spinner->getCurrentValue();
        body->setMinMaxArrowsVisibility(selectedVal == data.min, selectedVal == data.max);
        return ret;
    }
} // namespace gui

M products/BellHybrid/apps/application-bell-background-sounds/windows/BGSoundsVolumeWindow.hpp => products/BellHybrid/apps/application-bell-background-sounds/windows/BGSoundsVolumeWindow.hpp +4 -11
@@ 7,29 7,22 @@

#include <apps-common/popups/WindowWithTimer.hpp>
#include <apps-common/widgets/spinners/Spinners.hpp>
#include <common/models/AbstractAudioModel.hpp>

#include <module-audio/Audio/AudioCommon.hpp>
#include <module-audio/Audio/Profiles/Profile.hpp>
namespace gui
{
    class BellBaseLayout;
    class BGSoundsVolumeWindow : public WindowWithTimer, public app::bgSounds::BGSoundsVolumeContract::View
    class BGSoundsVolumeWindow : public WindowWithTimer
    {
        std::unique_ptr<app::bgSounds::BGSoundsVolumeContract::Presenter> presenter;
        audio::Volume volume = 1;
        audio::Context audioContext;

        std::unique_ptr<app::bgSounds::AbstractBGSoundsVolumePresenter> presenter;
        BellBaseLayout *body{};
        UIntegerSpinner *spinner = nullptr;

        void buildInterface() override;
        bool onInput(const gui::InputEvent &inputEvent) override;
        void onBeforeShow(ShowMode mode, SwitchData *data);

        audio::Volume getCurrentVolume() const noexcept override;

      public:
        BGSoundsVolumeWindow(app::ApplicationCommon *app,
                             std::unique_ptr<app::bgSounds::BGSoundsVolumeContract::Presenter> &&windowPresenter);
                             std::unique_ptr<app::bgSounds::AbstractBGSoundsVolumePresenter> &&windowPresenter);
    };
} // namespace gui

M products/BellHybrid/apps/application-bell-bedtime/ApplicationBellBedtime.cpp => products/BellHybrid/apps/application-bell-bedtime/ApplicationBellBedtime.cpp +1 -1
@@ 32,7 32,7 @@ namespace app

    void ApplicationBellBedtime::createUserInterface()
    {
        windowsFactory.attach(gui::name::window::main_window, [this](ApplicationCommon *app, const std::string &) {
        windowsFactory.attach(gui::name::window::main_window, [](ApplicationCommon *app, const std::string &) {
            auto bedtimeModel = std::make_unique<bell_bedtime::BedtimeModel>(app);
            auto provider     = std::make_shared<bell_bedtime::BedtimeListItemProvider>(std::move(bedtimeModel));
            auto presenter    = std::make_unique<bell_bedtime::BellBedtimeWindowPresenter>(provider);

M products/BellHybrid/apps/application-bell-main/ApplicationBellMain.cpp => products/BellHybrid/apps/application-bell-main/ApplicationBellMain.cpp +0 -1
@@ 19,7 19,6 @@
#include <common/windows/BellFactoryReset.hpp>
#include <service-db/DBNotificationMessage.hpp>
#include <windows/Dialog.hpp>
#include <service-audio/AudioMessage.hpp>
#include <common/popups/BedtimeNotificationWindow.hpp>

namespace app

M products/BellHybrid/apps/application-bell-meditation-timer/CMakeLists.txt => products/BellHybrid/apps/application-bell-meditation-timer/CMakeLists.txt +1 -0
@@ 37,6 37,7 @@ target_sources(application-bell-meditation-timer
target_link_libraries(application-bell-meditation-timer
    PRIVATE
        app
        bell::audio
        bell::app-common
        bell::app-main
        bellgui

M products/BellHybrid/apps/application-bell-meditation-timer/windows/MeditationRunningWindow.cpp => products/BellHybrid/apps/application-bell-meditation-timer/windows/MeditationRunningWindow.cpp +4 -3
@@ 5,10 5,10 @@
#include "MeditationRunningWindow.hpp"
#include "MeditationStyle.hpp"

#include <audio/AudioMessage.hpp>
#include <apps-common/widgets/BellBaseLayout.hpp>
#include <apps-common/widgets/ProgressTimerWithBarGraphAndCounter.hpp>
#include <purefs/filesystem_paths.hpp>
#include <service-audio/AudioServiceAPI.hpp>

namespace
{


@@ 182,7 182,8 @@ namespace gui

    void MeditationRunningWindow::playGong()
    {
        AudioServiceAPI::PlaybackStart(
            application, audio::PlaybackType::Meditation, purefs::dir::getCurrentOSPath() / meditationAudioPath);
        auto msg = std::make_shared<service::AudioStartPlaybackRequest>(
            purefs::dir::getCurrentOSPath() / meditationAudioPath, audio::PlaybackType::Meditation);
        application->bus.sendUnicast(std::move(msg), service::audioServiceName);
    }
} // namespace gui

M products/BellHybrid/apps/application-bell-powernap/ApplicationBellPowerNap.cpp => products/BellHybrid/apps/application-bell-powernap/ApplicationBellPowerNap.cpp +0 -1
@@ 10,7 10,6 @@
#include "windows/PowerNapSessionEndedWindow.hpp"
#include <common/models/TimeModel.hpp>
#include <AlarmSoundPaths.hpp>
#include <service-audio/AudioMessage.hpp>

namespace app
{

M products/BellHybrid/apps/application-bell-powernap/presenter/PowerNapProgressPresenter.cpp => products/BellHybrid/apps/application-bell-powernap/presenter/PowerNapProgressPresenter.cpp +3 -11
@@ 59,22 59,14 @@ namespace app::powernap
    {
        const auto filePath = soundsRepository->titleToPath(
            settings->getValue(bell::settings::Alarm::tone, settings::SettingsScope::Global));
        auto playResponseCb = [this](audio::RetCode retCode, audio::Token token) {
            if (retCode != audio::RetCode::Success || !token.IsValid()) {
                LOG_ERROR("Audio preview callback failed with retcode = %s. Token validity: %d",
                          str(retCode).c_str(),
                          token.IsValid());
                return;
            }
            this->currentToken = token;
        };
        audioModel->play(filePath.value_or(""), playResponseCb, AbstractAudioModel::PlaybackType::Alarm);

        audioModel->play(filePath.value_or(""), AbstractAudioModel::PlaybackType::Alarm, {});
        napAlarmTimer.start();
        napFinished = true;
    }
    void PowerNapProgressPresenter::onNapAlarmFinished()
    {
        audioModel->stop(currentToken, nullptr);
        audioModel->stop({});
        getView()->napEnded();
    }


M products/BellHybrid/apps/application-bell-powernap/presenter/PowerNapProgressPresenter.hpp => products/BellHybrid/apps/application-bell-powernap/presenter/PowerNapProgressPresenter.hpp +0 -1
@@ 58,7 58,6 @@ namespace app::powernap
        std::unique_ptr<app::TimerWithCallbacks> timer;
        std::unique_ptr<AbstractTimeModel> timeModel;
        sys::TimerHandle napAlarmTimer;
        audio::Token currentToken;
        bool napFinished{false};

        void activate() override;

M products/BellHybrid/apps/application-bell-settings/ApplicationBellSettings.cpp => products/BellHybrid/apps/application-bell-settings/ApplicationBellSettings.cpp +6 -6
@@ 144,16 144,16 @@ namespace app

        windowsFactory.attach(
            gui::BellSettingsPrewakeUpWindow::name, [this](ApplicationCommon *app, const std::string &name) {
                auto audioModel         = std::make_unique<AudioModel>(this);
                auto chimeDurationModel = std::make_unique<bell_settings::PrewakeUpChimeDurationModel>(this);
                auto chimeToneModel     = std::make_unique<bell_settings::PrewakeUpChimeToneModel>(this);
                auto chimeVolumeModel   = std::make_unique<bell_settings::PrewakeUpChimeVolumeModel>(this);
                auto chimeVolumeModel   = std::make_unique<bell_settings::PrewakeUpChimeVolumeModel>(*audioModel);
                auto lightDurationModel = std::make_unique<bell_settings::PrewakeUpLightDurationModel>(this);
                auto prewakeUpSettingsModel =
                    std::make_unique<bell_settings::PrewakeUpSettingsModel>(std::move(chimeDurationModel),
                                                                            std::move(chimeToneModel),
                                                                            std::move(chimeVolumeModel),
                                                                            std::move(lightDurationModel));
                auto audioModel       = std::make_unique<AudioModel>(this);
                auto soundsRepository = std::make_unique<SoundsRepository>(alarms::paths::getPreWakeUpChimesDir());
                auto provider         = std::make_shared<bell_settings::PrewakeUpListItemProvider>(
                    *prewakeUpSettingsModel, soundsRepository->getSongTitles());


@@ 169,18 169,18 @@ namespace app
                              });
        windowsFactory.attach(
            gui::BellSettingsAlarmSettingsSnoozeWindow::name, [this](ApplicationCommon *app, const std::string &) {
                auto audioModel               = std::make_unique<AudioModel>(this);
                auto snoozeOnOffModel         = std::make_unique<bell_settings::SnoozeOnOffModel>(this);
                auto snoozeLengthModel        = std::make_unique<bell_settings::SnoozeLengthModel>(this);
                auto snoozeChimeIntervalModel = std::make_unique<bell_settings::SnoozeChimeIntervalModel>(this);
                auto snoozeChimeToneModel     = std::make_unique<bell_settings::SnoozeChimeToneModel>(this);
                auto snoozeChimeVolumeModel   = std::make_unique<bell_settings::SnoozeChimeVolumeModel>(this);
                auto snoozeChimeVolumeModel   = std::make_unique<bell_settings::SnoozeChimeVolumeModel>(*audioModel);
                auto snoozeSettingsModel =
                    std::make_unique<bell_settings::SnoozeSettingsModel>(std::move(snoozeOnOffModel),
                                                                         std::move(snoozeLengthModel),
                                                                         std::move(snoozeChimeIntervalModel),
                                                                         std::move(snoozeChimeToneModel),
                                                                         std::move(snoozeChimeVolumeModel));
                auto audioModel       = std::make_unique<AudioModel>(this);
                auto soundsRepository = std::make_unique<SoundsRepository>(alarms::paths::getSnoozeChimesDir());
                auto provider         = std::make_shared<bell_settings::SnoozeListItemProvider>(
                    *snoozeSettingsModel, soundsRepository->getSongTitles());


@@ 190,12 190,12 @@ namespace app
            });
        windowsFactory.attach(
            gui::BellSettingsAlarmSettingsWindow::name, [this](ApplicationCommon *app, const std::string &) {
                auto audioModel           = std::make_unique<AudioModel>(this);
                auto alarmToneModel       = std::make_unique<bell_settings::AlarmToneModel>(this);
                auto alarmVolumeModel     = std::make_unique<bell_settings::AlarmVolumeModel>(this);
                auto alarmVolumeModel     = std::make_unique<bell_settings::AlarmVolumeModel>(*audioModel);
                auto alarmLightOnOffModel = std::make_unique<bell_settings::AlarmLightOnOffModel>(this);
                auto alarmSettingsModel   = std::make_unique<bell_settings::AlarmSettingsModel>(
                    std::move(alarmToneModel), std::move(alarmVolumeModel), std::move(alarmLightOnOffModel));
                auto audioModel       = std::make_unique<AudioModel>(this);
                auto soundsRepository = std::make_unique<SoundsRepository>(alarms::paths::getAlarmDir());
                auto provider         = std::make_shared<bell_settings::AlarmSettingsListItemProvider>(
                    *alarmSettingsModel, soundsRepository->getSongTitles());

M products/BellHybrid/apps/application-bell-settings/CMakeLists.txt => products/BellHybrid/apps/application-bell-settings/CMakeLists.txt +1 -0
@@ 120,6 120,7 @@ target_sources(application-bell-settings
target_link_libraries(application-bell-settings
    PRIVATE
        app
        bell::audio
        bellgui
        bell::db
        bell::alarms

M products/BellHybrid/apps/application-bell-settings/models/advanced/FrontlightModel.cpp => products/BellHybrid/apps/application-bell-settings/models/advanced/FrontlightModel.cpp +12 -4
@@ 10,15 10,23 @@

namespace
{
    constexpr auto multiplier = 10U;
    constexpr auto minPercent                       = 0.0f;
    constexpr auto maxPercent                       = 100.0f;
    constexpr auto minimumLightOnPercentOffsetValue = 16.0f;
    constexpr auto minBrightness                    = 1U;
    constexpr auto maxBrightness                    = 10U;
    constexpr float multiplier                      = (maxPercent - minimumLightOnPercentOffsetValue) / maxBrightness;

    float fixedValToPercentage(app::bell_settings::AbstractFrontlightModel::Brightness value)
    {
        return value * multiplier;
        float scaled = minimumLightOnPercentOffsetValue + (value - minBrightness) * multiplier;
        return std::min(maxPercent, std::max(minPercent, scaled));
    }

    app::bell_settings::AbstractFrontlightModel::Brightness percentageToFixedVal(float value)
    app::bell_settings::AbstractFrontlightModel::Brightness percentageToFixedVal(float percent)
    {
        return value / multiplier;
        auto value = (percent - minimumLightOnPercentOffsetValue) / multiplier;
        return std::round(value + minBrightness);
    }
} // namespace


M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AlarmSettingsModel.cpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AlarmSettingsModel.cpp +10 -3
@@ 21,13 21,20 @@ namespace app::bell_settings
    void AlarmVolumeModel::setValue(std::uint8_t value)
    {
        const auto valStr = std::to_string(value);
        settings.setValue(bell::settings::Alarm::volume, valStr, settings::SettingsScope::Global);
        audioModel.setVolume(value, AbstractAudioModel::PlaybackType::Alarm, {});
    }

    std::uint8_t AlarmVolumeModel::getValue() const
    {
        const auto str = settings.getValue(bell::settings::Alarm::volume, settings::SettingsScope::Global);
        return std::stoi(str);
        return defaultValue;
    }
    void AlarmVolumeModel::restoreDefault()
    {
        setValue(defaultValue);
    }
    AlarmVolumeModel::AlarmVolumeModel(AbstractAudioModel &audioModel) : audioModel{audioModel}
    {
        defaultValue = audioModel.getVolume(AbstractAudioModel::PlaybackType::Alarm).value_or(0);
    }

    void AlarmLightOnOffModel::setValue(bool value)

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AlarmSettingsModel.hpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AlarmSettingsModel.hpp +8 -3
@@ 5,6 5,7 @@

#include "AbstractAlarmSettingsModel.hpp"
#include <common/models/SettingsModel.hpp>
#include <common/models/AudioModel.hpp>

namespace app::bell_settings
{


@@ 17,13 18,17 @@ namespace app::bell_settings
        UTF8 getValue() const override;
    };

    class AlarmVolumeModel : public gui::SettingsModel<std::uint8_t>
    class AlarmVolumeModel : public gui::AbstractSettingsModel<std::uint8_t>
    {
      public:
        using SettingsModel::SettingsModel;

        explicit AlarmVolumeModel(AbstractAudioModel &audioModel);
        void setValue(std::uint8_t value) override;
        std::uint8_t getValue() const override;
        void restoreDefault() override;

      private:
        AbstractAudioModel &audioModel;
        std::uint8_t defaultValue;
    };

    class AlarmLightOnOffModel : public gui::SettingsModel<bool>

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.cpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.cpp +10 -3
@@ 33,13 33,20 @@ namespace app::bell_settings
    void PrewakeUpChimeVolumeModel::setValue(std::uint8_t value)
    {
        const auto valStr = std::to_string(value);
        settings.setValue(bell::settings::PrewakeUp::volume, valStr, settings::SettingsScope::Global);
        audioModel.setVolume(value, AbstractAudioModel::PlaybackType::PreWakeup, {});
    }

    std::uint8_t PrewakeUpChimeVolumeModel::getValue() const
    {
        const auto str = settings.getValue(bell::settings::PrewakeUp::volume, settings::SettingsScope::Global);
        return std::stoi(str);
        return defaultValue;
    }
    PrewakeUpChimeVolumeModel::PrewakeUpChimeVolumeModel(AbstractAudioModel &audioModel) : audioModel{audioModel}
    {
        defaultValue = audioModel.getVolume(AbstractAudioModel::PlaybackType::PreWakeup).value_or(0);
    }
    void PrewakeUpChimeVolumeModel::restoreDefault()
    {
        setValue(defaultValue);
    }

    void PrewakeUpLightDurationModel::setValue(std::uint8_t value)

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.hpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.hpp +8 -3
@@ 5,6 5,7 @@

#include "AbstractPrewakeUpSettingsModel.hpp"
#include <common/models/SettingsModel.hpp>
#include <common/models/AudioModel.hpp>

namespace app::bell_settings
{


@@ 26,13 27,17 @@ namespace app::bell_settings
        UTF8 getValue() const override;
    };

    class PrewakeUpChimeVolumeModel : public gui::SettingsModel<std::uint8_t>
    class PrewakeUpChimeVolumeModel : public gui::AbstractSettingsModel<std::uint8_t>
    {
      public:
        using SettingsModel::SettingsModel;

        explicit PrewakeUpChimeVolumeModel(AbstractAudioModel &audioModel);
        void setValue(std::uint8_t value) override;
        std::uint8_t getValue() const override;
        void restoreDefault() override;

      private:
        AbstractAudioModel &audioModel;
        std::uint8_t defaultValue;
    };

    class PrewakeUpLightDurationModel : public gui::SettingsModel<std::uint8_t>

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeSettingsModel.cpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeSettingsModel.cpp +10 -2
@@ 74,11 74,19 @@ namespace app::bell_settings
    void SnoozeChimeVolumeModel::setValue(std::uint8_t value)
    {
        const auto valStr = std::to_string(value);
        settings.setValue(bell::settings::Snooze::volume, valStr, settings::SettingsScope::Global);
        audioModel.setVolume(value, AbstractAudioModel::PlaybackType::Snooze, {});
    }

    std::uint8_t SnoozeChimeVolumeModel::getValue() const
    {
        return get_helper<std::uint8_t>(settings, bell::settings::Snooze::volume).value_or(0);
        return defaultValue;
    }
    SnoozeChimeVolumeModel::SnoozeChimeVolumeModel(AbstractAudioModel &audioModel) : audioModel{audioModel}
    {
        defaultValue = audioModel.getVolume(AbstractAudioModel::PlaybackType::Snooze).value_or(0);
    }
    void SnoozeChimeVolumeModel::restoreDefault()
    {
        setValue(defaultValue);
    }
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeSettingsModel.hpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeSettingsModel.hpp +8 -2
@@ 5,6 5,7 @@

#include "AbstractSnoozeSettingsModel.hpp"
#include <common/models/SettingsModel.hpp>
#include <common/models/AudioModel.hpp>

namespace app::bell_settings
{


@@ 44,13 45,18 @@ namespace app::bell_settings
        UTF8 getValue() const override;
    };

    class SnoozeChimeVolumeModel : public gui::SettingsModel<std::uint8_t>
    class SnoozeChimeVolumeModel : public gui::AbstractSettingsModel<std::uint8_t>
    {
      public:
        using SettingsModel::SettingsModel;
        explicit SnoozeChimeVolumeModel(AbstractAudioModel &audioModel);

        void setValue(std::uint8_t value) override;
        std::uint8_t getValue() const override;
        void restoreDefault() override;

      private:
        AbstractAudioModel &audioModel;
        std::uint8_t defaultValue;
    };

    class SnoozeSettingsModel : public AbstractSnoozeSettingsModel

M products/BellHybrid/apps/application-bell-settings/presenter/BedtimeSettingsPresenter.cpp => products/BellHybrid/apps/application-bell-settings/presenter/BedtimeSettingsPresenter.cpp +10 -16
@@ 12,21 12,11 @@ namespace app::bell_settings
        : provider(std::move(provider)),
          model(std::move(model)), audioModel{std::move(audioModel)}, soundsRepository{std::move(soundsRepository)}
    {
        auto playResponseCb = [this](audio::RetCode retCode, audio::Token token) {
            if (retCode != audio::RetCode::Success || !token.IsValid()) {
                LOG_ERROR("Audio preview callback failed with retcode = %s. Token validity: %d",
                          str(retCode).c_str(),
                          token.IsValid());
                return;
            }
            this->currentToken = token;
        };

        auto playSound = [this, playResponseCb](const UTF8 &val) {
        auto playSound = [this](const UTF8 &val) {
            currentSoundPath = val;
            this->audioModel->play(this->soundsRepository->titleToPath(currentSoundPath).value_or(""),
                                   playResponseCb,
                                   AbstractAudioModel::PlaybackType::Bedtime);
                                   AbstractAudioModel::PlaybackType::Bedtime,
                                   {});
        };

        this->provider->onExit = [this]() { getView()->exit(); };


@@ 36,9 26,9 @@ namespace app::bell_settings
        this->provider->onToneChange = playSound;

        this->provider->onVolumeEnter  = playSound;
        this->provider->onVolumeExit   = [this](const auto &) { this->audioModel->stop(currentToken, nullptr); };
        this->provider->onVolumeExit   = [this](const auto &) { this->stopSound(); };
        this->provider->onVolumeChange = [this, playSound](const auto &val) {
            this->audioModel->setVolume(val, AbstractAudioModel::PlaybackType::Bedtime);
            this->audioModel->setVolume(val, AbstractAudioModel::PlaybackType::Bedtime, {});
            playSound(currentSoundPath);
        };
    }


@@ 69,6 59,10 @@ namespace app::bell_settings

    void BedtimeSettingsPresenter::stopSound()
    {
        this->audioModel->stop(currentToken, nullptr);
        this->audioModel->stop({});
    }
    void BedtimeSettingsPresenter::exitWithoutSave()
    {
        model->getBedtimeVolume().restoreDefault();
    }
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/presenter/BedtimeSettingsPresenter.hpp => products/BellHybrid/apps/application-bell-settings/presenter/BedtimeSettingsPresenter.hpp +2 -1
@@ 35,6 35,7 @@ namespace app::bell_settings
            virtual auto saveData() -> void                                                 = 0;
            virtual auto loadData() -> void                                                 = 0;
            virtual auto eraseProviderData() -> void                                        = 0;
            virtual void exitWithoutSave()                                                  = 0;
        };
    };



@@ 50,6 51,7 @@ namespace app::bell_settings
        auto saveData() -> void override;
        auto loadData() -> void override;
        auto eraseProviderData() -> void override;
        void exitWithoutSave() override;

      private:
        void stopSound();


@@ 58,7 60,6 @@ namespace app::bell_settings
        std::shared_ptr<AbstractBedtimeModel> model;
        std::unique_ptr<AbstractAudioModel> audioModel;
        std::unique_ptr<AbstractSoundsRepository> soundsRepository;
        audio::Token currentToken;
        UTF8 currentSoundPath;
    };
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/AlarmSettingsPresenter.cpp => products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/AlarmSettingsPresenter.cpp +9 -15
@@ 13,20 13,10 @@ namespace app::bell_settings
        : provider(provider),
          model(std::move(model)), audioModel{std::move(audioModel)}, soundsRepository{std::move(soundsRepository)}
    {
        auto playResponseCb = [this](audio::RetCode retCode, audio::Token token) {
            if (retCode != audio::RetCode::Success || !token.IsValid()) {
                LOG_ERROR("Audio preview callback failed with retcode = %s. Token validity: %d",
                          str(retCode).c_str(),
                          token.IsValid());
                return;
            }
            this->currentToken = token;
        };

        auto playSound = [this, playResponseCb](const UTF8 &val) {
            this->audioModel->play(this->soundsRepository->titleToPath(val).value_or(""),
                                   playResponseCb,
                                   AbstractAudioModel::PlaybackType::Alarm);
        auto playSound = [this](const UTF8 &val) {
            this->audioModel->play(
                this->soundsRepository->titleToPath(val).value_or(""), AbstractAudioModel::PlaybackType::Alarm, {});
        };

        this->provider->onExit = [this]() { getView()->exit(); };


@@ 38,7 28,7 @@ namespace app::bell_settings
        this->provider->onVolumeEnter  = playSound;
        this->provider->onVolumeExit   = [this](const auto &) { stopSound(); };
        this->provider->onVolumeChange = [this](const auto &val) {
            this->audioModel->setVolume(val, AbstractAudioModel::PlaybackType::Alarm);
            this->audioModel->setVolume(val, AbstractAudioModel::PlaybackType::Alarm, {});
        };
    }



@@ 67,6 57,10 @@ namespace app::bell_settings
    }
    void AlarmSettingsPresenter::stopSound()
    {
        this->audioModel->stop(currentToken, nullptr);
        this->audioModel->stop({});
    }
    void AlarmSettingsPresenter::exitWithoutSave()
    {
        model->getAlarmVolume().restoreDefault();
    }
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/AlarmSettingsPresenter.hpp => products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/AlarmSettingsPresenter.hpp +2 -1
@@ 37,6 37,7 @@ namespace app::bell_settings
            virtual auto saveData() -> void                                                 = 0;
            virtual auto loadData() -> void                                                 = 0;
            virtual auto eraseProviderData() -> void                                        = 0;
            virtual void exitWithoutSave()                                                  = 0;
        };
    };



@@ 52,6 53,7 @@ namespace app::bell_settings
        auto saveData() -> void override;
        auto loadData() -> void override;
        auto eraseProviderData() -> void override;
        void exitWithoutSave() override;

      private:
        void stopSound();


@@ 60,6 62,5 @@ namespace app::bell_settings
        std::unique_ptr<AbstractAlarmSettingsModel> model;
        std::unique_ptr<AbstractAudioModel> audioModel;
        std::unique_ptr<AbstractSoundsRepository> soundsRepository;
        audio::Token currentToken;
    };
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/PrewakeUpPresenter.cpp => products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/PrewakeUpPresenter.cpp +10 -17
@@ 13,22 13,11 @@ namespace app::bell_settings
        : provider(std::move(provider)),
          model(std::move(model)), audioModel{std::move(audioModel)}, soundsRepository{std::move(soundsRepository)}
    {

        auto playResponseCb = [this](audio::RetCode retCode, audio::Token token) {
            if (retCode != audio::RetCode::Success || !token.IsValid()) {
                LOG_ERROR("Audio preview callback failed with retcode = %s. Token validity: %d",
                          str(retCode).c_str(),
                          token.IsValid());
                return;
            }
            this->currentToken = token;
        };

        auto playSound = [this, playResponseCb](const UTF8 &val) {
        auto playSound = [this](const UTF8 &val) {
            currentSoundPath = val;
            this->audioModel->play(this->soundsRepository->titleToPath(currentSoundPath).value_or(""),
                                   playResponseCb,
                                   AbstractAudioModel::PlaybackType::PreWakeup);
                                   AbstractAudioModel::PlaybackType::PreWakeup,
                                   {});
        };

        this->provider->onExit = [this]() { getView()->exit(); };


@@ 38,9 27,9 @@ namespace app::bell_settings
        this->provider->onToneChange = playSound;

        this->provider->onVolumeEnter  = playSound;
        this->provider->onVolumeExit   = [this](const auto &) { this->audioModel->stop(currentToken, nullptr); };
        this->provider->onVolumeExit   = [this](const auto &) { this->stopSound(); };
        this->provider->onVolumeChange = [this, playSound](const auto &val) {
            this->audioModel->setVolume(val, AbstractAudioModel::PlaybackType::PreWakeup);
            this->audioModel->setVolume(val, AbstractAudioModel::PlaybackType::PreWakeup, {});
            playSound(currentSoundPath);
        };
    }


@@ 70,6 59,10 @@ namespace app::bell_settings
    }
    void PrewakeUpWindowPresenter::stopSound()
    {
        this->audioModel->stop(currentToken, nullptr);
        this->audioModel->stop({});
    }
    void PrewakeUpWindowPresenter::exitWithoutSave()
    {
        model->getChimeVolume().restoreDefault();
    }
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/PrewakeUpPresenter.hpp => products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/PrewakeUpPresenter.hpp +2 -1
@@ 37,6 37,7 @@ namespace app::bell_settings
            virtual auto saveData() -> void                                                 = 0;
            virtual auto loadData() -> void                                                 = 0;
            virtual auto eraseProviderData() -> void                                        = 0;
            virtual void exitWithoutSave()                                                  = 0;
        };
    };



@@ 52,6 53,7 @@ namespace app::bell_settings
        auto saveData() -> void override;
        auto loadData() -> void override;
        auto eraseProviderData() -> void override;
        void exitWithoutSave() override;

      private:
        void stopSound();


@@ 60,7 62,6 @@ namespace app::bell_settings
        std::unique_ptr<AbstractPrewakeUpSettingsModel> model;
        std::unique_ptr<AbstractAudioModel> audioModel;
        std::unique_ptr<AbstractSoundsRepository> soundsRepository;
        audio::Token currentToken;
        UTF8 currentSoundPath;
    };
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/SnoozePresenter.cpp => products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/SnoozePresenter.cpp +10 -15
@@ 14,21 14,11 @@ namespace app::bell_settings
        : provider{provider}, snoozeSettingsModel{std::move(snoozeSettingsModel)}, audioModel{std::move(audioModel)},
          soundsRepository{std::move(soundsRepository)}
    {
        auto playResponseCb = [this](audio::RetCode retCode, audio::Token token) {
            if (retCode != audio::RetCode::Success || !token.IsValid()) {
                LOG_ERROR("Audio preview callback failed with retcode = %s. Token validity: %d",
                          str(retCode).c_str(),
                          token.IsValid());
                return;
            }
            this->currentToken = token;
        };

        auto playSound = [this, playResponseCb](const UTF8 &val) {
        auto playSound = [this](const UTF8 &val) {
            currentSoundPath = val;
            this->audioModel->play(this->soundsRepository->titleToPath(currentSoundPath).value_or(""),
                                   playResponseCb,
                                   AbstractAudioModel::PlaybackType::Chime);
                                   AbstractAudioModel::PlaybackType::Snooze,
                                   {});
        };

        this->provider->onExit = [this]() { getView()->exit(); };


@@ 38,8 28,9 @@ namespace app::bell_settings
        this->provider->onToneChange = playSound;

        this->provider->onVolumeEnter  = playSound;
        this->provider->onVolumeExit   = [this](const auto &) { stopSound(); };
        this->provider->onVolumeChange = [this, playSound](const auto &val) {
            this->audioModel->setVolume(val, AbstractAudioModel::PlaybackType::Chime);
            this->audioModel->setVolume(val, AbstractAudioModel::PlaybackType::Snooze, {});
            playSound(currentSoundPath);
        };
    }


@@ 65,10 56,14 @@ namespace app::bell_settings
    }
    void SnoozePresenter::stopSound()
    {
        audioModel->stop(currentToken, nullptr);
        audioModel->stop({});
    }
    void SnoozePresenter::eraseProviderData()
    {
        provider->clearData();
    }
    void SnoozePresenter::exitWithoutSave()
    {
        snoozeSettingsModel->getSnoozeChimeVolume().restoreDefault();
    }
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/SnoozePresenter.hpp => products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/SnoozePresenter.hpp +2 -2
@@ 33,6 33,7 @@ namespace app::bell_settings
        virtual void saveData()                                                         = 0;
        virtual void loadData()                                                         = 0;
        virtual void eraseProviderData()                                                = 0;
        virtual void exitWithoutSave()                                                  = 0;
    };

    class SnoozePresenter : public AbstractSnoozePresenter


@@ 46,6 47,7 @@ namespace app::bell_settings
        void saveData() override;
        void loadData() override;
        void eraseProviderData() override;
        void exitWithoutSave() override;

      private:
        void stopSound();


@@ 54,8 56,6 @@ namespace app::bell_settings
        std::unique_ptr<AbstractSnoozeSettingsModel> snoozeSettingsModel;
        std::unique_ptr<AbstractAudioModel> audioModel;
        std::unique_ptr<AbstractSoundsRepository> soundsRepository;

        audio::Token currentToken;
        UTF8 currentSoundPath;
    };
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/windows/BellSettingsBedtimeToneWindow.cpp => products/BellHybrid/apps/application-bell-settings/windows/BellSettingsBedtimeToneWindow.cpp +3 -0
@@ 51,6 51,9 @@ namespace gui
            exit();
            return true;
        }
        if (inputEvent.isShortRelease(KeyCode::KEY_RF)) {
            presenter->exitWithoutSave();
        }

        return AppWindow::onInput(inputEvent);
    }

M products/BellHybrid/apps/application-bell-settings/windows/alarm_settings/BellSettingsAlarmSettingsSnoozeWindow.cpp => products/BellHybrid/apps/application-bell-settings/windows/alarm_settings/BellSettingsAlarmSettingsSnoozeWindow.cpp +5 -0
@@ 50,6 50,11 @@ namespace gui
            exit();
            return true;
        }

        if (inputEvent.isShortRelease(KeyCode::KEY_RF)) {
            presenter->exitWithoutSave();
        }

        return AppWindow::onInput(inputEvent);
    }


M products/BellHybrid/apps/application-bell-settings/windows/alarm_settings/BellSettingsAlarmSettingsWindow.cpp => products/BellHybrid/apps/application-bell-settings/windows/alarm_settings/BellSettingsAlarmSettingsWindow.cpp +3 -0
@@ 55,6 55,9 @@ namespace gui
            exit();
            return true;
        }
        if (inputEvent.isShortRelease(KeyCode::KEY_RF)) {
            presenter->exitWithoutSave();
        }

        return AppWindow::onInput(inputEvent);
    }

M products/BellHybrid/apps/application-bell-settings/windows/alarm_settings/BellSettingsPrewakeUpWindow.cpp => products/BellHybrid/apps/application-bell-settings/windows/alarm_settings/BellSettingsPrewakeUpWindow.cpp +3 -0
@@ 54,6 54,9 @@ namespace gui
            exit();
            return true;
        }
        if (inputEvent.isShortRelease(KeyCode::KEY_RF)) {
            presenter->exitWithoutSave();
        }

        return AppWindow::onInput(inputEvent);
    }

M products/BellHybrid/apps/common/CMakeLists.txt => products/BellHybrid/apps/common/CMakeLists.txt +1 -0
@@ 79,6 79,7 @@ target_link_libraries(application-bell-common
    PRIVATE
        bell::app-main
        bell::app-alarm
        bell::audio
        module-gui
        bell::db
        )

M products/BellHybrid/apps/common/include/common/models/AbstractAudioModel.hpp => products/BellHybrid/apps/common/include/common/models/AbstractAudioModel.hpp +17 -16
@@ 3,40 3,41 @@

#pragma once

#include <Audio/AudioCommon.hpp>
#include <module-audio/Audio/AudioCommon.hpp>

#include <string>
#include <functional>
#include <optional>

namespace app
{
    using AlarmModelReadyHandler = std::function<void()>;

    class AbstractAudioModel
    {
      public:
        /// 0-10 range
        using Volume = std::uint8_t;

        using OnPlayCallback   = std::function<void(audio::RetCode retCode, audio::Token token)>;
        using OnStopCallback   = OnPlayCallback;
        using OnPauseCallback  = OnPlayCallback;
        using OnResumeCallback = OnPlayCallback;
        static constexpr auto minVolume = 1;
        static constexpr auto maxVolume = 10;
        using Volume                    = std::uint32_t;
        using OnStateChangeCallback     = std::function<void(const audio::RetCode code)>;
        using OnGetValueCallback        = std::function<void(const audio::RetCode, Volume)>;

        enum class PlaybackType
        {
            Chime,
            Multimedia,
            Snooze,
            Alarm,
            PreWakeup,
            Bedtime
        };

        virtual ~AbstractAudioModel() noexcept                                                            = default;
        virtual void setVolume(Volume volume, PlaybackType playbackType)                                  = 0;
        virtual bool play(const std::string &filePath, const OnPlayCallback &callback, PlaybackType type) = 0;
        virtual bool pause(const audio::Token &token, const OnPauseCallback &callback)                    = 0;
        virtual bool resume(const audio::Token &token, const OnResumeCallback &callback)                  = 0;
        virtual bool stop(const audio::Token &token, const OnStopCallback &callback)                      = 0;
        virtual ~AbstractAudioModel() noexcept                                                              = default;
        virtual void setVolume(Volume volume, PlaybackType playbackType, OnStateChangeCallback &&callback)  = 0;
        virtual std::optional<Volume> getVolume(PlaybackType playbackType)                                  = 0;
        virtual void getVolume(PlaybackType playbackType, OnGetValueCallback &&callback)                    = 0;
        virtual void play(const std::string &filePath, PlaybackType type, OnStateChangeCallback &&callback) = 0;
        virtual void stop(OnStateChangeCallback &&callback)                                                 = 0;
        virtual void pause(OnStateChangeCallback &&callback)                                                = 0;
        virtual void resume(OnStateChangeCallback &&callback)                                               = 0;
    };

} // namespace app

M products/BellHybrid/apps/common/include/common/models/AbstractSettingsModel.hpp => products/BellHybrid/apps/common/include/common/models/AbstractSettingsModel.hpp +44 -0
@@ 3,6 3,13 @@

#pragma once

#include <apps-common/AsyncTask.hpp>

namespace app
{
    class ApplicationCommon;
}

namespace gui
{
    template <class ValueType> class AbstractSettingsModel


@@ 12,5 19,42 @@ namespace gui

        virtual void setValue(ValueType value) = 0;
        virtual ValueType getValue() const     = 0;
        virtual void restoreDefault()
        {}
    };

    template <typename ValueT> class AsyncSettingsAdapter : public AbstractSettingsModel<ValueT>
    {
      public:
        std::function<void(ValueT)> onReady;

        void setValue(ValueT value) final
        {
            onSet(value);
        }

        ValueT getValue() const final
        {
            return currentValue;
        }

        void restoreDefault() final
        {
            onSet(defaultValue);
        }

      protected:
        std::function<void(ValueT)> onSet;

        void onUpdate(ValueT value)
        {
            currentValue = value;
            defaultValue = currentValue;
            onReady(currentValue);
        }

      private:
        ValueT currentValue{};
        ValueT defaultValue{};
    };
} // namespace gui

M products/BellHybrid/apps/common/include/common/models/AudioModel.hpp => products/BellHybrid/apps/common/include/common/models/AudioModel.hpp +9 -13
@@ 4,28 4,24 @@
#pragma once

#include "AbstractAudioModel.hpp"
#include <apps-common/AudioOperations.hpp>
#include <apps-common/AsyncTask.hpp>

namespace app
{
    class ApplicationCommon;
}

namespace app
{
    class AudioModel : public AbstractAudioModel
    class AudioModel : public AbstractAudioModel, public app::AsyncCallbackReceiver
    {
      public:
        explicit AudioModel(ApplicationCommon *app);

        void setVolume(Volume volume, PlaybackType playbackType) override;
        bool play(const std::string &filePath, const OnPlayCallback &callback, PlaybackType type) override;
        bool pause(const audio::Token &token, const OnPauseCallback &callback) override;
        bool resume(const audio::Token &token, const OnResumeCallback &callback) override;
        bool stop(const audio::Token &token, const OnStopCallback &callback) override;
        void setVolume(Volume volume, PlaybackType playbackType, OnStateChangeCallback &&callback) override;
        std::optional<Volume> getVolume(PlaybackType playbackType) override;
        void getVolume(PlaybackType playbackType, OnGetValueCallback &&callback) override;
        void play(const std::string &filePath, PlaybackType type, OnStateChangeCallback &&callback) override;
        void stop(OnStateChangeCallback &&callback) override;
        void pause(OnStateChangeCallback &&callback) override;
        void resume(OnStateChangeCallback &&callback) override;

      private:
        ApplicationCommon *app{};
        AsyncAudioOperations asyncAudioOperations;
    };
} // namespace app

M products/BellHybrid/apps/common/include/common/models/BedtimeModel.hpp => products/BellHybrid/apps/common/include/common/models/BedtimeModel.hpp +14 -6
@@ 6,13 6,14 @@
#include "AbstractBedtimeModel.hpp"
#include "SettingsModel.hpp"
#include <Service/Service.hpp>
#include <common/models/AudioModel.hpp>
#include <ApplicationCommon.hpp>
#include <ctime>

namespace app::bell_bedtime
{
    inline constexpr auto DEFAULT_BEDTIME_TIME   = "21:00";
    inline constexpr auto DEFAULT_BEDTIME_TONE   = "Evening Horizon";
    inline constexpr auto DEFAULT_BEDTIME_VOLUME = 1;
    inline constexpr auto DEFAULT_BEDTIME_TIME = "21:00";
    inline constexpr auto DEFAULT_BEDTIME_TONE = "Evening Horizon";

    class BedtimeOnOffModel : public gui::SettingsModel<bool>
    {


@@ 36,13 37,18 @@ namespace app::bell_bedtime
        auto getValue() const -> time_t override;
    };

    class BedtimeVolumeModel : public gui::SettingsModel<std::uint8_t>
    class BedtimeVolumeModel : public gui::AbstractSettingsModel<std::uint8_t>
    {
      public:
        using SettingsModel::SettingsModel;
        explicit BedtimeVolumeModel(AbstractAudioModel &audioModel);

        void setValue(std::uint8_t value) override;
        std::uint8_t getValue() const override;
        void restoreDefault() override;

      private:
        AbstractAudioModel &audioModel;
        std::uint8_t defaultValue;
    };

    class AlarmToneModel : public gui::SettingsModel<UTF8>


@@ 61,10 67,11 @@ namespace app::bell_bedtime

        explicit BedtimeModel(sys::Service *app)
        {
            audioModel    = std::make_unique<AudioModel>(static_cast<ApplicationCommon *>(app));
            bedtimeOnOff  = std::make_unique<bell_bedtime::BedtimeOnOffModel>(app);
            bedtimeTime   = std::make_unique<bell_bedtime::BedtimeTimeModel>(app);
            bedtimeTone   = std::make_unique<bell_bedtime::AlarmToneModel>(app);
            bedtimeVolume = std::make_unique<bell_bedtime::BedtimeVolumeModel>(app);
            bedtimeVolume = std::make_unique<bell_bedtime::BedtimeVolumeModel>(*audioModel);
        }
        gui::AbstractSettingsModel<bool> &getBedtimeOnOff() override
        {


@@ 86,6 93,7 @@ namespace app::bell_bedtime
        }

      private:
        std::unique_ptr<AudioModel> audioModel;
        std::unique_ptr<gui::AbstractSettingsModel<bool>> bedtimeOnOff;
        std::unique_ptr<gui::AbstractSettingsModel<time_t>> bedtimeTime;
        std::unique_ptr<gui::AbstractSettingsModel<UTF8>> bedtimeTone;

M products/BellHybrid/apps/common/src/AudioModel.cpp => products/BellHybrid/apps/common/src/AudioModel.cpp +143 -18
@@ 2,7 2,9 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "models/AudioModel.hpp"
#include <service-audio/AudioServiceAPI.hpp>

#include <ApplicationCommon.hpp>
#include <audio/AudioMessage.hpp>

namespace
{


@@ 10,45 12,168 @@ namespace
    {
        using Type = app::AbstractAudioModel::PlaybackType;
        switch (type) {
        case Type::Multimedia:
            return audio::PlaybackType::Multimedia;
        case Type::Alarm:
            return audio::PlaybackType::Alarm;
        case Type::Chime:
            return audio::PlaybackType::Alarm;
        case Type::Snooze:
            return audio::PlaybackType::Snooze;
        case Type::PreWakeup:
            return audio::PlaybackType::Alarm;
            return audio::PlaybackType::PreWakeUp;
        case Type::Bedtime:
            return audio::PlaybackType::Alarm;
            return audio::PlaybackType::Bedtime;
        default:
            return audio::PlaybackType::Alarm;
        }
    }

    void reportError(const char *prefix, audio::RetCode code)
    {
        if (code != audio::RetCode::Success) {
            LOG_ERROR("%s request error: %s", prefix, magic_enum::enum_name(code).data());
        }
    }

    auto SendAudioRequest(sys::Service *serv, std::shared_ptr<service::AudioMessage> msg)
    {
        auto msgType = static_cast<int>(msg->type);
        auto ret     = serv->bus.sendUnicastSync(msg, service::audioServiceName, sys::BusProxy::defaultTimeout);
        if (ret.first == sys::ReturnCodes::Success) {
            if (auto resp = std::dynamic_pointer_cast<service::AudioResponseMessage>(ret.second)) {
                return resp;
            }
            LOG_ERROR("msgType %d - not AudioResponseMessage", msgType);
            return std::make_shared<service::AudioResponseMessage>(audio::RetCode::Failed);
        }
        LOG_ERROR("Command %d Failed with %d error", msgType, static_cast<int>(ret.first));
        return std::make_shared<service::AudioResponseMessage>(audio::RetCode::Failed);
    }

} // namespace

namespace app
{

    AudioModel::AudioModel(ApplicationCommon *app) : app{app}, asyncAudioOperations{app}
    AudioModel::AudioModel(ApplicationCommon *app) : app::AsyncCallbackReceiver{app}, app{app}
    {}
    void AudioModel::setVolume(AbstractAudioModel::Volume volume, PlaybackType playbackType)
    void AudioModel::play(const std::string &filePath, PlaybackType type, OnStateChangeCallback &&callback)
    {
        auto msg  = std::make_unique<service::AudioStartPlaybackRequest>(filePath, convertPlaybackType(type));
        auto task = app::AsyncRequest::createFromMessage(std::move(msg), service::audioServiceName);
        auto cb   = [_callback = callback](auto response) {
            auto result = dynamic_cast<service::AudioStartPlaybackResponse *>(response);
            if (result == nullptr) {
                return false;
            }
            if (_callback) {
                _callback(result->retCode);
            }
            reportError("play", result->retCode);

            return true;
        };
        task->execute(app, this, std::move(cb));
    }

    void AudioModel::stop(OnStateChangeCallback &&callback)
    {
        auto msg  = std::make_unique<service::AudioStopRequest>();
        auto task = app::AsyncRequest::createFromMessage(std::move(msg), service::audioServiceName);
        auto cb   = [_callback = callback](auto response) {
            auto result = dynamic_cast<service::AudioStopResponse *>(response);
            if (result == nullptr) {
                return false;
            }
            if (_callback) {
                _callback(result->retCode);
            }
            reportError("stop", result->retCode);
            return true;
        };
        task->execute(app, this, std::move(cb));
    }

    void AudioModel::setVolume(AbstractAudioModel::Volume volume,
                               PlaybackType playbackType,
                               OnStateChangeCallback &&callback)
    {
        AudioServiceAPI::SetVolume(app, volume, convertPlaybackType(playbackType));
        auto msg = std::make_unique<service::AudioSetVolume>(convertPlaybackType(playbackType), std::to_string(volume));
        auto task = app::AsyncRequest::createFromMessage(std::move(msg), service::audioServiceName);
        auto cb   = [_callback = callback](auto response) {
            auto result = dynamic_cast<service::AudioResponseMessage *>(response);
            if (result == nullptr) {
                return false;
            }
            if (_callback) {
                _callback(result->retCode);
            }
            reportError("setVolume", result->retCode);
            return true;
        };
        task->execute(app, this, std::move(cb));
    }
    bool AudioModel::play(const std::string &filePath,
                          const AbstractAudioOperations::OnPlayCallback &callback,
                          PlaybackType type)
    void AudioModel::pause(OnStateChangeCallback &&callback)
    {
        return asyncAudioOperations.play(filePath, callback, convertPlaybackType(type));
        auto msg  = std::make_unique<service::AudioPauseRequest>();
        auto task = app::AsyncRequest::createFromMessage(std::move(msg), service::audioServiceName);
        auto cb   = [_callback = callback](auto response) {
            auto result = dynamic_cast<service::AudioResponseMessage *>(response);
            if (result == nullptr) {
                return false;
            }
            if (_callback) {
                _callback(result->retCode);
            }

            reportError("pause", result->retCode);
            return true;
        };
        task->execute(app, this, std::move(cb));
    }
    bool AudioModel::pause(const audio::Token &token, const AbstractAudioOperations::OnPauseCallback &callback)
    void AudioModel::resume(OnStateChangeCallback &&callback)
    {
        return asyncAudioOperations.pause(token, callback);
        auto msg  = std::make_unique<service::AudioResumeRequest>();
        auto task = app::AsyncRequest::createFromMessage(std::move(msg), service::audioServiceName);
        auto cb   = [_callback = callback](auto response) {
            auto result = dynamic_cast<service::AudioResponseMessage *>(response);
            if (result == nullptr) {
                return false;
            }
            if (_callback) {
                _callback(result->retCode);
            }
            reportError("resume", result->retCode);
            return true;
        };
        task->execute(app, this, std::move(cb));
    }
    bool AudioModel::resume(const audio::Token &token, const AbstractAudioOperations::OnResumeCallback &callback)
    void AudioModel::getVolume(AbstractAudioModel::PlaybackType playbackType,
                               AbstractAudioModel::OnGetValueCallback &&callback)
    {
        return asyncAudioOperations.resume(token, callback);
        auto msg  = std::make_unique<service::AudioGetVolume>(convertPlaybackType(playbackType));
        auto task = app::AsyncRequest::createFromMessage(std::move(msg), service::audioServiceName);
        auto cb   = [_callback = callback](auto response) {
            auto result = dynamic_cast<service::AudioResponseMessage *>(response);
            if (result == nullptr) {
                return false;
            }
            if (_callback) {
                _callback(result->retCode, utils::getNumericValue<AbstractAudioModel::Volume>(result->val));
            }

            reportError("getVolume", result->retCode);
            return true;
        };
        task->execute(app, this, std::move(cb));
    }
    bool AudioModel::stop(const audio::Token &token, const AbstractAudioOperations::OnStopCallback &callback)
    std::optional<AbstractAudioModel::Volume> AudioModel::getVolume(AbstractAudioModel::PlaybackType playbackType)
    {
        return asyncAudioOperations.stop(token, callback);
        auto msg       = std::make_shared<service::AudioGetVolume>(convertPlaybackType(playbackType));
        const auto ret = SendAudioRequest(app, msg);
        if (ret) {
            return utils::getNumericValue<audio::Volume>(ret->val);
        }

        return {};
    }
} // namespace app

M products/BellHybrid/apps/common/src/models/BedtimeModel.cpp => products/BellHybrid/apps/common/src/models/BedtimeModel.cpp +10 -8
@@ 78,18 78,20 @@ namespace app::bell_bedtime
    void BedtimeVolumeModel::setValue(std::uint8_t value)
    {
        const auto valStr = std::to_string(value);
        settings.setValue(bell::settings::Bedtime::volume, valStr, settings::SettingsScope::Global);
        audioModel.setVolume(value, AbstractAudioModel::PlaybackType::Bedtime, {});
    }

    auto BedtimeVolumeModel::getValue() const -> std::uint8_t
    {
        const auto str = settings.getValue(bell::settings::Bedtime::volume, settings::SettingsScope::Global);
        try {
            return std::stoi(str);
        }
        catch (const std::invalid_argument &) {
            return DEFAULT_BEDTIME_VOLUME;
        }
        return defaultValue;
    }
    BedtimeVolumeModel::BedtimeVolumeModel(AbstractAudioModel &audioModel) : audioModel{audioModel}
    {
        defaultValue = audioModel.getVolume(AbstractAudioModel::PlaybackType::Bedtime).value_or(0);
    }
    void BedtimeVolumeModel::restoreDefault()
    {
        setValue(defaultValue);
    }

} // namespace app::bell_bedtime

M products/BellHybrid/apps/common/src/popups/BedtimeNotificationWindow.cpp => products/BellHybrid/apps/common/src/popups/BedtimeNotificationWindow.cpp +3 -3
@@ 1,13 1,14 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <audio/AudioMessage.hpp>
#include <apps-common/popups/Popups.hpp>
#include <apps-common/popups/data/PopupRequestParams.hpp>
#include <common/popups/BedtimeNotificationWindow.hpp>
#include <gui/input/InputEvent.hpp>
#include <gui/widgets/Icon.hpp>
#include <i18n/i18n.hpp>
#include <purefs/filesystem_paths.hpp>
#include <service-audio/AudioServiceAPI.hpp>
#include <service-appmgr/Controller.hpp>

namespace gui


@@ 72,8 73,7 @@ namespace gui

    void BedtimeNotificationWindow::onClose(CloseReason reason)
    {
        auto stopPlaybackVec = std::vector<audio::PlaybackType>({audio::PlaybackType::Multimedia});
        AudioServiceAPI::Stop(app, stopPlaybackVec);
        application->bus.sendUnicast(std::make_shared<service::AudioStopRequest>(), service::audioServiceName);
    }

} /* namespace gui */

M products/BellHybrid/services/CMakeLists.txt => products/BellHybrid/services/CMakeLists.txt +1 -0
@@ 5,3 5,4 @@ add_subdirectory(evtmgr)
add_subdirectory(db)
add_subdirectory(desktop)
add_subdirectory(time)
add_subdirectory(audio)

A products/BellHybrid/services/audio/CMakeLists.txt => products/BellHybrid/services/audio/CMakeLists.txt +33 -0
@@ 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
add_library(bell-audio STATIC)
add_library(bell::audio ALIAS bell-audio)

target_include_directories(bell-audio
        PRIVATE
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/audio>
        PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
        )

target_sources(bell-audio
        PRIVATE
        ServiceAudio.cpp

        PUBLIC
        include/audio/AudioMessage.hpp
        include/audio/ServiceAudio.hpp

        )


target_link_libraries(bell-audio
        PRIVATE
        log
        module-utils
        service-db
        PUBLIC
        messagetype
        module-audio
        module-sys
        )

A products/BellHybrid/services/audio/ServiceAudio.cpp => products/BellHybrid/services/audio/ServiceAudio.cpp +307 -0
@@ 0,0 1,307 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ServiceAudio.hpp"
#include "system/Constants.hpp"

#include <audio/AudioMessage.hpp>
#include <service-db/Settings.hpp>
#include <system/messages/SentinelRegistrationMessage.hpp>

namespace
{
    constexpr auto stackSize            = 1024 * 4;
    constexpr auto defaultVolume        = "5";
    constexpr audio::Volume maxInVolume = 10;
    constexpr audio::Volume minVolume   = 0;
    constexpr auto profileType          = audio::Profile::Type::PlaybackLoudspeaker;
    namespace initializer
    {
        using namespace audio;
        // clang-format off
        static constexpr std::initializer_list<std::pair<audio::DbPathElement, const char *>> values{
            {DbPathElement{Setting::Volume, PlaybackType::Meditation, Profile::Type::PlaybackLoudspeaker},defaultVolume},
            {DbPathElement{Setting::Volume, PlaybackType::Multimedia, Profile::Type::PlaybackLoudspeaker},defaultVolume},
            {DbPathElement{Setting::Volume, PlaybackType::Alarm, Profile::Type::PlaybackLoudspeaker}, defaultVolume},
            {DbPathElement{Setting::Volume, PlaybackType::Bedtime, Profile::Type::PlaybackLoudspeaker}, defaultVolume},
            {DbPathElement{Setting::Volume, PlaybackType::PreWakeUp, Profile::Type::PlaybackLoudspeaker},defaultVolume},
            {DbPathElement{Setting::Volume, PlaybackType::Snooze, Profile::Type::PlaybackLoudspeaker}, defaultVolume},

            /// Profiles below are not used but unfortunately, must exist in order to satisfy audio module requirements
            {DbPathElement{Setting::Volume, PlaybackType::Meditation, Profile::Type::PlaybackHeadphones},defaultVolume},
            {DbPathElement{Setting::Volume, PlaybackType::Meditation, Profile::Type::PlaybackBluetoothA2DP},defaultVolume},
            {DbPathElement{Setting::Volume, PlaybackType::Multimedia, Profile::Type::PlaybackHeadphones},defaultVolume},
            {DbPathElement{Setting::Volume, PlaybackType::Multimedia, Profile::Type::PlaybackBluetoothA2DP},defaultVolume},
            {DbPathElement{Setting::Volume, PlaybackType::Alarm, Profile::Type::PlaybackHeadphones}, defaultVolume},
            {DbPathElement{Setting::Volume, PlaybackType::Alarm, Profile::Type::PlaybackBluetoothA2DP}, defaultVolume},
            {DbPathElement{Setting::Volume, PlaybackType::Bedtime, Profile::Type::PlaybackHeadphones}, defaultVolume},
            {DbPathElement{Setting::Volume, PlaybackType::Bedtime, Profile::Type::PlaybackBluetoothA2DP},defaultVolume},
            {DbPathElement{Setting::Volume, PlaybackType::PreWakeUp, Profile::Type::PlaybackHeadphones}, defaultVolume},
            {DbPathElement{Setting::Volume, PlaybackType::PreWakeUp, Profile::Type::PlaybackBluetoothA2DP},defaultVolume},
            {DbPathElement{Setting::Volume, PlaybackType::Snooze, Profile::Type::PlaybackHeadphones}, defaultVolume},
            {DbPathElement{Setting::Volume, PlaybackType::Snooze, Profile::Type::PlaybackBluetoothA2DP}, defaultVolume},
        };
        // clang-format on
    } // namespace initializer

    class AudioInternalEOFNotificationMessage : public service::AudioNotificationMessage
    {
      public:
        explicit AudioInternalEOFNotificationMessage(audio::Token token) : AudioNotificationMessage(token)
        {}
    };
} // namespace

namespace service
{
    Audio::Audio()
        : sys::Service(audioServiceName, "", stackSize, sys::ServicePriority::Idle),
          audioMux([this](auto... params) { return this->AudioServicesCallback(params...); }),
          cpuSentinel(std::make_shared<sys::CpuSentinel>(audioServiceName, this)),
          settingsProvider(std::make_unique<settings::Settings>())
    {
        LOG_INFO("%s Initializing", audioServiceName);
        bus.channels.push_back(sys::BusChannel::ServiceAudioNotifications);

        auto sentinelRegistrationMsg = std::make_shared<sys::SentinelRegistrationMessage>(cpuSentinel);
        bus.sendUnicast(std::move(sentinelRegistrationMsg), service::name::system_manager);

        connect(typeid(AudioStartPlaybackRequest), [this](sys::Message *msg) -> sys::MessagePointer {
            auto *msgl = static_cast<AudioStartPlaybackRequest *>(msg);
            return handleStart(audio::Operation::Type::Playback, msgl->fileName.c_str(), msgl->playbackType);
        });

        connect(typeid(AudioInternalEOFNotificationMessage), [this](sys::Message *msg) -> sys::MessagePointer {
            auto *msgl = static_cast<AudioInternalEOFNotificationMessage *>(msg);
            handleEOF(msgl->token);
            return sys::msgHandled();
        });

        connect(typeid(AudioStopRequest), [this](sys::Message *msg) -> sys::MessagePointer {
            auto *msgl = static_cast<AudioStopRequest *>(msg);
            return handleStop(msgl->stopVec, msgl->token);
        });

        connect(typeid(AudioSetVolume), [this](sys::Message *msg) -> sys::MessagePointer {
            auto *msgl = static_cast<AudioSetVolume *>(msg);
            return handleSetVolume(msgl->playbackType, msgl->val);
        });

        connect(typeid(AudioGetVolume), [this](sys::Message *msg) -> sys::MessagePointer {
            auto *msgl = static_cast<AudioGetVolume *>(msg);
            return handleGetVolume(msgl->playbackType);
        });

        connect(typeid(AudioPauseRequest), [this](sys::Message *msg) -> sys::MessagePointer { return handlePause(); });

        connect(typeid(AudioResumeRequest),
                [this](sys::Message *msg) -> sys::MessagePointer { return handleResume(); });
    }
    sys::MessagePointer Audio::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp)
    {
        return sys::msgNotHandled();
    }
    sys::ReturnCodes Audio::InitHandler()
    {
        settingsProvider->init(service::ServiceProxy(weak_from_this()));
        initializeDatabase();

        return sys::ReturnCodes::Success;
    }
    sys::ReturnCodes Audio::DeinitHandler()
    {
        return sys::ReturnCodes::Success;
    }
    void Audio::ProcessCloseReason([[maybe_unused]] sys::CloseReason closeReason)
    {
        if (const auto &activeInputOpt = audioMux.GetActiveInput(); activeInputOpt.has_value()) {
            const auto activeInput = activeInputOpt.value();
            activeInput->audio->Stop();
        }
        sendCloseReadyMessage(this);
    }
    auto Audio::handleStart(const audio::Operation::Type opType,
                            const std::string &fileName,
                            const audio::PlaybackType &playbackType) -> std::unique_ptr<AudioResponseMessage>
    {
        auto retCode  = audio::RetCode::Failed;
        auto retToken = audio::Token::MakeBadToken();

        auto AudioStart = [&](auto &input) {
            if (input) {
                for (auto &audioInput : audioMux.GetAllInputs()) {
                    stopInput(&audioInput);
                }
                retToken = audioMux.ResetInput(input);

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

        return std::make_unique<AudioStartPlaybackResponse>(retCode, retToken);
    }
    auto Audio::handleStop(const std::vector<audio::PlaybackType> &stopTypes, const audio::Token &token)
        -> std::unique_ptr<AudioResponseMessage>
    {
        std::vector<std::pair<audio::Token, audio::RetCode>> retCodes;

        for (auto &input : audioMux.GetAllInputs()) {
            auto t = input.token;
            retCodes.emplace_back(t, stopInput(&input));
        }

        // on failure return first false code
        auto it = std::find_if_not(
            retCodes.begin(), retCodes.end(), [](auto p) { return p.second == audio::RetCode::Success; });
        if (it != retCodes.end()) {
            return std::make_unique<AudioStopResponse>(it->second, it->first);
        }

        return std::make_unique<AudioStopResponse>(audio::RetCode::Success, token);
    }
    auto Audio::stopInput(audio::AudioMux::Input *input, Audio::StopReason stopReason) -> audio::RetCode
    {
        if (input->audio->GetCurrentState() == audio::Audio::State::Idle) {
            return audio::RetCode::Success;
        }
        const auto retCode = input->audio->Stop();
        // Send notification that audio file was stopped
        std::shared_ptr<AudioNotificationMessage> msg;
        if (stopReason == StopReason::Eof) {
            msg = std::make_shared<AudioEOFNotification>(input->token);
        }
        else {
            msg = std::make_shared<AudioStopNotification>(input->token);
        }
        bus.sendMulticast(std::move(msg), sys::BusChannel::ServiceAudioNotifications);
        audioMux.ResetInput(input);
        return retCode;
    }
    constexpr auto Audio::shouldLoop(const std::optional<audio::PlaybackType> &type) const -> bool
    {
        return type == audio::PlaybackType::Alarm;
    }
    auto Audio::isBusy() const -> bool
    {
        const auto &inputs = audioMux.GetAllInputs();
        return std::any_of(inputs.begin(), inputs.end(), [](const auto &input) {
            return input.audio->GetCurrentState() != audio::Audio::State::Idle;
        });
    }
    void Audio::handleEOF(const audio::Token &token)
    {
        if (const auto input = audioMux.GetInput(token); input) {
            if (shouldLoop((*input)->audio->GetCurrentOperationPlaybackType())) {
                (*input)->audio->Start();
                if ((*input)->audio->IsMuted()) {
                    (*input)->audio->Mute();
                }
            }
            else {
                stopInput(*input, StopReason::Eof);
            }
        }
    }
    auto Audio::AudioServicesCallback(const sys::Message *msg) -> std::optional<std::string>
    {
        std::optional<std::string> ret;
        if (const auto *eof = dynamic_cast<const AudioServiceMessage::EndOfFile *>(msg); eof) {
            bus.sendUnicast(std::make_shared<AudioInternalEOFNotificationMessage>(eof->GetToken()), audioServiceName);
        }
        else if (const auto *dbReq = dynamic_cast<const AudioServiceMessage::DbRequest *>(msg); dbReq) {
            auto selectedPlayback = dbReq->playback;
            auto selectedProfile  = dbReq->profile;
            if (const auto result =
                    settingsProvider->getValue(dbPath(dbReq->setting, selectedPlayback, selectedProfile));
                not result.empty()) {
                ret.emplace(result);
            }
        }
        else {
            LOG_DEBUG("Message received but not handled - no effect.");
        }

        return ret;
    }
    auto Audio::handleSetVolume(const audio::PlaybackType &playbackType, const std::string &value)
        -> std::unique_ptr<AudioResponseMessage>
    {
        constexpr auto setting  = audio::Setting::Volume;
        auto retCode            = audio::RetCode::Success;
        const auto clampedValue = std::clamp(utils::getNumericValue<audio::Volume>(value), minVolume, maxInVolume);

        if (const auto activeInput = audioMux.GetActiveInput(); activeInput) {
            if (activeInput) {
                retCode = activeInput.value()->audio->SetOutputVolume(clampedValue);
            }
        }

        if (retCode == audio::RetCode::Success) {
            settingsProvider->setValue(dbPath(setting, playbackType, profileType), std::to_string(clampedValue));
        }
        return std::make_unique<AudioResponseMessage>(retCode);
    }
    auto Audio::handleGetVolume(const audio::PlaybackType &playbackType) -> std::unique_ptr<AudioResponseMessage>
    {
        constexpr auto setting = audio::Setting::Volume;

        const auto path = dbPath(setting, playbackType, profileType);
        if (const auto value = settingsProvider->getValue(path); not value.empty()) {
            return std::make_unique<AudioResponseMessage>(audio::RetCode::Success, value);
        }

        return std::make_unique<AudioResponseMessage>(audio::RetCode::Failed);
    }
    sys::ReturnCodes Audio::SwitchPowerModeHandler([[maybe_unused]] const sys::ServicePowerMode mode)
    {
        return sys::ReturnCodes::Success;
    }
    auto Audio::handlePause() -> std::unique_ptr<AudioResponseMessage>
    {
        auto retCode = audio::RetCode::InvokedInIncorrectState;
        if (const auto activeInput = audioMux.GetActiveInput(); activeInput) {
            auto playbackType = (*activeInput)->audio->GetCurrentOperationPlaybackType();
            if (isResumable(playbackType)) {
                retCode = activeInput.value()->audio->Pause();
            }
            else {
                retCode = audio::RetCode::UnsupportedEvent;
            }
        }
        return std::make_unique<AudioResponseMessage>(retCode);
    }
    auto Audio::handleResume() -> std::unique_ptr<AudioResponseMessage>
    {
        auto retCode = audio::RetCode::InvokedInIncorrectState;
        if (const auto activeInput = audioMux.GetActiveInput();
            activeInput && activeInput.value()->audio->GetCurrentOperationState() == audio::Operation::State::Paused) {
            retCode = activeInput.value()->audio->Resume();
        }
        return std::make_unique<AudioResponseMessage>(retCode);
    }
    constexpr auto Audio::isResumable(audio::PlaybackType type) const -> bool
    {
        return type == audio::PlaybackType::Multimedia;
    }
    void Audio::manageCpuSentinel()
    {
        isBusy() ? cpuSentinel->HoldMinimumFrequency(bsp::CpuFrequencyHz::Level_6)
                 : cpuSentinel->ReleaseMinimumFrequency();
    }
    void Audio::initializeDatabase()
    {
        for (const auto &entry : initializer::values) {
            const auto path = dbPath(entry.first);
            if (settingsProvider->getValue(path).empty()) {
                settingsProvider->setValue(path, entry.second);
            }
        }
    }
} // namespace service

A products/BellHybrid/services/audio/include/audio/AudioMessage.hpp => products/BellHybrid/services/audio/include/audio/AudioMessage.hpp +141 -0
@@ 0,0 1,141 @@
// 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 <Audio/AudioCommon.hpp>
#include <MessageType.hpp>
#include <Service/Message.hpp>

#include <memory>
#include <variant>

namespace service
{
    inline constexpr auto audioServiceName = "ServiceAudio";

    class AudioMessage : public sys::DataMessage
    {
      public:
        AudioMessage() : sys::DataMessage(MessageType::AudioMessage)
        {}
    };

    class AudioResponseMessage : public sys::ResponseMessage
    {
      public:
        explicit AudioResponseMessage(audio::RetCode retCode = audio::RetCode::Success, const std::string &val = {})
            : sys::ResponseMessage(), retCode(retCode), val(val)
        {}

        const audio::RetCode retCode = audio::RetCode::Success;
        std::string val;
    };

    class AudioNotificationMessage : public AudioMessage
    {
      public:
        explicit AudioNotificationMessage(audio::Token token) : token{token}
        {}

        const audio::Token token;
    };

    class AudioStopNotification : public AudioNotificationMessage
    {
      public:
        explicit AudioStopNotification(audio::Token token) : AudioNotificationMessage{token}
        {}
    };

    class AudioEOFNotification : public AudioNotificationMessage
    {
      public:
        explicit AudioEOFNotification(audio::Token token) : AudioNotificationMessage{token}
        {}
    };

    class AudioSettingsMessage : public AudioMessage
    {
      public:
        AudioSettingsMessage(const audio::PlaybackType &playbackType, const std::string &val = {})
            : AudioMessage{}, playbackType{playbackType}, val{val}
        {}

        audio::PlaybackType playbackType = audio::PlaybackType::None;
        std::string val{};
    };

    class AudioGetVolume : public AudioSettingsMessage
    {
      public:
        AudioGetVolume(const audio::PlaybackType &playbackType) : AudioSettingsMessage{playbackType}
        {}
    };

    class AudioSetVolume : public AudioSettingsMessage
    {
      public:
        AudioSetVolume(const audio::PlaybackType &playbackType, const std::string &val)
            : AudioSettingsMessage{playbackType, val}
        {}
    };

    class AudioStopRequest : public AudioMessage
    {
      public:
        explicit AudioStopRequest(const std::vector<audio::PlaybackType> &stopVec = {}) : stopVec(stopVec)
        {}

        explicit AudioStopRequest(const audio::Token &token) : token(token)
        {}

        const std::vector<audio::PlaybackType> stopVec;
        const audio::Token token;
    };

    class AudioStopResponse : public AudioResponseMessage
    {
      public:
        AudioStopResponse(audio::RetCode retCode, const audio::Token &token)
            : AudioResponseMessage(retCode), token(token)
        {}

        const audio::Token token;
    };

    class AudioStartPlaybackRequest : public AudioMessage
    {
      public:
        AudioStartPlaybackRequest(const std::string &fileName, const audio::PlaybackType &playbackType)
            : AudioMessage(), fileName(fileName), playbackType(playbackType)
        {}

        const std::string fileName;
        const audio::PlaybackType playbackType;
    };

    class AudioStartPlaybackResponse : public AudioResponseMessage
    {
      public:
        AudioStartPlaybackResponse(audio::RetCode retCode, const audio::Token &token)
            : AudioResponseMessage(retCode), token(token)
        {}

        const audio::Token token;
    };

    class AudioPauseRequest : public AudioMessage
    {
      public:
        AudioPauseRequest() : AudioMessage()
        {}
    };

    class AudioResumeRequest : public AudioMessage
    {
      public:
        AudioResumeRequest() : AudioMessage()
        {}
    };
} // namespace service

A products/BellHybrid/services/audio/include/audio/ServiceAudio.hpp => products/BellHybrid/services/audio/include/audio/ServiceAudio.hpp +87 -0
@@ 0,0 1,87 @@
// 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 "AudioMessage.hpp"
#include <Audio/Audio.hpp>
#include <Audio/AudioMux.hpp>
#include <MessageType.hpp>
#include <service-db/DBServiceName.hpp>
#include <Service/Service.hpp>
#include <SystemManager/CpuSentinel.hpp>

#include <functional>

namespace settings
{
    class Settings;
}

namespace service
{
    class Audio : public sys::Service
    {
      public:
        Audio();

        sys::MessagePointer DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp = nullptr) final;
        sys::ReturnCodes InitHandler() final;
        sys::ReturnCodes DeinitHandler() final;
        sys::ReturnCodes SwitchPowerModeHandler(const sys::ServicePowerMode mode) final;
        void ProcessCloseReason(sys::CloseReason closeReason) final;

      private:
        enum class StopReason
        {
            Eof,
            Other
        };

        auto handleStart(audio::Operation::Type opType,
                         const std::string &fileName             = {},
                         const audio::PlaybackType &playbackType = audio::PlaybackType::None)
            -> std::unique_ptr<AudioResponseMessage>;
        auto handleStop(const std::vector<audio::PlaybackType> &stopTypes, const audio::Token &token)
            -> std::unique_ptr<AudioResponseMessage>;

        auto handleSetVolume(const audio::PlaybackType &playbackType, const std::string &value)
            -> std::unique_ptr<AudioResponseMessage>;
        auto handleGetVolume(const audio::PlaybackType &playbackType) -> std::unique_ptr<AudioResponseMessage>;

        auto handlePause() -> std::unique_ptr<AudioResponseMessage>;
        auto handleResume() -> std::unique_ptr<AudioResponseMessage>;

        void handleEOF(const audio::Token &token);

        auto AudioServicesCallback(const sys::Message *msg) -> std::optional<std::string>;

        auto stopInput(audio::AudioMux::Input *input, StopReason stopReason = StopReason::Other) -> audio::RetCode;

        constexpr auto shouldLoop(const std::optional<audio::PlaybackType> &type) const -> bool;
        constexpr auto isResumable(audio::PlaybackType type) const -> bool;
        auto isBusy() const -> bool;

        void manageCpuSentinel();
        void initializeDatabase();

        mutable audio::AudioMux audioMux;
        std::shared_ptr<sys::CpuSentinel> cpuSentinel;
        std::unique_ptr<settings::Settings> settingsProvider;
    };

} // namespace service

namespace sys
{
    template <> struct ManifestTraits<service::Audio>
    {
        static auto GetManifest() -> ServiceManifest
        {
            ServiceManifest manifest;
            manifest.name         = service::audioServiceName;
            manifest.dependencies = {service::name::db};
            return manifest;
        }
    };
} // namespace sys

M products/BellHybrid/services/db/include/db/SystemSettings.hpp => products/BellHybrid/services/db/include/db/SystemSettings.hpp +0 -4
@@ 15,19 15,16 @@ namespace bell::settings
        constexpr inline auto length   = "snooze_length";
        constexpr inline auto interval = "snooze_interval";
        constexpr inline auto tone     = "snooze_tone";
        constexpr inline auto volume   = "snooze_volume";
    } // namespace Snooze
    namespace PrewakeUp
    {
        constexpr inline auto duration      = "prewake_up_duration";
        constexpr inline auto tone          = "prewake_up_tone";
        constexpr inline auto volume        = "prewake_up_volume";
        constexpr inline auto lightDuration = "prewake_up_light_duration";
    } // namespace PrewakeUp
    namespace Alarm
    {
        constexpr inline auto tone        = "alarm_tone";
        constexpr inline auto volume      = "alarm_volume";
        constexpr inline auto lightActive = "alarm_light_active";
        constexpr inline auto duration    = "alarm_duration";
    } // namespace Alarm


@@ 36,7 33,6 @@ namespace bell::settings
        constexpr inline auto active   = "bedtime_active";
        constexpr inline auto time     = "bedtime_time";
        constexpr inline auto tone     = "bedtime_tone";
        constexpr inline auto volume   = "bedtime_volume";
        constexpr inline auto duration = "bedtime_duration";
    } // namespace Bedtime
};    // namespace bell::settings

M products/BellHybrid/services/evtmgr/CMakeLists.txt => products/BellHybrid/services/evtmgr/CMakeLists.txt +2 -0
@@ 12,6 12,7 @@ target_sources(evtmgr
        internal/StaticData.hpp
        screen-light-control/ScreenLightControl.cpp
        backlight-handler/BacklightHandler.cpp
        user-activity-handler/UserActivityHandler.cpp

        internal/key_sequences/AbstractKeySequence.hpp
        internal/key_sequences/KeySequenceMgr.hpp


@@ 26,6 27,7 @@ target_sources(evtmgr
        include/evtmgr/EventManager.hpp
        include/evtmgr/api/TemperatureApi.hpp
        include/evtmgr/backlight-handler/BacklightHandler.hpp
        include/evtmgr/user-activity-handler/UserActivityHandler.hpp
)

target_include_directories(evtmgr

M products/BellHybrid/services/evtmgr/EventManager.cpp => products/BellHybrid/services/evtmgr/EventManager.cpp +2 -1
@@ 38,7 38,7 @@ namespace

EventManager::EventManager(const std::string &name)
    : EventManagerCommon(name), temperatureSource{hal::temperature::AbstractTemperatureSource::Factory::create()},
      backlightHandler(settings, this)
      backlightHandler(settings, this), userActivityHandler(std::make_shared<sys::CpuSentinel>(name, this), this)
{
    buildKeySequences();
    updateTemperature(*temperatureSource);


@@ 56,6 56,7 @@ void EventManager::handleKeyEvent(sys::Message *msg)
    }

    if (kbdMessage->key.state == RawKey::State::Pressed || kbdMessage->key.state == RawKey::State::Moved) {
        userActivityHandler.handleUserInput();
        backlightHandler.handleKeyPressed(static_cast<int>(mapKey(static_cast<gui::KeyCode>(kbdMessage->key.keyCode))));
    }


M products/BellHybrid/services/evtmgr/WorkerEvent.cpp => products/BellHybrid/services/evtmgr/WorkerEvent.cpp +0 -1
@@ 4,7 4,6 @@
#include "WorkerEvent.hpp"

#include <bsp/eink_frontlight/eink_frontlight.hpp>
#include <service-audio/AudioMessage.hpp>
#include <service-evtmgr/EVMessages.hpp>

namespace bell

M products/BellHybrid/services/evtmgr/include/evtmgr/EventManager.hpp => products/BellHybrid/services/evtmgr/include/evtmgr/EventManager.hpp +2 -0
@@ 6,6 6,7 @@
#include <service-evtmgr/EventManagerCommon.hpp>

#include "backlight-handler/BacklightHandler.hpp"
#include "user-activity-handler/UserActivityHandler.hpp"

class KeySequenceMgr;



@@ 27,6 28,7 @@ class EventManager : public EventManagerCommon
    void buildKeySequences();
    std::shared_ptr<hal::temperature::AbstractTemperatureSource> temperatureSource;
    backlight::Handler backlightHandler;
    evm::UserActivityHandler userActivityHandler;

    std::shared_ptr<KeySequenceMgr> keySequenceMgr;
};

A products/BellHybrid/services/evtmgr/include/evtmgr/user-activity-handler/UserActivityHandler.hpp => products/BellHybrid/services/evtmgr/include/evtmgr/user-activity-handler/UserActivityHandler.hpp +25 -0
@@ 0,0 1,25 @@
// 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 <Timers/TimerHandle.hpp>
#include <SystemManager/CpuSentinel.hpp>
#include <Service/Service.hpp>

namespace evm
{
    class UserActivityHandler
    {
      public:
        UserActivityHandler(std::shared_ptr<sys::CpuSentinel> cpuSentinel, sys::Service *parent);

        void handleUserInput();

      private:
        void onUserActivityTimeout();

        std::shared_ptr<sys::CpuSentinel> cpuSentinel;
        sys::TimerHandle activityTimer;
    };
} // namespace evm

A products/BellHybrid/services/evtmgr/user-activity-handler/UserActivityHandler.cpp => products/BellHybrid/services/evtmgr/user-activity-handler/UserActivityHandler.cpp +36 -0
@@ 0,0 1,36 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <evtmgr/user-activity-handler/UserActivityHandler.hpp>
#include <Timers/TimerFactory.hpp>

namespace evm
{
    namespace
    {
        constexpr auto userActivityTimerTime = std::chrono::seconds(10);
        constexpr auto userActivityCPULevel  = bsp::CpuFrequencyHz::Level_5;
    } // namespace

    UserActivityHandler::UserActivityHandler(std::shared_ptr<sys::CpuSentinel> cpuSentinel, sys::Service *parent)
        : cpuSentinel{std::move(cpuSentinel)},
          activityTimer{sys::TimerFactory::createSingleShotTimer(
              parent, "UserActivityTimer", userActivityTimerTime, [this]([[maybe_unused]] sys::Timer &timer) {
                  onUserActivityTimeout();
              })}
    {}

    void UserActivityHandler::handleUserInput()
    {
        if (!activityTimer.isActive()) {
            cpuSentinel->HoldMinimumFrequency(userActivityCPULevel);
        }
        activityTimer.restart(userActivityTimerTime);
    }

    void UserActivityHandler::onUserActivityTimeout()
    {
        cpuSentinel->ReleaseMinimumFrequency();
    }

} // namespace evm