~aleteoryx/muditaos

d59ac56d516cdb04cca7c0a9824e5e69c4fbb84d — Bartosz Cichocki 3 years ago 106440c
[MOS-347] Separate A2DP from HFP in ProfileManager

Now, both profiles can operate separately. Additonally, minor
fixes has been applied to allow calling via car audio system.
Some infotainment systems still don't work though.
25 files changed, 123 insertions(+), 210 deletions(-)

M module-audio/Audio/Operation/RouterOperation.cpp
M module-bluetooth/Bluetooth/CommandHandler.cpp
M module-bluetooth/Bluetooth/CommandHandler.hpp
M module-bluetooth/Bluetooth/command/Command.hpp
M module-bluetooth/Bluetooth/interface/BluetoothDriverImpl.cpp
M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.cpp
M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.hpp
M module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.cpp
M module-bluetooth/Bluetooth/interface/profiles/HFP/HFP.cpp
M module-bluetooth/Bluetooth/interface/profiles/HFP/HFP.hpp
M module-bluetooth/Bluetooth/interface/profiles/HFP/HFPImpl.hpp
M module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.cpp
M module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.hpp
M module-bluetooth/Bluetooth/interface/profiles/HSP/HSPImpl.hpp
M module-bluetooth/Bluetooth/interface/profiles/PhoneInterface.cpp
M module-bluetooth/Bluetooth/interface/profiles/PhoneInterface.hpp
M module-bluetooth/Bluetooth/interface/profiles/Profile.hpp
M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.cpp
M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp
M module-bluetooth/lib/btstack
M module-services/service-audio/ServiceAudio.cpp
M module-services/service-bluetooth/ServiceBluetooth.cpp
M module-services/service-bluetooth/service-bluetooth/BluetoothMessage.hpp
M module-services/service-bluetooth/service-bluetooth/ServiceBluetooth.hpp
M module-utils/log/Logger.cpp
M module-audio/Audio/Operation/RouterOperation.cpp => module-audio/Audio/Operation/RouterOperation.cpp +2 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "RouterOperation.hpp"


@@ 80,6 80,7 @@ namespace audio
        // enable audio connections
        voiceOutputConnection->enable();
        if (!IsMuted()) {
            LOG_DEBUG("Voice input not muted");
            voiceInputConnection->enable();
        }


M module-bluetooth/Bluetooth/CommandHandler.cpp => module-bluetooth/Bluetooth/CommandHandler.cpp +2 -16
@@ 64,8 64,6 @@ namespace bluetooth
            return disconnectAudioConnection();
        case bluetooth::Command::PowerOff:
            return Error::Success;
        case bluetooth::Command::SwitchProfile:
            return switchAudioProfile();
        case bluetooth::Command::None:
            return Error::Success;
        case Command::StartRinging:


@@ 76,6 74,8 @@ namespace bluetooth
            return profileManager->initializeCall();
        case Command::CallAnswered:
            return profileManager->callAnswered();
        case Command::CallTerminated:
            return profileManager->terminateCall();
        case Command::IncomingCallNumber:
            return profileManager->setIncomingCallNumber(command.getData());
        case Command::SignalStrengthData:


@@ 143,20 143,6 @@ namespace bluetooth
        LOG_INFO("Pairing result: %s", magic_enum::enum_name(errorCode).data());
        return errorCode;
    }
    Error::Code CommandHandler::switchAudioProfile()
    {
        static auto profile = AudioProfile::A2DP;
        if (profile == AudioProfile::A2DP) {
            profile = AudioProfile::HSP;
            LOG_INFO("New profile: HSP");
        }
        else {
            profile = AudioProfile::A2DP;
            LOG_INFO("New profile: A2DP");
        }
        profileManager->switchProfile(profile);
        return Error::Success;
    }
    Error::Code CommandHandler::unpair(const DataVariant &data)
    {
        auto device = std::get<Devicei>(data);

M module-bluetooth/Bluetooth/CommandHandler.hpp => module-bluetooth/Bluetooth/CommandHandler.hpp +0 -1
@@ 49,7 49,6 @@ namespace bluetooth
        Error::Code pair(const DataVariant &data);
        Error::Code unpair(const DataVariant &data);
        Error::Code availableDevices();
        Error::Code switchAudioProfile();
        sys::Service *service;
        std::shared_ptr<bluetooth::SettingsHolder> settings;
        std::shared_ptr<bluetooth::ProfileManager> profileManager;

M module-bluetooth/Bluetooth/command/Command.hpp => module-bluetooth/Bluetooth/command/Command.hpp +1 -1
@@ 28,8 28,8 @@ namespace bluetooth
            StartRouting,
            StartStream,
            StopStream,
            SwitchProfile,
            CallAnswered,
            CallTerminated,
            IncomingCallNumber,
            SignalStrengthData,
            OperatorNameData,

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

#include "BluetoothDriverImpl.hpp"


@@ 83,8 83,10 @@ namespace bluetooth
        hci_event_callback_registration.callback = &hci_packet_handler;
        hci_add_event_handler(&hci_event_callback_registration);

        gap_ssp_set_io_capability(SSP_IO_CAPABILITY_KEYBOARD_ONLY);
        gap_ssp_set_io_capability(SSP_IO_CAPABILITY_DISPLAY_YES_NO);
        gap_ssp_set_auto_accept(false);

        gap_set_class_of_device(0x64020C);
        LOG_DEBUG("BT worker run success");
        return Error::Success;
    }

