~aleteoryx/muditaos

6d61aabbec9efe5725f9bcb8ba7a5c2d0724adb0 — Jakub Pyszczak 4 years ago f6b6cd9
[EGD-6514] HSP volume control

Bluetooth headset profile volume control
introduced. Small refactor on A2DP volume control
done.
M module-audio/Audio/VolumeScaler.cpp => module-audio/Audio/VolumeScaler.cpp +47 -11
@@ 5,20 5,56 @@

namespace audio::volume::scaler
{
    Volume toSystemVolume(std::uint8_t avrcpVolume) noexcept
    namespace
    {
        constexpr auto avrcpMaxVolume = float{0x7F}; // from AVRCP documentation
        const auto systemVolume       = (avrcpVolume / avrcpMaxVolume) * audio::maxVolume;
        // prevents conversion to 0 while in fact sound is not muted
        if (systemVolume > 0.01f && systemVolume < 1.0f) {
            return 1;
        /// @brief Takes volume level from bluetooth profile and converts it to according one for the system.
        /// @param profileVolume - Bluetooth profile volume level.
        /// @param profileMaxVolume - Bluetooth profile max volume level.
        /// @return Volume level scaled to satisfy system's range [audio::minVolume, audio::maxVolume].
        Volume btProfileToSystemVolume(std::uint8_t profileVolume, float profileMaxVolume) noexcept
        {
            const auto systemVolume = (profileVolume / profileMaxVolume) * audio::maxVolume;
            // prevents conversion to 0 while in fact sound is not muted
            if (systemVolume > 0.01f && systemVolume < 1.0f) {
                return 1;
            }
            return systemVolume;
        }
        return systemVolume;
    }

    std::uint8_t toAvrcpVolume(float systemVolume) noexcept
        /// @brief Takes volume level and converts it to according one for the bluetooth profile.
        /// @param systemVolume - system volume level.
        /// @param profileMaxVolume - bluetooth profile max volume level.
        /// @return Volume level scaled to satisfy bluetooth profile range [0, profileMaxVolume].
        std::uint8_t systemToBtProfileVolume(float systemVolume, std::uint8_t profileMaxVolume) noexcept
        {
            return std::round(systemVolume * profileMaxVolume / audio::maxVolume);
        }
    } // namespace
    namespace a2dp
    {
        constexpr auto avrcpMaxVolume = std::uint8_t{0x7F}; // from AVRCP documentation
        return std::round(systemVolume * avrcpMaxVolume / audio::maxVolume);
    }

        Volume toSystemVolume(std::uint8_t avrcpVolume) noexcept
        {
            return btProfileToSystemVolume(avrcpVolume, static_cast<float>(avrcpMaxVolume));
        }

        std::uint8_t toAvrcpVolume(float systemVolume) noexcept
        {
            return systemToBtProfileVolume(systemVolume, avrcpMaxVolume);
        }
    } // namespace a2dp
    namespace hsp
    {
        constexpr auto hspMaxVolume = float{0x0F}; // from HSP documentation

        Volume toSystemVolume(std::uint8_t hspSpeakerGain) noexcept
        {
            return btProfileToSystemVolume(hspSpeakerGain, static_cast<float>(hspMaxVolume));
        }
        std::uint8_t toHSPGain(float systemVolume) noexcept
        {
            return systemToBtProfileVolume(systemVolume, hspMaxVolume);
        }
    } // namespace hsp
} // namespace audio::volume::scaler

