~aleteoryx/muditaos

7b235b8f917dc53c6f4928870cc7b0a01146a341 — Lefucjusz 3 years ago b77af16
[MOS-647] Fix AVRCP volume control

Fix of the AVRCP volume control.
Minor code cleanup.
M module-bluetooth/Bluetooth/interface/profiles/A2DP/AVRCP.cpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/AVRCP.cpp +46 -35
@@ 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 "AVRCP.hpp"


@@ 10,28 10,28 @@

namespace bluetooth
{

    AVRCP::PlaybackStatusInfo AVRCP::playInfo;
    int AVRCP::currentTrackIndex;
    MediaContext AVRCP::mediaTracker;
    std::array<uint8_t, 200> AVRCP::sdpTargetServiceBuffer;
    std::array<uint8_t, 200> AVRCP::sdpControllerServiceBuffer;
    std::array<std::uint8_t, AVRCP::SDP_BUFFER_LENGTH> AVRCP::sdpTargetServiceBuffer;
    std::array<std::uint8_t, AVRCP::SDP_BUFFER_LENGTH> AVRCP::sdpControllerServiceBuffer;
    sys::Service *AVRCP::ownerService = nullptr;

    void AVRCP::packetHandler(uint8_t packetType, uint16_t channel, uint8_t *packet, uint16_t size)
    void AVRCP::packetHandler(uint8_t packetType,
                              [[maybe_unused]] uint16_t channel,
                              uint8_t *packet,
                              [[maybe_unused]] uint16_t size)
    {
        bd_addr_t event_addr;
        uint16_t local_cid;
        uint8_t status = ERROR_CODE_SUCCESS;
        std::uint16_t local_cid;
        std::uint8_t status = ERROR_CODE_SUCCESS;

        if (packetType != HCI_EVENT_PACKET) {
            return;
        }
        if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) {
        if (packetType != HCI_EVENT_PACKET || hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) {
            return;
        }

        switch (packet[2]) {
        const auto subevent_code = hci_event_avrcp_meta_get_subevent_code(packet);
        switch (subevent_code) {
        case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED:
            local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet);
            status    = avrcp_subevent_connection_established_get_status(packet);


@@ 46,13 46,15 @@ namespace bluetooth
            avrcp_target_support_event(AVRCP::mediaTracker.avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED);
            avrcp_target_support_event(AVRCP::mediaTracker.avrcp_cid,
                                       AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED);
            avrcp_controller_enable_notification(AVRCP::mediaTracker.avrcp_cid,
                                                 AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED);

            avrcp_target_set_now_playing_info(
                AVRCP::mediaTracker.avrcp_cid, NULL, sizeof(AVRCP::tracks) / sizeof(avrcp_track_t));
            avrcp_target_set_unit_info(AVRCP::mediaTracker.avrcp_cid, AVRCP_SUBUNIT_TYPE_AUDIO, AVRCP::companyId);
            avrcp_target_set_subunit_info(AVRCP::mediaTracker.avrcp_cid,
                                          AVRCP_SUBUNIT_TYPE_AUDIO,
                                          (uint8_t *)AVRCP::subunitInfo,
                                          static_cast<const std::uint8_t *>(AVRCP::subunitInfo),
                                          sizeof(AVRCP::subunitInfo));
            return;



@@ 66,7 68,7 @@ namespace bluetooth
        }

        if (status != ERROR_CODE_SUCCESS) {
            LOG_INFO("Responding to event 0x%02x failed with status 0x%02x\n", packet[2], status);
            LOG_INFO("Responding to event 0x%02x failed with status 0x%02x\n", subevent_code, status);
        }
    }



@@ 75,20 77,18 @@ namespace bluetooth
                                    uint8_t *packet,
                                    [[maybe_unused]] uint16_t size)
    {
        uint8_t status = ERROR_CODE_SUCCESS;
        std::uint8_t status = ERROR_CODE_SUCCESS;

        if (packetType != HCI_EVENT_PACKET) {
            return;
        }
        if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) {
        if (packetType != HCI_EVENT_PACKET || hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) {
            return;
        }

        switch (packet[2]) {
        const auto subevent_code = hci_event_avrcp_meta_get_subevent_code(packet);
        switch (subevent_code) {
        case AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED:
            AVRCP::mediaTracker.volume = avrcp_subevent_notification_volume_changed_get_absolute_volume(packet);
            LOG_INFO("AVRCP Target: Volume set to %d%% (%d)\n",
                     AVRCP::mediaTracker.volume * 127 / 100,
            LOG_INFO("AVRCP Target: Volume set to %u%% (%u)\n",
                     AVRCP::targetVolumeToPercent(AVRCP::mediaTracker.volume),
                     AVRCP::mediaTracker.volume);
            break;
        case AVRCP_SUBEVENT_PLAY_STATUS_QUERY:


@@ 98,7 98,8 @@ namespace bluetooth
                                              AVRCP::playInfo.status);
            break;
        case AVRCP_SUBEVENT_OPERATION: {
            auto operation_id = (avrcp_operation_id_t)avrcp_subevent_operation_get_operation_id(packet);
            const auto operation_id =
                static_cast<avrcp_operation_id_t>(avrcp_subevent_operation_get_operation_id(packet));
            switch (operation_id) {
            case AVRCP_OPERATION_ID_PLAY: {
                LOG_INFO("AVRCP Target: PLAY\n");


@@ 128,41 129,41 @@ namespace bluetooth
        }

        if (status != ERROR_CODE_SUCCESS) {
            LOG_INFO("Responding to event 0x%02x failed with status 0x%02x\n", packet[2], status);
            LOG_INFO("Responding to event 0x%02x failed with status 0x%02x\n", subevent_code, status);
        }
    }

    void AVRCP::controllerPacketHandler(uint8_t packetType,
                                        [[maybe_unused]] uint16_t channel,
                                        [[maybe_unused]] uint8_t *packet,
                                        uint16_t size)
                                        uint8_t *packet,
                                        [[maybe_unused]] uint16_t size)
    {
        uint8_t status = 0xFF;

        if (packetType != HCI_EVENT_PACKET) {
            return;
        }
        if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) {
        if (packetType != HCI_EVENT_PACKET || hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) {
            return;
        }

        status = packet[5];
        if (AVRCP::mediaTracker.avrcp_cid == 0u) {
            return;
        }

        const std::uint8_t status = packet[5];

        // ignore INTERIM status
        if (status == AVRCP_CTYPE_RESPONSE_INTERIM) {
            return;
        }

        switch (packet[2]) {
        const auto subevent_code = hci_event_avrcp_meta_get_subevent_code(packet);
        switch (subevent_code) {
        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::A2DPVolume>(volume), service::name::bluetooth);
            LOG_INFO("AVRCP Controller: notification absolute volume changed %d %%\n", volume * 100 / 127);
            LOG_INFO("AVRCP Controller: notification absolute volume changed %u%% (%u)\n",
                     AVRCP::controllerVolumeToPercent(volume),
                     volume);
        } break;

        case AVRCP_SUBEVENT_NOTIFICATION_EVENT_BATT_STATUS_CHANGED:
            // see avrcp_battery_status_t
            LOG_INFO("AVRCP Controller: Notification Battery Status %d\n",


@@ 191,4 192,14 @@ namespace bluetooth
        avrcp_controller_register_packet_handler(&controllerPacketHandler);
    }

    std::uint16_t AVRCP::targetVolumeToPercent(std::uint16_t volume)
    {
        return volume * 127 / 100;
    }

    std::uint16_t AVRCP::controllerVolumeToPercent(std::uint16_t volume)
    {
        return volume * 100 / 127;
    }

} // namespace bluetooth

M module-bluetooth/Bluetooth/interface/profiles/A2DP/AVRCP.hpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/AVRCP.hpp +10 -18
@@ 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


@@ 19,22 19,14 @@ namespace bluetooth
{
    class AVRCP
    {
      public:
        constexpr static const uint8_t subunitInfo[] = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
                                                        4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7};
        constexpr static uint32_t companyId          = 0x112233;
        constexpr static uint8_t companiesNum        = 1;
        constexpr static uint8_t companies[]         = {
            0x00, 0x19, 0x58 // BT SIG registered CompanyID
        };
      private:
        static std::uint16_t targetVolumeToPercent(std::uint16_t volume);
        static std::uint16_t controllerVolumeToPercent(std::uint16_t volume);

        constexpr static uint8_t eventsNum     = 6;
        constexpr static uint8_t events[]      = {AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED,
                                             AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED,
                                             AVRCP_NOTIFICATION_EVENT_PLAYER_APPLICATION_SETTING_CHANGED,
                                             AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED,
                                             AVRCP_NOTIFICATION_EVENT_AVAILABLE_PLAYERS_CHANGED,
                                             AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED};
      public:
        static constexpr uint8_t subunitInfo[] = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
                                                  4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7};
        static constexpr uint32_t companyId    = 0x112233;
        static constexpr int SDP_BUFFER_LENGTH = 200;
        struct PlaybackStatusInfo
        {


@@ 44,8 36,8 @@ namespace bluetooth
            uint32_t song_position_ms; // 0xFFFFFFFF if not supported
        };

        static std::array<uint8_t, SDP_BUFFER_LENGTH> sdpTargetServiceBuffer;
        static std::array<uint8_t, SDP_BUFFER_LENGTH> sdpControllerServiceBuffer;
        static std::array<std::uint8_t, SDP_BUFFER_LENGTH> sdpTargetServiceBuffer;
        static std::array<std::uint8_t, SDP_BUFFER_LENGTH> sdpControllerServiceBuffer;
        static sys::Service *ownerService;

        static avrcp_track_t tracks[3];