M module-audio/Audio/AudioDevice.hpp => module-audio/Audio/AudioDevice.hpp +2 -1
@@ 27,7 27,8 @@ namespace audio
None,
Audiocodec,
Cellular,
- Bluetooth
+ BluetoothA2DP,
+ BluetoothHSP
};
virtual ~AudioDevice() = default;
M module-audio/Audio/Profiles/ProfilePlaybackBluetoothA2DP.hpp => module-audio/Audio/Profiles/ProfilePlaybackBluetoothA2DP.hpp +1 -1
@@ 21,7 21,7 @@ namespace audio
.inputGain = 0,
.inputPath = audio::codec::InputPath::None,
.outputPath = audio::codec::OutputPath::None},
- AudioDevice::Type::Bluetooth)
+ AudioDevice::Type::BluetoothA2DP)
{}
};
M module-audio/Audio/Profiles/ProfileRecordingBluetoothHSP.hpp => module-audio/Audio/Profiles/ProfileRecordingBluetoothHSP.hpp +1 -1
@@ 23,7 23,7 @@ namespace audio
.inputGain = static_cast<float>(gain),
.inputPath = audio::codec::InputPath::None,
.outputPath = audio::codec::OutputPath::None},
- AudioDevice::Type::Bluetooth)
+ AudioDevice::Type::BluetoothHSP)
{}
};
M module-audio/Audio/Profiles/ProfileRoutingBluetoothHSP.hpp => module-audio/Audio/Profiles/ProfileRoutingBluetoothHSP.hpp +1 -1
@@ 23,7 23,7 @@ namespace audio
.inputGain = static_cast<float>(gain),
.inputPath = audio::codec::InputPath::None,
.outputPath = audio::codec::OutputPath::None},
- AudioDevice::Type::Bluetooth)
+ AudioDevice::Type::BluetoothHSP)
{}
};
M module-audio/Audio/transcode/InputTranscodeProxy.cpp => module-audio/Audio/transcode/InputTranscodeProxy.cpp +5 -0
@@ 23,6 23,11 @@ bool InputTranscodeProxy::push(const Span &span)
return getWrappedStream().push(transform->transform(span, transcodingSpaceSpan));
}
+bool InputTranscodeProxy::push(void *data, std::size_t dataSize)
+{
+ return push(Span{.data = reinterpret_cast<std::uint8_t *>(data), .dataSize = dataSize});
+}
+
void InputTranscodeProxy::commit()
{
if (isReserved) {
M module-audio/Audio/transcode/InputTranscodeProxy.hpp => module-audio/Audio/transcode/InputTranscodeProxy.hpp +1 -0
@@ 27,6 27,7 @@ namespace audio::transcode
std::shared_ptr<Transform> transform) noexcept;
bool push(const Span &span) override;
+ bool push(void *data, std::size_t dataSize);
void commit() override;
bool reserve(Span &span) override;
[[nodiscard]] auto getInputTraits() const noexcept -> Traits override;
M module-audio/board/rt1051/RT1051DeviceFactory.cpp => module-audio/board/rt1051/RT1051DeviceFactory.cpp +6 -2
@@ 21,8 21,12 @@ std::shared_ptr<AudioDevice> RT1051DeviceFactory::getDevice(const audio::Profile
device = std::make_shared<RT1051AudioCodec>(profile.GetAudioConfiguration());
} break;
- case AudioDevice::Type::Bluetooth: {
- device = std::make_shared<bluetooth::BluetoothAudioDevice>();
+ case AudioDevice::Type::BluetoothA2DP: {
+ device = std::make_shared<bluetooth::A2DPAudioDevice>();
+ } break;
+
+ case AudioDevice::Type::BluetoothHSP: {
+ device = std::make_shared<bluetooth::HSPAudioDevice>();
} break;
case AudioDevice::Type::Cellular: {
M module-bluetooth/Bluetooth/audio/BluetoothAudioDevice.cpp => module-bluetooth/Bluetooth/audio/BluetoothAudioDevice.cpp +158 -21
@@ 3,42 3,46 @@
#include "BluetoothAudioDevice.hpp"
-#include <Audio/AudioCommon.hpp>
#include <interface/profiles/A2DP/AVDTP.hpp>
-#include <module-audio/Audio/VolumeScaler.hpp>
+#include <interface/profiles/A2DP/AVRCP.hpp>
+#include <interface/profiles/HSP/SCO.hpp>
+#include <Audio/AudioCommon.hpp>
+#include <Audio/VolumeScaler.hpp>
#include <Audio/Stream.hpp>
#include <chrono>
#include <cassert>
using audio::AudioFormat;
-using namespace bluetooth;
+using bluetooth::A2DPAudioDevice;
+using bluetooth::BluetoothAudioDevice;
+using bluetooth::HSPAudioDevice;
+
using namespace std::chrono_literals;
-BluetoothAudioDevice::BluetoothAudioDevice(MediaContext *mediaContext) : ctx(mediaContext)
-{
- LOG_DEBUG("Bluetooth audio device created");
-}
+BluetoothAudioDevice::BluetoothAudioDevice(AudioProfile audioProfile) : profile(audioProfile)
+{}
BluetoothAudioDevice::~BluetoothAudioDevice()
{
LOG_DEBUG("Destroying bluetooth audio device");
}
-void BluetoothAudioDevice::setMediaContext(MediaContext *mediaContext)
+auto BluetoothAudioDevice::getProfileType() const -> AudioProfile
{
- ctx = mediaContext;
+ 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(ctx->avrcp_cid, volumeToSet);
+ 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;
}
@@ 48,19 52,125 @@ auto BluetoothAudioDevice::setInputGain(float gain) -> audio::AudioDevice::RetCo
return audio::AudioDevice::RetCode::Success;
}
-void BluetoothAudioDevice::onDataSend()
+auto BluetoothAudioDevice::isInputEnabled() const -> bool
+{
+ return inputEnabled;
+}
+
+auto BluetoothAudioDevice::isOutputEnabled() const -> bool
{
- if (outputEnabled) {
- fillSbcAudioBuffer(ctx);
+ return outputEnabled;
+}
+
+void A2DPAudioDevice::onDataSend()
+{
+ if (isOutputEnabled()) {
+ fillSbcAudioBuffer();
}
}
-void BluetoothAudioDevice::onDataReceive()
+void A2DPAudioDevice::onDataReceive()
{}
-void BluetoothAudioDevice::enableInput()
+void HSPAudioDevice::onDataSend()
{}
+void HSPAudioDevice::onDataSend(std::uint16_t scoHandle)
+{
+ if (!isOutputEnabled()) {
+ return;
+ }
+
+ hci_reserve_packet_buffer();
+ auto scoPacket = hci_get_outgoing_packet_buffer();
+
+ // get data to send
+ audio::AbstractStream::Span dataSpan;
+ Sink::_stream->peek(dataSpan);
+
+ // prepare packet to send
+ std::copy(dataSpan.data, dataSpan.dataEnd(), &scoPacket[packetDataOffset]);
+ Sink::_stream->consume();
+ little_endian_store_16(scoPacket, packetHandleOffset, scoHandle);
+ scoPacket[packetLengthOffset] = dataSpan.dataSize;
+
+ // send packet
+ hci_send_sco_packet_buffer(dataSpan.dataSize + packetDataOffset);
+ hci_request_sco_can_send_now_event();
+}
+
+void HSPAudioDevice::receiveCVSD(audio::AbstractStream::Span receivedData)
+{
+ if (!isInputEnabled()) {
+ return;
+ }
+
+ auto blockSize = Source::_stream->getInputTraits().blockSize;
+ auto decodedData = decodeCVSD(receivedData);
+ auto processedDataIndex = 0;
+
+ // try to complete leftovers to the full block size
+ if (leftoversSize != 0) {
+ auto maxFillSize = blockSize - leftoversSize;
+ auto fillSize = std::min(maxFillSize, decodedData.dataSize);
+
+ std::copy_n(decodedData.data, fillSize, &rxLeftovers[leftoversSize]);
+
+ if (fillSize + leftoversSize < blockSize) {
+ leftoversSize += fillSize;
+ return;
+ }
+
+ Source::_stream->push(&rxLeftovers[0], blockSize);
+ leftoversSize = 0;
+ processedDataIndex = fillSize;
+ }
+
+ // push as many blocks as possible
+ while (decodedData.dataSize - processedDataIndex >= blockSize) {
+ Source::_stream->push(&decodedData.data[processedDataIndex], blockSize);
+ processedDataIndex += blockSize;
+ }
+
+ // save leftovers
+ leftoversSize = decodedData.dataSize - processedDataIndex;
+ if (leftoversSize > 0) {
+ std::copy_n(&decodedData.data[processedDataIndex], leftoversSize, &rxLeftovers[0]);
+ }
+}
+
+auto HSPAudioDevice::decodeCVSD(audio::AbstractStream::Span dataToDecode) -> audio::AbstractStream::Span
+{
+ auto decodedData = dataToDecode;
+ std::array<std::int16_t, scratchBufferSize> scratchBuffer;
+
+ const auto audioBytesRead = dataToDecode.dataSize - packetDataOffset;
+ const auto samplesCount = audioBytesRead / sizeof(std::int16_t);
+ auto dataStart = &dataToDecode.data[packetDataOffset];
+
+ for (auto i = 0; i < samplesCount; ++i) {
+ scratchBuffer[i] = little_endian_read_16(dataStart, i * sizeof(std::uint16_t));
+ }
+
+ auto packetStatusByte = dataToDecode.data[packetStatusOffset];
+ auto isBadFrame = (packetStatusByte & allGoodMask) != 0;
+
+ btstack_cvsd_plc_process_data(&cvsdPlcState, isBadFrame, &scratchBuffer[0], samplesCount, &decoderBuffer[0]);
+
+ decodedData.data = reinterpret_cast<std::uint8_t *>(decoderBuffer.get());
+ decodedData.dataSize = audioBytesRead;
+
+ return decodedData;
+}
+
+void HSPAudioDevice::onDataReceive()
+{}
+
+void BluetoothAudioDevice::enableInput()
+{
+ inputEnabled = true;
+}
+
void BluetoothAudioDevice::enableOutput()
{
LOG_DEBUG("Enabling bluetooth audio output.");
@@ 68,7 178,9 @@ void BluetoothAudioDevice::enableOutput()
}
void BluetoothAudioDevice::disableInput()
-{}
+{
+ inputEnabled = false;
+}
void BluetoothAudioDevice::disableOutput()
{
@@ 76,11 188,21 @@ void BluetoothAudioDevice::disableOutput()
outputEnabled = false;
}
-auto BluetoothAudioDevice::fillSbcAudioBuffer(MediaContext *context) -> int
+void HSPAudioDevice::enableInput()
+{
+ auto blockSize = Source::_stream->getInputTraits().blockSize;
+ rxLeftovers = std::make_unique<std::uint8_t[]>(blockSize);
+ decoderBuffer = std::make_unique<std::int16_t[]>(scratchBufferSize);
+ btstack_cvsd_plc_init(&cvsdPlcState);
+ BluetoothAudioDevice::enableInput();
+}
+
+auto BluetoothAudioDevice::fillSbcAudioBuffer() -> int
{
// perform sbc encodin
int totalNumBytesRead = 0;
unsigned int numAudioSamplesPerSbcBuffer = btstack_sbc_encoder_num_audio_frames();
+ auto context = &AVRCP::mediaTracker;
assert(context != nullptr);
@@ 104,7 226,7 @@ auto BluetoothAudioDevice::fillSbcAudioBuffer(MediaContext *context) -> int
return totalNumBytesRead;
}
-auto BluetoothAudioDevice::getSupportedFormats() -> std::vector<audio::AudioFormat>
+auto A2DPAudioDevice::getSupportedFormats() -> std::vector<audio::AudioFormat>
{
constexpr static auto supportedBitWidth = 16U;
return std::vector<AudioFormat>{AudioFormat{static_cast<unsigned>(AVDTP::sbcConfig.samplingFrequency),
@@ 112,12 234,27 @@ auto BluetoothAudioDevice::getSupportedFormats() -> std::vector<audio::AudioForm
static_cast<unsigned>(AVDTP::sbcConfig.numChannels)}};
}
-auto BluetoothAudioDevice::getSourceFormat() -> audio::AudioFormat
+auto HSPAudioDevice::getSupportedFormats() -> std::vector<audio::AudioFormat>
{
- return audio::nullFormat;
+ return std::vector<AudioFormat>{getSourceFormat()};
}
-auto BluetoothAudioDevice::getTraits() const -> Traits
+auto A2DPAudioDevice::getTraits() const -> ::audio::Endpoint::Traits
{
return Traits{.usesDMA = false, .blockSizeConstraint = 512U, .timeConstraint = 10ms};
}
+
+auto HSPAudioDevice::getTraits() const -> ::audio::Endpoint::Traits
+{
+ return Traits{.usesDMA = false, .blockSizeConstraint = 32U, .timeConstraint = 16ms};
+}
+
+auto A2DPAudioDevice::getSourceFormat() -> ::audio::AudioFormat
+{
+ return audio::nullFormat;
+}
+
+auto HSPAudioDevice::getSourceFormat() -> ::audio::AudioFormat
+{
+ return AudioFormat{bluetooth::SCO::CVSD_SAMPLE_RATE, supportedBitWidth, supportedChannels};
+}
M module-bluetooth/Bluetooth/audio/BluetoothAudioDevice.hpp => module-bluetooth/Bluetooth/audio/BluetoothAudioDevice.hpp +70 -14
@@ 3,9 3,16 @@
#pragma once
+#include <Audio/Endpoint.hpp>
#include <Audio/AudioDevice.hpp>
#include <Audio/AudioFormat.hpp>
#include <interface/profiles/A2DP/MediaContext.hpp>
+#include <interface/profiles/AudioProfile.hpp>
+
+extern "C"
+{
+#include "classic/btstack_cvsd_plc.h"
+}
namespace bluetooth
{
@@ 13,31 20,80 @@ namespace bluetooth
class BluetoothAudioDevice : public audio::AudioDevice
{
public:
- BluetoothAudioDevice() = default;
- explicit BluetoothAudioDevice(MediaContext *mediaContext);
+ explicit BluetoothAudioDevice(AudioProfile audioProfile);
virtual ~BluetoothAudioDevice();
- RetCode setOutputVolume(float vol) override;
- RetCode setInputGain(float gain) override;
- void setMediaContext(MediaContext *MediaContext);
- auto getTraits() const -> Traits override;
- auto getSupportedFormats() -> std::vector<audio::AudioFormat> override;
- auto getSourceFormat() -> audio::AudioFormat override;
+ virtual auto getProfileType() const -> AudioProfile;
+
+ auto setOutputVolume(float vol) -> audio::AudioDevice::RetCode override;
+ auto setInputGain(float gain) -> audio::AudioDevice::RetCode override;
// Endpoint control methods
- void onDataSend() override;
- void onDataReceive() override;
void enableInput() override;
void enableOutput() override;
void disableInput() override;
void disableOutput() override;
+ protected:
+ auto isInputEnabled() const -> bool;
+ auto isOutputEnabled() const -> bool;
+ auto fillSbcAudioBuffer() -> int;
+
+ private:
+ bool outputEnabled = false;
+ bool inputEnabled = false;
+ AudioProfile profile = AudioProfile::None;
+ float outputVolume;
+ };
+
+ class A2DPAudioDevice : public BluetoothAudioDevice
+ {
+ public:
+ explicit A2DPAudioDevice() : BluetoothAudioDevice(AudioProfile::A2DP)
+ {}
+
+ void onDataSend() override;
+ void onDataReceive() override;
+ auto getSupportedFormats() -> std::vector<audio::AudioFormat> override;
+ auto getTraits() const -> Traits override;
+ auto getSourceFormat() -> ::audio::AudioFormat override;
+ };
+
+ class HSPAudioDevice : public BluetoothAudioDevice
+ {
+ public:
+ explicit HSPAudioDevice() : BluetoothAudioDevice(AudioProfile::HSP)
+ {}
+
+ void onDataSend() override;
+ void onDataSend(std::uint16_t scoHandle);
+ void onDataReceive() override;
+ auto getSupportedFormats() -> std::vector<audio::AudioFormat> override;
+ auto getTraits() const -> Traits override;
+ auto getSourceFormat() -> ::audio::AudioFormat override;
+ void enableInput() override;
+
+ void receiveCVSD(audio::AbstractStream::Span receivedData);
+
private:
- auto fillSbcAudioBuffer(MediaContext *context) -> int;
+ static constexpr std::size_t scratchBufferSize = 128;
+
+ static constexpr auto packetHandleOffset = 0;
+ static constexpr auto packetStatusOffset = 1;
+ static constexpr auto packetLengthOffset = 2;
+ static constexpr auto packetDataOffset = 3;
+
+ constexpr static auto supportedBitWidth = 16U;
+ constexpr static auto supportedChannels = 1;
+
+ constexpr static auto allGoodMask = 0x30;
+
+ auto decodeCVSD(audio::AbstractStream::Span dataToDecode) -> audio::AbstractStream::Span;
- MediaContext *ctx = nullptr;
- bool outputEnabled = false;
- float outputVolume = 0.0;
+ std::unique_ptr<std::uint8_t[]> rxLeftovers;
+ std::unique_ptr<std::int16_t[]> decoderBuffer;
+ std::size_t leftoversSize = 0;
+ btstack_cvsd_plc_state_t cvsdPlcState;
};
} // namespace bluetooth
M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.cpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.cpp +1 -1
@@ 97,6 97,7 @@ namespace bluetooth
auto A2DP::startRinging() const noexcept -> Error::Code
{
+ LOG_ERROR("Can't ring in A2DP profile");
return Error::SystemError;
}
@@ 622,7 623,6 @@ namespace bluetooth
void A2DP::A2DPImpl::setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> newAudioDevice)
{
- newAudioDevice->setMediaContext(&AVRCP::mediaTracker);
A2DP::A2DPImpl::audioDevice = std::move(newAudioDevice);
}
M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DPImpl.hpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DPImpl.hpp +0 -1
@@ 50,7 50,6 @@ namespace bluetooth
static void sendMediaPacket();
static void sendAudioEvent(audio::EventType event, audio::Event::DeviceState state);
static bool isConnected;
-
static std::shared_ptr<BluetoothAudioDevice> audioDevice;
public:
A module-bluetooth/Bluetooth/interface/profiles/AudioProfile.hpp => module-bluetooth/Bluetooth/interface/profiles/AudioProfile.hpp +15 -0
@@ 0,0 1,15 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+namespace bluetooth
+{
+ enum class AudioProfile
+ {
+ A2DP,
+ HSP,
+ HFP,
+ None
+ };
+};
M module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.cpp => module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.cpp +18 -2
@@ 111,6 111,7 @@ namespace bluetooth
const sys::Service *HSP::HSPImpl::ownerService;
std::string HSP::HSPImpl::agServiceName = "PurePhone HSP";
bool HSP::HSPImpl::isConnected = false;
+ std::shared_ptr<HSPAudioDevice> HSP::HSPImpl::audioDevice;
void HSP::HSPImpl::sendAudioEvent(audio::EventType event, audio::Event::DeviceState state)
{
@@ 127,7 128,9 @@ namespace bluetooth
if (READ_SCO_CONNECTION_HANDLE(event) != scoHandle) {
break;
}
- sco->receive(event, eventSize);
+ if (audioDevice != nullptr) {
+ audioDevice->receiveCVSD(audio::AbstractStream::Span{.data = event, .dataSize = eventSize});
+ }
break;
case HCI_EVENT_PACKET:
@@ 142,7 145,9 @@ namespace bluetooth
{
switch (hci_event_packet_get_type(event)) {
case HCI_EVENT_SCO_CAN_SEND_NOW:
- sco->send(scoHandle);
+ if (audioDevice != nullptr) {
+ audioDevice->onDataSend(scoHandle);
+ }
break;
case HCI_EVENT_HSP_META:
processHSPEvent(event);
@@ 163,6 168,7 @@ namespace bluetooth
break;
}
LOG_DEBUG("RFCOMM connection established.\n");
+ sendAudioEvent(audio::EventType::BlutoothHSPDeviceState, audio::Event::DeviceState::Connected);
isConnected = true;
break;
case HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE:
@@ 314,4 320,14 @@ namespace bluetooth
stopRinging();
establishAudioConnection();
}
+
+ void HSP::setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> audioDevice)
+ {
+ pimpl->setAudioDevice(audioDevice);
+ }
+
+ void HSP::HSPImpl::setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> audioDevice)
+ {
+ HSP::HSPImpl::audioDevice = std::static_pointer_cast<HSPAudioDevice>(audioDevice);
+ }
} // namespace bluetooth
M module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.hpp => module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.hpp +1 -2
@@ 55,8 55,7 @@ namespace bluetooth
/// @return Success
[[nodiscard]] auto initializeCall() const noexcept -> Error::Code override;
- void setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> audioDevice) override
- {}
+ void setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> audioDevice) override;
private:
class HSPImpl;
M module-bluetooth/Bluetooth/interface/profiles/HSP/HSPImpl.hpp => module-bluetooth/Bluetooth/interface/profiles/HSP/HSPImpl.hpp +3 -1
@@ 27,6 27,7 @@ namespace bluetooth
void setDeviceAddress(bd_addr_t addr);
void setOwnerService(const sys::Service *service);
auto getStreamData() -> std::shared_ptr<BluetoothStreamData>;
+ void setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> audioDevice);
private:
static void sendAudioEvent(audio::EventType event, audio::Event::DeviceState state);
@@ 43,5 44,6 @@ namespace bluetooth
static bd_addr_t deviceAddr;
static const sys::Service *ownerService;
static bool isConnected;
+ static std::shared_ptr<HSPAudioDevice> audioDevice;
};
-} // namespace Bt
+} // namespace bluetooth
M module-bluetooth/Bluetooth/interface/profiles/HSP/SCO.cpp => module-bluetooth/Bluetooth/interface/profiles/HSP/SCO.cpp +0 -1
@@ 32,7 32,6 @@ namespace bluetooth
auto getStreamData() -> std::shared_ptr<BluetoothStreamData>;
private:
- static constexpr auto CVSD_SAMPLE_RATE = 8000;
static constexpr auto BYTES_PER_FRAME = 2;
static constexpr auto ALL_GOOD_MASK = 0x30;
static constexpr auto AUDIO_BUFFER_LENGTH = 128;
M module-bluetooth/Bluetooth/interface/profiles/HSP/SCO.hpp => module-bluetooth/Bluetooth/interface/profiles/HSP/SCO.hpp +3 -1
@@ 30,8 30,10 @@ namespace bluetooth
[[nodiscard]] auto getStreamData() const -> std::shared_ptr<BluetoothStreamData>;
void setOwnerService(const sys::Service *service);
+ static constexpr auto CVSD_SAMPLE_RATE = 8000;
+
private:
class SCOImpl;
std::unique_ptr<SCOImpl> pimpl;
};
-} // namespace Bt
+} // namespace bluetooth
M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.cpp => module-bluetooth/Bluetooth/interface/profiles/ProfileManager.cpp +7 -3
@@ 97,6 97,7 @@ namespace bluetooth
auto ProfileManager::startRinging() -> Error::Code
{
+ switchProfile(AudioProfile::HSP);
return currentProfilePtr->startRinging();
}
@@ 107,16 108,19 @@ namespace bluetooth
auto ProfileManager::initializeCall() -> Error::Code
{
+ switchProfile(AudioProfile::HSP);
return currentProfilePtr->initializeCall();
}
auto ProfileManager::setAudioDevice(std::shared_ptr<BluetoothAudioDevice> device) -> Error::Code
{
- if (currentProfilePtr == nullptr) {
+ auto profileType = device->getProfileType();
+
+ if (currentProfilePtr == nullptr || profilesList[profileType] == nullptr) {
return Error::NotReady;
}
- currentProfilePtr->setAudioDevice(std::move(device));
- return Error::Success;
+ profilesList[profileType]->setAudioDevice(device);
+ return switchProfile(profileType);
}
} // namespace bluetooth
M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp => module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp +1 -8
@@ 6,6 6,7 @@
#include <Service/Service.hpp>
#include <Error.hpp>
#include "Profile.hpp"
+#include "AudioProfile.hpp"
#include "interface/profiles/A2DP/A2DP.hpp"
#include "interface/profiles/HSP/HSP.hpp"
#include "audio/BluetoothAudioDevice.hpp"
@@ 21,14 22,6 @@ extern "C"
namespace bluetooth
{
- enum class AudioProfile
- {
- A2DP,
- HSP,
- HFP,
- None
- };
-
using ProfileList = std::map<AudioProfile, std::shared_ptr<bluetooth::Profile>>;
class ProfileManager
M module-services/service-audio/ServiceAudio.cpp => module-services/service-audio/ServiceAudio.cpp +31 -13
@@ 26,11 26,11 @@ using namespace audio;
inline constexpr auto audioServiceStackSize = 1024 * 4;
-static constexpr auto defaultVolumeHigh = "10";
-static constexpr auto defaultVolumeLow = "2";
-static constexpr auto defaultVolumeMuted = "0";
-static constexpr auto defaultTrue = "1";
-static constexpr auto defaultFalse = "0";
+static constexpr auto defaultVolumeHigh = "10";
+static constexpr auto defaultVolumeLow = "2";
+static constexpr auto defaultVolumeMuted = "0";
+static constexpr auto defaultTrue = "1";
+static constexpr auto defaultFalse = "0";
static constexpr auto defaultCallRingtonePath = "assets/audio/ringtone/ringtone_drum_2.mp3";
static constexpr auto defaultTextMessageRingtonePath = "assets/audio/sms/sms_drum_2.mp3";
static constexpr auto defaultNotificationsPath = "assets/audio/alarm/alarm_hang_drum.mp3";
@@ 153,9 153,14 @@ std::optional<std::string> ServiceAudio::AudioServicesCallback(const sys::Messag
return settings_it->second;
}
else if (const auto *deviceMsg = dynamic_cast<const AudioServiceMessage::AudioDeviceCreated *>(msg); deviceMsg) {
- if (deviceMsg->getDeviceType() == AudioDevice::Type::Bluetooth) {
+ if (deviceMsg->getDeviceType() == AudioDevice::Type::BluetoothA2DP) {
auto startBluetoothAudioMsg = std::make_shared<BluetoothAudioStartMessage>(
- std::static_pointer_cast<bluetooth::BluetoothAudioDevice>(deviceMsg->getDevice()));
+ std::static_pointer_cast<bluetooth::A2DPAudioDevice>(deviceMsg->getDevice()));
+ bus.sendUnicast(std::move(startBluetoothAudioMsg), service::name::bluetooth);
+ }
+ else if (deviceMsg->getDeviceType() == AudioDevice::Type::BluetoothHSP) {
+ auto startBluetoothAudioMsg = std::make_shared<BluetoothAudioStartMessage>(
+ std::static_pointer_cast<bluetooth::HSPAudioDevice>(deviceMsg->getDevice()));
bus.sendUnicast(std::move(startBluetoothAudioMsg), service::name::bluetooth);
}
}
@@ 325,11 330,14 @@ std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleStart(const Operation:
if (opType == Operation::Type::Playback) {
auto input = audioMux.GetPlaybackInput(playbackType);
// stop bluetooth stream if available
- if (bluetoothConnected) {
+ if (bluetoothA2DPConnected || bluetoothHSPConnected) {
if (playbackType == audio::PlaybackType::CallRingtone) {
+ HandleSendEvent(std::make_shared<audio::Event>(EventType::BlutoothHSPDeviceState));
+
LOG_DEBUG("Sending Bluetooth start ringing");
bus.sendUnicast(std::make_shared<message::bluetooth::Ring>(message::bluetooth::Ring::State::Enable),
service::name::bluetooth);
+ return std::make_unique<AudioStartPlaybackResponse>(audio::RetCode::Success, retToken);
}
else {
LOG_DEBUG("Sending Bluetooth start stream request");
@@ 348,7 356,10 @@ std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleStart(const Operation:
}
else if (opType == Operation::Type::Router) {
auto input = audioMux.GetRoutingInput(true);
- if (bluetoothConnected) {
+ if (bluetoothA2DPConnected) {
+ HandleSendEvent(std::make_shared<audio::Event>(EventType::BlutoothHSPDeviceState));
+ }
+ if (bluetoothHSPConnected) {
LOG_DEBUG("Sending Bluetooth start routing");
bus.sendUnicast(std::make_shared<message::bluetooth::StartAudioRouting>(), service::name::bluetooth);
}
@@ 363,11 374,10 @@ std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleSendEvent(std::shared_
// update bluetooth state
if (evt->getType() == EventType::BlutoothA2DPDeviceState) {
auto newState = evt->getDeviceState() == Event::DeviceState::Connected;
- if (newState != bluetoothConnected) {
+ if (newState != bluetoothA2DPConnected) {
LOG_DEBUG("Bluetooth connection status changed: %s", newState ? "connected" : "disconnected");
- bluetoothConnected = newState;
+ bluetoothA2DPConnected = newState;
HandleStop({audio::PlaybackType::Alarm,
- audio::PlaybackType::CallRingtone,
audio::PlaybackType::Meditation,
audio::PlaybackType::Notifications,
audio::PlaybackType::TextMessageRingtone},
@@ 375,6 385,14 @@ std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleSendEvent(std::shared_
}
}
+ if (evt->getType() == EventType::BlutoothHSPDeviceState) {
+ auto newState = evt->getDeviceState() == Event::DeviceState::Connected;
+ if (newState != bluetoothHSPConnected) {
+ LOG_DEBUG("Bluetooth connection status changed: %s", newState ? "connected" : "disconnected");
+ bluetoothHSPConnected = newState;
+ }
+ }
+
// update information about endpoints availability
for (auto &input : audioMux.GetAllInputs()) {
input.audio->SendEvent(evt);
@@ 426,7 444,7 @@ std::unique_ptr<AudioResponseMessage> ServiceAudio::HandleStop(const std::vector
}
// stop bluetooth stream if available
- if (bluetoothConnected) {
+ if (bluetoothA2DPConnected) {
LOG_DEBUG("Sending Bluetooth stop request");
bus.sendUnicast(std::make_shared<BluetoothMessage>(BluetoothMessage::Request::Stop), service::name::bluetooth);
}
M module-services/service-audio/service-audio/ServiceAudio.hpp => module-services/service-audio/service-audio/ServiceAudio.hpp +2 -1
@@ 57,7 57,8 @@ class ServiceAudio : public sys::Service
audio::AudioMux::VibrationStatus vibrationMotorStatus = audio::AudioMux::VibrationStatus::Off;
std::unique_ptr<settings::Settings> settingsProvider;
std::map<std::string, std::string> settingsCache;
- bool bluetoothConnected = false;
+ bool bluetoothA2DPConnected = false;
+ bool bluetoothHSPConnected = false;
auto IsVibrationMotorOn()
{