M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.cpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.cpp +0 -44
@@ 94,49 94,10 @@ namespace bluetooth
        pimpl->stop();
    }

    auto A2DP::startRinging() const noexcept -> Error::Code
    {
        LOG_ERROR("Can't ring in A2DP profile");
        return Error::SystemError;
    }

    auto A2DP::stopRinging() const noexcept -> Error::Code
    {
        return Error::SystemError;
    }

    auto A2DP::initializeCall() const noexcept -> Error::Code
    {
        return Error::SystemError;
    }

    void A2DP::setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> audioDevice)
    {
        pimpl->setAudioDevice(std::move(audioDevice));
    }
    auto A2DP::callAnswered() const noexcept -> Error::Code
    {
        return Error::SystemError;
    }
    auto A2DP::setIncomingCallNumber(const std::string &num) const noexcept -> Error::Code
    {
        LOG_INFO("Setting number in A2DP - ignoring");
        return Error::Success;
    }
    auto A2DP::setSignalStrength(int bars) const noexcept -> Error::Code
    {
        LOG_INFO("Setting signal bars in A2DP - ignoring");
        return Error::Success;
    }
    auto A2DP::setOperatorName(const std::string_view &name) const noexcept -> Error::Code
    {
        LOG_INFO("Setting operator name in A2DP - ignoring");
        return Error::Success;
    }
    auto A2DP::setBatteryLevel(const BatteryLevel &level) const noexcept -> Error::Code
    {
        return Error::Success;
    }

    const sys::Service *A2DP::A2DPImpl::ownerService;
    QueueHandle_t A2DP::A2DPImpl::sourceQueue = nullptr;


@@ 222,11 183,6 @@ namespace bluetooth
            LOG_ERROR("Can't register service. Status %x", status);
        }

        // Set local name with a template Bluetooth address, that will be automatically
        // replaced with a actual address once it is available, i.e. when BTstack boots
        // up and starts talking to a Bluetooth module.
        gap_set_class_of_device(0x200408);

        // Register for HCI events.
        hciEventCallbackRegistration.callback = &hciPacketHandler;
        hci_add_event_handler(&hciEventCallbackRegistration);

M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.hpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.hpp +1 -18
@@ 11,7 11,7 @@

namespace bluetooth
{
    class A2DP : public Profile
    class A2DP : public MusicProfile
    {
      public:
        A2DP();


@@ 30,23 30,6 @@ namespace bluetooth
        void disconnect() override;
        void start() override;
        void stop() override;
        /// @return SystemError - it's not posible to start ringing while there's A2DP active
        [[nodiscard]] auto startRinging() const noexcept -> Error::Code override;
        /// @return SystemError - it's not posible to stop ringing while there's A2DP active
        [[nodiscard]] auto stopRinging() const noexcept -> Error::Code override;
        /// @return SystemError - it's not posible to start routing while there's A2DP active
        [[nodiscard]] auto initializeCall() const noexcept -> Error::Code override;
        /// @return SystemError - it's not posible to handle call answered while there's A2DP active
        [[nodiscard]] auto callAnswered() const noexcept -> Error::Code override;
        /// @return Success - ignoring in A2DP
        [[nodiscard]] auto setIncomingCallNumber(const std::string &num) const noexcept -> Error::Code override;
        /// @return Success - ignoring in A2DP
        [[nodiscard]] auto setSignalStrength(int bars) const noexcept -> Error::Code override;
        /// @return Success - ignoring in A2DP
        [[nodiscard]] auto setOperatorName(const std::string_view &name) const noexcept -> Error::Code override;
        /// @return Success - ignoring in A2DP
        [[nodiscard]] auto setBatteryLevel(const BatteryLevel &level) const noexcept -> Error::Code override;

