2013-12-30 12:34:07

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [RFC BlueZ 1/9] android: Add initial code for audio IPC

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.
---
android/hal-msg.h | 1 +
android/ipc.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++------
android/ipc.h | 3 +++
3 files changed, 51 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..6cdbf60 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 *connect_hal(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 = connect_hal(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 = connect_hal(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
+ cmd_connect_cb);
if (!cmd_io)
raise(SIGTERM);
}
@@ -338,3 +342,40 @@ void ipc_unregister(uint8_t service)
services[service].handler = NULL;
services[service].size = 0;
}
+
+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, terminating");
+ 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, cmd_watch_cb, NULL);
+
+ info("Audio IPC: successfully connected");
+
+ return FALSE;
+}
+
+void audio_ipc_init(void)
+{
+ audio_io = connect_hal(BLUEZ_AUDIO_SK_PATH, sizeof(BLUEZ_AUDIO_SK_PATH),
+ audio_connect_cb);
+ if (!cmd_io)
+ raise(SIGTERM);
+}
+
+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



2013-12-30 20:50:24

by Lukasz Rymanowski

[permalink] [raw]
Subject: Re: [RFC BlueZ 9/9] android: Add hal_audio_ipc_init and hal_audio_ipc_cleanup

Hi Luiz,

On Mon, Dec 30, 2013 at 1:34 PM, Luiz Augusto von Dentz
<[email protected]> wrote:
> From: Luiz Augusto von Dentz <[email protected]>
>
> These function initialize the audio IPC in the HAL side.
> ---
> android/hal-audio.c | 9 +++++++++
> android/hal-ipc.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> android/hal-ipc.h | 3 +++
> 3 files changed, 68 insertions(+)
>
> diff --git a/android/hal-audio.c b/android/hal-audio.c
> index 7f4a3f2..2e7dcca 100644
> --- a/android/hal-audio.c
> +++ b/android/hal-audio.c
> @@ -24,6 +24,7 @@
> #include <hardware/hardware.h>
>
> #include "hal-log.h"
> +#include "hal-ipc.h"
>
> static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
> size_t bytes)
> @@ -374,6 +375,9 @@ static int audio_dump(const audio_hw_device_t *device, int fd)
> static int audio_close(hw_device_t *device)
> {
> DBG("");
> +
> + hal_audio_ipc_cleanup();
> +
> free(device);
> return 0;
> }
> @@ -391,6 +395,11 @@ static int audio_open(const hw_module_t *module, const char *name,
> return -EINVAL;
> }
>
> + if (!hal_audio_ipc_init()) {
> + error("Unable to initialize audio IPC");
> + return -ENOTCONN;
> + }
> +
> audio = calloc(1, sizeof(struct audio_hw_device));
> if (!audio)
> return -ENOMEM;
> diff --git a/android/hal-ipc.c b/android/hal-ipc.c
> index b19704a..3a1fcc7 100644
> --- a/android/hal-ipc.c
> +++ b/android/hal-ipc.c
> @@ -38,6 +38,7 @@
>
> static int cmd_sk = -1;
> static int notif_sk = -1;
> +static int audio_sk = -1;
>
> static pthread_mutex_t cmd_sk_mutex = PTHREAD_MUTEX_INITIALIZER;
>
> @@ -449,3 +450,58 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
>
> return BT_STATUS_SUCCESS;
> }
> +
> +bool hal_audio_ipc_init(void)
> +{
> + struct sockaddr_un addr;
> + int sk;
> + int err;
> +
> + sk = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
> + if (sk < 0) {
> + err = errno;
> + error("Failed to create socket: %d (%s)", err,
> + strerror(err));
> + return false;
> + }
> +
> + memset(&addr, 0, sizeof(addr));
> + addr.sun_family = AF_UNIX;
> +
> + memcpy(addr.sun_path, BLUEZ_AUDIO_SK_PATH, sizeof(BLUEZ_AUDIO_SK_PATH));
> +
> + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
> + err = errno;
> + error("Failed to bind socket: %d (%s)", err, strerror(err));
> + close(sk);
> + return false;
> + }
> +
> + if (listen(sk, 2) < 0) {

Backlog = 1 should be enough here.

> + err = errno;
> + error("Failed to listen on socket: %d (%s)", err,
> + strerror(err));
> + close(sk);
> + return false;
> + }
> +
> + audio_sk = accept_connection(sk);

We can not block audio_open(), so as we discussed on IRC and as I
proposed in my patches, we need to call hal_audio_ipc_init in thread.

