Merge "qahw: Add support for voice tester"
This commit is contained in:
commit
f099596db7
|
@ -41,3 +41,27 @@ trans_loopback_test_SOURCES = trans_loopback_test.c
|
|||
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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
Loading…
Reference in New Issue