2014-01-08 13:37:08

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 1/2] android/audio: Add wrapper stuct for audio structures

This patch add wrapping struct for audio_hw_dev and audio_stream_out.
We will need this to keep some more addition info related to a2dp stream
and also hal IPC.

---
android/hal-audio.c | 109 +++++++++++++++++++++++++++++++---------------------
1 file changed, 65 insertions(+), 44 deletions(-)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 7f4a3f2..bb68648 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -25,6 +25,15 @@

#include "hal-log.h"

+struct a2dp_stream_out {
+ struct audio_stream_out stream;
+};
+
+struct a2dp_audio_dev {
+ struct audio_hw_device dev;
+ struct a2dp_stream_out *stream_out;
+};
+
static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
size_t bytes)
{
@@ -230,32 +239,37 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
struct audio_stream_out **stream_out)

{
- struct audio_stream_out *out;
+ struct a2dp_audio_dev *a2dp_dev = (struct a2dp_audio_dev *)dev;
+ struct a2dp_stream_out *a2dp_out;

- out = calloc(1, sizeof(struct audio_stream_out));
- if (!out)
+ a2dp_out = calloc(1, sizeof(struct a2dp_stream_out));
+ if (!a2dp_out)
return -ENOMEM;

DBG("");

- out->common.get_sample_rate = out_get_sample_rate;
- out->common.set_sample_rate = out_set_sample_rate;
- out->common.get_buffer_size = out_get_buffer_size;
- out->common.get_channels = out_get_channels;
- out->common.get_format = out_get_format;
- out->common.set_format = out_set_format;
- out->common.standby = out_standby;
- out->common.dump = out_dump;
- out->common.set_parameters = out_set_parameters;
- out->common.get_parameters = out_get_parameters;
- out->common.add_audio_effect = out_add_audio_effect;
- out->common.remove_audio_effect = out_remove_audio_effect;
- out->get_latency = out_get_latency;
- out->set_volume = out_set_volume;
- out->write = out_write;
- out->get_render_position = out_get_render_position;
-
- *stream_out = out;
+ a2dp_out->stream.common.get_sample_rate = out_get_sample_rate;
+ a2dp_out->stream.common.set_sample_rate = out_set_sample_rate;
+ a2dp_out->stream.common.get_buffer_size = out_get_buffer_size;
+ a2dp_out->stream.common.get_channels = out_get_channels;
+ a2dp_out->stream.common.get_format = out_get_format;
+ a2dp_out->stream.common.set_format = out_set_format;
+ a2dp_out->stream.common.standby = out_standby;
+ a2dp_out->stream.common.dump = out_dump;
+ a2dp_out->stream.common.set_parameters = out_set_parameters;
+ a2dp_out->stream.common.get_parameters = out_get_parameters;
+ a2dp_out->stream.common.add_audio_effect = out_add_audio_effect;
+ a2dp_out->stream.common.remove_audio_effect = out_remove_audio_effect;
+ a2dp_out->stream.get_latency = out_get_latency;
+ a2dp_out->stream.set_volume = out_set_volume;
+ a2dp_out->stream.write = out_write;
+ a2dp_out->stream.get_render_position = out_get_render_position;
+
+ /* Note that &a2dp_out->stream pointer is same as a2dp_out. This
+ * results from the structure of a2dp_stream_out struct. We rely on it
+ * later in the code */
+ *stream_out = &a2dp_out->stream;
+ a2dp_dev->stream_out = a2dp_out;

return 0;
}
@@ -264,6 +278,10 @@ static void audio_close_output_stream(struct audio_hw_device *dev,
struct audio_stream_out *stream)
{
DBG("");
+ struct a2dp_audio_dev *a2dp_dev = (struct a2dp_audio_dev *)dev;
+
+ free(stream);
+ a2dp_dev->stream_out = NULL;
}

static int audio_set_parameters(struct audio_hw_device *dev,
@@ -381,7 +399,7 @@ static int audio_close(hw_device_t *device)
static int audio_open(const hw_module_t *module, const char *name,
hw_device_t **device)
{
- struct audio_hw_device *audio;
+ struct a2dp_audio_dev *a2dp_dev;

DBG("");

@@ -391,30 +409,33 @@ static int audio_open(const hw_module_t *module, const char *name,
return -EINVAL;
}

- audio = calloc(1, sizeof(struct audio_hw_device));
- if (!audio)
+ a2dp_dev = calloc(1, sizeof(struct a2dp_audio_dev));
+ if (!a2dp_dev)
return -ENOMEM;

- audio->common.version = AUDIO_DEVICE_API_VERSION_CURRENT;
- audio->common.module = (struct hw_module_t *) module;
- audio->common.close = audio_close;
-
- audio->init_check = audio_init_check;
- audio->set_voice_volume = audio_set_voice_volume;
- audio->set_master_volume = audio_set_master_volume;
- audio->set_mode = audio_set_mode;
- audio->set_mic_mute = audio_set_mic_mute;
- audio->get_mic_mute = audio_get_mic_mute;
- audio->set_parameters = audio_set_parameters;
- audio->get_parameters = audio_get_parameters;
- audio->get_input_buffer_size = audio_get_input_buffer_size;
- audio->open_output_stream = audio_open_output_stream;
- audio->close_output_stream = audio_close_output_stream;
- audio->open_input_stream = audio_open_input_stream;
- audio->close_input_stream = audio_close_input_stream;
- audio->dump = audio_dump;
-
- *device = &audio->common;
+ a2dp_dev->dev.common.version = AUDIO_DEVICE_API_VERSION_CURRENT;
+ a2dp_dev->dev.common.module = (struct hw_module_t *) module;
+ a2dp_dev->dev.common.close = audio_close;
+
+ a2dp_dev->dev.init_check = audio_init_check;
+ a2dp_dev->dev.set_voice_volume = audio_set_voice_volume;
+ a2dp_dev->dev.set_master_volume = audio_set_master_volume;
+ a2dp_dev->dev.set_mode = audio_set_mode;
+ a2dp_dev->dev.set_mic_mute = audio_set_mic_mute;
+ a2dp_dev->dev.get_mic_mute = audio_get_mic_mute;
+ a2dp_dev->dev.set_parameters = audio_set_parameters;
+ a2dp_dev->dev.get_parameters = audio_get_parameters;
+ a2dp_dev->dev.get_input_buffer_size = audio_get_input_buffer_size;
+ a2dp_dev->dev.open_output_stream = audio_open_output_stream;
+ a2dp_dev->dev.close_output_stream = audio_close_output_stream;
+ a2dp_dev->dev.open_input_stream = audio_open_input_stream;
+ a2dp_dev->dev.close_input_stream = audio_close_input_stream;
+ a2dp_dev->dev.dump = audio_dump;
+
+ /* Note that &a2dp_dev->dev.common is the same pointer as a2dp_dev.
+ * This results from the structure of following structs:a2dp_audio_dev,
+ * audio_hw_device. We will rely on this later in the code.*/
+ *device = &a2dp_dev->dev.common;

return 0;
}
--
1.8.4



2014-01-08 14:38:50

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH 1/2] android/audio: Add wrapper stuct for audio structures

Hi Lukasz,