        void setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> audioDevice) override;

      private:

M module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.cpp => module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.cpp +2 -1
@@ 226,7 226,8 @@ namespace bluetooth
    void GAP::activeStateHandler(std::uint8_t eventType, std::uint8_t *packet, std::uint16_t size)
    {
        if (not(eventType == HCI_EVENT_TRANSPORT_PACKET_SENT || eventType == HCI_EVENT_COMMAND_STATUS ||
                eventType == HCI_EVENT_INQUIRY_COMPLETE || eventType == HCI_EVENT_COMMAND_COMPLETE)) {
                eventType == HCI_EVENT_INQUIRY_COMPLETE || eventType == HCI_EVENT_COMMAND_COMPLETE ||
                eventType == HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS)) {
            LOG_DEBUG("event: 0x%02X - %s - size: %" PRIu16, eventType, evt_cstr(eventType), size);
        }
        switch (eventType) {

M module-bluetooth/Bluetooth/interface/profiles/HFP/HFP.cpp => module-bluetooth/Bluetooth/interface/profiles/HFP/HFP.cpp +22 -23
@@ 66,16 66,6 @@ namespace bluetooth
    {
        pimpl->disconnect();
    }

    void HFP::start()
    {
        pimpl->start();
    }

    void HFP::stop()
    {
        pimpl->stop();
    }
    auto HFP::startRinging() const noexcept -> Error::Code
    {
        pimpl->startRinging();


@@ 91,6 81,11 @@ namespace bluetooth
        pimpl->initializeCall();
        return Error::Success;
    }
    auto HFP::terminateCall() const noexcept -> Error::Code
    {
        pimpl->terminateCall();
        return Error::Success;
    }
    void HFP::setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> audioDevice)
    {
        pimpl->setAudioDevice(audioDevice);


@@ 217,6 212,9 @@ namespace bluetooth
            if (audioDevice != nullptr) {
                audioDevice->onDataSend(scoHandle);
            }
            else {
                LOG_DEBUG("Audiodevice nullptr :(");
            }
            break;
        case HCI_EVENT_HFP_META:
            processHFPEvent(event);


@@ 285,6 283,7 @@ namespace bluetooth
                LOG_DEBUG("Audio connection established with SCO handle 0x%04x.\n", scoHandle);
                codec = static_cast<SCOCodec>(hfp_subevent_audio_connection_established_get_negotiated_codec(event));
                dump_supported_codecs();
                audioInterface->startAudioRouting(const_cast<sys::Service *>(ownerService));
                hci_request_sco_can_send_now_event();
                RunLoop::trigger();
            }


@@ 292,6 291,7 @@ namespace bluetooth
        case HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED:
            LOG_DEBUG("Audio connection released");
            scoHandle = HCI_CON_HANDLE_INVALID;
            audioInterface->stopAudioRouting(const_cast<sys::Service *>(ownerService));
            audioDevice.reset();
            break;
        case HFP_SUBEVENT_START_RINGING:


@@ 304,6 304,8 @@ namespace bluetooth
            break;
        case HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER:
            break;
        case HFP_SUBEVENT_RING:
            break;

        case HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG:
            // todo has to be feeded with proper phone number from cellular


@@ 351,7 353,7 @@ namespace bluetooth

        serviceBuffer.fill(0);
        constexpr std::uint32_t hspSdpRecordHandle = 0x10004;
        uint16_t supported_features                = (1 << HFP_AGSF_ESCO_S4) /*| (1 << HFP_AGSF_HF_INDICATORS) */ |
        uint16_t supported_features                = (1 << HFP_AGSF_ESCO_S4) | /* (1 << HFP_AGSF_HF_INDICATORS) | */
                                      (1 << HFP_AGSF_CODEC_NEGOTIATION) | (1 << HFP_AGSF_EXTENDED_ERROR_RESULT_CODES) |
                                      (1 << HFP_AGSF_ENHANCED_CALL_CONTROL) | (1 << HFP_AGSF_ENHANCED_CALL_STATUS) |
                                      (1 << HFP_AGSF_ABILITY_TO_REJECT_A_CALL) /*| (1 << HFP_AGSF_IN_BAND_RING_TONE) |*/


@@ 397,6 399,8 @@ namespace bluetooth
        }
        LOG_DEBUG("Connecting the HFP profile");
        hfp_ag_establish_service_level_connection(device.address);
        hfp_ag_set_speaker_gain(aclHandle, 8);
        hfp_ag_set_microphone_gain(aclHandle, 10);
    }

    void HFP::HFPImpl::disconnect()


