+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <bluetooth.h>
+#include <bluetooth_extension.h>
+
+#define LOG_RED "\033[0;31m"
+#define LOG_GREEN "\033[0;32m"
+#define LOG_BROWN "\033[0;33m"
+#define LOG_BLUE "\033[0;34m"
+#define LOG_END "\033[0;m"
+
+#define BT_PROFILE_SERVICE_UUID_HFP_HF "111e"
+#define BT_PROFILE_SERVICE_UUID_HFP_AG "111f"
+#define BT_PROFILE_SERVICE_UUID_A2DP_SOURCE "110a"
+#define BT_PROFILE_SERVICE_UUID_A2DP_SINK "110b"
+#define PHONE_NUMBER_LENGTH 15
+
+
+static const char *__bt_get_error(bt_error_e err)
+{
+ const char *err_str = NULL;
+
+ switch (err) {
+ case BT_ERROR_NONE:
+ err_str = "BT_ERROR_NONE";
+ break;
+ case BT_ERROR_CANCELLED:
+ err_str = "BT_ERROR_CANCELLED";
+ break;
+ case BT_ERROR_INVALID_PARAMETER:
+ err_str = "BT_ERROR_INVALID_PARAMETER";
+ break;
+ case BT_ERROR_OUT_OF_MEMORY:
+ err_str = "BT_ERROR_OUT_OF_MEMORY";
+ break;
+ case BT_ERROR_RESOURCE_BUSY:
+ err_str = "BT_ERROR_RESOURCE_BUSY";
+ break;
+ case BT_ERROR_TIMED_OUT:
+ err_str = "BT_ERROR_TIMED_OUT";
+ break;
+ case BT_ERROR_NOW_IN_PROGRESS:
+ err_str = "BT_ERROR_NOW_IN_PROGRESS";
+ break;
+ case BT_ERROR_NOT_INITIALIZED:
+ err_str = "BT_ERROR_NOT_INITIALIZED";
+ break;
+ case BT_ERROR_NOT_ENABLED:
+ err_str = "BT_ERROR_NOT_ENABLED";
+ break;
+ case BT_ERROR_ALREADY_DONE:
+ err_str = "BT_ERROR_ALREADY_DONE";
+ break;
+ case BT_ERROR_OPERATION_FAILED:
+ err_str = "BT_ERROR_OPERATION_FAILED";
+ break;
+ case BT_ERROR_NOT_IN_PROGRESS:
+ err_str = "BT_ERROR_NOT_IN_PROGRESS";
+ break;
+ case BT_ERROR_REMOTE_DEVICE_NOT_BONDED:
+ err_str = "BT_ERROR_REMOTE_DEVICE_NOT_BONDED";
+ break;
+ case BT_ERROR_AUTH_REJECTED:
+ err_str = "BT_ERROR_AUTH_REJECTED";
+ break;
+ case BT_ERROR_AUTH_FAILED:
+ err_str = "BT_ERROR_AUTH_FAILED";
+ break;
+ case BT_ERROR_REMOTE_DEVICE_NOT_FOUND:
+ err_str = "BT_ERROR_REMOTE_DEVICE_NOT_FOUND";
+ break;
+ case BT_ERROR_SERVICE_SEARCH_FAILED:
+ err_str = "BT_ERROR_SERVICE_SEARCH_FAILED";
+ break;
+ case BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED:
+ err_str = "BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED";
+ break;
+ case BT_ERROR_PERMISSION_DENIED:
+ err_str = "BT_ERROR_PERMISSION_DENIED";
+ break;
+ case BT_ERROR_SERVICE_NOT_FOUND:
+ err_str = "BT_ERROR_SERVICE_NOT_FOUND";
+ break;
+ case BT_ERROR_NO_DATA:
+ err_str = "BT_ERROR_NO_DATA";
+ break;
+ case BT_ERROR_NOT_SUPPORTED:
+ err_str = "BT_ERROR_NOT_SUPPORTED";
+ break;
+ case BT_ERROR_DEVICE_POLICY_RESTRICTION:
+ err_str = "DEVICE_POLICY_RESTRICTION";
+ break;
+ default:
+ err_str = "NOT Defined";
+ break;
+ }
+
+ return err_str;
+}
+
+
+gboolean test_thread(GIOChannel *source, GIOCondition condition, gpointer data);
+
+static char remote_phone_number[PHONE_NUMBER_LENGTH] = "+8200000000000";
+static char remote_phone_bt_mac[18] = "00:00:00:00:00:00";
+static int remote_phone_pb_size = 0;
+static bool ringing_status = false;
+
+void __bt_hf_set_remote_call_event_cb(bt_hf_remote_call_event_e event,
+ char *phone_number, void *user_data)
+{
+ switch (event) {
+ case BT_HF_REMOTE_CALL_EVENT_IDLE: {
+ printf("[remote_call_event_cb] event [IDLE]\n");
+ if (ringing_status) {
+ printf("[APP] STOP ALARM\n");
+ ringing_status = false;
+ }
+ break;
+ }
+ case BT_HF_REMOTE_CALL_EVENT_INCOMING:
+ printf("[remote_call_event_cb] event [INCOMING]\n");
+ break;
+ case BT_HF_REMOTE_CALL_EVENT_DIALING: {
+ int ret = 0;
+ GSList *list;
+
+ printf("[remote_call_event_cb] event [DIALING]\n");
+ ret = bt_hf_get_call_status_info_list(&list);
+
+ if (ret < BT_ERROR_NONE)
+ printf("failed with [0x%04x]\n", ret);
+ else {
+ for (; list; list = g_slist_next(list)) {
+ bt_hf_call_status_info_s *call_info = list->data;
+ printf("[CALL INFO] number : %s\n", call_info->number);
+ printf("[CALL INFO] direction (0: outgoing, 1: incoming) : %d\n", call_info->direction);
+ printf("[CALL INFO] status (0: active, 1: held, 2: dialing, 3: alerting) : %d\n", call_info->status);
+ strncpy(remote_phone_number, call_info->number, PHONE_NUMBER_LENGTH - 1);
+ }
+ bt_hf_free_call_status_info_list(list);
+ }
+ break;
+ }
+ case BT_HF_REMOTE_CALL_EVENT_ALERTING:
+ printf("[remote_call_event_cb] event [ALERTING]\n");
+ printf("[remote_call_event_cb] number : %s\n", remote_phone_number);
+ break;
+ case BT_HF_REMOTE_CALL_EVENT_CALL_TERMINATED:
+ printf("[remote_call_event_cb] event [TERMINATED]\n");
+ break;
+ case BT_HF_REMOTE_CALL_EVENT_CALL_STARTED: {
+ printf("[remote_call_event_cb] event [STARTED]\n");
+ if (ringing_status) {
+ printf("[APP] STOP ALARM\n");
+ ringing_status = false;
+ }
+ break;
+ }
+ case BT_HF_REMOTE_CALL_EVENT_CALL_ENDED:
+ printf("[remote_call_event_cb] event [ENDED]\n");
+ break;
+ case BT_HF_REMOTE_CALL_EVENT_UNHELD:
+ printf("[remote_call_event_cb] event [UNHELD]\n");
+ break;
+ case BT_HF_REMOTE_CALL_EVENT_HELD:
+ printf("[remote_call_event_cb] event [HELD]\n");
+ break;
+ case BT_HF_REMOTE_CALL_EVENT_RINGING: {
+ printf("[remote_call_event_cb] event [RINGING]\n");
+ printf("[remote_call_event_cb] phone_number [%s]\n", phone_number);
+ if (!ringing_status) {
+ printf("[APP] START ALARM\n");
+ ringing_status = true;
+ }
+ break;
+ }
+ case BT_HF_REMOTE_CALL_EVENT_WAITING:
+ printf("[remote_call_event_cb] event [WAITING]\n");
+ break;
+ case BT_HF_REMOTE_CALL_EVENT_FAILED_TO_DIALING:
+ printf("[remote_call_event_cb] event [FAILED_TO_DIALING]\n");
+ break;
+ default:
+ printf("[remote_call_event_cb] event [UNKNOWN]\n");
+ }
+
+}
+
+
+void __bt_pbap_phonebook_pull_cb(int result, const char *remote_address,
+ const char *vcf_file, void *user_data)
+{
+ printf("[__bt_pbap_phonebook_pull_cb] Result: %d\n", result);
+ printf("[__bt_pbap_phonebook_pull_cb] Remote Device: %s\n", remote_address);
+ printf("[__bt_pbap_phonebook_pull_cb] Phonebook Download File: %s\n", vcf_file);
+ printf("[__bt_pbap_phonebook_pull_cb] Phonebook Download Status: %s\n",
+ (result == BT_ERROR_NONE) ? "Successful" : "Unsuccessful");
+
+ if (result == BT_ERROR_NONE) {
+ printf("[__bt_pbap_phonebook_pull_cb] PHONEBOOK DOWNLOAD DONE.. DISCONNECT PBAP CLIENT\n");
+ } else
+ printf("[__bt_pbap_phonebook_pull_cb] PHONEBOOK DOWNLOAD FAILED.. (ERROR: %s)\n", __bt_get_error(result));
+}
+
+void __bt_pbap_phonebook_size_cb(int result, const char *remote_address, int size, void *user_data)
+{
+ int ret = 0;
+
+ printf("[__bt_pbap_phonebook_size_cb] Result: %d\n", result);
+ printf("[__bt_pbap_phonebook_size_cb] Remote Device: %s\n", remote_address);
+ printf("[__bt_pbap_phonebook_size_cb] Phonebook Size: %d\n", size);
+
+ remote_phone_pb_size = size;
+
+ if (result == BT_ERROR_NONE) {
+ ret = bt_pbap_client_get_phone_book(remote_address, BT_PBAP_SOURCE_DEVICE, BT_PBAP_FOLDER_PHONE_BOOK,
+ BT_PBAP_VCARD_FORMAT_VCARD30, BT_PBAP_ORDER_INDEXED, 0, size, BT_PBAP_FIELD_N | BT_PBAP_FIELD_TEL,
+ __bt_pbap_phonebook_pull_cb, NULL);
+ if (ret != BT_ERROR_NONE) {
+ printf("bt_pbap_client_get_phone_book failed (%d)\n", ret);
+ }
+ }
+}
+void __bt_pbap_connection_state_changed_cb(int result, bool connected, const char *remote_address, void *user_data)
+{
+ int ret = 0;
+
+ printf("[__bt_pbap_connection_state_changed_cb] Result: %d\n", result);
+ printf("[__bt_pbap_connection_state_changed_cb] Remote Device: %s\n", remote_address);
+ printf("[__bt_pbap_connection_state_changed_cb] Connected Status: %d\n", connected);
+
+ // if phone is PBAP connected, get connected mobile's phonebook size
+ if ((result == 0) && connected) {
+ ret = bt_pbap_client_get_phone_book_size(remote_address, BT_PBAP_SOURCE_DEVICE,
+ BT_PBAP_FOLDER_PHONE_BOOK, __bt_pbap_phonebook_size_cb, NULL);
+ if (ret != BT_ERROR_NONE) {
+ printf("bt_pbap_client_get_phone_book_size failed (%s)\n", __bt_get_error(result));
+ }
+ }
+}
+
+void __bt_audio_connection_state_changed_cb(int result, bool connected,
+ const char *remote_address, bt_audio_profile_type_e type, void *user_data)
+{
+
+ if (type == BT_AUDIO_PROFILE_TYPE_AG) {
+ printf("[__bt_audio_connection_state_changed_cb] result : %d\n", result);
+ printf("[__bt_audio_connection_state_changed_cb] connected : %d\n", connected);
+ printf("[__bt_audio_connection_state_changed_cb] address : %s\n", remote_address);
+ printf("[__bt_audio_connection_state_changed_cb] type : %d\n", type);
+
+ if (connected) {
+ printf("[__bt_audio_connection_state_changed_cb] mobile connected!!!!\n");
+
+ strncpy(remote_phone_bt_mac, remote_address, strlen(remote_phone_bt_mac));
+ }
+ if (!connected) {
+ printf("[__bt_audio_connection_state_changed_cb] mobile disconnected!!!!\n");
+ if (ringing_status) {
+ //mobile is disconnected during RINING event.. Stop all alarm
+ printf("[APP] STOP ALARM\n");
+ ringing_status = false;
+ }
+ }
+ }
+}
+
+static int initialize_bluetooth(void)
+{
+ int ret;
+
+ ret = bt_initialize();
+ if (ret != BT_ERROR_NONE) {
+ printf("bt_initialize failed (%s)\n", __bt_get_error(ret));
+ return -1;
+ }
+
+ ret = bt_audio_initialize();
+ if (ret != BT_ERROR_NONE) {
+ printf("bt_audio_initialize failed (%s)\n", __bt_get_error(ret));
+ return -1;
+ }
+
+ ret = bt_hf_initialize();
+ if (ret != BT_ERROR_NONE) {
+ printf("bt_hf_initialize failed (%s)\n", __bt_get_error(ret));
+ }
+
+ ret = bt_hf_set_remote_call_event_cb(__bt_hf_set_remote_call_event_cb, NULL);
+ if (ret != BT_ERROR_NONE) {
+ printf("bt_hf_set_remote_call_event_cb failed (%s)\n", __bt_get_error(ret));
+ return -1;
+ }
+
+ ret = bt_audio_set_connection_state_changed_cb(__bt_audio_connection_state_changed_cb, NULL);
+ if (ret != BT_ERROR_NONE) {
+ printf("bt_audio_set_connection_state_changed_cb failed (%s)\n", __bt_get_error(ret));
+ }
+
+ // PBAP initialize
+ ret = bt_pbap_client_initialize();
+ if (ret != BT_ERROR_NONE && ret != BT_ERROR_ALREADY_DONE) {
+ printf("bt_pbap_client_initialize failed (%s)\n", __bt_get_error(ret));
+ }
+
+ ret = bt_pbap_client_set_connection_state_changed_cb(__bt_pbap_connection_state_changed_cb, NULL);
+ if (ret != BT_ERROR_NONE) {
+ printf("bt_pbap_client_set_connection_state_changed_cb failed (%s)\n", __bt_get_error(ret));
+ }
+
+ return 1;
+}
+
+void test_deinitialize(void)
+{
+ int ret = 0;
+
+ ret = bt_hf_unset_remote_call_event_cb();
+ if (ret != BT_ERROR_NONE && ret != BT_ERROR_NOT_INITIALIZED) {
+ printf("bt_hf_unset_remote_call_event_cb failed (%s)\n", __bt_get_error(ret));
+ }
+
+ ret = bt_pbap_client_unset_connection_state_changed_cb();
+ if (ret != BT_ERROR_NONE && ret != BT_ERROR_NOT_INITIALIZED) {
+ printf("bt_pbap_client_unset_connection_state_changed_cb failed (%s)\n", __bt_get_error(ret));
+ }
+
+ ret = bt_audio_unset_connection_state_changed_cb();
+ if (ret != BT_ERROR_NONE && ret != BT_ERROR_NOT_INITIALIZED) {
+ printf("bt_audio_set_connection_state_changed_cb failed (%s)\n", __bt_get_error(ret));
+ }
+
+ ret = bt_pbap_client_deinitialize();
+ if (ret != BT_ERROR_NONE && ret != BT_ERROR_NOT_INITIALIZED) {
+ printf("bt_pbap_client_deinitialize failed (%s)\n", __bt_get_error(ret));
+ }
+
+ ret = bt_hf_deinitialize();
+ if (ret != BT_ERROR_NONE && ret != BT_ERROR_NOT_INITIALIZED) {
+ printf("bt_hf_deinitialize failed (%s)\n", __bt_get_error(ret));
+ }
+
+ ret = bt_audio_deinitialize();
+ if (ret != BT_ERROR_NONE && ret != BT_ERROR_NOT_INITIALIZED) {
+ printf("bt_audio_deinitialize failed (%s)\n", __bt_get_error(ret));
+ }
+
+ ret = bt_deinitialize();
+ if (ret != BT_ERROR_NONE && ret != BT_ERROR_NOT_INITIALIZED) {
+ printf("bt_deinitialize failed (%s)\n", __bt_get_error(ret));
+ }
+
+}
+int test_accept_incoming_call(void)
+{
+ int ret = 0;
+ ret = bt_hf_notify_call_event(BT_HF_CALL_EVENT_ANSWER, NULL);
+
+ if (ret != BT_ERROR_NONE) {
+ printf("bt_hf_notify_call_event(BT_HF_CALL_EVENT_ANSWER) failed (%s)\n", __bt_get_error(ret));
+ return -1;
+ } else
+ printf("[SUCCESS] accept incoming call\n");
+
+ return 1;
+}
+
+int test_initiate_call(void)
+{
+ int ret = 0;
+
+ printf("Input full phone number to dial : ");
+ ret = scanf("%14s", remote_phone_number);
+
+ ret = bt_hf_notify_call_event(BT_HF_CALL_EVENT_DIAL, remote_phone_number);
+ if (ret != BT_ERROR_NONE) {
+ printf("bt_hf_notify_call_event(BT_HF_CALL_EVENT_DIAL) failed (%s)\n", __bt_get_error(ret));
+ printf("phone number : %s", remote_phone_number);
+ return -1;
+ } else
+ printf("[SUCCESS] initiate call.. [%s]\n", remote_phone_number);
+
+ return 1;
+}
+
+int test_terminate_call(void)
+{
+ int ret = 0;
+ ret = bt_hf_notify_call_event(BT_HF_CALL_EVENT_IDLE, NULL);
+
+ if (ret != BT_ERROR_NONE) {
+ printf("bt_hf_notify_call_event(BT_HF_CALL_EVENT_IDLE) failed (%s)\n", __bt_get_error(ret));
+ return -1;
+ } else
+ printf("[SUCCESS] terminate call\n");
+
+ return 1;
+}
+
+int test_audio_mute_on(void)
+{
+ int ret = 0;
+ ret = bt_hf_notify_call_event(BT_HF_CALL_EVENT_AUDIO_MUTE_ON, NULL);
+
+ if (ret != BT_ERROR_NONE) {
+ printf("bt_hf_notify_call_event(BT_HF_CALL_EVENT_AUDIO_MUTE_ON) failed (%s)\n", __bt_get_error(ret));
+ return -1;
+ } else
+ printf("[SUCCESS] audio mute\n");
+
+ return 1;
+}
+
+int test_audio_mute_off(void)
+{
+ int ret = 0;
+ ret = bt_hf_notify_call_event(BT_HF_CALL_EVENT_AUDIO_MUTE_OFF, NULL);
+
+ if (ret != BT_ERROR_NONE) {
+ printf("bt_hf_notify_call_event(BT_HF_CALL_EVENT_AUDIO_MUTE_OFF) failed (%s)\n", __bt_get_error(ret));
+ return -1;
+ } else
+ printf("[SUCCESS] audio unmute\n");
+
+ return 1;
+}
+
+int test_pbap_connect(void)
+{
+ int ret = 0;
+
+ // try to PBAP connect to connected mobile phone device
+ ret = bt_pbap_client_connect(remote_phone_bt_mac);
+ if (ret != BT_ERROR_NONE) {
+ if (ret == BT_ERROR_ALREADY_DONE) {
+ printf("PBAP already connected [%s]\n", remote_phone_bt_mac);
+
+ /// if phone is PBAP connected, get connected mobile's phonebook size
+ ret = bt_pbap_client_get_phone_book_size(remote_phone_bt_mac, BT_PBAP_SOURCE_DEVICE,
+ BT_PBAP_FOLDER_PHONE_BOOK, __bt_pbap_phonebook_size_cb, NULL);
+ if (ret != BT_ERROR_NONE) {
+ printf("bt_pbap_client_get_phone_book_size failed (%s)\n", __bt_get_error(ret));
+ }
+ } else {
+ printf("bt_pbap_client_connect failed (%s)\n", __bt_get_error(ret));
+ return -1;
+ }
+ } else
+ printf("[SUCCESS] pbap connect.. [%s]\n", remote_phone_bt_mac);
+
+ return 1;
+}
+
+int test_pbap_disconnect(void)
+{
+ int ret = 0;
+
+ // try to PBAP connect to connected mobile phone device
+ ret = bt_pbap_client_disconnect(remote_phone_bt_mac);
+ if (ret != BT_ERROR_NONE) {
+ printf("bt_pbap_client_disconnect failed (%s)\n", __bt_get_error(ret));
+ return -1;
+ } else
+ printf("[SUCCESS] pbap disconnect.. [%s]\n", remote_phone_bt_mac);
+
+ return 1;
+}
+
+int main(void)
+{
+ GMainLoop *gmain_loop;
+
+ gmain_loop = g_main_loop_new(NULL, FALSE);
+
+ if (gmain_loop == NULL) {
+ printf("GMainLoop create failed\n");
+ return EXIT_FAILURE;
+ }
+
+ GIOChannel *channel = g_io_channel_unix_new(0);
+ g_io_add_watch(channel, (G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL), test_thread, NULL);
+
+ printf("Test Thread created...\n");
+
+ g_main_loop_run(gmain_loop);
+
+ if (gmain_loop)
+ g_main_loop_unref(gmain_loop);
+
+ return 0;
+}
+
+gboolean test_thread(GIOChannel *source, GIOCondition condition, gpointer data)
+{
+ int rv;
+ char a[10];
+
+ printf("Event received from stdin\n");
+
+ rv = read(0, a, 10);
+
+ if (rv <= 0 || a[0] == '0') {
+ test_deinitialize();
+ exit(1);
+ }
+
+ if (a[0] == '\n' || a[0] == '\r') {
+/* Public API */
+ printf("\n\n Bluetooth HFP Test App\n\n");
+ printf("Options..\n");
+ printf(LOG_GREEN "1 - Bluetooth init and set callbacks\n" LOG_END);
+ printf("2 - accept incoming call\n");
+ printf("3 - initiate call\n");
+ printf("4 - terminatate call\n");
+ printf("5 - audio mute\n");
+ printf("6 - audio unmute\n");
+ printf("7 - connect PBAP\n");
+ printf("8 - disconnect PBAP\n");
+ printf(LOG_RED "0 - Exit \n" LOG_END);
+
+ printf("ENTER - Show options menu.......\n");
+ }
+
+ switch (a[0]) {
+/* Public API */
+ case '1':
+ rv = initialize_bluetooth();
+ break;
+ case '2':
+ rv = test_accept_incoming_call();
+ break;
+ case '3':
+ rv = test_initiate_call();
+ break;
+ case '4':
+ rv = test_terminate_call();
+ break;
+ case '5':
+ rv = test_audio_mute_on();
+ break;
+ case '6':
+ rv = test_audio_mute_off();
+ break;
+ case '7':
+ rv = test_pbap_connect();
+ break;
+ case '8':
+ rv = test_pbap_disconnect();
+ break;
+
+ default:
+ break;
+ }
+
+ if (rv == 1)
+ printf("Operation succeeded!\n");
+ else
+ printf("Operation failed!\n");
+
+ return TRUE;
+}
+