~aleteoryx/muditaos

b327fc36e22afa15cd8bceea691d8946ad49fcb8 — hubert-chrzaniuk 5 years ago 6295751
[EGD-3778] Add priorities and sound mux to audio system (#726)

M changelog.md => changelog.md +1 -0
@@ 6,6 6,7 @@

* `[calendar]` Add notifications from database handling.
* `[cellular]``[call app]` Added DTMF tone generation 
* `[audio]` Enabled sounds priorities

### Changed


M module-apps/application-call/ApplicationCall.cpp => module-apps/application-call/ApplicationCall.cpp +6 -4
@@ 59,7 59,8 @@ namespace app
        assert(callWindow != nullptr);

        LOG_INFO("---------------------------------CallAborted");
        AudioServiceAPI::Stop(this);
        AudioServiceAPI::Stop(this, routingAudioHandle);
        AudioServiceAPI::Stop(this, callringAudioHandle);
        callDelayedStopTime = utils::time::Timestamp() + delayToSwitchToPreviousApp;
        callWindow->setState(gui::CallWindow::State::CALL_ENDED);
        if (getState() == State::ACTIVE_FORGROUND && getCurrentWindow() != callWindow) {


@@ 80,7 81,7 @@ namespace app
        gui::CallWindow *callWindow = dynamic_cast<gui::CallWindow *>(windows.find(window::name_call)->second);
        assert(callWindow != nullptr);

        AudioServiceAPI::RoutingStart(this);
        routingAudioHandle = AudioServiceAPI::RoutingStart(this);
        runCallTimer();

        LOG_INFO("---------------------------------CallActive");


@@ 98,7 99,8 @@ namespace app
            LOG_INFO("ignoring call incoming");
        }
        else {
            AudioServiceAPI::PlaybackStart(this, audio::PlaybackType::CallRingtone, ringtone_path);
            callringAudioHandle =
                AudioServiceAPI::PlaybackStart(this, audio::PlaybackType::CallRingtone, ringtone_path);
            runCallTimer();
            std::unique_ptr<gui::SwitchData> data = std::make_unique<app::IncomingCallData>(msg->number);
            // send to itself message to switch (run) call application


@@ 121,7 123,7 @@ namespace app
        assert(callWindow != nullptr);

        LOG_INFO("---------------------------------Ringing");
        AudioServiceAPI::RoutingStart(this);
        routingAudioHandle = AudioServiceAPI::RoutingStart(this);
        runCallTimer();

        std::unique_ptr<gui::SwitchData> data = std::make_unique<app::ExecuteCallData>(msg->number);

M module-apps/application-call/ApplicationCall.hpp => module-apps/application-call/ApplicationCall.hpp +2 -0
@@ 31,6 31,8 @@ namespace app
        void RingingHandler(const CellularCallMessage *const msg);

      protected:
        audio::Handle routingAudioHandle;
        audio::Handle callringAudioHandle;
        AppTimer timerCall;
        utils::time::Timestamp callStartTime = 0;
        utils::time::Duration callDuration;

M module-apps/application-music-player/ApplicationMusicPlayer.cpp => module-apps/application-music-player/ApplicationMusicPlayer.cpp +3 -3
@@ 92,9 92,9 @@ namespace app

    bool ApplicationMusicPlayer::play(const std::string &fileName)
    {
        auto ret = AudioServiceAPI::PlaybackStart(this, audio::PlaybackType::Multimedia, fileName);
        if (ret != audio::RetCode::Success) {
            LOG_ERROR("play failed with %s", audio::c_str(ret));
        auto handle = AudioServiceAPI::PlaybackStart(this, audio::PlaybackType::Multimedia, fileName);
        if (handle.GetLastRetCode() != audio::RetCode::Success) {
            LOG_ERROR("play failed with %s", audio::c_str(handle.GetLastRetCode()));
            return false;
        }
        return true;

M module-audio/Audio/Audio.cpp => module-audio/Audio/Audio.cpp +6 -4
@@ 6,8 6,7 @@
namespace audio
{

    Audio::Audio(std::function<int32_t(AudioEvents event)> asyncCallback,
                 std::function<uint32_t(const std::string &path, const uint32_t &defaultValue)> dbCallback)
    Audio::Audio(AsyncCallback asyncCallback, DbCallback dbCallback)
        : currentOperation(), asyncCallback(asyncCallback), dbCallback(dbCallback)
    {



@@ 74,7 73,10 @@ namespace audio
        return currentOperation->SetInputGain(gainToSet);
    }

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

        auto ret = Operation::Create(op, fileName, playbackType, dbCallback);


@@ 107,7 109,7 @@ namespace audio
            return RetCode::OperationCreateFailed;
        }

        return currentOperation->Start(asyncCallback);
        return currentOperation->Start(asyncCallback, token);
    }

    audio::RetCode Audio::Stop()

M module-audio/Audio/Audio.hpp => module-audio/Audio/Audio.hpp +4 -4
@@ 22,8 22,7 @@ namespace audio
            Routing,
        };

        Audio(std::function<int32_t(AudioEvents event)> asyncCallback,
              std::function<uint32_t(const std::string &path, const uint32_t &defaultValue)> dbCallback);
        Audio(AsyncCallback asyncCallback, DbCallback dbCallback);

        // Events
        audio::RetCode SendEvent(const Operation::Event evt, const EventData *data = nullptr);


@@ 66,6 65,7 @@ namespace audio

        // Operations
        audio::RetCode Start(Operation::Type op,
                             audio::Token token                      = audio::Token::MakeBadToken(),
                             const char *fileName                    = "",
                             const audio::PlaybackType &playbackType = audio::PlaybackType::None);



@@ 82,8 82,8 @@ namespace audio
        State currentState = State::Idle;
        std::unique_ptr<Operation> currentOperation;

        std::function<int32_t(AudioEvents event)> asyncCallback = nullptr;
        std::function<uint32_t(const std::string &path, const uint32_t &defaultValue)> dbCallback = nullptr;
        AsyncCallback asyncCallback;
        DbCallback dbCallback;
    };

} // namespace audio

M module-audio/Audio/AudioCommon.hpp => module-audio/Audio/AudioCommon.hpp +120 -2
@@ 7,6 7,11 @@

namespace audio
{
    class AudioMux;
}

namespace audio
{
    using Position = float;
    using Volume   = uint32_t;
    using Gain     = uint32_t;


@@ 37,7 42,17 @@ namespace audio
        Notifications,
        KeypadSound,
        CallRingtone,
        TextMessageRingtone
        TextMessageRingtone,
        Last = TextMessageRingtone,
    };

    const static std::map<PlaybackType, uint8_t> PlaybackTypePriority = {
        {PlaybackType::CallRingtone, 2},
        {PlaybackType::TextMessageRingtone, 3},
        {PlaybackType::Notifications, 3},
        {PlaybackType::Multimedia, 4},
        {PlaybackType::KeypadSound, 5},
        {PlaybackType::None, static_cast<uint8_t>(PlaybackType::Last)},
    };

    [[nodiscard]] const std::string str(const PlaybackType &playbackType) noexcept;


