qahw: Add support for voice tester
Add support for voice tester.
Change-Id: I7573ca4eb25be722f7e4b6005d86cb55d016c8c8
diff --git a/qahw_api/test/Makefile.am b/qahw_api/test/Makefile.am
index 40cc24a..97e7438 100644
--- a/qahw_api/test/Makefile.am
+++ b/qahw_api/test/Makefile.am
@@ -41,3 +41,27 @@
trans_loopback_test_CFLAGS = $(AM_CFLAGS) -Wno-sign-compare -Werror
trans_loopback_test_CFLAGS += $(trans_loopback_test_INCLUDES)
trans_loopback_test_LDADD = -llog -lutils ../libqahw.la -lcutils -lm
+
+if QAHW_V1
+bin_PROGRAMS += hal_voice_test
+
+VOICE_CFLAGS = -Wno-sign-compare -Werror
+VOICE_CFLAGS += -D__unused=__attribute__\(\(__unused__\)\)
+VOICE_INCLUDES = -I $(top_srcdir)/qahw_api/inc
+VOICE_INCLUDES += -I $(top_srcdir)/qahw/inc
+
+hal_voice_test_SOURCES = qahw_voice_test.c
+
+hal_voice_test_LDADD = -lutils ../libqahw.la
+AM_CFLAGS = -I $(PKG_CONFIG_SYSROOT_DIR)/usr/include/mm-audio/qahw/inc
+
+if QAP
+AM_CFLAGS += -DQAP
+AM_CFLAGS += -I ${WORKSPACE}/audio/mm-audio/qap_wrapper/inc/
+hal_voice_test_SOURCES += qap_wrapper_extn.c
+hal_voice_test_LDADD += -lqap_wrapper
+endif
+
+hal_voice_test_CFLAGS = $(VOICE_CFLAGS) $(VOICE_INCLUDES)
+hal_voice_test_CFLAGS += $(AM_CFLAGS) -DLINUX_ENABLED
+endif
diff --git a/qahw_api/test/qahw_voice_test.c b/qahw_api/test/qahw_voice_test.c
new file mode 100644
index 0000000..96da2c6
--- /dev/null
+++ b/qahw_api/test/qahw_voice_test.c
@@ -0,0 +1,675 @@
+/*
+* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Test app for voice call */
+
+#include "qahw_voice_test.h"
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+#define WAV_HEADER_LENGTH_MAX 128
+#define FORMAT_DESCRIPTOR_SIZE 12
+#define SUBCHUNK1_SIZE(x) ((8) + (x))
+#define SUBCHUNK2_SIZE 8
+
+voice_stream_config stream_params;
+volatile bool stop = false;
+void *context = NULL;
+
+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;
+};
+
+static void init_stream(void) {
+ stream_params.vsid = "11C05000";
+ stream_params.qahw_mod_handle = NULL;
+ stream_params.call_length = -1; /*infinite*/
+ stream_params.multi_call = 1;
+ stream_params.output_device[0] = AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ stream_params.output_device[1] = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ stream_params.in_call_rec = false;
+ stream_params.in_call_playback = false;
+ stream_params.hpcm = false;
+ stream_params.hpcm_tp = 2;
+ stream_params.tp_dir = 0;
+ stream_params.rec_file = "/data/default_rec.wav";
+ stream_params.playback_file = NULL;
+ stream_params.vol = .75;
+ stream_params.mute = false;
+ stream_params.mute_dir = 0;
+ stream_params.tty_mode = 0;
+ stream_params.dtmf_gen_enable = 0;
+ stream_params.dtmf_freq_low = 697;
+ stream_params.dtmf_freq_high = 1209;
+ stream_params.dtmf_gain = 100;
+}
+
+void usage() {
+ printf(" \n Command \n");
+ printf(" \n hal_voice_test <options> - starts voice call\n");
+ printf(" \n Options\n");
+ printf(" -i --vsid <vsid> - vsid to use sim1<297816064> sim2<29965107>.\n");
+ printf(" -d --device <decimal value> - see system/media/audio/include/system/audio.h for device values\n");
+ printf(" -l --length <call length> - call length in sec.\n");
+ printf(" -m --multi_call <number of calls> - number of calls to make.\n");
+ printf(" -r --in_call_rec <filename to record to> -t - tp_dir <0 = DL, 1 = UL, 2 = BOTH >\n");
+ printf(" -p --in_call_playback <filename to play from> play audio to voice call\n");
+ printf(" -v --vol <val> - volume.\n");
+ printf(" -u --mute <dir> - <dir 0= tx, 1 = rx> .\n");
+ printf(" -c --dtmf_gen .\n");
+ printf(" -y --tty_mode - <MODE_OFF = 0, MODE_FULL = 1, MODE_VCO = 2, MODE_HCO = 3\n");
+}
+
+void stop_signal_handler(int signal __unused) {
+ stop = true;
+}
+
+static void qti_audio_server_death_notify_cb(void *ctxt __unused) {
+ fprintf(stderr, "qas died\n");
+ stop = true;
+}
+
+void *rec_start(void *thread_param) {
+ uint32_t rc = 0;
+ voice_stream_config *params = (voice_stream_config *)thread_param;
+ qahw_module_handle_t *qahw_mod_handle = params->qahw_mod_handle;
+ qahw_stream_handle_t *in_handle = NULL;
+ uint32_t num_dev = 1;
+ audio_devices_t in_device[1] = { AUDIO_DEVICE_IN_BUILTIN_MIC };
+ struct qahw_stream_attributes attr;
+ qahw_buffer_t in_buf;
+ int data_sz = 0;
+ ssize_t bytes_read = -1;
+
+ fprintf(stderr, "%s starting rec thread\n", __func__);
+ if (qahw_mod_handle == NULL) {
+ fprintf(stderr, " qahw_load_module failed\n");
+ pthread_exit(0);
+ }
+ if(params->in_call_rec) {
+ fprintf(stderr, " setting in call record params\n");
+ switch (params->tp_dir) {
+ case 0:
+ attr.type = QAHW_AUDIO_CAPTURE_VOICE_CALL_RX;
+ break;
+ case 1:
+ attr.type = QAHW_AUDIO_CAPTURE_VOICE_CALL_TX;
+ break;
+ default:
+ fprintf(stderr, " invalid tp direction");
+ pthread_exit(0);
+ break;
+ }
+ attr.attr.audio.config.sample_rate = 48000;
+ }
+ if(params->hpcm) {
+ fprintf(stderr, "setting host pcm params\n");
+ switch(params->hpcm_tp) {
+ case QAHW_HPCM_TAP_POINT_RX:
+ attr.type = QAHW_AUDIO_HOST_PCM_RX;
+ break;
+ case QAHW_HPCM_TAP_POINT_TX:
+ attr.type = QAHW_AUDIO_HOST_PCM_TX;
+ break;
+ default:
+ fprintf(stderr, "unsupported tp %d\n", params->hpcm_tp);
+ pthread_exit(0);
+ break;
+ }
+ attr.attr.audio.config.sample_rate = 8000;
+ }
+ attr.direction = QAHW_STREAM_INPUT;
+ attr.attr.audio.config.format = AUDIO_FORMAT_PCM_16_BIT;
+
+ rc = qahw_stream_open(qahw_mod_handle,
+ attr,
+ num_dev,
+ in_device,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ &(in_handle));
+ if (rc) {
+ fprintf(stderr, " open input device failed!\n");
+ pthread_exit(0);
+ }
+
+ /* Get buffer size to get upper bound on data to read from the HAL */
+ size_t buffer_size;
+ rc = qahw_stream_get_buffer_size(in_handle, &buffer_size, NULL);
+ char *buffer = (char *)calloc(1, buffer_size);
+ size_t written_size;
+ int bps = 16;
+
+ if (buffer == NULL) {
+ fprintf(stderr, "calloc failed!!, handle(%d)\n", in_handle);
+ pthread_exit(0);
+ }
+ if (params->rec_file == NULL) {
+ fprintf(stderr, "no record stream provided\n", in_handle);
+ pthread_exit(0);
+ return NULL;
+ }
+ FILE *fd = fopen(params->rec_file, "w");
+ if (fd == NULL) {
+ fprintf(stderr, "File open failed \n");
+ free(buffer);
+ pthread_exit(0);
+ }
+ 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 = 1;
+ hdr.sample_rate = attr.attr.audio.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_buffer_t));
+ fprintf(stderr, "file %s opened for write", params->rec_file);
+ while (true && !stop) {
+ in_buf.buffer = buffer;
+ in_buf.size = buffer_size;
+
+ bytes_read = qahw_stream_read(in_handle, &in_buf);
+
+ written_size = fwrite(in_buf.buffer, 1, buffer_size, fd);
+ if (written_size < buffer_size) {
+ fprintf(stderr, "Error in fwrite\n");
+ break;
+ }
+ data_sz += buffer_size;
+ }
+ fprintf(stderr, "rec ended\n");
+ /* 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);
+ free(buffer);
+ fclose(fd);
+ fd = NULL;
+ fprintf(stderr, " closing input, handle(%d)", in_handle);
+
+ /* Close input stream and device. */
+ rc = qahw_stream_standby(in_handle);
+ if (rc) {
+ fprintf(stderr, "out standby failed %d, handle(%d)\n", rc, in_handle);
+ }
+
+ rc = qahw_stream_close(in_handle);
+ if (rc) {
+ fprintf(stderr, "could not close input stream %d, handle(%d)\n", rc, in_handle);
+ }
+
+ /* Print instructions to access the file.
+ * Caution: Below ADL log shouldnt be altered without notifying automation APT since it used for
+ * automation testing
+ */
+ fprintf(stderr, "\n\n ADL: 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\n\n",
+ params->rec_file, attr.attr.audio.config.sample_rate, attr.attr.audio.config.format, 1);
+ pthread_exit(0);
+
+ return NULL;
+}
+
+int get_wav_header_length(FILE *file_stream) {
+ int subchunk_size = 0;
+ int wav_header_len = 0;
+
+ fseek(file_stream, 16, SEEK_SET);
+ if (fread(&subchunk_size, 4, 1, file_stream) != 1) {
+ fprintf(stderr, "Unable to read subchunk:\n");
+ exit(1);
+ }
+ if (subchunk_size < 16) {
+ fprintf(stderr, "This is not a valid wav file \n");
+ } else {
+ wav_header_len = FORMAT_DESCRIPTOR_SIZE + SUBCHUNK1_SIZE(subchunk_size) + SUBCHUNK2_SIZE;
+ }
+ return wav_header_len;
+}
+
+void *playback_start(void *thread_param) {
+ uint32_t rc = 0;
+ voice_stream_config *params = (voice_stream_config *)thread_param;
+ qahw_module_handle_t *qahw_mod_handle = params->qahw_mod_handle;
+ qahw_stream_handle_t *out_handle = NULL;
+ uint32_t num_dev = 1;
+ audio_devices_t out_device[1] = { AUDIO_DEVICE_OUT_WIRED_HEADSET };
+ struct qahw_stream_attributes attr;
+ size_t bytes_wanted = 0;
+ size_t write_length = 0;
+ size_t bytes_remaining = 0;
+ ssize_t bytes_written = 0;
+ FILE *fp = NULL;
+ size_t bytes_read = 0;
+ qahw_buffer_t out_buf;
+ char *data_ptr = NULL;
+ bool exit = false;
+ bool read_complete_file = true;
+ int wav_header_len;
+ char header[WAV_HEADER_LENGTH_MAX] = { 0 };
+
+ if (qahw_mod_handle == NULL) {
+ fprintf(stderr, " qahw_load_module failed");
+ pthread_exit(0);
+ }
+
+ attr.direction = QAHW_STREAM_OUTPUT;
+ if(params->in_call_playback) {
+ attr.type = QAHW_AUDIO_PLAYBACK_VOICE_CALL_MUSIC;
+ attr.attr.audio.config.sample_rate = 48000;
+ attr.attr.audio.config.format = AUDIO_FORMAT_PCM_16_BIT;
+ }
+ if(params->hpcm) {
+ switch(params->hpcm_tp) {
+ case QAHW_HPCM_TAP_POINT_RX:
+ attr.type = QAHW_AUDIO_HOST_PCM_RX;
+ break;
+ case QAHW_HPCM_TAP_POINT_TX:
+ attr.type = QAHW_AUDIO_HOST_PCM_TX;
+ break;
+ default:
+ fprintf(stderr, "unsupported tp %d\n", params->hpcm_tp);
+ pthread_exit(0);
+ break;
+ }
+ attr.attr.audio.config.sample_rate = 8000;
+ attr.attr.audio.config.format = AUDIO_FORMAT_PCM_16_BIT;
+ }
+
+
+ if (params->playback_file != NULL)
+ fp = fopen(params->playback_file, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "failed to open file %s\n", params->playback_file);
+ pthread_exit(0);
+ }
+ /*
+ * Read the wave header
+ */
+ if ((wav_header_len = get_wav_header_length(fp)) <= 0) {
+ fprintf(stderr, "wav header length is invalid:%d\n", wav_header_len);
+ pthread_exit(0);
+ }
+ fseek(fp, 0, SEEK_SET);
+ rc = fread(header, wav_header_len, 1, fp);
+ if (rc != 1) {
+ fprintf(stderr, "Error fread failed\n");
+ pthread_exit(0);
+ }
+ if (strncmp(header, "RIFF", 4) && strncmp(header + 8, "WAVE", 4)) {;
+ fprintf(stderr, "Not a wave format\n");
+ pthread_exit(0);
+ }
+ //memcpy (&stream_info->channels, &header[22], 2);
+ memcpy(&attr.attr.audio.config.offload_info.sample_rate, &header[24], 4);
+ memcpy(&attr.attr.audio.config.offload_info.bit_width, &header[34], 2);
+ if (attr.attr.audio.config.offload_info.bit_width == 32)
+ attr.attr.audio.config.offload_info.format = AUDIO_FORMAT_PCM_32_BIT;
+ else if (attr.attr.audio.config.offload_info.bit_width == 24)
+ attr.attr.audio.config.offload_info.format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+ else
+ attr.attr.audio.config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
+
+ attr.attr.audio.config.sample_rate = attr.attr.audio.config.offload_info.sample_rate;
+ attr.attr.audio.config.format = attr.attr.audio.config.offload_info.format;
+
+ rc = qahw_stream_open(qahw_mod_handle,
+ attr,
+ num_dev,
+ out_device,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ &(out_handle));
+
+ if (rc) {
+ fprintf(stderr, " open output device failed!\n");
+ pthread_exit(0);
+ }
+ rc = qahw_stream_get_buffer_size(out_handle ,NULL, &bytes_wanted);
+ data_ptr = (char *)malloc(bytes_wanted);
+ if (data_ptr == NULL) {
+ fprintf(stderr, "failed to allocate data buffer\n");
+ pthread_exit(0);
+ }
+
+ while (!exit && !stop) {
+ if (!bytes_remaining) {
+ bytes_read = fread(data_ptr, 1, bytes_wanted, fp);
+ fprintf(stderr, "read bytes %zd\n", bytes_read);
+ bytes_remaining = write_length = bytes_read;
+ }
+
+ bytes_written = bytes_remaining;
+ memset(&out_buf, 0, sizeof(qahw_buffer_t));
+ out_buf.buffer = data_ptr;
+ out_buf.size = bytes_remaining;
+ bytes_written = qahw_stream_write(out_handle, &out_buf);
+ if (bytes_written <= 0) {
+ fprintf(stderr, "write end %d", bytes_written);
+ exit = true;
+ continue;
+ }
+ bytes_remaining -= bytes_written;
+ }
+
+ fclose(fp);
+ if (data_ptr)
+ free(data_ptr);
+
+ qahw_stream_close(out_handle);
+
+ return NULL;
+}
+
+int main(int argc, char *argv[]) {
+
+ uint32_t rc = 0;
+ int opt = 0;
+ int option_index = 0;
+ qahw_stream_direction dir;
+ int call_count = 0;
+ int call_lenght = 0;
+ pthread_t tid_rec;
+ pthread_t tid_pb;
+
+ init_stream();
+
+ struct option long_options[] = {
+ /* These options set a flag. */
+ { "vsid", required_argument, 0, 'i' },
+ { "device", required_argument, 0, 'd' },
+ { "call_length", required_argument, 0, 'l' },
+ { "help", no_argument, 0, 'h' },
+ { "in_call_playback", required_argument, 0, 'p' },
+ { "in_call_rec", required_argument, 0, 'r' },
+ { "host_pcm", no_argument, 0, 'b' },
+ { "tp_dir", required_argument, 0, 't' },
+ { "file", required_argument, 0, 'f' },
+ { "hpcm_tp", required_argument, 0, 'a' },
+ { "vol", required_argument, 0, 'v' },
+ { "mute", required_argument, 0, 'u' },
+ { "tty_mode", required_argument, 0, 'y' },
+ { "dtmf_gen", no_argument, 0, 'c' },
+ { 0, 0, 0, 0 }
+ };
+
+ while ((opt = getopt_long(argc,
+ argv,
+ "-v:d:l:m:p:r:t:f:a:b:h:i:u:y:c:",
+ long_options,
+ &option_index)) != -1) {
+
+ fprintf(stderr, "for argument %c, value is %s\n", opt, optarg);
+
+ switch (opt) {
+ case 'i':
+ stream_params.vsid = optarg;
+ break;
+ case 'd':
+ stream_params.output_device[0] = atoll(optarg);
+ break;
+ case 'l':
+ stream_params.call_length = atoll(optarg);
+ break;
+ case 'm':
+ stream_params.multi_call = atoll(optarg);
+ break;
+ case 'p':
+ stream_params.in_call_playback = true;
+ stream_params.playback_file = optarg;
+ break;
+ case 'r':
+ stream_params.in_call_rec = true;
+ stream_params.rec_file = optarg;
+ break;
+ case 'b':
+ stream_params.hpcm = true;
+ break;
+ case 'f':
+ stream_params.playback_file = optarg;
+ break;
+ case 't':
+ stream_params.tp_dir = atoll(optarg);
+ break;
+ case 'a':
+ stream_params.hpcm_tp = atoll(optarg);
+ break;
+ case 'v':
+ stream_params.vol = atof(optarg);
+ break;
+ case 'u':
+ stream_params.mute_dir = atoll(optarg);
+ stream_params.mute = true;
+ break;
+ case 'y':
+ stream_params.tty_mode = atoll(optarg);
+ break;
+ case 'c':
+ stream_params.dtmf_gen_enable = true;
+ break;
+ case 'h':
+ default:
+ usage();
+ return 0;
+ }
+ }
+
+ /* Register the SIGINT to close the App properly */
+ if (signal(SIGINT, stop_signal_handler) == SIG_ERR)
+ fprintf(stderr, "Failed to register SIGINT:%d\n", errno);
+
+ /* Register the SIGTERM to close the App properly */
+ if (signal(SIGTERM, stop_signal_handler) == SIG_ERR)
+ fprintf(stderr, "Failed to register SIGTERM:%d\n", errno);
+
+ qahw_register_qas_death_notify_cb((audio_error_callback)qti_audio_server_death_notify_cb, context);
+
+ fprintf(stderr, "starting voice call\n");
+ if ((stream_params.qahw_mod_handle = qahw_load_module(QAHW_MODULE_ID_PRIMARY)) == NULL) {
+ fprintf(stderr, "failure in Loading primary HAL\n");
+ goto exit;
+ }
+
+ struct qahw_stream_attributes attr;
+
+ attr.type = QAHW_VOICE_CALL;
+ attr.direction = QAHW_STREAM_INPUT_OUTPUT;
+ attr.attr.voice.vsid = stream_params.vsid;
+ stream_params.out_voice_handle = NULL;
+
+ fprintf(stderr, "vsid is %s device is %d \n", attr.attr.voice.vsid, stream_params.output_device[0]);
+ rc = qahw_stream_open(stream_params.qahw_mod_handle,
+ attr,
+ 1,
+ stream_params.output_device,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ &(stream_params.out_voice_handle));
+ if (rc) {
+ fprintf(stderr, "Could not open output stream.\n");
+ goto unload;
+ }
+ /*set tty mode if needed*/
+ if(stream_params.tty_mode) {
+ qahw_param_payload tty;
+ tty.tty_mode_params.mode = stream_params.tty_mode;
+ rc = qahw_stream_set_parameters(stream_params.out_voice_handle,
+ QAHW_PARAM_TTY_MODE, &tty);
+ }
+ while (stream_params.multi_call) {
+ call_count++;
+ rc = qahw_stream_start(stream_params.out_voice_handle);
+
+ if (rc) {
+ fprintf(stderr, "Could not start voice stream.\n");
+ goto close_stream;
+ }
+ fprintf(stderr, "started voice call %d\n", call_count);
+ /*set volume */
+ struct qahw_volume_data vol;
+ struct qahw_channel_vol vol_pair;
+
+ vol_pair.channel = QAHW_CHANNEL_L;
+ vol_pair.vol = stream_params.vol;
+ vol.num_of_channels = 1;
+ vol.vol_pair = &vol_pair;
+
+ rc = qahw_stream_set_volume(stream_params.out_voice_handle, vol);
+ if(rc){
+ fprintf(stderr, "set vol failed rc %d!\n", rc);
+ }
+ call_lenght = stream_params.call_length;
+ if (stream_params.in_call_rec) {
+ fprintf(stderr, "\n Create %s in call record thread \n");
+ rc = pthread_create(&tid_rec, NULL, rec_start, (void *)&stream_params);
+ if (rc) {
+ fprintf(stderr, "in call rec thread creation failed %d\n");
+ }
+ }
+ if (stream_params.in_call_playback) {
+ fprintf(stderr, "\n Create %s incall playback thread \n");
+ rc = pthread_create(&tid_pb, NULL, playback_start, (void *)&stream_params);
+ if (rc) {
+ fprintf(stderr, "in call playback thread creation failed %d\n");
+ }
+ }
+ if(stream_params.mute) {
+ struct qahw_mute_data mute;
+ mute.enable = true;
+ mute.direction = stream_params.mute_dir;
+ rc = qahw_stream_set_mute(stream_params.out_voice_handle, mute);
+ }
+ if(stream_params.dtmf_gen_enable) {
+ qahw_param_payload dtmf;
+ dtmf.dtmf_gen_params.low_freq = stream_params.dtmf_freq_low;
+ dtmf.dtmf_gen_params.high_freq = stream_params.dtmf_freq_high;
+ dtmf.dtmf_gen_params.gain = stream_params.dtmf_gain;
+ dtmf.dtmf_gen_params.enable = true;
+ rc = qahw_stream_set_parameters(stream_params.out_voice_handle,
+ QAHW_PARAM_DTMF_GEN, &dtmf);
+ /*let play for 50 ms*/
+ usleep(50000000);
+ dtmf.dtmf_gen_params.enable = false;
+ rc = qahw_stream_set_parameters(stream_params.out_voice_handle,
+ QAHW_PARAM_DTMF_GEN, &dtmf);
+
+ }
+ /*setup hpcm if needed*/
+ if(stream_params.hpcm) {
+ fprintf(stderr, "calling hpcm set param.\n");
+ qahw_param_payload hpcm;
+ hpcm.hpcm_params.tap_point = stream_params.hpcm_tp;
+ hpcm.hpcm_params.direction = stream_params.tp_dir;
+ rc = qahw_stream_set_parameters(stream_params.out_voice_handle,
+ QAHW_PARAM_HPCM, &hpcm);
+
+ switch(stream_params.tp_dir) {
+ case QAHW_HPCM_DIRECTION_OUT:
+ fprintf(stderr, "\n Create %s hpcm playback thread \n");
+ rc = pthread_create(&tid_pb, NULL, playback_start,
+ (void *)&stream_params);
+ break;
+ case QAHW_HPCM_DIRECTION_IN:
+ fprintf(stderr, "\n Create %s hpcm record thread \n");
+ rc = pthread_create(&tid_rec, NULL, rec_start,
+ (void *)&stream_params);
+ break;
+ case QAHW_HPCM_DIRECTION_OUT_IN:
+ fprintf(stderr, "\n Create %s hpcm record thread \n");
+ rc = pthread_create(&tid_rec, NULL, rec_start,
+ (void *)&stream_params);
+ fprintf(stderr, "\n Create %s hpcm playback thread \n");
+ rc = pthread_create(&tid_pb, NULL, playback_start,
+ (void *)&stream_params);
+ break;
+ default:
+ fprintf(stderr, "\n invalid HPCM direction \n");
+ break;
+ }
+ }
+ while (call_lenght) {
+ usleep(1000000);
+ call_lenght--;
+ }
+ stop = true;
+ fprintf(stderr, "stoping call %d\n", call_count);
+ rc = qahw_stream_stop(stream_params.out_voice_handle);
+ stream_params.multi_call--;
+ /*let session stop*/
+ usleep(100000);
+ }
+
+ close_stream:
+ fprintf(stderr, "closing voice stream\n");
+ rc = qahw_stream_close(stream_params.out_voice_handle);
+
+ unload:
+ fprintf(stderr, "unloading hal\n");
+ if (qahw_unload_module(stream_params.qahw_mod_handle) < 0) {
+ fprintf(stderr, "failure in Un Loading primary HAL\n");
+ return -1;
+ }
+ fprintf(stderr, "voice test ended\n");
+ exit:
+ return 0;
+}
diff --git a/qahw_api/test/qahw_voice_test.h b/qahw_api/test/qahw_voice_test.h
new file mode 100644
index 0000000..bb14094
--- /dev/null
+++ b/qahw_api/test/qahw_voice_test.h
@@ -0,0 +1,76 @@
+/*
+* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Test app for voice call */
+
+#ifndef QAHW_VOICE_TEST_H
+#define QAHW_VOICE_TEST_H
+
+#include <getopt.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <signal.h>
+#include <cutils/str_parms.h>
+#include <tinyalsa/asoundlib.h>
+#include "qahw_api.h"
+#include "qahw_defs.h"
+
+#define MAX_VOICE_TEST_DEVICES 2
+
+typedef struct {
+ qahw_module_handle_t *qahw_mod_handle;
+ qahw_stream_handle_t *out_voice_handle;
+ char* vsid;
+ audio_devices_t output_device[MAX_VOICE_TEST_DEVICES];
+ uint32_t call_length; /*sec*/
+ int multi_call; /*number of calls to make */
+ qahw_module_handle_t *out_handle;
+ bool in_call_rec;
+ bool in_call_playback;
+ bool hpcm;
+ int hpcm_tp;
+ int tp_dir;
+ char* rec_file;
+ char* playback_file;
+ float vol;
+ bool mute;
+ int mute_dir;
+ int tty_mode;
+ int dtmf_gen_enable;
+ int dtmf_freq_low;
+ int dtmf_freq_high;
+ int dtmf_gain;
+}voice_stream_config;
+
+#endif /* QAHW_VOICE_TEST_H */