From 141cb56fca7001a04b8558deb6f0f77c567252e0 Mon Sep 17 00:00:00 2001 From: Manish Dewangan Date: Tue, 27 Sep 2016 11:58:05 +0530 Subject: [PATCH] qahw: test: Initial qahw api test app changes -Add qahw test app changes for record and playback. Change-Id: I661cc01497dfd6f8dde0d9206c8ef39ec92f499e --- qahw_api/Android.mk | 2 + qahw_api/test/Android.mk | 40 ++ qahw_api/test/qahw_multi_record_test.c | 488 +++++++++++++++++++++++++ qahw_api/test/qahw_playback_test.c | 205 +++++++++++ 4 files changed, 735 insertions(+) create mode 100644 qahw_api/test/Android.mk create mode 100644 qahw_api/test/qahw_multi_record_test.c create mode 100644 qahw_api/test/qahw_playback_test.c diff --git a/qahw_api/Android.mk b/qahw_api/Android.mk index e35b67b4..3c02f51d 100644 --- a/qahw_api/Android.mk +++ b/qahw_api/Android.mk @@ -28,4 +28,6 @@ LOCAL_PROPRIETARY_MODULE := true include $(BUILD_SHARED_LIBRARY) +#test app compilation +include $(LOCAL_PATH)/test/Android.mk endif diff --git a/qahw_api/test/Android.mk b/qahw_api/test/Android.mk new file mode 100644 index 00000000..16880694 --- /dev/null +++ b/qahw_api/test/Android.mk @@ -0,0 +1,40 @@ +LOCAL_PATH := $(call my-dir) + +# audio_hal_playback_test +# ============================================================================== +include $(CLEAR_VARS) +LOCAL_SRC_FILES := qahw_playback_test.c +LOCAL_MODULE := hal_play_test + +hal-play-inc = $(TARGET_OUT_HEADERS)/mm-audio/qahw_api/inc + +LOCAL_CFLAGS += -Wall -Werror -Wno-sign-compare + +LOCAL_SHARED_LIBRARIES := \ + libaudioutils\ + libqahw \ + libutils + +LOCAL_32_BIT_ONLY := true + +LOCAL_C_INCLUDES += $(hal-play-inc) + +include $(BUILD_EXECUTABLE) + +# audio_hal_multi_record_test +# ============================================================================== +include $(CLEAR_VARS) +LOCAL_SRC_FILES := qahw_multi_record_test.c +LOCAL_MODULE := hal_rec_test +LOCAL_CFLAGS += -Wall -Werror -Wno-sign-compare +LOCAL_SHARED_LIBRARIES := \ + libaudioutils \ + libqahw \ + libutils + +LOCAL_32_BIT_ONLY := true + +hal-rec-inc = $(TARGET_OUT_HEADERS)/mm-audio/qahw_api/inc + +LOCAL_C_INCLUDES += $(hal-rec-inc) +include $(BUILD_EXECUTABLE) diff --git a/qahw_api/test/qahw_multi_record_test.c b/qahw_api/test/qahw_multi_record_test.c new file mode 100644 index 00000000..07dede74 --- /dev/null +++ b/qahw_api/test/qahw_multi_record_test.c @@ -0,0 +1,488 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2015 The Android Open Source Project * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Test app to record multiple audio sessions at the HAL layer */ + +#include +#include +#include +#include +#include +#include +#include "qahw_api.h" +#include "qahw_defs.h" + +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; + char profile[50]; +}; + +#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) +{ + char kvpair_soundfocus[200] = SOUNDFOCUS_PARAMS; + char kvpair_sourcetrack[200] = SOURCETRACK_PARAMS; + char *string = NULL; + char *token = NULL; + char choice = '\0'; + int i =0; + qahw_module_handle_t *qawh_module_handle = + (qahw_module_handle_t *)data; + + while (1) { + printf("\nGet SoundFocus Params from app"); + string = qahw_get_parameters(qawh_module_handle, kvpair_soundfocus); + if (!string) { + printf("Error.Failed Get SoundFocus Params\n"); + } else { + token = strtok (string , "="); + while (token) { + if (*token == 'S') { + choice = *(token + 11); + token = strtok (NULL,",;"); + i=0; + } + switch (choice) { + case 'g': + printf ("\nSoundFocus.gain_step=%s",token); + break; + case 'e': + printf ("\nSoundFocus.enable_sectors[%d]=%s",i,token); + i++; + break; + case 's': + printf ("\nSoundFocus.start_angles[%d]=%s",i,token); + i++; + break; + } + token = strtok (NULL,",;="); + } + } + choice = '\0'; + printf ("\nGet SourceTracking Params from app"); + string = qahw_get_parameters(qawh_module_handle, kvpair_sourcetrack); + if (!string) { + printf ("Error.Failed Get SourceTrack Params\n"); + } else { + token = strtok (string , "="); + while (token) { + if (*token == 'S') { + choice = *(token + 12); + if (choice == 'd') + choice = *(token + 16); + token = strtok (NULL,",;"); + i=0; + } + switch (choice) { + case 'p': + printf ("\nSourceTrack.polar_activity=%s,",token); + choice = '\0'; + break; + case 'v': + printf ("\nSourceTrack.vad[%d]=%s",i,token); + i++; + break; + case 's': + printf ("\nSourceTrack.doa_speech=%s",token); + break; + case 'n': + printf ("\nSourceTrack.doa_noise[%d]=%s",i,token); + i++; + break; + default : + printf ("%s,",token); + break; + } + token = strtok (NULL,",;="); + } + } + if (sourcetrack_done == 1) + return NULL; + } +} + +void *start_input(void *thread_param) +{ + int rc = 0; + 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. + 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); + if (rc) { + printf("ERROR :::: Could not open input stream.\n" ); + pthread_mutex_lock(&glock); + gerror = true; + pthread_cond_signal(&gcond); + pthread_mutex_unlock(&glock); + 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); + if (buffer == NULL) { + printf("calloc failed!!\n"); + pthread_mutex_lock(&glock); + gerror = true; + pthread_cond_signal(&gcond); + pthread_mutex_unlock(&glock); + 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 + 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); + + FILE *fd = fopen(params->output_filename,"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); + } + pthread_mutex_lock(&glock); + tests_running++; + pthread_cond_signal(&gcond); + pthread_mutex_unlock(&glock); + memset(&in_buf,0, sizeof(qahw_in_buffer_t)); + + while(true) { + 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; + } + } + + printf("closing input"); + + // Close output stream and device. + rc = qahw_in_standby(in_handle); + if (rc) { + printf("out standby failed %d \n",rc); + } + + rc = qahw_close_input_stream(in_handle); + if (rc) { + printf("could not close input stream %d \n",rc); + } + + // Print instructions to access the file. + printf("\nThe 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); + + pthread_mutex_lock(&glock); + tests_running--; + pthread_cond_signal(&gcond); + pthread_mutex_unlock(&glock); + pthread_exit(0); + 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"; + + 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; + + 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 (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 the sample rate (48000, 16000 etc) :::: "); + scanf(" %d", &sample_rate); + thread_param->config.sample_rate = sample_rate; + +#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 record duration in seconds :::: "); + scanf(" %lf", &thread_param->loopTime); + return 0; +} + +int main() { + int max_recordings_requested = 0, source_track = 0; + int thread_active[4] = {0}; + qahw_module_handle_t *qahw_mod_handle; + const char *mod_name = "audio.primary"; + + pthread_cond_init(&gcond, (const pthread_condattr_t *) NULL); + + qahw_mod_handle = qahw_load_module(mod_name); + if(qahw_mod_handle == NULL) { + printf(" 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; + + 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); + 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); + 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); + 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); + thread_active[0] = 1; + printf(" \n"); + break; + default: + printf(" INVALID input -- Max record sessions supported is 4 -exit \n"); + gerror = true; + break; + } + + 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); + if (ret) { + gerror = true; + printf(" 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); + if (ret) { + gerror = true; + printf(" 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); + if (ret) { + gerror = true; + printf(" 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); + if (ret) { + gerror = true; + printf(" Failed to create fourth record thread \n "); + thread_active[3] = 0; + } + } + if (source_track && max_recordings_requested) { + printf("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; + } + } + + // 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; + } +#endif + } + + printf(" Waiting for threads exit \n"); + if (thread_active[0] == 1) { + pthread_join(tid[0], NULL); + printf("after first record thread exit \n"); + } + if (thread_active[1] == 1) { + pthread_join(tid[1], NULL); + printf("after second record thread exit \n"); + } + if (thread_active[2] == 1) { + pthread_join(tid[2], NULL); + printf("after third record thread exit \n"); + } + if (thread_active[3] == 1) { + pthread_join(tid[3], NULL); + printf("after fourth record thread exit \n"); + } + if (source_track) { + sourcetrack_done = 1; + pthread_join(sourcetrack_thread,NULL); + printf("after source tracking thread exit \n"); + } + + ret = qahw_unload_module(qahw_mod_handle); + if (ret) { + printf("could not unload hal %d \n",ret); + } + + + printf("Done with hal record test \n"); + pthread_cond_destroy(&gcond); + return 0; +} diff --git a/qahw_api/test/qahw_playback_test.c b/qahw_api/test/qahw_playback_test.c new file mode 100644 index 00000000..84269452 --- /dev/null +++ b/qahw_api/test/qahw_playback_test.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2015 The Android Open Source Project * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Test app to play audio at the HAL layer */ + +#include +#include +#include +#include +#include "qahw_api.h" +#include "qahw_defs.h" +#define nullptr NULL +#define WAV 1 +#define MP3 2 + + +/* 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. +*/ + +int play_file(qahw_stream_handle_t* out_handle, FILE* in_file) { + + int rc = 0; + size_t frames_read = 1; + size_t bytes_wanted ; + char *data = NULL; + qahw_out_buffer_t out_buf; + + bytes_wanted = qahw_out_get_buffer_size(out_handle); + data = (char *) malloc (bytes_wanted); + if (data == NULL) { + printf("calloc failed!!\n"); + return -ENOMEM; + } + + while(frames_read != 0) { + frames_read = fread(data, bytes_wanted , 1, in_file); + if (frames_read < 1) { + if (feof(in_file)) + break; + else + printf("Error in fread --%d\n",ferror(in_file)); + } + memset(&out_buf,0, sizeof(qahw_out_buffer_t)); + out_buf.buffer = data; + out_buf.bytes = frames_read * bytes_wanted; + rc = qahw_out_write(out_handle, &out_buf); + if (rc < 0) { + printf("Writing data to hal failed %d \n",rc); + break; + } + } + return rc; +} + +// Prints usage information if input arguments are missing. +void Usage() { + fprintf(stderr, "Usage:hal_play [device] [filename] [filetype]\n" + "device: hex value representing the audio device (see " + "system/media/audio/include/system/audio.h)\n" + "filename must be passed as an argument.\n" + "filetype (1:WAV 2:MP3) \n"); +} + +int main(int argc, char* argv[]) { + if (argc < 4) { + Usage(); + return -1; + } + // Process command line arguments. + FILE *filestream = NULL; + char header[44] = {0}; + int sample_rate = 0; + int channels = 0; + const int audio_device_base = 16; + char* filename = nullptr; + int filetype; + qahw_module_handle_t *qahw_mod_handle; + const char *mod_name = "audio.primary"; + + uint32_t desired_output_device = strtol( + argv[1], nullptr /* look at full string*/, audio_device_base); + + filename = argv[2]; + filetype = atoi (argv[3]); + + printf("Starting audio hal tests.\n"); + int rc = 0; + + qahw_mod_handle = qahw_load_module(mod_name); + + // Set to a high number so it doesn't interfere with existing stream handles + audio_io_handle_t handle = 0x999; + audio_devices_t output_device = + (audio_devices_t)desired_output_device; + audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; + audio_config_t config; + + memset(&config, 0, sizeof(audio_config_t)); + + if (filename) { + printf("filename-----%s\n",filename); + filestream = fopen (filename,"r"); + if (filestream == NULL) { + printf("failed to open\n"); + exit(0); + } + } + + switch (filetype) { + case WAV: + //Read the wave header + rc = fread (header, 44 , 1, filestream); + if (rc != 1) { + printf("Error .Fread failed\n"); + exit(0); + } + if (strncmp (header,"RIFF",4) && strncmp (header+8, "WAVE",4)) { + printf("Not a wave format\n"); + exit (1); + } + memcpy (&channels, &header[22], 2); + memcpy (&sample_rate, &header[24], 4); + config.channel_mask = audio_channel_out_mask_from_count(channels); + config.offload_info.channel_mask = config.channel_mask; + config.offload_info.sample_rate = sample_rate; + config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT; + break; + case MP3: + printf("Enter Number of channels:"); + scanf ("%d",&channels); + config.channel_mask = audio_channel_out_mask_from_count(channels); + printf("\nEnter Sample Rate:"); + scanf ("%d",&sample_rate); + config.offload_info.channel_mask = config.channel_mask; + config.offload_info.sample_rate = sample_rate; + config.offload_info.format = AUDIO_FORMAT_MP3; + break; + default: + printf("Does not support given filetype\n"); + Usage(); + exit (0); + } + config.offload_info.version = AUDIO_OFFLOAD_INFO_VERSION_CURRENT; + config.offload_info.size = sizeof(audio_offload_info_t); + + printf("Now playing to output_device=%d sample_rate=%d \n",output_device, + config.offload_info.sample_rate); + const char* stream_name = "output_stream"; + + // Open audio output stream. + qahw_stream_handle_t* out_handle = nullptr; + printf("calling open_out_put_stream:\n"); + rc = qahw_open_output_stream(qahw_mod_handle, handle, output_device, + flags, &config, &out_handle, + stream_name); + printf("open output stream is sucess:%d out_handhle %p\n",rc,out_handle); + if (rc) { + printf("could not open output stream %d \n",rc); + return -1; + } + + play_file(out_handle, filestream); + + // Close output stream and device. + rc = qahw_out_standby(out_handle); + if (rc) { + printf("out standby failed %d \n",rc); + } + + rc = qahw_close_output_stream(out_handle); + if (rc) { + printf("could not close output stream %d \n",rc); + } + + rc = qahw_unload_module(qahw_mod_handle); + if (rc) { + printf("could not unload hal %d \n",rc); + return -1; + } + + printf("Done with hal tests \n"); + return 0; +}