M module-audio/Audio/VolumeScaler.hpp => module-audio/Audio/VolumeScaler.hpp +23 -8
@@ 7,12 7,27 @@
/// @brief Converts volume between system and bluetooth ranges.
namespace audio::volume::scaler
{
    /// @brief Takes volume level and converts it to according one for the system.
    /// @param avrcpVolume - AVRCP volume level.
    /// @return Volume level scaled to satisfy system's range [audio::minVolume, audio::maxVolume].
    Volume toSystemVolume(std::uint8_t avrcpVolume) noexcept;
    /// @brief Takes volume level and converts it to according one for the AVRCP.
    /// @param systemVolume - system volume level.
    /// @return Volume level scaled to satisfy AVRCP's range [0, 127].
    std::uint8_t toAvrcpVolume(float systemVolume) noexcept;
    namespace a2dp
    {
        /// @brief Takes volume level and converts it to according one for the system.
        /// @param avrcpVolume - AVRCP volume level.
        /// @return Volume level scaled to satisfy system's range [audio::minVolume, audio::maxVolume].
        Volume toSystemVolume(std::uint8_t avrcpVolume) noexcept;
        /// @brief Takes volume level and converts it to according one for the AVRCP.
        /// @param systemVolume - system volume level.
        /// @return Volume level scaled to satisfy AVRCP's range [0, 127].
        std::uint8_t toAvrcpVolume(float systemVolume) noexcept;

    } // namespace a2dp
    namespace hsp
    {
        /// @brief Takes volume level and converts it to according one for the system.
        /// @param hspSpeakerGain - HSP speaker gain.
        /// @return Volume level scaled to satisfy system's range [audio::minVolume, audio::maxVolume].
        Volume toSystemVolume(std::uint8_t hspSpeakerGain) noexcept;
        /// @brief Takes volume level and converts it to according one for the HSP speaker gain.
        /// @param systemVolume - system volume level.
        /// @return Volume level scaled to satisfy HSP's range [0, 15].
        std::uint8_t toHSPGain(float systemVolume) noexcept;
    } // namespace hsp
} // namespace audio::volume::scaler

M module-audio/Audio/test/unittest_scaler.cpp => module-audio/Audio/test/unittest_scaler.cpp +74 -10
@@ 15,49 15,49 @@ SCENARIO("Scale volume levels between system and bluetooth")
        {
            THEN("System volume is set to 10")
            {
                REQUIRE(audio::volume::scaler::toSystemVolume(127) == 10);
                REQUIRE(audio::volume::scaler::a2dp::toSystemVolume(127) == 10);
            }
        }
        WHEN("Volume is 100")
        {
            THEN("System volume is set to 7")
            {
                REQUIRE(audio::volume::scaler::toSystemVolume(100) == 7);
                REQUIRE(audio::volume::scaler::a2dp::toSystemVolume(100) == 7);
            }
        }
        WHEN("Volume is 89")
        {
            THEN("System volume is set to 7")
            {
                REQUIRE(audio::volume::scaler::toSystemVolume(89) == 7);
                REQUIRE(audio::volume::scaler::a2dp::toSystemVolume(89) == 7);
            }
        }
        WHEN("Volume is 88")
        {
            THEN("System volume is set to 6")
            {
                REQUIRE(audio::volume::scaler::toSystemVolume(88) == 6);
                REQUIRE(audio::volume::scaler::a2dp::toSystemVolume(88) == 6);
            }
        }
        WHEN("Volume is 13")
        {
            THEN("System volume is set to 1")
            {
                REQUIRE(audio::volume::scaler::toSystemVolume(13) == 1);
                REQUIRE(audio::volume::scaler::a2dp::toSystemVolume(13) == 1);
            }
        }
        WHEN("Volume is 12")
        {
            THEN("System volume is set to 1")
            {
                REQUIRE(audio::volume::scaler::toSystemVolume(12) == 1);
                REQUIRE(audio::volume::scaler::a2dp::toSystemVolume(12) == 1);
            }
        }
        WHEN("Volume is 0")
        {
            THEN("System volume is set to 0")
            {
                REQUIRE(audio::volume::scaler::toSystemVolume(0) == 0);
                REQUIRE(audio::volume::scaler::a2dp::toSystemVolume(0) == 0);
            }
        }
    }