@@ 422,18 426,10 @@ namespace bluetooth
        return sco->getStreamData();
    }

    void HFP::HFPImpl::start()
    {
        if (!isConnected) {
            connect();
        }
        hfp_ag_set_speaker_gain(aclHandle, 8);
        hfp_ag_set_microphone_gain(aclHandle, 10);
    }

    void HFP::HFPImpl::stop()
    void HFP::HFPImpl::terminateCall() const noexcept
    {
        hfp_ag_terminate_call();
        hfp_ag_release_audio_connection(aclHandle);
        isCallInitialized = false;
        isIncomingCall    = false;
    }


@@ 470,6 466,7 @@ namespace bluetooth
    {
        HFP::HFPImpl::audioDevice = std::static_pointer_cast<CVSDAudioDevice>(audioDevice);
        HFP::HFPImpl::audioDevice->setAclHandle(aclHandle);
        LOG_DEBUG("Audiodevice set!");
    }
    void HFP::HFPImpl::startRinging() const noexcept
    {


@@ 492,13 489,15 @@ namespace bluetooth
            audioInterface->startAudioRouting(const_cast<sys::Service *>(ownerService));
            hfp_ag_outgoing_call_established();
        }
        LOG_DEBUG("Establishing HFP audio connection");
        hfp_ag_establish_audio_connection(aclHandle);

        return Error::Success;
    }
    auto HFP::HFPImpl::setIncomingCallNumber(const std::string &num) const noexcept -> Error::Code
    {
        if (!isIncomingCall) {
            isIncomingCall = true;
            hfp_ag_incoming_call();
        }
        hfp_ag_set_clip(129, num.c_str());
        return Error::Success;
    }

M module-bluetooth/Bluetooth/interface/profiles/HFP/HFP.hpp => module-bluetooth/Bluetooth/interface/profiles/HFP/HFP.hpp +2 -3
@@ 12,7 12,7 @@
namespace bluetooth
{

    class HFP : public Profile
    class HFP : public CallProfile
    {
        // static constexpr auto CLASS_OF_DEVICE = 0x400204;
        // Service class: Telephony, Major device class: Phone, Minor device class: Cellular


@@ 31,8 31,6 @@ namespace bluetooth

        void connect() override;
        void disconnect() override;
        void start() override;
        void stop() override;
        /// @brief Starts ring
        /// @return Success
        [[nodiscard]] auto startRinging() const noexcept -> Error::Code override;


@@ 44,6 42,7 @@ namespace bluetooth
        /// - SCO link establishment
        /// @return Success
        [[nodiscard]] auto initializeCall() const noexcept -> Error::Code override;
        [[nodiscard]] auto terminateCall() const noexcept -> Error::Code override;
        [[nodiscard]] auto callAnswered() const noexcept -> Error::Code override;
        [[nodiscard]] auto setIncomingCallNumber(const std::string &num) const noexcept -> Error::Code override;
        /// @brief Sets the signal strength bars data

M module-bluetooth/Bluetooth/interface/profiles/HFP/HFPImpl.hpp => module-bluetooth/Bluetooth/interface/profiles/HFP/HFPImpl.hpp +1 -2
@@ 17,11 17,10 @@ namespace bluetooth
      public:
        static void packetHandler(uint8_t packetType, uint16_t channel, uint8_t *event, uint16_t eventSize);
        auto init() -> Error::Code;
        void start();
        void stop();
        void startRinging() const noexcept;
        void stopRinging() const noexcept;
        void initializeCall() const noexcept;
        void terminateCall() const noexcept;
        void connect();
        void disconnect();
        void setDevice(Devicei device);

M module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.cpp => module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.cpp +11 -22
@@ 69,16 69,6 @@ namespace bluetooth
        pimpl->disconnect();
    }

    void HSP::start()
    {
        pimpl->start();
    }

    void HSP::stop()
    {
        pimpl->stop();
    }