@@ 68,13 83,116 @@ namespace audio
        Failed
    };

    enum class AudioEvents
    class Token
    {
        using TokenType = int16_t;

      public:
        explicit Token(TokenType initValue = tokenUninitialized) : t(initValue)
        {}

        bool operator==(const Token &other) const noexcept
        {
            return other.t == t;
        }

        bool operator!=(const Token &other) const noexcept
        {
            return !(other.t == t);
        }

        /**
         * Valid token is one connected with existing sequence of operations
         * @return True if valid, false otherwise
         */
        bool IsValid() const
        {
            return t > tokenUninitialized;
        }
        /**
         * Bad token cannot be used anymore
         * @return True if token is flagged bad
         */
        bool IsBad() const
        {
            return t == tokenBad;
        }
        /**
         * Uninitialized token can be used but it is not connected to any sequence of operations
         * @return True if token is flagged uninitialized
         */
        bool IsUninitialized() const
        {
            return t == tokenUninitialized;
        }
        /**
         * Helper - returns bad Token
         * @return Unusable bad Token
         */
        static inline Token MakeBadToken()
        {
            return Token(tokenBad);
        }

      private:
        static constexpr auto maxToken = std::numeric_limits<TokenType>::max();
        Token IncrementToken()
        {
            t = (t == maxToken) ? 0 : t + 1;
            return *this;
        }

        constexpr static TokenType tokenUninitialized = -1;
        constexpr static TokenType tokenBad           = -2;

        TokenType t;
        friend class ::audio::AudioMux;
    };

    class Handle
    {
      public:
        Handle(const RetCode &retCode = RetCode::Failed, const Token &token = Token())
            : lastRetCode(retCode), token(token)
        {}
        auto GetLastRetCode() -> RetCode
        {
            return lastRetCode;
        }
        auto GetToken() const -> const Token &
        {
            return token;
        }

      private:
        RetCode lastRetCode;
        Token token;
    };

    enum class PlaybackEventType
    {
        Empty,
        EndOfFile,
        FileSystemNoSpace
    };

    struct PlaybackEvent
    {
        PlaybackEventType event = PlaybackEventType::Empty;
        audio::Token token      = audio::Token::MakeBadToken();
    };

    typedef std::function<int32_t(PlaybackEvent e)> AsyncCallback;
    typedef std::function<uint32_t(const std::string &path, const uint32_t &defaultValue)> DbCallback;

    RetCode GetDeviceError(bsp::AudioDevice::RetCode retCode);
    const char *c_str(RetCode retcode);
    [[nodiscard]] auto GetVolumeText(const audio::Volume &volume) -> const std::string;
} // namespace audio

namespace audio::notifications
{
    const std::vector<audio::PlaybackType> typesToMute = {audio::PlaybackType::Notifications,
                                                          audio::PlaybackType::CallRingtone,
                                                          audio::PlaybackType::TextMessageRingtone};
} // namespace audio::notifications

A module-audio/Audio/AudioMux.cpp => module-audio/Audio/AudioMux.cpp +150 -0
@@ 0,0 1,150 @@

#include "AudioMux.hpp"
#include "Audio.hpp"

namespace audio
{
    AudioMux::AudioMux(audio::AsyncCallback asyncClbk, audio::DbCallback dbClbk, size_t audioInputsCount)
    {
        audioInputsCount = audioInputsCount > 0 ? audioInputsCount : 1;
        audioInputs.reserve(audioInputsCount);
        for (size_t i = 0; i < audioInputsCount; i++) {
            audioInputs.emplace_back(Input(Audio(asyncClbk, dbClbk), refToken.IncrementToken()));
        }
    }

    std::optional<AudioMux::Input *> AudioMux::GetRoutingInput(bool force)
    {
        if (auto input = GetInput({Audio::State::Routing})) {
            return input;
        }

        if (force) {
            auto *lowInput = &audioInputs.front();
            for (auto &audioInput : audioInputs) {
                auto lowestPrio  = GetPlaybackPriority(lowInput->audio.GetCurrentOperation()->GetPlaybackType());
                auto currentPrio = GetPlaybackPriority(audioInput.audio.GetCurrentOperation()->GetPlaybackType());

                if (currentPrio > lowestPrio) {
                    lowInput = &audioInput;
                }
            }
            LOG_DEBUG("Routing took over audio input.");
            return lowInput;
        }
        return std::nullopt;
    }

    std::optional<AudioMux::Input *> AudioMux::GetRecordingInput()
    {
        if (auto input = GetInput({Audio::State::Recording, Audio::State::Routing})) {
            return input;
        }
        return std::nullopt;
    }

    std::optional<AudioMux::Input *> AudioMux::GetPlaybackInput(const Token &token,
                                                                const audio::PlaybackType &playbackType)
    {
        // if routing or recording we cannot continue
        if (GetInput({Audio::State::Routing, Audio::State::Recording})) {
            return std::nullopt;
        }
        // try get with token
        if (auto input = GetInput(token)) {
            return input;
        }
        // try get with priority
        if (auto input = GetInput(playbackType)) {
            return input;
        }
        return std::nullopt;
    }

    std::optional<AudioMux::Input *> AudioMux::GetIdleInput()
    {
        return GetInput({Audio::State::Idle});
    }

    std::optional<AudioMux::Input *> AudioMux::GetActiveInput()
    {
        for (auto &audioInput : audioInputs) {
            if (!audioInput.audio.GetCurrentOperation()) {
                continue;
            }
            if (audioInput.audio.GetCurrentState() != Audio::State::Idle &&
                audioInput.audio.GetCurrentOperation()->GetState() == audio::Operation::State::Active) {
                return &audioInput;
            }
        }
        return std::nullopt;
    }

    std::optional<AudioMux::Input *> AudioMux::GetInput(const std::vector<Audio::State> &states)
    {
        for (auto &audioInput : audioInputs) {
            if (std::find(states.begin(), states.end(), audioInput.audio.GetCurrentState()) != std::end(states)) {
                return &audioInput;
            }
        }
        return std::nullopt;
    }

    std::optional<AudioMux::Input *> AudioMux::GetInput(const Token &token)
    {
        if (!token.IsValid()) {
            return std::nullopt;
        }

        for (auto &audioInput : audioInputs) {
            // if has token - match or reject
            if (token == audioInput.token) {
                return &audioInput;
            }
        }
        return std::nullopt;
    }

