fhub: Apply lastest FHUB4.0 bluetooth-agent 18/282518/1
authorAyush Garg <ayush.garg@samsung.com>
Tue, 4 Oct 2022 08:30:50 +0000 (14:00 +0530)
committerAyush Garg <ayush.garg@samsung.com>
Wed, 5 Oct 2022 02:39:23 +0000 (08:09 +0530)
Applied patches:

[DA] enable bluetooth-hf-agent & add service file to multi-user.target.wants for systemd
[DA] move the audio function to bluetooth-hf-agnet from application layer
[DA] add AudioMute method
[DA] add hf-test (latest version + some modification)
[DA] audio patches (DA-audio) (latest version)
- add audio-input mute function and seperate audio-in and audio-out init
- move audio init into __bt_hf_agent_connection in order to reduce latency

This patchset should be merged with the following bluetooth-capi's
patchset in order to build successfully:
bluetooth-capi change-id: I3144f6091206891a67e19e81badf80737d8c5df6

Change-Id: Id2cbdcd0dbeb8238aa19aeea1f1f87804ff06a04
Signed-off-by: shss-choi <shss.choi@samsung.com>
Signed-off-by: Ayush Garg <ayush.garg@samsung.com>
CMakeLists.txt
hf-agent/CMakeLists.txt
hf-agent/bluetooth-hf-agent.c
hf-agent/bluetooth-hf-agent.h
hf-test/CMakeLists.txt [new file with mode: 0644]
hf-test/hf-test.c [new file with mode: 0644]
packaging/bluetooth-agent.spec
packaging/bluetooth-hf-agent.service

index 6f8fc2f..492d084 100644 (file)
@@ -11,4 +11,5 @@ ADD_SUBDIRECTORY(ipsp-agent)
 ADD_SUBDIRECTORY(hid-agent)
 IF (BUILD_GCOV)
 ADD_SUBDIRECTORY(unittest)
-ENDIF (BUILD_GCOV)
\ No newline at end of file
+ENDIF (BUILD_GCOV)
+ADD_SUBDIRECTORY(hf-test)
index 7b5e4a7..b62cdfc 100644 (file)
@@ -11,13 +11,14 @@ pkg_check_modules(pkgs_hf_agent
                REQUIRED
                dlog aul bluetooth-api alarm-service capi-appfw-app-manager
                glib-2.0 gio-2.0 gio-unix-2.0 capi-system-device vconf
-               capi-system-info)
+               capi-system-info capi-media-audio-io)
 
 FOREACH(flag ${pkgs_hf_agent_CFLAGS})
        SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
 ENDFOREACH(flag)
 
-SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Werror")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE -Wall -Werror")
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie")
 
 ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS})
 TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_hf_agent_LDFLAGS})
index 87d2611..edc623a 100644 (file)
 #include "bluetooth-hf-agent.h"
 #include "bluetooth-agent-profile.h"
 
+#include <audio_io.h>
+
+#define HFP_SCO_DATA_BUFFER_SIZE       48
+#define HFP_FHUB_SAMPLE_RATE           8000
+
 #define BT_AGENT_SYSPOPUP_MAX_ATTEMPT 3
 #define CALL_ALIAS_APP_ID "org.tizen.call-ui"
 
@@ -79,6 +84,7 @@ int clcc_async_retry_count = 0;
 #define CLCC_RETRY_TIMER 100   /* 100 msec */
 
 #define HFP_HF_UUID "0000111e-0000-1000-8000-00805f9b34fb"
+#define PBAP_PCE_UUID "0000112e-0000-1000-8000-00805f9b34fb"
 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
 
 /*Below Inrospection data is exposed to bluez from agent*/
@@ -149,6 +155,10 @@ static const gchar hf_agent_introspection_xml[] =
 "               <method name='IsInbandRingtoneSupported'>"
 "                      <arg type='b' name='status' direction='out'/>"
 "               </method>"
+"               <method name='AudioMuteOn'>"
+"               </method>"
+"               <method name='AudioMuteOff'>"
+"               </method>"
 " </interface>"
 "</node>";
 
