Re: [PATCHv4 07/12] android/haltest: Add testinng for audio SCO HAL

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Andrei,

On Thu, May 8, 2014 at 3:25 PM, Andrei Emeltchenko
<Andrei.Emeltchenko.news@xxxxxxxxx> wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@xxxxxxxxx>
>
> Adds testing support for audio-sco HAL.
> ---
>  android/Android.mk            |   1 +
>  android/Makefile.am           |   1 +
>  android/client/haltest.c      |   3 +
>  android/client/if-audio-sco.c | 520 ++++++++++++++++++++++++++++++++++++++++++
>  android/client/if-main.h      |   1 +
>  5 files changed, 526 insertions(+)
>  create mode 100644 android/client/if-audio-sco.c
>
> diff --git a/android/Android.mk b/android/Android.mk
> index 942c7ba..c453f91 100644
> --- a/android/Android.mk
> +++ b/android/Android.mk
> @@ -149,6 +149,7 @@ LOCAL_SRC_FILES := \
>         bluez/android/client/history.c \
>         bluez/android/client/tabcompletion.c \
>         bluez/android/client/if-audio.c \
> +       bluez/android/client/if-audio-sco.c \
>         bluez/android/client/if-av.c \
>         bluez/android/client/if-rc.c \
>         bluez/android/client/if-bt.c \
> diff --git a/android/Makefile.am b/android/Makefile.am
> index 990ce6b..5113d71 100644
> --- a/android/Makefile.am
> +++ b/android/Makefile.am
> @@ -109,6 +109,7 @@ android_haltest_SOURCES = android/client/haltest.c \
>                                 android/client/if-hl.c \
>                                 android/client/if-sock.c \
>                                 android/client/if-audio.c \
> +                               android/client/if-audio-sco.c \
>                                 android/hardware/hardware.c \
>                                 android/hal-utils.h android/hal-utils.c
>
> diff --git a/android/client/haltest.c b/android/client/haltest.c
> index 5d05b75..0871dd7 100644
> --- a/android/client/haltest.c
> +++ b/android/client/haltest.c
> @@ -32,6 +32,7 @@
>
>  const struct interface *interfaces[] = {
>         &audio_if,
> +       &sco_if,
>         &bluetooth_if,
>         &av_if,
>         &rc_if,
> @@ -394,10 +395,12 @@ static void init(void)
>         const struct method *m;
>         const char *argv[4];
>         char init_audio[] = "audio init";
> +       char init_audio_sco[] = "audio-sco init";
>         char init_bt[] = "bluetooth init";
>         uint32_t i;
>
>         process_line(init_audio);
> +       process_line(init_audio_sco);
>         process_line(init_bt);
>
>         m = get_interface_method("bluetooth", "get_profile_interface");
> diff --git a/android/client/if-audio-sco.c b/android/client/if-audio-sco.c
> new file mode 100644
> index 0000000..24e07cd
> --- /dev/null
> +++ b/android/client/if-audio-sco.c
> @@ -0,0 +1,520 @@
> +/*
> + * Copyright (C) 2014 Intel Corporation
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *      http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + *
> + */
> +
> +#include "if-main.h"
> +#include "../hal-utils.h"
> +#include "pthread.h"
> +#include "unistd.h"
> +#include <math.h>
> +
> +audio_hw_device_t *if_audio_sco = NULL;
> +static 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
> +};
> +
> +SINTMAP(audio_channel_mask_t, -1, "(AUDIO_CHANNEL_INVALID)")
> +       DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
> +       DELEMENT(AUDIO_CHANNEL_OUT_FRONT_RIGHT),
> +       DELEMENT(AUDIO_CHANNEL_OUT_FRONT_CENTER),
> +       DELEMENT(AUDIO_CHANNEL_OUT_LOW_FREQUENCY),
> +       DELEMENT(AUDIO_CHANNEL_OUT_BACK_LEFT),
> +       DELEMENT(AUDIO_CHANNEL_OUT_BACK_RIGHT),
> +       DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER),
> +       DELEMENT(AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER),
> +       DELEMENT(AUDIO_CHANNEL_OUT_BACK_CENTER),
> +       DELEMENT(AUDIO_CHANNEL_OUT_SIDE_LEFT),
> +       DELEMENT(AUDIO_CHANNEL_OUT_SIDE_RIGHT),
> +       DELEMENT(AUDIO_CHANNEL_OUT_TOP_CENTER),
> +       DELEMENT(AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT),
> +       DELEMENT(AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER),
> +       DELEMENT(AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT),
> +       DELEMENT(AUDIO_CHANNEL_OUT_TOP_BACK_LEFT),
> +       DELEMENT(AUDIO_CHANNEL_OUT_TOP_BACK_CENTER),
> +       DELEMENT(AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT),
> +       DELEMENT(AUDIO_CHANNEL_OUT_MONO),
> +       DELEMENT(AUDIO_CHANNEL_OUT_STEREO),
> +       DELEMENT(AUDIO_CHANNEL_OUT_QUAD),
> +       DELEMENT(AUDIO_CHANNEL_OUT_SURROUND),
> +       DELEMENT(AUDIO_CHANNEL_OUT_5POINT1),
> +       DELEMENT(AUDIO_CHANNEL_OUT_7POINT1),
> +       DELEMENT(AUDIO_CHANNEL_OUT_ALL),
> +       DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
> +       DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
> +       DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
> +       DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
> +       DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
> +ENDMAP
> +
> +SINTMAP(audio_format_t, -1, "(AUDIO_FORMAT_INVALID)")
> +       DELEMENT(AUDIO_FORMAT_DEFAULT),
> +       DELEMENT(AUDIO_FORMAT_PCM),
> +       DELEMENT(AUDIO_FORMAT_MP3),
> +       DELEMENT(AUDIO_FORMAT_AMR_NB),
> +       DELEMENT(AUDIO_FORMAT_AMR_WB),
> +       DELEMENT(AUDIO_FORMAT_AAC),
> +       DELEMENT(AUDIO_FORMAT_HE_AAC_V1),
> +       DELEMENT(AUDIO_FORMAT_HE_AAC_V2),
> +       DELEMENT(AUDIO_FORMAT_VORBIS),
> +       DELEMENT(AUDIO_FORMAT_MAIN_MASK),
> +       DELEMENT(AUDIO_FORMAT_SUB_MASK),
> +       DELEMENT(AUDIO_FORMAT_PCM_16_BIT),
> +       DELEMENT(AUDIO_FORMAT_PCM_8_BIT),
> +       DELEMENT(AUDIO_FORMAT_PCM_32_BIT),
> +       DELEMENT(AUDIO_FORMAT_PCM_8_24_BIT),
> +ENDMAP
> +
> +static int current_state = STATE_STOPPED;
> +
> +#define SAMPLERATE 44100
> +static short sample[SAMPLERATE];
> +static uint16_t sample_pos;
> +
> +static void init_p(int argc, const char **argv)
> +{
> +       int err;
> +       const hw_module_t *module;
> +       audio_hw_device_t *device;
> +
> +       err = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, "hsp", &module);
> +       if (err) {
> +               haltest_error("hw_get_module_by_class returned %d\n", err);
> +               return;
> +       }
> +
> +       err = audio_hw_device_open(module, &device);
> +       if (err) {
> +               haltest_error("audio_hw_device_open returned %d\n", err);
> +               return;
> +       }
> +
> +       if_audio_sco = device;
> +}
> +
> +static int feed_from_file(short *buffer, void *data)
> +{
> +       FILE *in = data;
> +       return fread(buffer, buffer_size, 1, in);
> +}
> +
> +static int feed_from_generator(short *buffer, void *data)
> +{
> +       size_t i = 0;
> +       float volume = 0.5;
> +       float *freq = data;
> +       float f = 1;
> +
> +       if (freq)
> +               f = *freq;
> +
> +       /* buffer_size is in bytes but we are using buffer of shorts (2 bytes)*/
> +       for (i = 0; i < buffer_size / sizeof(*buffer) - 1;) {
> +               if (sample_pos >= SAMPLERATE)
> +                       sample_pos = sample_pos % SAMPLERATE;
> +
> +               /* Use the same sample for both channels */
> +               buffer[i++] = sample[sample_pos] * volume;
> +               buffer[i++] = sample[sample_pos] * volume;
> +
> +               sample_pos += f;
> +       }
> +
> +       return buffer_size;
> +}
> +
> +static void prepare_sample(void)
> +{
> +       int x;
> +       double s;
> +
> +       haltest_info("Preparing audio sample...\n");
> +
> +       for (x = 0; x < SAMPLERATE; x++) {
> +               /* prepare sinusoidal 1Hz sample */
> +               s = (2.0 * 3.14159) * ((double)x / SAMPLERATE);
> +               s = sin(s);
> +
> +               /* remap <-1, 1> to signed 16bit PCM range */
> +               sample[x] = s * 32767;
> +       }
> +
> +       sample_pos = 0;
> +}
> +
> +static void *playback_thread(void *data)
> +{
> +       int (*filbuff_cb) (short*, void*);
> +       short buffer[buffer_size / sizeof(short)];
> +       size_t len = 0;
> +       ssize_t w_len = 0;
> +       FILE *in = data;
> +       void *cb_data = NULL;
> +       float freq = 440.0;
> +
> +       /* Use file or fall back to generator */
> +       if (in) {
> +               filbuff_cb = feed_from_file;
> +               cb_data = in;
> +       } else {
> +               prepare_sample();
> +               filbuff_cb = feed_from_generator;
> +               cb_data = &freq;
> +       }
> +
> +       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) {
> +                       haltest_info("Detected stopping\n");
> +                       pthread_mutex_unlock(&state_mutex);
> +                       break;
> +               } else if (current_state == STATE_SUSPENDED) {
> +                       pthread_mutex_unlock(&state_mutex);
> +                       usleep(500);
> +                       continue;
> +               }
> +
> +               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 > 0);
> +
> +       if (in)
> +               fclose(in);
> +
> +       pthread_mutex_lock(&state_mutex);
> +       current_state = STATE_STOPPED;
> +       pthread_mutex_unlock(&state_mutex);
> +
> +       haltest_info("Done playing.\n");
> +
> +       return NULL;
> +}
> +
> +static void play_p(int argc, const char **argv)
> +{
> +       const char *fname = NULL;
> +       FILE *in = NULL;
> +
> +       RETURN_IF_NULL(if_audio_sco);
> +       RETURN_IF_NULL(stream_out);
> +
> +       if (argc < 3) {
> +               haltest_error("Invalid audio file path.\n");
> +               haltest_info("Using sound generator.\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");
> +               goto fail;
> +       }
> +
> +       pthread_mutex_lock(&state_mutex);
> +       if (current_state != STATE_STOPPED) {
> +               haltest_error("Already playing or stream suspended!\n");
> +               pthread_mutex_unlock(&state_mutex);
> +               goto fail;
> +       }
> +       pthread_mutex_unlock(&state_mutex);
> +
> +       if (pthread_create(&play_thread, NULL, playback_thread, in) != 0) {
> +               haltest_error("Cannot create playback thread!\n");
> +               goto fail;
> +       }
> +
> +       return;
> +fail:
> +       if (in)
> +               fclose(in);
> +}
> +
> +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);
> +
> +       haltest_info("Ended %s\n", __func__);
> +}
> +
> +static void open_output_stream_p(int argc, const char **argv)
> +{
> +       int err;
> +
> +       RETURN_IF_NULL(if_audio_sco);
> +
> +       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_sco->open_output_stream(if_audio_sco,
> +                                               0,
> +                                               AUDIO_DEVICE_OUT_ALL_A2DP,

I suppose this should be AUDIO_DEVICE_OUT_ALL_HSP or whatever it is called.

> +                                               AUDIO_OUTPUT_FLAG_NONE,
> +                                               NULL,
> +                                               &stream_out);
> +       if (err < 0) {
> +               haltest_error("open output stream returned %d\n", err);
> +               return;
> +       }
> +
> +       buffer_size = stream_out->common.get_buffer_size(&stream_out->common);
> +       if (buffer_size == 0)
> +               haltest_error("Invalid buffer size received!\n");
> +       else
> +               haltest_info("Using buffer size: %zu\n", buffer_size);
> +}
> +
> +static void close_output_stream_p(int argc, const char **argv)
> +{
> +       RETURN_IF_NULL(if_audio_sco);
> +       RETURN_IF_NULL(stream_out);
> +
> +       stop_p(argc, argv);
> +
> +       haltest_info("Waiting for playback thread...\n");
> +       pthread_join(play_thread, NULL);
> +
> +       if_audio_sco->close_output_stream(if_audio_sco, stream_out);
> +
> +       stream_out = NULL;
> +       buffer_size = 0;
> +}
> +
> +static void cleanup_p(int argc, const char **argv)
> +{
> +       int err;
> +
> +       RETURN_IF_NULL(if_audio_sco);
> +
> +       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_sco);
> +       if (err < 0) {
> +               haltest_error("audio_hw_device_close returned %d\n", err);
> +               return;
> +       }
> +
> +       if_audio_sco = NULL;
> +}
> +
> +static void suspend_p(int argc, const char **argv)
> +{
> +       RETURN_IF_NULL(if_audio_sco);
> +       RETURN_IF_NULL(stream_out);
> +
> +       pthread_mutex_lock(&state_mutex);
> +       if (current_state != STATE_PLAYING) {
> +               pthread_mutex_unlock(&state_mutex);
> +               return;
> +       }
> +       current_state = STATE_SUSPENDED;
> +       pthread_mutex_unlock(&state_mutex);
> +
> +       pthread_mutex_lock(&outstream_mutex);
> +       stream_out->common.standby(&stream_out->common);
> +       pthread_mutex_unlock(&outstream_mutex);
> +}
> +
> +static void resume_p(int argc, const char **argv)
> +{
> +       RETURN_IF_NULL(if_audio_sco);
> +       RETURN_IF_NULL(stream_out);
> +
> +       pthread_mutex_lock(&state_mutex);
> +       if (current_state == STATE_SUSPENDED)
> +               current_state = STATE_PLAYING;
> +       pthread_mutex_unlock(&state_mutex);
> +}
> +
> +static void get_latency_p(int argc, const char **argv)
> +{
> +       RETURN_IF_NULL(if_audio_sco);
> +       RETURN_IF_NULL(stream_out);
> +
> +       haltest_info("Output audio stream latency: %d\n",
> +                                       stream_out->get_latency(stream_out));
> +}
> +
> +static void get_buffer_size_p(int argc, const char **argv)
> +{
> +       RETURN_IF_NULL(if_audio_sco);
> +       RETURN_IF_NULL(stream_out);
> +
> +       haltest_info("Current output buffer size: %zu\n",
> +               stream_out->common.get_buffer_size(&stream_out->common));
> +}
> +
> +static void get_channels_p(int argc, const char **argv)
> +{
> +       audio_channel_mask_t channels;
> +
> +       RETURN_IF_NULL(if_audio_sco);
> +       RETURN_IF_NULL(stream_out);
> +
> +       channels = stream_out->common.get_channels(&stream_out->common);
> +
> +       haltest_info("Channels: %s\n", audio_channel_mask_t2str(channels));
> +}
> +
> +static void get_format_p(int argc, const char **argv)
> +{
> +       audio_format_t format;
> +
> +       RETURN_IF_NULL(if_audio_sco);
> +       RETURN_IF_NULL(stream_out);
> +
> +       format = stream_out->common.get_format(&stream_out->common);
> +
> +       haltest_info("Format: %s\n", audio_format_t2str(format));
> +}
> +
> +static void get_sample_rate_p(int argc, const char **argv)
> +{
> +       RETURN_IF_NULL(if_audio_sco);
> +       RETURN_IF_NULL(stream_out);
> +
> +       haltest_info("Current sample rate: %d\n",
> +               stream_out->common.get_sample_rate(&stream_out->common));
> +}
> +
> +static void get_parameters_p(int argc, const char **argv)
> +{
> +       const char *keystr;
> +
> +       RETURN_IF_NULL(if_audio_sco);
> +       RETURN_IF_NULL(stream_out);
> +
> +       if (argc < 3) {
> +               haltest_info("No keys given.\n");
> +               keystr = "";
> +       } else {
> +               keystr = argv[2];
> +       }
> +
> +       haltest_info("Current parameters: %s\n",
> +                       stream_out->common.get_parameters(&stream_out->common,
> +                                                               keystr));
> +}
> +
> +static void set_parameters_p(int argc, const char **argv)
> +{
> +       RETURN_IF_NULL(if_audio_sco);
> +       RETURN_IF_NULL(stream_out);
> +
> +       if (argc < 3) {
> +               haltest_error("No key=value; pairs given.\n");
> +               return;
> +       }
> +
> +       stream_out->common.set_parameters(&stream_out->common, argv[2]);
> +}
> +
> +static void set_sample_rate_p(int argc, const char **argv)
> +{
> +       RETURN_IF_NULL(if_audio_sco);
> +       RETURN_IF_NULL(stream_out);
> +
> +       if (argc < 3)
> +               return;
> +
> +       stream_out->common.set_sample_rate(&stream_out->common, atoi(argv[2]));
> +}
> +
> +static void init_check_p(int argc, const char **argv)
> +{
> +       RETURN_IF_NULL(if_audio_sco);
> +
> +       haltest_info("Init check result: %d\n", if_audio_sco->init_check(if_audio_sco));
> +}
> +
> +static struct method methods[] = {
> +       STD_METHOD(init),
> +       STD_METHOD(cleanup),
> +       STD_METHOD(open_output_stream),
> +       STD_METHOD(close_output_stream),
> +       STD_METHODH(play, "<path to pcm file>"),
> +       STD_METHOD(stop),
> +       STD_METHOD(suspend),
> +       STD_METHOD(resume),
> +       STD_METHOD(get_latency),
> +       STD_METHOD(get_buffer_size),
> +       STD_METHOD(get_channels),
> +       STD_METHOD(get_format),
> +       STD_METHOD(get_sample_rate),
> +       STD_METHODH(get_parameters, "<closing>"),
> +       STD_METHODH(set_parameters, "<closing=value>"),
> +       STD_METHODH(set_sample_rate, "<sample rate>"),
> +       STD_METHOD(init_check),
> +       END_METHOD
> +};
> +
> +const struct interface sco_if = {
> +       .name = "audio-sco",
> +       .methods = methods
> +};
> diff --git a/android/client/if-main.h b/android/client/if-main.h
> index ff6006c..88da0c7 100644
> --- a/android/client/if-main.h
> +++ b/android/client/if-main.h
> @@ -68,6 +68,7 @@ struct interface {
>  };
>
>  extern const struct interface audio_if;
> +extern const struct interface sco_if;
>  extern const struct interface bluetooth_if;
>  extern const struct interface av_if;
>  extern const struct interface rc_if;
> --
> 1.8.3.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Luiz Augusto von Dentz
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux