~aleteoryx/muditaos

9c7e4139db8a1ac7b0490d1b2c85862de381dded — Hubert Chrzaniuk 5 years ago 0014dae
[EGD-3784] Add service audio non blocking API (#789)

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

* `[system]` Timer API - linked to timer, same for Services and Applications. Updated docs
* `[system]` Removed `using std` and `using cpp_freertos` from commonly used headers
* `[audio]` Made most audio api calls asynchronous
* `[messages]` Refactored messages SMS thread window to use ListView. 

### Fixed

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

        LOG_INFO("---------------------------------CallAborted");
        AudioServiceAPI::Stop(this, routingAudioHandle);
        AudioServiceAPI::Stop(this, callringAudioHandle);
        AudioServiceAPI::StopAll(this);

        callWindow->setState(gui::CallWindow::State::CALL_ENDED);
        if (getState() == State::ACTIVE_FORGROUND && getCurrentWindow() != callWindow) {
            switchWindow(window::name_call);


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

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

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


@@ 95,8 95,7 @@ namespace app
            LOG_INFO("ignoring call incoming");
        }
        else {
            callringAudioHandle =
                AudioServiceAPI::PlaybackStart(this, audio::PlaybackType::CallRingtone, ringtone_path);
            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


@@ 119,7 118,7 @@ namespace app
        assert(callWindow != nullptr);

        LOG_INFO("---------------------------------Ringing");
        routingAudioHandle = AudioServiceAPI::RoutingStart(this);
        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 +0 -2
@@ 32,8 32,6 @@ namespace app
        void RingingHandler(const CellularCallMessage *const msg);

      protected:
        audio::Handle routingAudioHandle;
        audio::Handle callringAudioHandle;
        std::unique_ptr<sys::Timer> 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 +1 -5
@@ 92,11 92,7 @@ namespace app

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


M module-audio/Audio/Audio.hpp => module-audio/Audio/Audio.hpp +7 -12
@@ 55,25 55,20 @@ namespace audio
            return currentOperation->GetInputGain();
        }

        const Operation *GetCurrentOperation() const
        const Operation &GetCurrentOperation() const
        {
            return currentOperation.get();
            // currentOperation always exists - null pattern design
            return *(currentOperation.get());
        }

        virtual std::optional<audio::PlaybackType> GetCurrentOperationPlaybackType() const
        virtual audio::PlaybackType GetCurrentOperationPlaybackType() const
        {
            if (currentOperation.get()) {
                return currentOperation.get()->GetPlaybackType();
            }
            return std::nullopt;
            return GetCurrentOperation().GetPlaybackType();
        }

        virtual std::optional<Operation::State> GetCurrentOperationState() const
        virtual Operation::State GetCurrentOperationState() const
        {
            if (currentOperation.get()) {
                return currentOperation.get()->GetState();
            }
            return std::nullopt;
            return GetCurrentOperation().GetState();
        }

        [[nodiscard]] inline bool GetHeadphonesInserted() const

M module-audio/Audio/AudioCommon.hpp => module-audio/Audio/AudioCommon.hpp +1 -0
@@ 80,6 80,7 @@ namespace audio
        OperationNotSet,
        ProfileNotSet,
        DeviceFailure,
        TokenNotFound,
        Failed
    };


