M module-apps/application-settings-new/models/BluetoothSettingsModel.cpp => module-apps/application-settings-new/models/BluetoothSettingsModel.cpp +4 -5
@@ 57,11 57,6 @@ void BluetoothSettingsModel::stopScan()
service::name::bluetooth);
}
-void BluetoothSettingsModel::setAddrForAudioProfiles(std::string addr)
-{
- application->bus.sendUnicast(std::make_shared<BluetoothAddrMessage>(std::move(addr)), service::name::bluetooth);
-}
-
void BluetoothSettingsModel::requestDevicePairing(std::string addr)
{
application->bus.sendUnicast(std::make_shared<BluetoothPairMessage>(std::move(addr)), service::name::bluetooth);
@@ 72,3 67,7 @@ void BluetoothSettingsModel::responsePasskey(std::string passkey)
application->bus.sendUnicast(std::make_shared<message::bluetooth::ResponsePasskey>(std::move(passkey)),
service::name::bluetooth);
}
+void BluetoothSettingsModel::requestAudioConnection(std::string addr)
+{
+ application->bus.sendUnicast(std::make_shared<BluetoothAddrMessage>(std::move(addr)), service::name::bluetooth);
+}
M module-apps/application-settings-new/models/BluetoothSettingsModel.hpp => module-apps/application-settings-new/models/BluetoothSettingsModel.hpp +1 -1
@@ 21,10 21,10 @@ class BluetoothSettingsModel
void setDeviceName(const UTF8 &deviceName);
void requestBondedDevices();
void requestScan();
+ void requestAudioConnection(std::string addr);
void stopScan();
void requestDevicePairing(std::string addr);
void responsePasskey(std::string passkey);
- void setAddrForAudioProfiles(std::string addr);
private:
app::Application *application = nullptr;
M module-apps/application-settings-new/windows/AddDeviceWindow.cpp => module-apps/application-settings-new/windows/AddDeviceWindow.cpp +0 -1
@@ 43,7 43,6 @@ namespace gui
device.name,
[=](gui::Item & /*unused*/) {
LOG_DEBUG("Device: %s", device.name.c_str());
- bluetoothSettingsModel->setAddrForAudioProfiles(bd_addr_to_str(device.address));
bluetoothSettingsModel->requestDevicePairing(bd_addr_to_str(device.address));
return true;
},
M module-apps/application-settings-new/windows/AllDevicesWindow.cpp => module-apps/application-settings-new/windows/AllDevicesWindow.cpp +2 -0
@@ 70,6 70,8 @@ namespace gui
device.name,
[=](gui::Item & /*item*/) {
LOG_DEBUG("Device: %s", device.name.c_str());
+ std::string addr{bd_addr_to_str(device.address)};
+ bluetoothSettingsModel->requestAudioConnection(std::move(addr));
return true;
},
nullptr,
M module-apps/application-settings/windows/BtWindow.cpp => module-apps/application-settings/windows/BtWindow.cpp +15 -12
@@ 63,14 63,12 @@ namespace gui
setTitle(utils::localize.get("app_settings_bt"));
LOG_INFO("Create box layout");
- box = new gui::VBox(this, 0, title->offset_h(), style::window_width, 7 * style::window::label::default_h);
+ box = new gui::VBox(this, 0, title->offset_h(), style::window_width, 8 * style::window::label::default_h);
box->setEdges(RectangleEdge::None);
- // TODO WIP: it's just for usability now
- // TODO scan should return async - handle that... (if in scan -> add to list and refresh if new on window)
add_box_label(box, "Bluetooth on off", [=](Item &) {
LOG_DEBUG("Callback Bluetooth on");
- message_bt(application, BluetoothMessage::Request::Start);
+
for (auto &el : box->children) {
el->visible = true;
}
@@ 92,21 90,26 @@ namespace gui
return true;
});
- add_box_label(box, " -> Set visible", [=](Item &) {
- LOG_DEBUG("Callback set visibility");
- message_bt(application, BluetoothMessage::Request::Visible);
+ add_box_label(box, " -> Switch A2DP <-> HSP", [=](Item &) {
+ LOG_DEBUG("Callback switch profile");
+ message_bt(application, BluetoothMessage::Request::SwitchProfile);
return true;
});
- add_box_label(box, " -> Play", [=](Item &) {
- LOG_DEBUG("Start playback");
+ add_box_label(box, " -> Start stream", [=](Item &) {
+ LOG_DEBUG("Start stream");
message_bt(application, BluetoothMessage::Request::Play);
return true;
});
- add_box_label(box, " -> Stop", [=](Item &) {
- LOG_DEBUG("Stop playback");
- message_bt(application, BluetoothMessage::Request::StopPlayback);
+ add_box_label(box, " -> Stop stream", [=](Item &) {
+ LOG_DEBUG("Stop stream");
+ message_bt(application, BluetoothMessage::Request::Stop);
+ return true;
+ });
+ add_box_label(box, " -> Disconnect audio", [=](Item &) {
+ LOG_DEBUG("Disconnect");
+ message_bt(application, BluetoothMessage::Request::Disconnect);
return true;
});
M module-bluetooth/Bluetooth/BluetoothWorker.cpp => module-bluetooth/Bluetooth/BluetoothWorker.cpp +4 -9
@@ 71,12 71,12 @@ namespace
auto createStatefulController(sys::Service *service,
bluetooth::RunLoop *loop,
std::shared_ptr<bluetooth::SettingsHolder> settings,
- std::shared_ptr<bluetooth::Profile> currentProfile,
+ std::shared_ptr<bluetooth::ProfileManager> profileManager,
DeviceRegistration::OnLinkKeyAddedCallback &&onLinkKeyAddedCallback)
{
auto driver = std::make_shared<bluetooth::Driver>(loop->getRunLoopInstance(), service);
auto commandHandler =
- std::make_unique<bluetooth::CommandHandler>(service, settings, std::move(currentProfile), driver);
+ std::make_unique<bluetooth::CommandHandler>(service, settings, std::move(profileManager), driver);
return std::make_unique<bluetooth::StatefulController>(
std::move(driver),
std::move(commandHandler),
@@ 85,11 85,11 @@ namespace
} // namespace
BluetoothWorker::BluetoothWorker(sys::Service *service)
- : Worker(service), service(service), currentProfile(std::make_shared<bluetooth::HSP>()),
+ : Worker(service), service(service), profileManager(std::make_shared<bluetooth::ProfileManager>(service)),
settings(static_cast<ServiceBluetooth *>(service)->settingsHolder),
runLoop(std::make_unique<bluetooth::RunLoop>()),
controller{createStatefulController(
- service, runLoop.get(), settings, currentProfile, [this](const std::string &addr) { onLinkKeyAdded(addr); })}
+ service, runLoop.get(), settings, profileManager, [this](const std::string &addr) { onLinkKeyAdded(addr); })}
{
init({
{queues::io, sizeof(bluetooth::Message), queues::queueLength},
@@ 247,11 247,6 @@ auto BluetoothWorker::handleMessage(uint32_t queueID) -> bool
return true;
}
-void BluetoothWorker::setDeviceAddress(bd_addr_t addr)
-{
- currentProfile->setDeviceAddress(addr);
-}
-
auto BluetoothWorker::deinit() -> bool
{
controller->turnOff();
M module-bluetooth/Bluetooth/BluetoothWorker.hpp => module-bluetooth/Bluetooth/BluetoothWorker.hpp +1 -2
@@ 98,12 98,11 @@ class BluetoothWorker : private sys::Worker
auto handleBtStackTrigger(QueueHandle_t queue) -> bool;
bool run() override;
- void setDeviceAddress(bd_addr_t addr);
auto deinit() -> bool override;
/// bluetooth stack id in use
unsigned long active_features;
- std::shared_ptr<bluetooth::Profile> currentProfile;
+ std::shared_ptr<bluetooth::ProfileManager> profileManager;
std::shared_ptr<bluetooth::SettingsHolder> settings;
std::vector<Devicei> pairedDevices;
std::unique_ptr<bluetooth::RunLoop> runLoop;
M module-bluetooth/Bluetooth/BtKeysStorage.cpp => module-bluetooth/Bluetooth/BtKeysStorage.cpp +5 -2
@@ 72,7 72,8 @@ namespace bluetooth
{
if (type != nullptr && bd_addr != nullptr) {
LOG_INFO("getting key for address %s from API", bd_addr_to_str(bd_addr));
- if (keys.size() == 0) {
+ if (keys.empty()) {
+ LOG_ERROR("Keys empty!");
return 0;
}
for (auto key : keys) {
@@ 81,11 82,13 @@ namespace bluetooth
if (bd_addr_cmp(addr, bd_addr) == 0) {
auto foundLinkKey = key[strings::link_key].string_value().c_str();
- memcpy(link_key, foundLinkKey, sizeof(link_key_t));
+ memcpy(link_key, reinterpret_cast<const uint8_t *>(foundLinkKey), sizeof(link_key_t));
+ LOG_INFO("Getting key: %s", foundLinkKey);
*type = static_cast<link_key_type_t>(key[strings::type].int_value());
return 1;
}
+ LOG_ERROR("Can't find key for this address!");
}
}
return 0;
M module-bluetooth/Bluetooth/CommandHandler.cpp => module-bluetooth/Bluetooth/CommandHandler.cpp +33 -24
@@ 29,9 29,9 @@ namespace bluetooth
CommandHandler::CommandHandler(sys::Service *service,
std::shared_ptr<bluetooth::SettingsHolder> settings,
- std::shared_ptr<bluetooth::Profile> currentProfile,
+ std::shared_ptr<bluetooth::ProfileManager> profileManager,
std::shared_ptr<bluetooth::AbstractDriver> driver)
- : service{service}, settings{std::move(settings)}, currentProfile{std::move(currentProfile)}, driver{std::move(
+ : service{service}, settings{std::move(settings)}, profileManager{std::move(profileManager)}, driver{std::move(
driver)}
{}
@@ 47,19 47,27 @@ namespace bluetooth
case bluetooth::Command::StartPan:
return startPan();
case bluetooth::Command::Pair:
- return pair(command.getArgument().value());
+ return pair(command.getAddress());
case bluetooth::Command::VisibilityOn:
return setVisibility(true);
case bluetooth::Command::VisibilityOff:
return setVisibility(false);
case bluetooth::Command::ConnectAudio:
- return establishAudioConnection();
+ return establishAudioConnection(command.getAddress());
case bluetooth::Command::DisconnectAudio:
return disconnectAudioConnection();
case bluetooth::Command::PowerOff:
return Error::Success;
+ case bluetooth::Command::SwitchProfile:
+ return switchAudioProfile();
case bluetooth::Command::None:
return Error::Success;
+ case Command::StartStream:
+ profileManager->start();
+ return Error::Success;
+ case Command::StopStream:
+ profileManager->stop();
+ return Error::Success;
}
return Error::LibraryError;
}
@@ 102,38 110,39 @@ namespace bluetooth
return Error::Success;
}
- Error::Code CommandHandler::establishAudioConnection()
+ Error::Code CommandHandler::establishAudioConnection(uint8_t *addr)
{
- currentProfile->setOwnerService(service);
- if (const auto status = currentProfile->init(); status != bluetooth::Error::Success) {
- return status;
- }
+ profileManager->init();
+ LOG_INFO("Connecting audio with %s", bd_addr_to_str(addr));
+ profileManager->connect(addr);
- currentProfile->connect();
return Error::Success;
}
Error::Code CommandHandler::disconnectAudioConnection()
{
- currentProfile->disconnect();
+ profileManager->disconnect();
return Error::Success;
}
- Error::Code CommandHandler::pair(CommandArgument arg)
+ Error::Code CommandHandler::pair(bd_addr_t addr)
{
- try {
- auto addrString = std::get<std::string>(arg);
- bd_addr_t addr;
- if (sscanf_bd_addr(addrString.c_str(), addr) != 0) {
- LOG_INFO("Pairing with %s", addrString.c_str());
- driver->pair(addr);
- }
- else {
- return Error::SystemError;
- }
+ LOG_INFO("Pairing with %s", bd_addr_to_str(addr));
+
+ return driver->pair(addr) ? Error::Success : Error::LibraryError;
+ }
+ Error::Code CommandHandler::switchAudioProfile()
+ {
+ static auto profile = AudioProfile::A2DP;
+ if (profile == AudioProfile::A2DP) {
+ profile = AudioProfile::HSP;
+ LOG_INFO("New profile: HSP");
}
- catch (const std::bad_variant_access &) {
- return Error::SystemError;
+ else {
+ profile = AudioProfile::A2DP;
+ LOG_INFO("New profile: A2DP");
}
+ profileManager->switchProfile(profile);
return Error::Success;
}
+
} // namespace bluetooth
M module-bluetooth/Bluetooth/CommandHandler.hpp => module-bluetooth/Bluetooth/CommandHandler.hpp +22 -13
@@ 4,7 4,7 @@
#pragma once
#include "Error.hpp"
-#include "interface/profiles/Profile.hpp"
+#include "interface/profiles/ProfileManager.hpp"
#include "interface/BluetoothDriver.hpp"
#include <cstdint>
@@ 17,11 17,10 @@ namespace sys
namespace bluetooth
{
class SettingsHolder;
- using CommandArgument = std::variant<std::string, bool, int>;
class Command
{
public:
- enum Type : std::uint8_t
+ enum Type
{
StartScan,
StopScan,
@@ 33,25 32,34 @@ namespace bluetooth
PowerOn,
PowerOff,
Pair,
+ StartStream,
+ StopStream,
+ SwitchProfile,
None,
};
- Command(Command::Type type, std::optional<CommandArgument> arg = std::nullopt)
- : argument(std::move(arg)), type(type)
- {}
+ explicit Command(Command::Type type, std::optional<uint8_t *> addr = std::nullopt) : type(type)
+ {
+ if (addr) {
+ bd_addr_copy(address, addr.value());
+ }
+ else {
+ memset(address, 0, sizeof(bd_addr_t));
+ }
+ }
auto getType() const noexcept -> Command::Type
{
return type;
}
- auto getArgument() const -> std::optional<CommandArgument>
+ auto getAddress() -> uint8_t *
{
- return argument;
+ return address;
}
private:
- std::optional<CommandArgument> argument;
+ bd_addr_t address{};
Type type;
};
@@ 68,7 76,7 @@ namespace bluetooth
public:
explicit CommandHandler(sys::Service *service,
std::shared_ptr<bluetooth::SettingsHolder> settings,
- std::shared_ptr<bluetooth::Profile> currentProfile,
+ std::shared_ptr<bluetooth::ProfileManager> profileManager,
std::shared_ptr<bluetooth::AbstractDriver> driver);
auto handle(Command command) -> Error::Code override;
@@ 78,13 86,14 @@ namespace bluetooth
Error::Code stopScan();
Error::Code startPan();
Error::Code setVisibility(bool visibility);
- Error::Code establishAudioConnection();
+ Error::Code establishAudioConnection(bd_addr_t addr);
Error::Code disconnectAudioConnection();
- Error::Code pair(CommandArgument arg);
+ Error::Code pair(bd_addr_t addr);
+ Error::Code switchAudioProfile();
sys::Service *service;
std::shared_ptr<bluetooth::SettingsHolder> settings;
- std::shared_ptr<bluetooth::Profile> currentProfile;
+ std::shared_ptr<bluetooth::ProfileManager> profileManager;
std::shared_ptr<AbstractDriver> driver;
};
} // namespace bluetooth
M module-bluetooth/Bluetooth/WorkerController.cpp => module-bluetooth/Bluetooth/WorkerController.cpp +1 -1
@@ 4,7 4,7 @@
#include "WorkerController.hpp"
#include "Device.hpp"
-#include "interface/profiles/Profile.hpp"
+#include "interface/profiles/ProfileManager.hpp"
#include <module-utils/log/log.hpp>
#define BOOST_SML_CFG_DISABLE_MIN_SIZE // GCC10 fix
M module-bluetooth/Bluetooth/btstack_config.h => module-bluetooth/Bluetooth/btstack_config.h +9 -8
@@ 36,20 36,21 @@
// BTstack configuration. buffers, sizes, ...
#define HCI_INCOMING_PRE_BUFFER_SIZE 14 // sizeof benep heade, avoid memcpy
-#define HCI_ACL_PAYLOAD_SIZE (1691 + 4)
+//#define HCI_ACL_PAYLOAD_SIZE (1691 + 4)
+#define HCI_ACL_PAYLOAD_SIZE (1021+4)
#define ENABLE_GATT_CLIENT_PAIRING
#define ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
#define ENABLE_CC256X_BAUDRATE_CHANGE_FLOWCONTROL_BUG_WORKAROUND
//#define HAVE_EMBEDDED_TIME_MS
-#define MAX_NR_HCI_CONNECTIONS 3
-#define MAX_NR_L2CAP_SERVICES 4
-#define MAX_NR_L2CAP_CHANNELS 10
-#define MAX_NR_RFCOMM_MULTIPLEXERS 2
-#define MAX_NR_RFCOMM_SERVICES 4
-#define MAX_NR_RFCOMM_CHANNELS 4
-#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 10
+//#define MAX_NR_HCI_CONNECTIONS 4
+//#define MAX_NR_L2CAP_SERVICES 5
+//#define MAX_NR_L2CAP_CHANNELS 6
+//#define MAX_NR_RFCOMM_MULTIPLEXERS 2
+//#define MAX_NR_RFCOMM_SERVICES 3
+//#define MAX_NR_RFCOMM_CHANNELS 3
+//#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 10
// As an option - much slower (according to docs)
// HCI Controller to Host Flow Control
M module-bluetooth/Bluetooth/glucode/BluetoothRunLoop.hpp => module-bluetooth/Bluetooth/glucode/BluetoothRunLoop.hpp +1 -1
@@ 30,7 30,6 @@ namespace bluetooth
static auto removeDataSource(btstack_data_source_t *ds) -> bool;
static void triggerExit();
static auto getTimeMs() -> TickType_t;
- static void trigger();
static void executeCodeOnMainThread(void (*fn)(void *arg), void *arg);
static void addTimer(btstack_timer_source_t *ts);
static void setTimer(btstack_timer_source_t *ts, uint32_t timeout_in_ms);
@@ 46,6 45,7 @@ namespace bluetooth
btstack_run_loop runLoop;
public:
+ static void trigger();
auto process() -> bool;
static void deinit();
void setTriggerQueue(QueueHandle_t queue);
M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.cpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.cpp +34 -11
@@ 77,11 77,21 @@ namespace bluetooth
void A2DP::connect()
{
- pimpl->start();
+ pimpl->connect();
}
void A2DP::disconnect()
{
+ pimpl->disconnect();
+ }
+
+ void A2DP::start()
+ {
+ pimpl->start();
+ }
+
+ void A2DP::stop()
+ {
pimpl->stop();
}
@@ 98,6 108,7 @@ namespace bluetooth
2,
53};
+ bool A2DP::A2DPImpl::isConnected = false;
/* LISTING_START(MainConfiguration): Setup Audio Source and AVRCP Target services */
auto A2DP::A2DPImpl::init() -> Error::Code
@@ 155,8 166,6 @@ namespace bluetooth
// Set local name with a template Bluetooth address, that will be automatically
// replaced with a actual address once it is available, i.e. when BTstack boots
// up and starts talking to a Bluetooth module.
- gap_set_local_name("PurePhone");
- gap_discoverable_control(1);
gap_set_class_of_device(0x200408);
// Register for HCI events.
@@ 330,6 339,7 @@ namespace bluetooth
bd_addr_to_str(address),
AVRCP::mediaTracker.a2dp_cid,
AVRCP::mediaTracker.local_seid);
+ isConnected = true;
break;
case A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION: {
@@ 458,8 468,6 @@ namespace bluetooth
LOG_ERROR("failed to create queue!");
}
- AVRCP::mediaTracker.stream_opened = 1;
- a2dp_source_start_stream(AVRCP::mediaTracker.a2dp_cid, AVRCP::mediaTracker.local_seid);
break;
case A2DP_SUBEVENT_STREAM_RECONFIGURED:
@@ 553,24 561,26 @@ namespace bluetooth
AVRCP::mediaTracker.a2dp_cid = 0;
LOG_INFO("A2DP Source: Signaling released.\n\n");
}
+ isConnected = false;
break;
default:
break;
}
}
- void A2DP::A2DPImpl::start()
+ void A2DP::A2DPImpl::connect()
{
- LOG_INFO("Starting playback to %s", bd_addr_to_str(deviceAddr));
- a2dp_source_establish_stream(deviceAddr, &AVRCP::mediaTracker.a2dp_cid);
+ if (!isConnected) {
+ LOG_INFO("Starting playback to %s", bd_addr_to_str(deviceAddr));
+ a2dp_source_establish_stream(deviceAddr, &AVRCP::mediaTracker.a2dp_cid);
+ }
}
- void A2DP::A2DPImpl::stop()
+ void A2DP::A2DPImpl::disconnect()
{
LOG_INFO("Stopping playback");
a2dp_source_disconnect(AVRCP::mediaTracker.a2dp_cid);
- l2cap_unregister_service(1);
- };
+ }
void A2DP::A2DPImpl::setDeviceAddress(bd_addr_t addr)
{
@@ 595,5 605,18 @@ namespace bluetooth
auto &busProxy = const_cast<sys::Service *>(ownerService)->bus;
busProxy.sendUnicast(std::move(msg), service::name::evt_manager);
}
+ void A2DP::A2DPImpl::start()
+ {
+ if (!isConnected) {
+ connect();
+ }
+ AVRCP::mediaTracker.stream_opened = 1;
+ a2dp_source_start_stream(AVRCP::mediaTracker.a2dp_cid, AVRCP::mediaTracker.local_seid);
+ }
+ void A2DP::A2DPImpl::stop()
+ {
+ AVRCP::mediaTracker.stream_opened = 1;
+ a2dp_source_pause_stream(AVRCP::mediaTracker.a2dp_cid, AVRCP::mediaTracker.local_seid);
+ }
} // namespace Bt
M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.hpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.hpp +2 -0
@@ 29,6 29,8 @@ namespace bluetooth
void connect() override;
void disconnect() override;
+ void start() override;
+ void stop() override;
private:
class A2DPImpl;
M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DPImpl.hpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DPImpl.hpp +3 -0
@@ 68,9 68,12 @@ namespace bluetooth
static void sendMediaPacket();
static auto fillSbcAudioBuffer(MediaContext *context) -> int;
static void sendAudioEvent(audio::EventType event, audio::Event::DeviceState state);
+ static bool isConnected;
public:
auto init() -> Error::Code;
+ void connect();
+ void disconnect();
void start();
void stop();
void setDeviceAddress(bd_addr_t addr);
M module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.cpp => module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.cpp +33 -9
@@ 8,6 8,7 @@
#include <log/log.hpp>
#include <service-evtmgr/Constants.hpp>
#include <service-audio/AudioMessage.hpp>
+#include <BluetoothWorker.hpp>
extern "C"
{
@@ 57,11 58,21 @@ namespace bluetooth
void HSP::connect()
{
- pimpl->start();
+ pimpl->connect();
}
void HSP::disconnect()
{
+ pimpl->disconnect();
+ }
+
+ void HSP::start()
+ {
+ pimpl->start();
+ }
+
+ void HSP::stop()
+ {
pimpl->stop();
}
@@ 74,6 85,7 @@ namespace bluetooth
std::unique_ptr<SCO> HSP::HSPImpl::sco;
const sys::Service *HSP::HSPImpl::ownerService;
std::string HSP::HSPImpl::agServiceName = "PurePhone HSP";
+ bool HSP::HSPImpl::isConnected = false;
void HSP::HSPImpl::sendAudioEvent(audio::EventType event, audio::Event::DeviceState state)
{
@@ 126,8 138,7 @@ namespace bluetooth
break;
}
LOG_DEBUG("RFCOMM connection established.\n");
- LOG_DEBUG("Establish Audio connection to %s...\n", bd_addr_to_str(deviceAddr));
- hsp_ag_establish_audio_connection();
+ isConnected = true;
break;
case HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE:
if (hsp_subevent_rfcomm_disconnection_complete_get_status(event) != 0u) {
@@ 148,13 159,14 @@ namespace bluetooth
scoHandle = hsp_subevent_audio_connection_complete_get_handle(event);
LOG_DEBUG("Audio connection established with SCO handle 0x%04x.\n", scoHandle);
hci_request_sco_can_send_now_event();
- btstack_run_loop_freertos_trigger();
+ RunLoop::trigger();
}
break;
case HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE:
LOG_DEBUG("Audio connection released.\n\n");
sendAudioEvent(audio::EventType::BlutoothHSPDeviceState, audio::Event::DeviceState::Disconnected);
scoHandle = HCI_CON_HANDLE_INVALID;
+ isConnected = false;
break;
case HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED:
LOG_DEBUG("Received microphone gain change %d\n", hsp_subevent_microphone_gain_changed_get_gain(event));
@@ 199,7 211,6 @@ namespace bluetooth
// register for SCO packets
hci_register_sco_packet_handler(&packetHandler);
- gap_set_local_name("PurePhone");
gap_discoverable_control(1);
gap_set_class_of_device(CLASS_OF_DEVICE);
@@ 208,14 219,15 @@ namespace bluetooth
return bluetooth::Error::Success;
}
- void HSP::HSPImpl::start()
+ void HSP::HSPImpl::connect()
{
- hsp_ag_connect(deviceAddr);
+ if (!isConnected) {
+ hsp_ag_connect(deviceAddr);
+ }
}
- void HSP::HSPImpl::stop()
+ void HSP::HSPImpl::disconnect()
{
- hsp_ag_release_audio_connection();
hsp_ag_disconnect();
}
@@ 234,5 246,17 @@ namespace bluetooth
{
return sco->getStreamData();
}
+ void HSP::HSPImpl::start()
+ {
+ if (!isConnected) {
+ connect();
+ }
+ LOG_DEBUG("Establish Audio connection to %s...\n", bd_addr_to_str(deviceAddr));
+ hsp_ag_establish_audio_connection();
+ }
+ void HSP::HSPImpl::stop()
+ {
+ hsp_ag_release_audio_connection();
+ }
} // namespace Bt
M module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.hpp => module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.hpp +5 -1
@@ 5,6 5,7 @@
#include "Profile.hpp"
#include <service-bluetooth/BluetoothMessage.hpp>
+#include <btstack_run_loop.h>
namespace bluetooth
{
@@ 29,11 30,14 @@ namespace bluetooth
void connect() override;
void disconnect() override;
+ void start() override;
+ void stop() override;
private:
class HSPImpl;
std::unique_ptr<HSPImpl> pimpl;
- const sys::Service *ownerService;
+ const sys::Service *ownerService{};
+ btstack_run_loop *runLoopInstance{};
};
} // namespace Bt
M module-bluetooth/Bluetooth/interface/profiles/HSP/HSPImpl.hpp => module-bluetooth/Bluetooth/interface/profiles/HSP/HSPImpl.hpp +3 -0
@@ 19,6 19,8 @@ namespace bluetooth
auto init() -> Error::Code;
void start();
void stop();
+ void connect();
+ void disconnect();
void setDeviceAddress(bd_addr_t addr);
void setOwnerService(const sys::Service *service);
auto getStreamData() -> std::shared_ptr<BluetoothStreamData>;
@@ 35,5 37,6 @@ namespace bluetooth
static std::array<char, commandBufferLength> ATcommandBuffer;
static bd_addr_t deviceAddr;
static const sys::Service *ownerService;
+ static bool isConnected;
};
} // namespace Bt
M module-bluetooth/Bluetooth/interface/profiles/Profile.hpp => module-bluetooth/Bluetooth/interface/profiles/Profile.hpp +2 -0
@@ 18,6 18,8 @@ namespace bluetooth
virtual void setOwnerService(const sys::Service *service) = 0;
virtual auto getStreamData() -> std::shared_ptr<BluetoothStreamData> = 0;
virtual void connect() = 0;
+ virtual void start() = 0;
+ virtual void stop() = 0;
virtual void disconnect() = 0;
};
A module-bluetooth/Bluetooth/interface/profiles/ProfileManager.cpp => module-bluetooth/Bluetooth/interface/profiles/ProfileManager.cpp +81 -0
@@ 0,0 1,81 @@
+#include <service-bluetooth/ServiceBluetooth.hpp>
+#include "ProfileManager.hpp"
+
+namespace bluetooth
+{
+
+ ProfileManager::ProfileManager(sys::Service *ownerService) : ownerService(ownerService)
+ {}
+
+ auto ProfileManager::init() -> Error::Code
+ {
+ if (!initialized) {
+ profilesList = {{AudioProfile::A2DP, std::make_shared<bluetooth::A2DP>()},
+ {AudioProfile::HSP, std::make_shared<bluetooth::HSP>()},
+ {AudioProfile::HFP, nullptr},
+ {AudioProfile::None, nullptr}};
+
+ for (auto &[profileName, ptr] : profilesList) {
+ if (ptr != nullptr) {
+ ptr->setOwnerService(ownerService);
+ ptr->init();
+ }
+ }
+ currentProfilePtr = profilesList[AudioProfile::A2DP].get();
+
+ if (auto serviceBt = dynamic_cast<ServiceBluetooth *>(ownerService); serviceBt != nullptr) {
+ serviceBt->profileManagerPtr = this;
+ }
+ initialized = true;
+ }
+ return Error::Success;
+ }
+
+ auto ProfileManager::connect(bd_addr_t address) -> Error::Code
+ {
+ bd_addr_copy(remoteAddr, address);
+ for (auto &[profileName, ptr] : profilesList) {
+ if (ptr != nullptr) {
+ ptr->setDeviceAddress(remoteAddr);
+ ptr->connect();
+ }
+ }
+ return Error::Success;
+ }
+
+ auto ProfileManager::disconnect() -> Error::Code
+ {
+ for (auto &[profileName, ptr] : profilesList) {
+ if (ptr != nullptr) {
+ ptr->disconnect();
+ }
+ }
+ return Error::Success;
+ }
+
+ auto ProfileManager::switchProfile(AudioProfile profile) -> Error::Code
+ {
+ if (profilesList[profile] == nullptr) {
+ LOG_ERROR("Invalid profile!");
+ return Error::SystemError;
+ }
+ if (currentProfilePtr == profilesList[profile].get()) {
+ return Error::Success;
+ }
+ stop();
+ currentProfilePtr = profilesList[profile].get();
+ start();
+ return Error::Success;
+ }
+ auto ProfileManager::start() -> Error::Code
+ {
+ currentProfilePtr->start();
+ return Error::Success;
+ }
+ auto ProfileManager::stop() -> Error::Code
+ {
+ currentProfilePtr->stop();
+ return Error::Success;
+ }
+
+} // namespace bluetooth
A module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp => module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp +51 -0
@@ 0,0 1,51 @@
+#pragma once
+
+#include <Service/Service.hpp>
+#include <Error.hpp>
+#include "Profile.hpp"
+#include "interface/profiles/A2DP/A2DP.hpp"
+#include "interface/profiles/HSP/HSP.hpp"
+
+extern "C"
+{
+#include <bluetooth.h>
+#include "btstack_util.h"
+}
+
+namespace bluetooth
+{
+
+ enum class AudioProfile
+ {
+ A2DP,
+ HSP,
+ HFP,
+ None
+ };
+
+ using ProfileList = std::map<AudioProfile, std::shared_ptr<bluetooth::Profile>>;
+
+ class ProfileManager
+ {
+ public:
+ explicit ProfileManager(sys::Service *ownerService);
+
+ auto init() -> Error::Code;
+
+ auto connect(bd_addr_t address) -> Error::Code;
+
+ auto disconnect() -> Error::Code;
+
+ auto switchProfile(AudioProfile profile) -> Error::Code;
+
+ auto start() -> Error::Code;
+ auto stop() -> Error::Code;
+
+ private:
+ sys::Service *ownerService;
+ ProfileList profilesList;
+ bluetooth::Profile *currentProfilePtr = nullptr;
+ bd_addr_t remoteAddr{};
+ bool initialized = false;
+ };
+} // namespace bluetooth
M module-bluetooth/CMakeLists.txt => module-bluetooth/CMakeLists.txt +3 -1
@@ 15,7 15,9 @@ set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/A2DP/AVDTP.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/HSP/HSP.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/HSP/SCO.cpp
-)
+ ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/ProfileManager.cpp
+
+ )
message("Build with BlueKitchen")
include(lib/btstack.cmake)
M module-services/service-bluetooth/ServiceBluetooth.cpp => module-services/service-bluetooth/ServiceBluetooth.cpp +17 -12
@@ 25,7 25,7 @@
#include <BtCommand.hpp>
#include <BtKeysStorage.hpp>
-ServiceBluetooth::ServiceBluetooth() : sys::Service(service::name::bluetooth)
+ServiceBluetooth::ServiceBluetooth() : sys::Service(service::name::bluetooth, "", 4096)
{
auto settings = std::make_unique<settings::Settings>(this);
settingsHolder = std::make_shared<bluetooth::SettingsHolder>(std::move(settings));
@@ 93,8 93,9 @@ sys::ReturnCodes ServiceBluetooth::InitHandler()
connect(typeid(BluetoothPairMessage), [&](sys::Message *msg) {
auto pairMsg = static_cast<BluetoothPairMessage *>(msg);
- auto addr = pairMsg->addr;
-
+ const auto addrString = pairMsg->addr;
+ bd_addr_t addr;
+ sscanf_bd_addr(addrString.c_str(), addr);
sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::Pair, addr));
return sys::MessageNone{};
});
@@ 175,11 176,18 @@ sys::MessagePointer ServiceBluetooth::DataReceivedHandler(sys::DataMessage *msg,
} break;
case BluetoothMessage::Play:
- sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::ConnectAudio));
+ sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::StartStream));
+ break;
+ case BluetoothMessage::SwitchProfile:
+ sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::SwitchProfile));
+
break;
- case BluetoothMessage::StopPlayback:
+ case BluetoothMessage::Disconnect:
sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::DisconnectAudio));
break;
+ case BluetoothMessage::Stop:
+ sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::StopStream));
+ break;
default:
break;
@@ 188,13 196,10 @@ sys::MessagePointer ServiceBluetooth::DataReceivedHandler(sys::DataMessage *msg,
}
case MessageType::BluetoothAddrResult: {
auto addrMsg = static_cast<BluetoothAddrMessage *>(msg);
- worker->setDeviceAddress(addrMsg->addr);
- } break;
- case MessageType::BluetoothRequestStream: {
- auto result =
- std::make_shared<BluetoothRequestStreamResultMessage>(worker->currentProfile->getStreamData());
- bus.sendUnicast(std::move(result), "ServiceAudio");
- LOG_INFO("Queues sent after a request!");
+ std::string addrString{bd_addr_to_str(addrMsg->addr)};
+ LOG_INFO("Connecting with %s", addrString.c_str());
+ sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::ConnectAudio, addrMsg->addr));
+
} break;
default:
break;
M module-services/service-bluetooth/service-bluetooth/BluetoothMessage.hpp => module-services/service-bluetooth/service-bluetooth/BluetoothMessage.hpp +3 -1
@@ 37,7 37,9 @@ class BluetoothMessage : public sys::DataMessage
PAN,
Visible,
Play,
- StopPlayback
+ SwitchProfile,
+ Stop,
+ Disconnect
};
enum Request req = Request::None;
BluetoothMessage(enum Request req = None) : sys::DataMessage(MessageType::BluetoothRequest), req(req){};
M module-services/service-bluetooth/service-bluetooth/ServiceBluetooth.hpp => module-services/service-bluetooth/service-bluetooth/ServiceBluetooth.hpp +2 -0
@@ 12,6 12,7 @@
#include <service-audio/ServiceAudio.hpp>
#include <module-bluetooth/Bluetooth/CommandHandler.hpp>
#include "BluetoothMessage.hpp"
+#include "ProfileManager.hpp"
#include <memory> // for unique_ptr
@@ 35,6 36,7 @@ class ServiceBluetooth : public sys::Service
void sendWorkerCommand(bluetooth::Command command);
QueueHandle_t workerQueue = nullptr;
std::shared_ptr<bluetooth::SettingsHolder> settingsHolder;
+ bluetooth::ProfileManager *profileManagerPtr = nullptr;
void scanStartedCallback();
void scanStoppedCallback();