android_hardware_qcom_audio/qahw_api/test/qap_wrapper_extn.c

1564 lines
66 KiB
C

/*
* Copyright (c) 2016-2017, 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 extension to exercise QAP (Non-tunnel Decode) */
#include <ctype.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <cutils/properties.h>
#include <cutils/list.h>
#include <cutils/log.h>
#include <cutils/str_parms.h>
#include <system/audio.h>
#include <qap_api.h>
#include <qti_audio.h>
#include "qahw_playback_test.h"
#undef LOG_TAG
#define LOG_TAG "HAL_TEST"
#undef LOG_NDEBUG
/*#define LOG_NDEBUG 0*/
#if LINUX_ENABLED
#define QAC_LIB_MS12 "/usr/lib/libdolby_ms12_wrapper.so"
#define QAC_LIB_M8 "/usr/lib/libdts_m8_wrapper.so"
#else
#define QAC_LIB_MS12 "/system/lib/libdolby_ms12_wrapper.so"
#define QAC_LIB_M8 "/system/lib/libdts_m8_wrapper.so"
#endif
#define SESSION_BLURAY 1
#define SESSION_BROADCAST 2
#define MAX_OUTPUT_CHANNELS 8
#define FRAME_SIZE 30000
#define MAX_BUFFER_SIZE 30000
#define CONTIGUOUS_TIMESTAMP 0x7fffffff
#define TIMESTAMP_ARRAY_SIZE 2048
#define DOLBY 1
#define DTS 2
qap_lib_handle_t ms12_lib_handle = NULL;
qap_lib_handle_t m8_lib_handle = NULL;
qap_session_handle_t qap_session_handle = NULL;
qahw_module_handle_t *qap_out_hal_handle = NULL;
qahw_module_handle_t *qap_out_spk_handle = NULL;
qahw_module_handle_t *qap_out_hdmi_handle = NULL;
qahw_module_handle_t *qap_out_hp_handle = NULL;
audio_io_handle_t qap_stream_out_spk_handle = 0x999;
audio_io_handle_t qap_stream_out_hdmi_handle = 0x998;
audio_io_handle_t qap_stream_out_hp_handle = 0x997;
audio_io_handle_t qap_stream_out_cmpr_handle = 0x996;
FILE *fp_output_writer_spk = NULL;
FILE *fp_output_writer_hp = NULL;
FILE *fp_output_writer_hdmi = NULL;
FILE *fp_output_timestamp_file = NULL;
unsigned char data_buf[MAX_BUFFER_SIZE];
uint32_t output_device_id = 0;
uint16_t input_streams_count = 0;
bool hdmi_connected = false;
bool play_through_bt = false;
bool encode = false;
bool dolby_formats = false;
bool timestamp_mode = false;
int data_write_count = 0;
int data_callback_count = 0;
bool play_list = false;
int play_list_cnt = 0;
uint8_t session_type = SESSION_BLURAY;
pthread_t main_input_thread;
pthread_attr_t main_input_thrd_attr;
pthread_cond_t main_eos_cond;
pthread_mutex_t main_eos_lock;
pthread_cond_t sec_eos_cond;
pthread_mutex_t sec_eos_lock;
qap_session_outputs_config_t session_output_config;
bool session_output_configured = false;
struct timeval tcold_start, tcold_stop;
struct timeval tcont_ts1, tcont_ts2;
double cold_start, cold_stop;
long int data_callback_ts_arr[TIMESTAMP_ARRAY_SIZE];
long int data_input_ts_arr[TIMESTAMP_ARRAY_SIZE];
double data_input_st_arr[TIMESTAMP_ARRAY_SIZE];
double data_callback_st_arr[TIMESTAMP_ARRAY_SIZE];
bool has_system_input = false;
char session_kv_pairs[256];
bool stream_close = false;
static void update_combo_dev_kvpairs()
{
bool enable_spk = false;
bool enable_hp = false;
bool enable_hdmi = false;
bool combo_enabled = false;
char dev_kv_pair[16] = {0};
ALOGV("%s:%d output device id %d", __func__, __LINE__, output_device_id);
if (output_device_id & AUDIO_DEVICE_OUT_HDMI)
enable_hdmi = true;
if (output_device_id & AUDIO_DEVICE_OUT_WIRED_HEADPHONE)
enable_hp = true;
if (output_device_id & AUDIO_DEVICE_OUT_SPEAKER)
enable_spk = true;
// Update the kv_pair based on the output device selsction
// To select hdmi, spekaer and headphone: o_device=1,2,8
// To select hdmi, headphone: o_device=2,8
// To select hdmi, spekaer : o_device=1,8
// To select spekaer and headphone: o_device=1,2
if (enable_hdmi && enable_hp && enable_spk) {
sprintf(dev_kv_pair, "o_device=1,2,8");
combo_enabled = true;
} else if (enable_hdmi && enable_hp) {
sprintf(dev_kv_pair, "o_device=2,8");
combo_enabled = true;
} else if (enable_hdmi && enable_spk) {
sprintf(dev_kv_pair, "o_device=1,8");
combo_enabled = true;
} else if (enable_hp && enable_spk) {
sprintf(dev_kv_pair, "o_device=1,2");
combo_enabled = true;
}
if (combo_enabled)
strcat(session_kv_pairs, dev_kv_pair);
ALOGV("%s:%d session set param %s and combo_enabled %d", __func__, __LINE__, session_kv_pairs, combo_enabled);
return;
}
static void update_kvpairs_for_encode(int out_device_id) {
uint8_t device_id;
char command[64];
if (out_device_id == AUDIO_DEVICE_OUT_HDMI)
device_id = 8;
switch (render_format) {
case 1:
sprintf(command, "o_device=%d;od=;", device_id);
strcat(session_kv_pairs, command);
encode = true;
break;
case 2:
sprintf(command, "o_device=%d;odp=;", device_id);
strcat(session_kv_pairs, command);
encode = true;
break;
case 3:
sprintf(command, "o_device=%d;render_format=odts;enabletransencode;", device_id);
strcat(session_kv_pairs, command);
encode = true;
break;
default:
encode = false;
break;
}
ALOGV("%s::%d output device %d and session set params %s", __func__, __LINE__, out_device_id, session_kv_pairs);
return;
}
static void qap_wrapper_create_multi_channel_dump(char *path) {
fp_output_writer_hdmi = fopen(path,"wb");
if (fp_output_writer_hdmi)
fprintf(stdout, "output file ::%s has been generated.\n", path);
else
fprintf(stderr, "Failed open hdmi dump file\n");
}
/*
* cold_time_latency is the time difference between the session open
* and the first data output received from decoder.
*
* cont_time_latency is the avg time taken to decode the input buffers
* i.e. avg of the time differences between the time the input buffer feeded
* and the time the o/p buffer received
*/
static void qap_wrapper_measure_kpi_values(double cold_start, double cold_stop)
{
int i=0, m=0, j=0;
int cnt = 0;
double syst_time_arr[TIMESTAMP_ARRAY_SIZE];
double total_lat = 0;
double cold_time_latency, cont_time_latency;
cold_time_latency = cold_stop - cold_start;
memset(syst_time_arr,0, sizeof(syst_time_arr));
if (data_write_count > TIMESTAMP_ARRAY_SIZE)
data_write_count = TIMESTAMP_ARRAY_SIZE;
if (data_callback_count > TIMESTAMP_ARRAY_SIZE)
data_callback_count = TIMESTAMP_ARRAY_SIZE;
for (i = 6; i < data_write_count; i++) {
for(j = 6; j < ((data_callback_count < TIMESTAMP_ARRAY_SIZE) ? data_callback_count : TIMESTAMP_ARRAY_SIZE); j++) {
if( abs(data_input_ts_arr[i] - data_callback_ts_arr[j]) <= 4000) {
syst_time_arr[cnt++] = (data_callback_st_arr[j] - data_input_st_arr[i]);
}
}
}
for(m = 0; m < cnt; m++) {
total_lat += syst_time_arr[m];
ALOGV("%d system time diff %lf", __LINE__, syst_time_arr[m]);
}
cont_time_latency = total_lat/(cnt);
fprintf(stdout, "cold time latency %lf ms, avg cont time latency %lf ms,"
"total cont time latency %f ms, total count %d\n",
cold_time_latency, cont_time_latency, total_lat, cnt);
}
static void qap_wrapper_read_frame_size_from_file(qap_audio_buffer_t *buffer, FILE *fp_framesize)
{
if (NULL != fp_framesize) {
char tempstr[100];
fgets(tempstr, sizeof(tempstr), fp_framesize);
buffer->common_params.size = atoi(tempstr);
}
}
static void read_bytes_timestamps_from_file(qap_audio_buffer_t *buffer, FILE *fp_timestamp, FILE *fp_input_file)
{
if (NULL != fp_timestamp) {
char tempstr[100];
int seek_offset = 0;
fgets(tempstr, sizeof(tempstr), fp_timestamp);
printf("%s and tempstr is %s \n", __FUNCTION__, tempstr);
char * token = strtok(tempstr, ",");
if (token != NULL) {
buffer->common_params.size = atoi(token);
if(token!= NULL) {
token = strtok(NULL, ",");
if (token!= NULL) {
buffer->common_params.timestamp = atoi(token);
ALOGV("%s and timestamp to be pushed to queue is %lld", __FUNCTION__, buffer->common_params.timestamp);
}
token = strtok(NULL, ",");
if (token != NULL) {
seek_offset = atoi(token);
if (fp_input_file && seek_offset > 0)
fseek(fp_input_file, seek_offset, SEEK_CUR);
}
}
}
}
}
bool is_qap_session_active(int argc, char* argv[], char *kvp_string) {
char *qap_kvp = NULL;
char *cmd_str = NULL;
char *tmp_str = NULL;
int status = 0;
cmd_str = (char *)qap_wrapper_get_cmd_string_from_arg_array(argc, argv, &status);
if (status > 0) {
qap_kvp = qap_wrapper_get_single_kvp("qap", cmd_str, &status);
if (qap_kvp == NULL) {
return false;
}
strncpy(kvp_string, cmd_str, strlen(cmd_str));
if (cmd_str != NULL) {
free(cmd_str);
cmd_str = NULL;
}
}
return true;
}
char* check_for_playlist(char *kvp_string) {
char *file_str = NULL;
char *tmp_str = NULL;
char *play_list = NULL;
int len = 0;
tmp_str = strstr(kvp_string, "g=");
if (tmp_str != NULL) {
file_str = strstr(kvp_string, ".txt");
len = file_str - tmp_str;
play_list = (char*) malloc(sizeof(char) * (len+4));
memset(play_list, '\0', len+4);
strncpy(play_list, tmp_str+2, len+2);
}
return play_list;
}
int start_playback_through_qap_playlist(char *cmd_kvp_str[], int num_of_streams, char *kvp_string, stream_config stream_param[],
bool qap_wrapper_session_active, qahw_module_handle_t *hal_handle) {
stream_config *stream = NULL;
int rc = 0;
bool broad_cast = false, bd = false;
int i = 0, curr_clip_type = DOLBY, prev_clip_type;
if (strstr(kvp_string, "broadcast"))
broad_cast = true;
else if(strstr(kvp_string, "bd"))
bd = true;
do {
fprintf(stdout, "cmd_kvp_string is %s kvp_string %s and num_of_streams %d\n", cmd_kvp_str[i], kvp_string, num_of_streams);
stream = &stream_param[i];
fprintf(stdout, "stream->filename is %s\n", stream->filename);
if (stream->filename) {
prev_clip_type = curr_clip_type;
if ((stream->file_stream = fopen(stream->filename, "r"))== NULL) {
fprintf(stderr, "Cannot open audio file %s\n", stream->filename);
return -EINVAL;
}
if (strstr(stream->filename, ".dts")) {
curr_clip_type = DTS;
} else {
curr_clip_type = DOLBY;
}
}
get_file_format(stream);
fprintf(stdout, "Playing from:%s\n", stream->filename);
qap_module_handle_t qap_module_handle = NULL;
if ((bd || (prev_clip_type != curr_clip_type)) && qap_wrapper_session_active) {
fprintf(stdout, " prev_clip_type is %d curr_clip_type is %d\n", prev_clip_type, curr_clip_type);
qap_wrapper_session_close();
qap_wrapper_session_active = false;
}
if (!qap_wrapper_session_active) {
if (broad_cast) {
cmd_kvp_str[i] = realloc(cmd_kvp_str[i], strlen(cmd_kvp_str[i])+11);
strcat(strcat(cmd_kvp_str[i], ";"), "broadcast");
} else if (bd) {
cmd_kvp_str[i] = realloc(cmd_kvp_str[i], strlen(cmd_kvp_str[i])+4);
strcat(strcat(cmd_kvp_str[i], ";"), "bd");
}
rc = qap_wrapper_session_open(cmd_kvp_str[i], stream, num_of_streams, hal_handle);
if (rc != 0) {
fprintf(stderr, "Session Open failed\n");
return -EINVAL;
}
qap_wrapper_session_active = true;
}
if (qap_wrapper_session_active) {
stream->qap_module_handle = qap_wrapper_stream_open(stream);
if (stream->qap_module_handle == NULL) {
fprintf(stderr, "QAP Stream open Failed\n");
} else {
fprintf(stdout, "QAP module handle is %p and file name is %s\n", stream->qap_module_handle, stream->filename);
qap_wrapper_start_stream(&stream_param[i]);
free(stream->filename);
stream->filename = NULL;
free(cmd_kvp_str[i]);
cmd_kvp_str[i] = NULL;
}
}
i++;
while (!stream_close) {
usleep(50000);
fprintf(stderr, "QAP Stream not closed\n");
}
fprintf(stderr, "QAP Stream closed\n");
} while (i <num_of_streams);
if (broad_cast && qap_wrapper_session_active) {
qap_wrapper_session_close();
qap_wrapper_session_active = false;
}
return 0;
}
#ifdef QAP
char *qap_wrapper_get_single_kvp(const char *key, const char *kv_pairs, int *status)
{
char *kvp = NULL;
char *tempstr = NULL;
char *token = NULL;
char *context1 = NULL;
char *context2 = NULL;
char *temp_kvp = NULL;
char *temp_key = NULL;
if (NULL == key || NULL == kv_pairs) {
*status = -EINVAL;
return NULL;
}
tempstr = strdup(kv_pairs);
token = strtok_r(tempstr, ";", &context1);
if (token != NULL) {
temp_kvp = strdup(token);
if (temp_kvp != NULL) {
temp_key = strtok_r(temp_kvp, "=", &context2);
if (!strncmp(key, temp_key, strlen(key))) {
kvp = malloc((strlen(token) + 1) * sizeof(char));
memset(kvp, 0, strlen(token) + 1);
strncat(kvp, token, strlen(token));
return kvp;
}
free(temp_kvp);
}
while (token != NULL) {
token = strtok_r(NULL, ";", &context1);
if (token != NULL) {
temp_kvp = strdup(token);
if (temp_kvp != NULL) {
temp_key = strtok_r(temp_kvp, "=", &context2);
if (!strncmp(key, temp_key, strlen(key))) {
kvp = malloc((strlen(token) + 1) * sizeof(char));
memset(kvp, 0, strlen(token) + 1);
strncat(kvp, token, strlen(token));
return kvp;
}
free(temp_kvp);
temp_kvp = NULL;
}
}
}
free(tempstr);
}
return NULL;
}
#endif
int *qap_wrapper_get_int_value_array(const char *kvp, int *count, int *status __unused)
{
char *tempstr1;
char *tempstr2;
char *l1;
char *l2 __unused;
char *ctx1;
char *ctx2 __unused;
int *val = NULL;
int i = 0;
char *s;
char *endstr;
int temp = 0;
char *jump;
*count = 0;
if (kvp == NULL) {
return NULL;
}
tempstr1 = strdup(kvp);
l1 = strtok_r(tempstr1, "=", &ctx1);
if (l1 != NULL) {
/* jump from key to value */
l1 = strtok_r(NULL, "=", &ctx1);
if (l1 != NULL) {
tempstr2 = strdup(l1);
s = tempstr2;
for (i=0; s[i]; s[i]==',' ? i++ : *s++);
temp = i;
val = malloc((i + 1)*sizeof(int));
i = 0;
val[i++] = strtol(tempstr2, &endstr, 0);
while (i <= temp) {
jump = endstr + 1;
val[i++] = strtol(jump, &endstr, 0);
}
free(tempstr2);
}
}
free(tempstr1);
*count = i;
return val;
}
char * qap_wrapper_get_cmd_string_from_arg_array(int argc, char * argv[], int *status)
{
char * kvps;
int idx;
int has_key = 0;
int mem = 0;
fprintf(stdout, "%s %d in", __func__, __LINE__);
if (argc < 2 || NULL == argv) {
fprintf(stdout, "%s %d returning EINVAL\n", __func__, __LINE__);
*status = -EINVAL;
return NULL;
}
for (idx = 0; idx < argc; idx++) {
mem += (strlen(argv[idx]) + 2); /* Extra byte to insert delim ';' */
}
if (mem > 0)
kvps = malloc(mem * sizeof(char));
else {
*status = -EINVAL;
fprintf(stdout, "%s %d returning EINVAL\n", __func__, __LINE__);
return NULL;
}
if (NULL == kvps) {
*status = -ENOMEM;
fprintf(stdout, "%s %d returning EINVAL\n", __func__, __LINE__);
return NULL;
}
for (idx = 1; idx < argc; idx++) {
if (( argv[idx][0] == '-') &&
(argv[idx][1] < '0' || argv[idx][1] > '9')) {
if (has_key) {
strcat(kvps, ";");
has_key = 0;
}
strcat(kvps, argv[idx]+1);
strcat(kvps, "=");
has_key = 1;
} else if (has_key) {
strcat(kvps, argv[idx]);
strcat(kvps, ";");
has_key = 0;
} else {
*status = -EINVAL;
if (kvps != NULL) {
free(kvps);
kvps = NULL;
}
fprintf(stdout, "%s %d returning EINVAL\n", __func__, __LINE__);
return NULL;
}
}
*status = mem;
fprintf(stdout, "%s %d returning\n", __func__, __LINE__);
return kvps;
}
static int qap_wrapper_map_input_format(audio_format_t audio_format, qap_audio_format_t *format)
{
if (audio_format == AUDIO_FORMAT_AC3) {
*format = QAP_AUDIO_FORMAT_AC3;
fprintf(stdout, "File Format is AC3!\n");
} else if (audio_format == AUDIO_FORMAT_E_AC3) {
*format = QAP_AUDIO_FORMAT_EAC3;
fprintf(stdout, "File Format is E_AC3!\n");
} else if ((audio_format == AUDIO_FORMAT_AAC_ADTS_LC) ||
(audio_format == AUDIO_FORMAT_AAC_ADTS_HE_V1) ||
(audio_format == AUDIO_FORMAT_AAC_ADTS_HE_V2) ||
(audio_format == AUDIO_FORMAT_AAC_LC) ||
(audio_format == AUDIO_FORMAT_AAC_HE_V1) ||
(audio_format == AUDIO_FORMAT_AAC_HE_V2) ||
(audio_format == AUDIO_FORMAT_AAC_LATM_LC) ||
(audio_format == AUDIO_FORMAT_AAC_LATM_HE_V1) ||
(audio_format == AUDIO_FORMAT_AAC_LATM_HE_V2)) {
*format = QAP_AUDIO_FORMAT_AAC_ADTS;
fprintf(stdout, "File Format is AAC!\n");
} else if (audio_format == AUDIO_FORMAT_DTS) {
*format = QAP_AUDIO_FORMAT_DTS;
fprintf(stdout, "File Format is DTS!\n");
} else if (audio_format == AUDIO_FORMAT_DTS_HD) {
*format = QAP_AUDIO_FORMAT_DTS_HD;
fprintf(stdout, "File Format is DTS_HD!\n");
} else if (audio_format == AUDIO_FORMAT_PCM_16_BIT) {
*format = QAP_AUDIO_FORMAT_PCM_16_BIT;
fprintf(stdout, "File Format is PCM_16!\n");
} else if (audio_format == AUDIO_FORMAT_PCM_32_BIT) {
*format = QAP_AUDIO_FORMAT_PCM_32_BIT;
fprintf(stdout, "File Format is PCM_32!\n");
} else if (audio_format == AUDIO_FORMAT_PCM_24_BIT_PACKED) {
*format = QAP_AUDIO_FORMAT_PCM_24_BIT_PACKED;
fprintf(stdout, "File Format is PCM_24!\n");
} else if ((audio_format == AUDIO_FORMAT_PCM_8_BIT) ||
(audio_format == AUDIO_FORMAT_PCM_8_24_BIT)) {
*format = QAP_AUDIO_FORMAT_PCM_8_24_BIT;
fprintf(stdout, "File Format is PCM_8_24!\n");
} else {
fprintf(stdout, "File Format not supported!\n");
return -EINVAL;
}
return 0;
}
char *get_string_value(const char *kvp, int *status)
{
char *tempstr1 = NULL;
char *tempstr2 = NULL;
char *l1;
char *ctx1;
if (kvp == NULL)
return NULL;
tempstr1 = strdup(kvp);
l1 = strtok_r(tempstr1, "=", &ctx1);
if (l1 != NULL) {
/* jump from key to value */
l1 = strtok_r(NULL, "=", &ctx1);
if (l1 != NULL)
tempstr2 = strdup(l1);
}
free(tempstr1);
return tempstr2;
}
int qap_wrapper_write_to_hal(qahw_stream_handle_t* out_handle, char *data, size_t bytes)
{
ssize_t ret;
qahw_out_buffer_t out_buf;
memset(&out_buf,0, sizeof(qahw_out_buffer_t));
out_buf.buffer = data;
out_buf.bytes = bytes;
ret = qahw_out_write(out_handle, &out_buf);
if (ret < 0)
fprintf(stderr, "%s::%d: writing data to hal failed (ret = %zd)\n", __func__, __LINE__, ret);
else if (ret != bytes)
fprintf(stdout, "%s::%d provided bytes %zd, written bytes %d\n",__func__, __LINE__, bytes, ret);
return ret;
}
static void close_output_streams()
{
int ret;
if (qap_out_hal_handle && qap_out_spk_handle) {
ret = qahw_out_standby(qap_out_spk_handle);
if (ret)
fprintf(stderr, "%s::%d: out standby failed %d \n", __func__, __LINE__, ret);
if (play_through_bt) {
fprintf(stdout, "%s::%d: disconnecting BT\n", __func__, __LINE__);
char param[100] = {0};
snprintf(param, sizeof(param), "%s=%d", "disconnect", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP);
qahw_set_parameters(qap_out_hal_handle, param);
}
fprintf(stdout, "%s::%d: closing output stream\n", __func__, __LINE__);
ret = qahw_close_output_stream(qap_out_spk_handle);
if (ret)
fprintf(stderr, "%s::%d: could not close output stream, error - %d\n", __func__, __LINE__, ret);
qap_out_spk_handle = NULL;
}
if (qap_out_hal_handle && qap_out_hp_handle) {
ret = qahw_out_standby(qap_out_hp_handle);
if (ret)
fprintf(stderr, "%s::%d: out standby failed %d \n", __func__, __LINE__, ret);
fprintf(stdout, "%s::%d: closing output stream\n", __func__, __LINE__);
ret = qahw_close_output_stream(qap_out_hp_handle);
if (ret)
fprintf(stderr, "%s::%d: could not close output stream, error - %d\n", __func__, __LINE__, ret);
qap_out_hp_handle = NULL;
}
if (qap_out_hal_handle && qap_out_hdmi_handle) {
char param[100] = {0};
snprintf(param, sizeof(param), "%s=%d", "disconnect", AUDIO_DEVICE_OUT_HDMI);
ret = qahw_out_standby(qap_out_hdmi_handle);
if (ret)
fprintf(stderr, "%s::%d: out standby failed %d\n", __func__, __LINE__, ret);
qahw_set_parameters(qap_out_hal_handle, param);
fprintf(stdout, "%s::%d: closing output stream\n", __func__, __LINE__);
ret = qahw_close_output_stream(qap_out_hdmi_handle);
if (ret)
fprintf(stderr, "%s::%d: could not close output stream, error - %d\n", __func__, __LINE__, ret);
qap_out_hdmi_handle = NULL;
}
stream_close = true;
}
void qap_wrapper_session_callback(qap_session_handle_t session_handle __unused, void* priv_data __unused, qap_callback_event_t event_id, int size __unused, void *data)
{
int ret = 0;
int bytes_written = 0;
int bytes_remaining = 0;
int offset = 0;
audio_output_flags_t flags;
flags = (AUDIO_OUTPUT_FLAG_NON_BLOCKING |
AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
AUDIO_OUTPUT_FLAG_DIRECT);
ALOGV("%s %d Received event id %d\n", __func__, __LINE__, event_id);
switch (event_id) {
case QAP_CALLBACK_EVENT_EOS:
ALOGV("%s %d Received Main Input EOS", __func__, __LINE__);
pthread_mutex_lock(&main_eos_lock);
pthread_cond_signal(&main_eos_cond);
pthread_mutex_unlock(&main_eos_lock);
ALOGE("%s %d Received Main Input EOS ", __func__, __LINE__);
if (!stream_close)
close_output_streams();
if (play_list_cnt && input_streams_count) {
play_list_cnt--;
input_streams_count = 0;
}
break;
case QAP_CALLBACK_EVENT_EOS_ASSOC:
case QAP_CALLBACK_EVENT_MAIN_2_EOS:
if (!has_system_input){
ALOGV("%s %d Received Secondary Input EOS", __func__, __LINE__);
pthread_mutex_lock(&sec_eos_lock);
pthread_cond_signal(&sec_eos_cond);
pthread_mutex_unlock(&sec_eos_lock);
}
break;
case QAP_CALLBACK_EVENT_ERROR:
break;
case QAP_CALLBACK_EVENT_SUCCESS:
break;
case QAP_CALLBACK_EVENT_METADATA:
case QAP_CALLBACK_EVENT_OUTPUT_CFG_CHANGE:
break;
case QAP_CALLBACK_EVENT_DATA:
if (data != NULL) {
qap_audio_buffer_t *buffer = (qap_audio_buffer_t *) data;
if (buffer && timestamp_mode) {
char ch[100] = {0};
if (kpi_mode) {
if ((data_callback_count > 5) && (data_callback_count < TIMESTAMP_ARRAY_SIZE)) {
gettimeofday(&tcont_ts2, NULL);
data_callback_ts_arr[data_callback_count] = buffer->common_params.timestamp;
data_callback_st_arr[data_callback_count] = (tcont_ts2.tv_sec) * 1000 + (tcont_ts2.tv_usec) / 1000;
ALOGV("%s::%d data size %d, Kpi cont ts2 %lf, buffer timestamp %ld",
__func__, __LINE__, buffer->common_params.size,
data_callback_st_arr[data_callback_count], data_callback_ts_arr[data_callback_count]);
}
if (data_callback_count < TIMESTAMP_ARRAY_SIZE)
data_callback_count++;
}
if (fp_output_timestamp_file == NULL) {
fp_output_timestamp_file =
fopen("/sdcard/output_timestamp_file.txt","w");
if(fp_output_timestamp_file) {
fprintf(stdout, "output file :: "
"/sdcard/output_file_timestamp.txt"
" has been generated.");
}
}
if (fp_output_timestamp_file) {
sprintf(ch, "%d,%lld\n", buffer->common_params.size, buffer->common_params.timestamp);
fprintf(stdout, "%s: %s", __func__, ch);
ret = fwrite((char *)&ch, sizeof(char),
strlen(ch), fp_output_timestamp_file);
fflush(fp_output_timestamp_file);
}
}
if (buffer && buffer->common_params.data) {
if (buffer->buffer_parms.output_buf_params.output_id &
AUDIO_DEVICE_OUT_HDMI) {
if (!hdmi_connected) {
char param[100] = {0};
snprintf(param, sizeof(param), "%s=%d", "connect", AUDIO_DEVICE_OUT_HDMI);
qahw_set_parameters(qap_out_hal_handle, param);
hdmi_connected = true;
}
if (encode) {
if (enable_dump && fp_output_writer_hdmi == NULL) {
if (buffer->buffer_parms.output_buf_params.output_id ==
(AUDIO_FORMAT_E_AC3|AUDIO_DEVICE_OUT_HDMI))
qap_wrapper_create_multi_channel_dump("/sdcard/output_hdmi.ddp");
else if (buffer->buffer_parms.output_buf_params.output_id ==
(AUDIO_FORMAT_AC3|AUDIO_DEVICE_OUT_HDMI))
qap_wrapper_create_multi_channel_dump("/sdcard/output_hdmi.dd");
else
qap_wrapper_create_multi_channel_dump("/sdcard/output_hdmi_dts.dts");
}
} else {
if (enable_dump && fp_output_writer_hdmi == NULL)
qap_wrapper_create_multi_channel_dump("/sdcard/output_hdmi.dump");
}
if (fp_output_writer_hdmi) {
ret = fwrite((unsigned char *)buffer->common_params.data, sizeof(unsigned char),
buffer->common_params.size, fp_output_writer_hdmi);
fflush(fp_output_writer_hdmi);
}
if (hdmi_connected && qap_out_hdmi_handle == NULL) {
struct audio_config config;
audio_devices_t devices;
config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
config.sample_rate = config.offload_info.sample_rate =
session_output_config.output_config->sample_rate;
if (session_output_config.output_config->bit_width == 24) {
config.format = config.offload_info.format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
config.offload_info.bit_width = 24;
} else {
config.format = config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
config.offload_info.bit_width = 16;
}
if (session_output_config.output_config->channels == 2) {
config.offload_info.channel_mask = config.channel_mask =
AUDIO_CHANNEL_OUT_STEREO;
} else {
config.offload_info.channel_mask = config.channel_mask =
audio_channel_out_mask_from_count(MAX_OUTPUT_CHANNELS);
}
devices = AUDIO_DEVICE_OUT_HDMI;
if (timestamp_mode)
flags |= AUDIO_OUTPUT_FLAG_TIMESTAMP;
if (encode) {
if (buffer->buffer_parms.output_buf_params.output_id ==
(AUDIO_FORMAT_AC3|AUDIO_DEVICE_OUT_HDMI))
config.format = config.offload_info.format = AUDIO_FORMAT_AC3;
else if (buffer->buffer_parms.output_buf_params.output_id ==
(AUDIO_FORMAT_E_AC3|AUDIO_DEVICE_OUT_HDMI))
config.format = config.offload_info.format = AUDIO_FORMAT_E_AC3;
else
config.format = config.offload_info.format = AUDIO_FORMAT_DTS;
ALOGV("%s:%d output format %x", __func__, __LINE__,
config.format, config.offload_info.format);
ret = qahw_open_output_stream(qap_out_hal_handle, qap_stream_out_cmpr_handle, devices,
flags, &config, &qap_out_hdmi_handle, "stream");
} else {
ret = qahw_open_output_stream(qap_out_hal_handle, qap_stream_out_hdmi_handle, devices,
flags, &config, &qap_out_hdmi_handle, "stream");
}
ret = qahw_out_set_volume(qap_out_hdmi_handle, vol_level, vol_level);
if (ret < 0)
ALOGE("unable to set volume");
}
if (qap_out_hdmi_handle) {
bytes_written = qap_wrapper_write_to_hal(qap_out_hdmi_handle,
buffer->common_params.data, buffer->common_params.size);
if (bytes_written == -1) {
ALOGE("%s::%d write failed in hal", __func__, __LINE__);
}
}
if (kpi_mode && data_callback_count == 1) {
gettimeofday(&tcold_stop, NULL);
cold_stop = (tcold_stop.tv_sec) * 1000 + (tcold_stop.tv_usec) / 1000;
ALOGD("%s::%d Measuring Kpi cold stop %lf", __func__, __LINE__, cold_stop);
}
}
if (buffer->buffer_parms.output_buf_params.output_id & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
if (enable_dump && fp_output_writer_hp == NULL) {
fp_output_writer_hp =
fopen("/sdcard/output_hp.dump","wb");
if (fp_output_writer_hp) {
fprintf(stdout, "output file :: "
"/sdcard/output_hp.dump"
" has been generated.\n");
} else {
fprintf(stderr, "Failed open hp dump file\n");
}
}
if (fp_output_writer_hp) {
ret = fwrite((unsigned char *)buffer->common_params.data, sizeof(unsigned char),
buffer->common_params.size, fp_output_writer_hp);
fflush(fp_output_writer_hp);
}
if (qap_out_hp_handle == NULL) {
struct audio_config config;
audio_devices_t devices;
config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
config.sample_rate = config.offload_info.sample_rate =
session_output_config.output_config->sample_rate;
if (session_output_config.output_config->bit_width == 24) {
config.format = config.offload_info.format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
config.offload_info.bit_width = 24;
} else {
config.format = config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
config.offload_info.bit_width = 16;
}
config.offload_info.channel_mask = config.channel_mask =
AUDIO_CHANNEL_OUT_STEREO;
devices = AUDIO_DEVICE_OUT_LINE;//ToDO - Need to change to AUDIO_DEVICE_OUT_WIRED_HEADPHONE
if (timestamp_mode)
flags |= AUDIO_OUTPUT_FLAG_TIMESTAMP;
ret = qahw_open_output_stream(qap_out_hal_handle, qap_stream_out_hp_handle, devices,
flags, &config, &qap_out_hp_handle, "stream");
if (ret) {
ALOGE("%s:%d could not open output stream, error - %d", __func__, __LINE__, ret);
return;
}
ret = qahw_out_set_volume(qap_out_hp_handle, vol_level, vol_level);
if (ret < 0)
ALOGE("unable to set volume");
}
if (qap_out_hp_handle) {
bytes_written = qap_wrapper_write_to_hal(qap_out_hp_handle,
buffer->common_params.data, buffer->common_params.size);
if (bytes_written == -1) {
ALOGE("%s::%d write failed in hal", __func__, __LINE__);
}
}
if (kpi_mode && data_callback_count == 1) {
gettimeofday(&tcold_stop, NULL);
cold_stop = (tcold_stop.tv_sec) * 1000 + (tcold_stop.tv_usec) / 1000;
ALOGD("%s::%d Measuring Kpi cold stop %lf", __func__, __LINE__, cold_stop);
}
}
if (buffer->buffer_parms.output_buf_params.output_id & AUDIO_DEVICE_OUT_SPEAKER) {
if (enable_dump && fp_output_writer_spk == NULL) {
char ch[4] = {0};
fp_output_writer_spk =
fopen("/sdcard/output_speaker.dump","wb");
if (fp_output_writer_spk) {
fprintf(stdout, "output file :: "
"/sdcard/output_speaker.dump"
" has been generated.\n");
if (dolby_formats) {
ret = fwrite((unsigned char *)&ch, sizeof(unsigned char),
4, fp_output_writer_spk);
}
} else {
fprintf(stderr, "Failed open speaker dump file\n");
}
}
if (fp_output_writer_spk) {
ret = fwrite((unsigned char *)buffer->common_params.data, sizeof(unsigned char),
buffer->common_params.size, fp_output_writer_spk);
fflush(fp_output_writer_spk);
}
if (qap_out_spk_handle == NULL) {
struct audio_config config;
audio_devices_t devices;
config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
config.sample_rate = config.offload_info.sample_rate =
session_output_config.output_config->sample_rate;
if (session_output_config.output_config->bit_width == 24) {
config.format = config.offload_info.format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
config.offload_info.bit_width = 24;
} else {
config.format = config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
config.offload_info.bit_width = 16;
}
config.offload_info.channel_mask = config.channel_mask =
AUDIO_CHANNEL_OUT_STEREO;
if (play_through_bt) {
fprintf(stderr, "%s::%d: connecting BT\n", __func__, __LINE__);
char param[100] = {0};
snprintf(param, sizeof(param), "%s=%d", "connect", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP);
qahw_set_parameters(qap_out_hal_handle, param);
devices = AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
} else {
devices = AUDIO_DEVICE_OUT_SPEAKER;
}
if (timestamp_mode)
flags |= AUDIO_OUTPUT_FLAG_TIMESTAMP;
ALOGD("%s::%d: open output for device %d", __func__, __LINE__, devices);
ret = qahw_open_output_stream(qap_out_hal_handle, qap_stream_out_spk_handle, devices,
flags, &config, &qap_out_spk_handle, "stream");
if (ret) {
ALOGE("%s:%d could not open output stream, error - %d", __func__, __LINE__, ret);
return;
}
ret = qahw_out_set_volume(qap_out_spk_handle, vol_level, vol_level);
if (ret < 0)
ALOGE("unable to set volume");
}
if (qap_out_spk_handle) {
bytes_written = qap_wrapper_write_to_hal(qap_out_spk_handle,
buffer->common_params.data, buffer->common_params.size);
if (bytes_written == -1) {
ALOGE("%s::%d write failed in hal", __func__, __LINE__);
}
}
if (kpi_mode && data_callback_count == 1) {
gettimeofday(&tcold_stop, NULL);
cold_stop = (tcold_stop.tv_sec) * 1000 + (tcold_stop.tv_usec) / 1000;
ALOGD("%s::%d Measuring Kpi cold stop %lf", __func__, __LINE__, cold_stop);
}
}
}
}
break;
default:
break;
}
}
static void qap_wrapper_is_dap_enabled(char *kv_pairs, int out_device_id) {
int status = 0;
int temp = 0;
char *dap_kvp = NULL;
int *dap_value = NULL;
int dap_enable = 0;
dap_kvp = qap_wrapper_get_single_kvp("dap_enable", kv_pairs, &status);
if (dap_kvp != NULL) {
dap_value = qap_wrapper_get_int_value_array(dap_kvp, &temp, &status);
if (dap_value != NULL)
dap_enable = dap_value[0];
if (dap_enable) {
fprintf(stdout, "dap enable %d and device id %d\n", dap_enable, out_device_id);
char *dev_kvp = NULL;
if (out_device_id == AUDIO_DEVICE_OUT_SPEAKER) {
dev_kvp = (char *) calloc(1, status + strlen("o_device=1; "));
if (dev_kvp != NULL) {
strcat(dev_kvp, "o_device=1;");
strcat(session_kv_pairs, dev_kvp);
fprintf(stdout, "session set params %s\n", session_kv_pairs);
free(dev_kvp);
dev_kvp = NULL;
}
} else if ((out_device_id == AUDIO_DEVICE_OUT_LINE)||
(out_device_id == AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
dev_kvp = (char *) calloc(1, status + strlen("o_device=2; "));
if (dev_kvp != NULL) {
strcat(dev_kvp, "o_device=2;");
strcat(session_kv_pairs, dev_kvp);
fprintf(stdout, "session set params %s\n", session_kv_pairs);
free(dev_kvp);
dev_kvp = NULL;
}
}
}
free(dap_kvp);
dap_kvp = NULL;
}
}
int qap_wrapper_session_open(char *kv_pairs, void* stream_data, int num_of_streams, qahw_module_handle_t *hal_handle)
{
int status = 0;
int ret = 0;
int i;
int temp = 0;
stream_config *stream = (stream_config *)stream_data;
char *session_type_kvp = NULL;
char *encode_kvp = NULL;
int *temp_val = NULL;
char *bitwidth_kvp = NULL;
qap_out_hal_handle = hal_handle;
if (kpi_mode) {
memset(data_input_st_arr, 0, sizeof(data_input_st_arr));
memset(data_input_ts_arr, 0, sizeof(data_input_ts_arr));
memset(data_callback_st_arr, 0, sizeof(data_callback_st_arr));
memset(data_callback_ts_arr, 0, sizeof(data_callback_ts_arr));
gettimeofday(&tcold_start, NULL);
cold_start = (tcold_start.tv_sec) * 1000 + (tcold_start.tv_usec) / 1000;
ALOGD("%s::%d Measuring Kpi cold start %lf", __func__, __LINE__, cold_start);
}
if (play_list)
play_list_cnt = num_of_streams;
memset(&session_output_config, 0, sizeof(session_output_config));
strcpy(session_kv_pairs, kv_pairs);
if (NULL != (session_type_kvp = qap_wrapper_get_single_kvp("broadcast", kv_pairs, &status))) {
session_type = SESSION_BROADCAST;
fprintf(stdout, "Session Type is Broadcast\n");
free(session_type_kvp);
session_type_kvp = NULL;
} else if (NULL != (session_type_kvp = qap_wrapper_get_single_kvp("bd", kv_pairs, &status))) {
session_type = SESSION_BLURAY;
free(session_type_kvp);
session_type_kvp = NULL;
fprintf(stdout, "Session Type is Bluray\n");
}
if (session_type == SESSION_BLURAY) {
if ((stream->filetype == FILE_WAV) ||
(stream->filetype == FILE_AAC)) {
fprintf(stderr, "Format is not supported for BD usecase\n");
return -EINVAL;
}
if (!play_list && num_of_streams > 1) {
fprintf(stderr, "Please specifiy proper session type\n");
return -EINVAL;
}
}
if (stream->filetype == FILE_DTS) {
m8_lib_handle = (qap_session_handle_t) qap_load_library(QAC_LIB_M8);
if (m8_lib_handle == NULL) {
fprintf(stdout, "Failed to load M8 library\n");
return -EINVAL;
}
fprintf(stdout, "loaded M8 library\n");
dolby_formats = false;
} else if ((stream->filetype == FILE_AC3) ||
(stream->filetype == FILE_EAC3) ||
(stream->filetype == FILE_EAC3_JOC) ||
(stream->filetype == FILE_WAV) ||
(stream->filetype == FILE_AAC) ||
(stream->filetype == FILE_AAC_ADTS) ||
(stream->filetype == FILE_AAC_LATM)) {
ms12_lib_handle = (qap_session_handle_t) qap_load_library(QAC_LIB_MS12);
if (ms12_lib_handle == NULL) {
fprintf(stderr, "Failed to load MS12 library\n");
return -EINVAL;
}
dolby_formats = true;
}
qap_wrapper_is_dap_enabled(kv_pairs, stream->output_device);
// To-Do - Need to check SPDIF out also when SPDIF out is supported
ALOGD("%s::%d output device %d", __func__, __LINE__, stream->output_device);
if (stream->output_device & AUDIO_DEVICE_OUT_HDMI)
update_kvpairs_for_encode(AUDIO_DEVICE_OUT_HDMI);
if (stream->filetype == FILE_DTS)
session_output_config.output_config->bit_width = 24;
bitwidth_kvp = qap_wrapper_get_single_kvp("bitwidth", kv_pairs, &status);
if (bitwidth_kvp != NULL) {
temp_val = qap_wrapper_get_int_value_array(bitwidth_kvp, &temp, &status);
if (temp_val != NULL) {
if (stream->filetype == FILE_DTS)
session_output_config.output_config->bit_width = temp_val[0];
free(temp_val);
temp_val = NULL;
}
free(bitwidth_kvp);
bitwidth_kvp = NULL;
}
if ((session_type == SESSION_BROADCAST) && dolby_formats) {
fprintf(stdout, "%s::%d Setting BROADCAST session for dolby formats\n", __func__, __LINE__);
qap_session_handle = (qap_session_handle_t) qap_session_open(QAP_SESSION_BROADCAST, ms12_lib_handle);
if (qap_session_handle == NULL)
return -EINVAL;
} else if ((session_type == SESSION_BROADCAST) && !dolby_formats) {
fprintf(stdout, "%s::%d Setting BROADCAST session for dts formats\n", __func__, __LINE__);
qap_session_handle = (qap_session_handle_t) qap_session_open(QAP_SESSION_BROADCAST, m8_lib_handle);
if (qap_session_handle == NULL)
return -EINVAL;
} else if (session_type == SESSION_BLURAY) {
fprintf(stdout, "%s::%d Setting BD session\n", __func__, __LINE__);
if (!encode && dolby_formats) {
fprintf(stdout, "%s::%d Setting BD session for decoding dolby formats\n", __func__, __LINE__);
qap_session_handle = (qap_session_handle_t) qap_session_open(QAP_SESSION_DECODE_ONLY, ms12_lib_handle);
if (qap_session_handle == NULL)
return -EINVAL;
} else if (!encode && !dolby_formats) {
fprintf(stdout, "%s::%d Setting BD session for decoding dts formats \n", __func__, __LINE__, qap_session_handle);
qap_session_handle = (qap_session_handle_t) qap_session_open(QAP_SESSION_DECODE_ONLY, m8_lib_handle);
if (qap_session_handle == NULL)
return -EINVAL;
} else if (encode && dolby_formats) {
fprintf(stdout, "%s::%d Setting BD session for encoding dolby formats \n", __func__, __LINE__, qap_session_handle);
qap_session_handle = (qap_session_handle_t) qap_session_open(QAP_SESSION_ENCODE_ONLY, ms12_lib_handle);
if (qap_session_handle == NULL)
return -EINVAL;
} else if (encode && !dolby_formats) {
fprintf(stdout, "%s::%d Setting BD session for encoding dts formats \n", __func__, __LINE__, qap_session_handle);
qap_session_handle = (qap_session_handle_t) qap_session_open(QAP_SESSION_ENCODE_ONLY, m8_lib_handle);
if (qap_session_handle == NULL)
return -EINVAL;
}
}
ret = qap_session_set_callback(qap_session_handle, &qap_wrapper_session_callback);
if (ret != QAP_STATUS_OK) {
fprintf(stderr, "!!!! Please specify appropriate Session\n");
return -EINVAL;
}
if (!session_output_configured) {
session_output_config.output_config->channels = stream->channels;
session_output_config.output_config->sample_rate = stream->config.sample_rate;
if (session_type == SESSION_BROADCAST)
session_output_config.output_config->sample_rate = 48000;
output_device_id = stream->output_device;
if (output_device_id & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
output_device_id |= AUDIO_DEVICE_OUT_SPEAKER;
play_through_bt = true;
}
if (output_device_id & AUDIO_DEVICE_OUT_LINE) {
output_device_id |= AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
}
if (encode) {
if (render_format == 1)
output_device_id |= AUDIO_FORMAT_AC3;
else if (render_format == 2)
output_device_id |= AUDIO_FORMAT_E_AC3;
else if (render_format == 3)
output_device_id |= AUDIO_FORMAT_DTS;
}
session_output_config.output_config->id = output_device_id;
update_combo_dev_kvpairs();
if (stream->filetype != FILE_DTS)
session_output_config.output_config->bit_width = stream->config.offload_info.bit_width;
session_output_config.num_output = 1;
ret = qap_session_cmd(qap_session_handle, QAP_SESSION_CMD_SET_OUTPUTS, sizeof(session_output_config), &session_output_config, NULL, NULL);
if (ret != QAP_STATUS_OK) {
fprintf(stderr, "Output config failed\n");
return -EINVAL;
}
ALOGV("Session set params %s", session_kv_pairs);
ret = qap_session_cmd(qap_session_handle, QAP_SESSION_CMD_SET_KVPAIRS, sizeof(session_kv_pairs), session_kv_pairs, NULL, NULL);
if (ret != QAP_STATUS_OK) {
fprintf(stderr, "Session set params failed\n");
return -EINVAL;
}
usleep(2000);
session_output_configured = true;
}
pthread_mutex_init(&main_eos_lock, (const pthread_mutexattr_t *)NULL);
pthread_mutex_init(&sec_eos_lock, (const pthread_mutexattr_t *)NULL);
pthread_cond_init(&main_eos_cond, (const pthread_condattr_t *) NULL);
pthread_cond_init(&sec_eos_cond, (const pthread_condattr_t *) NULL);
fprintf(stdout, "Session open returing success\n");
return 0;
}
int qap_wrapper_session_close ()
{
ALOGD("closing QAP session");
session_output_configured = false;
qap_session_close(qap_session_handle);
qap_session_handle = NULL;
}
void *qap_wrapper_start_stream (void* stream_data)
{
int ret = 0;
qap_audio_buffer_t *buffer;
int8_t first_read = 1;
int bytes_wanted;
int bytes_read;
int bytes_consumed = 0, status = 0;;
qap_module_handle_t qap_module_handle = NULL;
stream_config *stream_info = (stream_config *)stream_data;
FILE *fp_input = stream_info->file_stream;
int is_buffer_available = 0;
char *temp_str = NULL;
void *reply_data;
char* temp_ptr = NULL;
qap_audio_format_t format;
if (fp_input == NULL) {
fprintf(stderr, "Open File Failed for %s\n", stream_info->filename);
pthread_exit(0);
}
qap_module_handle = stream_info->qap_module_handle;
buffer = (qap_audio_buffer_t *) calloc(1, sizeof(qap_audio_buffer_t));
if (buffer == NULL) {
fprintf(stderr, "%s::%d: Memory Alloc Error\n", __func__, __LINE__);
pthread_exit(0);
}
buffer->common_params.data = calloc(1, FRAME_SIZE);
if (buffer->common_params.data == NULL) {
fprintf(stderr, "%s::%d: Memory Alloc Error\n", __func__, __LINE__);
pthread_exit(0);
if (NULL != buffer) {
free( buffer);
buffer = NULL;
}
}
buffer->buffer_parms.output_buf_params.output_id = output_device_id;
fprintf(stdout, "%s::%d: output device id %d\n",
__func__, __LINE__, buffer->buffer_parms.output_buf_params.output_id);
fprintf(stdout, "Opened Input File %s format %d handle %p\n", stream_info->filename, format, fp_input);
ret = qap_module_cmd(qap_module_handle, QAP_MODULE_CMD_START, sizeof(QAP_MODULE_CMD_START), NULL, NULL, NULL);
if (ret != QAP_STATUS_OK) {
fprintf(stderr, "START failed\n");
pthread_exit(0);
if (NULL != buffer && NULL != buffer->common_params.data) {
free( buffer->common_params.data);
buffer->common_params.data = NULL;
free( buffer);
buffer = NULL;
}
}
do {
if (stream_info->filetype == FILE_WAV) {
if (first_read) {
first_read = 0;
int wav_header_len = get_wav_header_length(stream_info->file_stream);
fseek(fp_input, wav_header_len, SEEK_SET);
}
}
buffer->buffer_parms.input_buf_params.flags = QAP_BUFFER_NO_TSTAMP;
buffer->common_params.timestamp = QAP_BUFFER_NO_TSTAMP;
buffer->common_params.size = stream_info->bytes_to_read;
if (stream_info->timestamp_filename != NULL) {
if (!stream_info->timestamp_file_ptr) {
stream_info->timestamp_file_ptr = fopen(stream_info->timestamp_filename, "r");
if (!stream_info->timestamp_file_ptr) {
fprintf(stderr, "Cannot open audio file %s\n", stream_info->filename);
goto exit;
}
}
read_bytes_timestamps_from_file(buffer, stream_info->timestamp_file_ptr, fp_input);
if (buffer->common_params.timestamp == CONTIGUOUS_TIMESTAMP)
buffer->buffer_parms.input_buf_params.flags = QAP_BUFFER_TSTAMP_CONTINUE;
else
buffer->buffer_parms.input_buf_params.flags = QAP_BUFFER_TSTAMP;
timestamp_mode = true;
}
bytes_wanted = buffer->common_params.size;
bytes_read = fread(data_buf, sizeof(unsigned char), bytes_wanted, fp_input);
buffer->common_params.offset = 0;
buffer->common_params.size = bytes_read;
memcpy(buffer->common_params.data, data_buf, bytes_read);
if (bytes_read <= 0) {
buffer->buffer_parms.input_buf_params.flags = QAP_BUFFER_EOS;
bytes_consumed = qap_module_process(qap_module_handle, buffer);
ret = qap_module_cmd(qap_module_handle, QAP_MODULE_CMD_STOP, sizeof(QAP_MODULE_CMD_STOP), NULL, NULL, NULL);
fprintf(stdout, "Stopped feeding input %s : %p\n", stream_info->filename, fp_input);
ALOGV("Stopped feeding input %s : %p", stream_info->filename, fp_input);
break;
}
reply_data = (char*) calloc(1, 100);
is_buffer_available = 0;
temp_ptr = buffer->common_params.data;
if (kpi_mode) {
if (data_write_count > 5 && data_write_count < TIMESTAMP_ARRAY_SIZE) {
gettimeofday(&tcont_ts1, NULL);
data_input_ts_arr[data_write_count] = buffer->common_params.timestamp;
data_input_st_arr[data_write_count] = (tcont_ts1.tv_sec) * 1000 + (tcont_ts1.tv_usec) / 1000;
ALOGV("%s::%d Kpi cont ts1 %lf, buffer timestamp %ld count %d",
__func__, __LINE__, data_input_st_arr[data_write_count], data_input_ts_arr[data_write_count], data_write_count);
}
if (data_write_count < TIMESTAMP_ARRAY_SIZE)
data_write_count++;
}
do {
bytes_consumed = qap_module_process(qap_module_handle, buffer);
if (bytes_consumed > 0) {
buffer->common_params.data += bytes_consumed;
buffer->common_params.size -= bytes_consumed;
}
ALOGV("%s %d feeding Input of size %d and bytes_cosumed is %d",
__FUNCTION__, __LINE__,bytes_read, bytes_consumed);
if (stream_info->filetype == FILE_DTS) {
if (bytes_consumed < 0) {
while (!is_buffer_available) {
usleep(1000);
ret = qap_module_cmd(qap_module_handle, QAP_MODULE_CMD_GET_PARAM,
sizeof(QAP_MODULE_CMD_GET_PARAM), "buf_available", NULL, reply_data
);
if (reply_data)
temp_str = get_string_value(reply_data, &status);
if (temp_str) {
is_buffer_available = atoi(temp_str);
free(temp_str);
}
ALOGV("%s : %d, dts clip reply_data is %d buffer availabale is %d",
__FUNCTION__, __LINE__, reply_data, is_buffer_available);
}
}
}
} while (buffer->common_params.size > 0);
if (reply_data)
free(reply_data);
buffer->common_params.data = temp_ptr;
if (!(stream_info->system_input || stream_info->sec_input)) {
usleep(5000); //To swtich between main and secondary threads incase of dual input
}
} while (1);
wait_for_eos:
if (stream_info->sec_input && !stream_info->aac_fmt_type) {
pthread_mutex_lock(&sec_eos_lock);
pthread_cond_wait(&sec_eos_cond, &sec_eos_lock);
pthread_mutex_unlock(&sec_eos_lock);
fprintf(stdout, "Received EOS event for secondary input\n");
ALOGV("Received EOS event for secondary input\n");
}
if (!(stream_info->system_input || stream_info->sec_input)){
pthread_mutex_lock(&main_eos_lock);
pthread_cond_wait(&main_eos_cond, &main_eos_lock);
pthread_mutex_unlock(&main_eos_lock);
fprintf(stdout, "Received EOS event for main input\n");
ALOGV("Received EOS event for main input\n");
}
exit:
if (NULL != buffer && NULL != buffer->common_params.data) {
free( buffer->common_params.data);
buffer->common_params.data = NULL;
free( buffer);
buffer = NULL;
}
if ((true == play_list) && (0 == play_list_cnt) && qap_out_hal_handle) {
ALOGV("%s %d QAP_CALLBACK_EVENT_EOS for play list received and unload_hals", __func__, __LINE__);
unload_hals();
qap_out_hal_handle = NULL;
} else if (!play_list && qap_out_hal_handle) {
ALOGV("%s %d QAP_CALLBACK_EVENT_EOS and unload_hals", __func__, __LINE__);
unload_hals();
qap_out_hal_handle = NULL;
}
qap_module_deinit(qap_module_handle);
if (kpi_mode) {
qap_wrapper_measure_kpi_values(cold_start, cold_stop);
}
fprintf(stdout, "%s::%d , THREAD EXIT \n", __func__, __LINE__);
ALOGD("%s::%d , THREAD EXIT \n", __func__, __LINE__);
return NULL;
}
qap_module_handle_t qap_wrapper_stream_open(void* stream_data)
{
qap_module_config_t *input_config = NULL;
int ret = 0;
int i = 0;
stream_config *stream_info = (stream_config *)stream_data;
qap_module_handle_t qap_module_handle = NULL;
input_config = (qap_module_config_t *) calloc(1, sizeof(qap_module_config_t));
if (input_config == NULL) {
fprintf(stderr, "%s::%d Memory Alloc Error\n", __func__, __LINE__);
return NULL;
}
input_config->sample_rate = stream_info->config.sample_rate;
input_config->channels = stream_info->channels;
input_config->bit_width = stream_info->config.offload_info.bit_width;
if (stream_info->filetype == FILE_DTS)
stream_info->bytes_to_read = 10*1024;
else
stream_info->bytes_to_read = 1024;
input_streams_count++;
if (input_streams_count == 2) {
if (stream_info->filetype == FILE_WAV) {
input_config->flags = QAP_MODULE_FLAG_SYSTEM_SOUND;
stream_info->system_input = true;
has_system_input = true;
ALOGV("%s::%d Set Secondary System Sound Flag", __func__, __LINE__);
} else if (stream_info->filetype != FILE_WAV) {
if (stream_info->flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) {
ALOGV("%s::%d Set Secondary Assoc Input Flag", __func__, __LINE__);
input_config->flags = QAP_MODULE_FLAG_SECONDARY;
stream_info->sec_input = true;
} else {
ALOGV("%s::%d Set Secondary Main Input Flag", __func__, __LINE__);
input_config->flags = QAP_MODULE_FLAG_PRIMARY;
stream_info->sec_input = true;
}
}
stream_info->bytes_to_read = 2048;
} else {
if (stream_info->filetype == FILE_WAV) {
ALOGV("%s::%d Set Secondary System Sound Flag", __func__, __LINE__);
input_config->flags = QAP_MODULE_FLAG_SYSTEM_SOUND;
stream_info->system_input = true;
} else {
ALOGV("%s::%d Set Primary Main Input Flag", __func__, __LINE__);
input_config->flags = QAP_MODULE_FLAG_PRIMARY;
}
}
if (!encode)
input_config->module_type = QAP_MODULE_DECODER;
else
input_config->module_type = QAP_MODULE_ENCODER;
ret = qap_wrapper_map_input_format(stream_info->config.offload_info.format, &input_config->format);
if (ret == -EINVAL)
return NULL;
ret = qap_module_init(qap_session_handle, input_config, &qap_module_handle);
if (qap_module_handle == NULL) {
fprintf(stderr, "%s Module Handle is Null\n", __func__);
return NULL;
}
stream_close = false;
return qap_module_handle;
}
void get_play_list(FILE *fp, stream_config (*stream_param)[], int *num_of_streams, char *kvp_str[])
{
char *token = NULL;
char *strings[100] = {NULL};
char cmd_str[500] = {0};
char *tmp_str = NULL;
int i = 0;
do {
int j = 0, cnt = 1, status = 0;
if (fgets(cmd_str, sizeof(cmd_str), fp) != NULL)
tmp_str = strdup(cmd_str);
else
break;
fprintf(stdout, "%s %d\n", __FUNCTION__, __LINE__);
token = strtok(tmp_str, " ");
if (NULL != token) {
strings[cnt] = (char*)calloc(1, (strlen(token) +1));
memset(strings[cnt], '\0', strlen(token) +1);
strncpy(strings[cnt], token, strlen(token));
cnt++;
while (NULL != (token = strtok(NULL, " "))) {
strings[cnt] = (char*)calloc(1, (strlen(token) +1));
memset(strings[cnt], '\0', strlen(token) +1);
strncpy(strings[cnt], token, strlen(token));
cnt++;
}
strings[0] = calloc(1, 4);
memset(strings[0], '\0', 4);
strncpy(strings[0], "play_list", 3);
for (j = 0;j< cnt;j++) {
if (!strncmp(strings[j], "-f", 2)) {
(*stream_param)[i].filename = strdup(strings[j+1]);
} else if (!strncmp(strings[j], "-r", 2)) {
(*stream_param)[i].config.offload_info.sample_rate = atoi(strings[j+1]);
(*stream_param)[i].config.sample_rate = atoi(strings[j+1]);
} else if (!strncmp(strings[j], "-c", 2)) {
(*stream_param)[i].channels = atoi(strings[j+1]);
(*stream_param)[i].config.channel_mask = audio_channel_out_mask_from_count(atoi(strings[j+1]));
} else if (!strncmp(strings[j], "-b", 2)) {
(*stream_param)[i].config.offload_info.bit_width = atoi(strings[j+1]);
} else if (!strncmp(strings[j], "-d", 2)) {
(*stream_param)[i].output_device = atoll(strings[j+1]);
} else if (!strncmp(strings[j], "-t", 2)) {
(*stream_param)[i].filetype = atoi(strings[j+1]);
} else if (!strncmp(strings[j], "-a", 2)) {
(*stream_param)[i].aac_fmt_type = atoi(strings[j+1]);
}
}
}
if(NULL != (*stream_param)[i].filename) {
*num_of_streams = i+1;
play_list = true;
kvp_str[i] = (char *)qap_wrapper_get_cmd_string_from_arg_array(cnt, (char**)strings, &status);
}
free(tmp_str);
for (j=0; j < cnt; j++)
free(strings[j]);
i++;
}while(NULL != cmd_str);
return;
}
void hal_test_qap_usage() {
printf(" \n qap commands \n");
printf(" -qap - Enabling playback through QAP for nun tunnel decoding mode\n");
printf(" -bd - Enabling Broadcast Decode/Encode session through QAP\n");
printf(" -broadcast - Enabling playback through QAP for nun tunnel decoding mode\n");
printf(" -y --timestamp filename - Input timestamp file to be used to send timestamp and bytes to be read from main input file.\n");
printf(" -z --framesize filename - Input framesize file to be used to send bytes to be read from main input file.\n");
printf(" hal_play_test -qap -broadcast -f /data/5ch_dd_25fps_channeld_id.ac3 -t 9 -d 2 -v 0.01 -r 48000 -c 6 \n");
printf(" -> plays AC3 stream(-t = 9) on speaker device(-d = 2)\n");
printf(" -> 6 channels and 48000 sample rate\n\n");
printf(" -> using QAP with Broadcast session\n\n");
printf(" hal_play_test -qap -bd -f /data/200_48_16_ieq_mix_voice_40s.ec3 -t 11 -d 2 -v 0.01 -r 48000 -c 2 \n");
printf(" -> plays EAC3 stream(-t = 11) on speaker device(-d = 2)\n");
printf(" -> 2 channels and 48000 sample rate\n\n");
printf(" -> using QAP with Bluray session\n\n");
}