> + if (audio_sk < 0) {
> + close(sk);
> + return false;
> + }
> +
> + info("audio connected");
> +
> + close(sk);
> +
> + return true;
> +}
> +
> +void hal_audio_ipc_cleanup(void)
> +{
> + close(audio_sk);
> + audio_sk = -1;
> +
> + shutdown(audio_sk, SHUT_RD);
> +}
> diff --git a/android/hal-ipc.h b/android/hal-ipc.h
> index 2fbf30f..bd1682d 100644
> --- a/android/hal-ipc.h
> +++ b/android/hal-ipc.h
> @@ -30,3 +30,6 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
> void hal_ipc_register(uint8_t service, const struct hal_ipc_handler *handlers,
> uint8_t size);
> void hal_ipc_unregister(uint8_t service);
> +
> +bool hal_audio_ipc_init(void);
> +void hal_audio_ipc_cleanup(void);
> --
> 1.8.4.2
>

\Lukasz

> --
> 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

2013-12-30 13:36:37

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [RFC BlueZ 3/9] android: Add audio open command/response struct

Hi Szymon,

On Mon, Dec 30, 2013 at 3:27 PM, Szymon Janc <[email protected]> wrote:
> Hi Luiz,
>
> On Monday 30 December 2013 14:34:09 Luiz Augusto von Dentz wrote:
>> From: Luiz Augusto von Dentz <[email protected]>
>>
>> This adds the definitions to audio open command and response.
>> ---
>> android/a2dp.c | 9 +++++++++
>> android/audio-ipc-api.txt | 2 +-
>> android/hal-msg.h | 18 ++++++++++++++++++
>> android/ipc.c | 5 ++++-
>> 4 files changed, 32 insertions(+), 2 deletions(-)
>>
>> diff --git a/android/a2dp.c b/android/a2dp.c
>> index 63f1f58..5cb01f7 100644
>> --- a/android/a2dp.c
>> +++ b/android/a2dp.c
>> @@ -352,7 +352,16 @@ static sdp_record_t *a2dp_record(void)
>> return record;
>> }
>>
>> +static void bt_audio_open(const void *buf, uint16_t len)
>> +{
>> + DBG("Not Implemented");
>> +
>> + ipc_send_rsp(HAL_SERVICE_ID_AUDIO, 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 1afb1bc..4b52e5e 100644
>> --- a/android/hal-msg.h
>> +++ b/android/hal-msg.h
>> @@ -567,3 +567,21 @@ struct hal_ev_a2dp_audio_state {
>> uint8_t state;
>> uint8_t bdaddr[6];
>> } __attribute__((packed));
>> +
>> +#define AUDIO_OP_OPEN 0x01
>> +struct audio_cmd_open {
>> + uint16_t uuid;
>> + uint8_t codec;
>> + uint8_t presets;
>> + uint8_t len;
>> + uint8_t data[0];
>
> Maybe this could be
> struct audio_preset[0];
> ? (if that would make code cleaner)

Indeed, will fix it.

Luiz Augusto von Dentz

2013-12-30 13:34:26

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [RFC BlueZ 1/9] android: Add initial code for audio IPC

Hi Szymon,

On Mon, Dec 30, 2013 at 3:26 PM, Szymon Janc <[email protected]> wrote:
> Hi Luiz,
>
> On Monday 30 December 2013 14:34:07 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.
>> ---
>> android/hal-msg.h | 1 +
>> android/ipc.c | 53
>> +++++++++++++++++++++++++++++++++++++++++++++++------ android/ipc.h |
>> 3 +++
>> 3 files changed, 51 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..6cdbf60 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 *connect_hal(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 = connect_hal(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 = connect_hal(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
>> + cmd_connect_cb);
>> if (!cmd_io)
>> raise(SIGTERM);
>> }
>> @@ -338,3 +342,40 @@ void ipc_unregister(uint8_t service)
>> services[service].handler = NULL;
>> services[service].size = 0;
>> }
>> +
>> +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, terminating");
>
> This message is misleading since we should raise(SIGTERM) to terminate.
>
> But I wonder if we should really terminate on audio IPC failure...
> That is failing on IPC error is OK (since that is a bug in our code anyway),
> but on not being able to connect we could simply fail to register a2dp HAL.
> Same goes with socket being closed - in such case we could fail any request to
> a2dp HAL until connection is recovered.

Yep, the terminating part of the message is misleading it should not
really exit just fail to initialize a2dp.

>> + 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, cmd_watch_cb, NULL);
>> +
>> + info("Audio IPC: successfully connected");
>> +
>> + return FALSE;
>> +}
>> +
>> +void audio_ipc_init(void)
>> +{
>> + audio_io = connect_hal(BLUEZ_AUDIO_SK_PATH, sizeof(BLUEZ_AUDIO_SK_PATH),
>> + audio_connect_cb);
>> + if (!cmd_io)
>
> audio_io here?

Yep, that is a bug.

--
Luiz Augusto von Dentz

2013-12-30 13:27:53

by Szymon Janc

[permalink] [raw]
Subject: Re: [RFC BlueZ 3/9] android: Add audio open command/response struct

Hi Luiz,

On Monday 30 December 2013 14:34:09 Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <[email protected]>
>
> This adds the definitions to audio open command and response.
> ---
> android/a2dp.c | 9 +++++++++
> android/audio-ipc-api.txt | 2 +-
> android/hal-msg.h | 18 ++++++++++++++++++
> android/ipc.c | 5 ++++-
> 4 files changed, 32 insertions(+), 2 deletions(-)
>
> diff --git a/android/a2dp.c b/android/a2dp.c
> index 63f1f58..5cb01f7 100644
> --- a/android/a2dp.c
> +++ b/android/a2dp.c
> @@ -352,7 +352,16 @@ static sdp_record_t *a2dp_record(void)
> return record;
> }
>
> +static void bt_audio_open(const void *buf, uint16_t len)
> +{
> + DBG("Not Implemented");
> +
> + ipc_send_rsp(HAL_SERVICE_ID_AUDIO, 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 1afb1bc..4b52e5e 100644
> --- a/android/hal-msg.h
> +++ b/android/hal-msg.h
> @@ -567,3 +567,21 @@ struct hal_ev_a2dp_audio_state {
> uint8_t state;
> uint8_t bdaddr[6];
> } __attribute__((packed));
> +
> +#define AUDIO_OP_OPEN 0x01
> +struct audio_cmd_open {
> + uint16_t uuid;
> + uint8_t codec;
> + uint8_t presets;
> + uint8_t len;
> + uint8_t data[0];

Maybe this could be
struct audio_preset[0];
? (if that would make code cleaner)

> +} __attribute__((packed));
> +
> +struct audio_preset {
> + uint8_t len;
> + uint8_t data[0];
> +} __attribute__((packed));
> +
> +struct audio_rsp_open {
> + uint8_t id;
> +} __attribute__((packed));
> diff --git a/android/ipc.c b/android/ipc.c
> index 6cdbf60..bb16553 100644
> --- a/android/ipc.c
> +++ b/android/ipc.c
> @@ -301,7 +301,10 @@ void 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(cmd_io);
> + if (service_id == HAL_SERVICE_ID_AUDIO)
> + sk = g_io_channel_unix_get_fd(audio_io);
> + else
> + sk = g_io_channel_unix_get_fd(cmd_io);
>
> if (status == HAL_STATUS_SUCCESS) {
> ipc_send(sk, service_id, opcode, 0, NULL, -1);

--
Szymon K. Janc
[email protected]

2013-12-30 13:26:40

by Szymon Janc

[permalink] [raw]
Subject: Re: [RFC BlueZ 1/9] android: Add initial code for audio IPC

Hi Luiz,

On Monday 30 December 2013 14:34:07 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.
> ---
> android/hal-msg.h | 1 +
> android/ipc.c | 53
> +++++++++++++++++++++++++++++++++++++++++++++++------ android/ipc.h |
> 3 +++
> 3 files changed, 51 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..6cdbf60 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 *connect_hal(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 = connect_hal(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 = connect_hal(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
> + cmd_connect_cb);
> if (!cmd_io)
> raise(SIGTERM);
> }
> @@ -338,3 +342,40 @@ void ipc_unregister(uint8_t service)
> services[service].handler = NULL;
> services[service].size = 0;
> }
> +
> +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, terminating");

This message is misleading since we should raise(SIGTERM) to terminate.

But I wonder if we should really terminate on audio IPC failure...
That is failing on IPC error is OK (since that is a bug in our code anyway),
but on not being able to connect we could simply fail to register a2dp HAL.
Same goes with socket being closed - in such case we could fail any request to
a2dp HAL until connection is recovered.

> + 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, cmd_watch_cb, NULL);
> +
> + info("Audio IPC: successfully connected");
> +
> + return FALSE;
> +}
> +
> +void audio_ipc_init(void)
> +{
> + audio_io = connect_hal(BLUEZ_AUDIO_SK_PATH, sizeof(BLUEZ_AUDIO_SK_PATH),
> + audio_connect_cb);
> + if (!cmd_io)

audio_io here?

> + raise(SIGTERM);
> +}
> +
> +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]

2013-12-30 12:34:15

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [RFC BlueZ 9/9] android: Add hal_audio_ipc_init and hal_audio_ipc_cleanup

From: Luiz Augusto von Dentz <[email protected]>

These function initialize the audio IPC in the HAL side.
---
android/hal-audio.c | 9 +++++++++
android/hal-ipc.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++
android/hal-ipc.h | 3 +++
3 files changed, 68 insertions(+)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 7f4a3f2..2e7dcca 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -24,6 +24,7 @@
#include <hardware/hardware.h>

#include "hal-log.h"
+#include "hal-ipc.h"

static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
size_t bytes)
@@ -374,6 +375,9 @@ static int audio_dump(const audio_hw_device_t *device, int fd)
static int audio_close(hw_device_t *device)
{
DBG("");
+
+ hal_audio_ipc_cleanup();
+
free(device);
return 0;
}
@@ -391,6 +395,11 @@ static int audio_open(const hw_module_t *module, const char *name,
return -EINVAL;
}

+ if (!hal_audio_ipc_init()) {
+ error("Unable to initialize audio IPC");
+ return -ENOTCONN;
+ }
+
audio = calloc(1, sizeof(struct audio_hw_device));
if (!audio)
return -ENOMEM;
diff --git a/android/hal-ipc.c b/android/hal-ipc.c
index b19704a..3a1fcc7 100644
--- a/android/hal-ipc.c
+++ b/android/hal-ipc.c
@@ -38,6 +38,7 @@

static int cmd_sk = -1;
static int notif_sk = -1;
+static int audio_sk = -1;

static pthread_mutex_t cmd_sk_mutex = PTHREAD_MUTEX_INITIALIZER;

@@ -449,3 +450,58 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,

return BT_STATUS_SUCCESS;
}
+
+bool hal_audio_ipc_init(void)
+{
+ struct sockaddr_un addr;
+ int sk;
+ int err;
+
+ sk = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
+ if (sk < 0) {
+ err = errno;
+ error("Failed to create socket: %d (%s)", err,
+ strerror(err));
+ return false;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+
+ memcpy(addr.sun_path, BLUEZ_AUDIO_SK_PATH, sizeof(BLUEZ_AUDIO_SK_PATH));
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ err = errno;
+ error("Failed to bind socket: %d (%s)", err, strerror(err));
+ close(sk);
+ return false;
+ }
+
+ if (listen(sk, 2) < 0) {
+ err = errno;
+ error("Failed to listen on socket: %d (%s)", err,
+ strerror(err));
+ close(sk);
+ return false;
+ }
+
+ audio_sk = accept_connection(sk);
+ if (audio_sk < 0) {
+ close(sk);
+ return false;
+ }
+
+ info("audio connected");
+
+ close(sk);
+
+ return true;
+}
+
+void hal_audio_ipc_cleanup(void)
+{
+ close(audio_sk);
+ audio_sk = -1;
+
+ shutdown(audio_sk, SHUT_RD);
+}
diff --git a/android/hal-ipc.h b/android/hal-ipc.h
index 2fbf30f..bd1682d 100644
--- a/android/hal-ipc.h
+++ b/android/hal-ipc.h
@@ -30,3 +30,6 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
void hal_ipc_register(uint8_t service, const struct hal_ipc_handler *handlers,
uint8_t size);
void hal_ipc_unregister(uint8_t service);
+
+bool hal_audio_ipc_init(void);
+void hal_audio_ipc_cleanup(void);
--
1.8.4.2


