./src/bt-hal-hidhost.c
./src/bt-hal-av.c
./src/bt-hal-av-dbus-handler.c
+./src/bt-hal-a2dp-sink.c
+./src/bt-hal-a2dp-sink-dbus-handler.c
./src/bt-hal-hf.c
./src/bt-hal-hf-dbus-handler.c
./src/bt-hal-hid-dbus-handler.c
uint8_t channel_count;
} __attribute__((packed));
+/* A2DP Sink Role connection*/
+#define HAL_EV_A2DP_SOURCE_CONN_STATE 0x8F
+
/* HandsFree Headers */
#define HAL_EV_HANDSFREE_CONN_STATE_DISCONNECTED 0x00
#define HAL_EV_HANDSFREE_CONN_STATE_CONNECTING 0x01
--- /dev/null
+/*
+ * Bluetooth HAL
+ *
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Nilesh Trimbake <t.shripati@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <dlog.h>
+#include <vconf.h>
+
+#include "bt-hal-a2dp-sink-dbus-handler.h"
+#include "bt-hal-dbus-common-utils.h"
+#include "bt-hal-internal.h"
+
+
+static handle_stack_msg event_cb = NULL;
+
+/* To send stack event to hal-a2dp-sink handler */
+void _bt_hal_register_a2dp_sink_dbus_handler_cb(handle_stack_msg cb)
+{
+ event_cb = cb;
+}
+
+/* To send stack event to hal-a2dp-sink handler */
+void _bt_hal_unregister_a2dp_sink_dbus_handler_cb()
+{
+ event_cb = NULL;
+}
+
+static void __bt_a2dp_sink_connect_cb(GDBusProxy *proxy, GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *g_error = NULL;
+ struct hal_ev_a2dp_conn_state ev;
+ GVariant *reply = NULL;
+ char *address = user_data;
+ int result = BT_STATUS_SUCCESS;
+
+ DBG("+");
+
+ reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
+ g_object_unref(proxy);
+ if (reply == NULL) {
+ ERR("A2DP Source Connect Dbus Call Error");
+ if (g_error) {
+ ERR("Error: %s\n", g_error->message);
+ g_clear_error(&g_error);
+ }
+ result = BT_STATUS_FAIL;
+ }
+ g_variant_unref(reply);
+
+ DBG("Address: %s", address);
+ /*
+ * If result is success, Send connecting event
+ */
+ if (result == BT_STATUS_SUCCESS) {
+ /* Prepare to send A2DP Source connecting event */
+ memset(&ev, 0, sizeof(ev));
+ _bt_convert_addr_string_to_type(ev.bdaddr, address);
+ ev.state = HAL_EV_A2DP_STATE_CONNECTING;
+ if (!event_cb)
+ ERR("A2DP SINK DBUS handler callback not registered");
+ else
+ event_cb(HAL_EV_A2DP_SOURCE_CONN_STATE, (void *)&ev, sizeof(ev));
+ } else {
+ /* Prepare to send A2DP Source disconnected event */
+ memset(&ev, 0, sizeof(ev));
+ _bt_convert_addr_string_to_type(ev.bdaddr, address);
+ ev.state = HAL_EV_A2DP_STATE_DISCONNECTED;
+ if (!event_cb)
+ ERR("A2DP SINK DBUS handler callback not registered");
+ else
+ event_cb(HAL_EV_A2DP_SOURCE_CONN_STATE, (void *)&ev, sizeof(ev));
+ }
+ g_free(address);
+}
+
+bt_status_t _bt_hal_dbus_handler_a2dp_sink_connect(bt_bdaddr_t *bd_addr)
+{
+ char *address;
+ GDBusConnection *conn;
+
+ int ret;
+
+ if(!bd_addr) {
+ ERR("bd_addr is NULL, return");
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ conn = _bt_get_system_gconn();
+ if(!conn) {
+ ERR("_bt_get_system_gconn returned NULL, return");
+ return BT_STATUS_FAIL;
+ }
+
+ address = g_malloc0(BT_HAL_ADDRESS_STRING_SIZE * sizeof(char));
+ if (!address) {
+ ERR("Memory allocation failed");
+ return BT_STATUS_NOMEM;
+ }
+ _bt_convert_addr_type_to_string(address, bd_addr->address);
+
+ ret = _bt_connect_profile(address, A2DP_SOURCE_UUID,
+ __bt_a2dp_sink_connect_cb, address);
+
+ if (ret != BT_HAL_ERROR_NONE) {
+ ERR("_bt_connect_profile(A2DP source) Error");
+ return BT_STATUS_FAIL;
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+static void __bt_a2dp_source_disconnect_cb(GDBusProxy *proxy, GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *g_error = NULL;
+ struct hal_ev_a2dp_conn_state ev;
+ GVariant *reply = NULL;
+ char *address = user_data;
+ int result = BT_STATUS_SUCCESS;
+
+ DBG("+");
+
+ reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
+ g_object_unref(proxy);
+ if (reply == NULL) {
+ ERR("A2DP Source Disconnect Dbus Call Error");
+ if (g_error) {
+ ERR("Error: %s\n", g_error->message);
+ g_clear_error(&g_error);
+ }
+ result = BT_STATUS_FAIL;
+ }
+ g_variant_unref(reply);
+
+ if (result != BT_STATUS_FAIL)
+ DBG("A2DP Source Disconnect successful for Device: %s", address);
+ else
+ DBG("A2DP Source Disconnect un-successful for Device: %s", address);
+ if (result == BT_STATUS_FAIL) {
+ /* Prepare to send AV source disconnected state event */
+ memset(&ev, 0, sizeof(ev));
+ _bt_convert_addr_string_to_type(ev.bdaddr, address);
+ ev.state = HAL_EV_A2DP_STATE_DISCONNECTED;
+ if (!event_cb)
+ ERR("A2DP SINK DBUS handler callback not registered");
+ else
+ event_cb(HAL_EV_A2DP_SOURCE_CONN_STATE, (void *)&ev, sizeof(ev));
+ } else {
+ /* Prepare to send AV source disconnecting state event */
+ memset(&ev, 0, sizeof(ev));
+ _bt_convert_addr_string_to_type(ev.bdaddr, address);
+ ev.state = HAL_EV_A2DP_STATE_DISCONNECTING;
+ if (!event_cb)
+ ERR("A2DP SINK DBUS handler callback not registered");
+ else
+ event_cb(HAL_EV_A2DP_SOURCE_CONN_STATE, (void *)&ev, sizeof(ev));
+ }
+ g_free(address);
+ DBG("-");
+}
+
+bt_status_t _bt_hal_dbus_handler_a2dp_sink_disconnect(bt_bdaddr_t *bd_addr)
+{
+ char *address;
+ GDBusConnection *conn;
+
+ int ret;
+
+ if(!bd_addr) {
+ ERR("bd_addr is NULL, return");
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ conn = _bt_get_system_gconn();
+ if(!conn) {
+ ERR("_bt_get_system_gconn returned NULL, return");
+ return BT_STATUS_FAIL;
+ }
+
+ address = g_malloc0(BT_HAL_ADDRESS_STRING_SIZE * sizeof(char));
+ if (!address) {
+ ERR("Memory allocation failed");
+ return BT_STATUS_NOMEM;
+ }
+ _bt_convert_addr_type_to_string(address, bd_addr->address);
+
+ ret = _bt_disconnect_profile(address, A2DP_SOURCE_UUID,
+ __bt_a2dp_source_disconnect_cb, address);
+
+ if (ret != BT_HAL_ERROR_NONE) {
+ ERR("_bt_connect_profile(AV) Error");
+ return BT_STATUS_FAIL;
+ }
+
+ return BT_STATUS_SUCCESS;
+}
--- /dev/null
+/* Bluetooth HAL
+ *
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Nilesh Trimbake <t.shripati@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#ifndef _BT_HAL_A2DP_SINK_DBUS_HANDLER_H_
+#define _BT_HAL_A2DP_SINK_DBUS_HANDLER_H_
+
+#include <glib.h>
+#include <sys/types.h>
+
+#include "bt-hal.h"
+#include "bt-hal-log.h"
+#include "bt-hal-msg.h"
+
+#include "bt-hal-event-receiver.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void _bt_hal_register_a2dp_sink_dbus_handler_cb(handle_stack_msg cb);
+
+void _bt_hal_unregister_a2dp_sink_dbus_handler_cb();
+
+bt_status_t _bt_hal_dbus_handler_a2dp_sink_connect(bt_bdaddr_t *bd_addr);
+
+bt_status_t _bt_hal_dbus_handler_a2dp_sink_disconnect(bt_bdaddr_t *bd_addr);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _BT_HAL_A2DP_SINK_DBUS_HANDLER_H_*/
--- /dev/null
+/*
+ * Bluetooth HAL
+ *
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Nilesh Trimbake <t.shripati@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dlog.h>
+
+#include "bt-hal.h"
+#include "bt-hal-log.h"
+#include "bt-hal-msg.h"
+#include "bt-hal-utils.h"
+#include "bt-hal-a2dp-sink-dbus-handler.h"
+
+static const btav_callbacks_t *bt_hal_a2dp_sink_cbacks;
+
+static bool interface_ready(void)
+{
+ return bt_hal_a2dp_sink_cbacks != NULL;
+}
+
+static bt_status_t a2dp_sink_connect(bt_bdaddr_t *bd_addr)
+{
+ DBG("");
+ return _bt_hal_dbus_handler_a2dp_sink_connect(bd_addr);
+}
+
+static bt_status_t a2dp_sink_disconnect(bt_bdaddr_t *bd_addr)
+{
+ DBG("");
+ return _bt_hal_dbus_handler_a2dp_sink_disconnect(bd_addr);
+}
+
+static void __bt_hal_handle_a2dp_sink_conn_state(void *buf, uint16_t len)
+{
+ struct hal_ev_a2dp_conn_state *ev = buf;
+
+ if (bt_hal_a2dp_sink_cbacks->connection_state_cb)
+ bt_hal_a2dp_sink_cbacks->connection_state_cb(ev->state, (bt_bdaddr_t *) ev->bdaddr);
+}
+
+static void __bt_hal_handle_a2dp_sink_audio_conn_state(void *buf, uint16_t len)
+{
+ struct hal_ev_a2dp_audio_state *ev = buf;
+
+ if (bt_hal_a2dp_sink_cbacks->audio_state_cb)
+ bt_hal_a2dp_sink_cbacks->audio_state_cb(ev->state, (bt_bdaddr_t *) ev->bdaddr);
+}
+
+static void __bt_hal_handle_a2dp_sink_events(int message, void *buf, uint16_t len)
+{
+ DBG("+");
+ if (!interface_ready())
+ return;
+ switch(message) {
+ case HAL_EV_A2DP_SOURCE_CONN_STATE:
+ DBG("Event: HAL_EV_A2DP_SOURCE_CONN_STATE");
+ __bt_hal_handle_a2dp_sink_conn_state(buf, len);
+ break;
+ case HAL_EV_A2DP_AUDIO_STATE:
+ DBG("Event: HAL_EV_A2DP_AUDIO_STATE");
+ __bt_hal_handle_a2dp_sink_audio_conn_state(buf, len);
+ break;
+ default:
+ DBG("Event Currently not handled!!");
+ break;
+ }
+ DBG("-");
+}
+
+static bt_status_t init(btav_callbacks_t* callbacks)
+{
+ DBG("");
+
+ if (interface_ready())
+ return BT_STATUS_DONE;
+
+ bt_hal_a2dp_sink_cbacks = callbacks;
+ DBG("Register A2DP Sink events callback function");
+ _bt_hal_register_a2dp_sink_dbus_handler_cb(__bt_hal_handle_a2dp_sink_events);
+ _bt_hal_register_a2dp_sink_event_handler_cb(__bt_hal_handle_a2dp_sink_events);
+ return BT_STATUS_SUCCESS;
+}
+
+static void cleanup(void)
+{
+ DBG("");
+
+ if (!interface_ready())
+ return;
+
+ bt_hal_a2dp_sink_cbacks = NULL;
+ _bt_hal_unregister_a2dp_sink_event_handler_cb();
+}
+
+static btav_interface_t a2dp_sink_if = {
+ .size = sizeof(a2dp_sink_if),
+ .init = init,
+ .connect = a2dp_sink_connect,
+ .disconnect = a2dp_sink_disconnect,
+ .cleanup = cleanup
+};
+
+btav_interface_t *bt_get_a2dp_sink_interface(void)
+{
+ DBG("Get A2DP Sink Profile Interface");
+ return &a2dp_sink_if;
+}
--- /dev/null
+/*
+ * Bluetooth HAL
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Nilesh Trimbake <t.shripati@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __BT_HAL_A2DP_SINK_H__
+#define __BT_HAL_A2DP_SINK_H__
+
+#include <stdint.h>
+#include <glib.h>
+#include <unistd.h>
+#include <dlog.h>
+#include <stdio.h>
+
+btav_interface_t *bt_get_a2dp_sink_interface(void);
+
+#endif //__BT_HAL_A2DP_SINK_H__
#include <bt-hal-av.h>
#include <bt-hal-hf.h>
#include <bt-hal-hdp.h>
+#include <bt-hal-a2dp-sink.h>
#define enum_prop_to_hal(prop, hal_prop, type) do { \
static type e; \
return NULL;
if (!strcmp(profile_id, BT_PROFILE_ADVANCED_AUDIO_SINK_ID))
- return NULL;
+ return bt_get_a2dp_sink_interface();
return NULL;
}
static handle_stack_msg event_cb = NULL;
static handle_stack_msg hid_event_cb = NULL;
static handle_stack_msg av_event_cb = NULL;
+static handle_stack_msg a2dp_sink_event_cb = NULL;
static handle_stack_msg hf_event_cb = NULL;
static guint event_id;
static void __bt_hal_send_device_acl_connection_state_event(gboolean connected, const char *address);
static void __bt_hal_handle_input_event(GVariant *msg, const char *path);
static void __bt_hal_send_av_connection_state_event(gboolean connected, const char *address);
+static void __bt_hal_send_a2dp_sink_connection_state_event(gboolean connected, const char *address);
static void __bt_hal_send_device_trust_state_event(gboolean is_trusted, const char *address);
static int __bt_hal_register_audio_subscribe_signal(GDBusConnection *conn, int subscribe);
} else {
ERR("A2DP Profile state: Invalid");
}
+ } else if ((strncmp(profile_uuid, A2DP_SOURCE_UUID, strlen(A2DP_SOURCE_UUID)) == 0)) {
+ if (state == BT_HAL_PROFILE_STATE_CONNECTED) {
+ DBG("A2DP Sink Profile state changed: BT_HAL_PROFILE_STATE_CONNECTED");
+ __bt_hal_send_a2dp_sink_connection_state_event(TRUE, address);
+ } else if (state == BT_HAL_PROFILE_STATE_DISCONNECTED) {
+ DBG("A2DP Sink Profile state changed: BT_HAL_PROFILE_STATE_DISCONNECTED");
+ __bt_hal_send_a2dp_sink_connection_state_event(FALSE, address);
+ } else if (state == BT_HAL_PROFILE_STATE_DISCONNECTING) {
+ DBG("A2DP Sink Profile state changed: BT_HAL_PROFILE_STATE_DISCONNECTING");
+ } else if (state == BT_HAL_PROFILE_STATE_CONNECTING) {
+ DBG("A2DP Sink Profile state changed: BT_HAL_PROFILE_STATE_CONNECTING");
+ }
} else if (strncmp(profile_uuid, HFP_HF_UUID, strlen(HFP_HF_UUID)) == 0) {
if (state == BT_HAL_PROFILE_STATE_CONNECTING)
DBG("HFP Profile state changed: BT_PROFILE_STATE_CONNECTING");
av_event_cb = NULL;
}
-/* HF(AG Role) Events */
-void _bt_hal_register_hf_event_handler_cb(handle_stack_msg cb)
+static void __bt_hal_send_av_connection_state_event(gboolean connected, const char *address)
{
- hf_event_cb = cb;
+ DBG("+");
+ struct hal_ev_a2dp_conn_state ev;
+
+ if (connected == TRUE)
+ INFO("A2DP(Src) Profile Connected for address [%s]", address);
+ else
+ INFO("A2DP(Src) Profile DisConnected for address [%s]", address);
+
+ ev.state = (connected == TRUE) ?
+ HAL_EV_A2DP_STATE_CONNECTED :
+ HAL_EV_A2DP_STATE_DISCONNECTED;
+
+ _bt_convert_addr_string_to_type(ev.bdaddr, address);
+
+ if (!av_event_cb)
+ ERR("AV event handler not registered");
+ else
+ av_event_cb(HAL_EV_A2DP_CONN_STATE, &ev, sizeof(ev));
}
-void _bt_hal_unregister_hf_event_handler_cb()
+/* A2DP Sink Role(Remote:Source) Events */
+void _bt_hal_register_a2dp_sink_event_handler_cb(handle_stack_msg cb)
{
- hf_event_cb = NULL;
+ a2dp_sink_event_cb = cb;
}
-static void __bt_hal_send_av_connection_state_event(gboolean connected, const char *address)
+void _bt_hal_unregister_a2dp_sink_event_handler_cb(void)
+{
+ a2dp_sink_event_cb = NULL;
+}
+
+static void __bt_hal_send_a2dp_sink_connection_state_event(gboolean connected, const char *address)
{
DBG("+");
struct hal_ev_a2dp_conn_state ev;
if (connected == TRUE)
- INFO("A2DP(Src) Profile Connected for address [%s]", address);
+ INFO("A2DP(Sink) Profile Connected for address [%s]", address);
else
- INFO("A2DP(Src) Profile DisConnected for address [%s]", address);
+ INFO("A2DP(Sink) Profile DisConnected for address [%s]", address);
ev.state = (connected == TRUE) ?
HAL_EV_A2DP_STATE_CONNECTED :
_bt_convert_addr_string_to_type(ev.bdaddr, address);
- if (!av_event_cb)
+ if (!a2dp_sink_event_cb)
ERR("AV event handler not registered");
else
- av_event_cb(HAL_EV_A2DP_CONN_STATE, &ev, sizeof(ev));
+ a2dp_sink_event_cb(HAL_EV_A2DP_SOURCE_CONN_STATE, &ev, sizeof(ev));
+}
+
+/* HF(AG Role) Events */
+void _bt_hal_register_hf_event_handler_cb(handle_stack_msg cb)
+{
+ hf_event_cb = cb;
+}
+
+void _bt_hal_unregister_hf_event_handler_cb()
+{
+ hf_event_cb = NULL;
}
static void __bt_hal_send_hf_audio_connection_state_event(gboolean connected,
void _bt_hal_unregister_av_event_handler_cb();
+/* A2DP(SINK Role) Events */
+void _bt_hal_register_a2dp_sink_event_handler_cb(handle_stack_msg cb);
+
+void _bt_hal_unregister_a2dp_sink_event_handler_cb(void);
+
/* HF(AG Role) Events*/
void _bt_hal_register_hf_event_handler_cb(handle_stack_msg cb);
/* UUIDs */
#define HID_UUID "00001124-0000-1000-8000-00805f9b34fb"
#define A2DP_SINK_UUID "0000110b-0000-1000-8000-00805f9b34fb"
+#define A2DP_SOURCE_UUID "0000110a-0000-1000-8000-00805f9b34fb"
#define HFP_HF_UUID "0000111e-0000-1000-8000-00805f9b34fb"
/* TODO More declarations to be added in subsequent patches */
service_id = BT_A2DP_SERVICE_ID;
else if (!strcasecmp(uuid, BT_HAL_A2DP_PROFILE_UUID))
service_id = BT_A2DP_SERVICE_ID;
+ else if (!strcasecmp(uuid, BT_HAL_A2DP_SOURCE_UUID))
+ service_id = BT_A2DP_SRC_SERVICE_ID;
else if (!strcasecmp(uuid, BT_HAL_AVRCP_TARGET_UUID))
service_id = BT_AVRCP_SERVICE_ID;
else if (!strcasecmp(uuid, BT_HAL_AVRCP_REMOTE_UUID))