diff --git a/android/client/if-audio.c b/android/client/if-audio.c
index 4c1efce..cd0a851 100644
--- a/android/client/if-audio.c
+++ b/android/client/if-audio.c
#include "if-main.h"
#include "../hal-utils.h"
+#include "pthread.h"
+#include "unistd.h"
audio_hw_device_t *if_audio = NULL;
struct audio_stream_out *stream_out = NULL;
static size_t buffer_size = 0;
+static pthread_t play_thread = 0;
+static pthread_mutex_t outstream_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t state_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+enum state {
+ STATE_STOPPED,
+ STATE_STOPPING,
+ STATE_PLAYING,
+ STATE_SUSPENDED,
+ STATE_MAX
+};
+
+static int current_state = STATE_STOPPED;
static void init_p(int argc, const char **argv)
{
if_audio = device;
}
+static void playthread_cleanup(void *arg)
+{
+ pthread_mutex_lock(&state_mutex);
+ current_state = STATE_STOPPED;
+ pthread_mutex_unlock(&state_mutex);
+
+ haltest_info("Done playing.\n");
+}
+
+static int feed_from_file(short *buffer, void *data)
+{
+ FILE *in = data;
+ return fread(buffer, buffer_size, 1, in);
+}
+
+static void *playback_thread(void *data)
+{
+ int (*filbuff_cb) (short*, void*);
+ short buffer[buffer_size / sizeof(short)];
+ size_t len = 0;
+ size_t w_len = 0;
+ FILE *in = data;
+ void *cb_data = NULL;
+
+ pthread_cleanup_push(playthread_cleanup, NULL);
+
+ /* Use file or fall back to generator */
+ if (in) {
+ filbuff_cb = feed_from_file;
+ cb_data = in;
+ } else {
+ /* TODO: Use generator */
+ goto end;
+ }
+
+ pthread_mutex_lock(&state_mutex);
+ current_state = STATE_PLAYING;
+ pthread_mutex_unlock(&state_mutex);
+
+ do {
+ pthread_mutex_lock(&state_mutex);
+ if (current_state == STATE_STOPPING) {
+ pthread_mutex_unlock(&state_mutex);
+ break;
+ }
+ pthread_mutex_unlock(&state_mutex);
+
+ len = filbuff_cb(buffer, cb_data);
+
+ pthread_mutex_lock(&outstream_mutex);
+ if (!stream_out) {
+ pthread_mutex_unlock(&outstream_mutex);
+ break;
+ }
+
+ w_len = stream_out->write(stream_out, buffer, buffer_size);
+ pthread_mutex_unlock(&outstream_mutex);
+ } while (len && w_len);
+
+ if (in) {
+ fclose(in);
+ in = NULL;
+ }
+end:
+ pthread_cleanup_pop(1);
+ return NULL;
+}
+
+static void play_p(int argc, const char **argv)
+{
+ const char *fname = NULL;
+ FILE *in = NULL;
+
+ RETURN_IF_NULL(if_audio);
+ RETURN_IF_NULL(stream_out);
+
+ if (argc < 3) {
+ haltest_error("Invalid audio file path.\n");
+ } else {
+ fname = argv[2];
+ in = fopen(fname, "r");
+
+ if (in == NULL) {
+ haltest_error("Cannot open file: %s\n", fname);
+ return;
+ }
+ haltest_info("Playing file: %s\n", fname);
+ }
+
+ if (buffer_size == 0) {
+ haltest_error("Invalid buffer size. Was stream_out opened?\n");
+ return;
+ }
+
+ pthread_mutex_lock(&state_mutex);
+ if (current_state != STATE_STOPPED) {
+ haltest_error("Already playing or stream suspended!\n");
+ pthread_mutex_unlock(&state_mutex);
+ return;
+ }
+ pthread_mutex_unlock(&state_mutex);
+
+ if (pthread_create(&play_thread, NULL, playback_thread, in) != 0)
+ haltest_error("Cannot create playback thread!\n");
+}
+
+static void stop_p(int argc, const char **argv)
+{
+ pthread_mutex_lock(&state_mutex);
+ if (current_state == STATE_STOPPED || current_state == STATE_STOPPING) {
+ pthread_mutex_unlock(&state_mutex);
+ return;
+ }
+
+ current_state = STATE_STOPPING;
+ pthread_mutex_unlock(&state_mutex);
+
+ pthread_mutex_lock(&outstream_mutex);
+ stream_out->common.standby(&stream_out->common);
+ pthread_mutex_unlock(&outstream_mutex);
+}
+
static void open_output_stream_p(int argc, const char **argv)
{
int err;
RETURN_IF_NULL(if_audio);
+ pthread_mutex_lock(&state_mutex);
+ if (current_state == STATE_PLAYING) {
+ haltest_error("Already playing!\n");
+ pthread_mutex_unlock(&state_mutex);
+ return;
+ }
+ pthread_mutex_unlock(&state_mutex);
+
err = if_audio->open_output_stream(if_audio,
0,
AUDIO_DEVICE_OUT_ALL_A2DP,
RETURN_IF_NULL(if_audio);
RETURN_IF_NULL(stream_out);
+ stop_p(argc, argv);
+
+ haltest_info("Waiting for playback thread...\n");
+ pthread_join(play_thread, NULL);
+
if_audio->close_output_stream(if_audio, stream_out);
+
+ stream_out = NULL;
+ buffer_size = 0;
}
static void cleanup_p(int argc, const char **argv)
RETURN_IF_NULL(if_audio);
+ pthread_mutex_lock(&state_mutex);
+ if (current_state != STATE_STOPPED) {
+ pthread_mutex_unlock(&state_mutex);
+ close_output_stream_p(0, NULL);
+ } else {
+ pthread_mutex_unlock(&state_mutex);
+ }
+
err = audio_hw_device_close(if_audio);
if (err < 0) {
haltest_error("audio_hw_device_close returned %d\n", err);
STD_METHOD(cleanup),
STD_METHOD(open_output_stream),
STD_METHOD(close_output_stream),
+ STD_METHODH(play, "<path to pcm file>"),
+ STD_METHOD(stop),
END_METHOD
};