2013-12-30 12:34:10

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [RFC BlueZ 4/9] android: Add audio close command/response struct

From: Luiz Augusto von Dentz <[email protected]>

This adds the definitions to audio close command and response.
---
android/a2dp.c | 9 +++++++++
android/hal-msg.h | 5 +++++
2 files changed, 14 insertions(+)

diff --git a/android/a2dp.c b/android/a2dp.c
index 5cb01f7..43590f0 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -359,9 +359,18 @@ static void bt_audio_open(const void *buf, uint16_t len)
ipc_send_rsp(HAL_SERVICE_ID_AUDIO, AUDIO_OP_OPEN, HAL_STATUS_FAILED);
}

+static void bt_audio_close(const void *buf, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ ipc_send_rsp(HAL_SERVICE_ID_AUDIO, 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 4b52e5e..f359952 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -585,3 +585,8 @@ struct audio_preset {
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


2013-12-30 12:34:14

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [RFC BlueZ 8/9] android: Add stream suspend command/response struct

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 284d44d..9dbb470 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -390,6 +390,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");
+
+ ipc_send_rsp(HAL_SERVICE_ID_AUDIO, 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) },
@@ -401,6 +409,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 fe433d1..ef40dac 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -610,3 +610,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


2013-12-30 12:34:12

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [RFC BlueZ 6/9] android: Add stream close command/response struct

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 104b950..2dba482 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -374,6 +374,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");
+
+ ipc_send_rsp(HAL_SERVICE_ID_AUDIO, 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) },
@@ -381,6 +389,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 62674fa..2816f6f 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -600,3 +600,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


2013-12-30 12:34:11

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [RFC BlueZ 5/9] android: Add stream open command/response struct

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 43590f0..104b950 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -366,11 +366,21 @@ static void bt_audio_close(const void *buf, uint16_t len)
ipc_send_rsp(HAL_SERVICE_ID_AUDIO, AUDIO_OP_CLOSE, HAL_STATUS_FAILED);
}