@@ 68,21 68,85 @@ SCENARIO("Scale volume levels between system and bluetooth")
        {
            THEN("AVRCP volume is 127")
            {
                REQUIRE(audio::volume::scaler::toAvrcpVolume(10) == std::uint8_t{127});
                REQUIRE(audio::volume::scaler::a2dp::toAvrcpVolume(10) == std::uint8_t{127});
            }
            THEN("HSP speaker gain is 15")
            {
                REQUIRE(audio::volume::scaler::hsp::toHSPGain(10) == std::uint8_t{15});
            }
        }
        WHEN("System volume is set to 7")
        {
            THEN("AVRCP volume is 89")
            {
                REQUIRE(audio::volume::scaler::toAvrcpVolume(7) == std::uint8_t{89});
                REQUIRE(audio::volume::scaler::a2dp::toAvrcpVolume(7) == std::uint8_t{89});
            }
            THEN("HSP speaker gain is 7")
            {
                REQUIRE(audio::volume::scaler::hsp::toHSPGain(7) == std::uint8_t{11});
            }
        }
        WHEN("System volume is set to 1")
        {
            THEN("AVRCP volume is 13")
            {
                REQUIRE(audio::volume::scaler::toAvrcpVolume(1) == std::uint8_t{13});
                REQUIRE(audio::volume::scaler::a2dp::toAvrcpVolume(1) == std::uint8_t{13});
            }
            THEN("HSP speaker gain is 2")
            {
                REQUIRE(audio::volume::scaler::hsp::toHSPGain(1) == std::uint8_t{2});
            }
        }
    }
    GIVEN("HSP speaker gain")
    {
        WHEN("Gain is 15")
        {
            THEN("System volume is set to 10")
            {
                REQUIRE(audio::volume::scaler::hsp::toSystemVolume(15) == 10);
            }
        }
        WHEN("Gain is 12")
        {
            THEN("System volume is set to 8")
            {
                REQUIRE(audio::volume::scaler::hsp::toSystemVolume(12) == 8);
            }
        }
        WHEN("Gain is 10")
        {
            THEN("System volume is set to 6")
            {
                REQUIRE(audio::volume::scaler::hsp::toSystemVolume(10) == 6);
            }
        }
        WHEN("Gain is 7")
        {
            THEN("System volume is set to 4")
            {
                REQUIRE(audio::volume::scaler::hsp::toSystemVolume(7) == 4);
            }
        }
        WHEN("Gain is 3")
        {
            THEN("System volume is set to 2")
            {
                REQUIRE(audio::volume::scaler::hsp::toSystemVolume(3) == 2);
            }
        }
        WHEN("Gain is 1")
        {
            THEN("System volume is set to 1")
            {
                REQUIRE(audio::volume::scaler::hsp::toSystemVolume(1) == 1);
            }
        }
        WHEN("Volume is 0")
        {
            THEN("System volume is set to 0")
            {
                REQUIRE(audio::volume::scaler::hsp::toSystemVolume(0) == 0);
            }
        }
    }

M module-bluetooth/Bluetooth/audio/BluetoothAudioDevice.cpp => module-bluetooth/Bluetooth/audio/BluetoothAudioDevice.cpp +23 -13
@@ 34,19 34,6 @@ auto BluetoothAudioDevice::getProfileType() const -> AudioProfile
    return profile;
}

auto BluetoothAudioDevice::setOutputVolume(float vol) -> audio::AudioDevice::RetCode
{
    const auto volumeToSet = audio::volume::scaler::toAvrcpVolume(vol);
    const auto status      = avrcp_controller_set_absolute_volume(AVRCP::mediaTracker.avrcp_cid, volumeToSet);
    if (status != ERROR_CODE_SUCCESS) {
        LOG_ERROR("Can't set volume level. Status %x", status);
        return audio::AudioDevice::RetCode::Failure;
    }

    outputVolume = vol;
    return audio::AudioDevice::RetCode::Success;
}