@@ -702,6 +712,14 @@ static void __hf_agent_method(GDBusConnection *connection,
                                "Supported" : "NotSupported");
                g_dbus_method_invocation_return_value(context,
                                g_variant_new("(b)", is_supported));
+       } else if (g_strcmp0(method_name, "AudioMuteOn") == 0) {
+               DBG("Going to MUTE audio");
+               bt_hf_info.is_audio_input_mute = TRUE;
+               g_dbus_method_invocation_return_value(context, NULL);
+       } else if (g_strcmp0(method_name, "AudioMuteOff") == 0) {
+               DBG("Going to UNMUTE audio");
+               bt_hf_info.is_audio_input_mute = FALSE;
+               g_dbus_method_invocation_return_value(context, NULL);
        }
 
        INFO("-");
@@ -1194,18 +1212,24 @@ static void __bt_hf_agent_handle_ind_change(bt_hf_agent_info_t *bt_hf_info,
                                        "CallStarted", NULL);
                        bt_hf_info->is_dialing = FALSE;
                        bt_hf_info->call_active = TRUE;
+                       if (TIZEN_MODEL_NAME_FHUB)
+                               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_STARTED;
                } else if (bt_hf_info->call_active) {
                        __bt_hf_agent_emit_signal(conn,
                                        BT_HF_AGENT_OBJECT_PATH,
                                        BT_HF_SERVICE_INTERFACE,
                                        "CallEnded", NULL);
                        bt_hf_info->call_active = FALSE;
+                       if (TIZEN_MODEL_NAME_FHUB)
+                               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_ENDED;
 
                        if (bt_hf_info->ciev_call_setup_status == 0) {
                                __bt_hf_agent_emit_signal(gdbus_conn,
                                                BT_HF_AGENT_OBJECT_PATH,
                                                BT_HF_SERVICE_INTERFACE,
                                                "CallIdle", NULL);
+                               if (TIZEN_MODEL_NAME_FHUB)
+                                       bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_IDLE;
                        }
                }
 
@@ -1218,6 +1242,8 @@ static void __bt_hf_agent_handle_ind_change(bt_hf_agent_info_t *bt_hf_info,
                                        BT_HF_SERVICE_INTERFACE,
                                        "CallTerminated",
                                        NULL);
+                       if (TIZEN_MODEL_NAME_FHUB)
+                               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_TERMINATED;
                } else if (!bt_hf_info->is_dialing && value > 0) {
                        bt_hf_info->is_dialing = TRUE;
                }
@@ -1227,6 +1253,8 @@ static void __bt_hf_agent_handle_ind_change(bt_hf_agent_info_t *bt_hf_info,
                                        BT_HF_AGENT_OBJECT_PATH,
                                        BT_HF_SERVICE_INTERFACE,
                                        "CallSetupIncoming", NULL);
