hal_play_test : multi-stream playback support
changes to run multiple playback streams
Change-Id: Ifefaa0e9c786c35a0bb8f935beea0106e786b084
diff --git a/qahw_api/test/qahw_playback_test.c b/qahw_api/test/qahw_playback_test.c
index 223726d..4a7a382 100644
--- a/qahw_api/test/qahw_playback_test.c
+++ b/qahw_api/test/qahw_playback_test.c
@@ -45,11 +45,47 @@
#define ID_FMT 0x20746d66
#define ID_DATA 0x61746164
+#define KV_PAIR_MAX_LENGTH 1000
+
#define FORMAT_PCM 1
#define WAV_HEADER_LENGTH_MAX 46
-static thread_data_t *ethread_data = NULL;
-static cmd_data_t cmd_data;
+#define MAX_PLAYBACK_STREAMS 2
+#define PRIMARY_STREAM_INDEX 0
+
+static int get_wav_header_length (FILE* file_stream);
+static void init_streams(void);
+
+
+enum {
+ FILE_WAV = 1,
+ FILE_MP3,
+ FILE_AAC,
+ FILE_AAC_ADTS,
+ FILE_FLAC,
+ FILE_ALAC,
+ FILE_VORBIS,
+ FILE_WMA,
+ FILE_AC3,
+ FILE_AAC_LATM,
+ FILE_EAC3,
+ FILE_EAC3_JOC,
+ FILE_DTS,
+ FILE_MP2,
+ FILE_APTX
+};
+
+typedef enum {
+ AAC_LC = 1,
+ AAC_HE_V1,
+ AAC_HE_V2
+} aac_format_type_t;
+
+typedef enum {
+ WMA = 1,
+ WMA_PRO,
+ WMA_LOSSLESS
+} wma_format_type_t;
struct wav_header {
uint32_t riff_id;
@@ -83,46 +119,51 @@
struct audio_config_params acp;
struct wav_header hdr;
};
+
+typedef struct {
+ qahw_module_handle_t *qahw_mod_handle;
+ audio_io_handle_t handle;
+ char* filename;
+ FILE* file_stream;
+ int filetype;
+ int stream_index;
+ audio_devices_t output_device;
+ audio_config_t config;
+ audio_output_flags_t flags;
+ qahw_stream_handle_t* out_handle;
+ int channels;
+ aac_format_type_t aac_fmt_type;
+ wma_format_type_t wma_fmt_type;
+ char *kvpair_values;
+ bool flags_set;
+ int effect_index;
+ thread_func_t ethread_func;
+ thread_data_t *ethread_data;
+ cmd_data_t cmd_data;
+ pthread_cond_t write_cond;
+ pthread_mutex_t write_lock;
+ pthread_cond_t drain_cond;
+ pthread_mutex_t drain_lock;
+}stream_config;
+
+
FILE * log_file = NULL;
volatile bool stop_playback = false;
const char *log_filename = NULL;
float vol_level = 0.01;
+struct proxy_data proxy_params;
+bool proxy_thread_active;
pthread_t proxy_thread;
+pthread_t playback_thread[MAX_PLAYBACK_STREAMS];
+bool thread_active[MAX_PLAYBACK_STREAMS] = { false };
-enum {
- FILE_WAV = 1,
- FILE_MP3,
- FILE_AAC,
- FILE_AAC_ADTS,
- FILE_FLAC,
- FILE_ALAC,
- FILE_VORBIS,
- FILE_WMA,
- FILE_AC3,
- FILE_AAC_LATM,
- FILE_EAC3,
- FILE_EAC3_JOC,
- FILE_DTS,
- FILE_MP2,
- FILE_APTX
-};
+stream_config stream_param[MAX_PLAYBACK_STREAMS];
+bool kpi_mode;
-typedef enum {
- AAC_LC = 1,
- AAC_HE_V1,
- AAC_HE_V2
-} aac_format_type_t;
-
-typedef enum {
- WMA = 1,
- WMA_PRO,
- WMA_LOSSLESS
-} wma_format_type_t;
-
-static pthread_mutex_t write_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t write_cond = PTHREAD_COND_INITIALIZER;
-static pthread_mutex_t drain_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t drain_cond = PTHREAD_COND_INITIALIZER;
+/*
+ * Set to a high number so it doesn't interfere with existing stream handles
+ */
+audio_io_handle_t stream_handle = 0x999;
#define FLAC_KVPAIR "music_offload_avg_bit_rate=%d;" \
"music_offload_flac_max_blk_size=%d;" \
@@ -165,6 +206,44 @@
stop_playback = true;
}
+void usage();
+int measure_kpi_values(qahw_stream_handle_t* out_handle, bool is_offload);
+
+static void init_streams(void)
+{
+ int i = 0;
+ for ( i = 0; i < MAX_PLAYBACK_STREAMS; i++) {
+ memset(&stream_param[i], 0, sizeof(stream_config));
+
+ stream_param[i].qahw_mod_handle = nullptr;
+ stream_param[i].filename = nullptr;
+ stream_param[i].file_stream = nullptr;
+ stream_param[i].filetype = FILE_WAV;
+ stream_param[i].stream_index = i+1;
+ stream_param[i].output_device = AUDIO_DEVICE_OUT_SPEAKER;
+ stream_param[i].flags = AUDIO_OUTPUT_FLAG_NONE;
+ stream_param[i].out_handle = nullptr;
+ stream_param[i].channels = 2;
+ stream_param[i].config.offload_info.sample_rate = 44100;
+ stream_param[i].config.offload_info.bit_width = 16;
+ stream_param[i].aac_fmt_type = AAC_LC;
+ stream_param[i].wma_fmt_type = WMA;
+ stream_param[i].kvpair_values = nullptr;
+ stream_param[i].flags_set = false;
+ stream_param[i].effect_index = -1;
+ stream_param[i].ethread_func = nullptr;
+ stream_param[i].ethread_data = nullptr;
+
+ pthread_mutex_init(&stream_param[i].write_lock, (const pthread_mutexattr_t *)NULL);
+ pthread_cond_init(&stream_param[i].write_cond, (const pthread_condattr_t *) NULL);
+ pthread_mutex_init(&stream_param[i].drain_lock, (const pthread_mutexattr_t *)NULL);
+ pthread_cond_init(&stream_param[i].drain_cond, (const pthread_condattr_t *) NULL);
+
+ stream_param[i].handle = stream_handle;
+ stream_handle--;
+ }
+}
+
void read_kvpair(char *kvpair, char* kvpair_values, int filetype)
{
char *kvpair_type = NULL;
@@ -205,20 +284,28 @@
}
int async_callback(qahw_stream_callback_event_t event, void *param __unused,
- void *cookie __unused)
+ void *cookie)
{
+ if(cookie == NULL) {
+ fprintf(log_file, "Invalid callback handle\n");
+ fprintf(stderr, "Invalid callback handle\n");
+ return 0;
+ }
+
+ stream_config *params = (stream_config*) cookie;
+
switch (event) {
case QAHW_STREAM_CBK_EVENT_WRITE_READY:
- fprintf(log_file, "QAHW_STREAM_CBK_EVENT_DRAIN_READY\n");
- pthread_mutex_lock(&write_lock);
- pthread_cond_signal(&write_cond);
- pthread_mutex_unlock(&write_lock);
+ fprintf(log_file, "stream %d: received event - QAHW_STREAM_CBK_EVENT_WRITE_READY\n", params->stream_index);
+ pthread_mutex_lock(¶ms->write_lock);
+ pthread_cond_signal(¶ms->write_cond);
+ pthread_mutex_unlock(¶ms->write_lock);
break;
case QAHW_STREAM_CBK_EVENT_DRAIN_READY:
- fprintf(log_file, "QAHW_STREAM_CBK_EVENT_DRAIN_READY\n");
- pthread_mutex_lock(&drain_lock);
- pthread_cond_signal(&drain_cond);
- pthread_mutex_unlock(&drain_lock);
+ fprintf(log_file, "stream %d: received event - QAHW_STREAM_CBK_EVENT_DRAIN_READY\n", params->stream_index);
+ pthread_mutex_lock(¶ms->drain_lock);
+ pthread_cond_signal(¶ms->drain_cond);
+ pthread_mutex_unlock(¶ms->drain_lock);
default:
break;
}
@@ -297,89 +384,177 @@
return 0;
}
-int write_to_hal(qahw_stream_handle_t* out_handle, char *data,
- size_t bytes)
+
+/* Entry point function for stream playback
+ * Opens the stream
+ * Reads KV pairs, sets volume, allocates input buffer
+ * Opens proxy and effects threads if enabled
+ * Starts freading the file and writing to HAL
+ * Drains out and close the stream after EOF
+ */
+void *start_stream_playback (void* stream_data)
{
- ssize_t ret;
- pthread_mutex_lock(&write_lock);
- qahw_out_buffer_t out_buf;
+ int rc = 0;
+ stream_config *params = (stream_config*) stream_data;
+ const char* stream_name = "output_stream";
- memset(&out_buf,0, sizeof(qahw_out_buffer_t));
- out_buf.buffer = data;
- out_buf.bytes = bytes;
+ rc = qahw_open_output_stream(params->qahw_mod_handle,
+ params->handle,
+ params->output_device,
+ params->flags,
+ &(params->config),
+ &(params->out_handle),
+ stream_name);
- ret = qahw_out_write(out_handle, &out_buf);
- if (ret < 0 || ret == bytes) {
- fprintf(log_file, "Writing data to hal failed or full write %zd, %zd\n",
- ret, bytes);
- } else if (ret != bytes) {
- fprintf(log_file, "ret %zd, bytes %zd\n", ret, bytes);
- fprintf(log_file, "Waiting for event write ready\n");
- pthread_cond_wait(&write_cond, &write_lock);
- fprintf(log_file, "out of wait for event write ready\n");
+ if (rc) {
+ fprintf(log_file, "stream %d: could not open output stream, error - %d \n", params->stream_index, rc);
+ fprintf(stderr, "stream %d: could not open output stream, error - %d \n", params->stream_index, rc);
+ pthread_exit(0);
}
- pthread_mutex_unlock(&write_lock);
- return ret;
-}
+ fprintf(log_file, "stream %d: open output stream is success, out_handle %p\n", params->stream_index, params->out_handle);
+ if (kpi_mode == true) {
+ measure_kpi_values(params->out_handle, params->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+ rc = qahw_close_output_stream(params->out_handle);
+ if (rc) {
+ fprintf(log_file, "stream %d: could not close output stream %d, error - %d \n", params->stream_index, rc);
+ fprintf(stderr, "stream %d: could not close output stream %d, error - %d \n", params->stream_index, rc);
+ }
+ return;
+ }
-/* Play audio from a WAV file.
- *
- * Parameters:
- * out_stream: A pointer to the output audio stream.
- * in_file: A pointer to a SNDFILE object.
- * config: A pointer to struct that contains audio configuration data.
- *
- * Returns: An int which has a non-negative number on success.
- */
+ switch(params->filetype) {
+ char kvpair[KV_PAIR_MAX_LENGTH] = {0};
+ case FILE_WMA:
+ case FILE_VORBIS:
+ case FILE_ALAC:
+ case FILE_FLAC:
+ fprintf(log_file, "%s:calling setparam for kvpairs\n", __func__);
+ if (!(params->kvpair_values)) {
+ fprintf(log_file, "stream %d: error!!No metadata for the clip\n", params->stream_index);
+ fprintf(stderr, "stream %d: error!!No metadata for the clip\n", params->stream_index);
+ pthread_exit(0);;
+ }
+ read_kvpair(kvpair, params->kvpair_values, params->filetype);
+ rc = qahw_out_set_parameters(params->out_handle, kvpair);
+ if(rc){
+ fprintf(log_file, "stream %d: failed to set kvpairs\n", params->stream_index);
+ fprintf(stderr, "stream %d: failed to set kvpairs\n", params->stream_index);
+ pthread_exit(0);;
+ }
+ fprintf(log_file, "stream %d: kvpairs are set\n", params->stream_index);
+ break;
+ default:
+ break;
+ }
-int play_file(qahw_stream_handle_t* out_handle, FILE* in_file,
- bool is_offload) {
- int rc = 0;
int offset = 0;
+ bool is_offload = params->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
size_t bytes_wanted = 0;
size_t write_length = 0;
size_t bytes_remaining = 0;
size_t bytes_written = 0;
size_t bytes_read = 0;
- char *data = NULL;
+ char *data_ptr = NULL;
bool exit = false;
if (is_offload) {
- fprintf(log_file, "Set callback for offload stream\n");
- qahw_out_set_callback(out_handle, async_callback, NULL);
+ fprintf(log_file, "stream %d: set callback for offload stream for playback usecase\n", params->stream_index);
+ qahw_out_set_callback(params->out_handle, async_callback, params);
}
- rc = qahw_out_set_volume(out_handle, vol_level, vol_level);
- if (rc < 0)
- fprintf(log_file, "unable to set volume");
+ // create effect thread, use thread_data to transfer command
+ if (params->ethread_func &&
+ (params->flags & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_DIRECT))) {
- bytes_wanted = qahw_out_get_buffer_size(out_handle);
- data = (char *) malloc (bytes_wanted);
- if (data == NULL) {
- fprintf(log_file, "calloc failed!!\n");
- return -ENOMEM;
+ fprintf(log_file, "stream %d: effect type:%s\n", params->stream_index, effect_str[params->effect_index]);
+ params->ethread_data = create_effect_thread(params->effect_index, params->ethread_func);
+
+ // create effect command thread
+ params->cmd_data.exit = false;
+ params->cmd_data.fx_data_ptr = &(params->ethread_data);
+ pthread_attr_init(&(params->cmd_data.attr));
+ pthread_attr_setdetachstate(&(params->cmd_data.attr), PTHREAD_CREATE_JOINABLE);
+ rc = pthread_create(&(params->cmd_data.cmd_thread), &(params->cmd_data.attr),
+ &command_thread_func, &(params->cmd_data));
+ if (rc < 0) {
+ fprintf(log_file, "stream %d: could not create effect command thread!\n", params->stream_index);
+ fprintf(stderr, "stream %d: could not create effect command thread!\n", params->stream_index);
+ pthread_exit(0);
+ }
+
+ fprintf(log_file, "stream %d: loading effects\n", params->stream_index);
+ if (params->ethread_data != nullptr) {
+ // load effect module
+ notify_effect_command(params->ethread_data, EFFECT_LOAD_LIB, -1, 0, NULL);
+
+ // get effect desc
+ notify_effect_command(params->ethread_data, EFFECT_GET_DESC, -1, 0, NULL);
+
+ // create effect
+ params->ethread_data->io_handle = params->handle;
+ notify_effect_command(params->ethread_data, EFFECT_CREATE, -1, 0, NULL);
+
+ // broadcast device info
+ notify_effect_command(params->ethread_data, EFFECT_CMD, QAHW_EFFECT_CMD_SET_DEVICE, sizeof(audio_devices_t), &(params->output_device));
+
+ // enable effect
+ notify_effect_command(params->ethread_data, EFFECT_CMD, QAHW_EFFECT_CMD_ENABLE, 0, NULL);
+ }
+ }
+
+ if (params->output_device & AUDIO_DEVICE_OUT_ALL_A2DP) {
+ params->output_device = AUDIO_DEVICE_OUT_PROXY;
+ proxy_params.acp.qahw_mod_handle = params->qahw_mod_handle;
+ proxy_params.acp.handle = stream_handle;
+ stream_handle--;
+ 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, "stream %d: create thread to read data from proxy\n", params->stream_index);
+ rc = pthread_create(&proxy_thread, NULL, proxy_read, (void *)&proxy_params);
+ if (!rc)
+ proxy_thread_active = true;
+ }
+
+ rc = qahw_out_set_volume(params->out_handle, vol_level, vol_level);
+ if (rc < 0) {
+ fprintf(log_file, "stream %d: unable to set volume\n", params->stream_index);
+ fprintf(stderr, "stream %d: unable to set volume\n", params->stream_index);
+ }
+
+ bytes_wanted = qahw_out_get_buffer_size(params->out_handle);
+ data_ptr = (char *) malloc (bytes_wanted);
+ if (data_ptr == NULL) {
+ fprintf(log_file, "stream %d: failed to allocate data buffer\n", params->stream_index);
+ fprintf(stderr, "stream %d: failed to allocate data buffer\n", params->stream_index);
+ pthread_exit(0);
}
while (!exit && !stop_playback) {
if (!bytes_remaining) {
- bytes_read = fread(data, 1, bytes_wanted, in_file);
- fprintf(log_file, "fread from file %zd\n", bytes_read);
+ bytes_read = fread(data_ptr, 1, bytes_wanted, params->file_stream);
+ fprintf(log_file, "\nstream %d: fread from file %zd bytes\n", params->stream_index, bytes_read);
if (bytes_read <= 0) {
- if (feof(in_file)) {
- fprintf(log_file, "End of file\n");
+ if (feof(params->file_stream)) {
+ fprintf(log_file, "stream %d: end of file\n", params->stream_index);
if (is_offload) {
- pthread_mutex_lock(&drain_lock);
- qahw_out_drain(out_handle, QAHW_DRAIN_ALL);
- pthread_cond_wait(&drain_cond, &drain_lock);
- fprintf(log_file, "Out of compress drain\n");
- fprintf(stdout, "Playback completed sucessfully\n");
- pthread_mutex_unlock(&drain_lock);
+ pthread_mutex_lock(¶ms->drain_lock);
+ qahw_out_drain(params->out_handle, QAHW_DRAIN_ALL);
+ pthread_cond_wait(¶ms->drain_cond, ¶ms->drain_lock);
+ fprintf(log_file, "stream %d: out of compress drain\n", params->stream_index);
+ fprintf(log_file, "stream %d: playback completed successfully\n", params->stream_index);
+ pthread_mutex_unlock(¶ms->drain_lock);
}
} else {
- fprintf(log_file, "Error in fread --%d\n", ferror(in_file));
- fprintf(stderr, "Error in fread --%d\n", ferror(in_file));
+ fprintf(log_file, "stream %d: error in fread, error %d\n", params->stream_index, ferror(params->file_stream));
+ fprintf(stderr, "stream %d: error in fread, error %d\n", params->stream_index, ferror(params->file_stream));
}
exit = true;
continue;
@@ -388,15 +563,100 @@
}
offset = write_length - bytes_remaining;
- fprintf(log_file, "bytes_remaining %zd, offset %d, write length %zd\n",
- bytes_remaining, offset, write_length);
- bytes_written = write_to_hal(out_handle, data+offset, bytes_remaining);
+ fprintf(log_file, "stream %d: writing to hal %zd bytes, offset %d, write length %zd\n",
+ params->stream_index, bytes_remaining, offset, write_length);
+ bytes_written = write_to_hal(params->out_handle, data_ptr+offset, bytes_remaining, params);
bytes_remaining -= bytes_written;
- fprintf(log_file, "bytes_written %zd, bytes_remaining %zd\n",
- bytes_written, bytes_remaining);
+ fprintf(log_file, "stream %d: bytes_written %zd, bytes_remaining %zd\n",
+ params->stream_index, bytes_written, bytes_remaining);
}
- return rc;
+ if (params->ethread_data != nullptr) {
+ fprintf(log_file, "stream %d: un-loading effects\n", params->stream_index);
+ // disable effect
+ notify_effect_command(params->ethread_data, EFFECT_CMD, QAHW_EFFECT_CMD_DISABLE, 0, NULL);
+
+ // release effect
+ notify_effect_command(params->ethread_data, EFFECT_RELEASE, -1, 0, NULL);
+
+ // unload effect module
+ notify_effect_command(params->ethread_data, EFFECT_UNLOAD_LIB, -1, 0, NULL);
+
+ // destroy effect thread
+ destroy_effect_thread(params->ethread_data);
+
+ free(params->ethread_data);
+ params->ethread_data = NULL;
+
+ // destory effect command thread
+ params->cmd_data.exit = true;
+ usleep(100000); // give a chance for thread to exit gracefully
+ rc = pthread_cancel(params->cmd_data.cmd_thread);
+ if (rc != 0) {
+ fprintf(log_file, "Fail to cancel thread!\n");
+ fprintf(stderr, "Fail to cancel thread!\n");
+ }
+ rc = pthread_join(params->cmd_data.cmd_thread, NULL);
+ if (rc < 0) {
+ fprintf(log_file, "Fail to join effect command thread!\n");
+ fprintf(stderr, "Fail to join effect command thread!\n");
+ }
+ }
+
+ if (proxy_thread_active) {
+ /*
+ * 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 proxy thread exit\n");
+ pthread_join(proxy_thread, NULL);
+ }
+
+ rc = qahw_out_standby(params->out_handle);
+ if (rc) {
+ fprintf(log_file, "stream %d: out standby failed %d \n", params->stream_index, rc);
+ fprintf(stderr, "stream %d: out standby failed %d \n", params->stream_index, rc);
+ }
+
+ fprintf(log_file, "stream %d: closing output stream\n", params->stream_index);
+ rc = qahw_close_output_stream(params->out_handle);
+ if (rc) {
+ fprintf(log_file, "stream %d: could not close output stream, error - %d \n", params->stream_index, rc);
+ fprintf(stderr, "stream %d: could not close output stream, error - %d \n", params->stream_index, rc);
+ }
+
+ fprintf(log_file, "stream %d: stream closed\n", params->stream_index);
+ return;
+
+}
+
+int write_to_hal(qahw_stream_handle_t* out_handle, char *data, size_t bytes, void *params_ptr)
+{
+ stream_config *stream_params = (stream_config*) params_ptr;
+
+ ssize_t ret;
+ pthread_mutex_lock(&stream_params->write_lock);
+ qahw_out_buffer_t out_buf;
+
+ memset(&out_buf,0, sizeof(qahw_out_buffer_t));
+ out_buf.buffer = data;
+ out_buf.bytes = bytes;
+
+ ret = qahw_out_write(out_handle, &out_buf);
+ if (ret < 0) {
+ fprintf(log_file, "stream %d: writing data to hal failed (ret = %zd)\n", stream_params->stream_index, ret);
+ } else if (ret != bytes) {
+ fprintf(log_file, "stream %d: provided bytes %zd, written bytes %d\n",stream_params->stream_index, bytes, ret);
+ fprintf(log_file, "stream %d: waiting for event write ready\n", stream_params->stream_index);
+ pthread_cond_wait(&stream_params->write_cond, &stream_params->write_lock);
+ fprintf(log_file, "stream %d: out of wait for event write ready\n", stream_params->stream_index);
+ }
+
+ pthread_mutex_unlock(&stream_params->write_lock);
+ return ret;
}
bool is_valid_aac_format_type(aac_format_type_t format_type)
@@ -474,6 +734,106 @@
return aac_format;
}
+static void get_file_format(stream_config *stream_info)
+{
+ int rc = 0;
+
+ if (!(stream_info->flags_set)) {
+ stream_info->flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING;
+ stream_info->flags |= AUDIO_OUTPUT_FLAG_DIRECT;
+ }
+
+ char header[WAV_HEADER_LENGTH_MAX] = {0};
+ int wav_header_len = 0;
+
+ switch (stream_info->filetype) {
+ case FILE_WAV:
+ /*
+ * Read the wave header
+ */
+ if((wav_header_len = get_wav_header_length(stream_info->file_stream)) <= 0) {
+ fprintf(log_file, "wav header length is invalid:%d\n", wav_header_len);
+ exit(1);
+ }
+ fseek(stream_info->file_stream, 0, SEEK_SET);
+ rc = fread (header, wav_header_len , 1, stream_info->file_stream);
+ if (rc != 1) {
+ fprintf(log_file, "Error fread failed\n");
+ fprintf(stderr, "Error fread failed\n");
+ exit(1);
+ }
+ if (strncmp (header, "RIFF", 4) && strncmp (header+8, "WAVE", 4)) {
+ fprintf(log_file, "Not a wave format\n");
+ fprintf(stderr, "Not a wave format\n");
+ exit (1);
+ }
+ memcpy (&stream_info->channels, &header[22], 2);
+ memcpy (&stream_info->config.offload_info.sample_rate, &header[24], 4);
+ memcpy (&stream_info->config.offload_info.bit_width, &header[34], 2);
+ if (stream_info->config.offload_info.bit_width == 32)
+ stream_info->config.offload_info.format = AUDIO_FORMAT_PCM_32_BIT;
+ else if (stream_info->config.offload_info.bit_width == 24)
+ stream_info->config.offload_info.format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+ else
+ stream_info->config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
+ if (!(stream_info->flags_set))
+ stream_info->flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+ break;
+
+ case FILE_MP3:
+ stream_info->config.offload_info.format = AUDIO_FORMAT_MP3;
+ break;
+
+ case FILE_AAC:
+ case FILE_AAC_ADTS:
+ case FILE_AAC_LATM:
+ if (!is_valid_aac_format_type(stream_info->aac_fmt_type)) {
+ fprintf(log_file, "Invalid format type for AAC %d\n", stream_info->aac_fmt_type);
+ fprintf(stderr, "Invalid format type for AAC %d\n", stream_info->aac_fmt_type);
+ return;
+ }
+ stream_info->config.offload_info.format = get_aac_format(stream_info->filetype, stream_info->aac_fmt_type);
+ break;
+ case FILE_FLAC:
+ stream_info->config.offload_info.format = AUDIO_FORMAT_FLAC;
+ break;
+ case FILE_ALAC:
+ stream_info->config.offload_info.format = AUDIO_FORMAT_ALAC;
+ break;
+ case FILE_VORBIS:
+ stream_info->config.offload_info.format = AUDIO_FORMAT_VORBIS;
+ break;
+ case FILE_WMA:
+ if (stream_info->wma_fmt_type == WMA)
+ stream_info->config.offload_info.format = AUDIO_FORMAT_WMA;
+ else
+ stream_info->config.offload_info.format = AUDIO_FORMAT_WMA_PRO;
+ break;
+ case FILE_MP2:
+ stream_info->config.offload_info.format = AUDIO_FORMAT_MP2;
+ break;
+ case FILE_AC3:
+ stream_info->config.offload_info.format = AUDIO_FORMAT_AC3;
+ break;
+ case FILE_EAC3:
+ case FILE_EAC3_JOC:
+ stream_info->config.offload_info.format = AUDIO_FORMAT_E_AC3;
+ break;
+ case FILE_DTS:
+ stream_info->config.offload_info.format = AUDIO_FORMAT_DTS;
+ break;
+ case FILE_APTX:
+ stream_info->config.offload_info.format = AUDIO_FORMAT_APTX;
+ break;
+ default:
+ fprintf(log_file, "Does not support given filetype\n");
+ fprintf(stderr, "Does not support given filetype\n");
+ usage();
+ return;
+ }
+ return;
+}
+
int measure_kpi_values(qahw_stream_handle_t* out_handle, bool is_offload) {
int rc = 0;
int offset = 0;
@@ -487,8 +847,8 @@
uint64_t tcold, tcont, scold = 0, uscold = 0, scont = 0, uscont = 0;
if (is_offload) {
- fprintf(log_file, "Set callback for offload stream\n");
- qahw_out_set_callback(out_handle, async_callback, NULL);
+ fprintf(log_file, "Set callback for offload stream in kpi mesaurement usecase\n");
+ qahw_out_set_callback(out_handle, async_callback, &stream_param[PRIMARY_STREAM_INDEX]);
}
FILE *fd_latency_node = fopen(LATENCY_NODE, "r+");
@@ -496,9 +856,11 @@
ret = fwrite(LATENCY_NODE_INIT_STR, sizeof(LATENCY_NODE_INIT_STR), 1, fd_latency_node);
if (ret<1)
fprintf(log_file, "error(%d) writing to debug node!", ret);
+ fprintf(stderr, "error(%d) writing to debug node!", ret);
fflush(fd_latency_node);
} else {
fprintf(log_file, "debug node(%s) open failed!", LATENCY_NODE);
+ fprintf(stderr, "debug node(%s) open failed!", LATENCY_NODE);
return -1;
}
@@ -506,6 +868,7 @@
data = (char *) calloc (1, bytes_wanted);
if (data == NULL) {
fprintf(log_file, "calloc failed!!\n");
+ fprintf(stderr, "calloc failed!!\n");
return -ENOMEM;
}
@@ -517,6 +880,7 @@
ret = clock_gettime(CLOCK_REALTIME, &ts_cold);
if (ret) {
fprintf(log_file, "error(%d) fetching start time for cold latency", ret);
+ fprintf(stderr, "error(%d) fetching start time for cold latency", ret);
return -1;
}
} else if (count == 16) {
@@ -525,12 +889,13 @@
ret = clock_gettime(CLOCK_REALTIME, &ts_cont);
if (ret) {
fprintf(log_file, "error(%d) fetching start time for continuous latency", ret);
+ fprintf(stderr, "error(%d) fetching start time for continuous latency", ret);
return -1;
}
}
offset = write_length - bytes_remaining;
- bytes_written = write_to_hal(out_handle, data+offset, bytes_remaining);
+ bytes_written = write_to_hal(out_handle, data+offset, bytes_remaining, &stream_param[PRIMARY_STREAM_INDEX]);
bytes_remaining -= bytes_written;
fprintf(log_file, "bytes_written %zd, bytes_remaining %zd\n",
bytes_written, bytes_remaining);
@@ -606,8 +971,10 @@
printf(" file path is not used here as file playback is not done in this mode\n");
printf(" file path and other file specific options would be ignored in this mode.\n\n");
printf(" -e --effect-type <effect type> - Effect used for test\n");
- printf(" 0:bassboost 1:virtualizer 2:equalizer 3:visualizer(NA) 4:reverb 5:audiosphere others:null");
- printf(" -A --bt-addr <bt device addr> - Required to set bt device adress for aptx decoder\n");
+ printf(" 0:bassboost 1:virtualizer 2:equalizer 3:visualizer(NA) 4:reverb 5:audiosphere others:null\n\n");
+ printf(" -A --bt-addr <bt device addr> - Required to set bt device adress for aptx decoder\n\n");
+ printf(" -P - Argument to do multi-stream playback, currently 2 streams are supported to run concurrently\n");
+ printf(" Put -P and mention required attributes for the next stream\n");
printf(" \n Examples \n");
printf(" hal_play_test -f /etc/Anukoledenadu.wav -> plays Wav stream with default params\n\n");
printf(" hal_play_test -f /etc/MateRani.mp3 -t 2 -d 2 -v 0.01 -r 44100 -c 2 \n");
@@ -649,7 +1016,9 @@
printf(" hal_play_test -f /etc/03_Kuch_Khaas_BE.btaptx -t 9 -d 2 -v 0.2 -r 44100 -c 2 -A 00:02:5b:00:ff:03 \n");
printf(" -> Play aptx clip (-t = 9)\n");
printf(" -> 2 channels and 44100 sample rate\n");
- printf(" -> BT addr: bt_addr=00:02:5b:00:ff:03\n");
+ printf(" -> BT addr: bt_addr=00:02:5b:00:ff:03\n\n");
+ printf(" hal_play_test -f /data/silence.ac3 -t 9 -r 48000 -c 2 -v 0.05 -F 16433 -P -f /data/music_48k.ac3 -t 9 -r 48000 -c 2 -F 32817\n");
+ printf(" -> Plays a silence clip as main stream and music clip as associated\n\n");
printf(" hal_play_test -K -F 4 -> Measure latency KPIs for low latency output\n\n");
printf(" hal_play_test -f /etc//Moto_320kbps.mp3 -t 2 -d 2 -v 0.1 -r 44100 -c 2 -e 2\n");
printf(" -> plays MP3 stream(-t = 2) on speaker device(-d = 2)\n");
@@ -663,23 +1032,25 @@
fseek(file_stream, 16, SEEK_SET);
if(fread(&subchunk_size, 4, 1, file_stream) != 1) {
- fprintf(stdout, "Unable to read subchunk:\n");
+ fprintf(log_file, "Unable to read subchunk:\n");
+ fprintf(stderr, "Unable to read subchunk:\n");
exit (1);
}
if(subchunk_size < 16) {
- fprintf(stdout, "This is not a valid wav file \n");
+ fprintf(log_file, "This is not a valid wav file \n");
+ fprintf(stderr, "This is not a valid wav file \n");
} else {
switch (subchunk_size) {
case 16:
- fprintf(stdout, "44-byte wav header \n");
+ fprintf(log_file, "44-byte wav header \n");
wav_header_len = 44;
break;
case 18:
- fprintf(stdout, "46-byte wav header \n");
+ fprintf(log_file, "46-byte wav header \n");
wav_header_len = 46;
break;
default:
- fprintf(stdout, "Header contains extra data and is larger than 46 bytes: subchunk_size=%d \n", subchunk_size);
+ fprintf(log_file, "Header contains extra data and is larger than 46 bytes: subchunk_size=%d \n", subchunk_size);
wav_header_len = subchunk_size;
break;
}
@@ -690,36 +1061,23 @@
int main(int argc, char* argv[]) {
- FILE *file_stream = NULL;
- char header[WAV_HEADER_LENGTH_MAX] = {0};
- char* filename = nullptr;
qahw_module_handle_t *qahw_mod_handle = NULL;
const char *mod_name = "audio.primary";
- qahw_stream_handle_t* out_handle = nullptr;
- int rc = 0, wav_header_len = 0;
- char *kvpair_values = NULL;
- char kvpair[1000] = {0};
- struct proxy_data proxy_params;
char *ba = NULL;
qahw_param_payload payload;
qahw_param_id param_id;
struct qahw_aptx_dec_param aptx_params;
- /*
- * Default values
- */
- bool kpi_mode = false;
- bool flags_set = false;
- bool proxy_thread_active = false;
- int filetype = FILE_WAV;
- int sample_rate = 44100;
- int channels = 2;
- int bitwidth = 16;
- aac_format_type_t format_type = AAC_LC;
- wma_format_type_t wma_format_type = WMA;
+ int rc = 0;
+ int i = 0;
+ int j = 0;
+ kpi_mode = false;
+ proxy_thread_active = false;
+
log_file = stdout;
- audio_devices_t output_device = AUDIO_DEVICE_OUT_SPEAKER;
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
proxy_params.acp.file_name = "/data/pcm_dump.wav";
+ init_streams();
+
+ int num_of_streams = 1;
struct option long_options[] = {
/* These options set a flag. */
@@ -737,6 +1095,7 @@
{"kvpairs", required_argument, 0, 'k'},
{"flags", required_argument, 0, 'F'},
{"kpi-mode", no_argument, 0, 'K'},
+ {"plus", no_argument, 0, 'P'},
{"effect-path", required_argument, 0, 'e'},
{"bt-addr", required_argument, 0, 'A'},
{"help", no_argument, 0, 'h'},
@@ -745,453 +1104,255 @@
int opt = 0;
int option_index = 0;
- int effect_index = -1;
- thread_func_t ethread_func = NULL;
+
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.num_channels = 2;
+ proxy_params.hdr.sample_rate = 44100;
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,
- "-f:r:c:b:d:v:l:t:a:w:k:D:KF:e:A:h",
+ "-f:r:c:b:d:v:l:t:a:w:k:PD:KF:e:A:h",
long_options,
&option_index)) != -1) {
- switch (opt) {
- case 'f':
- filename = optarg;
- break;
- case 'r':
- sample_rate = atoi(optarg);
- break;
- case 'c':
- channels = atoi(optarg);
- break;
- case 'b':
- bitwidth = atoi(optarg);
- break;
- case 'd':
- output_device = atoll(optarg);
- break;
- case 'v':
- vol_level = atof(optarg);
- break;
- case 'l':
- log_filename = optarg;
- if (strcasecmp(log_filename, "stdout") &&
- strcasecmp(log_filename, "1") &&
- (log_file = fopen(log_filename,"wb")) == NULL) {
- fprintf(stderr, "Cannot open log file %s\n", log_filename);
- /* continue to log to std out. */
- log_file = stdout;
- }
- break;
- case 't':
- filetype = atoi(optarg);
- break;
- case 'a':
- format_type = atoi(optarg);
- break;
- case 'w':
- wma_format_type = atoi(optarg);
- break;
- case 'k':
- kvpair_values = optarg;
- break;
- case 'D':
- proxy_params.acp.file_name = optarg;
- break;
- case 'K':
- kpi_mode = true;
- break;
- case 'F':
- flags = atoll(optarg);
- flags_set = true;
- break;
- case 'e':
- effect_index = atoi(optarg);
- if (effect_index < 0 || effect_index >= EFFECT_MAX) {
- fprintf(stderr, "Invalid effect type %d\n", effect_index);
- effect_index = -1;
- } else if (effect_index == 3) {
- // visualizer is a special effect that is not perceivable by hearing
- // hence, add as an exception in test app.
- fprintf(stdout, "visualizer effect testing is not available\n");
- effect_index = -1;
- } else {
- ethread_func = effect_thread_funcs[effect_index];
- }
- break;
- case 'A':
- ba = optarg;
- break;
- case 'h':
- usage();
+ fprintf(log_file, "for argument %c, value is %s\n", opt, optarg);
+
+ switch (opt) {
+ case 'f':
+ stream_param[i].filename = optarg;
+ break;
+ case 'r':
+ stream_param[i].config.offload_info.sample_rate = atoi(optarg);
+ break;
+ case 'c':
+ stream_param[i].channels = atoi(optarg);
+ break;
+ case 'b':
+ stream_param[i].config.offload_info.bit_width = atoi(optarg);
+ break;
+ case 'd':
+ stream_param[i].output_device = atoll(optarg);
+ break;
+ case 'v':
+ vol_level = atof(optarg);
+ break;
+ case 'l':
+ log_filename = optarg;
+ if (strcasecmp(log_filename, "stdout") &&
+ strcasecmp(log_filename, "1") &&
+ (log_file = fopen(log_filename,"wb")) == NULL) {
+ fprintf(log_file, "Cannot open log file %s\n", log_filename);
+ fprintf(stderr, "Cannot open log file %s\n", log_filename);
+ /* continue to log to std out. */
+ log_file = stdout;
+ }
+ break;
+ case 't':
+ stream_param[i].filetype = atoi(optarg);
+ break;
+ case 'a':
+ stream_param[i].aac_fmt_type = atoi(optarg);
+ break;
+ case 'w':
+ stream_param[i].wma_fmt_type = atoi(optarg);
+ break;
+ case 'k':
+ stream_param[i].kvpair_values = optarg;
+ break;
+ case 'D':
+ proxy_params.acp.file_name = optarg;
+ break;
+ case 'K':
+ kpi_mode = true;
+ break;
+ case 'F':
+ stream_param[i].flags = atoll(optarg);
+ stream_param[i].flags_set = true;
+ break;
+ case 'e':
+ stream_param[i].effect_index = atoi(optarg);
+ if (stream_param[i].effect_index < 0 || stream_param[i].effect_index >= EFFECT_MAX) {
+ fprintf(log_file, "Invalid effect type %d\n", stream_param[i].effect_index);
+ fprintf(stderr, "Invalid effect type %d\n", stream_param[i].effect_index);
+ stream_param[i].effect_index = -1;
+ } else if (stream_param[i].effect_index == 3) {
+ // visualizer is a special effect that is not perceivable by hearing
+ // hence, add as an exception in test app.
+ fprintf(log_file, "visualizer effect testing is not available\n");
+ stream_param[i].effect_index = -1;
+ } else {
+ stream_param[i].ethread_func = effect_thread_funcs[stream_param[i].effect_index];
+ }
+ break;
+ case 'A':
+ ba = optarg;
+ break;
+ case 'P':
+ if(i >= MAX_PLAYBACK_STREAMS - 1) {
+ fprintf(log_file, "cannot have more than %d streams\n", MAX_PLAYBACK_STREAMS);
+ fprintf(stderr, "cannot have more than %d streams\n", MAX_PLAYBACK_STREAMS);
return 0;
- break;
- }
- }
-
- if (!kpi_mode) {
- if (filename == nullptr) {
- fprintf(stderr, "File name is must for non kpi-mode\n");
+ }
+ i++;
+ fprintf(log_file, "Stream index incremented to %d\n", i);
+ break;
+ case 'h':
usage();
- goto EXIT;
+ return 0;
+ break;
+
}
- if ((file_stream = fopen(filename, "r"))== NULL) {
- fprintf(stderr, "Cannot Open Audio File %s\n", filename);
- goto EXIT;
- }
- fprintf(stdout, "Playing:%s\n", filename);
- fprintf(stdout, "File Type:%d\n", filetype);
}
- fprintf(stdout, "Sample Rate:%d\n", sample_rate);
- fprintf(stdout, "Channels:%d\n", channels);
- fprintf(stdout, "Bitwidth:%d\n", bitwidth);
- fprintf(stdout, "Log file:%s\n", log_filename);
- fprintf(stdout, "Volume level:%f\n", vol_level);
- fprintf(stdout, "Output Device:%d\n", output_device);
- fprintf(stdout, "Format Type:%d\n", format_type);
- fprintf(stdout, "kvpair values:%s\n", kvpair_values);
- fprintf(stdout, "Output Flags:%d\n", flags);
+ num_of_streams = i+1;
+ fprintf(log_file, "Starting audio hal tests for streams : %d\n", num_of_streams);
- /*
- * Set to a high number so it doesn't interfere with existing stream handles
- */
- audio_io_handle_t handle = 0x999;
+ if (kpi_mode == true && num_of_streams > 1) {
+ fprintf(log_file, "kpi-mode is not supported for multi-playback usecase\n");
+ fprintf(stderr, "kpi-mode is not supported for multi-playback usecase\n");
+ goto exit;
+ }
- if (output_device & AUDIO_DEVICE_OUT_ALL_A2DP)
- fprintf(stdout, "Saving pcm data to file: %s\n", proxy_params.acp.file_name);
-
- if (effect_index != -1)
- fprintf(stdout, "Effect type:%s\n", effect_str[effect_index]);
-
- fprintf(stdout, "Starting audio hal tests.\n");
+ if (num_of_streams > 1 && stream_param[num_of_streams-1].output_device & AUDIO_DEVICE_OUT_ALL_A2DP) {
+ fprintf(log_file, "Proxy thread is not supported for multi-playback usecase\n");
+ fprintf(stderr, "Proxy thread is not supported for multi-playback usecase\n");
+ goto exit;
+ }
qahw_mod_handle = qahw_load_module(mod_name);
- /*
- * set device connection state for HDMI.
- */
- if (output_device == AUDIO_DEVICE_OUT_AUX_DIGITAL) {
- char param[100] = {0};
- snprintf(param, sizeof(param), "%s=%d", "connect", AUDIO_DEVICE_OUT_AUX_DIGITAL);
- qahw_set_parameters(qahw_mod_handle, param);
- }
-
- audio_config_t config;
- memset(&config, 0, sizeof(audio_config_t));
-
- if (kpi_mode) {
- config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
- } else {
-
- if (!flags_set) {
- flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING;
- flags |= AUDIO_OUTPUT_FLAG_DIRECT;
- }
-
- switch (filetype) {
- case FILE_WAV:
- /*
- * Read the wave header
- */
- if((wav_header_len = get_wav_header_length(file_stream)) <= 0) {
- fprintf(stdout, "wav header length is invalid:%d\n", wav_header_len);
- exit(1);
- }
- fseek(file_stream, 0, SEEK_SET);
- rc = fread (header, wav_header_len, 1, file_stream);
- if (rc != 1) {
- fprintf(stdout, "Error .Fread failed\n");
- exit(0);
- }
- if (strncmp (header, "RIFF", 4) && strncmp (header+8, "WAVE", 4)) {
- fprintf(stdout, "Not a wave format\n");
- exit (1);
- }
- memcpy (&channels, &header[22], 2);
- memcpy (&sample_rate, &header[24], 4);
- memcpy (&bitwidth, &header[34], 2);
- if (bitwidth == 32)
- config.offload_info.format = AUDIO_FORMAT_PCM_32_BIT;
- else if (bitwidth == 24)
- config.offload_info.format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
- else
- config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
- if (!flags_set)
- flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
- break;
-
- case FILE_MP3:
- config.offload_info.format = AUDIO_FORMAT_MP3;
- break;
-
- case FILE_AAC:
- case FILE_AAC_ADTS:
- case FILE_AAC_LATM:
- if (!is_valid_aac_format_type(format_type)) {
- fprintf(log_file, "Invalid format type for AAC %d\n", format_type);
- goto EXIT;
- }
- config.offload_info.format = get_aac_format(filetype, format_type);
- break;
- case FILE_FLAC:
- config.offload_info.format = AUDIO_FORMAT_FLAC;
- break;
- case FILE_ALAC:
- config.offload_info.format = AUDIO_FORMAT_ALAC;
- break;
- case FILE_VORBIS:
- config.offload_info.format = AUDIO_FORMAT_VORBIS;
- break;
- case FILE_WMA:
- if (wma_format_type == WMA)
- config.offload_info.format = AUDIO_FORMAT_WMA;
- else
- config.offload_info.format = AUDIO_FORMAT_WMA_PRO;
- break;
- case FILE_MP2:
- config.offload_info.format = AUDIO_FORMAT_MP2;
- break;
- case FILE_AC3:
- config.offload_info.format = AUDIO_FORMAT_AC3;
- break;
- case FILE_EAC3:
- case FILE_EAC3_JOC:
- config.offload_info.format = AUDIO_FORMAT_E_AC3;
- break;
- case FILE_DTS:
- config.offload_info.format = AUDIO_FORMAT_DTS;
- break;
- case FILE_APTX:
- config.offload_info.format = AUDIO_FORMAT_APTX;
- break;
- default:
- fprintf(stderr, "Does not support given filetype\n");
- usage();
- return 0;
- }
- }
- config.channel_mask = audio_channel_out_mask_from_count(channels);
- config.sample_rate = sample_rate;
- config.format = config.offload_info.format;
- config.offload_info.channel_mask = config.channel_mask;
- config.offload_info.sample_rate = sample_rate;
- config.offload_info.bit_width = bitwidth;
- config.offload_info.version = AUDIO_OFFLOAD_INFO_VERSION_CURRENT;
- config.offload_info.size = sizeof(audio_offload_info_t);
-
- fprintf(log_file, "Now playing to output_device=%d sample_rate=%d \n"
- , 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;
- }
- if (filetype == FILE_APTX) {
- if (ba != NULL) {
- parse_aptx_dec_bt_addr(ba, &aptx_params);
- payload = (qahw_param_payload)aptx_params;
- param_id = QAHW_PARAM_APTX_DEC;
- fprintf(log_file, "Send BT addr nap %d, uap %d lap %d to HAL\n", aptx_params.bt_addr.nap,
- aptx_params.bt_addr.uap, aptx_params.bt_addr.lap);
- rc = qahw_set_param_data(qahw_mod_handle, param_id, &payload);
- if (rc != 0)
- printf("Error.Failed Set BT addr\n");
- } else {
- fprintf(log_file, "BT addr is NULL, Need valid BT addr for aptx file playback to work\n");
- fprintf(stderr, "BT addr is NULL, Need valid BT addr for aptx file playback to work\n");
- goto EXIT;
- }
- }
-
- fprintf(log_file, "calling open_out_put_stream:\n");
- rc = qahw_open_output_stream(qahw_mod_handle,
- handle,
- output_device,
- flags,
- &config,
- &out_handle,
- stream_name);
- fprintf(log_file, "open output stream is sucess:%d out_handhle %p\n"
- , rc, out_handle);
- if (rc) {
- fprintf(stdout, "could not open output stream %d \n", rc);
- goto EXIT;
- }
-
- if (kpi_mode) {
- measure_kpi_values(out_handle, (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
- goto EXIT;
- }
-
- switch(filetype) {
- case FILE_WMA:
- case FILE_VORBIS:
- case FILE_ALAC:
- case FILE_FLAC:
- if (!kvpair_values) {
- fprintf (log_file, "Error!!No metadata for the Clip\n");
- fprintf (stdout, "Error!!No metadata for the Clip\n");
- goto EXIT;
- }
- read_kvpair(kvpair, kvpair_values, filetype);
- qahw_out_set_parameters(out_handle, kvpair);
- break;
- default:
- 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");
- rc = pthread_create(&proxy_thread, NULL, proxy_read, (void *)&proxy_params);
- if (!rc)
- proxy_thread_active = true;
- }
-
- // create effect thread, use thread_data to transfer command
- if (ethread_func &&
- (flags & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_DIRECT))) {
- ethread_data = create_effect_thread(effect_index, ethread_func);
-
- // create effect command thread
- cmd_data.exit = false;
- cmd_data.fx_data_ptr = ðread_data;
- pthread_attr_init(&cmd_data.attr);
- pthread_attr_setdetachstate(&cmd_data.attr, PTHREAD_CREATE_JOINABLE);
- rc = pthread_create(&cmd_data.cmd_thread, &cmd_data.attr,
- &command_thread_func, &cmd_data);
- if (rc < 0) {
- fprintf(stderr, "Could not create effect command thread!\n");
- goto EXIT;
- }
- }
-
- if (ethread_data) {
- // load effect module
- notify_effect_command(ethread_data, EFFECT_LOAD_LIB, -1, 0, NULL);
-
- // get effect desc
- notify_effect_command(ethread_data, EFFECT_GET_DESC, -1, 0, NULL);
-
- // create effect
- ethread_data->io_handle = handle;
- notify_effect_command(ethread_data, EFFECT_CREATE, -1, 0, NULL);
-
- // broadcast device info
- notify_effect_command(ethread_data, EFFECT_CMD, QAHW_EFFECT_CMD_SET_DEVICE, sizeof(audio_devices_t), &output_device);
-
- // enable effect
- notify_effect_command(ethread_data, EFFECT_CMD, QAHW_EFFECT_CMD_ENABLE, 0, NULL);
- }
-
/* Register the SIGINT to close the App properly */
- if (signal(SIGINT, stop_signal_handler) == SIG_ERR)
+ if (signal(SIGINT, stop_signal_handler) == SIG_ERR) {
fprintf(log_file, "Failed to register SIGINT:%d\n",errno);
-
- play_file(out_handle,
- file_stream,
- (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
-
- if (ethread_data) {
- // disable effect
- notify_effect_command(ethread_data, EFFECT_CMD, QAHW_EFFECT_CMD_DISABLE, 0, NULL);
-
- // release effect
- notify_effect_command(ethread_data, EFFECT_RELEASE, -1, 0, NULL);
-
- // unload effect module
- notify_effect_command(ethread_data, EFFECT_UNLOAD_LIB, -1, 0, NULL);
-
- // destroy effect thread
- destroy_effect_thread(ethread_data);
-
- free(ethread_data);
- ethread_data = NULL;
-
- // destory effect command thread
- cmd_data.exit = true;
- usleep(100000); // give a chance for thread to exit gracefully
- rc = pthread_cancel(cmd_data.cmd_thread);
- if (rc != 0) {
- fprintf(stderr, "Fail to cancel thread!\n");
- }
- rc = pthread_join(cmd_data.cmd_thread, NULL);
- if (rc < 0) {
- fprintf(stderr, "Fail to join effect command thread!\n");
- }
+ fprintf(stderr, "Failed to register SIGINT:%d\n",errno);
}
- if (proxy_thread_active) {
- /*
- * 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 proxy thread exit\n");
+ for (i = 0; i < num_of_streams; i++) {
+ fprintf(log_file, "Playing:%s\n", stream_param[i].filename);
+
+ stream_param[i].qahw_mod_handle = qahw_mod_handle;
+
+ if (kpi_mode == false) {
+ if (stream_param[PRIMARY_STREAM_INDEX].filename == nullptr) {
+ fprintf(log_file, "Primary file name is must for non kpi-mode\n");
+ fprintf(stderr, "Primary file name is must for non kpi-mode\n");
+ goto exit;
+ }
+ if ((stream_param[i].file_stream = fopen(stream_param[i].filename, "r"))== NULL) {
+ fprintf(log_file, "Cannot open audio file %s\n", stream_param[i].filename);
+ fprintf(stderr, "Cannot open audio file %s\n", stream_param[i].filename);
+ goto exit;
+ }
+ }
+
+ if (stream_param[i].output_device & AUDIO_DEVICE_OUT_ALL_A2DP)
+ fprintf(log_file, "Saving pcm data to file: %s\n", proxy_params.acp.file_name);
+
+ /* Set device connection state for HDMI */
+ if (stream_param[i].output_device == AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+ char param[100] = {0};
+ snprintf(param, sizeof(param), "%s=%d", "connect", AUDIO_DEVICE_OUT_AUX_DIGITAL);
+ qahw_set_parameters(qahw_mod_handle, param);
+ }
+
+ if (kpi_mode == true) {
+ stream_param[i].config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
+ } else {
+ get_file_format(&stream_param[i]);
+ }
+
+ fprintf(log_file, "stream %d: File Type:%d\n", stream_param[i].stream_index, stream_param[i].filetype);
+ fprintf(log_file, "stream %d: Audio Format:%d\n", stream_param[i].stream_index, stream_param[i].config.offload_info.format);
+ fprintf(log_file, "stream %d: Output Device:%d\n", stream_param[i].stream_index, stream_param[i].output_device);
+ fprintf(log_file, "stream %d: Output Flags:%d\n", stream_param[i].stream_index, stream_param[i].flags);
+ fprintf(log_file, "stream %d: Sample Rate:%d\n", stream_param[i].stream_index, stream_param[i].config.offload_info.sample_rate);
+ fprintf(log_file, "stream %d: Channels:%d\n", stream_param[i].stream_index, stream_param[i].channels);
+ fprintf(log_file, "stream %d: Bitwidth:%d\n", stream_param[i].stream_index, stream_param[i].config.offload_info.bit_width);
+ fprintf(log_file, "stream %d: AAC Format Type:%d\n", stream_param[i].stream_index, stream_param[i].aac_fmt_type);
+ fprintf(log_file, "stream %d: Kvpair Values:%s\n", stream_param[i].stream_index, stream_param[i].kvpair_values);
+ fprintf(log_file, "Log file:%s\n", log_filename);
+ fprintf(log_file, "Volume level:%f\n", vol_level);
+
+ stream_param[i].config.offload_info.channel_mask = stream_param[i].config.channel_mask;
+ stream_param[i].config.offload_info.version = AUDIO_OFFLOAD_INFO_VERSION_CURRENT;
+ stream_param[i].config.offload_info.size = sizeof(audio_offload_info_t);
+
+ stream_param[i].config.channel_mask = audio_channel_out_mask_from_count(stream_param[i].channels);
+ stream_param[i].config.format = stream_param[i].config.offload_info.format;
+ stream_param[i].config.sample_rate = stream_param[i].config.offload_info.sample_rate;
+
+ fprintf(log_file, "stream %d: playing to output_device=%d \n", stream_param[i].stream_index, stream_param[i].output_device);
+
+ if (stream_param[i].filetype == FILE_APTX) {
+ if (ba != NULL) {
+ parse_aptx_dec_bt_addr(ba, &aptx_params);
+ payload = (qahw_param_payload)aptx_params;
+ param_id = QAHW_PARAM_APTX_DEC;
+ fprintf(log_file, "Send BT addr nap %d, uap %d lap %d to HAL\n", aptx_params.bt_addr.nap,
+ aptx_params.bt_addr.uap, aptx_params.bt_addr.lap);
+ rc = qahw_set_param_data(qahw_mod_handle, param_id, &payload);
+ if (rc != 0)
+ fprintf(log_file, "Error.Failed Set BT addr\n");
+ fprintf(stderr, "Error.Failed Set BT addr\n");
+ } else {
+ fprintf(log_file, "BT addr is NULL, Need valid BT addr for aptx file playback to work\n");
+ fprintf(stderr, "BT addr is NULL, Need valid BT addr for aptx file playback to work\n");
+ goto exit;
+ }
+ }
+
+ rc = pthread_create(&playback_thread[i], NULL, start_stream_playback, (void *)&stream_param[i]);
+ if (rc) {
+ fprintf(log_file, "stream %d: failed to create thread\n", stream_param[i].stream_index);
+ fprintf(stderr, "stream %d: failed to create thread\n", stream_param[i].stream_index);
+ exit(0);
+ }
+
+ thread_active[i] = true;
+
}
-EXIT:
+exit:
- if (proxy_thread_active)
- pthread_join(proxy_thread, NULL);
-
- if (out_handle != nullptr) {
- rc = qahw_out_standby(out_handle);
- if (rc) {
- fprintf(stdout, "out standby failed %d \n", rc);
- }
-
- rc = qahw_close_output_stream(out_handle);
- if (rc) {
- fprintf(stdout, "could not close output stream %d \n", rc);
- }
+ for (i=0; i<MAX_PLAYBACK_STREAMS; i++) {
+ if(thread_active[i])
+ pthread_join(playback_thread[i], NULL);
}
/*
- * reset device connection state for HDMI.
+ * reset device connection state for HDMI and close the file streams
*/
- if (output_device == AUDIO_DEVICE_OUT_AUX_DIGITAL) {
- char param[100] = {0};
- snprintf(param, sizeof(param), "%s=%d", "disconnect", AUDIO_DEVICE_OUT_AUX_DIGITAL);
- qahw_set_parameters(qahw_mod_handle, param);
- }
+ for (i = 0; i < num_of_streams; i++) {
+ if (stream_param[i].output_device == AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+ char param[100] = {0};
+ snprintf(param, sizeof(param), "%s=%d", "disconnect", AUDIO_DEVICE_OUT_AUX_DIGITAL);
+ qahw_set_parameters(qahw_mod_handle, param);
+ }
+
+ if (stream_param[i].file_stream != nullptr)
+ fclose(stream_param[i].file_stream);
+ }
rc = qahw_unload_module(qahw_mod_handle);
if (rc) {
- fprintf(stdout, "could not unload hal %d \n", rc);
+ fprintf(log_file, "could not unload hal %d \n", rc);
+ fprintf(stderr, "could not unload hal %d \n", rc);
return -1;
}
if ((log_file != stdout) && (log_file != nullptr))
fclose(log_file);
- if (file_stream != nullptr)
- fclose(file_stream);
-
- fprintf(stdout, "\nBYE BYE\n");
+ fprintf(log_file, "\nBYE BYE\n");
return 0;
}