oal-hfp.c
oal-hdp.c
oal-gatt.c
+oal-hf-client.c
common/oal-utils.c
common/oal-common.c
common/oal-event-dispatcher.c
./src/bt-hal-gatt.c
./src/bt-hal-gatt-server.c
./src/bt-hal-gatt-client.c
+./src/bt-hal-hf-client.c
+./src/bt-hal-hf-client-dbus-handler.c
)
SET(PREFIX ${CMAKE_INSTALL_PREFIX})
int32_t mtu;
} __attribute__((packed));
+/* HF Client Headers */
+#define HAL_EV_HF_CLIENT_CONN_STATE_DISCONNECTED 0x00
+#define HAL_EV_HF_CLIENT_CONN_STATE_CONNECTING 0x01
+#define HAL_EV_HF_CLIENT_CONN_STATE_CONNECTED 0x02
+#define HAL_EV_HF_CLIENT_CONN_STATE_SLC_CONNECTED 0x03
+#define HAL_EV_HF_CLIENT_CONN_STATE_DISCONNECTING 0x04
+
+#define HAL_EV_HF_CLIENT_CONN_STATE 0xCD
+struct hal_ev_hf_client_conn_state {
+ uint8_t state;
+ uint8_t bdaddr[6];
+} __attribute__((packed));
#endif //_BT_HAL_MSG_H_
#include <hardware/bt_sock.h>
#include <hardware/bt_hl.h>
#include <hardware/bt_rc.h>
+#include <hardware/bt_hf_client.h>
/*TODO: Profile interfaces headers and exposed methods of Android HAL framework to be included in next patches */
#endif //_BT_HAL_H
#include <bt-hal-adapter-le.h>
#include <bt-hal-agent.h>
#endif
+#include <bt-hal-hf-client.h>
#define enum_prop_to_hal(prop, hal_prop, type) do { \
static type e; \
if (!strcmp(profile_id, BT_PROFILE_HANDSFREE_ID))
return bt_get_hf_interface();
+ if (!strcmp(profile_id, BT_PROFILE_HANDSFREE_CLIENT_ID))
+ return bt_get_hf_client_interface();
+
if (!strcmp(profile_id, BT_PROFILE_GATT_ID))
return bt_get_gatt_interface();
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 handle_stack_msg hf_client_event_cb = NULL;
static handle_stack_msg avrcp_ctrl_event_cb = NULL;
static handle_stack_msg avrcp_tg_event_cb = NULL;
static handle_stack_msg gatt_event_cb = NULL;
static void __bt_hal_send_device_trusted_profile_changed_event(uint32_t trust_val, const char *address);
static void __bt_hal_handle_adv_report(GVariant *msg, const char *path);
static void __bt_hal_handle_gatts_mtu_changed_event(char *address, int mtu);
+static void __bt_hal_send_hf_client_connection_state_event(gboolean connected, const char *address);
static gboolean __bt_hal_discovery_finished_cb(gpointer user_data)
if (flight_mode != TRUE) {
ERR("Ignore the event");
return;
- }
- else {
+ } else {
ERR("Flight Mode == TRUE");
}
} else {
} 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) {
+ } else if (strcmp(profile_uuid, HFP_HF_UUID) == 0) {
if (state == BT_HAL_PROFILE_STATE_CONNECTING)
DBG("HFP Profile state changed: BT_PROFILE_STATE_CONNECTING");
else if (state == BT_HAL_PROFILE_STATE_CONNECTED) {
} else {
ERR("HFP Profile state: Invalid");
}
+ } else if (strncmp(profile_uuid, HFP_AG_UUID, strlen(HFP_AG_UUID)) == 0) {
+ if (state == BT_HAL_PROFILE_STATE_CONNECTING)
+ DBG("HFP Client Profile state changed: BT_PROFILE_STATE_CONNECTING");
+ else if (state == BT_HAL_PROFILE_STATE_CONNECTED) {
+ DBG("HFP Client Profile state changed: BT_PROFILE_STATE_CONNECTED");
+ __bt_hal_send_hf_client_connection_state_event(TRUE, address);
+ } else if (state == BT_HAL_PROFILE_STATE_DISCONNECTED) {
+ DBG("HFP Client Profile state changed: BT_PROFILE_STATE_DISCONNECTED");
+ __bt_hal_send_hf_client_connection_state_event(FALSE, address);
+ } else if (state == BT_HAL_PROFILE_STATE_DISCONNECTING) {
+ DBG("HFP Client Profile state changed: BT_PROFILE_STATE_DISCONNECTING");
+ } else {
+ ERR("HFP Client Profile state: Invalid");
+ }
} else if ((strncmp(profile_uuid, AVRCP_TARGET_UUID, strlen(AVRCP_TARGET_UUID)) == 0)) {
if (state == BT_HAL_PROFILE_STATE_CONNECTED) {
DBG("AVRCP Controller Profile state changed: BT_HAL_PROFILE_STATE_CONNECTED");
hf_event_cb(HAL_EV_HANDSFREE_CONN_STATE, &ev, sizeof(ev));
}
+/* HF(Client Role) Profile Events */
+static void __bt_hal_send_hf_client_connection_state_event(gboolean connected,
+ const char *address)
+{
+ struct hal_ev_hf_client_conn_state ev;
+
+ if (connected == TRUE)
+ INFO("HF Client Profile Connected for address [%s]", address);
+ else
+ INFO("HF Client Profile DisConnected for address [%s]", address);
+
+ ev.state = (connected == TRUE) ?
+ HAL_EV_HF_CLIENT_CONN_STATE_CONNECTED :
+ HAL_EV_HF_CLIENT_CONN_STATE_DISCONNECTED;
+
+ _bt_hal_convert_addr_string_to_type(ev.bdaddr, address);
+
+ if (!hf_client_event_cb)
+ ERR("HF Client event handler not registered");
+ else
+ hf_client_event_cb(HAL_EV_HF_CLIENT_CONN_STATE, &ev, sizeof(ev));
+}
+
void _bt_hal_register_event_handler_cb(bt_hal_module_e module, handle_stack_msg cb)
{
switch (module) {
case HAL_HF_AG:
hf_event_cb = cb;
break;
+ case HAL_HF_CLIENT:
+ hf_client_event_cb = cb;
+ break;
case HAL_AVRCP_TG:
avrcp_tg_event_cb = cb;
break;
case HAL_HF_AG:
hf_event_cb = NULL;
break;
+ case HAL_HF_CLIENT:
+ hf_client_event_cb = NULL;
+ break;
case HAL_AVRCP_TG:
avrcp_tg_event_cb = NULL;
break;
HAL_A2DP_SRC,
HAL_A2DP_SNK,
HAL_HF_AG,
+ HAL_HF_CLIENT,
HAL_AVRCP_TG,
HAL_AVRCP_CTRL,
HAL_GATT,
--- /dev/null
+/*
+ * BLUETOOTH HAL
+ *
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <glib.h>
+#include <gio/gio.h>
+#include <dlog.h>
+#include <vconf.h>
+
+#include "bt-hal-hf-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-hf handler */
+void _bt_hal_register_hf_client_dbus_handler_cb(handle_stack_msg cb)
+{
+ event_cb = cb;
+}
+
+/* To send stack event to hal-hf handler */
+void _bt_hal_unregister_hf_client_dbus_handler_cb()
+{
+ event_cb = NULL;
+}
+
+static void __bt_hf_client_connect_cb(GDBusProxy *proxy, GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *g_error = NULL;
+ struct hal_ev_hf_client_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("HF Client Connect Dbus Call Error");
+ if (g_error) {
+ ERR("Error: %s", g_error->message);
+ g_clear_error(&g_error);
+ }
+ result = BT_STATUS_FAIL;
+ }
+ g_variant_unref(reply);
+
+ DBG("Address: %s", address);
+ /*
+ * If result is success, HF client connected event will be triggered
+ * automatically from stack, so return from here.
+ */
+ if (result == BT_STATUS_SUCCESS) {
+ /* Prepare to send HF client connecting event */
+ memset(&ev, 0, sizeof(ev));
+ _bt_hal_convert_addr_string_to_type(ev.bdaddr, address);
+ ev.state = HAL_EV_HF_CLIENT_CONN_STATE_CONNECTING;
+ if (!event_cb)
+ ERR("HF client dbus handler callback not registered");
+ else
+ event_cb(HAL_EV_HF_CLIENT_CONN_STATE, (void *)&ev, sizeof(ev));
+
+ } else {
+ /* Prepare to send HF client connection state event */
+ ERR("HF client Connection has failed!!");
+ memset(&ev, 0, sizeof(ev));
+ _bt_hal_convert_addr_string_to_type(ev.bdaddr, address);
+ ev.state = HAL_EV_HF_CLIENT_CONN_STATE_DISCONNECTED;
+ if (!event_cb)
+ ERR("HF client DBUS handler callback not registered");
+ else
+ event_cb(HAL_EV_HF_CLIENT_CONN_STATE, (void *)&ev, sizeof(ev));
+ }
+ g_free(address);
+}
+
+bt_status_t _bt_hal_dbus_handler_hf_client_connect(bt_bdaddr_t *bd_addr)
+{
+ char *address;
+ int ret;
+
+ if (!bd_addr) {
+ ERR("bd_addr is NULL, return");
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ address = g_malloc0(BT_HAL_ADDRESS_STRING_SIZE * sizeof(char));
+ if (!address) {
+ ERR("Memory allocation failed");
+ return BT_STATUS_NOMEM;
+ }
+ _bt_hal_convert_addr_type_to_string(address, bd_addr->address);
+
+ DBG("Connect profile :HFP_AG_UUID");
+ ret = _bt_hal_connect_profile(address, HFP_AG_UUID,
+ __bt_hf_client_connect_cb, address);
+
+ if (ret != BT_HAL_ERROR_NONE) {
+ ERR("_bt_hal_connect_profile(HF) Error");
+ g_free(address);
+ return BT_STATUS_FAIL;
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+static void __bt_hf_client_disconnect_cb(GDBusProxy *proxy, GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *g_error = NULL;
+ struct hal_ev_hf_client_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("HF Client 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_SUCCESS) {
+ DBG("HF Client Disconnect successful for Device: %s", address);
+ /* Prepare to send HF Client Disconnecting event */
+ memset(&ev, 0, sizeof(ev));
+ _bt_hal_convert_addr_string_to_type(ev.bdaddr, address);
+ ev.state = HAL_EV_HF_CLIENT_CONN_STATE_DISCONNECTING;
+ if (!event_cb)
+ ERR("HF Client dbus handler callback not registered");
+ else
+ event_cb(HAL_EV_HF_CLIENT_CONN_STATE, (void *)&ev, sizeof(ev));
+
+ } else {
+ /* Prepare to send HF Client Disconnection state event */
+ ERR("HF Client Disconnect failed for Device: %s", address);
+ memset(&ev, 0, sizeof(ev));
+ _bt_hal_convert_addr_string_to_type(ev.bdaddr, address);
+ ev.state = HAL_EV_HF_CLIENT_CONN_STATE_DISCONNECTED;
+ if (!event_cb)
+ ERR("HF Client DBUS handler callback not registered");
+ else
+ event_cb(HAL_EV_HF_CLIENT_CONN_STATE, (void *)&ev, sizeof(ev));
+ }
+ g_free(address);
+ DBG("-");
+}
+
+bt_status_t _bt_hal_dbus_handler_hf_client_disconnect(bt_bdaddr_t *bd_addr)
+{
+ char *address;
+ int ret;
+
+ if (!bd_addr) {
+ ERR("bd_addr is NULL, return");
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ address = g_malloc0(BT_HAL_ADDRESS_STRING_SIZE * sizeof(char));
+ if (!address) {
+ ERR("Memory allocation failed");
+ return BT_STATUS_NOMEM;
+ }
+ _bt_hal_convert_addr_type_to_string(address, bd_addr->address);
+
+ DBG("Disconnect profile :HFP_AG_UUID");
+
+ ret = _bt_hal_disconnect_profile(address, HFP_AG_UUID,
+ __bt_hf_client_disconnect_cb, address);
+
+ if (ret != BT_HAL_ERROR_NONE) {
+ ERR("_bt_hal_connect_profile Error");
+ g_free(address);
+ return BT_STATUS_FAIL;
+ }
+
+ return BT_STATUS_SUCCESS;
+}
--- /dev/null
+/*
+ * BLUETOOTH HAL
+ *
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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_HF_CLIENT_DBUS_HANDLER_H_
+#define _BT_HAL_HF_CLIENT_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_hf_client_dbus_handler_cb(handle_stack_msg cb);
+
+void _bt_hal_unregister_hf_client_dbus_handler_cb();
+
+bt_status_t _bt_hal_dbus_handler_hf_client_connect(bt_bdaddr_t *bd_addr);
+
+bt_status_t _bt_hal_dbus_handler_hf_client_disconnect(bt_bdaddr_t *bd_addr);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _BT_HAL_HF_CLIENT_DBUS_HANDLER_H_*/
--- /dev/null
+/*
+ * BLUETOOTH HAL
+ *
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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-hf-client-dbus-handler.h"
+#include "bt-hal-event-receiver.h"
+#include "bt-hal-hf-client.h"
+
+static bthf_client_callbacks_t *bt_hal_hf_client_cbacks;
+
+static bool interface_ready(void)
+{
+ return bt_hal_hf_client_cbacks != NULL;
+}
+
+static bt_status_t bt_hal_hf_client_connect(bt_bdaddr_t *bd_addr)
+{
+ DBG("");
+ return _bt_hal_dbus_handler_hf_client_connect(bd_addr);
+}
+
+static bt_status_t bt_hal_hf_client_disconnect(bt_bdaddr_t *bd_addr)
+{
+ DBG("");
+ return _bt_hal_dbus_handler_hf_client_disconnect(bd_addr);
+}
+
+static bt_status_t bt_hal_hf_client_connect_audio(bt_bdaddr_t *bd_addr)
+{
+ DBG("");
+ return BT_STATUS_UNSUPPORTED;
+}
+
+static bt_status_t bt_hal_hf_client_disconnect_audio(bt_bdaddr_t *bd_addr)
+{
+ DBG("");
+ return BT_STATUS_UNSUPPORTED;
+}
+
+static bt_status_t bt_hal_hf_client_start_voice_recognition(void)
+{
+ DBG("");
+ return BT_STATUS_UNSUPPORTED;
+}
+
+static bt_status_t bt_hal_hf_client_stop_voice_recognition(void)
+{
+ DBG("");
+ return BT_STATUS_UNSUPPORTED;
+}
+
+static bt_status_t bt_hal_hf_client_volume_control(bthf_client_volume_type_t type, int volume)
+{
+ DBG("");
+ return BT_STATUS_UNSUPPORTED;
+}
+
+static bt_status_t bt_hal_hf_client_dial(const char *number)
+{
+ DBG("");
+ return BT_STATUS_UNSUPPORTED;
+}
+
+static bt_status_t bt_hal_hf_client_dial_memory(int location)
+{
+ DBG("");
+ return BT_STATUS_UNSUPPORTED;
+}
+
+static bt_status_t bt_hal_hf_client_handle_call_action(bthf_client_call_action_t action, int idx)
+{
+ DBG("");
+ return BT_STATUS_UNSUPPORTED;
+}
+
+static bt_status_t bt_hal_hf_client_query_current_calls(void)
+{
+ DBG("");
+ return BT_STATUS_UNSUPPORTED;
+}
+
+static bt_status_t bt_hal_hf_client_query_current_operator_name(void)
+{
+ DBG("");
+ return BT_STATUS_UNSUPPORTED;
+}
+
+static bt_status_t bt_hal_hf_client_retrieve_subscriber_info(void)
+{
+ DBG("");
+ return BT_STATUS_UNSUPPORTED;
+}
+
+static bt_status_t bt_hal_hf_client_send_dtmf(char code)
+{
+ DBG("");
+ return BT_STATUS_UNSUPPORTED;
+}
+
+static bt_status_t bt_hal_hf_client_request_last_voice_tag_number(void)
+{
+ DBG("");
+ return BT_STATUS_UNSUPPORTED;
+}
+
+static bt_status_t bt_hal_hf_client_send_at_cmd(int cmd, int val1, int val2, const char *arg)
+{
+ DBG("");
+ return BT_STATUS_UNSUPPORTED;
+}
+
+static bt_status_t bt_hal_hf_client_send_voice_data(unsigned char *p_buf, unsigned char len)
+{
+ DBG("");
+ return BT_STATUS_UNSUPPORTED;
+}
+
+static void __bt_hal_handle_hf_client_conn_state(void *buf, uint16_t len)
+{
+ struct hal_ev_hf_client_conn_state *ev = buf;
+ unsigned int peer_feat = 0;
+ unsigned int chld_feat = 0;
+
+ if (bt_hal_hf_client_cbacks->connection_state_cb)
+ bt_hal_hf_client_cbacks->connection_state_cb(ev->state,
+ peer_feat, chld_feat, (bt_bdaddr_t *) ev->bdaddr);
+}
+
+static void __bt_hal_handle_hf_client_events(int message, void *buf, uint16_t len)
+{
+ DBG("+");
+ if (!interface_ready())
+ return;
+ switch (message) {
+ case HAL_EV_HF_CLIENT_CONN_STATE:
+ DBG("Event: HAL_EV_HF_CLIENT_CONN_STATE");
+ __bt_hal_handle_hf_client_conn_state(buf, len);
+ break;
+ default:
+ DBG("Event Currently not handled!!");
+ break;
+ }
+ DBG("-");
+}
+
+static bt_status_t bt_hal_hf_init(bthf_client_callbacks_t* callbacks)
+{
+ DBG("");
+
+ if (interface_ready())
+ return BT_STATUS_DONE;
+
+ bt_hal_hf_client_cbacks = callbacks;
+ DBG("Register HF Client Role callback function");
+ _bt_hal_register_hf_client_dbus_handler_cb(__bt_hal_handle_hf_client_events);
+ _bt_hal_register_event_handler_cb(HAL_HF_CLIENT, __bt_hal_handle_hf_client_events);
+ return BT_STATUS_SUCCESS;
+}
+
+static void bt_hal_hf_cleanup(void)
+{
+ if (!interface_ready())
+ return;
+
+ _bt_hal_unregister_event_handler_cb(HAL_HF_AG);
+ bt_hal_hf_client_cbacks = NULL;
+}
+
+static bthf_client_interface_t bthf_client_if = {
+ .size = sizeof(bthf_client_if),
+ .init = bt_hal_hf_init,
+ .connect = bt_hal_hf_client_connect,
+ .disconnect = bt_hal_hf_client_disconnect,
+ .connect_audio = bt_hal_hf_client_connect_audio,
+ .disconnect_audio = bt_hal_hf_client_disconnect_audio,
+ .start_voice_recognition = bt_hal_hf_client_start_voice_recognition,
+ .stop_voice_recognition = bt_hal_hf_client_stop_voice_recognition,
+ .volume_control = bt_hal_hf_client_volume_control,
+ .dial = bt_hal_hf_client_dial,
+ .dial_memory = bt_hal_hf_client_dial_memory,
+ .handle_call_action = bt_hal_hf_client_handle_call_action,
+ .query_current_calls = bt_hal_hf_client_query_current_calls,
+ .query_current_operator_name = bt_hal_hf_client_query_current_operator_name,
+ .retrieve_subscriber_info = bt_hal_hf_client_retrieve_subscriber_info,
+ .send_dtmf = bt_hal_hf_client_send_dtmf,
+ .request_last_voice_tag_number = bt_hal_hf_client_request_last_voice_tag_number,
+ .cleanup = bt_hal_hf_cleanup,
+ .send_at_cmd = bt_hal_hf_client_send_at_cmd,
+ .send_voice_data = bt_hal_hf_client_send_voice_data,
+};
+
+/*******************************************************************************
+**
+** Function bt_get_hf_client_interface
+**
+** Description Get the hf client callback interface
+**
+** Returns bthf_client_interface_t
+**
+*******************************************************************************/
+bthf_client_interface_t *bt_get_hf_client_interface()
+{
+ return &bthf_client_if;
+}
--- /dev/null
+/*
+ * BLUETOOTH HAL
+ *
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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_HF_CLIENT_H__
+#define __BT_HAL_HF_CLIENT_H__
+
+#include <stdint.h>
+#include <glib.h>
+#include <unistd.h>
+#include <dlog.h>
+#include <stdio.h>
+
+bthf_client_interface_t *bt_get_hf_client_interface(void);
+
+#endif //__BT_HAL_HF_CLIENT_H__
+
#define AVRCP_CTRL_UUID "0000110e-0000-1000-8000-00805f9b34fb"
#define AVRCP_TARGET_UUID "0000110c-0000-1000-8000-00805f9b34fb"
#define HFP_HF_UUID "0000111e-0000-1000-8000-00805f9b34fb"
+#define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb"
/* TODO More declarations to be added in subsequent patches */
#ifdef __cplusplus
--- /dev/null
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 ANDROID_INCLUDE_BT_HF_CLIENT_H
+#define ANDROID_INCLUDE_BT_HF_CLIENT_H
+
+__BEGIN_DECLS
+
+typedef enum {
+ BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED = 0,
+ BTHF_CLIENT_CONNECTION_STATE_CONNECTING,
+ BTHF_CLIENT_CONNECTION_STATE_CONNECTED,
+ BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED,
+ BTHF_CLIENT_CONNECTION_STATE_DISCONNECTING
+} bthf_client_connection_state_t;
+
+typedef enum {
+ BTHF_CLIENT_AUDIO_STATE_DISCONNECTED = 0,
+ BTHF_CLIENT_AUDIO_STATE_CONNECTING,
+ BTHF_CLIENT_AUDIO_STATE_CONNECTED,
+ BTHF_CLIENT_AUDIO_STATE_CONNECTED_MSBC,
+} bthf_client_audio_state_t;
+
+typedef enum {
+ BTHF_CLIENT_VR_STATE_STOPPED = 0,
+ BTHF_CLIENT_VR_STATE_STARTED
+} bthf_client_vr_state_t;
+
+typedef enum {
+ BTHF_CLIENT_VOLUME_TYPE_SPK = 0,
+ BTHF_CLIENT_VOLUME_TYPE_MIC
+} bthf_client_volume_type_t;
+
+typedef enum {
+ BTHF_CLIENT_NETWORK_STATE_NOT_AVAILABLE = 0,
+ BTHF_CLIENT_NETWORK_STATE_AVAILABLE
+} bthf_client_network_state_t;
+
+typedef enum {
+ BTHF_CLIENT_SERVICE_TYPE_HOME = 0,
+ BTHF_CLIENT_SERVICE_TYPE_ROAMING
+} bthf_client_service_type_t;
+
+typedef enum {
+ BTHF_CLIENT_CALL_STATE_ACTIVE = 0,
+ BTHF_CLIENT_CALL_STATE_HELD,
+ BTHF_CLIENT_CALL_STATE_DIALING,
+ BTHF_CLIENT_CALL_STATE_ALERTING,
+ BTHF_CLIENT_CALL_STATE_INCOMING,
+ BTHF_CLIENT_CALL_STATE_WAITING,
+ BTHF_CLIENT_CALL_STATE_HELD_BY_RESP_HOLD,
+} bthf_client_call_state_t;
+
+typedef enum {
+ BTHF_CLIENT_CALL_NO_CALLS_IN_PROGRESS = 0,
+ BTHF_CLIENT_CALL_CALLS_IN_PROGRESS
+} bthf_client_call_t;
+
+typedef enum {
+ BTHF_CLIENT_CALLSETUP_NONE = 0,
+ BTHF_CLIENT_CALLSETUP_INCOMING,
+ BTHF_CLIENT_CALLSETUP_OUTGOING,
+ BTHF_CLIENT_CALLSETUP_ALERTING
+
+} bthf_client_callsetup_t;
+
+typedef enum {
+ BTHF_CLIENT_CALLHELD_NONE = 0,
+ BTHF_CLIENT_CALLHELD_HOLD_AND_ACTIVE,
+ BTHF_CLIENT_CALLHELD_HOLD,
+} bthf_client_callheld_t;
+
+typedef enum {
+ BTHF_CLIENT_RESP_AND_HOLD_HELD = 0,
+ BTRH_CLIENT_RESP_AND_HOLD_ACCEPT,
+ BTRH_CLIENT_RESP_AND_HOLD_REJECT,
+} bthf_client_resp_and_hold_t;
+
+typedef enum {
+ BTHF_CLIENT_CALL_DIRECTION_OUTGOING = 0,
+ BTHF_CLIENT_CALL_DIRECTION_INCOMING
+} bthf_client_call_direction_t;
+
+typedef enum {
+ BTHF_CLIENT_CALL_MPTY_TYPE_SINGLE = 0,
+ BTHF_CLIENT_CALL_MPTY_TYPE_MULTI
+} bthf_client_call_mpty_type_t;
+
+typedef enum {
+ BTHF_CLIENT_CMD_COMPLETE_OK = 0,
+ BTHF_CLIENT_CMD_COMPLETE_ERROR,
+ BTHF_CLIENT_CMD_COMPLETE_ERROR_NO_CARRIER,
+ BTHF_CLIENT_CMD_COMPLETE_ERROR_BUSY,
+ BTHF_CLIENT_CMD_COMPLETE_ERROR_NO_ANSWER,
+ BTHF_CLIENT_CMD_COMPLETE_ERROR_DELAYED,
+ BTHF_CLIENT_CMD_COMPLETE_ERROR_BLACKLISTED,
+ BTHF_CLIENT_CMD_COMPLETE_ERROR_CME
+} bthf_client_cmd_complete_t;
+
+typedef enum {
+ BTHF_CLIENT_CALL_ACTION_CHLD_0 = 0,
+ BTHF_CLIENT_CALL_ACTION_CHLD_1,
+ BTHF_CLIENT_CALL_ACTION_CHLD_2,
+ BTHF_CLIENT_CALL_ACTION_CHLD_3,
+ BTHF_CLIENT_CALL_ACTION_CHLD_4,
+ BTHF_CLIENT_CALL_ACTION_CHLD_1x,
+ BTHF_CLIENT_CALL_ACTION_CHLD_2x,
+ BTHF_CLIENT_CALL_ACTION_ATA,
+ BTHF_CLIENT_CALL_ACTION_CHUP,
+ BTHF_CLIENT_CALL_ACTION_BTRH_0,
+ BTHF_CLIENT_CALL_ACTION_BTRH_1,
+ BTHF_CLIENT_CALL_ACTION_BTRH_2,
+} bthf_client_call_action_t;
+
+typedef enum {
+ BTHF_CLIENT_SERVICE_UNKNOWN = 0,
+ BTHF_CLIENT_SERVICE_VOICE,
+ BTHF_CLIENT_SERVICE_FAX
+} bthf_client_subscriber_service_type_t;
+
+typedef enum {
+ BTHF_CLIENT_IN_BAND_RINGTONE_NOT_PROVIDED = 0,
+ BTHF_CLIENT_IN_BAND_RINGTONE_PROVIDED,
+} bthf_client_in_band_ring_state_t;
+
+/* Peer features masks */
+#define BTHF_CLIENT_PEER_FEAT_3WAY 0x00000001 /* Three-way calling */
+#define BTHF_CLIENT_PEER_FEAT_ECNR 0x00000002 /* Echo cancellation and/or noise reduction */
+#define BTHF_CLIENT_PEER_FEAT_VREC 0x00000004 /* Voice recognition */
+#define BTHF_CLIENT_PEER_FEAT_INBAND 0x00000008 /* In-band ring tone */
+#define BTHF_CLIENT_PEER_FEAT_VTAG 0x00000010 /* Attach a phone number to a voice tag */
+#define BTHF_CLIENT_PEER_FEAT_REJECT 0x00000020 /* Ability to reject incoming call */
+#define BTHF_CLIENT_PEER_FEAT_ECS 0x00000040 /* Enhanced Call Status */
+#define BTHF_CLIENT_PEER_FEAT_ECC 0x00000080 /* Enhanced Call Control */
+#define BTHF_CLIENT_PEER_FEAT_EXTERR 0x00000100 /* Extended error codes */
+#define BTHF_CLIENT_PEER_FEAT_CODEC 0x00000200 /* Codec Negotiation */
+
+/* Peer call handling features masks */
+#define BTHF_CLIENT_CHLD_FEAT_REL 0x00000001 /* 0 Release waiting call or held calls */
+#define BTHF_CLIENT_CHLD_FEAT_REL_ACC 0x00000002 /* 1 Release active calls and accept other (waiting or held) cal */
+#define BTHF_CLIENT_CHLD_FEAT_REL_X 0x00000004 /* 1x Release specified active call only */
+#define BTHF_CLIENT_CHLD_FEAT_HOLD_ACC 0x00000008 /* 2 Active calls on hold and accept other (waiting or held) call */
+#define BTHF_CLIENT_CHLD_FEAT_PRIV_X 0x00000010 /* 2x Request private mode with specified call (put the rest on hold) */
+#define BTHF_CLIENT_CHLD_FEAT_MERGE 0x00000020 /* 3 Add held call to multiparty */
+#define BTHF_CLIENT_CHLD_FEAT_MERGE_DETACH 0x00000040 /* 4 Connect two calls and leave (disconnect from) multiparty */
+
+/** Callback for connection state change.
+ * state will have one of the values from BtHfConnectionState
+ * peer/chld_features are valid only for BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED state
+ */
+typedef void (*bthf_client_connection_state_callback)(bthf_client_connection_state_t state, unsigned int peer_feat, unsigned int chld_feat, bt_bdaddr_t *bd_addr);
+
+/** Callback for audio connection state change.
+ * state will have one of the values from BtHfAudioState
+ */
+typedef void (*bthf_client_audio_state_callback)(bthf_client_audio_state_t state, bt_bdaddr_t *bd_addr);
+
+/** Callback for VR connection state change.
+ * state will have one of the values from BtHfVRState
+ */
+typedef void (*bthf_client_vr_cmd_callback)(bthf_client_vr_state_t state);
+
+/** Callback for network state change
+ */
+typedef void (*bthf_client_network_state_callback) (bthf_client_network_state_t state);
+
+/** Callback for network roaming status change
+ */
+typedef void (*bthf_client_network_roaming_callback) (bthf_client_service_type_t type);
+
+/** Callback for signal strength indication
+ */
+typedef void (*bthf_client_network_signal_callback) (int signal_strength);
+
+/** Callback for battery level indication
+ */
+typedef void (*bthf_client_battery_level_callback) (int battery_level);
+
+/** Callback for current operator name
+ */
+typedef void (*bthf_client_current_operator_callback) (const char *name);
+
+/** Callback for call indicator
+ */
+typedef void (*bthf_client_call_callback) (bthf_client_call_t call);
+
+/** Callback for callsetup indicator
+ */
+typedef void (*bthf_client_callsetup_callback) (bthf_client_callsetup_t callsetup);
+
+/** Callback for callheld indicator
+ */
+typedef void (*bthf_client_callheld_callback) (bthf_client_callheld_t callheld);
+
+/** Callback for response and hold
+ */
+typedef void (*bthf_client_resp_and_hold_callback) (bthf_client_resp_and_hold_t resp_and_hold);
+
+/** Callback for Calling Line Identification notification
+ * Will be called only when there is an incoming call and number is provided.
+ */
+typedef void (*bthf_client_clip_callback) (const char *number);
+
+/**
+ * Callback for Call Waiting notification
+ */
+typedef void (*bthf_client_call_waiting_callback) (const char *number);
+
+/**
+ * Callback for listing current calls. Can be called multiple time.
+ * If number is unknown NULL is passed.
+ */
+typedef void (*bthf_client_current_calls) (int index, bthf_client_call_direction_t dir,
+ bthf_client_call_state_t state,
+ bthf_client_call_mpty_type_t mpty,
+ const char *number);
+
+/** Callback for audio volume change
+ */
+typedef void (*bthf_client_volume_change_callback) (bthf_client_volume_type_t type, int volume);
+
+/** Callback for command complete event
+ * cme is valid only for BTHF_CLIENT_CMD_COMPLETE_ERROR_CME type
+ */
+typedef void (*bthf_client_cmd_complete_callback) (bthf_client_cmd_complete_t type, int cme);
+
+/** Callback for subscriber information
+ */
+typedef void (*bthf_client_subscriber_info_callback) (const char *name, bthf_client_subscriber_service_type_t type);
+
+/** Callback for in-band ring tone settings
+ */
+typedef void (*bthf_client_in_band_ring_tone_callback) (bthf_client_in_band_ring_state_t state);
+
+/**
+ * Callback for requested number from AG
+ */
+typedef void (*bthf_client_last_voice_tag_number_callback) (const char *number);
+
+/**
+ * Callback for sending ring indication to app
+ */
+typedef void (*bthf_client_ring_indication_callback) (void);
+
+/**
+ * Callback for sending voice data to app
+ */
+typedef void (*bthf_client_get_voice_data_callback) (uint8_t *p_buf, uint8_t len);
+
+/** BT-HF callback structure. */
+typedef struct {
+ /** set to sizeof(BtHfClientCallbacks) */
+ size_t size;
+ bthf_client_connection_state_callback connection_state_cb;
+ bthf_client_audio_state_callback audio_state_cb;
+ bthf_client_vr_cmd_callback vr_cmd_cb;
+ bthf_client_network_state_callback network_state_cb;
+ bthf_client_network_roaming_callback network_roaming_cb;
+ bthf_client_network_signal_callback network_signal_cb;
+ bthf_client_battery_level_callback battery_level_cb;
+ bthf_client_current_operator_callback current_operator_cb;
+ bthf_client_call_callback call_cb;
+ bthf_client_callsetup_callback callsetup_cb;
+ bthf_client_callheld_callback callheld_cb;
+ bthf_client_resp_and_hold_callback resp_and_hold_cb;
+ bthf_client_clip_callback clip_cb;
+ bthf_client_call_waiting_callback call_waiting_cb;
+ bthf_client_current_calls current_calls_cb;
+ bthf_client_volume_change_callback volume_change_cb;
+ bthf_client_cmd_complete_callback cmd_complete_cb;
+ bthf_client_subscriber_info_callback subscriber_info_cb;
+ bthf_client_in_band_ring_tone_callback in_band_ring_tone_cb;
+ bthf_client_last_voice_tag_number_callback last_voice_tag_number_callback;
+ bthf_client_ring_indication_callback ring_indication_cb;
+ bthf_client_get_voice_data_callback get_voice_data_cb;
+} bthf_client_callbacks_t;
+
+/** Represents the standard BT-HF interface. */
+typedef struct {
+
+ /** set to sizeof(BtHfClientInterface) */
+ size_t size;
+ /**
+ * Register the BtHf callbacks
+ */
+ bt_status_t (*init)(bthf_client_callbacks_t* callbacks);
+
+ /** connect to audio gateway */
+ bt_status_t (*connect)(bt_bdaddr_t *bd_addr);
+
+ /** disconnect from audio gateway */
+ bt_status_t (*disconnect)(bt_bdaddr_t *bd_addr);
+
+ /** create an audio connection */
+ bt_status_t (*connect_audio)(bt_bdaddr_t *bd_addr);
+
+ /** close the audio connection */
+ bt_status_t (*disconnect_audio)(bt_bdaddr_t *bd_addr);
+
+ /** start voice recognition */
+ bt_status_t (*start_voice_recognition)(void);
+
+ /** stop voice recognition */
+ bt_status_t (*stop_voice_recognition)(void);
+
+ /** volume control */
+ bt_status_t (*volume_control) (bthf_client_volume_type_t type, int volume);
+
+ /** place a call with number a number
+ * if number is NULL last called number is called (aka re-dial)*/
+ bt_status_t (*dial) (const char *number);
+
+ /** place a call with number specified by location (speed dial) */
+ bt_status_t (*dial_memory) (int location);
+
+ /** perform specified call related action
+ * idx is limited only for enhanced call control related action
+ */
+ bt_status_t (*handle_call_action) (bthf_client_call_action_t action, int idx);
+
+ /** query list of current calls */
+ bt_status_t (*query_current_calls) (void);
+
+ /** query name of current selected operator */
+ bt_status_t (*query_current_operator_name) (void);
+
+ /** Retrieve subscriber information */
+ bt_status_t (*retrieve_subscriber_info) (void);
+
+ /** Send DTMF code*/
+ bt_status_t (*send_dtmf) (char code);
+
+ /** Request a phone number from AG corresponding to last voice tag recorded */
+ bt_status_t (*request_last_voice_tag_number) (void);
+
+ /** Closes the interface. */
+ void (*cleanup)(void);
+
+ /** Send AT Command. */
+ bt_status_t (*send_at_cmd) (int cmd, int val1, int val2, const char *arg);
+
+ /** send sco packet over HCI */
+ bt_status_t (*send_voice_data)(unsigned char *p_buf, unsigned char len);
+} bthf_client_interface_t;
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_HF_CLIENT_H */
EVENT(OAL_EVENT_HFP_AUDIO_CONNECTING) /* bt_address_t*/ \
EVENT(OAL_EVENT_HFP_AUDIO_CONNECTED) /* bt_address_t*/ \
EVENT(OAL_EVENT_HFP_AUDIO_DISCONNECTING) /* bt_address_t*/ \
+ EVENT(OAL_EVENT_HF_CLIENT_DISCONNECTED) /* bt_address_t*/ \
+ EVENT(OAL_EVENT_HF_CLIENT_CONNECTING) /* bt_address_t*/ \
+ EVENT(OAL_EVENT_HF_CLIENT_CONNECTED) /* bt_address_t*/ \
+ EVENT(OAL_EVENT_HF_CLIENT_DISCONNECTING) /* bt_address_t*/ \
EVENT(OAL_EVENT_AVRCP_CONNECTED) /* AVRCP Target connected */ \
EVENT(OAL_EVENT_AVRCP_DISCONNECTED) /* AVRCP Target disconnected */ \
EVENT(OAL_EVENT_AVRCP_REMOTE_FEATURES) /* AVRCP FATURE INFO*/ \
--- /dev/null
+/*
+ * Open Adaptation Layer (OAL)
+ *
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * 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 _OAL_HF_CLIENT_H_
+#define _OAL_HF_CLIENT_H_
+
+#include <glib.h>
+#include <sys/types.h>
+#include <oal-manager.h>
+#include "oal-event.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Enable Audio HFP Client profile or HF Role of HFP profile
+ *
+ * @remarks BT audio gateway devices will be able to connect.
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS Successful
+ *
+ * @pre OAL API must be initialized with oal_bt_init().
+ *
+ * @see hfp_client_disable()
+ */
+oal_status_t hf_client_enable(void);
+
+/**
+ * @brief Disable Audio HFP client profile or HF Role of HFP profile
+ *
+ * @remarks BT audio gateway devices will be able to disconnect.
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise a non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS Successful
+ *
+ * @pre AG Host should be enabled with hf_client_enable().
+ *
+ * @see hfp_enable()
+ */
+oal_status_t hf_client_disable(void);
+
+/**
+ * @brief Initiate a HFP connection with a remote audio gateway device
+ *
+ * @details Result will be notified through an OAL event
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise a non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS Successful
+ *
+ * @pre HFP Client should be enabled with hf_client_enable().
+ *
+ * @see OAL_EVENT_HFP_CLIENT_DISCONNECTED
+ */
+oal_status_t hf_client_connect(bt_address_t *device_address);
+
+/**
+ * @brief Terminate a HFP connection with a remote audio gateway device
+ *
+ * @details Result will be notified through an OAL event
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise a non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS Successful
+ *
+ * @pre HFP Client should be enabled with hf_client_enable().
+ *
+ * @see OAL_EVENT_HFP_CLIENT_CONNECTED
+ */
+oal_status_t hf_client_disconnect(bt_address_t *device_address);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _OAL_HF_CLIENT_H_*/
--- /dev/null
+/*
+ * Open Adaptation Layer (OAL)
+ *
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * 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 <sys/un.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dlog.h>
+
+#include <bluetooth.h>
+#include <bt_hf_client.h>
+
+#include "oal-common.h"
+#include "oal-internal.h"
+#include "oal-hf-client.h"
+#include "oal-utils.h"
+
+static const bthf_client_interface_t *blued_hf_client_interface = NULL;
+
+#define CHECK_OAL_HFP_CLIENT_ENABLED() \
+ do { \
+ if (blued_hf_client_interface == NULL) { \
+ BT_ERR("OAL, HFP Client Not Enabled"); \
+ return OAL_STATUS_NOT_READY; \
+ } \
+ } while (0)
+
+static void cb_hf_client_connection_state(bthf_client_connection_state_t state, unsigned int peer_feat,
+ unsigned int chld_feat, bt_bdaddr_t *bd_addr);
+
+static bthf_client_callbacks_t blued_hf_client_cb = {
+ .size = sizeof(blued_hf_client_cb),
+ .connection_state_cb = cb_hf_client_connection_state,
+ .audio_state_cb = NULL,
+ .vr_cmd_cb = NULL,
+ .network_state_cb = NULL,
+ .network_roaming_cb = NULL,
+ .network_signal_cb = NULL,
+ .battery_level_cb = NULL,
+ .current_operator_cb = NULL,
+ .call_cb = NULL,
+ .callsetup_cb = NULL,
+ .callheld_cb = NULL,
+ .resp_and_hold_cb = NULL,
+ .clip_cb = NULL,
+ .call_waiting_cb = NULL,
+ .current_calls_cb = NULL,
+ .volume_change_cb = NULL,
+ .cmd_complete_cb = NULL,
+ .subscriber_info_cb = NULL,
+ .in_band_ring_tone_cb = NULL,
+ .last_voice_tag_number_callback = NULL,
+ .ring_indication_cb = NULL,
+ .get_voice_data_cb = NULL
+};
+
+oal_status_t hf_client_enable(void)
+{
+ const bt_interface_t* blued_inf;
+ int ret;
+
+ API_TRACE("HFP Client Enable");
+
+ if ((blued_inf = adapter_get_stack_interface()) == NULL) {
+ BT_ERR("Bluetooth module is not loaded");
+ return OAL_STATUS_NOT_READY;
+ }
+
+ if (blued_hf_client_interface != NULL) {
+ BT_WARN("HFP Client Interface is already initialized...");
+ return OAL_STATUS_ALREADY_DONE;
+ }
+
+ if ((blued_hf_client_interface = (const bthf_client_interface_t *)blued_inf->get_profile_interface(BT_PROFILE_HANDSFREE_CLIENT_ID)) == NULL) {
+ BT_ERR("OAL, Failed to get Bluetooth HFP Client Interface");
+ return OAL_STATUS_INTERNAL_ERROR;
+ }
+
+ BT_DBG("Got profile interface");
+ if ((ret = blued_hf_client_interface->init(&blued_hf_client_cb)) != BT_STATUS_SUCCESS) {
+ BT_ERR("Failed to initialize Bluetooth HFP Client, status: %s", status2string(ret));
+ blued_hf_client_interface = NULL;
+ return convert_to_oal_status(ret);
+ }
+ BT_DBG("OAL, Bluetooth HFP Client interface initialised");
+
+ return OAL_STATUS_SUCCESS;
+}
+
+/* HFP Client deinit: Resets all the HFP Client information
+ * Note: Adapter should be disabled before calling deinit
+ * */
+oal_status_t hf_client_disable(void)
+{
+ API_TRACE("HFP Client disable");
+ CHECK_OAL_HFP_CLIENT_ENABLED();
+
+ blued_hf_client_interface->cleanup();
+ blued_hf_client_interface = NULL;
+
+ return OAL_STATUS_SUCCESS;
+}
+
+void hf_client_cleanup(void)
+{
+ API_TRACE("HFP Client Cleanup");
+ blued_hf_client_interface = NULL;
+}
+
+oal_status_t hf_client_connect(bt_address_t *device_address)
+{
+ int result = OAL_STATUS_SUCCESS;
+ bt_status_t status;
+ bdstr_t bdstr;
+ API_TRACE("HF Client Connect");
+
+ CHECK_OAL_HFP_CLIENT_ENABLED();
+ OAL_CHECK_PARAMETER(device_address, return);
+
+ BT_INFO("BT remote AG Device Address: %s", bdt_bd2str(device_address, &bdstr));
+ /* Call connect function of Bluedroid*/
+ status = blued_hf_client_interface->connect((bt_bdaddr_t *)device_address);
+ if ((status != BT_STATUS_SUCCESS) && (status != BT_STATUS_DONE)) {
+ BT_ERR("Connection could not be established, err: %s", status2string(status));;
+ result = convert_to_oal_status(status);
+ }
+ return result;
+}
+
+
+oal_status_t hf_client_disconnect(bt_address_t *device_address)
+{
+ int result = OAL_STATUS_SUCCESS;
+ bdstr_t bdstr;
+ bt_status_t status;
+ API_TRACE("HF Client Disconnect");
+
+ CHECK_OAL_HFP_CLIENT_ENABLED();
+ OAL_CHECK_PARAMETER(device_address, return);
+
+ BT_INFO("BT remote AG Address: %s", bdt_bd2str(device_address, &bdstr));
+ /* call Disconnect function of Bluedroid */
+ status = blued_hf_client_interface->disconnect((bt_bdaddr_t *)device_address);
+ if ((status != BT_STATUS_SUCCESS) && (status != BT_STATUS_DONE)) {
+ BT_ERR("OAL, Disconnection failed err: %s", status2string(status));
+ result = convert_to_oal_status(status);
+ }
+ return result;
+}
+
+void cb_hf_client_connection_state(bthf_client_connection_state_t state, unsigned int peer_feat,
+ unsigned int chld_feat, bt_bdaddr_t *bd_addr)
+{
+ int event_type;
+ bdstr_t bdstr;
+ bt_address_t * event_data = NULL;
+ event_data = g_new0(bt_address_t, 1);
+ memcpy(event_data->addr, bd_addr->address, BT_ADDRESS_BYTES_NUM);
+
+ if (bd_addr == NULL) {
+ BT_ERR("Address is NULL");
+ if (event_data)
+ g_free(event_data);
+ return;
+ }
+
+ BT_INFO("HFP Client Profile state = [%d], BT Address = [%s]", state, bdt_bd2str((bt_address_t*)bd_addr, &bdstr));
+ switch (state) {
+ case BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED: {
+ event_type = OAL_EVENT_HF_CLIENT_DISCONNECTED;
+ break;
+ }
+ case BTHF_CLIENT_CONNECTION_STATE_CONNECTING: {
+ event_type = OAL_EVENT_HF_CLIENT_CONNECTING;
+ break;
+ }
+ case BTHF_CLIENT_CONNECTION_STATE_CONNECTED: {
+ event_type = OAL_EVENT_HF_CLIENT_CONNECTED;
+ break;
+ }
+ case BTHF_CLIENT_CONNECTION_STATE_DISCONNECTING: {
+ event_type = OAL_EVENT_HF_CLIENT_DISCONNECTING;
+ break;
+ }
+ default: {
+ BT_INFO("Invalid state");
+ if (event_data)
+ g_free(event_data);
+ return;
+ }
+ }
+ send_event_bda_trace(event_type, event_data, sizeof(bt_address_t), (bt_address_t*)bd_addr);
+}
+
./services/audio/avrcp/bt-service-avrcp-tg.c
./services/audio/avrcp/bt-service-avrcp-ctrl.c
./services/gatt/bt-service-gatt.c
+./services/audio/hf/bt-service-hf-client.c
)
IF("$ENV{CFLAGS}" MATCHES "-DTIZEN_FEATURE_BT_OBEX")
if (ret != BLUETOOTH_ERROR_NONE)
BT_ERR("_bt_gatt_init Failed");
+ /* Initialize HF Client */
+ ret = _bt_audio_initialize(BT_HFP_MODULE);
+ if (ret != BLUETOOTH_ERROR_NONE)
+ BT_ERR("_bt_audio_initialize(BT_HFP_MODULE) Failed");
+
return BLUETOOTH_ERROR_NONE;
}
#include "bt-service-avrcp-tg.h"
#include "bt-service-avrcp-ctrl.h"
#include "bt-service-hf.h"
+#include "bt-service-hf-client.h"
+#include "oal-hf-client.h"
#ifdef TIZEN_SUPPORT_DUAL_HF
#define VCONF_KEY_BT_HOST_BT_MAC_ADDR "db/wms/host_bt_mac"
case BT_AUDIO_A2DP_SOURCE:
return _bt_a2dp_connect_remote_source(address);
break;
+ case BT_AUDIO_AG:
+ return _bt_connect_remote_ag(address);
default:
BT_ERR("Unknown role");
return BLUETOOTH_ERROR_INTERNAL;
break;
}
case BT_HFP_MODULE: {
- return BLUETOOTH_ERROR_NOT_SUPPORT;
+ status = hf_client_enable();
+ if (OAL_STATUS_SUCCESS != status) {
+ BT_ERR("Failed to initialize Bluetooth HFP client Profile, status: %d", status);
+ return BLUETOOTH_ERROR_INTERNAL;
+ }
+ /* Register Audio module event handler */
+ _bt_service_register_event_handler_callback(module, _bt_hf_client_event_handler);
+ break;
}
case BT_AG_MODULE: {
status = hfp_enable(1);
BT_INFO("role: %s", (role == BLUETOOTH_A2DP_SINK) ? "AUDIO_SINK" : "AUDIO_SOURCE");
curr_audio_role = role;
}
+
+int _bt_hf_connect(bluetooth_device_address_t *device_address)
+{
+ int result = BLUETOOTH_ERROR_NONE;
+ BT_INFO("+");
+
+ result = _bt_connect_remote_ag(device_address);
+ if (result != BLUETOOTH_ERROR_NONE)
+ BT_ERR("HF Client connect to remote AG failed");
+
+ return result;
+}
+
+int _bt_hf_disconnect(bluetooth_device_address_t *device_address)
+{
+ int result = BLUETOOTH_ERROR_NONE;
+ BT_INFO("+");
+
+ result = _bt_disconnect_remote_ag(device_address);
+ if (result != BLUETOOTH_ERROR_NONE)
+ BT_ERR("HF Client disconnect to remote AG failed");
+
+ return result;
+}
--- /dev/null
+/*
+ * Bluetooth-frwk
+ *
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <sys/errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <vconf.h>
+
+#include "oal-hardware.h"
+#include "oal-manager.h"
+#include "oal-audio-src.h"
+#include "oal-device-mgr.h"
+#include "oal-hf-client.h"
+#include "bt-service-common.h"
+
+#include <bt-service-hf-client.h>
+#include <bt-service-event.h>
+
+
+
+
+static void __bt_reply_hf_client_disconnection_pending_request(bt_address_t *address)
+{
+ BT_DBG("+");
+ char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
+ bluetooth_device_address_t device_address;
+ GArray *out_param;
+ invocation_info_t *req_info;
+ int result = BLUETOOTH_ERROR_NONE;
+
+ ret_if(NULL == address);
+
+ memcpy(device_address.addr, address->addr, BLUETOOTH_ADDRESS_LENGTH);
+ _bt_convert_addr_type_to_string(addr, address->addr);
+
+ BT_INFO("HF Client Disconnection remote device [%s]", addr);
+
+ /* Find Async request information*/
+ req_info = _bt_get_request_info_data(BT_HF_DISCONNECT, addr);
+ if (NULL == req_info) {
+ BT_INFO("HF DisConnect request not found or possibly already replied..");
+
+ /* if HF Connect call fails on Bluez DBUS, Async callback from bluez will be received
+ __bt_hf_client_connect_cb) which will internally trigger HF DISCONNECTED event */
+ req_info = _bt_get_request_info_data(BT_HF_CONNECT, addr);
+ if (NULL == req_info) {
+ BT_INFO("HF Connect request not found..");
+ return;
+ } else {
+ BT_INFO("HF Connect request found..reply this request");
+ }
+ } else {
+ BT_INFO("HF DisConnect request found..reply this request");
+ }
+
+ /* In any of the above cases, reply DBUS context */
+ out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+ g_array_append_vals(out_param, &device_address, sizeof(bluetooth_device_address_t));
+ _bt_service_method_return(req_info->context, out_param, result);
+ g_array_free(out_param, TRUE);
+ g_free(req_info->user_data);
+ _bt_free_info_from_invocation_list(req_info);
+
+ BT_DBG("-");
+}
+
+static void __bt_reply_hf_client_connection_pending_request(bt_address_t *address)
+{
+ BT_DBG("+");
+ char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
+ bluetooth_device_address_t device_address;
+ GArray *out_param;
+ invocation_info_t *req_info;
+ int result = BLUETOOTH_ERROR_NONE;
+
+ ret_if(NULL == address);
+
+ memcpy(device_address.addr, address->addr, BLUETOOTH_ADDRESS_LENGTH);
+ _bt_convert_addr_type_to_string(addr, address->addr);
+
+ BT_INFO("HF Client Connection remote device [%s]", addr);
+
+ /* Find Async request information*/
+ req_info = _bt_get_request_info_data(BT_HF_CONNECT, addr);
+ if (NULL == req_info) {
+ BT_INFO("HF Connect request not found or possibly already replied..");
+ return;
+
+ } else {
+ BT_INFO("HF Connect request found..");
+ }
+
+ /* In any of the above cases, reply DBUS context */
+ out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+ g_array_append_vals(out_param, &device_address, sizeof(bluetooth_device_address_t));
+ _bt_service_method_return(req_info->context, out_param, result);
+ g_array_free(out_param, TRUE);
+ g_free(req_info->user_data);
+ _bt_free_info_from_invocation_list(req_info);
+
+ BT_DBG("-");
+}
+
+
+/* This event handler process events for HF Client role */
+void _bt_hf_client_event_handler(int oal_event, gpointer event_data)
+{
+ BT_INFO("+");
+ bt_address_t *bt_addr = event_data;
+
+ switch (oal_event) {
+ case OAL_EVENT_HF_CLIENT_DISCONNECTED:
+ /* Reply to async request for HF Client connect or disconnect request, if any */
+ BT_INFO("HF client Profile disconnected, reply pending DBUS request and check waiting device");
+ __bt_reply_hf_client_disconnection_pending_request(bt_addr);
+ break;
+ case OAL_EVENT_HF_CLIENT_CONNECTED:
+ BT_INFO("HF Client Profile connected, Event & DBUS context will be handled at finalizing SCO connect..");
+ __bt_reply_hf_client_connection_pending_request(bt_addr);
+ break;
+ case OAL_EVENT_HF_CLIENT_CONNECTING:
+ BT_INFO("HF Client Profile connection successful, wait for Audio connect..");
+ break;
+ case OAL_EVENT_HF_CLIENT_DISCONNECTING:
+ BT_INFO("HF Client Connecting or Disconnecting..No need to send event to app");
+ break;
+ default:
+ break;
+ }
+}
+
+int _bt_connect_remote_ag(bluetooth_device_address_t *device_address)
+{
+ oal_status_t status = OAL_STATUS_SUCCESS;
+ int result = BLUETOOTH_ERROR_NONE;
+ gboolean is_connected = FALSE;
+
+ BT_INFO("+");
+
+ is_connected = device_get_svc_conn_state((bt_address_t*)device_address, HFP_SERVICE_ID);
+ if (is_connected == TRUE) {
+ BT_ERR("HF Client is already connected");
+ return BLUETOOTH_ERROR_ALREADY_CONNECT;
+ }
+
+ status = hf_client_connect((bt_address_t *)device_address);
+ if (status != OAL_STATUS_SUCCESS) {
+ BT_ERR("HF Client Connection could not be established, err: [%d]", status);
+ result = BLUETOOTH_ERROR_INTERNAL;
+ }
+ return result;
+}
+
+int _bt_disconnect_remote_ag(bluetooth_device_address_t *device_address)
+{
+ oal_status_t status = OAL_STATUS_SUCCESS;
+ int result = BLUETOOTH_ERROR_NONE;
+ BT_INFO("+");
+
+ status = hf_client_disconnect((bt_address_t *)device_address);
+ if (status != OAL_STATUS_SUCCESS) {
+ BT_ERR("HF Client DisConnection err: [%d]", status);
+ result = BLUETOOTH_ERROR_INTERNAL;
+ }
+ return result;
+}
+
}
break;
}
+ case BT_HF_CONNECT: {
+ bluetooth_device_address_t address = { {0} };
+
+ __bt_service_get_parameters(in_param1,
+ &address, sizeof(bluetooth_device_address_t));
+
+ result = _bt_hf_connect(&address);
+ if (result != BLUETOOTH_ERROR_NONE) {
+ char addr[BT_ADDRESS_STRING_SIZE];
+ _bt_convert_addr_type_to_string(addr, address.addr);
+ g_array_append_vals(*out_param1, addr, BT_ADDRESS_STRING_SIZE);
+ } else {
+ char *addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
+ _bt_convert_addr_type_to_string(addr, address.addr);
+ sender = (char*)g_dbus_method_invocation_get_sender(context);
+ _bt_save_invocation_context(context, result, sender,
+ function_name, (gpointer)addr);
+ }
+ break;
+ }
+ case BT_HF_DISCONNECT: {
+ bluetooth_device_address_t address = { {0} };
+
+ __bt_service_get_parameters(in_param1,
+ &address, sizeof(bluetooth_device_address_t));
+
+ result = _bt_hf_disconnect(&address);
+ if (result != BLUETOOTH_ERROR_NONE) {
+ char addr[BT_ADDRESS_STRING_SIZE];
+ _bt_convert_addr_type_to_string(addr, address.addr);
+ g_array_append_vals(*out_param1, addr, BT_ADDRESS_STRING_SIZE);
+ } else {
+ char *addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
+ _bt_convert_addr_type_to_string(addr, address.addr);
+ sender = (char*)g_dbus_method_invocation_get_sender(context);
+ _bt_save_invocation_context(context, result, sender,
+ function_name, (gpointer)addr);
+ }
+ break;
+ }
case BT_AVRCP_TARGET_CONNECT: {
bluetooth_device_address_t address = { {0} };
_bt_service_event_handler_callback avrcp_cb;
_bt_service_event_handler_callback adapter_le_cb;
_bt_service_event_handler_callback adapter_gatt_cb;
+_bt_service_event_handler_callback hf_client_cb;
void _bt_service_register_event_handler_callback(
bt_service_module_t module, _bt_service_event_handler_callback cb)
BT_INFO("Register BT_AG_MODULE callback");
ag_cb = cb;
break;
+ case BT_HFP_MODULE:
+ BT_INFO("Register BT_HFP_MODULE callback");
+ hf_client_cb = cb;
+ break;
case BT_HEALTH_MODULE:
BT_INFO("Register BT_HEALTH_MODULE callback");
hdp_cb = cb;
if (ag_cb)
ag_cb(event_type, event_data);
break;
+ case OAL_EVENT_HF_CLIENT_CONNECTING:
+ case OAL_EVENT_HF_CLIENT_DISCONNECTING:
+ case OAL_EVENT_HF_CLIENT_CONNECTED:
+ case OAL_EVENT_HF_CLIENT_DISCONNECTED:
+ if (hf_client_cb)
+ hf_client_cb(event_type, event_data);
+ break;
case OAL_EVENT_HDP_APP_REGISTERED:
case OAL_EVENT_HDP_APP_UNREGISTERED:
case OAL_EVENT_HDP_CHANNEL_CONNECTED:
BT_AVRCP_TARGET = 0x04, /* AVRCP Target Connection to remote AVRCP controller */
BT_AVRCP = 0x08, /* AVRCP ctrl Connection to remote AVRCP target */
BT_AUDIO_A2DP_SOURCE = 0x10, /* A2DP Sink Connection, remote device is A2DP Source */
- BT_AUDIO_HFP_SOURCE = 0x11 /* HSP and A2DP Sink Connection (BT_AUDIO_HSP and BT_AUDIO_A2DP_SOURCE)*/
+ BT_AUDIO_HFP_SOURCE = 0x11, /* HSP and A2DP Sink Connection (BT_AUDIO_HSP and BT_AUDIO_A2DP_SOURCE)*/
+ BT_AUDIO_AG = 0x12 /* BT_HF_CONNECT local device HF Client and remote device AG */
} bt_audio_type_t;
typedef enum {
void _bt_audio_set_current_role(bluetooth_audio_role_t role);
+int _bt_hf_connect(bluetooth_device_address_t *device_address);
+
+int _bt_hf_disconnect(bluetooth_device_address_t *device_address);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
--- /dev/null
+/*
+ * Bluetooth-frwk
+ *
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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_SERVICE_HF_CLIENT_H__
+#define __BT_SERVICE_HF_CLIENT_H__
+
+#include "bt-service-event-receiver.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "oal-hardware.h"
+#include <oal-manager.h>
+#include <bluetooth-api.h>
+
+int _bt_connect_remote_ag(bluetooth_device_address_t *device_address);
+
+int _bt_disconnect_remote_ag(bluetooth_device_address_t *device_address);
+
+void _bt_hf_client_event_handler(int oal_event, gpointer event_data);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __BT_SERVICE_HF_CLIENT_H__ */