~aleteoryx/muditaos

b65675615912f41c355523d17cf28c3bf8eadb80 — Mateusz Piesta 4 years ago 6888e44
[BH-1117] Bell audio service

Added Bell audio service
Added volume scaling.
69 files changed, 1119 insertions(+), 475 deletions(-)

M image/user/db/settings_bell_002.sql
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 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/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/WorkerEvent.cpp
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-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 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 +12 -37
@@ 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,23 @@ 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();
            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();
        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/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/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