+                       if (TIZEN_MODEL_NAME_FHUB)
+                               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_SETUP_INCOMING;
                        if (__bt_hf_agent_launch_call_app()  == FALSE)
                                DBG("call app launching failed");
                } else if (bt_hf_info->ciev_call_setup_status == 2) {
@@ -1234,17 +1262,23 @@ static void __bt_hf_agent_handle_ind_change(bt_hf_agent_info_t *bt_hf_info,
                                        BT_HF_AGENT_OBJECT_PATH,
                                        BT_HF_SERVICE_INTERFACE,
                                        "CallSetupDialing", NULL);
+                       if (TIZEN_MODEL_NAME_FHUB)
+                               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_SETUP_DIALING;
                } else if (bt_hf_info->ciev_call_setup_status == 3) {
                        __bt_hf_agent_emit_signal(gdbus_conn,
                                        BT_HF_AGENT_OBJECT_PATH,
                                        BT_HF_SERVICE_INTERFACE,
                                        "CallSetupAlerting", NULL);
+                       if (TIZEN_MODEL_NAME_FHUB)
+                               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_SETUP_ALERTING;
                } else  if (bt_hf_info->ciev_call_status == 0 &&
                                                bt_hf_info->ciev_call_setup_status == 0) {
                        __bt_hf_agent_emit_signal(gdbus_conn,
                                        BT_HF_AGENT_OBJECT_PATH,
                                        BT_HF_SERVICE_INTERFACE,
                                                "CallIdle", NULL);
+                       if (TIZEN_MODEL_NAME_FHUB)
+                               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_IDLE;
                }
        } else if (!strcmp(name, "\"callheld\"")) {
                if (value == 0) { /* No calls held*/
@@ -2515,6 +2549,196 @@ static guint __bt_hf_get_hold_mpty_features(gchar *features)
        return result;
 }
 
+/* for FHUB's HFP HF role */
+#include <sound_manager.h>
+sound_stream_info_h g_stream_info_write_h = NULL;
+
+static void __release_audio_in(bt_hf_agent_info_t *bt_hf_info)
+{
+       INFO("+");
+
+       if (bt_hf_info->audio_input != NULL) {
+               audio_in_unprepare((audio_in_h)bt_hf_info->audio_input);
+               audio_in_destroy((audio_in_h)bt_hf_info->audio_input);
+               bt_hf_info->audio_input = NULL;
+       }
+
+       INFO("-");
+}
+
+static void __release_audio_out(bt_hf_agent_info_t *bt_hf_info)
+{
+       INFO("+");
+
+       if (bt_hf_info->audio_output != NULL) {
+               audio_out_drain((audio_out_h)bt_hf_info->audio_output);
+               audio_out_unprepare((audio_out_h)bt_hf_info->audio_output);
+               audio_out_destroy((audio_out_h)bt_hf_info->audio_output);
+               bt_hf_info->audio_output = NULL;
+       }
+
+       INFO("-");
+}
+
+static int __initialize_audio_in(bt_hf_agent_info_t *bt_hf_info)
+{
+       int ret = 0;
+
+       INFO("+");
+       if (bt_hf_info->audio_input != NULL) {
+               __release_audio_in(bt_hf_info);
+       }
+
+       //init capturing
+       ret = audio_in_create(HFP_FHUB_SAMPLE_RATE, AUDIO_CHANNEL_MONO,
+                                       AUDIO_SAMPLE_TYPE_S16_LE, (audio_in_h *)&bt_hf_info->audio_input);
+       if (ret == AUDIO_IO_ERROR_NONE) {
+               if (!(audio_in_prepare((audio_in_h)bt_hf_info->audio_input))) {
+                       DBG("voice capturing is ready!\n");
+                       bt_hf_info->is_audio_input_mute = FALSE;
+               } else {
+                       ERR("audio_in_prepare failed, err(0x%x)\n", ret);
+                       audio_in_destroy((audio_in_h)bt_hf_info->audio_input);
+                       ret = -18;
+               }
+       } else {
+               ERR("audio_in_create failed.\n");
+               ret = -17;
+       }
+
+       INFO("-");
+       return ret;
+}
+
+static int __initialize_audio_out(bt_hf_agent_info_t *bt_hf_info)
+{
+       int ret = 0;
+       INFO("+");
+
+       if (bt_hf_info->audio_output != NULL) {
+               __release_audio_out(bt_hf_info);
+       }
+
+       //init playback
+       ret = audio_out_create_new(HFP_FHUB_SAMPLE_RATE, AUDIO_CHANNEL_MONO,
+                                       AUDIO_SAMPLE_TYPE_S16_LE, (audio_out_h *)&bt_hf_info->audio_output);
+       if (ret == AUDIO_IO_ERROR_NONE) {
+               INFO("after audio_out_create!!!");
+
+               /* set sound stream info */
+               if (g_stream_info_write_h) {
+                       if (!(ret = audio_out_set_sound_stream_info(bt_hf_info->audio_output, g_stream_info_write_h))) {
+                               INFO("after audio_out_set_sound_stream_info");
+                       } else {
+                               ERR("fail to audio_out_set_sound_stream_info(), ret(0x%x)\n", ret);
+                       }
+               } else {
+                       ERR("no stream info!!!!");
+               }
+
+               /* prepare */
+               if (!(ret = audio_out_prepare((audio_out_h)bt_hf_info->audio_output))) {
+                       DBG("voice playback is ready!\n");
+               } else {
+                       ERR("audio_out_prepare failed, err(0x%x)\n", ret);
+                       audio_out_destroy((audio_out_h)bt_hf_info->audio_output);
+                       bt_hf_info->audio_output = NULL;
+               }
+       } else {
+               ERR("audio_out_create failed. \n");
+       }
+
+       INFO("-");
+       return ret;
+}
+
+static gboolean __bt_hf_agent_sco_event_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
+{
+       bt_hf_agent_info_t *bt_hf_info = user_data;
+       GDBusConnection *conn;
+       int sco_skt = g_io_channel_unix_get_fd(chan);
+
+       if (cond & G_IO_NVAL)
+               return FALSE;
+
+       if (cond & (G_IO_HUP | G_IO_ERR)) {
+               g_io_channel_shutdown(chan, TRUE, NULL);
+               close(bt_hf_info->cli_sco_fd);
+               bt_hf_info->cli_sco_fd = -1;
+               g_io_channel_unref(chan);
+               DBG("Emit AudioDisconnected Signal");
+
+               sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
+
+               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_IDLE;
+               bt_hf_info->is_first_audio_out = TRUE;
+
+               __release_audio_out(bt_hf_info);
+               __release_audio_in(bt_hf_info);
+
+               conn = __bt_hf_get_gdbus_connection();
+               if (!conn) {
+                       ERR("Unable to get connection");
+                       return FALSE;
+               }
+               __bt_hf_agent_emit_signal(conn,
+                               BT_HF_AGENT_OBJECT_PATH,
+                               BT_HF_SERVICE_INTERFACE,
+                               "AudioDisconnected", NULL);
+
+               return FALSE;
+       }
+
+       if (cond & G_IO_IN) {
+               gchar buf_rx[HFP_SCO_DATA_BUFFER_SIZE] = { 0, };
+               int read;
+
+               read = recv(sco_skt, buf_rx, HFP_SCO_DATA_BUFFER_SIZE, MSG_DONTWAIT);
+               if (read > 0) {
+                       if (bt_hf_info->call_state == BT_HF_DA_CALL_STAT_CALL_SETUP_DIALING ||
+                               bt_hf_info->call_state == BT_HF_DA_CALL_STAT_CALL_SETUP_ALERTING ||
+                               bt_hf_info->call_active) {
+
+                               if (bt_hf_info->is_first_audio_out) {
+                                       __initialize_audio_out(bt_hf_info);
+                                       bt_hf_info->is_first_audio_out = FALSE;
+                               }
+                               if (bt_hf_info->audio_output) {
+                                       audio_out_write(bt_hf_info->audio_output, buf_rx, read);
+                               } else {
+                                       ERR("can't write audio");
+                               }
+                       }
+               }
+       }
+       if (cond & G_IO_OUT) {
+               gchar buf_tx[HFP_SCO_DATA_BUFFER_SIZE] = { 0, };
+               int size;
+
+               if (bt_hf_info->is_first_audio_in) {
+                       __initialize_audio_in(bt_hf_info);
+                       bt_hf_info->is_first_audio_in = FALSE;
+                       return  TRUE;
+               }
+
+               size = audio_in_read(bt_hf_info->audio_input, (void *)buf_tx, HFP_SCO_DATA_BUFFER_SIZE);
+               if (size > 0) {
+                       if (bt_hf_info->call_active) {
+
+                               if (bt_hf_info->is_audio_input_mute) {
+                                       memset(buf_tx, 0x0, size);
+                               }
+
+                               if (send(sco_skt, buf_tx, size, MSG_DONTWAIT) < 0) {
+                                       ERR("Write failed, error = %d[%s]", errno, strerror(errno));
+                               }
+                       }
+               }
+       }
+       return TRUE;
+}
+
+
 static gboolean __bt_hf_agent_sco_disconnect_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
 {
        bt_hf_agent_info_t *bt_hf_info = user_data;
@@ -2581,8 +2805,17 @@ static gboolean __bt_hf_agent_sco_accept_cb(GIOChannel *chan, GIOCondition cond,
        g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
        g_io_channel_set_buffered(sco_io, FALSE);
 
-       g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                                       __bt_hf_agent_sco_disconnect_cb, bt_hf_info);
+       if (TIZEN_MODEL_NAME_FHUB) {
+               bt_hf_info->call_state = BT_HF_DA_CALL_STAT_CALL_IDLE;
+               bt_hf_info->is_first_audio_out = TRUE;
+               bt_hf_info->is_first_audio_in = TRUE;
+               //__initialize_audio_in(bt_hf_info);
+
+               g_io_add_watch(sco_io, G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                                               __bt_hf_agent_sco_event_cb, bt_hf_info);
+       } else
+               g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                                               __bt_hf_agent_sco_disconnect_cb, bt_hf_info);
 
        if (bt_hf_info->state != BT_HF_STATE_CONNECTED)
                ERR("HFP is not yet connected");
@@ -2789,14 +3022,22 @@ static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info
        gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
        gboolean ret;
        char *buf_ptr;
-       guint feature = BT_HF_FEATURE_EC_ANDOR_NR |
-                       BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
-                       BT_HF_FEATURE_CLI_PRESENTATION |
-                       BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
-                       BT_HF_FEATURE_ENHANCED_CALL_STATUS;
-
-       if (TIZEN_PROFILE_WEARABLE)
-               feature = feature | BT_HF_FEATURE_CODEC_NEGOTIATION;
+       guint feature;
+
+       if (TIZEN_MODEL_NAME_FHUB)
+               feature = BT_HF_FEATURE_CLI_PRESENTATION |
+                               BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
+                               BT_HF_FEATURE_ENHANCED_CALL_STATUS;
+       else {
+               feature = BT_HF_FEATURE_EC_ANDOR_NR |
+                               BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
+                               BT_HF_FEATURE_CLI_PRESENTATION |
+                               BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
+                               BT_HF_FEATURE_ENHANCED_CALL_STATUS;
+
+               if (TIZEN_PROFILE_WEARABLE)
+                       feature = feature | BT_HF_FEATURE_CODEC_NEGOTIATION;
+       }
 
        snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_FEATURES, feature);
        ret = __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf,
