2014-11-28 09:37:20

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v2 0/5] android/handsfree-client: Add SCO to HFP HF

Last missing piece to HFP HF implementation.

v2:
* Handled Szymon comments
* rebase and minor self review fixes in 2/5

Lukasz Rymanowski (5):
android/handsfree-client: Add SCO to handsfree client
android/handsfree-client: Add handle incoming SCO connection
android/handsfree-client: Implement audio connect/disconnect
android/handsfree-client: Send AT+BCC to start codec negotiation
android/README: Update status of HAL HFP HF implementation

android/README | 2 +-
android/handsfree-client.c | 191 ++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 180 insertions(+), 13 deletions(-)

--
1.8.4



2014-11-28 09:37:21

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v2 1/5] android/handsfree-client: Add SCO to handsfree client

---
android/handsfree-client.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)

diff --git a/android/handsfree-client.c b/android/handsfree-client.c
index 283519f..9e67c7f 100644
--- a/android/handsfree-client.c
+++ b/android/handsfree-client.c
@@ -47,6 +47,7 @@
#include "bluetooth.h"
#include "hal-msg.h"
#include "handsfree-client.h"
+#include "sco.h"

#define HFP_HF_CHANNEL 7

@@ -139,6 +140,8 @@ static uint32_t hfp_hf_record_id = 0;
static struct queue *devices = NULL;
static GIOChannel *hfp_hf_server = NULL;

+static struct bt_sco *sco = NULL;
+
static struct device *find_default_device(void)
{
return queue_peek_head(devices);
@@ -1999,6 +2002,11 @@ static void cleanup_hfp_hf(void)
bt_adapter_remove_record(hfp_hf_record_id);
hfp_hf_record_id = 0;
}
+
+ if (sco) {
+ bt_sco_unref(sco);
+ sco = NULL;
+ }
}

bool bt_hf_client_register(struct ipc *ipc, const bdaddr_t *addr)
@@ -2016,6 +2024,12 @@ bool bt_hf_client_register(struct ipc *ipc, const bdaddr_t *addr)
if (!enable_hf_client())
goto failed;

+ sco = bt_sco_new(addr);
+ if (!sco) {
+ error("hf-client: Cannot create SCO. HFP AG is in use ?");
+ goto failed;
+ }
+
hal_ipc = ipc;
ipc_register(hal_ipc, HAL_SERVICE_ID_HANDSFREE_CLIENT, cmd_handlers,
G_N_ELEMENTS(cmd_handlers));
@@ -2023,6 +2037,7 @@ bool bt_hf_client_register(struct ipc *ipc, const bdaddr_t *addr)
return true;

failed:
+ cleanup_hfp_hf();
queue_destroy(devices, free);
devices = NULL;

--
1.8.4


2014-11-28 09:37:24

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v2 4/5] android/handsfree-client: Send AT+BCC to start codec negotiation

With this patch we start codec negotation on audio connect if both sides
does support it.

This patch also moves codec_negotiation_supported functions up in the
file
---
android/handsfree-client.c | 26 ++++++++++++++++++--------
1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/android/handsfree-client.c b/android/handsfree-client.c
index fd68d78..9818a47 100644
--- a/android/handsfree-client.c
+++ b/android/handsfree-client.c
@@ -312,9 +312,26 @@ static void set_audio_state(struct device *dev, uint8_t state)
HAL_EV_HF_CLIENT_AUDIO_STATE, sizeof(ev), &ev);
}

+static void bcc_cb(enum hfp_result result, enum hfp_error cme_err,
+ void *user_data)
+{
+ struct device *dev = user_data;
+
+ if (result != HFP_RESULT_OK)
+ set_audio_state(dev, HAL_HF_CLIENT_AUDIO_STATE_DISCONNECTED);
+}
+
+static bool codec_negotiation_supported(struct device *dev)
+{
+ return (dev->features & HFP_AG_FEAT_CODEC) &&
+ (hfp_hf_features & HFP_HF_FEAT_CODEC);
+}
+
static bool connect_sco(struct device *dev)
{
- /* TODO: handle codec negotiation */
+ if (codec_negotiation_supported(dev))
+ return hfp_hf_send_command(dev->hf, bcc_cb, dev,
+ "AT+BCC");

return bt_sco_connect(sco, &dev->bdaddr, BT_VOICE_CVSD_16BIT);
}
@@ -383,7 +400,6 @@ static void cmd_complete_cb(enum hfp_result result, enum hfp_error cme_err,
struct hal_ev_hf_client_command_complete ev;

DBG("");
-
memset(&ev, 0, sizeof(ev));

switch (result) {
@@ -1653,12 +1669,6 @@ static void slc_brsf_cb(struct hfp_context *context, void *user_data)
dev->features = feat;
}

-static bool codec_negotiation_supported(struct device *dev)
-{
- return (dev->features & HFP_AG_FEAT_CODEC) &&
- (hfp_hf_features & HFP_HF_FEAT_CODEC);
-}
-
static void slc_brsf_resp(enum hfp_result result, enum hfp_error cme_err,
void *user_data)
{
--
1.8.4


2014-11-28 09:37:22

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v2 2/5] android/handsfree-client: Add handle incoming SCO connection

---
android/handsfree-client.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 92 insertions(+)

diff --git a/android/handsfree-client.c b/android/handsfree-client.c
index 9e67c7f..be12d5e 100644
--- a/android/handsfree-client.c
+++ b/android/handsfree-client.c
@@ -116,6 +116,7 @@ struct device {
bdaddr_t bdaddr;
struct hfp_hf *hf;
uint8_t state;
+ uint8_t audio_state;

uint8_t negotiated_codec;
uint32_t features;
@@ -184,6 +185,7 @@ static struct device *device_create(const bdaddr_t *bdaddr)

bacpy(&dev->bdaddr, bdaddr);
dev->state = HAL_HF_CLIENT_CONN_STATE_DISCONNECTED;
+ dev->audio_state = HAL_HF_CLIENT_AUDIO_STATE_DISCONNECTED;

init_codecs(dev);

@@ -290,6 +292,26 @@ done:
HAL_OP_HF_CLIENT_DISCONNECT, status);
}