M module-audio/Audio/AudioMux.cpp => module-audio/Audio/AudioMux.cpp +4 -16
@@ 45,21 45,12 @@ namespace audio
        return std::nullopt;
    }

    std::optional<AudioMux::Input *> AudioMux::GetPlaybackInput(const Token &token,
                                                                const audio::PlaybackType &playbackType)
    std::optional<AudioMux::Input *> AudioMux::GetPlaybackInput(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;
        }
        if (token.IsValid()) {
            // reject since operation does not exist
            return std::nullopt;
        }
        // try get with priority
        if (auto input = GetAvailableInput(playbackType)) {
            return input;


@@ 75,10 66,6 @@ namespace audio
    std::optional<AudioMux::Input *> AudioMux::GetActiveInput()
    {
        for (auto &audioInput : audioInputs) {

            if (!audioInput.audio->GetCurrentOperation()) {
                continue;
            }
            if (audioInput.audio->GetCurrentState() != Audio::State::Idle &&
                audioInput.audio->GetCurrentOperationState() == audio::Operation::State::Active) {
                return &audioInput;


@@ 118,7 105,7 @@ namespace audio
        std::optional<AudioMux::Input *> overridableInput;

        for (auto &audioInput : audioInputs) {
            auto currentPlaybackType = audioInput.audio->GetCurrentOperationPlaybackType().value_or(PlaybackType::None);
            auto currentPlaybackType = audioInput.audio->GetCurrentOperationPlaybackType();
            auto currentInputPrior   = GetPlaybackPriority(currentPlaybackType);

            // check busy input


@@ 144,9 131,10 @@ namespace audio
        return idleInput ? idleInput : overridableInput;
    }

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

M module-audio/Audio/AudioMux.hpp => module-audio/Audio/AudioMux.hpp +22 -4
@@ 12,12 12,32 @@ namespace audio
    class AudioMux
    {
      public:
        enum class VibrationStatus
        {
            On,
            Off
        };

        struct Input
        {
            Input(std::unique_ptr<audio::Audio> a, audio::Token handle) : audio(std::move(a)), token(handle)
            {}
            std::unique_ptr<audio::Audio> audio;
            audio::Token token;
            VibrationStatus vibrationOn = VibrationStatus::Off;

            void EnableVibration()
            {
                vibrationOn = VibrationStatus::On;
            }
            void DisableVibration()
            {
                vibrationOn = VibrationStatus::Off;
            }
            auto GetVibrationStatus() const -> VibrationStatus
            {
                return vibrationOn;
            };
        };
        /**
         * Constructs class with fixed number of managed inputs


@@ 75,18 95,16 @@ namespace audio
        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 GetPlaybackInput(const audio::PlaybackType &playbackType) -> std::optional<AudioMux::Input *>;

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

      private:
        auto GetPlaybackPriority(const std::optional<audio::PlaybackType> type) -> uint8_t;

M module-audio/Audio/test/unittest_audio.cpp => module-audio/Audio/test/unittest_audio.cpp +8 -15
@@ 81,12 81,12 @@ class MockAudio : public audio::Audio
          state(state), plbckType(plbckType), opState(opState)
    {}

    std::optional<audio::PlaybackType> GetCurrentOperationPlaybackType() const override
    audio::PlaybackType GetCurrentOperationPlaybackType() const override
    {
        return plbckType;
    }

    std::optional<audio::Operation::State> GetCurrentOperationState() const override
    audio::Operation::State GetCurrentOperationState() const override
    {
        return opState;
    }


@@ 97,8 97,8 @@ class MockAudio : public audio::Audio
    }

    State state = State::Idle;
    std::optional<audio::PlaybackType> plbckType;
    std::optional<audio::Operation::State> opState;
    audio::PlaybackType plbckType;
    audio::Operation::State opState;
};

TEST_CASE("Test AudioMux")


@@ 344,33 344,26 @@ TEST_CASE("Test AudioMux")

        GIVEN("One Input")
        {
            WHEN("When token matches")
            WHEN("When free inputs available")
            {
                tkId = insertAudio(
                    audioInputs, Audio::State::Playback, PlaybackType::Multimedia, Operation::State::Active, tokenIdx);
                auto retInput = aMux.GetPlaybackInput(Token(tkId), testPlaybackTypeLowPrio);
                auto retInput = aMux.GetPlaybackInput(testPlaybackTypeLowPrio);
                REQUIRE(retInput != std::nullopt);
                REQUIRE((*retInput)->token == Token(tkId));
            }
            WHEN("When token not found")
            {
                tkId =
                    insertAudio(audioInputs, Audio::State::Idle, PlaybackType::None, Operation::State::Idle, tokenIdx);
                auto retInput = aMux.GetPlaybackInput(Token(tkId + 1), testPlaybackTypeLowPrio);
                REQUIRE(retInput == std::nullopt);
            }
            WHEN("Should reject due to Recording active")
            {
                tkId = insertAudio(
                    audioInputs, Audio::State::Recording, PlaybackType::None, Operation::State::Idle, tokenIdx);
                auto retInput = aMux.GetPlaybackInput(Token(), testPlaybackTypeHighPrio);
                auto retInput = aMux.GetPlaybackInput(testPlaybackTypeHighPrio);
                REQUIRE(retInput == std::nullopt);
            }
            WHEN("Should reject due to Routing active")
            {
                tkId = insertAudio(
                    audioInputs, Audio::State::Routing, PlaybackType::None, Operation::State::Idle, tokenIdx);
                auto retInput = aMux.GetPlaybackInput(Token(), testPlaybackTypeHighPrio);
                auto retInput = aMux.GetPlaybackInput(testPlaybackTypeHighPrio);
                REQUIRE(retInput == std::nullopt);
            }
        }

M module-services/service-audio/ServiceAudio.cpp => module-services/service-audio/ServiceAudio.cpp +209 -195
@@ 46,8 46,7 @@ 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);
        auto msg = std::make_shared<AudioNotificationMessage>(AudioNotificationMessage::Type::EndOfFile, e.token);
        sys::Bus::SendMulticast(msg, sys::BusChannels::ServiceAudioNotifications, this);
    } break;
    case audio::PlaybackEventType::FileSystemNoSpace:


@@ 103,10 102,10 @@ static bool IsPlaybackEnabled(const audio::PlaybackType &type)
    return true;
}

std::optional<ServiceAudio::VibrationType> ServiceAudio::GetVibrationType(const audio::PlaybackType &type)
ServiceAudio::VibrationType ServiceAudio::GetVibrationType(const audio::PlaybackType &type)
{
    if (!IsVibrationEnabled(type)) {
        return std::nullopt;
        return VibrationType::None;
    }

    if (type == PlaybackType::CallRingtone) {


@@ 115,40 114,51 @@ std::optional<ServiceAudio::VibrationType> ServiceAudio::GetVibrationType(const 
    else if (type == PlaybackType::Notifications || type == PlaybackType::TextMessageRingtone) {
        return VibrationType::OneShot;
    }
    return std::nullopt;
    return VibrationType::None;
}

void ServiceAudio::VibrationStart(const audio::PlaybackType &type, std::shared_ptr<AudioResponseMessage> &resp)
void ServiceAudio::VibrationUpdate(const audio::PlaybackType &type, std::optional<AudioMux::Input *> input)
{
    auto vibType = GetVibrationType(type);
    if (!vibType || vibrationToken.IsValid()) {
        return;
    auto curVibrationType = GetVibrationType(type);
    if (curVibrationType == VibrationType::OneShot && !IsVibrationMotorOn()) {
        ExtVibrateOnce();
    }
    else if (input && curVibrationType == VibrationType::Continuous) {
        input.value()->EnableVibration();
    }

    if (vibType == VibrationType::OneShot) {
        vibrationToken = Token();
        ExtVibrateOnce();
    auto &inputs       = audioMux.GetAllInputs();
    auto anyOfInputsOn = std::any_of(inputs.cbegin(), inputs.cend(), [](auto &i) {
        return i.GetVibrationStatus() == AudioMux::VibrationStatus::On;
    });
    if (anyOfInputsOn && !IsVibrationMotorOn()) {
        ExtVibrationStart();
        vibrationMotorStatus = AudioMux::VibrationStatus::On;
    }
    else if (!anyOfInputsOn && IsVibrationMotorOn()) {
        ExtVibrationStop();
        vibrationMotorStatus = AudioMux::VibrationStatus::Off;
    }
    else if (vibType == VibrationType::Continuous) {
        if (resp && resp->token.IsValid()) {
            // audio has started
            vibrationToken = resp->token;
}

std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleGetFileTags(const std::string &fileName)
{
    if (auto input = audioMux.GetAvailableInput()) {
        auto tag = (*input)->audio->GetFileTags(fileName.c_str());
        if (tag) {
            return std::make_unique<AudioResponseMessage>(RetCode::Success, tag.value());
        }
        else {
            // audio did not start but we still want vibration
            vibrationToken = audioMux.IncrementToken();
            resp           = std::make_unique<AudioResponseMessage>(RetCode::Success, Tags(), vibrationToken);
            return std::make_unique<AudioResponseMessage>(RetCode::FileDoesntExist);
        }
        ExtVibrationStart();
    }
    return {};
}

void ServiceAudio::VibrationStop(const Token &token)
std::unique_ptr<AudioResponseMessage> ServiceAudio::HandlePause(const Token &token)
{
    if (vibrationToken.IsValid() && vibrationToken == token) {
        ExtVibrationStop();
        vibrationToken = Token();
    }
    auto input = audioMux.GetInput(token);
    return HandlePause(input);
}

void ServiceAudio::addOrIgnoreEntry(const std::string &profilePath, const std::string &defaultValue)


@@ 169,69 179,118 @@ void ServiceAudio::addOrIgnoreEntry(const std::string &profilePath, const std::s
    }
}

std::unique_ptr<AudioResponseMessage> ServiceAudio::HandlePause(std::optional<AudioRequestMessage *> msg)
std::unique_ptr<AudioResponseMessage> ServiceAudio::HandlePause(std::optional<AudioMux::Input *> input)
{
    auto retCode  = audio::RetCode::Failed;
    auto retToken = Token();

    audio::RetCode retCode = audio::RetCode::Failed;
    audio::Token retToken  = Token::MakeBadToken();
    if (!input) {
        return std::make_unique<AudioPauseResponse>(RetCode::TokenNotFound, Token::MakeBadToken());
    }

    auto pauseInput = [this](AudioMux::Input &audioInput) {
        auto playbackType = audioInput.audio->GetCurrentOperationPlaybackType();
        if (playbackType && IsResumable(*playbackType)) {
            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();
        }
    };
    auto &audioInput = input.value();

    if (msg) {
        std::optional<AudioMux::Input *> input = audioMux.GetInput((*msg)->token);
        if (!input) {
            retToken = pauseInput(**input);
        }
    auto playbackType = audioInput->audio->GetCurrentOperationPlaybackType();
    if (IsResumable(playbackType)) {
        retCode  = audioInput->audio->Pause();
        retToken = audioInput->token;
        audioInput->DisableVibration();
    }
    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);
        retCode = audioInput->audio->Stop();
        auto broadMsg =
            std::make_shared<AudioNotificationMessage>(AudioNotificationMessage::Type::Stop, audioInput->token);
        sys::Bus::SendMulticast(broadMsg, sys::BusChannels::ServiceAudioNotifications, this);
        audioMux.ResetInput(audioInput);
    }

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

std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleResume(const Token &token)
{
    if (auto input = audioMux.GetInput(token)) {
        VibrationUpdate(input.value()->audio->GetCurrentOperationPlaybackType(), input);
        return std::make_unique<AudioResumeResponse>((*input)->audio->Resume(), token);
    }
    return std::make_unique<AudioPauseResponse>(RetCode::TokenNotFound, Token::MakeBadToken());
}

template <typename... Args>
std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleStart(std::optional<AudioMux::Input *> input,
                                                                Operation::Type opType,
                                                                Args... args)
std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleStart(const Operation::Type opType,
                                                                const std::string fileName,
                                                                const audio::PlaybackType &playbackType)
{
    audio::RetCode retCode = audio::RetCode::Failed;
    audio::Token retToken  = Token::MakeBadToken();
    auto retCode  = audio::RetCode::Failed;
    auto retToken = Token::MakeBadToken();

    auto AudioStart = [&](auto &input) {
        if (input) {
            for (auto &audioInput : audioMux.GetAllInputs()) {
                HandlePause(&audioInput);
            }
            if (opType == Operation::Type::Recorder) {
                // since recording works on the same audio as routing
                retToken = input.value()->token;
            }
            else {
                retToken = audioMux.ResetInput(input);
            }

            if (IsPlaybackEnabled(playbackType)) {
                retCode = (*input)->audio->Start(opType, retToken, fileName.c_str(), playbackType);
            }
        }

    if (input) {
        if (retToken.IsValid()) {
            VibrationUpdate(playbackType, input);
            retCode = audio::RetCode::Success;
        }
    };

        HandlePause();
        retToken = audioMux.IncrementToken(input);
        retCode  = (*input)->audio->Start(opType, retToken, args...);
    if (opType == Operation::Type::Playback) {
        auto input = audioMux.GetPlaybackInput(playbackType);
        AudioStart(input);
        return std::make_unique<AudioStartPlaybackResponse>(retCode, retToken);
    }
    if (retCode != audio::RetCode::Success) {
        retToken = Token::MakeBadToken();
    else if (opType == Operation::Type::Recorder) {
        auto input = audioMux.GetRecordingInput();
        AudioStart(input);
        return std::make_unique<AudioStartRecorderResponse>(retCode, retToken);
    }
    return std::make_unique<AudioResponseMessage>(retCode, Tags(), retToken);
    else if (opType == Operation::Type::Router) {
        auto input = audioMux.GetRecordingInput();
        AudioStart(input);
        return std::make_unique<AudioStartRoutingResponse>(retCode, retToken);
    }
    return {};
}

std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleRoutingControl(
    const AudioRoutingControlRequest::ControlType &controlType, const bool enable)
{
    std::optional<Operation::Event> evt;

    if (controlType == AudioRoutingControlRequest::ControlType::Mute) {
        evt = enable ? Operation::Event::CallMute : Operation::Event::CallUnmute;
    }
    else if (controlType == AudioRoutingControlRequest::ControlType::SwitchSpeakerphone) {
        evt = enable ? Operation::Event::CallSpeakerphoneOn : Operation::Event::CallSpeakerphoneOff;
    }
    else if (controlType == AudioRoutingControlRequest::ControlType::SwitchHeadphones) {
        evt = enable ? Operation::Event::HeadphonesPlugin : Operation::Event::HeadphonesUnplug;
    }

    if (auto input = audioMux.GetRoutingInput(); evt && input) {
        return std::make_unique<AudioResponseMessage>((*input)->audio->SendEvent(evt.value()));
    }

    return {};
}

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

    auto stopInput = [this](auto inp) {


@@ 240,30 299,30 @@ std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleStop(AudioStopMessage 
        }
        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);
        auto msgStop = std::make_shared<AudioNotificationMessage>(AudioNotificationMessage::Type::Stop, inp->token);
        sys::Bus::SendMulticast(msgStop, sys::BusChannels::ServiceAudioNotifications, this);
        audioMux.IncrementToken(inp);
        audioMux.ResetInput(inp);
        return rCode;
    };

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


@@ 274,120 333,82 @@ std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleStop(AudioStopMessage 
    if (it != retCodes.end()) {
        return std::make_unique<AudioResponseMessage>(*it);
    }

    VibrationUpdate();
    return std::make_unique<AudioResponseMessage>(audio::RetCode::Success);
}

sys::Message_t ServiceAudio::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp)
void ServiceAudio::HandleNotification(const AudioNotificationMessage::Type &type, const Token &token)
{
    std::shared_ptr<AudioResponseMessage> responseMsg;
    if (type == AudioNotificationMessage::Type::EndOfFile) {
        auto input = audioMux.GetInput(token);
        if (input && ShouldLoop((*input)->audio->GetCurrentOperationPlaybackType())) {
            (*input)->audio->Start();
        }
        else {
            auto newMsg = std::make_shared<AudioStopRequest>(token);
            sys::Bus::SendUnicast(newMsg, ServiceAudio::serviceName, this);
        }
        return;
    }

    auto msgType = static_cast<int>(msgl->messageType);
    LOG_DEBUG("msgType %d", msgType);
    if (type != AudioNotificationMessage::Type::Stop) {
        LOG_DEBUG("Unhandled AudioNotificationMessage");
    }
}

    if (auto *msg = dynamic_cast<AudioNotificationMessage *>(msgl)) {
        switch (msg->type) {
        case AudioNotificationMessage::Type::EndOfFile: {
            auto input = audioMux.GetInput(msg->token);
            if (input && ShouldLoop((*input)->audio->GetCurrentOperationPlaybackType())) {
                (*input)->audio->Start();
            }
            else {
                auto newMsg = std::make_shared<AudioStopMessage>(msg->token);
                sys::Bus::SendUnicast(newMsg, ServiceAudio::serviceName, this);
            }
        } break;
sys::Message_t ServiceAudio::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp)
{
    std::shared_ptr<AudioResponseMessage> responseMsg;

        case AudioNotificationMessage::Type::Stop: {
    auto &msgType = typeid(*msgl);
    LOG_DEBUG("msgType %d", static_cast<int>(msgl->messageType));

        } break;
        default:
            LOG_DEBUG("Unhandled AudioNotificationMessage");
            break;
        }
    if (msgType == typeid(AudioNotificationMessage)) {
        auto *msg = static_cast<AudioNotificationMessage *>(msgl);
        HandleNotification(msg->type, msg->token);
    }
    else if (auto *msg = dynamic_cast<AudioGetSetting *>(msgl)) {
    else if (msgType == typeid(AudioGetSetting)) {
        auto *msg   = static_cast<AudioGetSetting *>(msgl);
        auto value  = getSetting(msg->setting, msg->profileType, msg->playbackType);
        responseMsg = std::make_shared<AudioResponseMessage>(RetCode::Success, utils::getValue<float>(value));
    }
    else if (auto *msg = dynamic_cast<AudioSetSetting *>(msgl)) {
    else if (msgType == typeid(AudioSetSetting)) {
        auto *msg = static_cast<AudioSetSetting *>(msgl);
        setSetting(msg->setting, msg->val, msg->profileType, msg->playbackType);
        responseMsg = std::make_shared<AudioResponseMessage>(RetCode::Success);
    }
    else if (auto *msg = dynamic_cast<AudioStopMessage *>(msgl)) {
        VibrationStop(msg->token);
        responseMsg = HandleStop(msg);
    else if (msgType == typeid(AudioStopRequest)) {
        auto *msg   = static_cast<AudioStopRequest *>(msgl);
        responseMsg = HandleStop(msg->stopVec, msg->token);
    }
    else if (auto *msg = dynamic_cast<AudioStartMessage *>(msgl)) {
        if (IsPlaybackEnabled(msg->playbackType)) {
            if (auto input = audioMux.GetPlaybackInput(msg->token, msg->playbackType)) {
                responseMsg = HandleStart(input, Operation::Type::Playback, msg->fileName.c_str(), msg->playbackType);
            }
        }
        VibrationStart(msg->playbackType, responseMsg);
    }
    else if (auto *msg = dynamic_cast<AudioRequestMessage *>(msgl)) {
        switch (msg->type) {
        case MessageType::AudioRecorderStart: {
            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");
            if (auto input = audioMux.GetRoutingInput(true)) {
                responseMsg = HandleStart(input, Operation::Type::Router);
            }
        } break;

        case MessageType::AudioPause: {
            responseMsg = HandlePause(msg);
        } break;

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

        case MessageType::AudioGetFileTags: {
            if (auto input = audioMux.GetAvailableInput()) {
                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::AudioRoutingMute: {
            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: {
            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: {
            if (auto input = audioMux.GetRecordingInput()) {
                responseMsg = std::make_shared<AudioResponseMessage>((*input)->audio->SendEvent(
                    msg->enable ? Operation::Event::HeadphonesPlugin : Operation::Event::HeadphonesUnplug));
            }
        } break;

        default:
            LOG_ERROR("Unhandled AudioRequestMessage");
            responseMsg = std::make_shared<AudioResponseMessage>(RetCode::Failed);
            break;
        }
    else if (msgType == typeid(AudioStartPlaybackRequest)) {
        auto *msg   = static_cast<AudioStartPlaybackRequest *>(msgl);
        responseMsg = HandleStart(Operation::Type::Playback, msg->fileName.c_str(), msg->playbackType);
    }
    else if (msgType == typeid(AudioStartRecorderRequest)) {
        auto *msg   = static_cast<AudioStartRecorderRequest *>(msgl);
        responseMsg = HandleStart(Operation::Type::Recorder, msg->fileName.c_str());
    }
    else if (msgType == typeid(AudioStartRoutingRequest)) {
        LOG_DEBUG("AudioRoutingStart");
        responseMsg = HandleStart(Operation::Type::Router);
    }
    else if (msgType == typeid(AudioPauseRequest)) {
        auto *msg   = static_cast<AudioPauseRequest *>(msgl);
        responseMsg = HandlePause(msg->token);
    }
    else if (msgType == typeid(AudioResumeRequest)) {
        auto *msg   = static_cast<AudioResumeRequest *>(msgl);
        responseMsg = HandleResume(msg->token);
    }
    else if (msgType == typeid(AudioGetFileTagsRequest)) {
        auto *msg   = static_cast<AudioGetFileTagsRequest *>(msgl);
        responseMsg = HandleGetFileTags(msg->fileName);
    }
    else if (msgType == typeid(AudioRoutingControlRequest)) {
        auto *msg   = static_cast<AudioRoutingControlRequest *>(msgl);
        responseMsg = HandleRoutingControl(msg->controlType, msg->enable);
    }
    else {
        LOG_DEBUG("Unhandled message");


@@ 397,7 418,7 @@ sys::Message_t ServiceAudio::DataReceivedHandler(sys::DataMessage *msgl, sys::Re
        return responseMsg;
    }
    else {
        return std::make_shared<AudioResponseMessage>(RetCode::Failed, Tags{}, Token::MakeBadToken());
        return std::make_shared<AudioResponseMessage>(RetCode::Failed);
    }
}



@@ 413,28 434,21 @@ void ServiceAudio::updateDbValue(const std::string &path, const audio::Setting &
    DBServiceAPI::GetQuery(this, db::Interface::Name::Settings_v2, std::move(query));
}

void ServiceAudio::updateDbValue(const audio::Operation *currentOperation,
void ServiceAudio::updateDbValue(const audio::Operation &currentOperation,
                                 const audio::Setting &setting,
                                 const uint32_t &value)
{
    if (currentOperation == nullptr) {
        return;
    }
    const auto currentProfile = currentOperation->GetProfile();
    const auto currentProfile = currentOperation.GetProfile();

    auto dbPath = audio::str(setting, currentOperation->GetPlaybackType(), currentProfile->GetType());
    auto dbPath = audio::str(setting, currentOperation.GetPlaybackType(), currentProfile->GetType());
    updateDbValue(dbPath, setting, std::to_string(value));
}

void ServiceAudio::updateDbValue(const audio::Operation *currentOperation,
void ServiceAudio::updateDbValue(const audio::Operation &currentOperation,
                                 const audio::Setting &setting,
                                 const bool &value)
{
    if (currentOperation == nullptr) {
        return;
    }

    auto dbPath = audio::str(setting, currentOperation->GetPlaybackType());
    auto dbPath = audio::str(setting, currentOperation.GetPlaybackType());
    updateDbValue(dbPath, setting, std::to_string(value));
}



@@ 487,13 501,13 @@ std::optional<std::string> ServiceAudio::getCurrentSetting(const audio::Setting 
        return {};
    }

    const auto currentOperation = (*activeInput)->audio->GetCurrentOperation();
    const auto &currentOperation = (*activeInput)->audio->GetCurrentOperation();
    const auto path             = [&setting, &currentOperation]() -> std::string {
        if (setting == audio::Setting::EnableVibration || setting == audio::Setting::EnableSound) {
            return audio::str(setting, currentOperation->GetPlaybackType());
            return audio::str(setting, currentOperation.GetPlaybackType());
        }
        else {
            return audio::str(setting, currentOperation->GetPlaybackType(), currentOperation->GetProfile()->GetType());
            return audio::str(setting, currentOperation.GetPlaybackType(), currentOperation.GetProfile()->GetType());
        }
    }();
    return fetchAudioSettingFromDb<std::string>(path, "");


@@ 517,7 531,7 @@ void ServiceAudio::setCurrentSetting(const audio::Setting &setting, const std::s
    }

    auto &audio                 = (*activeInput)->audio;
    const auto currentOperation = audio->GetCurrentOperation();
    const auto &currentOperation = audio->GetCurrentOperation();
    switch (setting) {
    case audio::Setting::Volume: {
        const auto valueToSet = std::clamp(utils::getValue<audio::Volume>(value), minVolume, maxVolume);

M module-services/service-audio/ServiceAudio.hpp => module-services/service-audio/ServiceAudio.hpp +26 -14
@@ 26,7 26,6 @@

class ServiceAudio : public sys::Service
{

  public:
    ServiceAudio();



@@ 45,26 44,39 @@ class ServiceAudio : public sys::Service
  private:
    enum class VibrationType
    {
        None,
        OneShot,
        Continuous
    };

    audio::AudioMux audioMux;
    audio::Token vibrationToken;
    audio::AudioMux::VibrationStatus vibrationMotorStatus = audio::AudioMux::VibrationStatus::Off;

    auto IsVibrationMotorOn()
    {
        return vibrationMotorStatus == audio::AudioMux::VibrationStatus::On;
    }

    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,
                                                      audio::Operation::Type opType,
                                                      Args... args);
    std::unique_ptr<AudioResponseMessage> HandlePause(std::optional<AudioRequestMessage *> msg = std::nullopt);
    std::unique_ptr<AudioResponseMessage> HandleStop(AudioStopMessage *msg);

    void VibrationStart(const audio::PlaybackType &type, std::shared_ptr<AudioResponseMessage> &resp);
    void VibrationStop(const audio::Token &token);
    auto GetVibrationType(const audio::PlaybackType &type) -> std::optional<VibrationType>;
    auto HandleStart(const audio::Operation::Type opType,
                     const std::string                       = "",
                     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 HandleRoutingControl(const AudioRoutingControlRequest::ControlType &cType, const bool enable)
        -> std::unique_ptr<AudioResponseMessage>;
    auto HandlePause(const audio::Token &token) -> std::unique_ptr<AudioResponseMessage>;
    auto HandlePause(std::optional<audio::AudioMux::Input *> input) -> std::unique_ptr<AudioResponseMessage>;
    auto HandleResume(const audio::Token &token) -> std::unique_ptr<AudioResponseMessage>;
    auto HandleGetFileTags(const std::string &fileName) -> std::unique_ptr<AudioResponseMessage>;
    void HandleNotification(const AudioNotificationMessage::Type &type, const audio::Token &token);

    void VibrationUpdate(const audio::PlaybackType &type               = audio::PlaybackType::None,
                         std::optional<audio::AudioMux::Input *> input = std::nullopt);
    auto GetVibrationType(const audio::PlaybackType &type) -> VibrationType;

    constexpr auto IsResumable(const audio::PlaybackType &type) const -> bool;
    constexpr auto ShouldLoop(const std::optional<audio::PlaybackType> &type) const -> bool;


@@ 103,8 115,8 @@ class ServiceAudio : public sys::Service
                                         const audio::PlaybackType &playbackType);
    std::optional<std::string> getCurrentSetting(const audio::Setting &setting);
    void updateDbValue(const std::string &path, const audio::Setting &setting, const std::string &value);
    void updateDbValue(const audio::Operation *currentOperation, const audio::Setting &setting, const uint32_t &value);
    void updateDbValue(const audio::Operation *currentOperation, const audio::Setting &setting, const bool &value);
    void updateDbValue(const audio::Operation &currentOperation, const audio::Setting &setting, const uint32_t &value);
    void updateDbValue(const audio::Operation &currentOperation, const audio::Setting &setting, const bool &value);
};

#endif // PUREPHONE_SERVICEAUDIO_HPP

M module-services/service-audio/api/AudioServiceAPI.cpp => module-services/service-audio/api/AudioServiceAPI.cpp +37 -49
@@ 34,86 34,75 @@ namespace AudioServiceAPI
        }
    } // namespace

    Handle PlaybackStart(sys::Service *serv, const audio::PlaybackType &playbackType, const std::string &fileName)
    bool PlaybackStart(sys::Service *serv, const audio::PlaybackType &playbackType, const std::string &fileName)
    {
        auto msg = std::make_shared<AudioStartMessage>(fileName, playbackType);
        auto ret = SendAudioRequest(serv, msg);
        return Handle(ret->retCode, ret->token);
        auto msg = std::make_shared<AudioStartPlaybackRequest>(fileName, playbackType);
        return sys::Bus::SendUnicast(msg, ServiceAudio::serviceName, serv);
    }

    Handle RecordingStart(sys::Service *serv, const std::string &fileName)
    bool RecordingStart(sys::Service *serv, const std::string &fileName)
    {
        auto msg      = std::make_shared<AudioRequestMessage>(MessageType::AudioRecorderStart);
        msg->fileName = fileName;
        auto ret      = SendAudioRequest(serv, msg);
        return Handle(ret->retCode, ret->token);
        auto msg = std::make_shared<AudioStartRecorderRequest>(fileName);
        return sys::Bus::SendUnicast(msg, ServiceAudio::serviceName, serv);
    }

    Handle RoutingStart(sys::Service *serv)
    bool RoutingStart(sys::Service *serv)
    {
        std::shared_ptr<AudioRequestMessage> msg =
            std::make_shared<AudioRequestMessage>(MessageType::AudioRoutingStart);
        auto ret = SendAudioRequest(serv, msg);
        return Handle(ret->retCode, ret->token);
        auto msg = std::make_shared<AudioStartRoutingRequest>();
        return sys::Bus::SendUnicast(msg, ServiceAudio::serviceName, serv);
    }

    audio::RetCode RoutingMute(sys::Service *serv, bool enable)
    bool RoutingMute(sys::Service *serv, bool enable)
    {
        auto msg    = std::make_shared<AudioRequestMessage>(MessageType::AudioRoutingMute);
        msg->enable = enable;

        return SendAudioRequest(serv, msg)->retCode;
        auto msg = std::make_shared<AudioRoutingControlRequest>(AudioRoutingControlRequest::ControlType::Mute, enable);
        return sys::Bus::SendUnicast(msg, ServiceAudio::serviceName, serv);
    }

    audio::RetCode RoutingSpeakerPhone(sys::Service *serv, bool enable)
    bool RoutingSpeakerPhone(sys::Service *serv, bool enable)
    {
        auto msg    = std::make_shared<AudioRequestMessage>(MessageType::AudioRoutingSpeakerhone);
        msg->enable = enable;

        return SendAudioRequest(serv, msg)->retCode;
        auto msg = std::make_shared<AudioRoutingControlRequest>(
            AudioRoutingControlRequest::ControlType::SwitchSpeakerphone, enable);
        return sys::Bus::SendUnicast(msg, ServiceAudio::serviceName, serv);
    }

    audio::RetCode RoutingHeadset(sys::Service *serv, bool enable)
    bool RoutingHeadset(sys::Service *serv, bool enable)
    {
        auto msg    = std::make_shared<AudioRequestMessage>(MessageType::AudioRoutingHeadset);
        msg->enable = enable;

        return SendAudioRequest(serv, msg)->retCode;
        auto msg = std::make_shared<AudioRoutingControlRequest>(
            AudioRoutingControlRequest::ControlType::SwitchHeadphones, enable);
        return sys::Bus::SendUnicast(msg, ServiceAudio::serviceName, serv);
    }

    RetCode Stop(sys::Service *serv, const std::vector<audio::PlaybackType> &stopVec)
    bool Stop(sys::Service *serv, const std::vector<audio::PlaybackType> &stopVec)
    {
        if (stopVec.empty()) {
            return RetCode::Success;
            return true;
        }
        auto msg = std::make_shared<AudioStopMessage>(stopVec);
        return SendAudioRequest(serv, msg)->retCode;
        auto msg = std::make_shared<AudioStopRequest>(stopVec);
        return sys::Bus::SendUnicast(msg, ServiceAudio::serviceName, serv);
    }

    RetCode Stop(sys::Service *serv, const audio::Handle &handle)
    bool Stop(sys::Service *serv, const audio::Token &token)
    {
        auto msg = std::make_shared<AudioStopMessage>(handle.GetToken());
        return SendAudioRequest(serv, msg)->retCode;
        auto msg = std::make_shared<AudioStopRequest>(token);
        return sys::Bus::SendUnicast(msg, ServiceAudio::serviceName, serv);
    }

    RetCode Stop(sys::Service *serv)
    bool StopAll(sys::Service *serv)
    {
        auto msg = std::make_shared<AudioStopMessage>();
        return SendAudioRequest(serv, msg)->retCode;
        auto msg = std::make_shared<AudioStopRequest>();
        return sys::Bus::SendUnicast(msg, ServiceAudio::serviceName, serv);
    }

    RetCode Pause(sys::Service *serv, const audio::Handle &handle)
    bool Pause(sys::Service *serv, const audio::Token &token)
    {
        std::shared_ptr<AudioRequestMessage> msg =
            std::make_shared<AudioRequestMessage>(MessageType::AudioPause, handle.GetToken());
        return SendAudioRequest(serv, msg)->retCode;
        auto msg = std::make_shared<AudioPauseRequest>(token);
        return sys::Bus::SendUnicast(msg, ServiceAudio::serviceName, serv);
    }

    RetCode Resume(sys::Service *serv, const audio::Handle &handle)
    bool Resume(sys::Service *serv, const audio::Token &token)
    {
        std::shared_ptr<AudioRequestMessage> msg =
            std::make_shared<AudioRequestMessage>(MessageType::AudioResume, handle.GetToken());
        return SendAudioRequest(serv, msg)->retCode;
        auto msg = std::make_shared<AudioResumeRequest>(token);
        return sys::Bus::SendUnicast(msg, ServiceAudio::serviceName, serv);
    }

    template <typename T>


@@ 170,8 159,7 @@ namespace AudioServiceAPI

    std::optional<Tags> GetFileTags(sys::Service *serv, const std::string &fileName)
    {
        auto msg      = std::make_shared<AudioRequestMessage>(MessageType::AudioGetFileTags);
        msg->fileName = fileName;
        auto msg = std::make_shared<AudioGetFileTagsRequest>(fileName);

        auto resp = SendAudioRequest(serv, msg);
        if (resp->retCode == audio::RetCode::Success) {

M module-services/service-audio/api/AudioServiceAPI.hpp => module-services/service-audio/api/AudioServiceAPI.hpp +39 -32
@@ 13,75 13,82 @@ class Service;
namespace AudioServiceAPI
{
    /**
     * @brief Starts playback operation.
     * @brief Starts playback operation. Asynchronous call.
     *
     * @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 operations.
     * @return True is request has been sent successfully, false otherwise
     *  Response will come as message AudioStartPlaybackResponse
     */
    audio::Handle PlaybackStart(sys::Service *serv,
                                const audio::PlaybackType &playbackType,
                                const std::string &fileName);
    bool PlaybackStart(sys::Service *serv, const audio::PlaybackType &playbackType, const std::string &fileName);

    /**
     * @brief Starts recording.
     * @brief Starts recording. Asynchronous call.
     *
     * @param serv Requesting service.
     * @param fileName Path to file where recording is to be saved.
     * @return audio::Handle Handle to operation to be used in subsequent operations.
     * @return True is request has been sent successfully, false otherwise
     *  Response will come as message AudioStartRecordingResponse
     */
    audio::Handle RecordingStart(sys::Service *serv, const std::string &fileName);
    bool RecordingStart(sys::Service *serv, const std::string &fileName);
    /**
     * @brief Starts routing.
     * @brief Starts routing. Asynchronous call.
     *
     * @param serv Requesting service.
     * @return audio::Handle Handle to operation to be used in subsequent operations.
     * @return True is request has been sent successfully, false otherwise
     *  Response will come as message AudioStartRoutingResponse
     */
    audio::Handle RoutingStart(sys::Service *serv);
    audio::RetCode RoutingMute(sys::Service *serv, bool enable);
    audio::RetCode RoutingSpeakerPhone(sys::Service *serv, bool enable);
    audio::RetCode RoutingHeadset(sys::Service *serv, bool enable);
    bool RoutingStart(sys::Service *serv);
    bool RoutingMute(sys::Service *serv, bool enable);
    bool RoutingSpeakerPhone(sys::Service *serv, bool enable);
    bool RoutingHeadset(sys::Service *serv, bool enable);
    /**
     * @brief Stops playback operations by type.
     * @brief Stops playback operations by type. Asynchronous call.
     *
     * @param serv Requesting service
     * @param stopVec Playback types to be stopped.
     *  When stop vector is passed it stops current operation only if it's type is contained in the vector.
     *  Otherwise does not have effect.
     * @return audio::RetCode standard service-api return code
     * @return True is request has been sent successfully, false otherwise
     *  Response will come as message AudioStopResponse for all stopped inputs
     */
    audio::RetCode Stop(sys::Service *serv, const std::vector<audio::PlaybackType> &stopVec);
    bool Stop(sys::Service *serv, const std::vector<audio::PlaybackType> &stopVec);
    /**
     * @brief Stops playback operation.
     *
     * @param serv Requesting service
     * @param handle Handle to controlled operation
     * @param token Identifier of related operation
     * @return audio::RetCode standard service-api return code
     *  Response will come as message AudioStopResponse
     */
    audio::RetCode Stop(sys::Service *serv, const audio::Handle &handle);
    bool Stop(sys::Service *serv, const audio::Token &token);
    /**
     * @brief Stops all active playback operation. Stopped operations cannot be resumed.
     * @brief Stops all active playback operation. Stopped operations cannot be resumed. Asynchronous call.
     *
     * @param serv Requesting service
     * @return audio::RetCode standard service-api return code
     * @return True is request has been sent successfully, false otherwise
     *  Response will come as message AudioStopResponse for all stopped inputs
     */
    audio::RetCode StopAll(sys::Service *serv);
    bool StopAll(sys::Service *serv);
    /**
     * @brief Pauses playback operation. Can be resumed by Resume()
     * @brief Pauses playback operation. Can be resumed by Resume(). Asynchronous call.
     *
     * @param serv Requesting service
     * @param handle Handle to controlled operation
     * @return audio::RetCode standard service-api return code
     * @param token Identifier of related operation
     * @return True is request has been sent successfully, false otherwise
     *  Response will come as message AudioPauseResponse
     */
    audio::RetCode Pause(sys::Service *serv, const audio::Handle &handle);
    bool Pause(sys::Service *serv, const audio::Token &token);
    /**
     * @brief Resumes paused operation.
     * @brief Resumes paused operation. Asynchronous call.
     *
     * @param serv Requesting service
     * @param handle Handle to controlled operation
     * @return audio::RetCode standard service-api return code
     * @param token Identifier of related operation
     * @return True is request has been sent successfully, false otherwise
     *  Response will come as message AudioResumeResponse
     */
    audio::RetCode Resume(sys::Service *serv, const audio::Handle &handle);
    bool Resume(sys::Service *serv, const audio::Token &token);
    /**
     * @brief Attempts to parse audio file for metatags.
     *


@@ 97,7 104,7 @@ namespace AudioServiceAPI
     * @param value - requested value.
     * @param profileType - selected profile type.
     * @param playbackType -  type of playback. Not used when profileType is different than playback.
     * @return           Standard service-api return code. Success if suitable.
     * @return Standard service-api return code. Success if suitable.
     */
    template <typename T>
    audio::RetCode GetSetting(sys::Service *serv,


@@ 112,7 119,7 @@ namespace AudioServiceAPI
     * @param value - value to be set.
     * @param profileType - selected profile type.
     * @param playbackType -  type of playback. Not used when profileType is different than playback.
     * @return           Standard service-api return code. Success if suitable.
     * @return Standard service-api return code. Success if suitable.
     */
    template <typename T>
    audio::RetCode SetSetting(sys::Service *serv,

M module-services/service-audio/messages/AudioMessage.hpp => module-services/service-audio/messages/AudioMessage.hpp +129 -44
@@ 20,25 20,30 @@
class AudioMessage : public sys::DataMessage
{
  public:
    AudioMessage() : sys::DataMessage(MessageType::MessageTypeUninitialized)
    AudioMessage() : sys::DataMessage(MessageType::AudioMessage)
    {}

    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;
};

class AudioResponseMessage : public sys::ResponseMessage
{
  public:
    AudioResponseMessage(audio::RetCode retCode  = audio::RetCode::Success,
                         const audio::Tags &tags = {},
                         const float val         = 0.0)
        : sys::ResponseMessage(), retCode(retCode), tags(tags), val(val)
    {}

    explicit AudioMessage(audio::Token token) : sys::DataMessage(MessageType::MessageTypeUninitialized), token(token)
    AudioResponseMessage(audio::RetCode retCode, const float val) : AudioResponseMessage(retCode, {}, val)
    {}

    explicit AudioMessage(const audio::PlaybackType &playbackType)
        : sys::DataMessage(MessageType::MessageTypeUninitialized), playbackType(playbackType)
    virtual ~AudioResponseMessage()
    {}

    MessageType type = MessageType::MessageTypeUninitialized;
    audio::PlaybackType playbackType = audio::PlaybackType::None;
    const audio::Token token;
    const audio::RetCode retCode = audio::RetCode::Success;
    audio::Tags tags             = {};
    float val                    = 0.0;
};

class AudioNotificationMessage : public AudioMessage


@@ 51,14 56,11 @@ class AudioNotificationMessage : public AudioMessage
        Stop
    };

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

    ~AudioNotificationMessage()
    {}

    Type type;
    const Type type;
    const audio::Token token;
};

class AudioSettingsMessage : public AudioMessage


@@ 104,63 106,146 @@ class AudioSetSetting : public AudioSettingsMessage
    ~AudioSetSetting() override = default;
};

class AudioRequestMessage : public AudioMessage
class AudioStopRequest : public AudioMessage
{
  public:
    AudioRequestMessage(MessageType messageType, audio::Token token = audio::Token())
        : AudioMessage(messageType, audio::PlaybackType::None, token)
    AudioStopRequest(const std::vector<audio::PlaybackType> &stopVec = {}) : stopVec(stopVec)
    {}

    ~AudioRequestMessage()
    AudioStopRequest(const audio::Token &token) : token(token)
    {}
    std::string fileName;
    float val;
    bool enable;

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

class AudioStopMessage : public AudioMessage
class AudioStopResponse : public AudioResponseMessage
{
  public:
    AudioStopMessage(const std::vector<audio::PlaybackType> &stopVec = {}) : AudioMessage(), stopVec(stopVec)
    AudioStopResponse(audio::RetCode retCode, const audio::Token &token) : AudioResponseMessage(retCode), token(token)
    {}

    AudioStopMessage(const audio::Token &token) : AudioMessage(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::vector<audio::PlaybackType> stopVec;
    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 AudioStartRoutingRequest : public AudioMessage
{
  public:
    AudioStartRoutingRequest()
    {}
};

class AudioStartMessage : public AudioMessage
class AudioStartRoutingResponse : public AudioResponseMessage
{
  public:
    AudioStartMessage(const std::string &fileName, const audio::PlaybackType &playbackType)
        : AudioMessage(playbackType), fileName(fileName)
    AudioStartRoutingResponse(audio::RetCode retCode, const audio::Token &token)
        : AudioResponseMessage(retCode), token(token)
    {}

    const audio::Token token;
};

class AudioStartRecorderRequest : public AudioMessage
{
  public:
    AudioStartRecorderRequest(const std::string &fileName) : fileName(fileName)
    {}

    const std::string fileName;
};

class AudioResponseMessage : public sys::ResponseMessage
class AudioStartRecorderResponse : public AudioResponseMessage
{
  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), token(token)
    AudioStartRecorderResponse(audio::RetCode retCode, const audio::Token &token)
        : AudioResponseMessage(retCode), token(token)
    {}

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

class AudioPauseRequest : public AudioMessage
{
  public:
    AudioPauseRequest(const audio::Token &token) : token(token)
    {}

    virtual ~AudioResponseMessage()
    const audio::Token token;
};

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

    const audio::Token token;
};

class AudioResumeRequest : public AudioMessage
{
  public:
    AudioResumeRequest(const audio::Token &token) : token(token)
    {}

    const audio::Token token;
};

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

    const audio::Token token;
};

class AudioGetFileTagsRequest : public AudioMessage
{
  public:
    AudioGetFileTagsRequest(const std::string &fileName) : fileName(fileName)
    {}

    const std::string fileName;
};

class AudioRoutingControlRequest : public AudioMessage
{
  public:
    enum class ControlType
    {
        RecordCtrl,
        Mute,
        SwitchSpeakerphone,
        SwitchHeadphones
    };

    AudioRoutingControlRequest(ControlType controlType, bool enable) : enable(enable), controlType(controlType)
    {}

    audio::RetCode retCode = audio::RetCode::Success;
    audio::Tags tags       = {};
    float val              = 0.0;
    audio::Token token;
    const bool enable;
    const ControlType controlType;
};

#endif // PUREPHONE_AUDIOMESSAGE_HPP

M module-services/service-evtmgr/EventManager.cpp => module-services/service-evtmgr/EventManager.cpp +3 -6
@@ 157,12 157,9 @@ sys::Message_t EventManager::DataReceivedHandler(sys::DataMessage *msgl, sys::Re

        handled = true;
    }
    else if (msgl->messageType == MessageType::AudioRoutingHeadset && msgl->sender == this->GetName()) {
        auto *msg = dynamic_cast<AudioRequestMessage *>(msgl);
        if (msg != nullptr) {
            AudioServiceAPI::RoutingHeadset(this, msg->enable);
            handled = true;
        }
    else if (auto msg = dynamic_cast<AudioRoutingControlRequest *>(msgl); msg && msgl->sender == this->GetName()) {
        AudioServiceAPI::RoutingHeadset(this, msg->enable);
        handled = true;
    }
    else if (!targetApplication.empty() && dynamic_cast<sevm::SIMMessage *>(msgl) != nullptr) {
        sys::Bus::SendUnicast(std::make_shared<sevm::SIMMessage>(), targetApplication, this);

M module-services/service-evtmgr/WorkerEvent.cpp => module-services/service-evtmgr/WorkerEvent.cpp +2 -3
@@ 71,9 71,8 @@ bool WorkerEvent::handleMessage(uint32_t queueID)

        if (bsp::headset::Handler(notification) == true) {
            bool state = bsp::headset::IsInserted();

            auto message    = std::make_shared<AudioRequestMessage>(MessageType::AudioRoutingHeadset);
            message->enable = state;
            auto message = std::make_shared<AudioRoutingControlRequest>(
                AudioRoutingControlRequest::ControlType::SwitchHeadphones, state);
            sys::Bus::SendUnicast(message, service::name::evt_manager, this->service);
        }
    }

M module-sys/Service/Service.cpp => module-sys/Service/Service.cpp +7 -2
@@ 114,9 114,8 @@ namespace sys
        return ret;
    }

    bool Service::connect(Message *msg, MessageHandler handler)
    bool Service::connect(const type_info &type, MessageHandler handler)
    {
        auto &type = typeid(*msg);
        auto idx   = type_index(type);
        if (message_handlers.find(idx) == message_handlers.end()) {
            LOG_DEBUG("Registering new message handler on %s", type.name());


@@ 127,6 126,12 @@ namespace sys
        return false;
    }

    bool Service::connect(Message *msg, MessageHandler handler)
    {
        auto &type = typeid(*msg);
        return connect(type, handler);
    }

    bool Service::connect(Message &&msg, MessageHandler handler)
    {
        return Service::connect(&msg, handler);

M module-sys/Service/Service.hpp => module-sys/Service/Service.hpp +2 -0
@@ 14,6 14,7 @@
#include <typeindex>   // for type_index
#include <utility>     // for pair
#include <vector>      // for vector<>::iterator, vector
#include <typeinfo>    // for connect by type

namespace sys
{


@@ 75,6 76,7 @@ namespace sys
        std::vector<std::pair<uint64_t, uint32_t>> staleUniqueMsg;

        /// connect: register message handler
        bool connect(const std::type_info &type, MessageHandler handler);
        bool connect(Message *msg, MessageHandler handler);
        bool connect(Message &&msg, MessageHandler handler);


M source/MessageType.hpp => source/MessageType.hpp +1 -15
@@ 127,21 127,7 @@ enum class MessageType
    DBCalllogGetCount,       // Get Calllog reocrds count

    // Audio service messages
    AudioNotification,
    AudioPlaybackStart,
    AudioRecorderStart,
    AudioRoutingStart,
    AudioStop,
    AudioPause,
    AudioResume,

    AudioRoutingMute,
    AudioRoutingSpeakerhone,
    AudioRoutingHeadset,

    AudioSetInputGain,
    AudioGetInputGain,
    AudioGetFileTags,
    AudioMessage,

    // application manager
    APMCheckAppRunning, // check if application is running in application manager