~aleteoryx/muditaos

d5f84437cab54acb9fc0b8f96deb6f5d46fed3de — Lefucjusz 3 years ago 2e38d0d
[MOS-92] Fix continuing music playback after BT disconnection

Fix of the issue that after disconnecting
BT A2DP device during music playback
and reconnecting it without leaving
music player app the sound was not
audible anywhere.
Additionally unified behaviour of music
playback on connection/disconnection
of audio devices.
M module-apps/application-music-player/include/application-music-player/ApplicationMusicPlayer.hpp => module-apps/application-music-player/include/application-music-player/ApplicationMusicPlayer.hpp +0 -1
@@ 6,7 6,6 @@
#include <Application.hpp>
#include <Audio/decoder/Decoder.hpp>
#include <purefs/filesystem_paths.hpp>
#include <atomic>

namespace gui
{

M module-audio/Audio/AudioCommon.cpp => module-audio/Audio/AudioCommon.cpp +2 -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 "AudioCommon.hpp"


@@ 12,7 12,7 @@ namespace audio
{
    audio::RetCode GetDeviceError(AudioDevice::RetCode retCode)
    {
        if (retCode == AudioDevice::RetCode::Success) {
        if (retCode != AudioDevice::RetCode::Failure) {
            return RetCode::Success;
        }


M module-audio/Audio/AudioDevice.hpp => module-audio/Audio/AudioDevice.hpp +2 -1
@@ 22,7 22,8 @@ namespace audio
        enum class RetCode
        {
            Success = 0,
            Failure
            Failure,
            Disconnected
        };

        enum class Type

M module-audio/Audio/Operation/PlaybackOperation.cpp => module-audio/Audio/Operation/PlaybackOperation.cpp +2 -3
@@ 15,10 15,9 @@ namespace audio
{

    using namespace AudioServiceMessage;
    using namespace utils;

    PlaybackOperation::PlaybackOperation(const char *file, const audio::PlaybackType &playbackType, Callback callback)
        : Operation(callback, playbackType), dec(nullptr)
        : Operation(std::move(callback), playbackType), dec(nullptr)
    {
        // order defines priority
        AddProfile(Profile::Type::PlaybackHeadphones, playbackType, false);


@@ 157,7 156,7 @@ namespace audio

    audio::RetCode PlaybackOperation::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:
            SetProfileAvailability({Profile::Type::PlaybackHeadphones}, isAvailable);

M module-audio/Audio/Operation/PlaybackOperation.hpp => module-audio/Audio/Operation/PlaybackOperation.hpp +1 -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

#pragma once


@@ 7,7 7,6 @@
#include "Audio/Stream.hpp"
#include "Audio/Endpoint.hpp"
#include "Audio/decoder/DecoderWorker.hpp"
#include "Audio/StreamQueuedEventsListener.hpp"
#include "Audio/decoder/Decoder.hpp"

#include <chrono>

M module-audio/Audio/Operation/RecorderOperation.cpp => module-audio/Audio/Operation/RecorderOperation.cpp +1 -6
@@ 1,23 1,18 @@
// 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 "RecorderOperation.hpp"

#include "Audio/AudioDevice.hpp"
#include "Audio/encoder/Encoder.hpp"
#include "Audio/Profiles/Profile.hpp"
#include "Audio/Profiles/ProfileRecordingHeadphones.hpp"
#include "Audio/Profiles/ProfileRecordingOnBoardMic.hpp"
#include "Audio/AudioCommon.hpp"

#include <log/log.hpp>
#include "FreeRTOS.h"
#include "task.h"

namespace audio
{
    using namespace AudioServiceMessage;
    using namespace utils;

#define PERF_STATS_ON 0


M module-audio/Audio/Operation/RecorderOperation.hpp => module-audio/Audio/Operation/RecorderOperation.hpp +1 -2
@@ 1,11 1,10 @@
// 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

#include "Operation.hpp"
#include <Audio/encoder/Encoder.hpp>
#include <Audio/AudioDevice.hpp>

namespace audio
{

M module-audio/Audio/decoder/DecoderWorker.cpp => module-audio/Audio/decoder/DecoderWorker.cpp +2 -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 "DecoderWorker.hpp"


@@ 10,7 10,7 @@ audio::DecoderWorker::DecoderWorker(audio::AbstractStream *audioStreamOut,
                                    EndOfFileCallback endOfFileCallback,
                                    ChannelMode mode)
    : sys::Worker(DecoderWorker::workerName, DecoderWorker::workerPriority, stackDepth), audioStreamOut(audioStreamOut),
      decoder(decoder), endOfFileCallback(endOfFileCallback),
      decoder(decoder), endOfFileCallback(std::move(endOfFileCallback)),
      bufferSize(audioStreamOut->getInputTraits().blockSize / sizeof(BufferInternalType)), channelMode(mode)
{}


M module-bluetooth/Bluetooth/audio/BluetoothAudioDevice.cpp => module-bluetooth/Bluetooth/audio/BluetoothAudioDevice.cpp +23 -6
@@ 159,7 159,7 @@ void CVSDAudioDevice::receiveCVSD(audio::AbstractStream::Span receivedData)
auto CVSDAudioDevice::decodeCVSD(audio::AbstractStream::Span dataToDecode) -> audio::AbstractStream::Span
{
    auto decodedData = dataToDecode;
    std::array<std::int16_t, scratchBufferSize> scratchBuffer;
    std::array<std::int16_t, scratchBufferSize> scratchBuffer{};

    const auto audioBytesRead = dataToDecode.dataSize - packetDataOffset;
    const auto samplesCount   = audioBytesRead / sizeof(std::int16_t);


@@ 293,16 293,33 @@ void CVSDAudioDevice::setAclHandle(hci_con_handle_t handle)
    aclHandle = handle;
}

audio::AudioDevice::RetCode A2DPAudioDevice::Pause()
audio::AudioDevice::RetCode A2DPAudioDevice::Start()
{
    return (a2dp_source_pause_stream(AVRCP::mediaTracker.a2dp_cid, AVRCP::mediaTracker.local_seid) == 0)
    return (a2dp_source_start_stream(AVRCP::mediaTracker.a2dp_cid, AVRCP::mediaTracker.local_seid) == 0)
               ? audio::AudioDevice::RetCode::Success
               : audio::AudioDevice::RetCode::Failure;
}

audio::AudioDevice::RetCode A2DPAudioDevice::Stop()
{
    const auto retCode = a2dp_source_pause_stream(AVRCP::mediaTracker.a2dp_cid, AVRCP::mediaTracker.local_seid);
    switch (retCode) {
    case ERROR_CODE_SUCCESS:
        return audio::AudioDevice::RetCode::Success;
    case ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER:
        return audio::AudioDevice::RetCode::Disconnected; // Device disconnected during playback, e.g. headphones
                                                          // discharged
    default:
        return audio::AudioDevice::RetCode::Failure;
    }
}

audio::AudioDevice::RetCode A2DPAudioDevice::Resume()
{
    return (a2dp_source_start_stream(AVRCP::mediaTracker.a2dp_cid, AVRCP::mediaTracker.local_seid) == 0)
               ? audio::AudioDevice::RetCode::Success
               : audio::AudioDevice::RetCode::Failure;
    return Start();
}

audio::AudioDevice::RetCode A2DPAudioDevice::Pause()
{
    return Stop();
}

M module-bluetooth/Bluetooth/audio/BluetoothAudioDevice.hpp => module-bluetooth/Bluetooth/audio/BluetoothAudioDevice.hpp +3 -1
@@ 60,8 60,10 @@ namespace bluetooth
        auto getTraits() const -> Traits override;
        auto getSourceFormat() -> ::audio::AudioFormat override;

        audio::AudioDevice::RetCode Pause() override;
        audio::AudioDevice::RetCode Start() override;
        audio::AudioDevice::RetCode Stop() override;
        audio::AudioDevice::RetCode Resume() override;
        audio::AudioDevice::RetCode Pause() override;
    };

    class CVSDAudioDevice : public BluetoothAudioDevice

M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.cpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.cpp +5 -5
@@ 480,7 480,7 @@ namespace bluetooth

            AVRCP::playInfo.status = AVRCP_PLAYBACK_STATUS_PLAYING;
            if (AVRCP::mediaTracker.avrcp_cid != 0u) {
                avrcp_target_set_playback_status(AVRCP::mediaTracker.avrcp_cid, AVRCP_PLAYBACK_STATUS_PLAYING);
                avrcp_target_set_playback_status(AVRCP::mediaTracker.avrcp_cid, AVRCP::playInfo.status);
            }
            startTimer(&AVRCP::mediaTracker);
            LOG_INFO(


@@ 504,7 504,7 @@ namespace bluetooth

            AVRCP::playInfo.status = AVRCP_PLAYBACK_STATUS_PAUSED;
            if (AVRCP::mediaTracker.avrcp_cid != 0u) {
                avrcp_target_set_playback_status(AVRCP::mediaTracker.avrcp_cid, AVRCP_PLAYBACK_STATUS_PAUSED);
                avrcp_target_set_playback_status(AVRCP::mediaTracker.avrcp_cid, AVRCP::playInfo.status);
            }
            LOG_INFO(
                "A2DP Source: Stream paused: a2dp_cid [expected 0x%02x, received 0x%02x], local_seid [expected %d, "


@@ 562,13 562,13 @@ namespace bluetooth
        if (isConnected) {
            disconnect();
        }
        LOG_INFO("Starting playback");
        LOG_INFO("Connecting A2DP profile");
        a2dp_source_establish_stream(device.address, &AVRCP::mediaTracker.a2dp_cid);
    }

    void A2DP::A2DPImpl::disconnect()
    {
        LOG_INFO("Stopping playback");
        LOG_INFO("Disonnecting A2DP profile");
        a2dp_source_disconnect(AVRCP::mediaTracker.a2dp_cid);
        auto &busProxy = const_cast<sys::Service *>(ownerService)->bus;
        busProxy.sendUnicast(std::make_shared<message::bluetooth::DisconnectResult>(device), service::name::bluetooth);


@@ 612,7 612,7 @@ namespace bluetooth
    }
    void A2DP::A2DPImpl::deInit()
    {
        LOG_DEBUG("[A2DP] deinit");
        LOG_DEBUG("Deinitializing A2DP profile");

        sdp_unregister_service(a2dpSdpRecordHandle);
        sdp_unregister_service(avrcpControllerSdpRecordHandle);

M module-bluetooth/Bluetooth/interface/profiles/A2DP/AVRCP.cpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/AVRCP.cpp +2 -0
@@ 57,6 57,8 @@ namespace bluetooth
                                          AVRCP_SUBUNIT_TYPE_AUDIO,
                                          static_cast<const std::uint8_t *>(AVRCP::subunitInfo),
                                          sizeof(AVRCP::subunitInfo));

            avrcp_target_set_playback_status(AVRCP::mediaTracker.avrcp_cid, AVRCP::playInfo.status);
            return;

        case AVRCP_SUBEVENT_CONNECTION_RELEASED:

M module-bluetooth/Bluetooth/interface/profiles/A2DP/AVRCP.hpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/AVRCP.hpp +1 -1
@@ 33,7 33,7 @@ namespace bluetooth
        {
            uint8_t track_id[8];
            uint32_t song_length_ms;
            avrcp_playback_status_t status;
            avrcp_playback_status_t status = AVRCP_PLAYBACK_STATUS_STOPPED;
            uint32_t song_position_ms; // 0xFFFFFFFF if not supported
        };


M module-services/service-audio/ServiceAudio.cpp => module-services/service-audio/ServiceAudio.cpp +39 -33
@@ 123,9 123,9 @@ ServiceAudio::ServiceAudio()
    connect(typeid(HFPDeviceVolumeChanged),
            [this](sys::Message *msg) -> sys::MessagePointer { return handleHFPVolumeChangedOnBluetoothDevice(msg); });
    connect(typeid(message::bluetooth::AudioPause),
            [this](sys::Message *msg) -> sys::MessagePointer { return handleA2DPAudioPause(); });
            [this](sys::Message *msg) -> sys::MessagePointer { return handleMultimediaAudioPause(); });
    connect(typeid(message::bluetooth::AudioStart),
            [this](sys::Message *msg) -> sys::MessagePointer { return handleA2DPAudioStart(); });
            [this](sys::Message *msg) -> sys::MessagePointer { return handleMultimediaAudioStart(); });
}

ServiceAudio::~ServiceAudio()


@@ 429,7 429,6 @@ std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleStart(const Operation:
        }

        if (bluetoothA2DPConnected && playbackType != audio::PlaybackType::CallRingtone) {
            LOG_DEBUG("Sending Bluetooth start stream request");
            bus.sendUnicast(std::make_shared<BluetoothMessage>(BluetoothMessage::Request::Play),
                            service::name::bluetooth);
        }


@@ 452,32 451,40 @@ std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleStart(const Operation:

std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleSendEvent(std::shared_ptr<Event> evt)
{
    // update bluetooth state
    if (evt->getType() == EventType::BlutoothA2DPDeviceState) {
        const auto newState = evt->getDeviceState() == Event::DeviceState::Connected;
        if (newState != bluetoothA2DPConnected) {
            LOG_DEBUG("Bluetooth connection status changed: %s", newState ? "connected" : "disconnected");
            bluetoothA2DPConnected = newState;
            const auto playbacksToBeStopped{
                (bluetoothA2DPConnected) ? std::vector<audio::PlaybackType>{audio::PlaybackType::Alarm,
                                                                            audio::PlaybackType::Meditation,
                                                                            audio::PlaybackType::Notifications,
                                                                            audio::PlaybackType::TextMessageRingtone}
                                         : std::vector<audio::PlaybackType>{audio::PlaybackType::Alarm,
                                                                            audio::PlaybackType::Meditation,
                                                                            audio::PlaybackType::Multimedia,
                                                                            audio::PlaybackType::Notifications,
                                                                            audio::PlaybackType::TextMessageRingtone}};
            HandleStop(playbacksToBeStopped, audio::Token());
    const auto eventType       = evt->getType();
    const auto deviceConnected = evt->getDeviceState() == audio::Event::DeviceState::Connected;

    switch (eventType) {
    case EventType::BlutoothA2DPDeviceState: {
        LOG_DEBUG("Bluetooth A2DP connection status changed: %s", deviceConnected ? "connected" : "disconnected");

        if (!deviceConnected) {
            handleMultimediaAudioPause();
        }
    }
    else if (evt->getType() == EventType::BlutoothHSPDeviceState ||
             evt->getType() == EventType::BlutoothHFPDeviceState) {
        auto newState = evt->getDeviceState() == Event::DeviceState::Connected;
        if (newState != bluetoothVoiceProfileConnected) {
            LOG_DEBUG("Bluetooth connection status changed: %s", newState ? "connected" : "disconnected");
            bluetoothVoiceProfileConnected = newState;

        const auto playbacksToBeStopped = std::vector<audio::PlaybackType>{audio::PlaybackType::Alarm,
                                                                           audio::PlaybackType::Meditation,
                                                                           audio::PlaybackType::Notifications,
                                                                           audio::PlaybackType::TextMessageRingtone};
        HandleStop(playbacksToBeStopped, audio::Token());
    } break;

    case EventType::BlutoothHSPDeviceState:
    case EventType::BlutoothHFPDeviceState: {
        if (deviceConnected != bluetoothVoiceProfileConnected) {
            LOG_DEBUG("Bluetooth voice connection status changed: %s", deviceConnected ? "connected" : "disconnected");
            bluetoothVoiceProfileConnected = deviceConnected;
        }
    } break;

    case EventType::JackState: {
        if (!deviceConnected) {
            handleMultimediaAudioPause();
        }
    } break;

    default:
        break;
    }

    // update information about endpoints availability


@@ 520,7 527,6 @@ std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleStop(const std::vector

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



@@ 647,14 653,13 @@ sys::MessagePointer ServiceAudio::DataReceivedHandler(sys::DataMessage *msgl, sy
    }
    else if (msgType == typeid(AudioStartPlaybackRequest)) {
        auto *msg   = static_cast<AudioStartPlaybackRequest *>(msgl);
        responseMsg = HandleStart(Operation::Type::Playback, msg->fileName.c_str(), msg->playbackType);
        responseMsg = HandleStart(Operation::Type::Playback, msg->fileName, msg->playbackType);
    }
    else if (msgType == typeid(AudioStartRecorderRequest)) {
        auto *msg   = static_cast<AudioStartRecorderRequest *>(msgl);
        responseMsg = HandleStart(Operation::Type::Recorder, msg->fileName.c_str());
        responseMsg = HandleStart(Operation::Type::Recorder, msg->fileName);
    }
    else if (msgType == typeid(AudioStartRoutingRequest)) {
        LOG_DEBUG("AudioRoutingStart");
        responseMsg = HandleStart(Operation::Type::Router);
    }
    else if (msgType == typeid(AudioPauseRequest)) {


@@ 870,7 875,8 @@ auto ServiceAudio::handleHFPVolumeChangedOnBluetoothDevice(sys::Message *msgl) -
    onVolumeChanged(volume, VolumeChangeRequestSource::HFP);
    return sys::msgHandled();
}
auto ServiceAudio::handleA2DPAudioPause() -> sys::MessagePointer

auto ServiceAudio::handleMultimediaAudioPause() -> sys::MessagePointer
{
    if (auto input = audioMux.GetPlaybackInput(audio::PlaybackType::Multimedia);
        input && (*input)->audio->Pause() == RetCode::Success) {


@@ 880,7 886,7 @@ auto ServiceAudio::handleA2DPAudioPause() -> sys::MessagePointer
    return sys::msgHandled();
}

auto ServiceAudio::handleA2DPAudioStart() -> sys::MessagePointer
auto ServiceAudio::handleMultimediaAudioStart() -> sys::MessagePointer
{
    if (auto input = audioMux.GetPlaybackInput(audio::PlaybackType::Multimedia);
        input && (*input)->audio->Resume() == RetCode::Success) {

M module-services/service-audio/include/service-audio/ServiceAudio.hpp => module-services/service-audio/include/service-audio/ServiceAudio.hpp +2 -4
@@ 8,8 8,6 @@

#include <Audio/Audio.hpp>
#include <Audio/AudioMux.hpp>
#include <MessageType.hpp>
#include <service-db/DBServiceAPI.hpp>
#include <service-db/DBServiceName.hpp>
#include <service-db/QueryMessage.hpp>
#include <Service/Service.hpp>


@@ 127,8 125,8 @@ class ServiceAudio : public sys::Service
    auto handleA2DPVolumeChangedOnBluetoothDevice(sys::Message *msgl) -> sys::MessagePointer;
    auto handleHSPVolumeChangedOnBluetoothDevice(sys::Message *msgl) -> sys::MessagePointer;
    auto handleHFPVolumeChangedOnBluetoothDevice(sys::Message *msgl) -> sys::MessagePointer;
    auto handleA2DPAudioPause() -> sys::MessagePointer;
    auto handleA2DPAudioStart() -> sys::MessagePointer;
    auto handleMultimediaAudioPause() -> sys::MessagePointer;
    auto handleMultimediaAudioStart() -> sys::MessagePointer;
};

namespace sys

M module-services/service-db/include/service-db/Settings.hpp => module-services/service-db/include/service-db/Settings.hpp +0 -3
@@ 7,14 7,11 @@
#include "SettingsScope.hpp"
#include "SettingsProxy.hpp"

#include <cstdint>
#include <functional>
#include <list>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <exception>

namespace settings
{

M pure_changelog.md => pure_changelog.md +1 -0
@@ 7,6 7,7 @@
* Separated system volume from Bluetooth device volume for A2DP

### Fixed
* Fixed music player behaviour when connecting/disconnecting audio devices
* Fixed dropping the call during the DND mode
* Fixed wrong tethering popup order
* Fixed crash during phone turn off