~aleteoryx/muditaos

01843fbadd954496538e66ca3b51efd450dad1c5 — Lefucjusz 2 years ago 9747ce2
[MOS-814] Fix no sound after BT device connection during call

Fix of the issue that connecting or
disconnecting BT device while call
was in progress resulted in no sound
being heard anywhere due to audio
routing being stopped when HFP device
disconnected.

Additionally minor code cleanup.
M module-apps/application-call/windows/CallWindow.cpp => module-apps/application-call/windows/CallWindow.cpp +2 -8
@@ 14,17 14,11 @@
#include <text/modes/InputMode.hpp>
#include <Label.hpp>
#include <log/log.hpp>
#include <magic_enum.hpp>
#include <Margins.hpp>
#include <service-appmgr/Controller.hpp>
#include <service-db/DBServiceAPI.hpp>
#include <time/time_conversion.hpp>

#include <cassert>
#include <functional>
#include <iomanip>
#include <memory>
#include <sstream>

namespace gui
{


@@ 82,7 76,7 @@ namespace gui
        microphoneIcon                    = new MicrophoneIcon(iconsBox);
        microphoneIcon->activatedCallback = [=](gui::Item &item) {
            microphoneIcon->setNext();
            LOG_INFO("Mic activated %d", static_cast<int>(microphoneIcon->get()));
            LOG_INFO("Microphone %s", static_cast<bool>(microphoneIcon->get()) ? "activated" : "deactivated");

            microphoneIcon->get() == MicrophoneIconState::MUTED ? presenter->muteCall() : presenter->unmuteCall();



@@ 92,7 86,7 @@ namespace gui
        speakerIcon                    = new SpeakerIcon(iconsBox);
        speakerIcon->activatedCallback = [=](gui::Item &item) {
            speakerIcon->setNext();
            LOG_INFO("Speaker activated %d", static_cast<int>(speakerIcon->get()));
            LOG_INFO("Speaker %s", static_cast<bool>(speakerIcon->get()) ? "activated" : "deactivated");

            switch (speakerIcon->get()) {
            case SpeakerIconState::SPEAKER: {

M module-audio/Audio/Operation/Operation.cpp => module-audio/Audio/Operation/Operation.cpp +5 -7
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "Operation.hpp"


@@ 47,12 47,10 @@ namespace audio
        auto ret = std::find_if(supportedProfiles.begin(), supportedProfiles.end(), [type](const auto &w) {
            return w.isAvailable && w.profile->GetType() == type;
        });
        if (ret == supportedProfiles.end()) {
            return nullptr;
        }
        else {
        if (ret != supportedProfiles.end()) {
            return ret->profile;
        }
        return nullptr;
    }

    std::optional<Profile::Type> Operation::GetPriorityProfile() const


@@ 81,12 79,12 @@ namespace audio
    void Operation::SetProfileAvailability(std::vector<Profile::Type> profiles, bool available)
    {
        for (auto &p : supportedProfiles) {
            if (auto shouldSet = (std::find(profiles.begin(), profiles.end(), p.profile->GetType()) != profiles.end());
                shouldSet) {
            if (std::find(profiles.begin(), profiles.end(), p.profile->GetType()) != profiles.end()) {
                p.isAvailable = available;
            }
        }
    }

    void Operation::AddProfile(const Profile::Type &profile, const PlaybackType &playback, bool isAvailable)
    {
        const auto reqVol  = AudioServiceMessage::DbRequest(Setting::Volume, playback, profile);

M module-audio/Audio/Operation/Operation.hpp => module-audio/Audio/Operation/Operation.hpp +2 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 51,7 51,7 @@ namespace audio
            case Type::Recorder:
                return "Recorder";
            case Type::Router:
                return "Router ";
                return "Router";
            }
            return "";
        }

M module-audio/Audio/Operation/RouterOperation.cpp => module-audio/Audio/Operation/RouterOperation.cpp +4 -10
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "RouterOperation.hpp"


@@ 8,14 8,8 @@
#include <Audio/Profiles/Profile.hpp>
#include <Audio/StreamFactory.hpp>
#include <Audio/transcode/TransformFactory.hpp>

#include <bsp/headset/headset.hpp>
#include <log/log.hpp>
#include <mutex.hpp>

#include <algorithm>
#include <optional>
#include <vector>

namespace audio
{


@@ 134,7 128,7 @@ namespace audio

    audio::RetCode RouterOperation::SendEvent(std::shared_ptr<Event> evt)
    {
        auto isAvailable = evt->getDeviceState() == Event::DeviceState::Connected ? true : false;
        const auto isAvailable = evt->getDeviceState() == Event::DeviceState::Connected;

        switch (evt->getType()) {
        case EventType::JackState:


@@ 184,8 178,8 @@ namespace audio

    audio::RetCode RouterOperation::SwitchProfile(const audio::Profile::Type type)
    {
        auto newProfile     = GetProfile(type);
        auto callInProgress = state == State::Active;
        const auto newProfile     = GetProfile(type);
        const auto callInProgress = state == State::Active;

        if (newProfile == nullptr) {
            return RetCode::UnsupportedProfile;

M module-audio/Audio/Operation/RouterOperation.hpp => module-audio/Audio/Operation/RouterOperation.hpp +1 -4
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 27,9 27,6 @@ namespace audio
{
    class RouterOperation : public Operation
    {
        using AudioCallback =
            std::function<std::int32_t(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer)>;
        static const std::size_t INPUT_BUFFER_START_SIZE = 1024;
        enum class Mute : bool
        {
            Enabled,

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

#include "BluetoothAudioDevice.hpp"


@@ 92,7 92,6 @@ void CVSDAudioDevice::onDataSend()
void CVSDAudioDevice::onDataSend(std::uint16_t scoHandle)
{
    if (!isOutputEnabled()) {
        LOG_WARN("Output is disabled");
        bluetooth::sco::utils::sendZeros(scoHandle);
        return;
    }


@@ 118,7 117,6 @@ void CVSDAudioDevice::onDataSend(std::uint16_t scoHandle)
void CVSDAudioDevice::receiveCVSD(audio::AbstractStream::Span receivedData)
{
    if (!isInputEnabled()) {
        LOG_DEBUG("Input is disabled");
        return;
    }


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

//


@@ 138,7 138,7 @@ namespace bluetooth
                                               AVDTP::sbcCodecConfiguration.data(),
                                               AVDTP::sbcCodecConfiguration.size());
        if (local_stream_endpoint == nullptr) {
            LOG_INFO("A2DP Source: not enough memory to create local stream endpoint\n");
            LOG_INFO("A2DP Source: not enough memory to create local stream endpoint");
            return bluetooth::Error::SystemError;
        }
        AVRCP::mediaTracker.local_seid = avdtp_local_seid(local_stream_endpoint);


@@ 307,7 307,7 @@ namespace bluetooth
            status = a2dp_subevent_signaling_connection_established_get_status(packet);

            if (status != ERROR_CODE_SUCCESS) {
                LOG_INFO("A2DP Source: Connection failed, status 0x%02x, cid 0x%02x, a2dp_cid 0x%02x \n",
                LOG_INFO("A2DP Source: Connection failed, status 0x%02x, cid 0x%02x, a2dp_cid 0x%02x ",
                         status,
                         cid,
                         AVRCP::mediaTracker.a2dp_cid);


@@ 321,7 321,7 @@ namespace bluetooth
            AVRCP::mediaTracker.a2dp_cid = cid;
            AVRCP::mediaTracker.volume   = 64;

            LOG_INFO("A2DP Source: Connected, a2dp cid 0x%02x, local seid %d.\n",
            LOG_INFO("A2DP Source: Connected, a2dp cid 0x%02x, local seid %d",
                     AVRCP::mediaTracker.a2dp_cid,
                     AVRCP::mediaTracker.local_seid);
            isConnected        = true;


@@ 356,7 356,7 @@ namespace bluetooth
            AVDTP::sbcConfig.maxBitpoolValue =
                a2dp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(packet);
            LOG_INFO("A2DP Source: Received SBC codec configuration, sampling frequency %u, a2dp_cid 0x%02x, local "
                     "seid 0x%02x, remote seid 0x%02x.\n",
                     "seid 0x%02x, remote seid 0x%02x",
                     AVDTP::sbcConfig.samplingFrequency,
                     cid,
                     AVRCP::mediaTracker.local_seid,


@@ 405,16 405,16 @@ namespace bluetooth
        }

        case A2DP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY:
            LOG_INFO("A2DP Source: remote supports delay report, remote seid %d\n",
            LOG_INFO("A2DP Source: remote supports delay report, remote seid %d",
                     avdtp_subevent_signaling_delay_reporting_capability_get_remote_seid(packet));
            break;
        case A2DP_SUBEVENT_SIGNALING_CAPABILITIES_DONE:
            LOG_INFO("A2DP Source: All capabilities reported, remote seid %d\n",
            LOG_INFO("A2DP Source: All capabilities reported, remote seid %d",
                     avdtp_subevent_signaling_capabilities_done_get_remote_seid(packet));
            break;

        case A2DP_SUBEVENT_SIGNALING_DELAY_REPORT:
            LOG_INFO("A2DP Source: Received delay report of %d.%0d ms, local seid %d\n",
            LOG_INFO("A2DP Source: Received delay report of %d.%0d ms, local seid %d",
                     avdtp_subevent_signaling_delay_report_get_delay_100us(packet) / 10,
                     avdtp_subevent_signaling_delay_report_get_delay_100us(packet) % 10,
                     avdtp_subevent_signaling_delay_report_get_local_seid(packet));


@@ 424,14 424,14 @@ namespace bluetooth
            a2dp_subevent_stream_established_get_bd_addr(packet, address);
            status = a2dp_subevent_stream_established_get_status(packet);
            if (status != 0u) {
                LOG_INFO("A2DP Source: Stream failed, status 0x%02x.\n", status);
                LOG_INFO("A2DP Source: Stream failed, status 0x%02x", status);
                break;
            }

            local_seid = a2dp_subevent_stream_established_get_local_seid(packet);
            cid        = a2dp_subevent_stream_established_get_a2dp_cid(packet);
            LOG_INFO("A2DP_SUBEVENT_STREAM_ESTABLISHED:  a2dp_cid [expected 0x%02x, received 0x%02x], local_seid %d "
                     "(expected %d), remote_seid %d (expected %d)\n",
                     "(expected %d), remote_seid %d (expected %d)",
                     AVRCP::mediaTracker.a2dp_cid,
                     cid,
                     local_seid,


@@ 440,12 440,12 @@ namespace bluetooth
                     AVRCP::mediaTracker.remote_seid);

            if (local_seid != AVRCP::mediaTracker.local_seid) {
                LOG_INFO("A2DP Source: Stream failed, wrong local seid %d, expected %d.\n",
                LOG_INFO("A2DP Source: Stream failed, wrong local seid %d, expected %d",
                         local_seid,
                         AVRCP::mediaTracker.local_seid);
                break;
            }
            LOG_INFO("A2DP Source: Stream established, a2dp cid 0x%02x, local seid %d, remote seid %d.\n",
            LOG_INFO("A2DP Source: Stream established, a2dp cid 0x%02x, local seid %d, remote seid %d",
                     AVRCP::mediaTracker.a2dp_cid,
                     AVRCP::mediaTracker.local_seid,
                     a2dp_subevent_stream_established_get_remote_seid(packet));


@@ 466,12 466,12 @@ namespace bluetooth
            cid        = a2dp_subevent_stream_reconfigured_get_a2dp_cid(packet);

            LOG_INFO("A2DP Source: Reconfigured: a2dp_cid [expected 0x%02x, received 0x%02x], local_seid [expected %d, "
                     "received %d]\n",
                     "received %d]",
                     AVRCP::mediaTracker.a2dp_cid,
                     cid,
                     AVRCP::mediaTracker.local_seid,
                     local_seid);
            LOG_INFO("Status 0x%02x\n", status);
            LOG_INFO("Status 0x%02x", status);
            break;

        case A2DP_SUBEVENT_STREAM_STARTED:


@@ 485,7 485,7 @@ namespace bluetooth
            startTimer(&AVRCP::mediaTracker);
            LOG_INFO(
                "A2DP Source: Stream started: a2dp_cid [expected 0x%02x, received 0x%02x], local_seid [expected %d, "
                "received %d]\n",
                "received %d]",
                AVRCP::mediaTracker.a2dp_cid,
                cid,
                AVRCP::mediaTracker.local_seid,


@@ 508,7 508,7 @@ namespace bluetooth
            }
            LOG_INFO(
                "A2DP Source: Stream paused: a2dp_cid [expected 0x%02x, received 0x%02x], local_seid [expected %d, "
                "received %d]\n",
                "received %d]",
                AVRCP::mediaTracker.a2dp_cid,
                cid,
                AVRCP::mediaTracker.local_seid,


@@ 523,7 523,7 @@ namespace bluetooth
            local_seid             = a2dp_subevent_stream_released_get_local_seid(packet);
            LOG_INFO(
                "A2DP Source: Stream released: a2dp_cid [expected 0x%02x, received 0x%02x], local_seid [expected %d, "
                "received %d]\n",
                "received %d]",
                AVRCP::mediaTracker.a2dp_cid,
                cid,
                AVRCP::mediaTracker.local_seid,


@@ 531,7 531,7 @@ namespace bluetooth
            sendAudioEvent(audio::EventType::BlutoothA2DPDeviceState, audio::Event::DeviceState::Disconnected);
            if (cid == AVRCP::mediaTracker.a2dp_cid) {
                AVRCP::mediaTracker.stream_opened = 0;
                LOG_INFO("A2DP Source: Stream released.\n");
                LOG_INFO("A2DP Source: Stream released");
            }
            if (AVRCP::mediaTracker.avrcp_cid != 0u) {



@@ 548,7 548,7 @@ namespace bluetooth
            if (cid == AVRCP::mediaTracker.a2dp_cid) {
                AVRCP::mediaTracker.avrcp_cid = 0;
                AVRCP::mediaTracker.a2dp_cid  = 0;
                LOG_INFO("A2DP Source: Signaling released.\n\n");
                LOG_INFO("A2DP Source: Signaling released");
            }
            isConnected = false;
            break;

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

#include "AVRCP.hpp"


@@ 36,7 36,7 @@ namespace bluetooth
            local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet);
            status    = avrcp_subevent_connection_established_get_status(packet);
            if (status != ERROR_CODE_SUCCESS) {
                LOG_INFO("AVRCP: Connection failed, local cid 0x%02x, status 0x%02x\n", local_cid, status);
                LOG_INFO("AVRCP: Connection failed, local cid 0x%02x, status 0x%02x", local_cid, status);
                return;
            }
            AVRCP::mediaTracker.avrcp_cid = local_cid;


@@ 62,7 62,7 @@ namespace bluetooth
            return;

        case AVRCP_SUBEVENT_CONNECTION_RELEASED:
            LOG_INFO("AVRCP Target: Disconnected, avrcp_cid 0x%02x\n",
            LOG_INFO("AVRCP Target: Disconnected, avrcp_cid 0x%02x",
                     avrcp_subevent_connection_released_get_avrcp_cid(packet));
            AVRCP::mediaTracker.avrcp_cid = 0;
            return;


@@ 71,7 71,7 @@ namespace bluetooth
        }

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



@@ 99,23 99,23 @@ namespace bluetooth
                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");
                LOG_INFO("AVRCP Target: PLAY");
                auto &busProxy = AVRCP::ownerService->bus;
                busProxy.sendUnicast(std::make_shared<message::bluetooth::AudioStart>(), service::name::audio);
                return;
            } break;
            case AVRCP_OPERATION_ID_PAUSE: {
                LOG_INFO("AVRCP Target: PAUSE\n");
                LOG_INFO("AVRCP Target: PAUSE");
                auto &busProxy = AVRCP::ownerService->bus;
                busProxy.sendUnicast(std::make_shared<message::bluetooth::AudioPause>(), service::name::audio);
                return;
            } break;
            case AVRCP_OPERATION_ID_STOP:
                LOG_INFO("AVRCP Target: STOP\n");
                LOG_INFO("AVRCP Target: STOP");
                status = a2dp_source_disconnect(AVRCP::mediaTracker.a2dp_cid);
                break;
            default:
                LOG_INFO("AVRCP Target: operation 0x%2x is not handled\n", operation_id);
                LOG_INFO("AVRCP Target: operation 0x%2x is not handled", operation_id);
                return;
            }
            break;


@@ 126,7 126,7 @@ namespace bluetooth
        }

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



@@ 150,18 150,18 @@ namespace bluetooth
            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: BT device volume changed to %u%% (%u)\n",
            LOG_INFO("AVRCP Controller: BT device volume changed to %u%% (%u)",
                     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",
            LOG_INFO("AVRCP Controller: Notification Battery Status %d",
                     avrcp_subevent_notification_event_batt_status_changed_get_battery_status(packet));
            break;
        case AVRCP_SUBEVENT_NOTIFICATION_STATE:
            LOG_INFO("AVRCP Controller: Notification %s - %s\n",
            LOG_INFO("AVRCP Controller: Notification %s - %s",
                     avrcp_event2str(avrcp_subevent_notification_state_get_event_id(packet)),
                     avrcp_subevent_notification_state_get_enabled(packet) != 0 ? "enabled" : "disabled");
            break;

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

#include "HFPImpl.hpp"


@@ 184,7 184,7 @@ namespace bluetooth
                LOG_DEBUG("mSBC");
            }
            else {
                LOG_WARN("mSBC codec disabled because eSCO not supported by local controller.\n");
                LOG_WARN("mSBC codec disabled because eSCO not supported by local controller.");
            }
            break;



@@ 247,13 247,13 @@ namespace bluetooth
            std::uint8_t status;
            status = hfp_subevent_service_level_connection_established_get_status(event);
            if (status) {
                LOG_DEBUG("Connection failed, status 0x%02x\n", status);
                LOG_DEBUG("Connection failed, status 0x%02x", status);
                sendAudioEvent(audio::EventType::BlutoothHFPDeviceState, audio::Event::DeviceState::Disconnected);
                break;
            }
            aclHandle = hfp_subevent_service_level_connection_established_get_acl_handle(event);
            hfp_subevent_service_level_connection_established_get_bd_addr(event, device.address);
            LOG_DEBUG("Service level connection established to %s.\n", bd_addr_to_str(device.address));
            LOG_DEBUG("Service level connection established to %s", bd_addr_to_str(device.address));
            sendAudioEvent(audio::EventType::BlutoothHFPDeviceState, audio::Event::DeviceState::Connected);
            {
                auto &busProxy     = const_cast<sys::Service *>(ownerService)->bus;


@@ 267,7 267,7 @@ namespace bluetooth
            dump_supported_codecs();
            break;
        case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED:
            LOG_DEBUG("Service level connection released.\n");
            LOG_DEBUG("Service level connection released");
            aclHandle = HCI_CON_HANDLE_INVALID;
            sendAudioEvent(audio::EventType::BlutoothHFPDeviceState, audio::Event::DeviceState::Disconnected);
            {


@@ 278,15 278,14 @@ namespace bluetooth
            break;
        case HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED:
            if (hfp_subevent_audio_connection_established_get_status(event)) {
                LOG_DEBUG("Audio connection establishment failed with status %u\n",
                LOG_DEBUG("Audio connection establishment failed with status %u",
                          hfp_subevent_audio_connection_established_get_status(event));
            }
            else {
                scoHandle = hfp_subevent_audio_connection_established_get_sco_handle(event);
                LOG_DEBUG("Audio connection established with SCO handle 0x%04x.\n", scoHandle);
                LOG_DEBUG("Audio connection established with SCO handle 0x%04x", 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();
            }


@@ 294,15 293,14 @@ 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:
            LOG_DEBUG("Start Ringing\n");
            LOG_DEBUG("Start Ringing");
            // todo request here ringtone stream
            break;
        case HFP_SUBEVENT_STOP_RINGING:
            LOG_DEBUG("Stop Ringing\n");
            LOG_DEBUG("Stop Ringing");
            // todo stop ringtone stream here
            break;
        case HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER: {


@@ 317,12 315,12 @@ namespace bluetooth
            break;
        case HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG:
            // todo has to be feeded with proper phone number from cellular
            // LOG_DEBUG("Attach number to voice tag. Sending '1234567\n");
            // LOG_DEBUG("Attach number to voice tag. Sending '1234567'");
            hfp_ag_send_phone_number_for_voice_tag(aclHandle, "1234567");
            break;
        case HFP_SUBEVENT_TRANSMIT_DTMF_CODES: {
            auto digitStr = hfp_subevent_transmit_dtmf_codes_get_dtmf(event);
            LOG_DEBUG("Send DTMF Codes: '%s'\n", digitStr);
            LOG_DEBUG("Send DTMF Codes: '%s'", digitStr);
            try {
                cellularInterface->sendDTMFCode(const_cast<sys::Service *>(ownerService), DTMFCode(digitStr));
            }


@@ 340,7 338,7 @@ namespace bluetooth
            const auto volume = hfp_subevent_speaker_volume_get_gain(event);
            auto &busProxy    = const_cast<sys::Service *>(ownerService)->bus;
            busProxy.sendUnicast(std::make_shared<message::bluetooth::HFPVolume>(volume), service::name::bluetooth);
            LOG_DEBUG("Received speaker gain change %d\n", hsp_subevent_speaker_gain_changed_get_gain(event));
            LOG_DEBUG("Received speaker gain change %d", hsp_subevent_speaker_gain_changed_get_gain(event));
        } break;

        case HFP_SUBEVENT_CALL_TERMINATED:


@@ 349,7 347,7 @@ namespace bluetooth
            currentCallStatus = CallStatus::Unknown;
            break;
        default:
            LOG_DEBUG("Event not handled %u\n", hci_event_hfp_meta_get_subevent_code(event));
            LOG_DEBUG("Event not handled %u", hci_event_hfp_meta_get_subevent_code(event));
            break;
        }
    }

M pure_changelog.md => pure_changelog.md +2 -1
@@ 28,6 28,8 @@
* Fixed inability to unblock SIM card when previously ejected during slot switching
* Fixed French translations for Ulock Screen
* Fixed crash when syncing with Mudita Center
* Fixed inactive alarms after timezone change and reboot.
* Fixed no sound when Bluetooth audio device connected/disconnected during call

### Added



@@ 261,7 263,6 @@
* Fixed problem with Music Player application crashing when trying to play files with unknown formats.
* Fixed problem with resuming music playback after connecting a headset.
* Fixed problem of battery discharging of phone without SIM card.
* Fixed inactive alarms after timezone change and reboot.

## [1.1.6 2022-01-20]