+static void bt_stream_open(const void *buf, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ ipc_send_rsp(HAL_SERVICE_ID_AUDIO, 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 f359952..62674fa 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -590,3 +590,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


2013-12-30 12:34:08

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [RFC BlueZ 2/9] android/A2DP: Add initial code to handle audio IPC commands

From: Luiz Augusto von Dentz <[email protected]>

This adds initial code to handle audio IPC commands and defines a new
service id (10).
---
android/a2dp.c | 13 ++++++++++++-
android/hal-msg.h | 3 ++-
2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index 581d094..63f1f58 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));

+ ipc_register(HAL_SERVICE_ID_AUDIO, 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);
+ ipc_unregister(HAL_SERVICE_ID_AUDIO);
+
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();
}
diff --git a/android/hal-msg.h b/android/hal-msg.h
index b14eced..1afb1bc 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -45,8 +45,9 @@ struct hal_hdr {
#define HAL_SERVICE_ID_HEALTH 7
#define HAL_SERVICE_ID_AVRCP 8
#define HAL_SERVICE_ID_GATT 9
+#define HAL_SERVICE_ID_AUDIO 10

-#define HAL_SERVICE_ID_MAX HAL_SERVICE_ID_GATT
+#define HAL_SERVICE_ID_MAX HAL_SERVICE_ID_AUDIO

/* Core Service */

--
1.8.4.2


2013-12-30 12:34:09

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [RFC BlueZ 3/9] android: Add audio open command/response struct

From: Luiz Augusto von Dentz <[email protected]>

This adds the definitions to audio open command and response.
---
android/a2dp.c | 9 +++++++++
android/audio-ipc-api.txt | 2 +-
android/hal-msg.h | 18 ++++++++++++++++++
android/ipc.c | 5 ++++-
4 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index 63f1f58..5cb01f7 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -352,7 +352,16 @@ static sdp_record_t *a2dp_record(void)
return record;
}

+static void bt_audio_open(const void *buf, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ ipc_send_rsp(HAL_SERVICE_ID_AUDIO, 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 1afb1bc..4b52e5e 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -567,3 +567,21 @@ struct hal_ev_a2dp_audio_state {
uint8_t state;
uint8_t bdaddr[6];
} __attribute__((packed));
+
+#define AUDIO_OP_OPEN 0x01
+struct audio_cmd_open {
+ uint16_t uuid;
+ uint8_t codec;
+ uint8_t presets;
+ uint8_t len;
+ uint8_t data[0];
+} __attribute__((packed));
+
+struct audio_preset {
+ uint8_t len;
+ uint8_t data[0];
+} __attribute__((packed));
+
+struct audio_rsp_open {
+ uint8_t id;
+} __attribute__((packed));
diff --git a/android/ipc.c b/android/ipc.c
index 6cdbf60..bb16553 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -301,7 +301,10 @@ void 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(cmd_io);
+ if (service_id == HAL_SERVICE_ID_AUDIO)
+ sk = g_io_channel_unix_get_fd(audio_io);
+ else
+ sk = g_io_channel_unix_get_fd(cmd_io);

if (status == HAL_STATUS_SUCCESS) {
ipc_send(sk, service_id, opcode, 0, NULL, -1);
--
1.8.4.2


2013-12-30 12:34:13

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [RFC BlueZ 7/9] android: Add stream resume command/response struct

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 2dba482..284d44d 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -382,6 +382,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");
+
+ ipc_send_rsp(HAL_SERVICE_ID_AUDIO, 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) },
@@ -391,6 +399,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 2816f6f..fe433d1 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -605,3 +605,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