    std::optional<AudioMux::Input *> AudioMux::GetInput(const audio::PlaybackType &playbackType)
    {
        std::optional<AudioMux::Input *> idleInput;
        std::optional<AudioMux::Input *> overridableInput;

        for (auto &audioInput : audioInputs) {
            auto currentInputPrior = GetPlaybackPriority(audioInput.audio.GetCurrentOperation()->GetPlaybackType());

            // check busy input
            if (audioInput.audio.GetCurrentState() != Audio::State::Idle) {
                // handle priorities
                if (GetPlaybackPriority(playbackType) > currentInputPrior) {
                    return std::nullopt;
                }
                else if (GetPlaybackPriority(playbackType) <= currentInputPrior) {
                    overridableInput = &audioInput;
                }
            }
            else {
                idleInput = &audioInput;
            }
        }

        return idleInput ? idleInput : overridableInput;
    }

    Token AudioMux::IncrementToken(std::optional<AudioMux::Input *> input)
    {
        if (input) {
            return (*input)->token = refToken.IncrementToken();
        }
        return Token::MakeBadToken();
    }

    uint8_t AudioMux::GetPlaybackPriority(const audio::PlaybackType &type)
    {
        const auto &pmap = audio::PlaybackTypePriority;
        if (pmap.find(type) != pmap.end()) {
            return pmap.at(type);
        }
        return static_cast<uint8_t>(PlaybackType::Last);
    }
} // namespace audio

A module-audio/Audio/AudioMux.hpp => module-audio/Audio/AudioMux.hpp +90 -0
@@ 0,0 1,90 @@
#pragma once

#include "AudioCommon.hpp"
#include "Audio.hpp"

namespace audio
{
    /**
     * Container for audio::Audio instances, handles the logic for choosing right input, but does not perform
     * operations on those inputs
     */
    class AudioMux
    {
      public:
        struct Input
        {
            Input(audio::Audio &&a, audio::Token handle) : audio(std::move(a)), token(handle)
            {}
            audio::Audio audio;
            audio::Token token;
        };
        /**
         * Constructs class with fixed number of managed inputs
         * @param asyncClbk Callback for async control events from of managed audio::Audio() instances
         * @param dbClbk Callback for async DB change events from of managed audio::Audio() instances
         * @param audioInputsCount Number of inputs managed and internal audio::Audio() classes created
         */
        AudioMux(audio::AsyncCallback asyncClbk, audio::DbCallback dbClbk, size_t audioInputsCount = 1);
        /**
         * Gets input related to given token
         * @param token Token to compare
         * @return nullopt if input not found
         */
        auto GetInput(const Token &token) -> std::optional<Input *>;
        /**
         * Gets first input which is in given state
         * @param states State to compare
         * @return nullopt if input not found
         */
        auto GetInput(const std::vector<Audio::State> &states) -> std::optional<Input *>;
        /**
         * Gets available input respecting priority
         * @param playbackType Playback type to compare to compare
         * @return Idle input if found, otherwise one of inputs that can be overridden.
         * nullopt if none of the inputs is not available (higher priority operation is active)
         */
        auto GetInput(const audio::PlaybackType &playbackType = audio::PlaybackType::None) -> std::optional<Input *>;
        /**
         * Gets first Idle input
         * @return nullopt if input not found
         */
        auto GetIdleInput() -> std::optional<Input *>;
        /**
         * Gets first Active input
         * @return nullopt if input not found
         */
        auto GetActiveInput() -> std::optional<Input *>;
        /**
         * Gets input for routing
         * @param force If set upon failure returns one of busy inputs
         * @return nullopt if input not found
         */
        auto GetRoutingInput(bool force = false) -> std::optional<Input *>;
        /**
         * Gets input for recording
         * @return nullopt if input not found
         */
        auto GetRecordingInput() -> std::optional<Input *>;
        /**
         * Gets input for playback
         * @param token Token to compare
         * @param playbackType Playback type to compare
         * @return nullopt if input not found
         */
        auto GetPlaybackInput(const Token &token, const audio::PlaybackType &playbackType)
            -> std::optional<AudioMux::Input *>;

        auto GetAllInputs() -> std::vector<Input> &
        {
            return audioInputs;
        };
        auto IncrementToken(std::optional<AudioMux::Input *> input) -> Token;

      private:
        auto GetPlaybackPriority(const audio::PlaybackType &type) -> uint8_t;
        std::vector<Input> audioInputs;
        audio::Token refToken;
    };

} // namespace audio

M module-audio/Audio/Operation/IdleOperation.hpp => module-audio/Audio/Operation/IdleOperation.hpp +1 -1
@@ 26,7 26,7 @@ namespace audio

        ~IdleOperation() = default;

        audio::RetCode Start([[maybe_unused]] std::function<int32_t(AudioEvents event)> callback) override final
        audio::RetCode Start([[maybe_unused]] audio::AsyncCallback callback, audio::Token token) override final
        {
            return audio::RetCode::Success;
        }

M module-audio/Audio/Operation/Operation.hpp => module-audio/Audio/Operation/Operation.hpp +3 -2
@@ 80,7 80,7 @@ namespace audio
            const audio::PlaybackType &operations = audio::PlaybackType::None,
            std::function<uint32_t(const std::string &path, const uint32_t &defaultValue)> dbCallback = nullptr);

        virtual audio::RetCode Start(std::function<int32_t(AudioEvents event)> callback) = 0;
        virtual audio::RetCode Start(audio::AsyncCallback callback, audio::Token token) = 0;

        virtual audio::RetCode Stop() = 0;



@@ 125,7 125,8 @@ namespace audio
        Profile *currentProfile = nullptr;
        std::vector<std::unique_ptr<Profile>> availableProfiles;
        State state                                             = State::Idle;
        std::function<int32_t(AudioEvents event)> eventCallback = nullptr;
        audio::AsyncCallback eventCallback                      = nullptr;
        audio::Token operationToken;

        bool isInitialized = false;
        audio::PlaybackType playbackType = audio::PlaybackType::None;

M module-audio/Audio/Operation/PlaybackOperation.cpp => module-audio/Audio/Operation/PlaybackOperation.cpp +4 -4
@@ 36,7 36,7 @@ namespace audio
#endif
            if (ret == 0) {
                state = State::Idle;
                eventCallback(AudioEvents::EndOfFile); // TODO:M.P pass proper err code
                eventCallback({PlaybackEventType::EndOfFile, audio::Token::MakeBadToken()});
            }
            return ret;
        };


@@ 71,13 71,13 @@ namespace audio
        isInitialized = true;
    }

    audio::RetCode PlaybackOperation::Start(std::function<int32_t(AudioEvents event)> callback)
    audio::RetCode PlaybackOperation::Start(audio::AsyncCallback callback, audio::Token token)
    {

        if (state == State::Active || state == State::Paused) {
            return RetCode::InvokedInIncorrectState;
        }

        operationToken = token;
        auto tags = dec->fetchTags();

        eventCallback = callback;


@@ 194,7 194,7 @@ namespace audio

        case State::Active:
            state = State::Idle;
            Start(eventCallback);
            Start(eventCallback, operationToken);
            break;
        }