auto BluetoothAudioDevice::setInputGain(float gain) -> audio::AudioDevice::RetCode
{
    return audio::AudioDevice::RetCode::Success;


@@ 62,6 49,19 @@ auto BluetoothAudioDevice::isOutputEnabled() const -> bool
    return outputEnabled;
}

auto A2DPAudioDevice::setOutputVolume(float vol) -> audio::AudioDevice::RetCode
{
    const auto volumeToSet = audio::volume::scaler::a2dp::toAvrcpVolume(vol);
    const auto status      = avrcp_controller_set_absolute_volume(AVRCP::mediaTracker.avrcp_cid, volumeToSet);
    if (status != ERROR_CODE_SUCCESS) {
        LOG_ERROR("Can't set volume level. Status %x", status);
        return audio::AudioDevice::RetCode::Failure;
    }

    outputVolume = vol;
    return audio::AudioDevice::RetCode::Success;
}

void A2DPAudioDevice::onDataSend()
{
    if (isOutputEnabled()) {


@@ 72,6 72,16 @@ void A2DPAudioDevice::onDataSend()
void A2DPAudioDevice::onDataReceive()
{}

auto HSPAudioDevice::setOutputVolume(float vol) -> audio::AudioDevice::RetCode
{
    const auto volumeToSet = audio::volume::scaler::hsp::toHSPGain(vol);
    hsp_ag_set_speaker_gain(volumeToSet);

    LOG_DEBUG("Volume to be set %d", volumeToSet);
    outputVolume = vol;
    return audio::AudioDevice::RetCode::Success;
}

void HSPAudioDevice::onDataSend()
{}


M module-bluetooth/Bluetooth/audio/BluetoothAudioDevice.hpp => module-bluetooth/Bluetooth/audio/BluetoothAudioDevice.hpp +3 -2
@@ 25,7 25,6 @@ namespace bluetooth

        virtual auto getProfileType() const -> AudioProfile;

        auto setOutputVolume(float vol) -> audio::AudioDevice::RetCode override;
        auto setInputGain(float gain) -> audio::AudioDevice::RetCode override;

        // Endpoint control methods


@@ 38,12 37,12 @@ namespace bluetooth
        auto isInputEnabled() const -> bool;
        auto isOutputEnabled() const -> bool;
        auto fillSbcAudioBuffer() -> int;
        float outputVolume;

      private:
        bool outputEnabled   = false;
        bool inputEnabled    = false;
        AudioProfile profile = AudioProfile::None;
        float outputVolume;
    };

    class A2DPAudioDevice : public BluetoothAudioDevice


@@ 52,6 51,7 @@ namespace bluetooth
        explicit A2DPAudioDevice() : BluetoothAudioDevice(AudioProfile::A2DP)
        {}

        auto setOutputVolume(float vol) -> audio::AudioDevice::RetCode override;
        void onDataSend() override;
        void onDataReceive() override;
        auto getSupportedFormats() -> std::vector<audio::AudioFormat> override;


@@ 65,6 65,7 @@ namespace bluetooth
        explicit HSPAudioDevice() : BluetoothAudioDevice(AudioProfile::HSP)
        {}

        auto setOutputVolume(float vol) -> audio::AudioDevice::RetCode override;
        void onDataSend() override;
        void onDataSend(std::uint16_t scoHandle);
        void onDataReceive() override;

M module-bluetooth/Bluetooth/interface/profiles/A2DP/AVRCP.cpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/AVRCP.cpp +1 -1
@@ 166,7 166,7 @@ namespace bluetooth
        case AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED: {
            const auto volume = avrcp_subevent_notification_volume_changed_get_absolute_volume(packet);
            auto &busProxy    = AVRCP::ownerService->bus;
            busProxy.sendUnicast(std::make_shared<message::bluetooth::AudioVolume>(volume), service::name::bluetooth);
            busProxy.sendUnicast(std::make_shared<message::bluetooth::A2DPVolume>(volume), service::name::bluetooth);
            LOG_INFO("AVRCP Controller: notification absolute volume changed %d %%\n", volume * 100 / 127);
        } break;
        case AVRCP_SUBEVENT_GET_CAPABILITY_EVENT_ID:

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

#include <log/log.hpp>
#include "HSPImpl.hpp"
#include "HSP.hpp"

#include <Bluetooth/Error.hpp>
#include <log.hpp>
#include <service-evtmgr/Constants.hpp>
#include <BluetoothWorker.hpp>
#include <service-audio/AudioMessage.hpp>
#include <service-bluetooth/Constants.hpp>
#include <service-bluetooth/messages/AudioVolume.hpp>
#include <service-cellular/service-cellular/CellularServiceAPI.hpp>
#include <BluetoothWorker.hpp>
#include <service-evtmgr/Constants.hpp>

extern "C"
{


@@ 202,9 205,12 @@ namespace bluetooth
        case HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED:
            LOG_DEBUG("Received microphone gain change %d\n", hsp_subevent_microphone_gain_changed_get_gain(event));
            break;
        case HSP_SUBEVENT_SPEAKER_GAIN_CHANGED:
        case HSP_SUBEVENT_SPEAKER_GAIN_CHANGED: {
            const auto volume = hsp_subevent_speaker_gain_changed_get_gain(event);
            auto &busProxy    = const_cast<sys::Service *>(ownerService)->bus;
            busProxy.sendUnicast(std::make_shared<message::bluetooth::HSPVolume>(volume), service::name::bluetooth);
            LOG_DEBUG("Received speaker gain change %d\n", hsp_subevent_speaker_gain_changed_get_gain(event));
            break;
        } break;
        case HSP_SUBEVENT_HS_CALL_ANSWER:
            LOG_DEBUG("HSP CALL ANSWER");
            cellularInterface->answerIncomingCall(const_cast<sys::Service *>(ownerService));

M module-services/service-audio/AudioServiceAPI.cpp => module-services/service-audio/AudioServiceAPI.cpp +7 -2
@@ 219,8 219,13 @@ namespace AudioServiceAPI
        return serv->bus.sendUnicast(msg, service::name::audio);
    }

    bool BluetoothVolumeChanged(sys::Service *serv, const uint8_t volume)
    bool BluetoothA2DPVolumeChanged(sys::Service *serv, const std::uint8_t volume)
    {
        return serv->bus.sendUnicast(std::make_shared<BluetoothDeviceVolumeChanged>(volume), service::name::audio);
        return serv->bus.sendUnicast(std::make_shared<A2DPDeviceVolumeChanged>(volume), service::name::audio);
    }

    bool BluetoothHSPVolumeChanged(sys::Service *serv, const std::uint8_t volume)
    {
        return serv->bus.sendUnicast(std::make_shared<HSPDeviceVolumeChanged>(volume), service::name::audio);
    }
} // namespace AudioServiceAPI

