v2: Fixed Luiz's comments (added new interface at bottom in
hal-ipc-txt and ID in hal-msg.h).
v1: Android Lollipop has new interface for AVRCP controller. It has
one command and two callbacks. Patchset updates support for IPC
doc, hal-msg, HAL part and client part.
Ravi kumar Veeramally (5):
android/hal-ipc-txt: Add support for new AVRCP CTRL interface
android/hal-msg: Add support for new AVRCP CTRL interface
android/hal-avrcp: Add suuport for new AVRCP ctrl interface
android/client: Add support for new AVRCP CTRL interface
android/avrcp: Add initial support for new AVRCP CTRL interface
android/avrcp.c | 72 ++++++++++++++++++++++------
android/avrcp.h | 4 ++
android/client/if-bt.c | 2 +
android/client/if-main.h | 2 +
android/client/if-rc.c | 88 ++++++++++++++++++++++++++++++++++
android/hal-avrcp.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++
android/hal-bluetooth.c | 3 ++
android/hal-ipc-api.txt | 45 ++++++++++++++++-
android/hal-msg.h | 24 +++++++++-
android/hal.h | 1 +
android/main.c | 11 +++++
11 files changed, 356 insertions(+), 18 deletions(-)
--
2.1.0
Hi Ravi,
On Mon, Nov 10, 2014 at 4:05 PM, Ravi kumar Veeramally
<[email protected]> wrote:
> v2: Fixed Luiz's comments (added new interface at bottom in
> hal-ipc-txt and ID in hal-msg.h).
>
> v1: Android Lollipop has new interface for AVRCP controller. It has
> one command and two callbacks. Patchset updates support for IPC
> doc, hal-msg, HAL part and client part.
>
> Ravi kumar Veeramally (5):
> android/hal-ipc-txt: Add support for new AVRCP CTRL interface
> android/hal-msg: Add support for new AVRCP CTRL interface
> android/hal-avrcp: Add suuport for new AVRCP ctrl interface
> android/client: Add support for new AVRCP CTRL interface
> android/avrcp: Add initial support for new AVRCP CTRL interface
>
> android/avrcp.c | 72 ++++++++++++++++++++++------
> android/avrcp.h | 4 ++
> android/client/if-bt.c | 2 +
> android/client/if-main.h | 2 +
> android/client/if-rc.c | 88 ++++++++++++++++++++++++++++++++++
> android/hal-avrcp.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++
> android/hal-bluetooth.c | 3 ++
> android/hal-ipc-api.txt | 45 ++++++++++++++++-
> android/hal-msg.h | 24 +++++++++-
> android/hal.h | 1 +
> android/main.c | 11 +++++
> 11 files changed, 356 insertions(+), 18 deletions(-)
>
> --
> 2.1.0
Patches 1-4 have been applied, patch 5/5 need some work see my comments to it.
--
Luiz Augusto von Dentz
Hi Ravi,
On Mon, Nov 10, 2014 at 4:05 PM, Ravi kumar Veeramally
<[email protected]> wrote:
> ---
> android/avrcp.c | 72 +++++++++++++++++++++++++++++++++++++++++++++------------
> android/avrcp.h | 4 ++++
> android/main.c | 11 +++++++++
> 3 files changed, 72 insertions(+), 15 deletions(-)
>
> diff --git a/android/avrcp.c b/android/avrcp.c
> index a0d412d..f372128 100644
> --- a/android/avrcp.c
> +++ b/android/avrcp.c
> @@ -1082,21 +1082,6 @@ bool bt_avrcp_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
> }
> record_tg_id = rec->handle;
>
> - rec = avrcp_ct_record();
> - if (!rec) {
> - error("Failed to allocate AVRCP CT record");
> - bt_adapter_remove_record(record_tg_id);
> - goto fail;
> - }
> -
> - if (bt_adapter_add_record(rec, 0) < 0) {
> - error("Failed to register AVRCP CT record");
> - bt_adapter_remove_record(record_tg_id);
> - sdp_record_free(rec);
> - goto fail;
> - }
> - record_ct_id = rec->handle;
We can't really remove the record here otherwise it breaks PTS tests
that requires CT record.
> hal_ipc = ipc;
>
> ipc_register(hal_ipc, HAL_SERVICE_ID_AVRCP, cmd_handlers,
> @@ -1171,3 +1156,60 @@ void bt_avrcp_disconnect(const bdaddr_t *dst)
>
> avrcp_device_remove(dev);
> }
> +
> +static void handle_send_passthrough(const void *buf, uint16_t len)
> +{
> + DBG("Not Implemented");
> +
> + ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_AVRCP_CTRL,
> + HAL_OP_AVRCP_CTRL_SEND_PASSTHROUGH,
> + HAL_STATUS_UNSUPPORTED);
> +}
> +
> +static const struct ipc_handler ctrl_cmd_handlers[] = {
> + /* HAL_OP_AVRCP_CTRL_SEND_PASSTHROUGH */
> + { handle_send_passthrough, false,
> + sizeof(struct hal_cmd_avrcp_ctrl_send_passthrough) },
> +};
> +
> +bool bt_avrcp_ctrl_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
> +{
> + sdp_record_t *rec;
> +
> + DBG("");
Here you can just check if record_ct_id is set then proceed without
adding another record, but you have to remember to do the same in
bt_avrcp_register.
> + rec = avrcp_ct_record();
> + if (!rec) {
> + error("Failed to allocate AVRCP CT record");
> + goto fail;
> + }
> +
> + if (bt_adapter_add_record(rec, 0) < 0) {
> + error("Failed to register AVRCP CT record");
> + sdp_record_free(rec);
> + goto fail;
> + }
> +
> + record_ct_id = rec->handle;
> +
> + if (!hal_ipc)
> + hal_ipc = ipc;
> +
> + ipc_register(hal_ipc, HAL_SERVICE_ID_AVRCP_CTRL, ctrl_cmd_handlers,
> + G_N_ELEMENTS(ctrl_cmd_handlers));
> +
> + return true;
> +
> +fail:
> + return false;
> +}
> +
> +void bt_avrcp_ctrl_unregister(void)
> +{
> + DBG("");
> +
> + ipc_unregister(hal_ipc, HAL_SERVICE_ID_AVRCP_CTRL);
Here it is a bit trickier, you might have to check if record_tg_id is
valid then leave it registered but something similar should be done
for bt_avrcp_unregister so it does not end up removing CT record if
ctrl interface is registered.
> + bt_adapter_remove_record(record_ct_id);
> + record_ct_id = 0;
> +}
> diff --git a/android/avrcp.h b/android/avrcp.h
> index 11e79b7..0af9f14 100644
> --- a/android/avrcp.h
> +++ b/android/avrcp.h
> @@ -24,5 +24,9 @@
> bool bt_avrcp_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode);
> void bt_avrcp_unregister(void);
>
> +bool bt_avrcp_ctrl_register(struct ipc *ipc, const bdaddr_t *addr,
> + uint8_t mode);
> +void bt_avrcp_ctrl_unregister(void);
> +
> void bt_avrcp_connect(const bdaddr_t *dst);
> void bt_avrcp_disconnect(const bdaddr_t *dst);
> diff --git a/android/main.c b/android/main.c
> index 58dd9ab..21becf6 100644
> --- a/android/main.c
> +++ b/android/main.c
> @@ -208,6 +208,14 @@ static void service_register(const void *buf, uint16_t len)
> }
>
> break;
> + case HAL_SERVICE_ID_AVRCP_CTRL:
> + if (!bt_avrcp_ctrl_register(hal_ipc, &adapter_bdaddr,
> + m->mode)) {
> + status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + break;
> case HAL_SERVICE_ID_HANDSFREE:
> if (!bt_handsfree_register(hal_ipc, &adapter_bdaddr, m->mode,
> m->max_clients)) {
> @@ -286,6 +294,9 @@ static bool unregister_service(uint8_t id)
> case HAL_SERVICE_ID_AVRCP:
> bt_avrcp_unregister();
> break;
> + case HAL_SERVICE_ID_AVRCP_CTRL:
> + bt_avrcp_ctrl_unregister();
> + break;
> case HAL_SERVICE_ID_HANDSFREE:
> bt_handsfree_unregister();
> break;
> --
> 2.1.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Luiz Augusto von Dentz
---
android/client/if-bt.c | 2 ++
android/client/if-main.h | 2 ++
android/client/if-rc.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 92 insertions(+)
diff --git a/android/client/if-bt.c b/android/client/if-bt.c
index 48aff1b..50212fc 100644
--- a/android/client/if-bt.c
+++ b/android/client/if-bt.c
@@ -800,6 +800,8 @@ static void get_profile_interface_p(int argc, const char **argv)
else if (strcmp(BT_PROFILE_GATT_ID, id) == 0)
pif = (const void **) &if_gatt;
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
+ else if (strcmp(BT_PROFILE_AV_RC_CTRL_ID, id) == 0)
+ pif = (const void **) &if_rc_ctrl;
else if (strcmp(BT_PROFILE_HANDSFREE_CLIENT_ID, id) == 0)
pif = (const void **) &if_hf_client;
else if (strcmp(BT_PROFILE_MAP_CLIENT_ID, id) == 0)
diff --git a/android/client/if-main.h b/android/client/if-main.h
index 93cc98d..96409aa 100644
--- a/android/client/if-main.h
+++ b/android/client/if-main.h
@@ -65,6 +65,7 @@ extern const btgatt_interface_t *if_gatt;
extern const btgatt_server_interface_t *if_gatt_server;
extern const btgatt_client_interface_t *if_gatt_client;
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
+extern const btrc_ctrl_interface_t *if_rc_ctrl;
extern const bthf_client_interface_t *if_hf_client;
extern const btmce_interface_t *if_mce;
#endif
@@ -92,6 +93,7 @@ extern const struct interface hf_if;
extern const struct interface hh_if;
extern const struct interface hl_if;
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
+extern const struct interface ctrl_rc_if;
extern const struct interface hf_client_if;
extern const struct interface mce_if;
#endif
diff --git a/android/client/if-rc.c b/android/client/if-rc.c
index ed65600..b42b8c6 100644
--- a/android/client/if-rc.c
+++ b/android/client/if-rc.c
@@ -28,6 +28,10 @@
const btrc_interface_t *if_rc = NULL;
+#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
+const btrc_ctrl_interface_t *if_rc_ctrl = NULL;
+#endif
+
SINTMAP(btrc_play_status_t, -1, "(unknown)")
DELEMENT(BTRC_PLAYSTATE_STOPPED),
DELEMENT(BTRC_PLAYSTATE_PLAYING),
@@ -398,3 +402,87 @@ const struct interface rc_if = {
.name = "rc",
.methods = methods
};
+
+#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
+static void passthrough_rsp_cb(int id, int key_state)
+{
+ haltest_info("%s: id=%d key_state=%d\n", __func__, id, key_state);
+}
+
+static void connection_state_cb(bool state, bt_bdaddr_t *bd_addr)
+{
+ haltest_info("%s: state=%s bd_addr=%s\n", __func__,
+ state ? "true" : "false",
+ bt_bdaddr_t2str(bd_addr, last_addr));
+}
+
+static btrc_ctrl_callbacks_t rc_ctrl_cbacks = {
+ .size = sizeof(rc_ctrl_cbacks),
+ .passthrough_rsp_cb = passthrough_rsp_cb,
+ .connection_state_cb = connection_state_cb,
+};
+
+/* ctrl_init */
+
+static void ctrl_init_p(int argc, const char **argv)
+{
+ RETURN_IF_NULL(if_rc_ctrl);
+
+ EXEC(if_rc_ctrl->init, &rc_ctrl_cbacks);
+}
+
+/* ctrl_cleanup */
+
+static void ctrl_cleanup_p(int argc, const char **argv)
+{
+ RETURN_IF_NULL(if_rc_ctrl);
+
+ EXECV(if_rc_ctrl->cleanup);
+ if_rc_ctrl = NULL;
+}
+
+/* send_pass_through_cmd */
+
+static void send_pass_through_cmd_c(int argc, const char **argv,
+ enum_func *enum_func, void **user)
+{
+}
+
+static void send_pass_through_cmd_p(int argc, const char **argv)
+{
+ bt_bdaddr_t addr;
+ uint8_t key_code, key_state;
+
+ RETURN_IF_NULL(if_rc);
+ VERIFY_ADDR_ARG(2, &addr);
+
+ if (argc <= 4) {
+ haltest_error("No key code specified");
+ return;
+ }
+
+ key_code = (uint8_t) atoi(argv[3]);
+
+ if (argc <= 5) {
+ haltest_error("No key state specified");
+ return;
+ }
+
+ key_state = (uint8_t) atoi(argv[4]);
+
+ EXEC(if_rc_ctrl->send_pass_through_cmd, &addr, key_code, key_state);
+}
+
+static struct method ctrl_methods[] = {
+ STD_METHOD(ctrl_init),
+ STD_METHODCH(send_pass_through_cmd,
+ "<bd_addr> <key_code> <key_state>"),
+ STD_METHOD(ctrl_cleanup),
+ END_METHOD
+};
+
+const struct interface ctrl_rc_if = {
+ .name = "rc-ctrl",
+ .methods = ctrl_methods
+};
+#endif
--
2.1.0
---
android/avrcp.c | 72 +++++++++++++++++++++++++++++++++++++++++++++------------
android/avrcp.h | 4 ++++
android/main.c | 11 +++++++++
3 files changed, 72 insertions(+), 15 deletions(-)
diff --git a/android/avrcp.c b/android/avrcp.c
index a0d412d..f372128 100644
--- a/android/avrcp.c
+++ b/android/avrcp.c
@@ -1082,21 +1082,6 @@ bool bt_avrcp_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
}
record_tg_id = rec->handle;
- rec = avrcp_ct_record();
- if (!rec) {
- error("Failed to allocate AVRCP CT record");
- bt_adapter_remove_record(record_tg_id);
- goto fail;
- }
-
- if (bt_adapter_add_record(rec, 0) < 0) {
- error("Failed to register AVRCP CT record");
- bt_adapter_remove_record(record_tg_id);
- sdp_record_free(rec);
- goto fail;
- }
- record_ct_id = rec->handle;
-
hal_ipc = ipc;
ipc_register(hal_ipc, HAL_SERVICE_ID_AVRCP, cmd_handlers,
@@ -1171,3 +1156,60 @@ void bt_avrcp_disconnect(const bdaddr_t *dst)
avrcp_device_remove(dev);
}
+
+static void handle_send_passthrough(const void *buf, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_AVRCP_CTRL,
+ HAL_OP_AVRCP_CTRL_SEND_PASSTHROUGH,
+ HAL_STATUS_UNSUPPORTED);
+}
+
+static const struct ipc_handler ctrl_cmd_handlers[] = {
+ /* HAL_OP_AVRCP_CTRL_SEND_PASSTHROUGH */
+ { handle_send_passthrough, false,
+ sizeof(struct hal_cmd_avrcp_ctrl_send_passthrough) },
+};
+
+bool bt_avrcp_ctrl_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
+{
+ sdp_record_t *rec;
+
+ DBG("");
+
+ rec = avrcp_ct_record();
+ if (!rec) {
+ error("Failed to allocate AVRCP CT record");
+ goto fail;
+ }
+
+ if (bt_adapter_add_record(rec, 0) < 0) {
+ error("Failed to register AVRCP CT record");
+ sdp_record_free(rec);
+ goto fail;
+ }
+
+ record_ct_id = rec->handle;
+
+ if (!hal_ipc)
+ hal_ipc = ipc;
+
+ ipc_register(hal_ipc, HAL_SERVICE_ID_AVRCP_CTRL, ctrl_cmd_handlers,
+ G_N_ELEMENTS(ctrl_cmd_handlers));
+
+ return true;
+
+fail:
+ return false;
+}
+
+void bt_avrcp_ctrl_unregister(void)
+{
+ DBG("");
+
+ ipc_unregister(hal_ipc, HAL_SERVICE_ID_AVRCP_CTRL);
+
+ bt_adapter_remove_record(record_ct_id);
+ record_ct_id = 0;
+}
diff --git a/android/avrcp.h b/android/avrcp.h
index 11e79b7..0af9f14 100644
--- a/android/avrcp.h
+++ b/android/avrcp.h
@@ -24,5 +24,9 @@
bool bt_avrcp_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode);
void bt_avrcp_unregister(void);
+bool bt_avrcp_ctrl_register(struct ipc *ipc, const bdaddr_t *addr,
+ uint8_t mode);
+void bt_avrcp_ctrl_unregister(void);
+
void bt_avrcp_connect(const bdaddr_t *dst);
void bt_avrcp_disconnect(const bdaddr_t *dst);
diff --git a/android/main.c b/android/main.c
index 58dd9ab..21becf6 100644
--- a/android/main.c
+++ b/android/main.c
@@ -208,6 +208,14 @@ static void service_register(const void *buf, uint16_t len)
}
break;
+ case HAL_SERVICE_ID_AVRCP_CTRL:
+ if (!bt_avrcp_ctrl_register(hal_ipc, &adapter_bdaddr,
+ m->mode)) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ break;
case HAL_SERVICE_ID_HANDSFREE:
if (!bt_handsfree_register(hal_ipc, &adapter_bdaddr, m->mode,
m->max_clients)) {
@@ -286,6 +294,9 @@ static bool unregister_service(uint8_t id)
case HAL_SERVICE_ID_AVRCP:
bt_avrcp_unregister();
break;
+ case HAL_SERVICE_ID_AVRCP_CTRL:
+ bt_avrcp_ctrl_unregister();
+ break;
case HAL_SERVICE_ID_HANDSFREE:
bt_handsfree_unregister();
break;
--
2.1.0
---
android/hal-msg.h | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/android/hal-msg.h b/android/hal-msg.h
index eef226e..ac691d8 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -37,6 +37,7 @@ static const char BLUEZ_HAL_SK_PATH[] = "\0bluez_hal_socket";
#define HAL_SERVICE_ID_GATT 9
#define HAL_SERVICE_ID_HANDSFREE_CLIENT 10
#define HAL_SERVICE_ID_MAP_CLIENT 11
+#define HAL_SERVICE_ID_AVRCP_CTRL 12
#define HAL_SERVICE_ID_MAX HAL_SERVICE_ID_MAP_CLIENT
@@ -607,7 +608,7 @@ struct hal_cmd_handsfree_phone_state_change {
uint8_t number[0];
} __attribute__((packed));
-/* AVRCP HAL API */
+/* AVRCP TARGET HAL API */
#define HAL_AVRCP_PLAY_STATUS_STOPPED 0x00
#define HAL_AVRCP_PLAY_STATUS_PLAYING 0x01
@@ -711,6 +712,15 @@ struct hal_cmd_avrcp_set_volume {
uint8_t value;
} __attribute__((packed));
+/* AVRCP CTRL HAL API */
+
+#define HAL_OP_AVRCP_CTRL_SEND_PASSTHROUGH 0x01
+struct hal_cmd_avrcp_ctrl_send_passthrough {
+ uint8_t bdaddr[6];
+ uint8_t key_code;
+ uint8_t key_state;
+} __attribute__((packed));
+
/* GATT HAL API */
#define HAL_OP_GATT_CLIENT_REGISTER 0x01
@@ -1499,6 +1509,18 @@ struct hal_ev_avrcp_passthrough_cmd {
uint8_t state;
} __attribute__((packed));
+#define HAL_EV_AVRCP_CTRL_CONN_STATE 0x80
+struct hal_ev_avrcp_ctrl_conn_state {
+ uint8_t state;
+ uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_EV_AVRCP_CTRL_PASSTHROUGH_RSP 0x81
+struct hal_ev_avrcp_ctrl_passthrough_rsp {
+ uint8_t id;
+ uint8_t key_state;
+} __attribute__((packed));
+
#define HAL_EV_GATT_CLIENT_REGISTER_CLIENT 0x81
struct hal_ev_gatt_client_register_client {
int32_t status;
--
2.1.0
---
android/hal-avrcp.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++
android/hal-bluetooth.c | 3 ++
android/hal.h | 1 +
3 files changed, 126 insertions(+)
diff --git a/android/hal-avrcp.c b/android/hal-avrcp.c
index 761ddfb..4202bfa 100644
--- a/android/hal-avrcp.c
+++ b/android/hal-avrcp.c
@@ -20,6 +20,7 @@
#include <string.h>
#include <stdlib.h>
+#include "hal-utils.h"
#include "hal-log.h"
#include "hal.h"
#include "hal-msg.h"
@@ -28,6 +29,10 @@
static const btrc_callbacks_t *cbs = NULL;
+#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
+static const btrc_ctrl_callbacks_t *ctrl_cbs = NULL;
+#endif
+
static bool interface_ready(void)
{
return cbs != NULL;
@@ -684,3 +689,120 @@ btrc_interface_t *bt_get_avrcp_interface(void)
{
return &iface;
}
+
+#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
+
+static bool ctrl_interface_ready(void)
+{
+ return ctrl_cbs != NULL;
+}
+
+static void handle_connection_state(void *buf, uint16_t len, int fd)
+{
+ struct hal_ev_avrcp_ctrl_conn_state *ev = buf;
+
+ if (ctrl_cbs->connection_state_cb)
+ ctrl_cbs->connection_state_cb(ev->state,
+ (bt_bdaddr_t *) (ev->bdaddr));
+}
+
+static void handle_passthrough_rsp(void *buf, uint16_t len, int fd)
+{
+ struct hal_ev_avrcp_ctrl_passthrough_rsp *ev = buf;
+
+ if (ctrl_cbs->passthrough_rsp_cb)
+ ctrl_cbs->passthrough_rsp_cb(ev->id, ev->key_state);
+}
+
+/*
+ * handlers will be called from notification thread context,
+ * index in table equals to 'opcode - HAL_MINIMUM_EVENT'
+ */
+static const struct hal_ipc_handler ctrl_ev_handlers[] = {
+ /* HAL_EV_AVRCP_CTRL_CONN_STATE */
+ { handle_connection_state, false,
+ sizeof(struct hal_ev_avrcp_ctrl_conn_state) },
+ /* HAL_EV_AVRCP_CTRL_PASSTHROUGH_RSP */
+ { handle_passthrough_rsp, false,
+ sizeof(struct hal_ev_avrcp_ctrl_passthrough_rsp) },
+};
+
+static bt_status_t ctrl_init(btrc_ctrl_callbacks_t *callbacks)
+{
+ struct hal_cmd_register_module cmd;
+ int ret;
+
+ DBG("");
+
+ if (ctrl_interface_ready())
+ return BT_STATUS_DONE;
+
+ ctrl_cbs = callbacks;
+
+ hal_ipc_register(HAL_SERVICE_ID_AVRCP_CTRL, ctrl_ev_handlers,
+ sizeof(ctrl_ev_handlers) / sizeof(ctrl_ev_handlers[0]));
+
+ cmd.service_id = HAL_SERVICE_ID_AVRCP_CTRL;
+ cmd.mode = HAL_MODE_DEFAULT;
+
+ ret = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
+ sizeof(cmd), &cmd, NULL, NULL, NULL);
+
+ if (ret != BT_STATUS_SUCCESS) {
+ cbs = NULL;
+ hal_ipc_unregister(HAL_SERVICE_ID_AVRCP_CTRL);
+ }
+
+ return ret;
+}
+
+static bt_status_t send_pass_through_cmd(bt_bdaddr_t *bd_addr, uint8_t key_code,
+ uint8_t key_state)
+{
+ struct hal_cmd_avrcp_ctrl_send_passthrough cmd;
+
+ DBG("");
+
+ if (!ctrl_interface_ready())
+ return BT_STATUS_NOT_READY;
+
+ memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+ cmd.key_code = key_code;
+ cmd.key_state = key_state;
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP_CTRL,
+ HAL_OP_AVRCP_CTRL_SEND_PASSTHROUGH,
+ sizeof(cmd), &cmd, NULL, NULL, NULL);
+}
+
+static void ctrl_cleanup(void)
+{
+ struct hal_cmd_unregister_module cmd;
+
+ DBG("");
+
+ if (!ctrl_interface_ready())
+ return;
+
+ ctrl_cbs = NULL;
+
+ cmd.service_id = HAL_SERVICE_ID_AVRCP_CTRL;
+
+ hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
+ sizeof(cmd), &cmd, NULL, NULL, NULL);
+
+ hal_ipc_unregister(HAL_SERVICE_ID_AVRCP_CTRL);
+}
+
+static btrc_ctrl_interface_t ctrl_iface = {
+ .size = sizeof(ctrl_iface),
+ .init = ctrl_init,
+ .send_pass_through_cmd = send_pass_through_cmd,
+ .cleanup = ctrl_cleanup
+};
+
+btrc_ctrl_interface_t *bt_get_avrcp_ctrl_interface(void)
+{
+ return &ctrl_iface;
+}
+#endif
diff --git a/android/hal-bluetooth.c b/android/hal-bluetooth.c
index 9b5ce16..164e232 100644
--- a/android/hal-bluetooth.c
+++ b/android/hal-bluetooth.c
@@ -866,6 +866,9 @@ static const void *get_profile_interface(const char *profile_id)
return bt_get_health_interface();
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
+ if (!strcmp(profile_id, BT_PROFILE_AV_RC_CTRL_ID))
+ return bt_get_avrcp_ctrl_interface();
+
if (!strcmp(profile_id, BT_PROFILE_HANDSFREE_CLIENT_ID))
return bt_get_hf_client_interface();
diff --git a/android/hal.h b/android/hal.h
index 76555a0..9e29dff 100644
--- a/android/hal.h
+++ b/android/hal.h
@@ -44,6 +44,7 @@ btgatt_interface_t *bt_get_gatt_interface(void);
bthl_interface_t *bt_get_health_interface(void);
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
+btrc_ctrl_interface_t *bt_get_avrcp_ctrl_interface(void);
bthf_client_interface_t *bt_get_hf_client_interface(void);
btmce_interface_t *bt_get_map_client_interface(void);
#endif
--
2.1.0
---
android/hal-ipc-api.txt | 45 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 43 insertions(+), 2 deletions(-)
diff --git a/android/hal-ipc-api.txt b/android/hal-ipc-api.txt
index 666e27f..4f202c8 100644
--- a/android/hal-ipc-api.txt
+++ b/android/hal-ipc-api.txt
@@ -1241,7 +1241,7 @@ Notifications:
0x04 = Destroyed
-Bluetooth Remote Control HAL (ID 8)
+Bluetooth Remote Control Target HAL (ID 8)
===================================
Android HAL name: "avrcp" (BT_PROFILE_AV_RC_ID)
@@ -1470,7 +1470,6 @@ Notifications:
Notification parameters: ID (1 octet)
State (1 octet)
-
Bluetooth GATT HAL (ID 9)
=========================
@@ -2505,3 +2504,45 @@ Notifications:
Channel # (4 octets)
Message types (4 octets)
Name # (string)
+
+Bluetooth Remote Control Controller HAL (ID 12)
+===================================
+
+Android HAL name: "avrcp-ctrl" (BT_PROFILE_AV_RC_CTRL_ID)
+
+Commands and responses:
+
+ Opcode 0x00 - Error response
+
+ Response parameters: Status (1 octet)
+
+ Valid status values: 0x01 = Fail
+ 0x02 = Not ready
+ 0x03 = No memory
+ 0x04 = Busy
+ 0x05 = Done (already completed)
+ 0x06 = Unsupported
+ 0x07 = Parameter invalid
+ 0x08 = Unhandled
+ 0x09 = Authentication failure
+ 0x0a = Remote device down
+
+ Opcode 0x01 - Send Pass Through command/response
+
+ Command parameters: Remote Address (6 octets)
+ Key Code (1 octet)
+ Key State (1 octet)
+
+ In case of an error, the error response will be returned.
+
+Notifications:
+
+ Opcode 0x81 - Passthrough Response Notification
+
+ Notification parameters: ID (1 octet)
+ Key State (1 octet)
+
+ Opcode 0x82 - Connection State Notification
+
+ Notification parameters: State (1 octet)
+ Remote Address (6 octets)
--
2.1.0