M module-audio/Audio/Operation/PlaybackOperation.hpp => module-audio/Audio/Operation/PlaybackOperation.hpp +1 -1
@@ 22,7 22,7 @@ namespace audio
            const audio::PlaybackType &playbackType,
            std::function<uint32_t(const std::string &path, const uint32_t &defaultValue)> dbCallback = nullptr);

        audio::RetCode Start(std::function<int32_t(AudioEvents event)> callback) override final;
        audio::RetCode Start(audio::AsyncCallback callback, audio::Token token) override final;

        audio::RetCode Stop() override final;


M module-audio/Audio/Operation/RecorderOperation.cpp => module-audio/Audio/Operation/RecorderOperation.cpp +4 -4
@@ 43,7 43,7 @@ namespace audio
#endif
            if (ret == 0) {
                state = State::Idle;
                eventCallback(AudioEvents::FileSystemNoSpace);
                eventCallback({PlaybackEventType::FileSystemNoSpace, audio::Token::MakeBadToken()});
            }
            return ret;
        };


@@ 89,13 89,13 @@ namespace audio
        isInitialized = true;
    }

    audio::RetCode RecorderOperation::Start(std::function<int32_t(AudioEvents event)> callback)
    audio::RetCode RecorderOperation::Start(audio::AsyncCallback callback, audio::Token token)
    {

        if (state == State::Paused || state == State::Active) {
            return RetCode::InvokedInIncorrectState;
        }

        operationToken = token;
        eventCallback = callback;
        state         = State::Active;



@@ 186,7 186,7 @@ namespace audio

        case State::Active:
            state = State::Idle;
            Start(eventCallback);
            Start(eventCallback, operationToken);
            break;
        }


M module-audio/Audio/Operation/RecorderOperation.hpp => module-audio/Audio/Operation/RecorderOperation.hpp +1 -1
@@ 23,7 23,7 @@ namespace audio
        RecorderOperation(const char *file,
                          std::function<uint32_t(const std::string &path, const uint32_t &defaultValue)> dbCallback);

        audio::RetCode Start(std::function<int32_t(AudioEvents event)> callback) override final;
        audio::RetCode Start(audio::AsyncCallback callback, audio::Token token) override final;

        audio::RetCode Stop() override final;


M module-audio/Audio/Operation/RouterOperation.cpp => module-audio/Audio/Operation/RouterOperation.cpp +3 -3
@@ 152,12 152,12 @@ namespace audio
        return GetDeviceError(ret);
    }

    audio::RetCode RouterOperation::Start(std::function<int32_t(audio::AudioEvents)> callback)
    audio::RetCode RouterOperation::Start(audio::AsyncCallback callback, audio::Token token)
    {
        if (state == State::Paused || state == State::Active) {
            return RetCode::InvokedInIncorrectState;
        }

        operationToken = token;
        eventCallback = callback;
        state         = State::Active;



@@ 282,7 282,7 @@ namespace audio

        case State::Active:
            state = State::Idle;
            Start(eventCallback);
            Start(eventCallback, operationToken);
            break;
        }


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

        ~RouterOperation();

        audio::RetCode Start([[maybe_unused]] std::function<int32_t(AudioEvents event)> callback) override final;
        audio::RetCode Start([[maybe_unused]] audio::AsyncCallback callback, audio::Token token) override final;

        audio::RetCode Stop() override final;


M module-audio/CMakeLists.txt => module-audio/CMakeLists.txt +1 -0
@@ 22,6 22,7 @@ set(SOURCES
        "${CMAKE_CURRENT_SOURCE_DIR}/Audio/encoder/EncoderWAV.cpp"

        "${CMAKE_CURRENT_SOURCE_DIR}/Audio/Audio.cpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/Audio/AudioMux.cpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/Audio/AudioCommon.cpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/Audio/Operation/Operation.cpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/Audio/Operation/PlaybackOperation.cpp"

M module-services/service-audio/ServiceAudio.cpp => module-services/service-audio/ServiceAudio.cpp +240 -103
@@ 16,30 16,12 @@ const char *ServiceAudio::serviceName = "ServiceAudio";

using namespace audio;


ServiceAudio::ServiceAudio()
    : sys::Service(serviceName, "", 4096 * 2, sys::ServicePriority::Idle),
      audio(
          [this](AudioEvents event) -> int32_t {
              switch (event) {
              case AudioEvents::EndOfFile: {
                  auto msg = std::make_shared<AudioNotificationMessage>(
                      static_cast<AudioNotificationMessage::Type>(AudioNotificationMessage::Type::EndOfFile));
                  sys::Bus::SendMulticast(msg, sys::BusChannels::ServiceAudioNotifications, this);
              } break;
              case AudioEvents::FileSystemNoSpace:
                  break;
              }
              return 0;
          },
          [this](const std::string &path, const uint32_t &defaultValue) -> uint32_t {
              this->addOrIgnoreEntry(path, defaultValue);
              return this->fetchAudioSettingFromDb(path, defaultValue);
          })
      audioMux([this](auto... params) { return this->AsyncCallback(params...); },
               [this](auto... params) { return this->DbCallback(params...); })
{

    busChannels.push_back(sys::BusChannels::ServiceAudioNotifications);

    LOG_INFO("[ServiceAudio] Initializing");
}



@@ 58,6 40,27 @@ sys::ReturnCodes ServiceAudio::DeinitHandler()
    return sys::ReturnCodes::Success;
}

int32_t ServiceAudio::AsyncCallback(PlaybackEvent e)
{
    switch (e.event) {
    case audio::PlaybackEventType::EndOfFile: {
        auto msg = std::make_shared<AudioNotificationMessage>(
            static_cast<AudioNotificationMessage::Type>(AudioNotificationMessage::Type::EndOfFile), e.token);
        sys::Bus::SendMulticast(msg, sys::BusChannels::ServiceAudioNotifications, this);
    } break;
    case audio::PlaybackEventType::FileSystemNoSpace:
    case audio::PlaybackEventType::Empty:
        break;
    }
    return 0;
};

uint32_t ServiceAudio::DbCallback(const std::string &path, const uint32_t &defaultValue)
{
    this->addOrIgnoreEntry(path, defaultValue);
    return this->fetchAudioSettingFromDb(path, defaultValue);
};