M module-services/service-audio/ServiceAudio.cpp => module-services/service-audio/ServiceAudio.cpp +23 -5
@@ 99,8 99,10 @@ ServiceAudio::ServiceAudio()
    LOG_INFO("[ServiceAudio] Initializing");
    bus.channels.push_back(sys::BusChannel::ServiceAudioNotifications);

    connect(typeid(BluetoothDeviceVolumeChanged),
            [this](sys::Message *msg) -> sys::MessagePointer { return handleVolumeChangedOnBluetoothDevice(msg); });
    connect(typeid(A2DPDeviceVolumeChanged),
            [this](sys::Message *msg) -> sys::MessagePointer { return handleA2DPVolumeChangedOnBluetoothDevice(msg); });
    connect(typeid(HSPDeviceVolumeChanged),
            [this](sys::Message *msg) -> sys::MessagePointer { return handleHSPVolumeChangedOnBluetoothDevice(msg); });
}

ServiceAudio::~ServiceAudio()


@@ 740,14 742,30 @@ void ServiceAudio::settingsChanged(const std::string &name, std::string value)
    }
    LOG_ERROR("ServiceAudio::settingsChanged received notification about not registered setting: %s", name.c_str());
}
auto ServiceAudio::handleVolumeChangedOnBluetoothDevice(sys::Message *msgl) -> sys::MessagePointer