@@ -3205,11 +3446,18 @@ static int __bt_hf_register_profile(const char *uuid, uint16_t version,
        g_variant_builder_add(builder, "{sv}",
                        "features", g_variant_new("q", features));
 
-       ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
-                               g_variant_new("(osa{sv})", path,
-                                       HFP_HF_UUID, builder),
-                               G_DBUS_CALL_FLAGS_NONE, -1,
-                               NULL, &error);
+       if (TIZEN_MODEL_NAME_FHUB)
+               ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
+                                       g_variant_new("(osa{sv})", object,
+                                               uuid, builder),
+                                       G_DBUS_CALL_FLAGS_NONE, -1,
+                                       NULL, &error);
+       else
+               ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
+                                       g_variant_new("(osa{sv})", path,
+                                               HFP_HF_UUID, builder),
+                                       G_DBUS_CALL_FLAGS_NONE, -1,
+                                       NULL, &error);
 
        g_variant_builder_unref(builder);
 
@@ -3246,7 +3494,15 @@ static void __bt_hf_agent_register(void)
        ret = __bt_hf_register_profile(HFP_HF_UUID, version, name, path,
                                                                features);
        if (ret)
-               ERR("Error in register");
+               ERR("Error in hf register");
+
+       if (TIZEN_MODEL_NAME_FHUB) {
+               ret = __bt_hf_register_profile(PBAP_PCE_UUID, 0x0101,
+                                       "Phone Book Access Client",
+                                       BT_PBAP_CLIENT_OBJECT_PATH, 0);
+               if (ret)
+                       ERR("Error in pce register");
+       }
 
        g_free(path);
        g_free(name);
