qahw: test: Add support for playback over BT
Add changes to open and read data from proxy port if
the device is BT and write to a file.
Change-Id: I2057e8801d8ef5e930ed9b24b8647db78801882a
diff --git a/qahw_api/test/qahw_multi_record_test.c b/qahw_api/test/qahw_multi_record_test.c
index 07dede7..42f7df0 100644
--- a/qahw_api/test/qahw_multi_record_test.c
+++ b/qahw_api/test/qahw_multi_record_test.c
@@ -213,6 +213,7 @@
}
printf("closing input");
+ fclose(fd);
// Close output stream and device.
rc = qahw_in_standby(in_handle);
diff --git a/qahw_api/test/qahw_playback_test.c b/qahw_api/test/qahw_playback_test.c
index ddfb31c..d9288e2 100644
--- a/qahw_api/test/qahw_playback_test.c
+++ b/qahw_api/test/qahw_playback_test.c
@@ -28,9 +28,53 @@
#include "qahw_defs.h"
#define nullptr NULL
+
+#define AFE_PROXY_SAMPLING_RATE 48000
+#define AFE_PROXY_CHANNEL_COUNT 2
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate;
+ uint16_t block_align;
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+
+struct audio_config_params {
+ qahw_module_handle_t *qahw_mod_handle;
+ audio_io_handle_t handle;
+ audio_devices_t input_device;
+ audio_config_t config;
+ audio_input_flags_t flags;
+ const char* kStreamName ;
+ audio_source_t kInputSource;
+ char *file_name;
+ volatile bool thread_exit;
+};
+
+struct proxy_data {
+ struct audio_config_params acp;
+ struct wav_header hdr;
+};
FILE * log_file = NULL;
const char *log_filename = NULL;
float vol_level = 0.01;
+pthread_t proxy_thread;
enum {
FILE_WAV = 1,
@@ -148,6 +192,76 @@
return 0;
}
+void *proxy_read (void* data)
+{
+ struct proxy_data* params = (struct proxy_data*) data;
+ qahw_module_handle_t *qahw_mod_handle = params->acp.qahw_mod_handle;
+ qahw_in_buffer_t in_buf;
+ char *buffer;
+ int rc = 0;
+ int bytes_to_read, bytes_written = 0;
+ FILE *fp = NULL;
+ qahw_stream_handle_t* in_handle = nullptr;
+
+ rc = qahw_open_input_stream(qahw_mod_handle, params->acp.handle,
+ params->acp.input_device, ¶ms->acp.config, &in_handle,
+ params->acp.flags, params->acp.kStreamName, params->acp.kInputSource);
+ if (rc) {
+ fprintf(log_file, "Could not open input stream %d \n",rc);
+ fprintf(stderr, "Could not open input stream %d \n",rc);
+ pthread_exit(0);
+ }
+
+ if (in_handle != NULL) {
+ bytes_to_read = qahw_in_get_buffer_size(in_handle);
+ buffer = (char *) calloc(1, bytes_to_read);
+ if (buffer == NULL) {
+ fprintf(log_file, "calloc failed!!\n");
+ fprintf(stderr, "calloc failed!!\n");
+ pthread_exit(0);
+ }
+
+ if ((fp = fopen(params->acp.file_name,"w"))== NULL) {
+ fprintf(log_file, "Cannot open file to dump proxy data\n");
+ fprintf(stderr, "Cannot open file to dump proxy data\n");
+ pthread_exit(0);
+ }
+ else {
+ params->hdr.num_channels = audio_channel_count_from_in_mask(params->acp.config.channel_mask);
+ params->hdr.sample_rate = params->acp.config.sample_rate;
+ params->hdr.byte_rate = params->hdr.sample_rate * params->hdr.num_channels * 2;
+ params->hdr.block_align = params->hdr.num_channels * 2;
+ params->hdr.bits_per_sample = 16;
+ fwrite(¶ms->hdr, 1, sizeof(params->hdr), fp);
+ }
+ memset(&in_buf,0, sizeof(qahw_in_buffer_t));
+ in_buf.buffer = buffer;
+ in_buf.bytes = bytes_to_read;
+
+ while (!(params->acp.thread_exit)) {
+ rc = qahw_in_read(in_handle, &in_buf);
+ if (rc > 0) {
+ bytes_written += fwrite((char *)(in_buf.buffer), sizeof(char), (int)in_buf.bytes, fp);
+ }
+ }
+ params->hdr.data_sz = bytes_written;
+ params->hdr.riff_sz = bytes_written + 36; //sizeof(hdr) - sizeof(riff_id) - sizeof(riff_sz)
+ fseek(fp, 0L , SEEK_SET);
+ fwrite(¶ms->hdr, 1, sizeof(params->hdr), fp);
+ fclose(fp);
+ rc = qahw_in_standby(in_handle);
+ if (rc) {
+ fprintf(log_file, "in standby failed %d \n", rc);
+ fprintf(stderr, "in standby failed %d \n", rc);
+ }
+ rc = qahw_close_input_stream(in_handle);
+ if (rc) {
+ fprintf(log_file, "could not close input stream %d \n", rc);
+ fprintf(stderr, "could not close input stream %d \n", rc);
+ }
+ fprintf(log_file, "pcm data saved to file %s", params->acp.file_name);
+ }
+}
int write_to_hal(qahw_stream_handle_t* out_handle, char *data,
size_t bytes)
@@ -221,7 +335,7 @@
fprintf(log_file, "fread from file %ld\n", bytes_read);
if (bytes_read <= 0) {
if (feof(in_file)) {
- fprintf(log_file, "End of file");
+ fprintf(log_file, "End of file\n");
if (is_offload) {
pthread_mutex_lock(&drain_lock);
if (is_offload) {
@@ -331,13 +445,18 @@
printf(" 1: LC 2: HE_V1 3: HE_V2\n\n");
printf(" -k --kvpairs <values> - Metadata information of clip\n");
printf(" See Example for more info\n\n");
- printf(" -l --log-file <FILEPATH> - File path for debug msg, to print\n");
+ printf(" -l --log-file <ABSOLUTE FILEPATH> - File path for debug msg, to print\n");
printf(" on console use stdout or 1 \n\n");
+ printf(" -f --pcm-dump <ABSOLUTE FILEPATH> - File path to save pcm data from proxy\n");
printf(" \n Examples \n");
printf(" hal_play_test /etc/Anukoledenadu.wav -> plays Wav stream with default params\n\n");
printf(" hal_play_test /etc/MateRani.mp3 -t 2 -d 2 -v 0.01 -r 44100 -c 2 \n");
printf(" -> plays MP3 stream(-t = 2) on speaker device(-d = 2)\n");
printf(" -> 2 channels and 44100 sample rate\n\n");
+ printf(" hal_play_test /etc/v1-CBR-32kHz-stereo-40kbps.mp3 -t 2 -d 128 -v 0.01 -r 32000 -c 2 -f /data/proxy_dump.wav\n");
+ printf(" -> plays MP3 stream(-t = 2) on BT device(-d = 128)\n");
+ printf(" -> 2 channels and 32000 sample rate\n");
+ printf(" -> saves pcm data to file at /data/proxy_dump.wav\n\n");
printf(" hal_play_test /etc/AACLC-71-48000Hz-384000bps.aac -t 4 -d 2 -v 0.05 -r 48000 -c 2 -a 1 \n");
printf(" -> plays AAC-ADTS stream(-t = 4) on speaker device(-d = 2)\n");
printf(" -> AAC format type is LC(-a = 1)\n");
@@ -380,6 +499,7 @@
int rc = 0;
char *kvpair_values = NULL;
char kvpair[1000] = {0};
+ struct proxy_data proxy_params;
/*
* Default values
@@ -391,6 +511,7 @@
aac_format_type_t format_type = AAC_LC;
log_file = stdout;
audio_devices_t output_device = AUDIO_DEVICE_OUT_SPEAKER;
+ proxy_params.acp.file_name = "/data/pcm_dump.wav";
struct option long_options[] = {
/* These options set a flag. */
@@ -408,9 +529,22 @@
int opt = 0;
int option_index = 0;
+ proxy_params.hdr.riff_id = ID_RIFF;
+ proxy_params.hdr.riff_sz = 0;
+ proxy_params.hdr.riff_fmt = ID_WAVE;
+ proxy_params.hdr.fmt_id = ID_FMT;
+ proxy_params.hdr.fmt_sz = 16;
+ proxy_params.hdr.audio_format = FORMAT_PCM;
+ proxy_params.hdr.num_channels = channels;
+ proxy_params.hdr.sample_rate = sample_rate;
+ proxy_params.hdr.byte_rate = proxy_params.hdr.sample_rate * proxy_params.hdr.num_channels * 2;
+ proxy_params.hdr.block_align = proxy_params.hdr.num_channels * 2;
+ proxy_params.hdr.bits_per_sample = 16;
+ proxy_params.hdr.data_id = ID_DATA;
+ proxy_params.hdr.data_sz = 0;
while ((opt = getopt_long(argc,
argv,
- "-r:c:d:v:l::t:a:k:h",
+ "-r:c:d:v:l:t:a:k:f:h",
long_options,
&option_index)) != -1) {
switch (opt) {
@@ -449,6 +583,9 @@
case 'k':
kvpair_values = optarg;
break;
+ case 'f':
+ proxy_params.acp.file_name = optarg;
+ break;
case 'h':
usage();
return 0;
@@ -478,6 +615,8 @@
fprintf(stdout, "Output Device:%d\n", output_device);
fprintf(stdout, "Format Type:%d\n", format_type);
fprintf(stdout, "kvpair values:%s\n", kvpair_values);
+ if (output_device & AUDIO_DEVICE_OUT_ALL_A2DP)
+ fprintf(stdout, "Saving pcm data to file: %s\n", proxy_params.acp.file_name);
fprintf(stdout, "Starting audio hal tests.\n");
@@ -574,6 +713,9 @@
, output_device, config.offload_info.sample_rate);
const char* stream_name = "output_stream";
+ if (output_device & AUDIO_DEVICE_OUT_ALL_A2DP) {
+ output_device = AUDIO_DEVICE_OUT_PROXY;
+ }
fprintf(log_file, "calling open_out_put_stream:\n");
rc = qahw_open_output_stream(qahw_mod_handle,
handle,
@@ -606,12 +748,36 @@
break;
}
+ if (output_device & AUDIO_DEVICE_OUT_PROXY) {
+ proxy_params.acp.qahw_mod_handle = qahw_mod_handle;
+ proxy_params.acp.handle = 0x998;
+ proxy_params.acp.input_device = AUDIO_DEVICE_IN_PROXY;
+ proxy_params.acp.flags = AUDIO_INPUT_FLAG_NONE;
+ proxy_params.acp.config.channel_mask = audio_channel_in_mask_from_count(AFE_PROXY_CHANNEL_COUNT);
+ proxy_params.acp.config.sample_rate = AFE_PROXY_SAMPLING_RATE;
+ proxy_params.acp.config.format = AUDIO_FORMAT_PCM_16_BIT;
+ proxy_params.acp.kStreamName = "input_stream";
+ proxy_params.acp.kInputSource = AUDIO_SOURCE_UNPROCESSED;
+ proxy_params.acp.thread_exit = false;
+ fprintf(log_file, "create thread to read data from proxy \n");
+ pthread_create(&proxy_thread, NULL, proxy_read, (void *)&proxy_params);
+ }
play_file(out_handle,
file_stream,
(flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
+ /*
+ * DSP gives drain ack for last buffer which will close proxy thread before
+ * app reads last buffer. So add sleep before exiting proxy thread to read
+ * last buffer of data. This is not a calculated value.
+ */
+ usleep(500000);
+ proxy_params.acp.thread_exit = true;
+ fprintf(log_file, "wait for thread exit\n");
+
EXIT:
+ pthread_join(proxy_thread, NULL);
if (out_handle != nullptr) {
rc = qahw_out_standby(out_handle);
if (rc) {