sys::ReturnCodes ServiceAudio::SwitchPowerModeHandler(const sys::ServicePowerMode mode)
{
    LOG_FATAL("[ServiceAudio] PowerModeHandler: %s", c_str(mode));


@@ 67,6 70,144 @@ sys::ReturnCodes ServiceAudio::SwitchPowerModeHandler(const sys::ServicePowerMod
void ServiceAudio::TickHandler(uint32_t id)
{}

bool ServiceAudio::IsResumable(const audio::PlaybackType &type)
{
    switch (type) {
    case audio::PlaybackType::Multimedia:
        return true;
    case audio::PlaybackType::None:
    case audio::PlaybackType::TextMessageRingtone:
    case audio::PlaybackType::Notifications:
    case audio::PlaybackType::KeypadSound:
    case audio::PlaybackType::CallRingtone:
        return false;
    }
    return false;
}

bool ServiceAudio::IsMergable(const audio::PlaybackType &type)
{
    switch (type) {
    case audio::PlaybackType::KeypadSound:
    case audio::PlaybackType::Notifications:
    case audio::PlaybackType::TextMessageRingtone:
        return true;
    case audio::PlaybackType::None:
    case audio::PlaybackType::Multimedia:
    case audio::PlaybackType::CallRingtone:
        return false;
    }
    return false;
}

std::unique_ptr<AudioResponseMessage> ServiceAudio::HandlePause(std::optional<AudioRequestMessage *> msg)
{

    audio::RetCode retCode = audio::RetCode::Failed;
    audio::Token retToken  = Token::MakeBadToken();

    auto pauseInput = [this](AudioMux::Input &audioInput) {
        if (IsResumable(audioInput.audio.GetCurrentOperation()->GetPlaybackType())) {
            audioInput.audio.Pause();
            return audioInput.token;
        }
        else {
            audioInput.audio.Stop();
            auto broadMsg = std::make_shared<AudioNotificationMessage>(
                static_cast<AudioNotificationMessage::Type>(AudioNotificationMessage::Type::Stop), audioInput.token);
            sys::Bus::SendMulticast(broadMsg, sys::BusChannels::ServiceAudioNotifications, this);
            audioMux.IncrementToken(&audioInput);
            return Token::MakeBadToken();
        }
    };

    if (msg) {
        std::optional<AudioMux::Input *> input = audioMux.GetInput((*msg)->token);
        if (!input) {
            retToken = pauseInput(**input);
        }
    }
    else {
        for (auto &audioInput : audioMux.GetAllInputs()) {
            if (audioInput.audio.GetCurrentOperation()->GetState() == Operation::State::Active) {
                pauseInput(audioInput);
            }
        }
        return std::make_unique<AudioResponseMessage>(audio::RetCode::Success, Tags(), retToken);
    }

    return std::make_unique<AudioResponseMessage>(retCode, Tags(), retToken);
}

template <typename... Args>
std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleStart(std::optional<AudioMux::Input *> input,
                                                                AudioRequestMessage *msg,
                                                                Operation::Type opType,
                                                                Args... args)
{
    audio::RetCode retCode = audio::RetCode::Failed;
    audio::Token retToken  = Token::MakeBadToken();

    if (input) {

        HandlePause();
        retToken = audioMux.IncrementToken(input);
        retCode  = (*input)->audio.Start(opType, retToken, args...);
    }
    if (retCode != audio::RetCode::Success) {
        retToken = Token::MakeBadToken();
    }
    return std::make_unique<AudioResponseMessage>(retCode, Tags(), retToken);
}

std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleStop(AudioStopMessage *msg)
{
    const auto playbackTypesToStop       = msg->stopVec;
    std::vector<audio::RetCode> retCodes = {audio::RetCode::Success};

    auto stopInput = [this](auto inp) {
        if (inp->audio.GetCurrentState() == Audio::State::Idle) {
            return audio::RetCode::Success;
        }
        auto rCode = inp->audio.Stop();
        // Send notification that audio file was stopped
        auto msgStop = std::make_shared<AudioNotificationMessage>(
            static_cast<AudioNotificationMessage::Type>(AudioNotificationMessage::Type::Stop), inp->token);
        sys::Bus::SendMulticast(msgStop, sys::BusChannels::ServiceAudioNotifications, this);
        audioMux.IncrementToken(inp);
        return rCode;
    };

    // stop by token
    if (auto tokenInput = audioMux.GetInput(msg->token)) {
        retCodes.emplace_back(stopInput(tokenInput.value()));
    }
    // stop with vector of playback types
    else if (!playbackTypesToStop.empty()) {
        for (auto &input : audioMux.GetAllInputs()) {
            const auto currentOperation = input.audio.GetCurrentOperation();
            if (currentOperation && (std::find(playbackTypesToStop.begin(),
                                               playbackTypesToStop.end(),
                                               currentOperation->GetPlaybackType()) != playbackTypesToStop.end())) {
                retCodes.emplace_back(stopInput(&input));
            }
        }
    }
    // stop all audio
    else if (!msg->token.IsUninitialized()) {
        for (auto &input : audioMux.GetAllInputs()) {
            retCodes.emplace_back(stopInput(&input));
        }
    }

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

sys::Message_t ServiceAudio::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp)
{
    std::shared_ptr<sys::ResponseMessage> responseMsg;


@@ 78,8 219,9 @@ sys::Message_t ServiceAudio::DataReceivedHandler(sys::DataMessage *msgl, sys::Re
        switch (msg->type) {

        case AudioNotificationMessage::Type::EndOfFile: {
            std::shared_ptr<AudioRequestMessage> msg = std::make_shared<AudioRequestMessage>(MessageType::AudioStop);
            sys::Bus::SendUnicast(msg, ServiceAudio::serviceName, this);
            std::shared_ptr<AudioRequestMessage> newMsg =
                std::make_shared<AudioRequestMessage>(MessageType::AudioStop, msg->token);
            sys::Bus::SendUnicast(newMsg, ServiceAudio::serviceName, this);
        } break;

        case AudioNotificationMessage::Type::Stop: {


@@ 99,74 241,79 @@ sys::Message_t ServiceAudio::DataReceivedHandler(sys::DataMessage *msgl, sys::Re
        responseMsg     = std::make_shared<AudioResponseMessage>(RetCode::Success);
    }
    else if (auto *msg = dynamic_cast<AudioStopMessage *>(msgl)) {
        const auto currentOperation = audio.GetCurrentOperation();
        const auto stopVec          = msg->stopVec;
        if (currentOperation &&
            (std::find(stopVec.begin(), stopVec.end(), currentOperation->GetPlaybackType()) == stopVec.end())) {
            responseMsg = std::make_shared<AudioResponseMessage>(RetCode::Success);
        }
        else {
            responseMsg = std::make_shared<AudioResponseMessage>(audio.Stop());

            // Send notification that audio file was stopped
            auto retMsg = std::make_shared<AudioNotificationMessage>(
                static_cast<AudioNotificationMessage::Type>(AudioNotificationMessage::Type::Stop));
            sys::Bus::SendMulticast(retMsg, sys::BusChannels::ServiceAudioNotifications, this);
        }
        responseMsg = HandleStop(msg);
    }
    else if (auto *msg = dynamic_cast<AudioRequestMessage *>(msgl)) {
        switch (msg->type) {
        case MessageType::AudioPlaybackStart: {
            responseMsg = std::make_shared<AudioResponseMessage>(
                audio.Start(Operation::Type::Playback, msg->fileName.c_str(), msg->playbackType));
            if (auto input = audioMux.GetPlaybackInput(msg->token, msg->playbackType)) {
                responseMsg =
                    HandleStart(input, msg, Operation::Type::Playback, msg->fileName.c_str(), msg->playbackType);
            }
        } break;

        case MessageType::AudioRecorderStart: {
            responseMsg =
                std::make_shared<AudioResponseMessage>(audio.Start(Operation::Type::Recorder, msg->fileName.c_str()));
            if (auto input = audioMux.GetRecordingInput()) {
                responseMsg = std::make_shared<AudioResponseMessage>(
                    (*input)->audio.Start(Operation::Type::Recorder, (*input)->token, msg->fileName.c_str()));
            }
        } break;

        case MessageType::AudioRoutingStart: {
            LOG_DEBUG("AudioRoutingStart");
            responseMsg = std::make_shared<AudioResponseMessage>(audio.Start(Operation::Type::Router));
            if (auto input = audioMux.GetRoutingInput(true)) {
                responseMsg = HandleStart(input, msg, Operation::Type::Router);
            }
        } break;

        case MessageType::AudioPause: {
            responseMsg = std::make_shared<AudioResponseMessage>(audio.Pause());
            responseMsg = HandlePause(msg);
        } break;

        case MessageType::AudioResume: {
            responseMsg = std::make_shared<AudioResponseMessage>(audio.Resume());
            if (auto input = audioMux.GetInput(msg->token)) {
                responseMsg = std::make_shared<AudioResponseMessage>((*input)->audio.Resume());
            }
        } break;

        case MessageType::AudioGetFileTags: {
            auto tag = audio.GetFileTags(msg->fileName.c_str());
            if (tag) {
                responseMsg = std::make_shared<AudioResponseMessage>(RetCode::Success, tag.value());
            }
            else {
                responseMsg = std::make_shared<AudioResponseMessage>(RetCode::FileDoesntExist);
            if (auto input = audioMux.GetInput()) {
                auto tag = (*input)->audio.GetFileTags(msg->fileName.c_str());
                if (tag) {
                    responseMsg = std::make_shared<AudioResponseMessage>(RetCode::Success, tag.value());
                }
                else {
                    responseMsg = std::make_shared<AudioResponseMessage>(RetCode::FileDoesntExist);
                }
            }
        } break;

        case MessageType::AudioRoutingRecordCtrl: {
            responseMsg = std::make_shared<AudioResponseMessage>(audio.SendEvent(
                msg->enable ? Operation::Event::StartCallRecording : Operation::Event::StopCallRecording));
            if (auto input = audioMux.GetRecordingInput()) {
                responseMsg = std::make_shared<AudioResponseMessage>((*input)->audio.SendEvent(
                    msg->enable ? Operation::Event::StartCallRecording : Operation::Event::StopCallRecording));
            }
        } break;

        case MessageType::AudioRoutingMute: {
            responseMsg = std::make_shared<AudioResponseMessage>(
                audio.SendEvent(msg->enable ? Operation::Event::CallMute : Operation::Event::CallUnmute));
            if (auto input = audioMux.GetRecordingInput()) {
                responseMsg = std::make_shared<AudioResponseMessage>(
                    (*input)->audio.SendEvent(msg->enable ? Operation::Event::CallMute : Operation::Event::CallUnmute));
            }
        } break;

        case MessageType::AudioRoutingSpeakerhone: {
            responseMsg = std::make_shared<AudioResponseMessage>(audio.SendEvent(
                msg->enable ? Operation::Event::CallSpeakerphoneOn : Operation::Event::CallSpeakerphoneOff));
            if (auto input = audioMux.GetRecordingInput()) {
                responseMsg = std::make_shared<AudioResponseMessage>((*input)->audio.SendEvent(
                    msg->enable ? Operation::Event::CallSpeakerphoneOn : Operation::Event::CallSpeakerphoneOff));
            }
        } break;

        case MessageType::AudioRoutingHeadset: {
            responseMsg = std::make_shared<AudioResponseMessage>(
                audio.SendEvent(msg->enable ? Operation::Event::HeadphonesPlugin : Operation::Event::HeadphonesUnplug));
            if (auto input = audioMux.GetRecordingInput()) {
                responseMsg = std::make_shared<AudioResponseMessage>((*input)->audio.SendEvent(
                    msg->enable ? Operation::Event::HeadphonesPlugin : Operation::Event::HeadphonesUnplug));
            }
        } break;

        default:


@@ 179,7 326,12 @@ sys::Message_t ServiceAudio::DataReceivedHandler(sys::DataMessage *msgl, sys::Re
        LOG_DEBUG("Unhandled message");
    }

    return responseMsg;
    if (responseMsg) {
        return responseMsg;
    }
    else {
        return std::make_shared<AudioResponseMessage>(RetCode::Failed, Tags{}, Token::MakeBadToken());
    }
}

void ServiceAudio::updateDbValue(const std::string &path, const audio::Setting &setting, const uint32_t &value)


@@ 235,20 387,19 @@ uint32_t ServiceAudio::getSetting(const audio::Setting &setting,

std::optional<uint32_t> ServiceAudio::getCurrentSetting(const audio::Setting &setting)
{
    const auto currentOperation   = audio.GetCurrentOperation();
    const auto noOngoingOperation = [&currentOperation]() -> bool {
        return currentOperation == nullptr || currentOperation->GetState() == audio::Operation::State::Idle;
    };
    const auto activeInput = audioMux.GetActiveInput();

    if (noOngoingOperation()) {
        if (setting == audio::Setting::Volume) {
            const auto path =
                audio::str(audio::PlaybackType::CallRingtone, audio::Setting::Volume, audio.GetHeadphonesInserted());
    if (!activeInput.has_value()) {
        const auto idleInput = audioMux.GetIdleInput();
        if (idleInput.has_value() && setting == audio::Setting::Volume) {
            const auto path = audio::str(
                audio::PlaybackType::CallRingtone, audio::Setting::Volume, (*idleInput)->audio.GetHeadphonesInserted());
            return fetchAudioSettingFromDb<audio::Volume>(path, 0);
        }
        return {};
    }

    const auto currentOperation = (*activeInput)->audio.GetCurrentOperation();
    const auto path =
        audio::str(currentOperation->GetProfile()->GetType(), setting, currentOperation->GetPlaybackType());
    return (setting == audio::Setting::Volume) ? fetchAudioSettingFromDb<audio::Volume>(path, 0)


@@ 257,46 408,32 @@ std::optional<uint32_t> ServiceAudio::getCurrentSetting(const audio::Setting &se

void ServiceAudio::setCurrentSetting(const audio::Setting &setting, const uint32_t &value)
{
    const auto currentOperation = audio.GetCurrentOperation();
    const auto valueToSet       = [&value, &setting]() -> std::optional<uint32_t> {
        switch (setting) {
        case audio::Setting::Volume: {
            return std::clamp(value, minVolume, maxVolume);
        }
        case audio::Setting::Gain: {
            return std::clamp(value, minGain, maxGain);
        }
        }
        return {};
    }();
    if (!valueToSet.has_value()) {
        return;
    }
    auto idleOperation = dynamic_cast<const IdleOperation *>(currentOperation);

    const auto noOngoingOperation = [&currentOperation, &idleOperation]() -> bool {
        return currentOperation == nullptr || idleOperation != nullptr ||
               currentOperation->GetState() == audio::Operation::State::Idle;
    };
    const auto activeInput = audioMux.GetActiveInput();

    if (noOngoingOperation()) {
        if (setting == audio::Setting::Volume) {
            const auto path =
                audio::str(audio::PlaybackType::CallRingtone, audio::Setting::Volume, audio.GetHeadphonesInserted());
    if (!activeInput.has_value()) {
        const auto idleInput = audioMux.GetIdleInput();
        if (idleInput.has_value() && setting == audio::Setting::Volume) {
            const auto path = audio::str(
                audio::PlaybackType::CallRingtone, audio::Setting::Volume, (*idleInput)->audio.GetHeadphonesInserted());
            addOrIgnoreEntry(path, audio::playbackDefaults::defaultLoudspeakerVolume);
            updateDbValue(path, Setting::Volume, valueToSet.value());
            const auto valueToSet = std::clamp(value, minVolume, maxVolume);
            updateDbValue(path, Setting::Volume, valueToSet);
        }
        return;
    }
    else {
        switch (setting) {
        case audio::Setting::Volume: {
            audio.SetOutputVolume(valueToSet.value());
            updateDbValue(currentOperation, audio::Setting::Volume, valueToSet.value());
        } break;
        case audio::Setting::Gain: {
            audio.SetInputGain(valueToSet.value());
            updateDbValue(currentOperation, audio::Setting::Gain, valueToSet.value());
        } break;
        }

    auto &audio                 = (*activeInput)->audio;
    const auto currentOperation = audio.GetCurrentOperation();
    switch (setting) {
    case audio::Setting::Volume: {
        const auto valueToSet = std::clamp(value, minVolume, maxVolume);
        audio.SetOutputVolume(valueToSet);
        updateDbValue(currentOperation, audio::Setting::Volume, valueToSet);
    } break;
    case audio::Setting::Gain: {
        const auto valueToSet = std::clamp(value, minGain, maxGain);
        audio.SetInputGain(valueToSet);
        updateDbValue(currentOperation, audio::Setting::Gain, valueToSet);
    } break;
    }
}

M module-services/service-audio/ServiceAudio.hpp => module-services/service-audio/ServiceAudio.hpp +16 -2
@@ 13,7 13,9 @@
#include "Service/Service.hpp"
#include <functional>
#include "Audio/Audio.hpp"
#include "Audio/AudioMux.hpp"
#include "MessageType.hpp"
#include "messages/AudioMessage.hpp"

#include <service-db/api/DBServiceAPI.hpp>
#include <queries/settings/QuerySettingsGet_v2.hpp>


@@ 45,8 47,20 @@ class ServiceAudio : public sys::Service
    static const char *serviceName;

  private:
    audio::Audio audio;
    std::function<uint32_t(audio::AudioEvents event)> audioCallback = nullptr;
    audio::AudioMux audioMux;
    auto AsyncCallback(audio::PlaybackEvent e) -> int32_t;
    auto DbCallback(const std::string &path, const uint32_t &defaultValue) -> uint32_t;

    template <typename... Args>
    std::unique_ptr<AudioResponseMessage> HandleStart(std::optional<audio::AudioMux::Input *> input,
                                                      AudioRequestMessage *msg,
                                                      audio::Operation::Type opType,
                                                      Args... args);
    std::unique_ptr<AudioResponseMessage> HandlePause(std::optional<AudioRequestMessage *> msg = std::nullopt);
    std::unique_ptr<AudioResponseMessage> HandleStop(AudioStopMessage *msg);

    auto IsResumable(const audio::PlaybackType &type) -> bool;
    auto IsMergable(const audio::PlaybackType &type) -> bool;

    template <typename T> void addOrIgnoreEntry(const std::string &profilePath, const T &defaultValue)
    {

M module-services/service-audio/api/AudioServiceAPI.cpp => module-services/service-audio/api/AudioServiceAPI.cpp +22 -15
@@ 34,28 34,29 @@ namespace AudioServiceAPI
        }
    } // namespace

    RetCode PlaybackStart(sys::Service *serv, const audio::PlaybackType &playbackType, const std::string &fileName)
    Handle PlaybackStart(sys::Service *serv, const audio::PlaybackType &playbackType, const std::string &fileName)
    {
        auto msg          = std::make_shared<AudioRequestMessage>(MessageType::AudioPlaybackStart);
        msg->fileName = fileName;
        msg->playbackType = playbackType;

        return SendAudioRequest(serv, msg)->retCode;
        auto ret          = SendAudioRequest(serv, msg);
        return Handle(ret->retCode, ret->token);
    }

    RetCode RecordingStart(sys::Service *serv, const std::string &fileName)
    Handle RecordingStart(sys::Service *serv, const std::string &fileName)
    {
        auto msg      = std::make_shared<AudioRequestMessage>(MessageType::AudioRecorderStart);
        msg->fileName = fileName;

        return SendAudioRequest(serv, msg)->retCode;
        auto ret      = SendAudioRequest(serv, msg);
        return Handle(ret->retCode, ret->token);
    }

    audio::RetCode RoutingStart(sys::Service *serv)
    Handle RoutingStart(sys::Service *serv)
    {
        auto msg = std::make_shared<AudioRequestMessage>(MessageType::AudioRoutingStart);

        return SendAudioRequest(serv, msg)->retCode;
        std::shared_ptr<AudioRequestMessage> msg =
            std::make_shared<AudioRequestMessage>(MessageType::AudioRoutingStart);
        auto ret = SendAudioRequest(serv, msg);
        return Handle(ret->retCode, ret->token);
    }

    audio::RetCode RoutingRecordCtrl(sys::Service *serv, bool enable)


@@ 97,17 98,23 @@ namespace AudioServiceAPI
        return SendAudioRequest(serv, msg)->retCode;
    }

    RetCode Pause(sys::Service *serv)
    RetCode Stop(sys::Service *serv, const audio::Handle &handle)
    {
        auto msg = std::make_shared<AudioRequestMessage>(MessageType::AudioPause);

        auto msg = std::make_shared<AudioStopMessage>(handle.GetToken());
        return SendAudioRequest(serv, msg)->retCode;
    }

    RetCode Resume(sys::Service *serv)
    RetCode Pause(sys::Service *serv, const audio::Handle &handle)
    {
        auto msg = std::make_shared<AudioRequestMessage>(MessageType::AudioResume);
        std::shared_ptr<AudioRequestMessage> msg =
            std::make_shared<AudioRequestMessage>(MessageType::AudioPause, handle.GetToken());
        return SendAudioRequest(serv, msg)->retCode;
    }

    RetCode Resume(sys::Service *serv, const audio::Handle &handle)
    {
        std::shared_ptr<AudioRequestMessage> msg =
            std::make_shared<AudioRequestMessage>(MessageType::AudioResume, handle.GetToken());
        return SendAudioRequest(serv, msg)->retCode;
    }


M module-services/service-audio/api/AudioServiceAPI.hpp => module-services/service-audio/api/AudioServiceAPI.hpp +34 -21
@@ 11,34 11,47 @@ namespace AudioServiceAPI
{
    /*! @brief Starts playback operation.
     *
     * @param serv - requesting service.
     * @param playbackType - type of playback.
     * If none, request would still be valid and default volume would be used.
     * @param fileName - name of the file.
     * @return           Standard service-api return code. Success if suitable.
     * @param serv Requesting service.
     * @param playbackType Type of playback.
     * @param fileName Name of the file.
     * @return audio::Handle Handle to operation to be used in subsequent operation.
     */
    audio::RetCode PlaybackStart(sys::Service *serv,
                                 const audio::PlaybackType &playbackType,
                                 const std::string &fileName);
    audio::RetCode RecordingStart(sys::Service *serv, const std::string &fileName);
    audio::RetCode RoutingStart(sys::Service *serv);
    audio::Handle PlaybackStart(sys::Service *serv,
                                const audio::PlaybackType &playbackType,
                                const std::string &fileName);
    audio::Handle RecordingStart(sys::Service *serv, const std::string &fileName);
    audio::Handle RoutingStart(sys::Service *serv);
    audio::RetCode RoutingRecordCtrl(sys::Service *serv, bool enable);
    audio::RetCode RoutingMute(sys::Service *serv, bool enable);
    audio::RetCode RoutingSpeakerPhone(sys::Service *serv, bool enable);
    audio::RetCode RoutingHeadset(sys::Service *serv, bool enable);
    /// Stops current audio operation.
    ///
    /// Stops current audio operation when it's valid and not idle.
    /// @param serv requesting service
    /// @param stopVec vector that contains playback types to be stopped.
    /// When no vector is passed it stops current operation.
    /// When stop vector is passed it stops current operation only if it's type is contained in the vector.
    /// @return Standard service-api return code. Success if suitable.
    audio::RetCode Stop(sys::Service *serv, const std::vector<audio::PlaybackType> &stopVec = {});
    audio::RetCode Pause(sys::Service *serv);
    audio::RetCode Resume(sys::Service *serv);
    /*!
     * @brief Stops playback operation.
     *
     * @param serv Requesting service
     * @param handle Handle to controlled operation
     * @return audio::RetCode standard service-api return code
     */
    audio::RetCode Stop(sys::Service *serv, const audio::Handle &handle);
    /*!
     * @brief Pauses playback operation. Can be resumed by Resume()
     *
     * @param serv Requesting service
     * @param handle Handle to controlled operation
     * @return audio::RetCode standard service-api return code
     */
    audio::RetCode Pause(sys::Service *serv, const audio::Handle &handle);
    /*!
     * @brief Resumes paused operation.
     *
     * @param serv Requesting service
     * @param handle Handle to controlled operation
     * @return audio::RetCode standard service-api return code
     */
    audio::RetCode Resume(sys::Service *serv, const audio::Handle &handle);

    std::optional<audio::Tags> GetFileTags(sys::Service *serv, const std::string &fileName);
    // audio::RetCode AdjustVolume(sys::Service *serv, const int &step = 0);
    /*! @brief Gets settings. Current profile is taken by default.
     *
     * @param serv - requesting service.

M module-services/service-audio/messages/AudioMessage.hpp => module-services/service-audio/messages/AudioMessage.hpp +24 -9
@@ 20,15 20,19 @@
class AudioMessage : public sys::DataMessage
{
  public:
    AudioMessage(MessageType messageType) : sys::DataMessage(messageType), type(messageType)
    AudioMessage() : sys::DataMessage(MessageType::MessageTypeUninitialized)
    {}

    AudioMessage() : sys::DataMessage(MessageType::MessageTypeUninitialized)
    AudioMessage(MessageType messageType,
                 audio::PlaybackType playbackType = audio::PlaybackType::None,
                 audio::Token token               = audio::Token())
        : sys::DataMessage(messageType), type(messageType), playbackType(playbackType), token(token)
    {}

    virtual ~AudioMessage() = default;

    MessageType type = MessageType::MessageTypeUninitialized;
    audio::PlaybackType playbackType = audio::PlaybackType::None;
    audio::Token token;
};

class AudioNotificationMessage : public AudioMessage


@@ 41,7 45,8 @@ class AudioNotificationMessage : public AudioMessage
        Stop
    };

    AudioNotificationMessage(Type type) : AudioMessage(MessageType::AudioNotification), type(type)
    AudioNotificationMessage(Type type, audio::Token token)
        : AudioMessage(MessageType::AudioNotification, audio::PlaybackType::None, token), type(type)
    {}

    ~AudioNotificationMessage()


@@ 96,24 101,29 @@ class AudioSetSetting : public AudioSettingsMessage
class AudioRequestMessage : public AudioMessage
{
  public:
    AudioRequestMessage(MessageType messageType) : AudioMessage(messageType)
    AudioRequestMessage(MessageType messageType, audio::Token token = audio::Token())
        : AudioMessage(messageType, audio::PlaybackType::None, token)
    {}

    ~AudioRequestMessage()
    {}

    std::string fileName;
    float val;
    bool enable;
    audio::PlaybackType playbackType = audio::PlaybackType::None;
};

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

    AudioStopMessage(const audio::Token &token) : AudioMessage(), token(token)
    {}

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

class AudioResponseMessage : public sys::ResponseMessage


@@ 121,17 131,22 @@ class AudioResponseMessage : public sys::ResponseMessage
  public:
    AudioResponseMessage(audio::RetCode retCode  = audio::RetCode::Success,
                         const audio::Tags &tags = {},
                         audio::Token token      = audio::Token(),
                         const float val         = 0.0)
        : sys::ResponseMessage(), tags(tags), val(val)
        : sys::ResponseMessage(), tags(tags), val(val), token(token)
    {}
    AudioResponseMessage(audio::RetCode retCode, const float val) : AudioResponseMessage(retCode, {}, val)

    AudioResponseMessage(audio::RetCode retCode, const float val)
        : AudioResponseMessage(retCode, {}, audio::Token(), val)
    {}

    virtual ~AudioResponseMessage()
    {}

    audio::RetCode retCode = audio::RetCode::Success;
    audio::Tags tags       = {};
    float val              = 0.0;
    audio::Token token;
};

#endif // PUREPHONE_AUDIOMESSAGE_HPP