    auto HSP::startRinging() const noexcept -> Error::Code
    {
        pimpl->startRinging();


@@ 336,18 326,6 @@ namespace bluetooth
    {
        return sco->getStreamData();
    }
    void HSP::HSPImpl::start()
    {
        if (!isConnected) {
            connect();
        }
    }
    void HSP::HSPImpl::stop()
    {
        stopRinging();
        hsp_ag_release_audio_connection();
        callAnswered = false;
    }

    void HSP::HSPImpl::startRinging() const noexcept
    {


@@ 393,9 371,20 @@ namespace bluetooth
    {
        return Error::Success;
    }
    auto HSP::terminateCall() const noexcept -> Error::Code
    {
        return pimpl->terminateCall();
    }

    void HSP::HSPImpl::setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> audioDevice)
    {
        HSP::HSPImpl::audioDevice = std::static_pointer_cast<CVSDAudioDevice>(audioDevice);
    }
    auto HSP::HSPImpl::terminateCall() const noexcept -> Error::Code
    {
        stopRinging();
        hsp_ag_release_audio_connection();
        callAnswered = false;
        return Error::Success;
    }
} // namespace bluetooth

M module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.hpp => module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.hpp +2 -3
@@ 10,7 10,7 @@

namespace bluetooth
{
    class HSP : public Profile
    class HSP : public CallProfile
    {
        static constexpr auto CLASS_OF_DEVICE = 0x400204;
        // Service class: Telephony, Major device class: Phone, Minor device class: Cellular


@@ 29,8 29,6 @@ namespace bluetooth

        void connect() override;
        void disconnect() override;
        void start() override;
        void stop() override;
        /// @brief Starts ring
        /// @return Success
        [[nodiscard]] auto startRinging() const noexcept -> Error::Code override;


@@ 42,6 40,7 @@ namespace bluetooth
        /// - SCO link establishment
        /// @return Success
        [[nodiscard]] auto initializeCall() const noexcept -> Error::Code override;
        [[nodiscard]] auto terminateCall() const noexcept -> Error::Code override;
        [[nodiscard]] auto callAnswered() const noexcept -> Error::Code override;
        [[nodiscard]] auto setIncomingCallNumber(const std::string &num) const noexcept -> Error::Code override;
        /// @return Success - ignoring in HSP

M module-bluetooth/Bluetooth/interface/profiles/HSP/HSPImpl.hpp => module-bluetooth/Bluetooth/interface/profiles/HSP/HSPImpl.hpp +2 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 17,11 17,10 @@ namespace bluetooth
      public:
        static void packetHandler(uint8_t packetType, uint16_t channel, uint8_t *event, uint16_t eventSize);
        auto init() -> Error::Code;
        void start();
        void stop();
        void startRinging() const noexcept;
        void stopRinging() const noexcept;
        void initializeCall() const noexcept;
        auto terminateCall() const noexcept -> Error::Code;
        void connect();
        void disconnect();
        void setDevice(const Devicei &dev);

M module-bluetooth/Bluetooth/interface/profiles/PhoneInterface.cpp => module-bluetooth/Bluetooth/interface/profiles/PhoneInterface.cpp +4 -0
@@ 21,4 21,8 @@ namespace bluetooth
    {
        return AudioServiceAPI::RoutingStart(service);
    }
    bool AudioInterfaceImpl::stopAudioRouting(sys::Service *service)
    {
        return AudioServiceAPI::StopAll(service);
    }
} // namespace bluetooth

M module-bluetooth/Bluetooth/interface/profiles/PhoneInterface.hpp => module-bluetooth/Bluetooth/interface/profiles/PhoneInterface.hpp +2 -0
@@ 27,10 27,12 @@ namespace bluetooth
      public:
        virtual ~AudioInterface()                             = default;
        virtual bool startAudioRouting(sys::Service *service) = 0;
        virtual bool stopAudioRouting(sys::Service *service)  = 0;
    };
    class AudioInterfaceImpl : public AudioInterface
    {
      public:
        bool startAudioRouting(sys::Service *service) override;
        bool stopAudioRouting(sys::Service *service) override;
    };
} // namespace bluetooth

M module-bluetooth/Bluetooth/interface/profiles/Profile.hpp => module-bluetooth/Bluetooth/interface/profiles/Profile.hpp +23 -12
@@ 21,12 21,28 @@ namespace bluetooth
        virtual void setDevice(const Devicei &device)                                             = 0;
        virtual void setOwnerService(const sys::Service *service)                                 = 0;
        virtual void connect()                                                                    = 0;
        virtual void start()                                                                      = 0;
        virtual void stop()                                                                       = 0;
        virtual void disconnect()                                                                 = 0;
        virtual void setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> audioDevice) = 0;
        /// Starts ringing
        /// @return Error code that determines, whether operation was successful or not

      protected:
        static void initSdp();
        static void initL2cap();

      private:
        static bool isL2CapInitialized;
        static bool isSdpInitialized;
    };

    class MusicProfile : public Profile
    {
      public:
        virtual void start() = 0;
        virtual void stop()  = 0;
    };

    class CallProfile : public Profile
    {
      public:
        [[nodiscard]] virtual auto startRinging() const noexcept -> Error::Code = 0;
        /// Stops ringing
        /// @return Error code that determines, whether operation was successful or not


@@ 34,6 50,9 @@ namespace bluetooth
        /// Initializes call
        /// @return Error code that determines, whether operation was successful or not
        [[nodiscard]] virtual auto initializeCall() const noexcept -> Error::Code = 0;
        /// Terminates call
        /// @return Error code that determines, whether operation was successful or not
        [[nodiscard]] virtual auto terminateCall() const noexcept -> Error::Code = 0;
        /// Executed after the call is answered
        /// @return Error code that determines, whether operation was successful or not
        [[nodiscard]] virtual auto callAnswered() const noexcept -> Error::Code = 0;


@@ 49,14 68,6 @@ namespace bluetooth
        /// Sets the operator name in HFP profile
        /// @return Error code that determines, whether operation was successful or not
        [[nodiscard]] virtual auto setBatteryLevel(const BatteryLevel &level) const noexcept -> Error::Code = 0;

      protected:
        static void initSdp();
        static void initL2cap();

      private:
        static bool isL2CapInitialized;
        static bool isSdpInitialized;
    };

} // namespace bluetooth

