From: Luiz Augusto von Dentz <[email protected]>
This add initial code for listen and accept connections on the abstract
socket defined for the audio IPC.
---
v2: Split audio IPC services for HAL services and fix invalid messages or
disconnections causing the daemon to exit. The audio HAL is independent of
bluetooth and should only affect A2DP service.
android/hal-msg.h | 1 +
android/ipc.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
android/ipc.h | 3 +++
3 files changed, 76 insertions(+), 6 deletions(-)
diff --git a/android/hal-msg.h b/android/hal-msg.h
index c351501..b14eced 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -24,6 +24,7 @@
#define BLUEZ_HAL_MTU 1024
static const char BLUEZ_HAL_SK_PATH[] = "\0bluez_hal_socket";
+static const char BLUEZ_AUDIO_SK_PATH[] = "\0bluez_audio_socket";
struct hal_hdr {
uint8_t service_id;
diff --git a/android/ipc.c b/android/ipc.c
index 9e8ccc3..4c5a77e 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -49,6 +49,7 @@ static struct service_handler services[HAL_SERVICE_ID_MAX + 1];
static GIOChannel *cmd_io = NULL;
static GIOChannel *notif_io = NULL;
+static GIOChannel *audio_io = NULL;
static void ipc_handle_msg(const void *buf, ssize_t len)
{
@@ -145,7 +146,8 @@ static gboolean notif_watch_cb(GIOChannel *io, GIOCondition cond,
return FALSE;
}
-static GIOChannel *connect_hal(GIOFunc connect_cb)
+static GIOChannel *ipc_connect(const char *path, size_t size,
+ GIOFunc connect_cb)
{
struct sockaddr_un addr;
GIOCondition cond;
@@ -167,11 +169,11 @@ static GIOChannel *connect_hal(GIOFunc connect_cb)
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
- memcpy(addr.sun_path, BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH));
+ memcpy(addr.sun_path, path, size);
if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- error("IPC: failed to connect HAL socket: %d (%s)", errno,
- strerror(errno));
+ error("IPC: failed to connect HAL socket %s: %d (%s)", &path[1],
+ errno, strerror(errno));
g_io_channel_unref(io);
return NULL;
}
@@ -218,7 +220,8 @@ static gboolean cmd_connect_cb(GIOChannel *io, GIOCondition cond,
return FALSE;
}
- notif_io = connect_hal(notif_connect_cb);
+ notif_io = ipc_connect(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
+ notif_connect_cb);
if (!notif_io)
raise(SIGTERM);
@@ -227,7 +230,8 @@ static gboolean cmd_connect_cb(GIOChannel *io, GIOCondition cond,
void ipc_init(void)
{
- cmd_io = connect_hal(cmd_connect_cb);
+ cmd_io = ipc_connect(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
+ cmd_connect_cb);
if (!cmd_io)
raise(SIGTERM);
}
@@ -338,3 +342,65 @@ void ipc_unregister(uint8_t service)
services[service].handler = NULL;
services[service].size = 0;
}
+
+static gboolean audio_watch_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ char buf[BLUEZ_HAL_MTU];
+ ssize_t ret;
+ int fd;
+
+ if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ info("Audio IPC: command socket closed");
+ goto fail;
+ }
+
+ fd = g_io_channel_unix_get_fd(io);
+
+ ret = read(fd, buf, sizeof(buf));
+ if (ret < 0) {
+ error("Audio IPC: command read failed (%s)", strerror(errno));
+ goto fail;
+ }
+
+ return TRUE;
+
+fail:
+ audio_ipc_cleanup();
+ return FALSE;
+}
+
+static gboolean audio_connect_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ DBG("");
+
+ if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ error("Audio IPC: socket connect failed");
+ audio_ipc_cleanup();
+ return FALSE;
+ }
+
+ cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+
+ g_io_add_watch(audio_io, cond, audio_watch_cb, NULL);
+
+ info("Audio IPC: successfully connected");
+
+ return FALSE;
+}
+
+void audio_ipc_init(void)
+{
+ audio_io = ipc_connect(BLUEZ_AUDIO_SK_PATH, sizeof(BLUEZ_AUDIO_SK_PATH),
+ audio_connect_cb);
+}
+
+void audio_ipc_cleanup(void)
+{
+ if (audio_io) {
+ g_io_channel_shutdown(audio_io, TRUE, NULL);
+ g_io_channel_unref(audio_io);
+ audio_io = NULL;
+ }
+}
diff --git a/android/ipc.h b/android/ipc.h
index 6cd102b..8e92811 100644
--- a/android/ipc.h
+++ b/android/ipc.h
@@ -37,3 +37,6 @@ void ipc_send_notif(uint8_t service_id, uint8_t opcode, uint16_t len,
void ipc_register(uint8_t service, const struct ipc_handler *handlers,
uint8_t size);
void ipc_unregister(uint8_t service);
+
+void audio_ipc_init(void);
+void audio_ipc_cleanup(void);
--
1.8.4.2
Hi Szymon,
On Sun, Jan 5, 2014 at 7:43 PM, Szymon Janc <[email protected]> wrote:
> Hi Luiz,
>
> On Thursday 02 January 2014 13:58:25 Luiz Augusto von Dentz wrote:
>> From: Luiz Augusto von Dentz <[email protected]>
>>
>> This add initial code for listen and accept connections on the abstract
>> socket defined for the audio IPC.
>> ---
>> v2: Split audio IPC services for HAL services and fix invalid messages or
>> disconnections causing the daemon to exit. The audio HAL is independent of
>> bluetooth and should only affect A2DP service.
>
> What seems to be missing is some way to recover from Audio IPC error.
This has been discussed already with Lukasz, Audio HAL is a little bit
different than Bluetooth HAL because it does not seems to be able to
restart the service from the UI so the Audio IPC disconnecting are
probably due to crashes, we will indeed need a way to recover from
Audio IPC errors but it is not really a feature but more a error
recover which we can be done in a separate set.
Luiz Augusto von Dentz
Hi Luiz,
On Thursday 02 January 2014 13:58:25 Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <[email protected]>
>
> This add initial code for listen and accept connections on the abstract
> socket defined for the audio IPC.
> ---
> v2: Split audio IPC services for HAL services and fix invalid messages or
> disconnections causing the daemon to exit. The audio HAL is independent of
> bluetooth and should only affect A2DP service.
What seems to be missing is some way to recover from Audio IPC error.
>
> android/hal-msg.h | 1 +
> android/ipc.c | 78
> ++++++++++++++++++++++++++++++++++++++++++++++++++----- android/ipc.h |
> 3 +++
> 3 files changed, 76 insertions(+), 6 deletions(-)
>
> diff --git a/android/hal-msg.h b/android/hal-msg.h
> index c351501..b14eced 100644
> --- a/android/hal-msg.h
> +++ b/android/hal-msg.h
> @@ -24,6 +24,7 @@
> #define BLUEZ_HAL_MTU 1024
>
> static const char BLUEZ_HAL_SK_PATH[] = "\0bluez_hal_socket";
> +static const char BLUEZ_AUDIO_SK_PATH[] = "\0bluez_audio_socket";
>
> struct hal_hdr {
> uint8_t service_id;
> diff --git a/android/ipc.c b/android/ipc.c
> index 9e8ccc3..4c5a77e 100644
> --- a/android/ipc.c
> +++ b/android/ipc.c
> @@ -49,6 +49,7 @@ static struct service_handler services[HAL_SERVICE_ID_MAX
> + 1];
>
> static GIOChannel *cmd_io = NULL;
> static GIOChannel *notif_io = NULL;
> +static GIOChannel *audio_io = NULL;
>
> static void ipc_handle_msg(const void *buf, ssize_t len)
> {
> @@ -145,7 +146,8 @@ static gboolean notif_watch_cb(GIOChannel *io,
> GIOCondition cond, return FALSE;
> }
>
> -static GIOChannel *connect_hal(GIOFunc connect_cb)
> +static GIOChannel *ipc_connect(const char *path, size_t size,
> + GIOFunc connect_cb)
> {
> struct sockaddr_un addr;
> GIOCondition cond;
> @@ -167,11 +169,11 @@ static GIOChannel *connect_hal(GIOFunc connect_cb)
> memset(&addr, 0, sizeof(addr));
> addr.sun_family = AF_UNIX;
>
> - memcpy(addr.sun_path, BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH));
> + memcpy(addr.sun_path, path, size);
>
> if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
> - error("IPC: failed to connect HAL socket: %d (%s)", errno,
> - strerror(errno));
> + error("IPC: failed to connect HAL socket %s: %d (%s)", &path[1],
> + errno, strerror(errno));
> g_io_channel_unref(io);
> return NULL;
> }
> @@ -218,7 +220,8 @@ static gboolean cmd_connect_cb(GIOChannel *io,
> GIOCondition cond, return FALSE;
> }
>
> - notif_io = connect_hal(notif_connect_cb);
> + notif_io = ipc_connect(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
> + notif_connect_cb);
> if (!notif_io)
> raise(SIGTERM);
>
> @@ -227,7 +230,8 @@ static gboolean cmd_connect_cb(GIOChannel *io,
> GIOCondition cond,
>
> void ipc_init(void)
> {
> - cmd_io = connect_hal(cmd_connect_cb);
> + cmd_io = ipc_connect(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
> + cmd_connect_cb);
> if (!cmd_io)
> raise(SIGTERM);
> }
> @@ -338,3 +342,65 @@ void ipc_unregister(uint8_t service)
> services[service].handler = NULL;
> services[service].size = 0;
> }
> +
> +static gboolean audio_watch_cb(GIOChannel *io, GIOCondition cond,
> + gpointer user_data)
> +{
> + char buf[BLUEZ_HAL_MTU];
> + ssize_t ret;
> + int fd;
> +
> + if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
> + info("Audio IPC: command socket closed");
> + goto fail;
> + }
> +
> + fd = g_io_channel_unix_get_fd(io);
> +
> + ret = read(fd, buf, sizeof(buf));
> + if (ret < 0) {
> + error("Audio IPC: command read failed (%s)", strerror(errno));
> + goto fail;
> + }
> +
> + return TRUE;
> +
> +fail:
> + audio_ipc_cleanup();
> + return FALSE;
> +}
> +
> +static gboolean audio_connect_cb(GIOChannel *io, GIOCondition cond,
> + gpointer user_data)
> +{
> + DBG("");
> +
> + if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
> + error("Audio IPC: socket connect failed");
> + audio_ipc_cleanup();
> + return FALSE;
> + }
> +
> + cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
> +
> + g_io_add_watch(audio_io, cond, audio_watch_cb, NULL);
> +
> + info("Audio IPC: successfully connected");
> +
> + return FALSE;
> +}
> +
> +void audio_ipc_init(void)
> +{
> + audio_io = ipc_connect(BLUEZ_AUDIO_SK_PATH, sizeof(BLUEZ_AUDIO_SK_PATH),
> + audio_connect_cb);
> +}
> +
> +void audio_ipc_cleanup(void)
> +{
> + if (audio_io) {
> + g_io_channel_shutdown(audio_io, TRUE, NULL);
> + g_io_channel_unref(audio_io);
> + audio_io = NULL;
> + }
> +}
> diff --git a/android/ipc.h b/android/ipc.h
> index 6cd102b..8e92811 100644
> --- a/android/ipc.h
> +++ b/android/ipc.h
> @@ -37,3 +37,6 @@ void ipc_send_notif(uint8_t service_id, uint8_t opcode,
> uint16_t len, void ipc_register(uint8_t service, const struct ipc_handler
> *handlers, uint8_t size);
> void ipc_unregister(uint8_t service);
> +
> +void audio_ipc_init(void);
> +void audio_ipc_cleanup(void);
--
Szymon K. Janc
[email protected]
Hi Andrei,
On Fri, Jan 3, 2014 at 12:56 PM, Andrei Emeltchenko
<[email protected]> wrote:
> Hi Luiz,
>
> On Thu, Jan 02, 2014 at 01:58:25PM +0200, Luiz Augusto von Dentz wrote:
>> From: Luiz Augusto von Dentz <[email protected]>
>>
>> This add initial code for listen and accept connections on the abstract
>> socket defined for the audio IPC.
>> ---
>> v2: Split audio IPC services for HAL services and fix invalid messages or
>> disconnections causing the daemon to exit. The audio HAL is independent of
>> bluetooth and should only affect A2DP service.
>>
>> android/hal-msg.h | 1 +
>> android/ipc.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
>> android/ipc.h | 3 +++
>> 3 files changed, 76 insertions(+), 6 deletions(-)
>>
>> diff --git a/android/hal-msg.h b/android/hal-msg.h
>> index c351501..b14eced 100644
>> --- a/android/hal-msg.h
>> +++ b/android/hal-msg.h
>> @@ -24,6 +24,7 @@
>> #define BLUEZ_HAL_MTU 1024
>>
>> static const char BLUEZ_HAL_SK_PATH[] = "\0bluez_hal_socket";
>> +static const char BLUEZ_AUDIO_SK_PATH[] = "\0bluez_audio_socket";
>>
>> struct hal_hdr {
>> uint8_t service_id;
>> diff --git a/android/ipc.c b/android/ipc.c
>> index 9e8ccc3..4c5a77e 100644
>> --- a/android/ipc.c
>> +++ b/android/ipc.c
>> @@ -49,6 +49,7 @@ static struct service_handler services[HAL_SERVICE_ID_MAX + 1];
>>
>> static GIOChannel *cmd_io = NULL;
>> static GIOChannel *notif_io = NULL;
>> +static GIOChannel *audio_io = NULL;
>>
>> static void ipc_handle_msg(const void *buf, ssize_t len)
>> {
>> @@ -145,7 +146,8 @@ static gboolean notif_watch_cb(GIOChannel *io, GIOCondition cond,
>> return FALSE;
>> }
>>
>> -static GIOChannel *connect_hal(GIOFunc connect_cb)
>> +static GIOChannel *ipc_connect(const char *path, size_t size,
>> + GIOFunc connect_cb)
>> {
>
> Does it make sense for better understanding to split patch to two parts:
> one is changing connect_hal to ipc_connect and another adding audio ipc?
Well, it is quite self contained and the functionality doesn't change
much as Im just passing the path of the socket to function that is
static instead of copying connect_hal so I considered it too trivial
to have it separated. Note that sometimes we do bother to split even
trivial changes when the patches get way too big and convoluted to be
able to spot this minor details, this patch though has less than 100
lines changes.
--
Luiz Augusto von Dentz
Hi Luiz,
On Thu, Jan 02, 2014 at 01:58:25PM +0200, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <[email protected]>
>
> This add initial code for listen and accept connections on the abstract
> socket defined for the audio IPC.
> ---
> v2: Split audio IPC services for HAL services and fix invalid messages or
> disconnections causing the daemon to exit. The audio HAL is independent of
> bluetooth and should only affect A2DP service.
>
> android/hal-msg.h | 1 +
> android/ipc.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
> android/ipc.h | 3 +++
> 3 files changed, 76 insertions(+), 6 deletions(-)
>
> diff --git a/android/hal-msg.h b/android/hal-msg.h
> index c351501..b14eced 100644
> --- a/android/hal-msg.h
> +++ b/android/hal-msg.h
> @@ -24,6 +24,7 @@
> #define BLUEZ_HAL_MTU 1024
>
> static const char BLUEZ_HAL_SK_PATH[] = "\0bluez_hal_socket";
> +static const char BLUEZ_AUDIO_SK_PATH[] = "\0bluez_audio_socket";
>
> struct hal_hdr {
> uint8_t service_id;
> diff --git a/android/ipc.c b/android/ipc.c
> index 9e8ccc3..4c5a77e 100644
> --- a/android/ipc.c
> +++ b/android/ipc.c
> @@ -49,6 +49,7 @@ static struct service_handler services[HAL_SERVICE_ID_MAX + 1];
>
> static GIOChannel *cmd_io = NULL;
> static GIOChannel *notif_io = NULL;
> +static GIOChannel *audio_io = NULL;
>
> static void ipc_handle_msg(const void *buf, ssize_t len)
> {
> @@ -145,7 +146,8 @@ static gboolean notif_watch_cb(GIOChannel *io, GIOCondition cond,
> return FALSE;
> }
>
> -static GIOChannel *connect_hal(GIOFunc connect_cb)
> +static GIOChannel *ipc_connect(const char *path, size_t size,
> + GIOFunc connect_cb)
> {
Does it make sense for better understanding to split patch to two parts:
one is changing connect_hal to ipc_connect and another adding audio ipc?
Best regards
Andrei Emeltchenko
> struct sockaddr_un addr;
> GIOCondition cond;
> @@ -167,11 +169,11 @@ static GIOChannel *connect_hal(GIOFunc connect_cb)
> memset(&addr, 0, sizeof(addr));
> addr.sun_family = AF_UNIX;
>
> - memcpy(addr.sun_path, BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH));
> + memcpy(addr.sun_path, path, size);
>
> if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
> - error("IPC: failed to connect HAL socket: %d (%s)", errno,
> - strerror(errno));
> + error("IPC: failed to connect HAL socket %s: %d (%s)", &path[1],
> + errno, strerror(errno));
> g_io_channel_unref(io);
> return NULL;
> }
> @@ -218,7 +220,8 @@ static gboolean cmd_connect_cb(GIOChannel *io, GIOCondition cond,
> return FALSE;
> }
>
> - notif_io = connect_hal(notif_connect_cb);
> + notif_io = ipc_connect(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
> + notif_connect_cb);
> if (!notif_io)
> raise(SIGTERM);
>
> @@ -227,7 +230,8 @@ static gboolean cmd_connect_cb(GIOChannel *io, GIOCondition cond,
>
> void ipc_init(void)
> {
> - cmd_io = connect_hal(cmd_connect_cb);
> + cmd_io = ipc_connect(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
> + cmd_connect_cb);
> if (!cmd_io)
> raise(SIGTERM);
> }
> @@ -338,3 +342,65 @@ void ipc_unregister(uint8_t service)
> services[service].handler = NULL;
> services[service].size = 0;
> }
> +
> +static gboolean audio_watch_cb(GIOChannel *io, GIOCondition cond,
> + gpointer user_data)
> +{
> + char buf[BLUEZ_HAL_MTU];
> + ssize_t ret;
> + int fd;
> +
> + if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
> + info("Audio IPC: command socket closed");
> + goto fail;
> + }
> +
> + fd = g_io_channel_unix_get_fd(io);
> +
> + ret = read(fd, buf, sizeof(buf));
> + if (ret < 0) {
> + error("Audio IPC: command read failed (%s)", strerror(errno));
> + goto fail;
> + }
> +
> + return TRUE;
> +
> +fail:
> + audio_ipc_cleanup();
> + return FALSE;
> +}
> +
> +static gboolean audio_connect_cb(GIOChannel *io, GIOCondition cond,
> + gpointer user_data)
> +{
> + DBG("");
> +
> + if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
> + error("Audio IPC: socket connect failed");
> + audio_ipc_cleanup();
> + return FALSE;
> + }
> +
> + cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
> +
> + g_io_add_watch(audio_io, cond, audio_watch_cb, NULL);
> +
> + info("Audio IPC: successfully connected");
> +
> + return FALSE;
> +}
> +
> +void audio_ipc_init(void)
> +{
> + audio_io = ipc_connect(BLUEZ_AUDIO_SK_PATH, sizeof(BLUEZ_AUDIO_SK_PATH),
> + audio_connect_cb);
> +}
> +
> +void audio_ipc_cleanup(void)
> +{
> + if (audio_io) {
> + g_io_channel_shutdown(audio_io, TRUE, NULL);
> + g_io_channel_unref(audio_io);
> + audio_io = NULL;
> + }
> +}
> diff --git a/android/ipc.h b/android/ipc.h
> index 6cd102b..8e92811 100644
> --- a/android/ipc.h
> +++ b/android/ipc.h
> @@ -37,3 +37,6 @@ void ipc_send_notif(uint8_t service_id, uint8_t opcode, uint16_t len,
> void ipc_register(uint8_t service, const struct ipc_handler *handlers,
> uint8_t size);
> void ipc_unregister(uint8_t service);
> +
> +void audio_ipc_init(void);
> +void audio_ipc_cleanup(void);
> --
> 1.8.4.2
>
> --
> 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
From: Luiz Augusto von Dentz <[email protected]>
This adds initial code to handle audio IPC commands.
---
android/a2dp.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index 581d094..7550644 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -352,6 +352,9 @@ static sdp_record_t *a2dp_record(void)
return record;
}
+static const struct ipc_handler audio_handlers[] = {
+};
+
bool bt_a2dp_register(const bdaddr_t *addr)
{
GError *err = NULL;
@@ -359,6 +362,8 @@ bool bt_a2dp_register(const bdaddr_t *addr)
DBG("");
+ audio_ipc_init();
+
bacpy(&adapter_addr, addr);
server = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
@@ -388,6 +393,9 @@ bool bt_a2dp_register(const bdaddr_t *addr)
ipc_register(HAL_SERVICE_ID_A2DP, cmd_handlers,
G_N_ELEMENTS(cmd_handlers));
+ audio_ipc_register(AUDIO_SERVICE_ID_CORE, audio_handlers,
+ G_N_ELEMENTS(audio_handlers));
+
return true;
fail:
@@ -411,8 +419,9 @@ void bt_a2dp_unregister(void)
g_slist_foreach(devices, a2dp_device_disconnected, NULL);
devices = NULL;
-
ipc_unregister(HAL_SERVICE_ID_A2DP);
+ audio_ipc_unregister(AUDIO_SERVICE_ID_CORE);
+
bt_adapter_remove_record(record_id);
record_id = 0;
@@ -421,4 +430,6 @@ void bt_a2dp_unregister(void)
g_io_channel_unref(server);
server = NULL;
}
+
+ audio_ipc_cleanup();
}
--
1.8.4.2
From: Luiz Augusto von Dentz <[email protected]>
This adds the definitions to audio open command and response.
---
android/a2dp.c | 10 ++++++++++
android/audio-ipc-api.txt | 2 +-
android/hal-msg.h | 18 ++++++++++++++++++
3 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index 7550644..325c282 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -352,7 +352,17 @@ static sdp_record_t *a2dp_record(void)
return record;
}
+static void bt_audio_open(const void *buf, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ audio_ipc_send_rsp(AUDIO_SERVICE_ID_CORE, AUDIO_OP_OPEN,
+ HAL_STATUS_FAILED);
+}
+
static const struct ipc_handler audio_handlers[] = {
+ /* AUDIO_OP_OPEN */
+ { bt_audio_open, true, sizeof(struct audio_cmd_open) },
};
bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/audio-ipc-api.txt b/android/audio-ipc-api.txt
index 1c42800..37a1569 100644
--- a/android/audio-ipc-api.txt
+++ b/android/audio-ipc-api.txt
@@ -49,9 +49,9 @@ Identifier: "audio" (BT_AUDIO_ID)
Command parameters: Service UUID (16 octets)
Codec ID (1 octet)
+ Number of codec presets (1 octet)
Codec capabilities length (1 octet)
Codec capabilities (variable)
- Number of codec presets (1 octet)
Codec preset # length (1 octet)
Codec preset # configuration (variable)
...
diff --git a/android/hal-msg.h b/android/hal-msg.h
index 267f9b2..1036988 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -570,3 +570,21 @@ struct hal_ev_a2dp_audio_state {
uint8_t state;
uint8_t bdaddr[6];
} __attribute__((packed));
+
+#define AUDIO_OP_OPEN 0x01
+struct audio_preset {
+ uint8_t len;
+ uint8_t data[0];
+} __attribute__((packed));
+
+struct audio_cmd_open {
+ uint16_t uuid;
+ uint8_t codec;
+ uint8_t presets;
+ uint8_t len;
+ struct audio_preset preset[0];
+} __attribute__((packed));
+
+struct audio_rsp_open {
+ uint8_t id;
+} __attribute__((packed));
--
1.8.4.2
From: Luiz Augusto von Dentz <[email protected]>
This adds audio_ipc_register and audio_ipc_unregister and adapt
ipc_handle_msg to be able to handle audio services messages.
---
android/hal-msg.h | 4 +++
android/ipc.c | 78 +++++++++++++++++++++++++++++++++++--------------------
android/ipc.h | 4 +++
3 files changed, 58 insertions(+), 28 deletions(-)
diff --git a/android/hal-msg.h b/android/hal-msg.h
index b14eced..267f9b2 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -48,6 +48,10 @@ struct hal_hdr {
#define HAL_SERVICE_ID_MAX HAL_SERVICE_ID_GATT
+#define AUDIO_SERVICE_ID_CORE 0
+
+#define AUDIO_SERVICE_ID_MAX AUDIO_SERVICE_ID_CORE
+
/* Core Service */
#define HAL_STATUS_SUCCESS 0x00
diff --git a/android/ipc.c b/android/ipc.c
index 4c5a77e..f18e1eb 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -46,51 +46,46 @@ struct service_handler {
};
static struct service_handler services[HAL_SERVICE_ID_MAX + 1];
+static struct service_handler audio_services[AUDIO_SERVICE_ID_MAX + 1];
static GIOChannel *cmd_io = NULL;
static GIOChannel *notif_io = NULL;
static GIOChannel *audio_io = NULL;
-static void ipc_handle_msg(const void *buf, ssize_t len)
+static int ipc_handle_msg(struct service_handler *handlers, size_t max_index,
+ const void *buf, ssize_t len)
{
const struct hal_hdr *msg = buf;
const struct ipc_handler *handler;
if (len < (ssize_t) sizeof(*msg)) {
- error("IPC: message too small (%zd bytes), terminating", len);
- raise(SIGTERM);
- return;
+ DBG("message too small (%zd bytes)", len);
+ return -EBADMSG;
}
if (len != (ssize_t) (sizeof(*msg) + msg->len)) {
- error("IPC: message malformed (%zd bytes), terminating", len);
- raise(SIGTERM);
- return;
+ DBG("message malformed (%zd bytes)", len);
+ return -EBADMSG;
}
/* if service is valid */
- if (msg->service_id > HAL_SERVICE_ID_MAX) {
- error("IPC: unknown service (0x%x), terminating",
- msg->service_id);
- raise(SIGTERM);
- return;
+ if (msg->service_id > max_index) {
+ DBG("unknown service (0x%x)", msg->service_id);
+ return -EOPNOTSUPP;
}
/* if service is registered */
- if (!services[msg->service_id].handler) {
- error("IPC: unregistered service (0x%x), terminating",
- msg->service_id);
- raise(SIGTERM);
- return;
+ if (!handlers[msg->service_id].handler) {
+ DBG("service not registered (0x%x)", msg->service_id);
+ return -EOPNOTSUPP;
}
/* if opcode is valid */
if (msg->opcode == HAL_OP_STATUS ||
- msg->opcode > services[msg->service_id].size) {
- error("IPC: invalid opcode 0x%x for service 0x%x, terminating",
- msg->opcode, msg->service_id);
- raise(SIGTERM);
- return;
+ msg->opcode > handlers[msg->service_id].size) {
+ DBG("invalid opcode 0x%x for service 0x%x", msg->opcode,
+ msg->service_id);
+ return -EOPNOTSUPP;
}
/* opcode is table offset + 1 */
@@ -99,13 +94,14 @@ static void ipc_handle_msg(const void *buf, ssize_t len)
/* if payload size is valid */
if ((handler->var_len && handler->data_len > msg->len) ||
(!handler->var_len && handler->data_len != msg->len)) {
- error("IPC: size invalid opcode 0x%x service 0x%x, terminating",
+ DBG("invalid size for opcode 0x%x service 0x%x",
msg->service_id, msg->opcode);
- raise(SIGTERM);
- return;
+ return -EMSGSIZE;
}
handler->handler(msg->payload, msg->len);
+
+ return 0;
}
static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
@@ -113,7 +109,7 @@ static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
{
char buf[BLUEZ_HAL_MTU];
ssize_t ret;
- int fd;
+ int fd, err;
if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
info("IPC: command socket closed, terminating");
@@ -129,7 +125,13 @@ static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
goto fail;
}
- ipc_handle_msg(buf, ret);
+ err = ipc_handle_msg(services, HAL_SERVICE_ID_MAX, buf, ret);
+ if (err < 0) {
+ error("IPC: failed to handle message, terminating (%s)",
+ strerror(-err));
+ goto fail;
+ }
+
return TRUE;
fail:
@@ -348,7 +350,7 @@ static gboolean audio_watch_cb(GIOChannel *io, GIOCondition cond,
{
char buf[BLUEZ_HAL_MTU];
ssize_t ret;
- int fd;
+ int fd, err;
if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
info("Audio IPC: command socket closed");
@@ -363,6 +365,13 @@ static gboolean audio_watch_cb(GIOChannel *io, GIOCondition cond,
goto fail;
}
+ err = ipc_handle_msg(audio_services, AUDIO_SERVICE_ID_MAX, buf, ret);
+ if (err < 0) {
+ error("Audio IPC: failed to handle message (%s)",
+ strerror(-err));
+ goto fail;
+ }
+
return TRUE;
fail:
@@ -404,3 +413,16 @@ void audio_ipc_cleanup(void)
audio_io = NULL;
}
}
+
+void audio_ipc_register(uint8_t service, const struct ipc_handler *handlers,
+ uint8_t size)
+{
+ audio_services[service].handler = handlers;
+ audio_services[service].size = size;
+}
+
+void audio_ipc_unregister(uint8_t service)
+{
+ audio_services[service].handler = NULL;
+ audio_services[service].size = 0;
+}
diff --git a/android/ipc.h b/android/ipc.h
index 8e92811..44d5a5d 100644
--- a/android/ipc.h
+++ b/android/ipc.h
@@ -40,3 +40,7 @@ void ipc_unregister(uint8_t service);
void audio_ipc_init(void);
void audio_ipc_cleanup(void);
+
+void audio_ipc_register(uint8_t service, const struct ipc_handler *handlers,
+ uint8_t size);
+void audio_ipc_unregister(uint8_t service);
--
1.8.4.2
From: Luiz Augusto von Dentz <[email protected]>
This adds the definitions to stream suspend command and response.
---
android/a2dp.c | 10 ++++++++++
android/hal-msg.h | 5 +++++
2 files changed, 15 insertions(+)
diff --git a/android/a2dp.c b/android/a2dp.c
index d3c02d6..dc2890c 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -392,6 +392,14 @@ static void bt_stream_resume(const void *buf, uint16_t len)
HAL_STATUS_FAILED);
}
+static void bt_stream_suspend(const void *buf, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ audio_ipc_send_rsp(AUDIO_SERVICE_ID_CORE, AUDIO_OP_SUSPEND_STREAM,
+ HAL_STATUS_FAILED);
+}
+
static const struct ipc_handler audio_handlers[] = {
/* AUDIO_OP_OPEN */
{ bt_audio_open, true, sizeof(struct audio_cmd_open) },
@@ -403,6 +411,8 @@ static const struct ipc_handler audio_handlers[] = {
{ bt_stream_close, false, sizeof(struct audio_cmd_close_stream) },
/* AUDIO_OP_RESUME_STREAM */
{ bt_stream_resume, false, sizeof(struct audio_cmd_resume_stream) },
+ /* AUDIO_OP_SUSPEND_STREAM */
+ { bt_stream_suspend, false, sizeof(struct audio_cmd_suspend_stream) },
};
bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/hal-msg.h b/android/hal-msg.h
index 259b687..6b2ec88 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -613,3 +613,8 @@ struct audio_cmd_close_stream {
struct audio_cmd_resume_stream {
uint8_t id;
} __attribute__((packed));
+
+#define AUDIO_OP_SUSPEND_STREAM 0x06
+struct audio_cmd_suspend_stream {
+ uint8_t id;
+} __attribute__((packed));
--
1.8.4.2
From: Luiz Augusto von Dentz <[email protected]>
This adds the definitions to stream open command and response.
---
android/a2dp.c | 10 ++++++++++
android/hal-msg.h | 10 ++++++++++
2 files changed, 20 insertions(+)
diff --git a/android/a2dp.c b/android/a2dp.c
index e3d58ca..7709b15 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -368,11 +368,21 @@ static void bt_audio_close(const void *buf, uint16_t len)
HAL_STATUS_FAILED);
}
+static void bt_stream_open(const void *buf, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ audio_ipc_send_rsp(AUDIO_SERVICE_ID_CORE, AUDIO_OP_OPEN_STREAM,
+ HAL_STATUS_FAILED);
+}
+
static const struct ipc_handler audio_handlers[] = {
/* AUDIO_OP_OPEN */
{ bt_audio_open, true, sizeof(struct audio_cmd_open) },
/* AUDIO_OP_CLOSE */
{ bt_audio_close, false, sizeof(struct audio_cmd_close) },
+ /* AUDIO_OP_OPEN_STREAM */
+ { bt_stream_open, false, sizeof(struct audio_cmd_open_stream) },
};
bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/hal-msg.h b/android/hal-msg.h
index d1135df..ff62de0 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -593,3 +593,13 @@ struct audio_rsp_open {
struct audio_cmd_close {
uint8_t id;
} __attribute__((packed));
+
+#define AUDIO_OP_OPEN_STREAM 0x03
+struct audio_cmd_open_stream {
+ uint8_t id;
+} __attribute__((packed));
+
+struct audio_rsp_open_stream {
+ uint8_t len;
+ uint8_t data[0];
+} __attribute__((packed));
--
1.8.4.2
From: Luiz Augusto von Dentz <[email protected]>
This adds the definitions to stream close command and response.
---
android/a2dp.c | 10 ++++++++++
android/hal-msg.h | 5 +++++
2 files changed, 15 insertions(+)
diff --git a/android/a2dp.c b/android/a2dp.c
index 7709b15..eac427d 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -376,6 +376,14 @@ static void bt_stream_open(const void *buf, uint16_t len)
HAL_STATUS_FAILED);
}
+static void bt_stream_close(const void *buf, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ audio_ipc_send_rsp(AUDIO_SERVICE_ID_CORE, AUDIO_OP_CLOSE_STREAM,
+ HAL_STATUS_FAILED);
+}
+
static const struct ipc_handler audio_handlers[] = {
/* AUDIO_OP_OPEN */
{ bt_audio_open, true, sizeof(struct audio_cmd_open) },
@@ -383,6 +391,8 @@ static const struct ipc_handler audio_handlers[] = {
{ bt_audio_close, false, sizeof(struct audio_cmd_close) },
/* AUDIO_OP_OPEN_STREAM */
{ bt_stream_open, false, sizeof(struct audio_cmd_open_stream) },
+ /* AUDIO_OP_CLOSE_STREAM */
+ { bt_stream_close, false, sizeof(struct audio_cmd_close_stream) },
};
bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/hal-msg.h b/android/hal-msg.h
index ff62de0..a708157 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -603,3 +603,8 @@ struct audio_rsp_open_stream {
uint8_t len;
uint8_t data[0];
} __attribute__((packed));
+
+#define AUDIO_OP_CLOSE_STREAM 0x04
+struct audio_cmd_close_stream {
+ uint8_t id;
+} __attribute__((packed));
--
1.8.4.2
From: Luiz Augusto von Dentz <[email protected]>
This adds the definitions to audio close command and response.
---
android/a2dp.c | 10 ++++++++++
android/hal-msg.h | 5 +++++
2 files changed, 15 insertions(+)
diff --git a/android/a2dp.c b/android/a2dp.c
index 325c282..e3d58ca 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -360,9 +360,19 @@ static void bt_audio_open(const void *buf, uint16_t len)
HAL_STATUS_FAILED);
}
+static void bt_audio_close(const void *buf, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ audio_ipc_send_rsp(AUDIO_SERVICE_ID_CORE, AUDIO_OP_CLOSE,
+ HAL_STATUS_FAILED);
+}
+
static const struct ipc_handler audio_handlers[] = {
/* AUDIO_OP_OPEN */
{ bt_audio_open, true, sizeof(struct audio_cmd_open) },
+ /* AUDIO_OP_CLOSE */
+ { bt_audio_close, false, sizeof(struct audio_cmd_close) },
};
bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/hal-msg.h b/android/hal-msg.h
index 1036988..d1135df 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -588,3 +588,8 @@ struct audio_cmd_open {
struct audio_rsp_open {
uint8_t id;
} __attribute__((packed));
+
+#define AUDIO_OP_CLOSE 0x02
+struct audio_cmd_close {
+ uint8_t id;
+} __attribute__((packed));
--
1.8.4.2
From: Luiz Augusto von Dentz <[email protected]>
This adds the definitions to stream resume command and response.
---
android/a2dp.c | 10 ++++++++++
android/hal-msg.h | 5 +++++
2 files changed, 15 insertions(+)
diff --git a/android/a2dp.c b/android/a2dp.c
index eac427d..d3c02d6 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -384,6 +384,14 @@ static void bt_stream_close(const void *buf, uint16_t len)
HAL_STATUS_FAILED);
}
+static void bt_stream_resume(const void *buf, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ audio_ipc_send_rsp(AUDIO_SERVICE_ID_CORE, AUDIO_OP_RESUME_STREAM,
+ HAL_STATUS_FAILED);
+}
+
static const struct ipc_handler audio_handlers[] = {
/* AUDIO_OP_OPEN */
{ bt_audio_open, true, sizeof(struct audio_cmd_open) },
@@ -393,6 +401,8 @@ static const struct ipc_handler audio_handlers[] = {
{ bt_stream_open, false, sizeof(struct audio_cmd_open_stream) },
/* AUDIO_OP_CLOSE_STREAM */
{ bt_stream_close, false, sizeof(struct audio_cmd_close_stream) },
+ /* AUDIO_OP_RESUME_STREAM */
+ { bt_stream_resume, false, sizeof(struct audio_cmd_resume_stream) },
};
bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/hal-msg.h b/android/hal-msg.h
index a708157..259b687 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -608,3 +608,8 @@ struct audio_rsp_open_stream {
struct audio_cmd_close_stream {
uint8_t id;
} __attribute__((packed));
+
+#define AUDIO_OP_RESUME_STREAM 0x05
+struct audio_cmd_resume_stream {
+ uint8_t id;
+} __attribute__((packed));
--
1.8.4.2
From: Luiz Augusto von Dentz <[email protected]>
These functions can be used to respond to commands recieved over audio
IPC.
---
android/ipc.c | 24 ++++++++++++++++++++++++
android/ipc.h | 4 ++++
2 files changed, 28 insertions(+)
diff --git a/android/ipc.c b/android/ipc.c
index f18e1eb..a116a20 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -414,6 +414,30 @@ void audio_ipc_cleanup(void)
}
}
+void audio_ipc_send_rsp(uint8_t service_id, uint8_t opcode, uint8_t status)
+{
+ struct hal_status s;
+ int sk;
+
+ sk = g_io_channel_unix_get_fd(audio_io);
+
+ if (status == HAL_STATUS_SUCCESS) {
+ ipc_send(sk, service_id, opcode, 0, NULL, -1);
+ return;
+ }
+
+ s.code = status;
+
+ ipc_send(sk, service_id, HAL_OP_STATUS, sizeof(s), &s, -1);
+}
+
+void audio_ipc_send_rsp_full(uint8_t service_id, uint8_t opcode, uint16_t len,
+ void *param, int fd)
+{
+ ipc_send(g_io_channel_unix_get_fd(audio_io), service_id, opcode, len,
+ param, fd);
+}
+
void audio_ipc_register(uint8_t service, const struct ipc_handler *handlers,
uint8_t size)
{
diff --git a/android/ipc.h b/android/ipc.h
index 44d5a5d..f224367 100644
--- a/android/ipc.h
+++ b/android/ipc.h
@@ -41,6 +41,10 @@ void ipc_unregister(uint8_t service);
void audio_ipc_init(void);
void audio_ipc_cleanup(void);
+void audio_ipc_send_rsp(uint8_t service_id, uint8_t opcode, uint8_t status);
+void audio_ipc_send_rsp_full(uint8_t service_id, uint8_t opcode, uint16_t len,
+ void *param, int fd);
+
void audio_ipc_register(uint8_t service, const struct ipc_handler *handlers,
uint8_t size);
void audio_ipc_unregister(uint8_t service);
--
1.8.4.2