From b1ec2bab8729952b1068263313522968fc488d31 Mon Sep 17 00:00:00 2001 From: Dhananjay Kumar Date: Wed, 16 Nov 2016 21:47:43 +0530 Subject: [PATCH] qahw: test: Enhance and add new functionality to record test app - Align test app code to c coding style. - Add command line options. - Add start delay for each session. Change-Id: I1b49fae319e61484288b031057556e54d984b7f2 --- qahw_api/test/qahw_multi_record_test.c | 798 +++++++++++++++++-------- 1 file changed, 561 insertions(+), 237 deletions(-) diff --git a/qahw_api/test/qahw_multi_record_test.c b/qahw_api/test/qahw_multi_record_test.c index 42f7df0f..96107c98 100644 --- a/qahw_api/test/qahw_multi_record_test.c +++ b/qahw_api/test/qahw_multi_record_test.c @@ -18,37 +18,74 @@ /* Test app to record multiple audio sessions at the HAL layer */ +#include #include #include #include #include #include #include +#include #include "qahw_api.h" #include "qahw_defs.h" +#define nullptr NULL +#define LATENCY_NODE "/sys/kernel/debug/audio_in_latency_measurement_node" +#define LATENCY_NODE_INIT_STR "1" + +static bool kpi_mode; +FILE * log_file = NULL; + +#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; /* sample_rate * num_channels * bps / 8 */ + uint16_t block_align; /* num_channels * bps / 8 */ + 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 output_filename[256]; - double loopTime; + audio_config_t config; + audio_source_t source; + int channels; + double record_delay; + double record_length; char profile[50]; }; +struct timed_params { + struct listnode list; + char param[256]; + int param_delay; +}; + +static pthread_mutex_t glock; +static volatile int tests_running; +static volatile int tests_completed; + #define SOUNDFOCUS_PARAMS "SoundFocus.start_angles;SoundFocus.enable_sectors;" \ "SoundFocus.gain_step" #define SOURCETRACK_PARAMS "SourceTrack.vad;SourceTrack.doa_speech;SourceTrack.doa_noise;"\ "SourceTrack.polar_activity;ssr.noise_level;ssr.noise_level_after_ns" -int sourcetrack_done = 0; -static pthread_mutex_t glock; -pthread_cond_t gcond; -int tests_running; -bool gerror; void *read_sourcetrack_data(void* data) { @@ -58,14 +95,13 @@ void *read_sourcetrack_data(void* data) char *token = NULL; char choice = '\0'; int i =0; - qahw_module_handle_t *qawh_module_handle = - (qahw_module_handle_t *)data; + qahw_module_handle_t *qawh_module_handle = (qahw_module_handle_t *) data; - while (1) { - printf("\nGet SoundFocus Params from app"); + while (true) { + fprintf(log_file, "\nGet SoundFocus Params from app"); string = qahw_get_parameters(qawh_module_handle, kvpair_soundfocus); if (!string) { - printf("Error.Failed Get SoundFocus Params\n"); + fprintf(log_file, "Error.Failed Get SoundFocus Params\n"); } else { token = strtok (string , "="); while (token) { @@ -76,14 +112,14 @@ void *read_sourcetrack_data(void* data) } switch (choice) { case 'g': - printf ("\nSoundFocus.gain_step=%s",token); + fprintf(log_file, "\nSoundFocus.gain_step=%s",token); break; case 'e': - printf ("\nSoundFocus.enable_sectors[%d]=%s",i,token); + fprintf(log_file, "\nSoundFocus.enable_sectors[%d]=%s",i,token); i++; break; case 's': - printf ("\nSoundFocus.start_angles[%d]=%s",i,token); + fprintf(log_file, "\nSoundFocus.start_angles[%d]=%s",i,token); i++; break; } @@ -91,10 +127,10 @@ void *read_sourcetrack_data(void* data) } } choice = '\0'; - printf ("\nGet SourceTracking Params from app"); + fprintf(log_file, "\nGet SourceTracking Params from app"); string = qahw_get_parameters(qawh_module_handle, kvpair_sourcetrack); if (!string) { - printf ("Error.Failed Get SourceTrack Params\n"); + fprintf(log_file, "Error.Failed Get SourceTrack Params\n"); } else { token = strtok (string , "="); while (token) { @@ -107,383 +143,671 @@ void *read_sourcetrack_data(void* data) } switch (choice) { case 'p': - printf ("\nSourceTrack.polar_activity=%s,",token); + fprintf(log_file, "\nSourceTrack.polar_activity=%s,",token); choice = '\0'; break; case 'v': - printf ("\nSourceTrack.vad[%d]=%s",i,token); + fprintf(log_file, "\nSourceTrack.vad[%d]=%s",i,token); i++; break; case 's': - printf ("\nSourceTrack.doa_speech=%s",token); + fprintf(log_file, "\nSourceTrack.doa_speech=%s",token); break; case 'n': - printf ("\nSourceTrack.doa_noise[%d]=%s",i,token); + fprintf(log_file, "\nSourceTrack.doa_noise[%d]=%s",i,token); i++; break; default : - printf ("%s,",token); + fprintf(log_file, "%s,",token); break; } token = strtok (NULL,",;="); } } - if (sourcetrack_done == 1) + if (tests_completed > 0 && tests_running == 0) return NULL; } } +void test_begin() +{ + pthread_mutex_lock(&glock); + tests_running++; + pthread_mutex_unlock(&glock); +} + +void test_end() +{ + pthread_mutex_lock(&glock); + tests_running--; + tests_completed++; + pthread_mutex_unlock(&glock); +} + void *start_input(void *thread_param) { - int rc = 0; + int rc = 0, ret = 0, count = 0; + FILE *fdLatencyNode = nullptr; + struct timespec tsColdI, tsColdF, tsCont; + uint64_t tCold, tCont, tsec, tusec; + char latencyBuf[200] = {0}; + time_t start_time = time(0); + double time_elapsed = 0; + ssize_t bytes_read = -1; + char param[100] = "audio_stream_profile="; + char file_name[256] = "/data/rec"; + int data_sz = 0, name_len = strlen(file_name); + qahw_in_buffer_t in_buf; + struct audio_config_params* params = (struct audio_config_params*) thread_param; qahw_module_handle_t *qahw_mod_handle = params->qahw_mod_handle; - // Open audio input stream. + /* convert/check params before use */ + switch(params->channels) { + case 1: + params->config.channel_mask = AUDIO_CHANNEL_IN_MONO; + break; + case 2: + params->config.channel_mask = AUDIO_CHANNEL_IN_STEREO; + break; + case 4: + params->config.channel_mask = AUDIO_CHANNEL_INDEX_MASK_4; + break; + default: + fprintf(log_file, "ERROR :::: channle count %d not supported, handle(%d)", params->channels, params->handle); + if (log_file != stdout) + fprintf(stdout, "ERROR :::: channle count %d not supported, handle(%d)", params->channels, params->handle); + pthread_exit(0); + } + + /* setup debug node if in kpi mode */ + if (kpi_mode) { + fdLatencyNode = fopen(LATENCY_NODE,"r+"); + if (fdLatencyNode) { + ret = fwrite(LATENCY_NODE_INIT_STR, sizeof(LATENCY_NODE_INIT_STR), 1, fdLatencyNode); + if (ret < 1) + fprintf(log_file, "error(%d) writing to debug node!, handle(%d)", ret, params->handle); + fflush(fdLatencyNode); + } else { + fprintf(log_file, "debug node(%s) open failed!, handle(%d)", LATENCY_NODE, params->handle); + if (log_file != stdout) + fprintf(stdout, "debug node(%s) open failed!, handle(%d)", LATENCY_NODE, params->handle); + pthread_exit(0); + } + } + + test_begin(); + /* Open audio input stream */ qahw_stream_handle_t* in_handle = NULL; rc = qahw_open_input_stream(qahw_mod_handle, params->handle, params->input_device, ¶ms->config, &in_handle, - params->flags, params->kStreamName, - params->kInputSource); + params->flags, "input_stream", + params->source); if (rc) { - printf("ERROR :::: Could not open input stream.\n" ); - pthread_mutex_lock(&glock); - gerror = true; - pthread_cond_signal(&gcond); - pthread_mutex_unlock(&glock); + fprintf(log_file, "ERROR :::: Could not open input stream, handle(%d)\n", params->handle); + if (log_file != stdout) + fprintf(stdout, "ERROR :::: Could not open input stream, handle(%d)\n", params->handle); + test_end(); pthread_exit(0); } - // Get buffer size to get upper bound on data to read from the HAL. - size_t buffer_size; - buffer_size = qahw_in_get_buffer_size(in_handle); - char *buffer; - buffer = (char *)calloc(1, buffer_size); + /* Get buffer size to get upper bound on data to read from the HAL */ + size_t buffer_size = qahw_in_get_buffer_size(in_handle); + char *buffer = (char *)calloc(1, buffer_size); if (buffer == NULL) { - printf("calloc failed!!\n"); - pthread_mutex_lock(&glock); - gerror = true; - pthread_cond_signal(&gcond); - pthread_mutex_unlock(&glock); - pthread_exit(0); + fprintf(log_file, "calloc failed!!, handle(%d)\n", params->handle); + if (log_file != stdout) + fprintf(stdout, "calloc failed!!, handle(%d)\n", params->handle); + test_end(); + pthread_exit(0); } - printf("input opened, buffer = %p, size %zun", - buffer, buffer_size); - - int num_channels = audio_channel_count_from_in_mask(params->config.channel_mask); - - time_t start_time = time(0); - ssize_t bytes_read = -1; - char param[100] = "audio_stream_profile="; - qahw_in_buffer_t in_buf; - - // set profile for the recording session + fprintf(log_file, " input opened, buffer %p, size %zu, handle(%d)", buffer, buffer_size, params->handle); + /* set profile for the recording session */ strlcat(param, params->profile, sizeof(param)); qahw_in_set_parameters(in_handle, param); - printf("\nPlease speak into the microphone for %lf seconds.\n", params->loopTime); + fprintf(log_file, "\n Please speak into the microphone for %lf seconds, handle(%d)\n", params->record_length, params->handle); + if (log_file != stdout) + fprintf(stdout, "\n Please speak into the microphone for %lf seconds, handle(%d)\n", params->record_length, params->handle); - FILE *fd = fopen(params->output_filename,"w"); + snprintf(file_name + name_len, sizeof(file_name) - name_len, "%d.wav", (0x99A - params->handle)); + FILE *fd = fopen(file_name,"w"); if (fd == NULL) { - printf("File open failed \n"); - pthread_mutex_lock(&glock); - gerror = true; - pthread_cond_signal(&gcond); - pthread_mutex_unlock(&glock); - pthread_exit(0); + fprintf(log_file, "File open failed \n"); + if (log_file != stdout) + fprintf(stdout, "File open failed \n"); + test_end(); + pthread_exit(0); } - pthread_mutex_lock(&glock); - tests_running++; - pthread_cond_signal(&gcond); - pthread_mutex_unlock(&glock); - memset(&in_buf,0, sizeof(qahw_in_buffer_t)); + int bps = 16; + switch(params->config.format) { + case AUDIO_FORMAT_PCM_24_BIT_PACKED: + bps = 24; + break; + case AUDIO_FORMAT_PCM_8_24_BIT: + case AUDIO_FORMAT_PCM_32_BIT: + bps = 32; + break; + case AUDIO_FORMAT_PCM_16_BIT: + default: + bps = 16; + } + + struct wav_header hdr; + hdr.riff_id = ID_RIFF; + hdr.riff_sz = 0; + hdr.riff_fmt = ID_WAVE; + hdr.fmt_id = ID_FMT; + hdr.fmt_sz = 16; + hdr.audio_format = FORMAT_PCM; + hdr.num_channels = params->channels; + hdr.sample_rate = params->config.sample_rate; + hdr.byte_rate = hdr.sample_rate * hdr.num_channels * (bps/8); + hdr.block_align = hdr.num_channels * (bps/8); + hdr.bits_per_sample = bps; + hdr.data_id = ID_DATA; + hdr.data_sz = 0; + fwrite(&hdr, 1, sizeof(hdr), fd); + + memset(&in_buf,0, sizeof(qahw_in_buffer_t)); + start_time = time(0); while(true) { + if(time_elapsed < params->record_delay) { + usleep(1000000*(params->record_delay - time_elapsed)); + continue; + } else if (time_elapsed > params->record_delay + params->record_length) { + fprintf(log_file, "\n Test for session with handle(%d) completed.\n", params->handle); + if (log_file != stdout) + fprintf(stdout, "\n Test for session with handle(%d) completed.\n", params->handle); + break; + } + + if (kpi_mode && count == 0) { + ret = clock_gettime(CLOCK_REALTIME, &tsColdI); + if (ret) + fprintf(log_file, "error(%d) getting current time before first read!, handle(%d)", ret, params->handle); + } + in_buf.buffer = buffer; in_buf.bytes = buffer_size; bytes_read = qahw_in_read(in_handle, &in_buf); - fwrite(in_buf.buffer, sizeof(char), buffer_size, fd); - if(difftime(time(0), start_time) > params->loopTime) { - printf("\nTest completed.\n"); - break; + + if (kpi_mode) { + if (count == 0) { + ret = clock_gettime(CLOCK_REALTIME, &tsColdF); + if (ret) + fprintf(log_file, "error(%d) getting current time after first read!, handle(%d)", ret, params->handle); + } else if (count == 8) { + /* 8th read done time is captured in kernel which would have trigger 9th read in DSP + * 9th read is received by usersace at this time + */ + ret = clock_gettime(CLOCK_REALTIME, &tsCont); + if (ret) + fprintf(log_file, "error(%d) getting current time after 8th read!, handle(%d)", ret, params->handle); + } + count++; } + + time_elapsed = difftime(time(0), start_time); + fwrite(in_buf.buffer, 1, buffer_size, fd); + data_sz += buffer_size; } - printf("closing input"); + /* update lengths in header */ + hdr.data_sz = data_sz; + hdr.riff_sz = data_sz + 44 - 8; + fseek(fd, 0, SEEK_SET); + fwrite(&hdr, 1, sizeof(hdr), fd); fclose(fd); - // Close output stream and device. + /* capture latency kpis if required */ + if (kpi_mode) { + tCold = tsColdF.tv_sec*1000 - tsColdI.tv_sec*1000 + + tsColdF.tv_nsec/1000000 - tsColdI.tv_nsec/1000000; + + fread((void *) latencyBuf, 100, 1, fdLatencyNode); + fclose(fdLatencyNode); + sscanf(latencyBuf, " %llu,%llu", &tsec, &tusec); + tCont = tsCont.tv_sec*1000 - tsec*1000 + tsCont.tv_nsec/1000000 - tusec/1000; + if (log_file != stdout) { + fprintf(stdout, "\n cold latency %llums, continuous latency %llums, handle(%d)\n", tCold, tCont, params->handle); + fprintf(stdout, " **Note: please add DSP Pipe/PP latency numbers to this, for final latency values\n"); + } + fprintf(log_file, "\n values from debug node %s, handle(%d)\n", latencyBuf, params->handle); + fprintf(log_file, "\n cold latency %llums, continuous latency %llums, handle(%d)\n", tCold, tCont, params->handle); + fprintf(log_file, " **Note: please add DSP Pipe/PP latency numbers to this, for final latency values\n"); + } + + fprintf(log_file, " closing input, handle(%d)", params->handle); + + /* Close output stream and device. */ rc = qahw_in_standby(in_handle); if (rc) { - printf("out standby failed %d \n",rc); + fprintf(log_file, "out standby failed %d, handle(%d)\n",rc, params->handle); + if (log_file != stdout) + fprintf(stdout, "out standby failed %d, handle(%d)\n",rc, params->handle); } rc = qahw_close_input_stream(in_handle); if (rc) { - printf("could not close input stream %d \n",rc); + fprintf(log_file, "could not close input stream %d, handle(%d)\n",rc, params->handle); + if (log_file != stdout) + fprintf(stdout, "could not close input stream %d, handle(%d)\n",rc, params->handle); } - // Print instructions to access the file. - printf("\nThe audio recording has been saved to %s. Please use adb pull to get " + /* Print instructions to access the file. */ + fprintf(log_file, "\n\n The audio recording has been saved to %s. Please use adb pull to get " "the file and play it using audacity. The audio data has the " - "following characteristics:\nsample rate: %i\nformat: %d\n" - "num channels: %i\n", - params->output_filename, params->config.sample_rate, - params->config.format, num_channels); + "following characteristics:\n Sample rate: %i\n Format: %d\n " + "Num channels: %i, handle(%d)\n\n", + file_name, params->config.sample_rate, params->config.format, params->channels, params->handle); + if (log_file != stdout) + fprintf(stdout, "\n\n The audio recording has been saved to %s. Please use adb pull to get " + "the file and play it using audacity. The audio data has the " + "following characteristics:\n Sample rate: %i\n Format: %d\n " + "Num channels: %i, handle(%d)\n\n", + file_name, params->config.sample_rate, params->config.format, params->channels, params->handle); - pthread_mutex_lock(&glock); - tests_running--; - pthread_cond_signal(&gcond); - pthread_mutex_unlock(&glock); - pthread_exit(0); + test_end(); return NULL; } -int read_config_params_from_user(struct audio_config_params *thread_param, int rec_session) { - int channels = 0, format = 0, sample_rate = 0,source = 0, device = 0; - - thread_param->kStreamName = "input_stream"; - +int read_config_params_from_user(struct audio_config_params *thread_param) { printf(" \n Enter input device (4->built-in mic, 16->wired_headset .. etc) ::::: "); - scanf(" %d", &device); - if (device & AUDIO_DEVICE_IN_BUILTIN_MIC) - thread_param->input_device = AUDIO_DEVICE_IN_BUILTIN_MIC; - else if (device & AUDIO_DEVICE_IN_WIRED_HEADSET) - thread_param->input_device = AUDIO_DEVICE_IN_WIRED_HEADSET; + scanf(" %d", &thread_param->input_device); + thread_param->input_device |= AUDIO_DEVICE_BIT_IN; - printf(" \n Enter the channels (1 -mono, 2 -stereo and 4 -quad channels) ::::: "); - scanf(" %d", &channels); - if (channels == 1) { - thread_param->config.channel_mask = AUDIO_CHANNEL_IN_MONO; - } else if (channels == 2) { - thread_param->config.channel_mask = AUDIO_CHANNEL_IN_STEREO; - } else if (channels == 4) { - thread_param->config.channel_mask = AUDIO_CHANNEL_INDEX_MASK_4; - } else { - gerror = true; - printf("\nINVALID channels"); - return -1; - } + printf(" \n Enter the format (1 ->16 bit pcm recording, 6 -> 24 bit packed pcm recording) ::::: "); + scanf(" %d", &thread_param->config.format); - printf(" \n Enter the format (16 - 16 bit recording, 24 - 24 bit recording) ::::: "); - scanf(" %d", &format); - if (format == 16) { - thread_param->config.format = AUDIO_FORMAT_PCM_16_BIT; - } else if (format == 24) { - thread_param->config.format = AUDIO_FORMAT_PCM_24_BIT_PACKED; - } else { - gerror = true; - printf("\n INVALID format"); - return -1; - } + printf(" \n Enter input flag to be used (0 -> none, 1 -> fast ...) ::::: "); + scanf(" %d", &thread_param->flags); printf(" \n Enter the sample rate (48000, 16000 etc) :::: "); - scanf(" %d", &sample_rate); - thread_param->config.sample_rate = sample_rate; + scanf(" %d", &thread_param->config.sample_rate); + + printf(" \n Enter the channels (1 -mono, 2 -stereo and 4 -quad channels) ::::: "); + scanf(" %d", &thread_param->channels); -#ifdef MULTIRECORD_SUPPOT printf(" \n Enter profile (none, record_fluence, record_mec, record_unprocessed etc) :::: "); scanf(" %s", thread_param->profile); -#else - thread_param->flags = (audio_input_flags_t)AUDIO_INPUT_FLAG_NONE; -#endif - printf("\n Enter the audio source ( ref: system/media/audio/include/system/audio.h) :::: "); - scanf(" %d", &source); - thread_param->kInputSource = (audio_source_t)source; - if (rec_session == 1) { - thread_param->handle = 0x999; - strcpy(thread_param->output_filename, "/data/rec1.raw"); - } else if (rec_session == 2) { - thread_param->handle = 0x998; - strcpy(thread_param->output_filename, "/data/rec2.raw"); - } else if (rec_session == 3) { - thread_param->handle = 0x997; - strcpy(thread_param->output_filename, "/data/rec3.raw"); - } else if (rec_session == 4) { - thread_param->handle = 0x996; - strcpy(thread_param->output_filename, "/data/rec4.raw"); - } + printf("\n Enter the audio source ( ref: system/media/audio/include/system/audio.h) :::: "); + scanf(" %d", &thread_param->source); printf("\n Enter the record duration in seconds :::: "); - scanf(" %lf", &thread_param->loopTime); + scanf(" %lf", &thread_param->record_length); + + printf("\n Enter the start delay for the session in seconds :::: "); + scanf(" %lf", &thread_param->record_delay); + return 0; } -int main() { - int max_recordings_requested = 0, source_track = 0; +void fill_default_params(struct audio_config_params *thread_param, int rec_session) { + memset(thread_param,0, sizeof(struct audio_config_params)); + + thread_param->input_device = AUDIO_DEVICE_IN_BUILTIN_MIC; + thread_param->config.format = AUDIO_FORMAT_PCM_16_BIT; + thread_param->channels = 2; + thread_param->flags = (audio_input_flags_t)AUDIO_INPUT_FLAG_NONE; + thread_param->config.sample_rate = 48000; + thread_param->source = 1; + thread_param->record_length = 8 /*sec*/; + thread_param->record_delay = 0 /*sec*/; + + if (rec_session == 1) { + thread_param->handle = 0x999; + } else if (rec_session == 2) { + thread_param->handle = 0x998; + } else if (rec_session == 3) { + thread_param->handle = 0x997; + } else if (rec_session == 4) { + thread_param->handle = 0x996; + } +} + +void usage() { + printf(" \n Command \n"); + printf(" \n hal_rec_test \n"); + printf(" \n Options\n"); + printf(" -d --device - see system/media/audio/include/system/audio.h for device values\n"); + printf(" Optional Argument and Default value is 4, i.e Built-in MIC\n\n"); + printf(" -f --format - Integer value of format in which data needs to be recorded\n\n"); + printf(" -F --flags - Integer value of flags to be used for opening input stream\n\n"); + printf(" -r --sample-rate <8000-96000> - Sampling rate to be used\n\n"); + printf(" -c --channels - Number of input channels needed\n\n"); + printf(" -s --source - Input Source type\n\n"); + printf(" -p --profile - Input profile tag, used for profile based app_type selection.\n\n"); + printf(" -t --recording-time - Time duration for the recording\n\n"); + printf(" -D --recording-delay - Delay in seconds after which recording should be started\n\n"); + printf(" -l --log-file - File path for debug msg, to print\n"); + printf(" on console use stdout or 1 \n\n"); + printf(" -K --kpi-mode - Use this flag to measure latency KPIs for this recording\n\n"); + printf(" -i --interactive-mode - Use this flag if prefer configuring streams using interactive mode\n"); + printf(" All other flags passed would be ignore if this flag is used\n\n"); + printf(" -S --source-tracking - Use this flag to show capture source tracking params for recordings\n\n"); + printf(" -h --help - Show this help\n\n"); + printf(" \n Examples \n"); + printf(" hal_rec_test -> start a recording stream with default configurations\n\n"); + printf(" hal_rec_test -i -> start a recording stream and get configurations from user interactively\n\n"); + printf(" hal_rec_test -d 2 -f 1 -r 44100 -c 2 -t 8 -D 2 -S -> start a recording session, with device 2[built-in-mic],\n"); + printf(" format 1[AUDIO_FORMAT_PCM_16_BIT], sample rate 44100, \n"); + printf(" channels 2[AUDIO_CHANNEL_IN_STEREO], record data for 8 secs\n"); + printf(" start recording after 2 secs, and capture source tracking params.\n\n"); + printf(" hal_rec_test -F 1 --kpi-mode -> start a recording with low latency input flag and calculate latency KPIs\n\n"); +} + +int main(int argc, char* argv[]) { + int max_recordings_requested = 0, status = 0; int thread_active[4] = {0}; qahw_module_handle_t *qahw_mod_handle; const char *mod_name = "audio.primary"; + struct audio_config_params params[4]; + bool interactive_mode = false, source_tracking = false; + struct listnode param_list; + char log_filename[256] = "stdout"; - pthread_cond_init(&gcond, (const pthread_condattr_t *) NULL); + log_file = stdout; + list_init(¶m_list); + fill_default_params(¶ms[0], 1); + struct option long_options[] = { + /* These options set a flag. */ + {"device", required_argument, 0, 'd'}, + {"format", required_argument, 0, 'f'}, + {"flags", required_argument, 0, 'F'}, + {"sample-rate", required_argument, 0, 'r'}, + {"channels", required_argument, 0, 'c'}, + {"source", required_argument, 0, 's'}, + {"profile", required_argument, 0, 'p'}, + {"recording-time", required_argument, 0, 't'}, + {"recording-delay", required_argument, 0, 'D'}, + {"log-file", required_argument, 0, 'l'}, + {"kpi-mode", no_argument, 0, 'K'}, + {"interactive", no_argument, 0, 'i'}, + {"source-tracking", no_argument, 0, 'S'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + int opt = 0; + int option_index = 0; + while ((opt = getopt_long(argc, + argv, + "-d:f:F:r:c:s:p:t:D:l:KiSh", + long_options, + &option_index)) != -1) { + switch (opt) { + case 'd': + params[0].input_device = atoll(optarg); + break; + case 'f': + params[0].config.format = atoll(optarg); + break; + case 'F': + params[0].flags = atoll(optarg); + break; + case 'r': + params[0].config.sample_rate = atoi(optarg); + break; + case 'c': + params[0].channels = atoi(optarg); + break; + case 's': + params[0].source = atoi(optarg); + break; + case 'p': + snprintf(params[0].profile, sizeof(params[0].profile), "%s", optarg); + break; + case 't': + params[0].record_length = atoi(optarg); + break; + case 'D': + params[0].record_delay = atoi(optarg); + break; + case 'l': + snprintf(log_filename, sizeof(log_filename), "%s", optarg); + break; + case 'K': + kpi_mode = true; + break; + case 'i': + interactive_mode = true; + break; + case 'S': + source_tracking = true; + break; + case 'h': + usage(); + return 0; + break; + } + } qahw_mod_handle = qahw_load_module(mod_name); if(qahw_mod_handle == NULL) { - printf(" qahw_load_module failed"); + fprintf(log_file, " qahw_load_module failed"); return -1; } -#ifdef MULTIRECORD_SUPPOT - printf("Starting audio hal multi recording test. \n"); - printf(" Enter number of record sessions to be started \n"); - printf(" (Maximum of 4 record sessions are allowed):::: "); - scanf(" %d", &max_recordings_requested); -#else - max_recordings_requested = 1; -#endif - printf(" \n Source Tracking enabled ??? ( 1 - Enable 0 - Disable)::: "); - scanf(" %d", &source_track); - - struct audio_config_params thread1_params, thread2_params; - struct audio_config_params thread3_params, thread4_params; + fprintf(log_file, " Starting audio hal multi recording test. \n"); + if (interactive_mode) { + printf(" Enter logfile path (stdout or 1 for console out)::: \n"); + scanf(" %s", log_filename); + printf(" Enter number of record sessions to be started \n"); + printf(" (Maximum of 4 record sessions are allowed):::: "); + scanf(" %d", &max_recordings_requested); + } else { + max_recordings_requested = 1; + } + if (strcasecmp(log_filename, "stdout") && strcasecmp(log_filename, "1")) { + if ((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; + } + } switch (max_recordings_requested) { case 4: - printf(" Enter the config params for fourth record session \n"); - thread4_params.qahw_mod_handle = qahw_mod_handle; - read_config_params_from_user( &thread4_params, 4); + if (interactive_mode) { + printf(" Enter the config params for fourth record session \n"); + fill_default_params(¶ms[3], 4); + read_config_params_from_user(¶ms[3]); + } + params[3].qahw_mod_handle = qahw_mod_handle; thread_active[3] = 1; printf(" \n"); case 3: - printf(" Enter the config params for third record session \n"); - thread3_params.qahw_mod_handle = qahw_mod_handle; - read_config_params_from_user( &thread3_params, 3); + if (interactive_mode) { + printf(" Enter the config params for third record session \n"); + fill_default_params(¶ms[2], 3); + read_config_params_from_user(¶ms[2]); + } + params[2].qahw_mod_handle = qahw_mod_handle; thread_active[2] = 1; printf(" \n"); case 2: - printf(" Enter the config params for second record session \n"); - thread2_params.qahw_mod_handle = qahw_mod_handle; - read_config_params_from_user( &thread2_params, 2); + if (interactive_mode) { + printf(" Enter the config params for second record session \n"); + fill_default_params(¶ms[1], 2); + read_config_params_from_user(¶ms[1]); + } + params[1].qahw_mod_handle = qahw_mod_handle; thread_active[1] = 1; printf(" \n"); case 1: - printf(" Enter the config params for first record session \n"); - thread1_params.qahw_mod_handle = qahw_mod_handle; - read_config_params_from_user( &thread1_params, 1); + if (interactive_mode) { + printf(" Enter the config params for first record session \n"); + fill_default_params(¶ms[0], 1); + read_config_params_from_user(¶ms[0]); + } + params[0].qahw_mod_handle = qahw_mod_handle; thread_active[0] = 1; printf(" \n"); break; default: - printf(" INVALID input -- Max record sessions supported is 4 -exit \n"); - gerror = true; + fprintf(log_file, " INVALID input -- Max record sessions supported is 4 -exit \n"); + if (log_file != stdout) + fprintf(stdout, " INVALID input -- Max record sessions supported is 4 -exit \n"); + status = -1; break; } + if (interactive_mode && status == 0) { + int option = 0; + + printf(" \n Source Tracking enabled ??? ( 1 - Enable 0 - Disable)::: "); + scanf(" %d", &option); + source_tracking = option ? true : false; + + printf(" \n Measure latency KPI values ??? ( 1 - Enable 0 - Disable)::: "); + scanf(" %d", &option); + kpi_mode = option ? true : false; + + while(true) { + char ch = 'y'; + printf(" \n SetParam command required ??? (y/n)::: "); + scanf(" %c", &ch); + if (ch != 'y' && ch != 'Y') + break; + struct timed_params *param = (struct timed_params *) + calloc(1, sizeof(struct timed_params)); + if (param == NULL) { + fprintf(log_file, " \n Failed to alloc memory for param, ignoring param conf\n\n"); + if (log_file != stdout) + fprintf(stdout, " \n Failed to alloc memory for param, ignoring param conf\n\n"); + continue; + } + printf(" \n Enter param kv pair :::: "); + scanf(" %s", param->param); + printf(" \n Enter param delay in sec (time after which param need to be set):::: "); + scanf(" %d", ¶m->param_delay); + + list_add_tail(¶m_list, ¶m->list); + } + } pthread_t tid[4]; pthread_t sourcetrack_thread; int ret = -1; if (thread_active[0] == 1) { - printf("\n Create first record thread \n"); - ret = pthread_create(&tid[0], NULL, start_input, (void *)&thread1_params); + fprintf(log_file, "\n Create first record thread \n"); + ret = pthread_create(&tid[0], NULL, start_input, (void *)¶ms[0]); if (ret) { - gerror = true; - printf(" Failed to create first record thread \n "); + status = -1; + fprintf(log_file, " Failed to create first record thread \n "); + if (log_file != stdout) + fprintf(stdout, " Failed to create first record thread \n "); thread_active[0] = 0; } } if (thread_active[1] == 1) { - printf("Create second record thread \n"); - ret = pthread_create(&tid[1], NULL, start_input, (void *)&thread2_params); + fprintf(log_file, "Create second record thread \n"); + ret = pthread_create(&tid[1], NULL, start_input, (void *)¶ms[1]); if (ret) { - gerror = true; - printf(" Failed to create second record thread \n "); + status = -1; + fprintf(log_file, " Failed to create second record thread \n "); + if (log_file != stdout) + fprintf(stdout, " Failed to create second record thread \n "); thread_active[1] = 0; } } if (thread_active[2] == 1) { - printf("Create third record thread \n"); - ret = pthread_create(&tid[2], NULL, start_input, (void *)&thread3_params); + fprintf(log_file, "Create third record thread \n"); + ret = pthread_create(&tid[2], NULL, start_input, (void *)¶ms[2]); if (ret) { - gerror = true; - printf(" Failed to create third record thread \n "); + status = -1; + fprintf(log_file, " Failed to create third record thread \n "); + if (log_file != stdout) + fprintf(stdout, " Failed to create third record thread \n "); thread_active[2] = 0; } } if (thread_active[3] == 1) { - printf("Create fourth record thread \n"); - ret = pthread_create(&tid[3], NULL, start_input, (void *)&thread4_params); + fprintf(log_file, "Create fourth record thread \n"); + ret = pthread_create(&tid[3], NULL, start_input, (void *)¶ms[3]); if (ret) { - gerror = true; - printf(" Failed to create fourth record thread \n "); + status = -1; + fprintf(log_file, " Failed to create fourth record thread \n "); + if (log_file != stdout) + fprintf(stdout, " Failed to create fourth record thread \n "); thread_active[3] = 0; } } - if (source_track && max_recordings_requested) { - printf("Create source tracking thread \n"); + if (source_tracking && max_recordings_requested) { + fprintf(log_file, "Create source tracking thread \n"); ret = pthread_create(&sourcetrack_thread, NULL, read_sourcetrack_data, (void *)qahw_mod_handle); if (ret) { - printf(" Failed to create source tracking thread \n "); - source_track = 0; + fprintf(log_file, " Failed to create source tracking thread \n "); + if (log_file != stdout) + fprintf(stdout, " Failed to create source tracking thread \n "); + source_tracking = 0; } } + fprintf(log_file, " All threads started \n"); + if (log_file != stdout) + fprintf(stdout, " All threads started \n"); - // set bad mic param - while (max_recordings_requested && !source_track) { - bool test_completed = false; - - pthread_mutex_lock(&glock); - if (!tests_running && !gerror) - pthread_cond_wait(&gcond, &glock); - test_completed = (tests_running == 0); - gerror = true; - pthread_mutex_unlock(&glock); - - if (test_completed) - break; -#ifdef MULTIRECORD_SUPPOT - char ch; - printf("\n Bad mic test required (y/n):::"); - scanf(" %c", &ch); - if (ch == 'y' || ch == 'Y') { - int bad_mic_ch_index, ret; - char param[100] = "bad_mic_channel_index="; - printf("\nEnter bad mic channel index (1, 2, 4 ...):::"); - scanf(" %d", &bad_mic_ch_index); - snprintf(param, sizeof(param), "%s%d", param, bad_mic_ch_index); - ret = qahw_set_parameters(qahw_mod_handle, param); - printf("param %s set to hal with return value %d\n", param, ret); - } else { - break; + /* set params if queued */ + time_t start_time = time(0); + while (!list_empty(¶m_list)) { + struct listnode *node, *tempnode; + struct timed_params *param; + time_t curr_time = time(0); + list_for_each_safe(node, tempnode, ¶m_list) { + param = node_to_item(node, struct timed_params, list); + if (curr_time - start_time > param->param_delay || + (tests_completed > 0 && tests_running == 0)) { + if (curr_time - start_time > param->param_delay) { + ret = qahw_set_parameters(qahw_mod_handle, param->param); + fprintf(log_file, " param %s set to hal with return value %d\n", param->param, ret); + } + list_remove(¶m->list); + free(param); + } } -#endif + usleep(10000); } - printf(" Waiting for threads exit \n"); + fprintf(log_file, " Waiting for threads exit \n"); + if (log_file != stdout) + fprintf(stdout, " Waiting for threads exit \n"); if (thread_active[0] == 1) { pthread_join(tid[0], NULL); - printf("after first record thread exit \n"); + fprintf(log_file, " after first record thread exit \n"); } if (thread_active[1] == 1) { pthread_join(tid[1], NULL); - printf("after second record thread exit \n"); + fprintf(log_file, " after second record thread exit \n"); } if (thread_active[2] == 1) { pthread_join(tid[2], NULL); - printf("after third record thread exit \n"); + fprintf(log_file, " after third record thread exit \n"); } if (thread_active[3] == 1) { pthread_join(tid[3], NULL); - printf("after fourth record thread exit \n"); + fprintf(log_file, " after fourth record thread exit \n"); } - if (source_track) { - sourcetrack_done = 1; + if (source_tracking) { pthread_join(sourcetrack_thread,NULL); - printf("after source tracking thread exit \n"); + fprintf(log_file, " after source tracking thread exit \n"); } ret = qahw_unload_module(qahw_mod_handle); if (ret) { - printf("could not unload hal %d \n",ret); + fprintf(log_file, "could not unload hal %d \n",ret); } - - printf("Done with hal record test \n"); - pthread_cond_destroy(&gcond); + fprintf(log_file, "\n Done with hal record test \n"); + if (log_file != stdout) { + fprintf(stdout, "\n Done with hal record test \n"); + fclose(log_file); + } return 0; }