M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.cpp => module-bluetooth/Bluetooth/interface/profiles/ProfileManager.cpp +24 -38
@@ 25,11 25,9 @@ namespace bluetooth
                    ptr->init();
                }
            }
            // TODO profile selection based on capabilities and priority?
            // audio & capa cell & HSP & HFP  & A2DP-> HFP
            // audio & capa cell & HSP  & A2DP-> HSP
            // audio & HSP & HFP & A2DP -> A2DP
            currentProfilePtr = profilesList[AudioProfile::A2DP].get();

            musicProfilePtr = dynamic_cast<MusicProfile *>(profilesList[AudioProfile::A2DP].get());
            callProfilePtr  = dynamic_cast<CallProfile *>(profilesList[AudioProfile::HFP].get());

            if (auto serviceBt = dynamic_cast<ServiceBluetooth *>(ownerService); serviceBt != nullptr) {
                serviceBt->profileManagerPtr = this;


@@ 60,70 58,58 @@ namespace bluetooth
        return Error::Success;
    }

    auto ProfileManager::switchProfile(AudioProfile profile) -> Error::Code
    {
        if (profilesList[profile] == nullptr) {
            LOG_ERROR("Invalid profile!");
            return Error::SystemError;
        }
        if (currentProfilePtr == profilesList[profile].get()) {
            return Error::Success;
        }
        stop();
        currentProfilePtr = profilesList[profile].get();
        start();
        return Error::Success;
    }

    auto ProfileManager::start() -> Error::Code
    {
        currentProfilePtr->start();
        musicProfilePtr->start();
        return Error::Success;
    }

    auto ProfileManager::stop() -> Error::Code
    {
        currentProfilePtr->stop();
        musicProfilePtr->stop();
        return Error::Success;
    }

    auto ProfileManager::startRinging() -> Error::Code
    {
        switchProfile(AudioProfile::HFP);
        return currentProfilePtr->startRinging();
        return callProfilePtr->startRinging();
    }

    auto ProfileManager::stopRinging() -> Error::Code
    {
        return currentProfilePtr->stopRinging();
        return callProfilePtr->stopRinging();
    }

    auto ProfileManager::initializeCall() -> Error::Code
    {
        switchProfile(AudioProfile::HFP);
        return currentProfilePtr->initializeCall();
        return callProfilePtr->initializeCall();
    }
    auto ProfileManager::terminateCall() -> Error::Code
    {
        return callProfilePtr->terminateCall();
    }

    auto ProfileManager::setAudioDevice(std::shared_ptr<BluetoothAudioDevice> device) -> Error::Code
    {
        auto profileType = device->getProfileType();

        if (currentProfilePtr == nullptr || profilesList[profileType] == nullptr) {
        if (profilesList[profileType] == nullptr) {
            return Error::NotReady;
        }

        profilesList[profileType]->setAudioDevice(device);
        return switchProfile(profileType);
        LOG_ERROR("AudioDevice for profile: %s set!", magic_enum::enum_name(profileType).data());
        return Error::Success;
    }
    auto ProfileManager::callAnswered() -> Error::Code
    {
        return currentProfilePtr->callAnswered();
        return callProfilePtr->callAnswered();
    }
    auto ProfileManager::setIncomingCallNumber(const DataVariant &data) -> Error::Code
    {
        auto number = std::get<utils::PhoneNumber::View>(data);
        if (currentProfilePtr) {
            return currentProfilePtr->setIncomingCallNumber(number.getE164());
        if (callProfilePtr) {
            return callProfilePtr->setIncomingCallNumber(number.getE164());
        }
        LOG_ERROR("No profile, returning!");
        return Error::NotReady;


@@ 131,8 117,8 @@ namespace bluetooth
    auto ProfileManager::setSignalStrengthData(const DataVariant &data) -> Error::Code
    {
        auto signalData = std::get<Store::SignalStrength>(data);
        if (currentProfilePtr) {
            return currentProfilePtr->setSignalStrength(static_cast<int>(signalData.rssiBar));
        if (callProfilePtr) {
            return callProfilePtr->setSignalStrength(static_cast<int>(signalData.rssiBar));
        }
        LOG_ERROR("No profile, returning!");
        return Error::NotReady;


@@ 140,8 126,8 @@ namespace bluetooth
    auto ProfileManager::setOperatorNameData(const DataVariant &data) -> Error::Code
    {
        auto operatorName = std::get<OperatorName>(data);
        if (currentProfilePtr) {
            return currentProfilePtr->setOperatorName(operatorName.getName());
        if (callProfilePtr) {
            return callProfilePtr->setOperatorName(operatorName.getName());
        }
        LOG_ERROR("No profile, returning!");
        return Error::NotReady;


@@ 149,8 135,8 @@ namespace bluetooth
    auto ProfileManager::setBatteryLevelData(const DataVariant &data) -> Error::Code
    {
        auto batteryLevel = std::get<BatteryLevel>(data);
        if (currentProfilePtr) {
            return currentProfilePtr->setBatteryLevel(batteryLevel);
        if (callProfilePtr) {
            return callProfilePtr->setBatteryLevel(batteryLevel);
        }
        LOG_ERROR("No profile, returning!");
        return Error::NotReady;

M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp => module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp +3 -7
@@ 32,30 32,26 @@ namespace bluetooth
        explicit ProfileManager(sys::Service *ownerService);

        auto init() -> Error::Code;

        auto connect(const Devicei &device) -> Error::Code;

        auto disconnect() -> Error::Code;

        auto switchProfile(AudioProfile profile) -> Error::Code;

        auto start() -> Error::Code;
        auto stop() -> Error::Code;
        auto startRinging() -> Error::Code;
        auto stopRinging() -> Error::Code;
        auto initializeCall() -> Error::Code;
        auto terminateCall() -> Error::Code;
        auto callAnswered() -> Error::Code;
        auto setIncomingCallNumber(const DataVariant &data) -> Error::Code;
        auto setSignalStrengthData(const DataVariant &data) -> Error::Code;
        auto setOperatorNameData(const DataVariant &data) -> Error::Code;
        auto setBatteryLevelData(const DataVariant &data) -> Error::Code;

        auto setAudioDevice(std::shared_ptr<BluetoothAudioDevice> device) -> Error::Code;

      private:
        sys::Service *ownerService;
        ProfileList profilesList;
        bluetooth::Profile *currentProfilePtr = nullptr;
        bluetooth::MusicProfile *musicProfilePtr = nullptr;
        bluetooth::CallProfile *callProfilePtr   = nullptr;
        bool initialized = false;
    };
} // namespace bluetooth

M module-bluetooth/lib/btstack => module-bluetooth/lib/btstack +1 -1
@@ 1,1 1,1 @@
Subproject commit 6a217e2cc9aa1a4d900f3a26af8c934c980ae145
Subproject commit 49c8d45475aa9cad1b853df2c10883ce037161cb

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

    if (opType == Operation::Type::Playback) {
        auto input = audioMux.GetPlaybackInput(playbackType);
        if (playbackType == audio::PlaybackType::CallRingtone && bluetoothVoiceProfileConnected && input &&
            (*input)->audio->GetPriorityPlaybackProfile() == Profile::Type::PlaybackBluetoothA2DP) {
        if (playbackType == audio::PlaybackType::CallRingtone && bluetoothVoiceProfileConnected && input) {
            LOG_DEBUG("Sending Bluetooth start ringing");
            bus.sendUnicast(std::make_shared<message::bluetooth::Ring>(message::bluetooth::Ring::State::Enable),
                            service::name::bluetooth);


@@ 448,10 447,6 @@ std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleStart(const Operation:
    }
    else if (opType == Operation::Type::Router) {
        auto input = audioMux.GetRoutingInput(true);
        if (bluetoothVoiceProfileConnected) {
            LOG_DEBUG("Sending Bluetooth start routing");
            bus.sendUnicast(std::make_shared<message::bluetooth::StartAudioRouting>(), service::name::bluetooth);
        }
        AudioStart(input);
        return std::make_unique<AudioStartRoutingResponse>(retCode, retToken);
    }


@@ 527,7 522,7 @@ std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleStop(const std::vector
    }

    // stop bluetooth stream if available
    if (bluetoothA2DPConnected || bluetoothVoiceProfileConnected) {
    if (bluetoothA2DPConnected) {
        LOG_DEBUG("Sending Bluetooth stop request");
        bus.sendUnicast(std::make_shared<BluetoothMessage>(BluetoothMessage::Request::Stop), service::name::bluetooth);
    }

M module-services/service-bluetooth/ServiceBluetooth.cpp => module-services/service-bluetooth/ServiceBluetooth.cpp +7 -3
@@ 118,6 118,7 @@ sys::ReturnCodes ServiceBluetooth::InitHandler()
    connectHandler<message::bluetooth::RequestStatusIndicatorData>();
    connectHandler<CellularCallerIdMessage>();
    connectHandler<CellularCallActiveNotification>();
    connectHandler<cellular::CallEndedNotification>();
    connectHandler<CellularSignalStrengthUpdateNotification>();
    connectHandler<CellularCurrentOperatorNameNotification>();
    connectHandler<sevm::BatteryStatusChangeMessage>();


@@ 419,9 420,6 @@ auto ServiceBluetooth::handle(BluetoothMessage *msg) -> std::shared_ptr<sys::Mes
    case BluetoothMessage::Play:
        sendWorkerCommand(bluetooth::Command::Type::StartStream);
        break;
    case BluetoothMessage::SwitchProfile:
        sendWorkerCommand(bluetooth::Command::Type::SwitchProfile);
        break;
    case BluetoothMessage::Disconnect:
        sendWorkerCommand(bluetooth::Command::Type::DisconnectAudio);
        break;


@@ 472,6 470,7 @@ auto ServiceBluetooth::handle(message::bluetooth::HFPVolume *msg) -> std::shared

auto ServiceBluetooth::handle(message::bluetooth::Ring *msg) -> std::shared_ptr<sys::Message>
{
    LOG_DEBUG("Start ringing from audio");
    const auto enableRing = msg->enabled();
    sendWorkerCommand(enableRing ? bluetooth::Command::Type::StartRinging : bluetooth::Command::Type::StopRinging);



@@ 570,3 569,8 @@ auto ServiceBluetooth::handle(sevm::BatteryStatusChangeMessage *msg) -> std::sha
    sendWorkerCommand(bluetooth::Command::Type::BatteryLevelData, std::move(commandData));
    return sys::MessageNone{};
}
auto ServiceBluetooth::handle(cellular::CallEndedNotification *msg) -> std::shared_ptr<sys::Message>
{
    sendWorkerCommand(bluetooth::Command::Type::CallTerminated);
    return sys::MessageNone{};
}

M module-services/service-bluetooth/service-bluetooth/BluetoothMessage.hpp => module-services/service-bluetooth/service-bluetooth/BluetoothMessage.hpp +0 -1
@@ 37,7 37,6 @@ class BluetoothMessage : public sys::DataMessage
        getDevicesAvailable,
        Visible,
        Play,
        SwitchProfile,
        Stop,
        Disconnect
    };

M module-services/service-bluetooth/service-bluetooth/ServiceBluetooth.hpp => module-services/service-bluetooth/service-bluetooth/ServiceBluetooth.hpp +5 -0
@@ 67,6 67,10 @@ class CellularCallerIdMessage;
class CellularCallActiveNotification;
class CellularSignalStrengthUpdateNotification;
class CellularCurrentOperatorNameNotification;
namespace cellular
{
    class CallEndedNotification;
}

class ServiceBluetooth : public sys::Service
{


@@ 129,6 133,7 @@ class ServiceBluetooth : public sys::Service
    [[nodiscard]] auto handle(message::bluetooth::RequestStatusIndicatorData *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(CellularCallerIdMessage *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(CellularCallActiveNotification *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(cellular::CallEndedNotification *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(CellularSignalStrengthUpdateNotification *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(CellularCurrentOperatorNameNotification *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(sevm::BatteryStatusChangeMessage *msg) -> std::shared_ptr<sys::Message>;

M module-utils/log/Logger.cpp => module-utils/log/Logger.cpp +0 -1
@@ 40,7 40,6 @@ namespace Log
            {CRIT_STR, logger_level::LOGTRACE},
            {IRQ_STR, logger_level::LOGTRACE},
            {"FileIndexer", logger_level::LOGINFO},
            {"ServiceAudio", logger_level::LOGERROR},
            {"EventManager", logger_level::LOGINFO}
        };
    }