+static void set_audio_state(struct device *dev, uint8_t state)
+{
+ struct hal_ev_hf_client_audio_state ev;
+ char address[18];
+
+ if (dev->audio_state == state)
+ return;
+
+ dev->audio_state = state;
+
+ ba2str(&dev->bdaddr, address);
+ DBG("device %s audio state %u", address, state);
+
+ bdaddr2android(&dev->bdaddr, ev.bdaddr);
+ ev.state = state;
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_HANDSFREE_CLIENT,
+ HAL_EV_HF_CLIENT_AUDIO_STATE, sizeof(ev), &ev);
+}
+
static void handle_connect_audio(const void *buf, uint16_t len)
{
DBG("Not Implemented");
@@ -2009,6 +2031,72 @@ static void cleanup_hfp_hf(void)
}
}

+static bool confirm_sco_cb(const bdaddr_t *addr, uint16_t *voice_settings)
+{
+ struct device *dev;
+
+ DBG("");
+
+ dev = find_device(addr);
+ if (!dev || dev->state != HAL_HF_CLIENT_CONN_STATE_SLC_CONNECTED) {
+ error("hf-client: No device or SLC not ready");
+ return false;
+ }
+
+ set_audio_state(dev, HAL_HF_CLIENT_AUDIO_STATE_CONNECTING);
+
+ if (codec_negotiation_supported(dev) &&
+ dev->negotiated_codec != CODEC_ID_CVSD)
+ *voice_settings = BT_VOICE_TRANSPARENT;
+ else
+ *voice_settings = BT_VOICE_CVSD_16BIT;
+
+ return true;
+}
+
+static void connect_sco_cb(enum sco_status status, const bdaddr_t *addr)
+{
+ struct device *dev;
+ uint8_t audio_state;
+
+ DBG("SCO Status %u", status);
+
+ /* Device shall be there, just sanity check */
+ dev = find_device(addr);
+ if (!dev) {
+ error("hf-client: There is no device?");
+ return;
+ }
+
+ if (status != SCO_STATUS_OK) {
+ audio_state = HAL_HF_CLIENT_AUDIO_STATE_DISCONNECTED;
+ goto done;
+ }
+
+ if (dev->negotiated_codec == CODEC_ID_MSBC)
+ audio_state = HAL_HF_CLIENT_AUDIO_STATE_CONNECTED_MSBC;
+ else
+ audio_state = HAL_HF_CLIENT_AUDIO_STATE_CONNECTED;
+
+done:
+ set_audio_state(dev, audio_state);
+}
+
+static void disconnect_sco_cb(const bdaddr_t *addr)
+{
+ struct device *dev;
+
+ DBG("");
+
+ dev = find_device(addr);
+ if (!dev) {
+ error("hf-client: No device");
+ return;
+ }
+
+ set_audio_state(dev, HAL_HF_CLIENT_AUDIO_STATE_DISCONNECTED);
+}
+
bool bt_hf_client_register(struct ipc *ipc, const bdaddr_t *addr)
{
DBG("");
@@ -2030,6 +2118,10 @@ bool bt_hf_client_register(struct ipc *ipc, const bdaddr_t *addr)
goto failed;
}

+ bt_sco_set_confirm_cb(sco, confirm_sco_cb);
+ bt_sco_set_connect_cb(sco, connect_sco_cb);
+ bt_sco_set_disconnect_cb(sco, disconnect_sco_cb);
+
hal_ipc = ipc;
ipc_register(hal_ipc, HAL_SERVICE_ID_HANDSFREE_CLIENT, cmd_handlers,
G_N_ELEMENTS(cmd_handlers));
--
1.8.4


2014-11-28 09:37:23

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v2 3/5] android/handsfree-client: Implement audio connect/disconnect