void ServiceAudio::onVolumeChanged(Volume volume)
{
    auto *msg                              = static_cast<BluetoothDeviceVolumeChanged *>(msgl);
    const auto volume                      = volume::scaler::toSystemVolume(msg->getVolume());
    const auto [profileType, playbackType] = getCurrentContext();
    settingsProvider->setValue(dbPath(Setting::Volume, playbackType, profileType), std::to_string(volume));
    settingsCache[dbPath(Setting::Volume, playbackType, profileType)] = std::to_string(volume);
    bus.sendMulticast(std::make_unique<VolumeChanged>(volume, std::make_pair(profileType, playbackType)),
                      sys::BusChannel::ServiceAudioNotifications);
}

auto ServiceAudio::handleA2DPVolumeChangedOnBluetoothDevice(sys::Message *msgl) -> sys::MessagePointer
{
    auto *a2dpMsg = dynamic_cast<A2DPDeviceVolumeChanged *>(msgl);
    assert(a2dpMsg != nullptr);
    const auto volume = volume::scaler::a2dp::toSystemVolume(a2dpMsg->getVolume());
    onVolumeChanged(volume);
    return sys::msgHandled();
}

auto ServiceAudio::handleHSPVolumeChangedOnBluetoothDevice(sys::Message *msgl) -> sys::MessagePointer
{
    auto *hspMsg = dynamic_cast<HSPDeviceVolumeChanged *>(msgl);
    assert(hspMsg != nullptr);
    const auto volume = volume::scaler::hsp::toSystemVolume(hspMsg->getVolume());
    onVolumeChanged(volume);
    return sys::msgHandled();
}

M module-services/service-audio/service-audio/AudioMessage.hpp => module-services/service-audio/service-audio/AudioMessage.hpp +14 -0
@@ 287,3 287,17 @@ class BluetoothDeviceVolumeChanged : public AudioMessage
  private:
    const std::uint8_t volume;
};

class A2DPDeviceVolumeChanged : public BluetoothDeviceVolumeChanged
{
  public:
    A2DPDeviceVolumeChanged(std::uint8_t volume) : BluetoothDeviceVolumeChanged{volume}
    {}
};

class HSPDeviceVolumeChanged : public BluetoothDeviceVolumeChanged
{
  public:
    HSPDeviceVolumeChanged(std::uint8_t volume) : BluetoothDeviceVolumeChanged{volume}
    {}
};

M module-services/service-audio/service-audio/AudioServiceAPI.hpp => module-services/service-audio/service-audio/AudioServiceAPI.hpp +10 -2
@@ 212,11 212,19 @@ namespace AudioServiceAPI
     */
    bool KeyPressed(sys::Service *serv, const int step);

    /** @brief Bluetooth volume changed handler.
    /** @brief Bluetooth A2DP volume changed handler.
     *
     * @param serv - requesting service.
     * @param volume - volume level
     * @return True if request has been sent successfully, false otherwise
     */
    bool BluetoothVolumeChanged(sys::Service *serv, const uint8_t volume);
    bool BluetoothA2DPVolumeChanged(sys::Service *serv, const std::uint8_t volume);

    /** @brief Bluetooth HSP volume changed handler.
     *
     * @param serv - requesting service.
     * @param volume - volume level
     * @return True if request has been sent successfully, false otherwise
     */
    bool BluetoothHSPVolumeChanged(sys::Service *serv, const std::uint8_t volume);
}; // namespace AudioServiceAPI

