From 1332cc7d0a618ee88b4d19813340665332d406ca Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Mon, 28 Feb 2022 13:04:45 -0500 Subject: Add Bluetooth media control support Rework to expose Bluetooth AVRCP media control in the Bluetooth class, and use that support to implement a Bluetooth backend in the Mediaplayer class. This replaces the scheme that existed with the agl-service-mediaplayer binding where it abstracted away the Bluetooth support itself. However, care has been take to make sure that the exposed API to users of libqtappfw-mediaplayer has not changed. Bug-AGL: SPEC-4231 Signed-off-by: Scott Murray Change-Id: I76b4f75621ce0121364eea3259b074bf3067ee88 --- bluetooth/bluetootheventhandler.cpp | 142 +++++++++++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 3 deletions(-) (limited to 'bluetooth/bluetootheventhandler.cpp') diff --git a/bluetooth/bluetootheventhandler.cpp b/bluetooth/bluetootheventhandler.cpp index 0acd5f5..a0154bb 100644 --- a/bluetooth/bluetootheventhandler.cpp +++ b/bluetooth/bluetootheventhandler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Konsulko Group + * Copyright (C) 2021,2022 Konsulko Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,20 +16,27 @@ #include #include - #include "bluetootheventhandler.h" #include "bluetooth.h" #include "bluetoothmodel.h" +#undef BLUETOOTH_EVENT_DEBUG + -BluetoothEventHandler::BluetoothEventHandler (Bluetooth *parent, bool register_agent) : +BluetoothEventHandler::BluetoothEventHandler(Bluetooth *parent, bool register_agent, bool handle_media) : m_parent(parent), m_agent(register_agent) { bluez_add_adapter_event_callback(adapter_event_cb, this); bluez_add_device_event_callback(device_event_cb, this); + if (register_agent) bluez_add_agent_event_callback(agent_event_cb, this); + + if (handle_media) { + bluez_add_media_control_event_callback(media_control_event_cb, this); + bluez_add_media_player_event_callback(media_player_event_cb, this); + } } BluetoothEventHandler::~BluetoothEventHandler() @@ -38,6 +45,10 @@ BluetoothEventHandler::~BluetoothEventHandler() void BluetoothEventHandler::handle_init_event(gchar *adapter, gboolean status) { +#ifdef BLUETOOTH_EVENT_DEBUG + qDebug() << "BluetoothEventHandler::handle_init_event: enter, status = " << (int) status; +#endif + if (status) m_parent->init_adapter_state(QString(adapter)); else @@ -48,6 +59,15 @@ void BluetoothEventHandler::handle_adapter_event(gchar *adapter, bluez_event_t event, GVariant *properties) { +#ifdef BLUETOOTH_EVENT_DEBUG + qDebug() << "BluetoothEventHandler::handle_adapter_event: enter"; + gchar *p = properties ? g_variant_print(properties, TRUE) : g_strdup("(null)"); + qDebug() << "BluetoothEventHandler::handle_adapter_event: adapter = " + << adapter << ", event = " << (int) event; + qDebug() << "BluetoothEventHandler::handle_adapter_event: properties = " << p; + g_free(p); +#endif + if (!adapter || event != BLUEZ_EVENT_CHANGE) return; @@ -71,6 +91,15 @@ void BluetoothEventHandler::handle_device_event(gchar *adapter, bluez_event_t event, GVariant *properties) { +#ifdef BLUETOOTH_EVENT_DEBUG + qDebug() << "BluetoothEventHandler::handle_device_event: enter"; + gchar *p = properties ? g_variant_print(properties, TRUE) : g_strdup("(null)"); + qDebug() << "BluetoothEventHandler::handle_device_event: adapter = " + << adapter << ", device = " << device << ", event = " << (int) event; + qDebug() << "BluetoothEventHandler::handle_device_event: properties = " << p; + g_free(p); +#endif + if (!device) return; @@ -91,6 +120,72 @@ void BluetoothEventHandler::handle_device_event(gchar *adapter, // device not previously in model m_parent->m_bluetooth->addDevice(new_device); } + + // Update parent's connected state + // NOTE: Currently not worrying about multiple devices being connected + GVariantDict *props_dict = g_variant_dict_new(properties); + if (props_dict) { + gboolean connected = FALSE; + if (g_variant_dict_lookup(props_dict, "Connected", "b", &connected)) { + m_parent->update_connected_state(QString(device), connected); + } + g_variant_dict_unref(props_dict); + } +} + +void BluetoothEventHandler::handle_media_control_event(gchar *adapter, + gchar *device, + bluez_event_t event, + GVariant *properties) +{ +#ifdef BLUETOOTH_EVENT_DEBUG + qDebug() << "BluetoothEventHandler::handle_media_control_event: enter"; + gchar *p = properties ? g_variant_print(properties, TRUE) : g_strdup("(null)"); + qDebug() << "BluetoothEventHandler::handle_media_control_event: adapter = " + << adapter << ", device = " << device << ", event = " << (int) event; + qDebug() << "BluetoothEventHandler::handle_media_control_event: properties = " << p; + g_free(p); +#endif + + if (event != BLUEZ_EVENT_CHANGE) + return; + + // Update parent's media connected state + // NOTE: Currently not worrying about multiple devices being connected + GVariantDict *props_dict = g_variant_dict_new(properties); + if (props_dict) { + gboolean connected = FALSE; + if (g_variant_dict_lookup(props_dict, "Connected", "b", &connected)) { + m_parent->update_media_connected_state(connected); + } + g_variant_dict_unref(props_dict); + } + +} + +void BluetoothEventHandler::handle_media_player_event(gchar *adapter, + gchar *device, + gchar *player, + bluez_event_t event, + GVariant *properties) +{ +#ifdef BLUETOOTH_EVENT_DEBUG + qDebug() << "BluetoothEventHandler::handle_media_player_event: enter"; + gchar *p = properties ? g_variant_print(properties, TRUE) : g_strdup("(null)"); + qDebug() << "BluetoothEventHandler::handle_media_player_event: adapter = " + << adapter << ", device = " << device << ", player = " << player + << ", event = " << (int) event; + qDebug() << "BluetoothEventHandler::handle_media_player_event: properties = " << p; + g_free(p); +#endif + + if (event != BLUEZ_EVENT_REMOVE) { + QVariantMap tmp; + parse_media_player_properties(properties, tmp); + if (!tmp.empty()) { + m_parent->update_media_properties(tmp); + } + } } void BluetoothEventHandler::handle_agent_event(gchar *device, @@ -119,3 +214,44 @@ void BluetoothEventHandler::handle_pair_event(gchar *device, gboolean status) qDebug() << "pairing failed"; } +void BluetoothEventHandler::parse_media_player_properties(GVariant *properties, QVariantMap &metadata) +{ + GVariantDict *props_dict = g_variant_dict_new(properties); + if (!props_dict) + return; + + GVariant *v = NULL; + if (g_variant_dict_lookup(props_dict, "Track", "@a{sv}", &v)) { + GVariantDict *track_dict = g_variant_dict_new(v); + QVariantMap track; + gchar *p = NULL; + + if (g_variant_dict_lookup(track_dict, "Title", "&s", &p)) + track.insert(QString("title"), QVariant(QString(p))); + + if (g_variant_dict_lookup(track_dict, "Artist", "&s", &p)) + track.insert(QString("artist"), QVariant(QString(p))); + + if (g_variant_dict_lookup(track_dict, "Album", "&s", &p)) + track.insert(QString("album"), QVariant(QString(p))); + + unsigned int duration = 0; + if (g_variant_dict_lookup(track_dict, "Duration", "u", &duration)) + track.insert(QString("duration"), QVariant(duration)); + + g_variant_dict_unref(track_dict); + + metadata.insert("track", track); + } + + unsigned int position = 0; + if (g_variant_dict_lookup(props_dict, "Position", "u", &position)) { + metadata.insert("position", QVariant(position)); + } + + gchar *p = NULL; + if (g_variant_dict_lookup(props_dict, "Status", "&s", &p)) + metadata.insert(QString("status"), QVariant(QString(p))); + + g_variant_dict_unref(props_dict); +} -- cgit 1.2.3-korg