On Wed, Jan 8, 2014 at 3:37 PM, Lukasz Rymanowski
<[email protected]> wrote:
> This patch add wrapping struct for audio_hw_dev and audio_stream_out.
> We will need this to keep some more addition info related to a2dp stream
> and also hal IPC.
>
> ---
> android/hal-audio.c | 109 +++++++++++++++++++++++++++++++---------------------
> 1 file changed, 65 insertions(+), 44 deletions(-)
>
> diff --git a/android/hal-audio.c b/android/hal-audio.c
> index 7f4a3f2..bb68648 100644
> --- a/android/hal-audio.c
> +++ b/android/hal-audio.c
> @@ -25,6 +25,15 @@
>
> #include "hal-log.h"
>
> +struct a2dp_stream_out {
> + struct audio_stream_out stream;
> +};
> +
> +struct a2dp_audio_dev {
> + struct audio_hw_device dev;
> + struct a2dp_stream_out *stream_out;
> +};
> +
> static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
> size_t bytes)
> {
> @@ -230,32 +239,37 @@ static int audio_open_output_stream(struct audio_hw_device *dev,
> struct audio_stream_out **stream_out)
>
> {
> - struct audio_stream_out *out;
> + struct a2dp_audio_dev *a2dp_dev = (struct a2dp_audio_dev *)dev;
> + struct a2dp_stream_out *a2dp_out;
>
> - out = calloc(1, sizeof(struct audio_stream_out));
> - if (!out)
> + a2dp_out = calloc(1, sizeof(struct a2dp_stream_out));
> + if (!a2dp_out)
> return -ENOMEM;
>
> DBG("");
>
> - out->common.get_sample_rate = out_get_sample_rate;
> - out->common.set_sample_rate = out_set_sample_rate;
> - out->common.get_buffer_size = out_get_buffer_size;
> - out->common.get_channels = out_get_channels;
> - out->common.get_format = out_get_format;
> - out->common.set_format = out_set_format;
> - out->common.standby = out_standby;
> - out->common.dump = out_dump;
> - out->common.set_parameters = out_set_parameters;
> - out->common.get_parameters = out_get_parameters;
> - out->common.add_audio_effect = out_add_audio_effect;
> - out->common.remove_audio_effect = out_remove_audio_effect;
> - out->get_latency = out_get_latency;
> - out->set_volume = out_set_volume;
> - out->write = out_write;
> - out->get_render_position = out_get_render_position;
> -
> - *stream_out = out;
> + a2dp_out->stream.common.get_sample_rate = out_get_sample_rate;
> + a2dp_out->stream.common.set_sample_rate = out_set_sample_rate;
> + a2dp_out->stream.common.get_buffer_size = out_get_buffer_size;
> + a2dp_out->stream.common.get_channels = out_get_channels;
> + a2dp_out->stream.common.get_format = out_get_format;
> + a2dp_out->stream.common.set_format = out_set_format;
> + a2dp_out->stream.common.standby = out_standby;
> + a2dp_out->stream.common.dump = out_dump;
> + a2dp_out->stream.common.set_parameters = out_set_parameters;
> + a2dp_out->stream.common.get_parameters = out_get_parameters;
> + a2dp_out->stream.common.add_audio_effect = out_add_audio_effect;
> + a2dp_out->stream.common.remove_audio_effect = out_remove_audio_effect;
> + a2dp_out->stream.get_latency = out_get_latency;
> + a2dp_out->stream.set_volume = out_set_volume;
> + a2dp_out->stream.write = out_write;
> + a2dp_out->stream.get_render_position = out_get_render_position;
> +
> + /* Note that &a2dp_out->stream pointer is same as a2dp_out. This
> + * results from the structure of a2dp_stream_out struct. We rely on it
> + * later in the code */
> + *stream_out = &a2dp_out->stream;
> + a2dp_dev->stream_out = a2dp_out;
>
> return 0;
> }
> @@ -264,6 +278,10 @@ static void audio_close_output_stream(struct audio_hw_device *dev,
> struct audio_stream_out *stream)
> {
> DBG("");
> + struct a2dp_audio_dev *a2dp_dev = (struct a2dp_audio_dev *)dev;
> +
> + free(stream);
> + a2dp_dev->stream_out = NULL;
> }
>
> static int audio_set_parameters(struct audio_hw_device *dev,
> @@ -381,7 +399,7 @@ static int audio_close(hw_device_t *device)
> static int audio_open(const hw_module_t *module, const char *name,
> hw_device_t **device)
> {
> - struct audio_hw_device *audio;
> + struct a2dp_audio_dev *a2dp_dev;
>
> DBG("");
>
> @@ -391,30 +409,33 @@ static int audio_open(const hw_module_t *module, const char *name,
> return -EINVAL;
> }
>
> - audio = calloc(1, sizeof(struct audio_hw_device));
> - if (!audio)
> + a2dp_dev = calloc(1, sizeof(struct a2dp_audio_dev));
> + if (!a2dp_dev)
> return -ENOMEM;
>
> - audio->common.version = AUDIO_DEVICE_API_VERSION_CURRENT;
> - audio->common.module = (struct hw_module_t *) module;
> - audio->common.close = audio_close;
> -
> - audio->init_check = audio_init_check;
> - audio->set_voice_volume = audio_set_voice_volume;
> - audio->set_master_volume = audio_set_master_volume;
> - audio->set_mode = audio_set_mode;
> - audio->set_mic_mute = audio_set_mic_mute;
> - audio->get_mic_mute = audio_get_mic_mute;
> - audio->set_parameters = audio_set_parameters;
> - audio->get_parameters = audio_get_parameters;
> - audio->get_input_buffer_size = audio_get_input_buffer_size;
> - audio->open_output_stream = audio_open_output_stream;
> - audio->close_output_stream = audio_close_output_stream;
> - audio->open_input_stream = audio_open_input_stream;
> - audio->close_input_stream = audio_close_input_stream;
> - audio->dump = audio_dump;
> -
> - *device = &audio->common;
> + a2dp_dev->dev.common.version = AUDIO_DEVICE_API_VERSION_CURRENT;
> + a2dp_dev->dev.common.module = (struct hw_module_t *) module;
> + a2dp_dev->dev.common.close = audio_close;
> +
> + a2dp_dev->dev.init_check = audio_init_check;
> + a2dp_dev->dev.set_voice_volume = audio_set_voice_volume;
> + a2dp_dev->dev.set_master_volume = audio_set_master_volume;
> + a2dp_dev->dev.set_mode = audio_set_mode;
> + a2dp_dev->dev.set_mic_mute = audio_set_mic_mute;
> + a2dp_dev->dev.get_mic_mute = audio_get_mic_mute;
> + a2dp_dev->dev.set_parameters = audio_set_parameters;
> + a2dp_dev->dev.get_parameters = audio_get_parameters;
> + a2dp_dev->dev.get_input_buffer_size = audio_get_input_buffer_size;
> + a2dp_dev->dev.open_output_stream = audio_open_output_stream;
> + a2dp_dev->dev.close_output_stream = audio_close_output_stream;
> + a2dp_dev->dev.open_input_stream = audio_open_input_stream;
> + a2dp_dev->dev.close_input_stream = audio_close_input_stream;
> + a2dp_dev->dev.dump = audio_dump;
> +
> + /* Note that &a2dp_dev->dev.common is the same pointer as a2dp_dev.
> + * This results from the structure of following structs:a2dp_audio_dev,
> + * audio_hw_device. We will rely on this later in the code.*/
> + *device = &a2dp_dev->dev.common;
>
> return 0;
> }
> --
> 1.8.4

Ive pushed this one with some modifications, it doesn't seems
necessary to create a wrapper for audio_stream_out so I prefer to
introduce it later whenever it becomes necessary.


--
Luiz Augusto von Dentz

2014-01-08 13:37:09

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 2/2] android/audio: Add listener thread on the Audio HAL socket

This patch add thread which is reponsible for listen on audio HAL
socket and later open a2dp endpoint(s) and maintain socket.
When bluetooth daemon goes down, HAL audio plugin starts to listen on Audio HAL
socket again.

---
android/Makefile.am | 5 ++-
android/hal-audio.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 129 insertions(+), 2 deletions(-)

diff --git a/android/Makefile.am b/android/Makefile.am
index 8810369..88ffa7f 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -112,7 +112,8 @@ android_android_tester_LDFLAGS = -pthread

noinst_LTLIBRARIES += android/libaudio-internal.la

-android_libaudio_internal_la_SOURCES = android/hal-audio.c \
+android_libaudio_internal_la_SOURCES = androdid/audio-msg.h \
+ android/hal-audio.c \
android/hardware/audio.h \
android/hardware/audio_effect.h \
android/hardware/hardware.h \
@@ -120,6 +121,8 @@ android_libaudio_internal_la_SOURCES = android/hal-audio.c \

android_libaudio_internal_la_CFLAGS = -I$(srcdir)/android

+android_libaudio_internal_la_LDFLAGS = -pthread
+
endif

EXTRA_DIST += android/Android.mk android/hal-ipc-api.txt android/README \
diff --git a/android/hal-audio.c b/android/hal-audio.c
index bb68648..c3d3bf4 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -16,15 +16,28 @@
*/

#include <errno.h>
+#include <pthread.h>
+#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>

#include <hardware/audio.h>
#include <hardware/hardware.h>

+#include "audio-msg.h"
#include "hal-log.h"

+static int audio_sk = -1;
+static bool close_thread;
+
+static pthread_t bt_watcher_th = 0;
+static pthread_mutex_t sk_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t close_mutex = PTHREAD_MUTEX_INITIALIZER;
+
struct a2dp_stream_out {
struct audio_stream_out stream;
};
@@ -391,15 +404,117 @@ static int audio_dump(const audio_hw_device_t *device, int fd)

static int audio_close(hw_device_t *device)
{
+ struct a2dp_audio_dev *a2dp_dev = (struct a2dp_audio_dev *)device;
+
DBG("");
- free(device);
+
+ pthread_mutex_lock(&close_mutex);
+ shutdown(audio_sk, SHUT_RDWR);
+ close_thread = true;
+ pthread_mutex_unlock(&close_mutex);
+
+ (void) pthread_join(bt_watcher_th, NULL);
+
+ free(a2dp_dev);
return 0;
}

+static bool create_audio_ipc(void)
+{
+ struct sockaddr_un addr;
+ int err;
+ int sk;
+
+ DBG("");
+
+ sk = socket(PF_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));
+ goto error;
+ }
+
+ if (listen(sk, 1) < 0) {
+ err = errno;
+ error("Failed to bind socket: %d (%s)", err, strerror(err));
+ goto error;
+ }
+
+ audio_sk = accept(sk, NULL, NULL);
+ if (audio_sk < 0) {
+ err = errno;
+ error("Failed to accept socket: %d (%s)", err, strerror(err));
+ goto error;
+ }
+
+ close(sk);
+ return true;
+
+error:
+ close(sk);
+ return false;
+}
+
+static void *bluetoothd_watcher_thread(void *data)
+{
+ bool done = false;
+ struct a2dp_audio_dev *a2dp_dev = (struct a2dp_audio_dev *)data;
+ struct pollfd pfd;
+
+ DBG("");
+
+ close_thread = false;
+
+ while (!done) {
+ if(!create_audio_ipc()) {
+ error("Failed to create listening socket");
+ continue;
+ }
+
+ DBG("Audio IPC: Connected");
+
+ /* TODO: Register ENDPOINT here */
+
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = audio_sk;
+ pfd.events = POLLHUP | POLLERR | POLLNVAL;
+
+ /* Check if socket is still alive */
+ while (poll(&pfd, 1, -1) < 0 && errno == EINTR);
+
+ if (pfd.revents & (POLLHUP | POLLERR | POLLNVAL)) {
+ info("Audio HAL: Socket closed");
+ audio_sk = -1;
+ }
+
+ /*Check if audio_dev is closed */
+ pthread_mutex_lock(&close_mutex);
+ done = close_thread;
+ pthread_mutex_unlock(&close_mutex);
+ }
+
+ info("Closing bluetooth_watcher thread");
+ pthread_exit(NULL);
+ return NULL;
+}
+
static int audio_open(const hw_module_t *module, const char *name,
hw_device_t **device)
{
struct a2dp_audio_dev *a2dp_dev;
+ int err;

DBG("");

@@ -437,6 +552,15 @@ static int audio_open(const hw_module_t *module, const char *name,
* audio_hw_device. We will rely on this later in the code.*/
*device = &a2dp_dev->dev.common;

+ err = pthread_create(&bt_watcher_th, NULL, bluetoothd_watcher_thread,
+ NULL);
+ if (err < 0) {
+ bt_watcher_th = 0;
+ error("Failed to start bluetoothd watcher thread: %d (%s)",
+ -err, strerror(-err));
+ return (-err);
+ }
+
return 0;
}

--
1.8.4