---
android/handsfree-client.c | 60 ++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 55 insertions(+), 5 deletions(-)

diff --git a/android/handsfree-client.c b/android/handsfree-client.c
index be12d5e..fd68d78 100644
--- a/android/handsfree-client.c
+++ b/android/handsfree-client.c
@@ -312,19 +312,69 @@ static void set_audio_state(struct device *dev, uint8_t state)
HAL_EV_HF_CLIENT_AUDIO_STATE, sizeof(ev), &ev);
}

+static bool connect_sco(struct device *dev)
+{
+ /* TODO: handle codec negotiation */
+
+ return bt_sco_connect(sco, &dev->bdaddr, BT_VOICE_CVSD_16BIT);
+}
+
static void handle_connect_audio(const void *buf, uint16_t len)
{
- DBG("Not Implemented");
+ const struct hal_cmd_hf_client_connect_audio *cmd = (void *) buf;
+ struct device *dev;
+ uint8_t status;
+ bdaddr_t bdaddr;
+
+ DBG("");
+
+ android2bdaddr(&cmd->bdaddr, &bdaddr);
+
+ dev = find_device(&bdaddr);
+ if (!dev || dev->state != HAL_HF_CLIENT_CONN_STATE_SLC_CONNECTED ||
+ dev->audio_state != HAL_HF_CLIENT_AUDIO_STATE_DISCONNECTED) {
+ error("hf-client: Cannot create SCO, check SLC or audio state");
+ status = HAL_STATUS_FAILED;
+ goto done;
+ }
+
+ if (connect_sco(dev)) {
+ status = HAL_STATUS_SUCCESS;
+ set_audio_state(dev, HAL_HF_CLIENT_AUDIO_STATE_CONNECTING);
+ } else {
+ status = HAL_STATUS_FAILED;
+ }
+
+done:
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HANDSFREE_CLIENT,
- HAL_OP_HF_CLIENT_CONNECT_AUDIO, HAL_STATUS_UNSUPPORTED);
+ HAL_OP_HF_CLIENT_CONNECT_AUDIO, status);
}

static void handle_disconnect_audio(const void *buf, uint16_t len)
{
- DBG("Not Implemented");
+ const struct hal_cmd_hf_client_disconnect_audio *cmd = (void *) buf;
+ struct device *dev;
+ uint8_t status;
+ bdaddr_t bdaddr;
+
+ DBG("");
+
+ android2bdaddr(&cmd->bdaddr, &bdaddr);
+
+ dev = find_device(&bdaddr);
+ if (!dev ||
+ dev->audio_state == HAL_HF_CLIENT_AUDIO_STATE_DISCONNECTED) {
+ error("hf-client: Device not found or audio not connected");
+ status = HAL_STATUS_FAILED;
+ goto done;
+ }
+
+ bt_sco_disconnect(sco);
+ status = HAL_STATUS_SUCCESS;
+
+done:
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HANDSFREE_CLIENT,
- HAL_OP_HF_CLIENT_DISCONNECT_AUDIO,
- HAL_STATUS_UNSUPPORTED);
+ HAL_OP_HF_CLIENT_DISCONNECT_AUDIO, status);
}

static void cmd_complete_cb(enum hfp_result result, enum hfp_error cme_err,
--
1.8.4


2014-11-28 09:37:25

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v2 5/5] android/README: Update status of HAL HFP HF implementation

---
android/README | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/android/README b/android/README
index aa12e51..6e5c95a 100644
--- a/android/README
+++ b/android/README
@@ -289,7 +289,7 @@ health bt_hl.h complete complete
pan bt_pan.h complete complete
avrcp bt_rc.h complete complete
socket bt_sock.h complete partial
-handsfree_client bt_hf_client.h N/A partial
+handsfree_client bt_hf_client.h N/A complete
map_client bt_mce.h N/A complete
a2dp_sink bt_av.h N/A partial
avrcp_ctrl bt_rc.h N/A partial
--
1.8.4


2014-12-01 16:14:21

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH v2 0/5] android/handsfree-client: Add SCO to HFP HF

Hi Ɓukasz,

On Friday 28 of November 2014 10:37:20 Lukasz Rymanowski wrote:
> Last missing piece to HFP HF implementation.
>
> v2:
> * Handled Szymon comments
> * rebase and minor self review fixes in 2/5
>
> Lukasz Rymanowski (5):
> android/handsfree-client: Add SCO to handsfree client
> android/handsfree-client: Add handle incoming SCO connection
> android/handsfree-client: Implement audio connect/disconnect
> android/handsfree-client: Send AT+BCC to start codec negotiation
> android/README: Update status of HAL HFP HF implementation
>
> android/README | 2 +-
> android/handsfree-client.c | 191 ++++++++++++++++++++++++++++++++++++++++++---
> 2 files changed, 180 insertions(+), 13 deletions(-)

All patches applied, thanks.

--
Best regards,
Szymon Janc