@@ -3777,15 +4033,23 @@ static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd)
 
 static uint32_t __bt_hf_agent_get_hf_features(void)
 {
-       uint32_t hf_features = BT_HF_FEATURE_EC_ANDOR_NR |
-                       BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
-                       BT_HF_FEATURE_CLI_PRESENTATION |
-                       BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
-                       BT_HF_FEATURE_ENHANCED_CALL_STATUS |
-                       BT_HF_FEATURE_CODEC_NEGOTIATION;
+       uint32_t hf_features;
 
-       if (TIZEN_PROFILE_WEARABLE)
-               hf_features = hf_features | BT_HF_FEATURE_CODEC_NEGOTIATION;
+       if (TIZEN_MODEL_NAME_FHUB)
+               hf_features = BT_HF_FEATURE_CLI_PRESENTATION |
+                               BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
+                               BT_HF_FEATURE_ENHANCED_CALL_STATUS;
+       else {
+               hf_features = BT_HF_FEATURE_EC_ANDOR_NR |
+                               BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
+                               BT_HF_FEATURE_CLI_PRESENTATION |
+                               BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
+                               BT_HF_FEATURE_ENHANCED_CALL_STATUS |
+                               BT_HF_FEATURE_CODEC_NEGOTIATION;
+
+               if (TIZEN_PROFILE_WEARABLE)
+                       hf_features = hf_features | BT_HF_FEATURE_CODEC_NEGOTIATION;
+       }
 
        hf_ver = HFP_VERSION_1_6;
 
@@ -3806,6 +4070,9 @@ int main(void)
        hf_features = __bt_hf_agent_get_hf_features();
        bt_hf_info.feature = (uint16_t) hf_features & 0x3F;
 
+       bt_hf_info.audio_input = NULL;
+       bt_hf_info.audio_output = NULL;
+
        memset(&sa, 0, sizeof(sa));
        sa.sa_flags = SA_NOCLDSTOP;
        sa.sa_handler = __bt_hf_agent_sigterm_handler;
index d544bae..bbac08a 100644 (file)
@@ -106,6 +106,8 @@ extern "C" {
 #define BT_HF_SERVICE_INTERFACE "org.tizen.HfApp"
 #define BT_HF_BLUEZ_OBJECT_PATH "/org/tizen/handsfree"
 #define BT_HF_BLUEZ_INTERFACE  "org.bluez.HandsfreeAgent"
+#define BT_PBAP_CLIENT_OBJECT_PATH "/org/tizen/pbap_client"
+
 #define BLUEZ_SERVICE_NAME "org.bluez"
 #define BLUEZ_HF_INTERFACE_NAME "org.bluez.HandsfreeGateway"
 #define BLUEZ_PROFILE_MGMT_INTERFACE "org.bluez.ProfileManager1"
@@ -259,6 +261,17 @@ typedef enum {
        BT_HF_CALL_STAT_WAITING,
 } bt_hf_call_status_t;
 
+typedef enum {
+       BT_HF_DA_CALL_STAT_CALL_STARTED,
+       BT_HF_DA_CALL_STAT_CALL_ENDED,
+       BT_HF_DA_CALL_STAT_CALL_IDLE,
+       BT_HF_DA_CALL_STAT_CALL_TERMINATED,
+       BT_HF_DA_CALL_STAT_CALL_WAITING,
+       BT_HF_DA_CALL_STAT_CALL_SETUP_INCOMING,
+       BT_HF_DA_CALL_STAT_CALL_SETUP_DIALING,
+       BT_HF_DA_CALL_STAT_CALL_SETUP_ALERTING,
+} bt_hf_da_call_status_t;
+
 typedef struct {
        guint32 fd;
        gint sco_fd;
@@ -293,6 +306,13 @@ typedef struct {
 
        GDBusMethodInvocation *context;
        char *path;
+
+       void *audio_output;
+       void *audio_input;
+       bt_hf_da_call_status_t call_state;
+       gboolean is_first_audio_out;
+       gboolean is_first_audio_in;
+       gboolean is_audio_input_mute;
 } bt_hf_agent_info_t;
 
 typedef struct {
diff --git a/hf-test/CMakeLists.txt b/hf-test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..21754f7
--- /dev/null
@@ -0,0 +1,25 @@
+PROJECT(hf_role_test C)
+
+SET(fw_test "hf-test")
+
+SET(dependents "capi-base-common glib-2.0 capi-network-bluetooth")
+SET(pc_dependents "capi-base-common")
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(${fw_test} REQUIRED ${dependents})
+FOREACH(flag ${${fw_test}_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wall -fPIE")
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie")
+
+aux_source_directory(. sources)
+FOREACH(src ${sources})
+       GET_FILENAME_COMPONENT(src_name ${src} NAME_WE)
+       MESSAGE("${src_name}")
+       ADD_EXECUTABLE(${src_name} ${src})
+       TARGET_LINK_LIBRARIES(${src_name} ${fw_name} ${${fw_test}_LDFLAGS})
+ENDFOREACH()
+
+INSTALL(TARGETS hf-test RUNTIME DESTINATION bin/)
diff --git a/hf-test/hf-test.c b/hf-test/hf-test.c
new file mode 100644 (file)
index 0000000..edaa0ae
--- /dev/null
@@ -0,0 +1,566 @@
+#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;
+}
+
index f6c36e0..81da085 100644 (file)
@@ -11,6 +11,7 @@ Source1001:   bluetooth-agent.manifest
 
 BuildRequires:  pkgconfig(aul)
 BuildRequires:  pkgconfig(bluetooth-api)
+BuildRequires:  pkgconfig(capi-media-audio-io)
 
 # The profile macro usage with the following comments may be removed after
 # Tizen OBS build projects are merged. However, each vendor may keep using
@@ -98,6 +99,12 @@ Group:      Network & Connectivity/Bluetooth
 %description ipsp
 Bluetooth agent binary compiled for IPSP(Internet Protocol Support Profile)
 
+%package tool
+Summary:       Test Application for HF
+
+%description tool
+Test Application for HF
+
 %prep
 %setup -q
 cp %{SOURCE1001} .
@@ -148,6 +155,9 @@ find . -name '*.gcno' -exec cp '{}' gcov-obj ';'
 rm -rf %{buildroot}
 %make_install
 
+mkdir -p %{buildroot}%{_libdir}/systemd/system/
+mkdir -p %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/
+
 # This usage of profile macro does NOT conflict 4.0 configurability.
 #%if "%{?profile}" != "mobile" && "%{?profile}" != "tv"
 # Original: wearable, ivi. Added: common, "undefined"
@@ -176,6 +186,9 @@ pushd unittest
 popd
 %endif
 
+install -D -m 0644 packaging/bluetooth-hf-agent.service %{buildroot}%{_libdir}/systemd/system/bluetooth-hf-agent.service
+ln -s ../bluetooth-hf-agent.service %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/bluetooth-hf-agent.service
+
 %files
 %manifest %{name}.manifest
 %license LICENSE
@@ -204,6 +217,8 @@ popd
 %{_unitdir}/bluetooth-hf-agent.service
 #%exclude %{_unitdir}/bluetooth-map-agent.service
 #%exclude %{_unitdir}/bluetooth-pbap-agent.service
+%{_libdir}/systemd/system/bluetooth-hf-agent.service
+%{_libdir}/systemd/system/multi-user.target.wants/bluetooth-hf-agent.service
 
 %files map
 %manifest %{name}.manifest
@@ -235,3 +250,6 @@ popd
 %{_bindir}/bluetooth-ipsp-agent
 %{_datadir}/dbus-1/system-services/org.bluez.ipsp_agent.service
 %{_sysconfdir}/dbus-1/system.d/bluetooth-ipsp-agent.conf
+
+%files tool
+%{_bindir}/hf-test
index db368b8..2407817 100644 (file)
@@ -4,6 +4,7 @@ Description=Bluetooth HF Agent
 [Service]
 User=network_fw
 Group=network_fw
+SupplementaryGroups=system_share
 SmackProcessLabel=System
 Type=dbus
 BusName=org.bluez.hf_agent