M module-services/service-audio/service-audio/ServiceAudio.hpp => module-services/service-audio/service-audio/ServiceAudio.hpp +3 -1
@@ 109,7 109,9 @@ class ServiceAudio : public sys::Service

    const audio::Context getCurrentContext();
    void settingsChanged(const std::string &name, std::string value);
    auto handleVolumeChangedOnBluetoothDevice(sys::Message *msgl) -> sys::MessagePointer;
    void onVolumeChanged(audio::Volume volume);
    auto handleA2DPVolumeChangedOnBluetoothDevice(sys::Message *msgl) -> sys::MessagePointer;
    auto handleHSPVolumeChangedOnBluetoothDevice(sys::Message *msgl) -> sys::MessagePointer;
};

namespace sys

M module-services/service-bluetooth/ServiceBluetooth.cpp => module-services/service-bluetooth/ServiceBluetooth.cpp +12 -3
@@ 82,7 82,8 @@ sys::ReturnCodes ServiceBluetooth::InitHandler()
    connectHandler<BluetoothAudioStartMessage>();
    connectHandler<BluetoothMessage>();
    connectHandler<BluetoothPairMessage>();
    connectHandler<message::bluetooth::AudioVolume>();
    connectHandler<message::bluetooth::A2DPVolume>();
    connectHandler<message::bluetooth::HSPVolume>();
    connectHandler<message::bluetooth::Ring>();
    connectHandler<message::bluetooth::StartAudioRouting>();
    connectHandler<message::bluetooth::Connect>();


@@ 343,9 344,17 @@ auto ServiceBluetooth::handle(sdesktop::developerMode::DeveloperModeRequest *msg
    return sys::MessageNone{};
}

auto ServiceBluetooth::handle(message::bluetooth::AudioVolume *msg) -> std::shared_ptr<sys::Message>
auto ServiceBluetooth::handle(message::bluetooth::A2DPVolume *msg) -> std::shared_ptr<sys::Message>
{
    AudioServiceAPI::BluetoothVolumeChanged(this, msg->getVolume());
    using namespace message::bluetooth;
    AudioServiceAPI::BluetoothA2DPVolumeChanged(this, msg->getVolume());
    return sys::MessageNone{};
}

auto ServiceBluetooth::handle(message::bluetooth::HSPVolume *msg) -> std::shared_ptr<sys::Message>
{
    using namespace message::bluetooth;
    AudioServiceAPI::BluetoothHSPVolumeChanged(this, msg->getVolume());
    return sys::MessageNone{};
}


M module-services/service-bluetooth/service-bluetooth/ServiceBluetooth.hpp => module-services/service-bluetooth/service-bluetooth/ServiceBluetooth.hpp +4 -2
@@ 48,7 48,8 @@ namespace message::bluetooth
    class ConnectResult;
    class Disconnect;
    class DisconnectResult;
    class AudioVolume;
    class A2DPVolume;
    class HSPVolume;
    class Ring;
    class StartAudioRouting;
} // namespace message::bluetooth


@@ 98,7 99,8 @@ class ServiceBluetooth : public sys::Service
    [[nodiscard]] auto handle(BluetoothAddrMessage *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(sdesktop::developerMode::DeveloperModeRequest *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(BluetoothAudioStartMessage *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(message::bluetooth::AudioVolume *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(message::bluetooth::A2DPVolume *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(message::bluetooth::HSPVolume *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(message::bluetooth::Ring *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(message::bluetooth::StartAudioRouting *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(message::bluetooth::ResponsePasskey *msg) -> std::shared_ptr<sys::Message>;

M module-services/service-bluetooth/service-bluetooth/messages/AudioVolume.hpp => module-services/service-bluetooth/service-bluetooth/messages/AudioVolume.hpp +13 -0
@@ 21,4 21,17 @@ namespace message::bluetooth
      private:
        const std::uint8_t volume;
    };

    class A2DPVolume : public AudioVolume
    {
      public:
        explicit A2DPVolume(std::uint8_t volume) : AudioVolume{volume}
        {}
    };
    class HSPVolume : public AudioVolume
    {
      public:
        explicit HSPVolume(std::uint8_t volume) : AudioVolume{volume}
        {}
    };
} // namespace message::bluetooth