Merge "configs: add system property to set AudioFlinger client heap size"
diff --git a/configs/apq8098_latv/apq8098_latv.mk b/configs/apq8098_latv/apq8098_latv.mk
index e5c8978..242c6d5 100644
--- a/configs/apq8098_latv/apq8098_latv.mk
+++ b/configs/apq8098_latv/apq8098_latv.mk
@@ -123,117 +123,105 @@
# Low latency audio buffer size in frames
PRODUCT_PROPERTY_OVERRIDES += \
- audio_hal.period_size=192
+ vendor.audio_hal.period_size=192
##fluencetype can be "fluence" or "fluencepro" or "none"
PRODUCT_PROPERTY_OVERRIDES += \
-ro.qc.sdk.audio.fluencetype=none\
-persist.audio.fluence.voicecall=true\
-persist.audio.fluence.voicerec=false\
-persist.audio.fluence.speaker=true
+ro.vendor.audio.sdk.fluencetype=none\
+persist.vendor.audio.fluence.voicecall=true\
+persist.vendor.audio.fluence.voicerec=false\
+persist.vendor.audio.fluence.speaker=true
#disable tunnel encoding
PRODUCT_PROPERTY_OVERRIDES += \
-tunnel.audio.encode=false
+vendor.audio.tunnel.encode=false
#Disable RAS Feature by default
PRODUCT_PROPERTY_OVERRIDES += \
-persist.audio.ras.enabled=false
+persist.vendor.audio.ras.enabled=false
#Buffer size in kbytes for compress offload playback
PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.buffer.size.kb=32
+vendor.audio.offload.buffer.size.kb=32
#Enable offload audio video playback by default
PRODUCT_PROPERTY_OVERRIDES += \
audio.offload.video=true
-#Enable 16 bit PCM offload by default
-PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.pcm.16bit.enable=true
-
-#Enable 24 bit PCM offload by default
-PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.pcm.24bit.enable=true
-
#Enable audio track offload by default
PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.track.enable=true
+vendor.audio.offload.track.enable=true
#Enable music through deep buffer
PRODUCT_PROPERTY_OVERRIDES += \
audio.deep_buffer.media=true
-#QC property used when calculating client heap size in audio flinger
-PRODUCT_PROPERTY_OVERRIDES += \
-audio.heap.size.multiplier=7
-
#enable voice path for PCM VoIP by default
PRODUCT_PROPERTY_OVERRIDES += \
-use.voice.path.for.pcm.voip=true
+vendor.voice.path.for.pcm.voip=true
#Enable multi channel aac through offload
PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.multiaac.enable=true
+vendor.audio.offload.multiaac.enable=true
#Enable DS2, Hardbypass feature for Dolby
PRODUCT_PROPERTY_OVERRIDES += \
-audio.dolby.ds2.enabled=false\
-audio.dolby.ds2.hardbypass=false
+vendor.audio.dolby.ds2.enabled=false\
+vendor.audio.dolby.ds2.hardbypass=false
#Disable Multiple offload sesison
PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.multiple.enabled=false
+vendor.audio.offload.multiple.enabled=false
#Disable Compress passthrough playback
PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.passthrough=false
+vendor.audio.offload.passthrough=false
#Disable surround sound recording
PRODUCT_PROPERTY_OVERRIDES += \
-ro.qc.sdk.audio.ssr=false
+ro.vendor.audio.sdk.ssr=false
#enable dsp gapless mode by default
PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.gapless.enabled=true
+vendor.audio.offload.gapless.enabled=true
#enable pbe effects
PRODUCT_PROPERTY_OVERRIDES += \
-audio.safx.pbe.enabled=true
+vendor.audio.safx.pbe.enabled=true
#parser input buffer size(256kb) in byte stream mode
PRODUCT_PROPERTY_OVERRIDES += \
-audio.parser.ip.buffer.size=262144
+vendor.audio.parser.ip.buffer.size=262144
#flac sw decoder 24 bit decode capability
PRODUCT_PROPERTY_OVERRIDES += \
-flac.sw.decoder.24bit.support=true
+vendor.audio.flac.sw.decoder.24bit=true
#split a2dp DSP supported encoder list
PRODUCT_PROPERTY_OVERRIDES += \
-persist.bt.a2dp_offload_cap=sbc-aptx-aptxhd-aac
+persist.vendor.bt.a2dp_offload_cap=sbc-aptx-aptxhd-aac
#enable software decoders for ALAC and APE
PRODUCT_PROPERTY_OVERRIDES += \
-use.qti.sw.alac.decoder=true
+vendor.audio.use.sw.alac.decoder=true
PRODUCT_PROPERTY_OVERRIDES += \
-use.qti.sw.ape.decoder=true
+vendor.audio.use.sw.ape.decoder=true
#enable hw aac encoder by default
PRODUCT_PROPERTY_OVERRIDES += \
-qcom.hw.aac.encoder=true
+vendor.audio.hw.aac.encoder=true
#Disable FM a2dp concurrency
PRODUCT_PROPERTY_OVERRIDES += \
-fm.a2dp.conc.disabled=true
+vendor.fm.a2dp.conc.disabled=true
#audio becoming noisy intent broadcast delay
PRODUCT_PROPERTY_OVERRIDES += \
-audio.noisy.broadcast.delay=600
+vendor.audio.noisy.broadcast.delay=600
#offload pausetime out duration to 3 secs to inline with other outputs
PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.pstimeout.secs=3
+vendor.audio.offload.pstimeout.secs=3
#Set AudioFlinger client heap size
PRODUCT_PROPERTY_OVERRIDES += \
diff --git a/configs/apq8098_latv/audio_policy_configuration.xml b/configs/apq8098_latv/audio_policy_configuration.xml
index fafd322..c8707e3 100644
--- a/configs/apq8098_latv/audio_policy_configuration.xml
+++ b/configs/apq8098_latv/audio_policy_configuration.xml
@@ -329,7 +329,7 @@
<route type="mix" sink="voice_rx"
sources="Telephony Rx"/>
<route type="mix" sink="primary input"
- sources="Wired Headset Mic,BT SCO Headset Mic,FM Tuner,USB Device In,Telephony Rx"/>
+ sources="Built-In Mic,Wired Headset Mic,BT SCO Headset Mic,FM Tuner,USB Device In,Telephony Rx"/>
<route type="mix" sink="surround_sound"
sources="Built-In Mic,Built-In Back Mic"/>
<route type="mix" sink="record_24"
diff --git a/configs/msm8998/mixer_paths_tasha.xml b/configs/msm8998/mixer_paths_tasha.xml
index a7dfbeb..93656e6 100644
--- a/configs/msm8998/mixer_paths_tasha.xml
+++ b/configs/msm8998/mixer_paths_tasha.xml
@@ -125,6 +125,10 @@
<ctl name="MultiMedia1 Mixer SLIM_0_TX" value="0" />
<ctl name="MultiMedia1 Mixer SLIM_4_TX" value="0" />
<ctl name="MultiMedia1 Mixer SLIM_7_TX" value="0" />
+ <ctl name="HDMI RX Format" value="LPCM" />
+ <ctl name="HDMI_RX Bit Format" value="S16_LE" />
+ <ctl name="HDMI_RX SampleRate" value="KHZ_48" />
+ <ctl name="HDMI_RX Channels" value="Two" />
<ctl name="HDMI Mixer MultiMedia1" value="0" />
<ctl name="HDMI Mixer MultiMedia2" value="0" />
<ctl name="HDMI Mixer MultiMedia3" value="0" />
@@ -139,6 +143,10 @@
<ctl name="HDMI Mixer MultiMedia14" value="0" />
<ctl name="HDMI Mixer MultiMedia15" value="0" />
<ctl name="HDMI Mixer MultiMedia16" value="0" />
+ <ctl name="Display Port RX Format" value="LPCM" />
+ <ctl name="Display Port RX Bit Format" value="S16_LE" />
+ <ctl name="Display Port RX SampleRate" value="KHZ_48" />
+ <ctl name="Display Port RX Channels" value="Two" />
<ctl name="DISPLAY_PORT Mixer MultiMedia1" value="0" />
<ctl name="DISPLAY_PORT Mixer MultiMedia2" value="0" />
<ctl name="DISPLAY_PORT Mixer MultiMedia3" value="0" />
diff --git a/configs/msm8998/mixer_paths_tavil.xml b/configs/msm8998/mixer_paths_tavil.xml
index def9580..ba37799 100644
--- a/configs/msm8998/mixer_paths_tavil.xml
+++ b/configs/msm8998/mixer_paths_tavil.xml
@@ -72,6 +72,10 @@
<ctl name="MultiMedia8 Mixer SLIM_0_TX" value="0" />
<ctl name="MultiMedia8 Mixer SLIM_4_TX" value="0" />
<ctl name="MultiMedia8 Mixer SLIM_7_TX" value="0" />
+ <ctl name="HDMI RX Format" value="LPCM" />
+ <ctl name="HDMI_RX Bit Format" value="S16_LE" />
+ <ctl name="HDMI_RX SampleRate" value="KHZ_48" />
+ <ctl name="HDMI_RX Channels" value="Two" />
<ctl name="HDMI Mixer MultiMedia1" value="0" />
<ctl name="HDMI Mixer MultiMedia2" value="0" />
<ctl name="HDMI Mixer MultiMedia3" value="0" />
@@ -86,6 +90,10 @@
<ctl name="HDMI Mixer MultiMedia14" value="0" />
<ctl name="HDMI Mixer MultiMedia15" value="0" />
<ctl name="HDMI Mixer MultiMedia16" value="0" />
+ <ctl name="Display Port RX Format" value="LPCM" />
+ <ctl name="Display Port RX Bit Format" value="S16_LE" />
+ <ctl name="Display Port RX SampleRate" value="KHZ_48" />
+ <ctl name="Display Port RX Channels" value="Two" />
<ctl name="DISPLAY_PORT Mixer MultiMedia1" value="0" />
<ctl name="DISPLAY_PORT Mixer MultiMedia2" value="0" />
<ctl name="DISPLAY_PORT Mixer MultiMedia3" value="0" />
diff --git a/configure.ac b/configure.ac
index da39527..978d235 100644
--- a/configure.ac
+++ b/configure.ac
@@ -114,6 +114,7 @@
AM_CONDITIONAL([AUDIO_HW_LOOPBACK], [test x$AUDIO_FEATURE_ENABLED_AUDIO_HW_LOOPBACK = xtrue])
AM_CONDITIONAL([AUDIO_PARSER], [test x$AUDIO_FEATURE_ENABLED_PARSER = xtrue])
AM_CONDITIONAL([DTSHD_PARSER], [test x$AUDIO_FEATURE_ENABLED_DTSHD_PARSER = xtrue])
+AM_CONDITIONAL([QAP], [test x$AUDIO_FEATURE_ENABLED_QAP = xtrue])
AC_CONFIG_FILES([ \
Makefile \
diff --git a/hal/audio_extn/a2dp.c b/hal/audio_extn/a2dp.c
index 2103930..9ebc0f2 100644
--- a/hal/audio_extn/a2dp.c
+++ b/hal/audio_extn/a2dp.c
@@ -1038,6 +1038,7 @@
a2dp.enc_sampling_rate = 48000;
a2dp.is_a2dp_offload_supported = false;
a2dp.is_handoff_in_progress = false;
+ reset_a2dp_enc_config_params();
update_offload_codec_capabilities();
}
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index a1b1344..2726d40 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -99,16 +99,24 @@
#define AUDIO_FORMAT_AC4 0x23000000UL
#endif
-#ifndef AUDIO_OUTPUT_FLAG_TIMESTAMP
-#define AUDIO_OUTPUT_FLAG_TIMESTAMP 0x10000
+#ifndef AUDIO_OUTPUT_FLAG_MAIN
+#define AUDIO_OUTPUT_FLAG_MAIN 0x8000000
#endif
-#ifndef AUDIO_OUTPUT_FLAG_BD10
-#define AUDIO_OUTPUT_FLAG_BD10 0x20000
+#ifndef AUDIO_OUTPUT_FLAG_ASSOCIATED
+#define AUDIO_OUTPUT_FLAG_ASSOCIATED 0x10000000
+#endif
+
+#ifndef AUDIO_OUTPUT_FLAG_TIMESTAMP
+#define AUDIO_OUTPUT_FLAG_TIMESTAMP 0x20000000
+#endif
+
+#ifndef AUDIO_OUTPUT_FLAG_BD
+#define AUDIO_OUTPUT_FLAG_BD 0x40000000
#endif
#ifndef AUDIO_OUTPUT_FLAG_INTERACTIVE
-#define AUDIO_OUTPUT_FLAG_INTERACTIVE 0x40000
+#define AUDIO_OUTPUT_FLAG_INTERACTIVE 0x80000000
#endif
#ifndef COMPRESS_METADATA_NEEDED
@@ -508,6 +516,8 @@
#define audio_extn_passthru_init(a) do {} while(0)
#define audio_extn_passthru_should_standby(o) (1)
#define audio_extn_passthru_get_channel_count(out) (0)
+#define audio_extn_passthru_update_dts_stream_configuration(out, buffer, bytes) (-ENOSYS)
+#define audio_extn_passthru_is_direct_passthrough(out) (0)
#else
bool audio_extn_passthru_is_convert_supported(struct audio_device *adev,
struct stream_out *out);
@@ -532,6 +542,9 @@
void audio_extn_passthru_init(struct audio_device *adev);
bool audio_extn_passthru_should_standby(struct stream_out *out);
int audio_extn_passthru_get_channel_count(struct stream_out *out);
+int audio_extn_passthru_update_dts_stream_configuration(struct stream_out *out,
+ const void *buffer, size_t bytes);
+bool audio_extn_passthru_is_direct_passthrough(struct stream_out *out);
#endif
#ifndef HFP_ENABLED
diff --git a/hal/audio_extn/hw_loopback.c b/hal/audio_extn/hw_loopback.c
index 180e575..7c846d9 100644
--- a/hal/audio_extn/hw_loopback.c
+++ b/hal/audio_extn/hw_loopback.c
@@ -41,7 +41,10 @@
#define PATCH_HANDLE_INVALID 0xFFFF
#define MAX_SOURCE_PORTS_PER_PATCH 1
#define MAX_SINK_PORTS_PER_PATCH 1
+#define HW_LOOPBACK_RX_VOLUME "Trans Loopback RX Volume"
+#define HW_LOOPBACK_RX_UNITY_GAIN 0x2000
+#include <math.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
@@ -59,7 +62,8 @@
#include <system/thread_defs.h>
#include <cutils/sched_policy.h>
#include "audio_extn.h"
-#include "sound/compress_params.h"
+#include <sound/compress_params.h>
+#include <sound/compress_offload.h>
#include <system/audio.h>
/*
@@ -131,6 +135,34 @@
}
}
+/* Set loopback volume : for mute implementation */
+static int hw_loopback_set_volume(struct audio_device *adev, int value)
+{
+ int32_t ret = 0;
+ struct mixer_ctl *ctl;
+ char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT];
+ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "Transcode Loopback Rx Volume");
+
+ ALOGD("%s: (%d)\n", __func__, value);
+
+ ALOGD("%s: Setting HW loopback volume to %d \n", __func__, value);
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+
+ if(mixer_ctl_set_value(ctl, 0, value) < 0) {
+ ALOGE("%s: Couldn't set HW Loopback Volume: [%d]", __func__, value);
+ return -EINVAL;
+ }
+
+ ALOGV("%s: exit", __func__);
+ return ret;
+}
+
/* Initialize patch database */
int init_patch_database(patch_db_t* patch_db)
{
@@ -147,7 +179,8 @@
{
if((sink_device_mask & AUDIO_DEVICE_OUT_SPEAKER) ||
(sink_device_mask & AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
- (sink_device_mask & AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+ (sink_device_mask & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
+ (sink_device_mask & AUDIO_DEVICE_OUT_LINE)) {
return true;
}
return false;
@@ -270,7 +303,7 @@
adev->active_input = get_next_active_input(adev);
- if (audio_extn_ip_hdlr_intf_supported(source_patch_config->format, false) && inout->ip_hdlr_handle) {
+ if (inout->ip_hdlr_handle) {
ret = audio_extn_ip_hdlr_intf_close(inout->ip_hdlr_handle, true, inout);
if (ret < 0)
ALOGE("%s: audio_extn_ip_hdlr_intf_close failed %d",__func__, ret);
@@ -284,8 +317,7 @@
inout->adsp_hdlr_stream_handle = NULL;
}
- if (audio_extn_ip_hdlr_intf_supported(source_patch_config->format, false) &&
- inout->ip_hdlr_handle) {
+ if (inout->ip_hdlr_handle) {
audio_extn_ip_hdlr_intf_deinit(inout->ip_hdlr_handle);
inout->ip_hdlr_handle = NULL;
}
@@ -306,6 +338,27 @@
return 0;
}
+#if defined SNDRV_COMPRESS_LATENCY_MODE
+static void transcode_loopback_util_set_latency_mode(
+ loopback_patch_t *active_loopback_patch,
+ uint32_t latency_mode)
+{
+ struct snd_compr_metadata metadata;
+
+ metadata.key = SNDRV_COMPRESS_LATENCY_MODE;
+ metadata.value[0] = latency_mode;
+ ALOGV("%s: Setting latency mode %d",__func__, latency_mode);
+ compress_set_metadata(active_loopback_patch->source_stream,&metadata);
+}
+#else
+static void transcode_loopback_util_set_latency_mode(
+ loopback_patch_t *active_loopback_patch __unused,
+ uint32_t latency_mode __unused)
+{
+ ALOGD("%s:: Latency mode configuration not supported", __func__);
+}
+#endif
+
/* Create a loopback session based on active loopback patch selected */
int create_loopback_session(loopback_patch_t *active_loopback_patch)
{
@@ -323,6 +376,7 @@
struct stream_inout *inout = &active_loopback_patch->patch_stream;
struct adsp_hdlr_stream_cfg hdlr_stream_cfg;
struct stream_in loopback_source_stream;
+ char prop_value[PROPERTY_VALUE_MAX] = {0};
ALOGD("%s: Create loopback session begin", __func__);
@@ -381,8 +435,9 @@
inout->adsp_hdlr_stream_handle = NULL;
goto exit;
}
- if (audio_extn_ip_hdlr_intf_supported(source_patch_config->format, false)) {
- ret = audio_extn_ip_hdlr_intf_init(&inout->ip_hdlr_handle, NULL, NULL);
+ if (audio_extn_ip_hdlr_intf_supported(source_patch_config->format,false, true)) {
+ ret = audio_extn_ip_hdlr_intf_init(&inout->ip_hdlr_handle, NULL, NULL, adev,
+ USECASE_AUDIO_TRANSCODE_LOOPBACK);
if (ret < 0) {
ALOGE("%s: audio_extn_ip_hdlr_intf_init failed %d", __func__, ret);
inout->ip_hdlr_handle = NULL;
@@ -434,6 +489,14 @@
sink_config.fragments = 1;
sink_config.codec = &codec;
+ /* Do not alter the location of sending latency mode property */
+ /* Mode set on any stream but before both streams are open */
+ if(property_get("audio.transcode.latency.mode", prop_value, "")) {
+ uint32_t latency_mode = atoi(prop_value);
+ transcode_loopback_util_set_latency_mode(active_loopback_patch,
+ latency_mode);
+ }
+
/* Open compress stream in playback path */
active_loopback_patch->sink_stream = compress_open(adev->snd_card,
pcm_dev_asm_rx_id, COMPRESS_IN, &sink_config);
@@ -467,7 +530,7 @@
ret = -EINVAL;
goto exit;
}
- if (audio_extn_ip_hdlr_intf_supported(source_patch_config->format, false) && inout->ip_hdlr_handle) {
+ if (inout->ip_hdlr_handle) {
ret = audio_extn_ip_hdlr_intf_open(inout->ip_hdlr_handle, true, inout,
USECASE_AUDIO_TRANSCODE_LOOPBACK);
if (ret < 0) {
@@ -662,8 +725,7 @@
struct audio_port *port_in)
{
int status = 0, n=0, patch_num=-1;
- loopback_patch_t *active_loopback_patch = NULL;
- port_info_t *port_info = NULL;
+ port_info_t port_info;
struct audio_port_config *port_out=NULL;
ALOGV("%s %d", __func__, __LINE__);
@@ -675,10 +737,10 @@
pthread_mutex_lock(&audio_loopback_mod->lock);
- port_info->id = port_in->id;
- port_info->role = port_in->role; /* sink or source */
- port_info->type = port_in->type; /* device, mix ... */
- port_out = get_port_from_patch_db(port_info, &audio_loopback_mod->patch_db,
+ port_info.id = port_in->id;
+ port_info.role = port_in->role; /* sink or source */
+ port_info.type = port_in->type; /* device, mix ... */
+ port_out = get_port_from_patch_db(&port_info, &audio_loopback_mod->patch_db,
&patch_num);
if (port_out == NULL) {
ALOGE("%s, Unable to find a valid matching port in patch \
@@ -709,40 +771,64 @@
const struct audio_port_config *config)
{
int status = 0, n=0, patch_num=-1;
- loopback_patch_t *active_loopback_patch = NULL;
- port_info_t *port_info = NULL;
+ port_info_t port_info;
struct audio_port_config *port_out=NULL;
+ struct audio_device *adev = audio_loopback_mod->adev;
+ int loopback_gain = HW_LOOPBACK_RX_UNITY_GAIN;
+
ALOGV("%s %d", __func__, __LINE__);
if ((audio_loopback_mod == NULL) || (dev == NULL)) {
ALOGE("%s, Invalid device", __func__);
- status = -1;
+ status = -EINVAL;
return status;
}
pthread_mutex_lock(&audio_loopback_mod->lock);
- port_info->id = config->id;
- port_info->role = config->role; /* sink or source */
- port_info->type = config->type; /* device, mix */
- port_out = get_port_from_patch_db(port_info, &audio_loopback_mod->patch_db
+ port_info.id = config->id;
+ port_info.role = config->role; /* sink or source */
+ port_info.type = config->type; /* device, mix */
+ port_out = get_port_from_patch_db(&port_info, &audio_loopback_mod->patch_db
, &patch_num);
if (port_out == NULL) {
ALOGE("%s, Unable to find a valid matching port in patch \
database,exiting", __func__);
- status = -1;
- return status;
+ status = -EINVAL;
+ goto exit_set_port_config;
}
- port_out->config_mask = config->config_mask;
- port_out->channel_mask = config->channel_mask;
- port_out->format = config->format;
- port_out->gain = config->gain;
- port_out->sample_rate = config->sample_rate;
+ port_out->config_mask |= config->config_mask;
+ if(config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK)
+ port_out->channel_mask = config->channel_mask;
+ if(config->config_mask & AUDIO_PORT_CONFIG_FORMAT)
+ port_out->format = config->format;
+ if(config->config_mask & AUDIO_PORT_CONFIG_GAIN)
+ port_out->gain = config->gain;
+ if(config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE)
+ port_out->sample_rate = config->sample_rate;
+
+ /* Convert gain in millibels to ratio and convert to Q13 */
+ loopback_gain = pow(10, (float)((float)port_out->gain.values[0]/2000)) *
+ (1 << 13);
+ ALOGV("%s, Port config gain_in_mbells: %d, gain_in_q13 : %d", __func__,
+ port_out->gain.values[0], loopback_gain);
+ if((port_out->config_mask & AUDIO_PORT_CONFIG_GAIN) &&
+ port_out->gain.mode == AUDIO_GAIN_MODE_JOINT ) {
+ status = hw_loopback_set_volume(adev, loopback_gain);
+ if (status) {
+ ALOGE("%s, Error setting loopback gain config: status %d",
+ __func__, status);
+ }
+ } else {
+ ALOGE("%s, Unsupported port config ,exiting", __func__);
+ status = -EINVAL;
+ }
/* Currently, port config is not used for anything,
need to restart session */
+exit_set_port_config:
pthread_mutex_unlock(&audio_loopback_mod->lock);
return status;
}
diff --git a/hal/audio_extn/ip_hdlr_intf.c b/hal/audio_extn/ip_hdlr_intf.c
index 0f31f21..a94e6de 100644
--- a/hal/audio_extn/ip_hdlr_intf.c
+++ b/hal/audio_extn/ip_hdlr_intf.c
@@ -70,6 +70,7 @@
int (*deinit)(void *handle);
int (*open)(void *handle, bool is_dsp_decode, void *aud_sess_handle);
int (*shm_info)(void *handle, int *fd);
+ int (*get_lib_fd)(void *handle, int *lib_fd);
int (*close)(void *handle);
int (*event)(void *handle, void *payload);
int (*reg_cb)(void *handle, void *ack_cb, void *fail_cb);
@@ -116,12 +117,20 @@
uint8_t payload[0];
};
-bool audio_extn_ip_hdlr_intf_supported(audio_format_t format,bool is_direct_passthru)
+bool audio_extn_ip_hdlr_intf_supported(audio_format_t format,
+ bool is_direct_passthrough,
+ bool is_transcode_loopback)
{
- if (((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_DOLBY_TRUEHD) ||
- ((!is_direct_passthru) &&
- (((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_E_AC3) ||
- ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AC3))))
+
+ if ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_DOLBY_TRUEHD)
+ return true;
+ else if (!is_direct_passthrough && !audio_extn_qaf_is_enabled() &&
+ (((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_E_AC3) ||
+ ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AC3)))
+ return true;
+ else if (is_transcode_loopback &&
+ (((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_E_AC3) ||
+ ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AC3)))
return true;
else
return false;
@@ -416,9 +425,13 @@
return ret;
}
-int audio_extn_ip_hdlr_intf_init(void **handle, char *lib_path, void **lib_handle)
+int audio_extn_ip_hdlr_intf_init(void **handle, char *lib_path, void **lib_handle,
+ struct audio_device *dev, audio_usecase_t usecase)
{
- int ret = 0;
+ int ret = 0, pcm_device_id;
+ int lib_fd;
+ struct mixer_ctl *ctl = NULL;
+ char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
if (!ip_hdlr) {
ip_hdlr = (struct ip_hdlr_intf *)calloc(1, sizeof(struct ip_hdlr_intf));
@@ -444,11 +457,13 @@
void *fail_cb))dlsym(ip_hdlr->lib_hdl, "audio_ip_hdlr_reg_cb");
ip_hdlr->shm_info =(int (*)(void *handle, int *fd))dlsym(ip_hdlr->lib_hdl,
"audio_ip_hdlr_shm_info");
+ ip_hdlr->get_lib_fd =(int (*)(void *handle, int *fd))dlsym(ip_hdlr->lib_hdl,
+ "audio_ip_hdlr_lib_fd");
ip_hdlr->event =(int (*)(void *handle, void *payload))dlsym(ip_hdlr->lib_hdl,
"audio_ip_hdlr_event");
if (!ip_hdlr->init || !ip_hdlr->deinit || !ip_hdlr->open ||
!ip_hdlr->close || !ip_hdlr->reg_cb || !ip_hdlr->shm_info ||
- !ip_hdlr->event) {
+ !ip_hdlr->event || !ip_hdlr->get_lib_fd) {
ALOGE("%s: failed to get symbols", __func__);
ret = -EINVAL;
goto dlclose;
@@ -462,6 +477,32 @@
ret = -EINVAL;
goto dlclose;
}
+ if (!lib_path) {
+ ip_hdlr->get_lib_fd(*handle, &lib_fd);
+
+ pcm_device_id = platform_get_pcm_device_id(usecase, PCM_PLAYBACK);
+ ret = snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "Playback ION LIB FD %d", pcm_device_id);
+ if (ret < 0) {
+ ALOGE("%s:[%d] snprintf failed",__func__, ip_hdlr->ref_cnt, ret);
+ goto dlclose;
+ }
+ ALOGV("%s: fd = %d pcm_id = %d", __func__, lib_fd, pcm_device_id);
+
+ ctl = mixer_get_ctl_by_name(dev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s:[%d] Could not get ctl for mixer cmd - %s", __func__,
+ ip_hdlr->ref_cnt, mixer_ctl_name);
+ ret = -EINVAL;
+ goto dlclose;
+ }
+ ret = mixer_ctl_set_array(ctl, &lib_fd, sizeof(lib_fd));
+ if (ret < 0) {
+ ALOGE("%s:[%d] Could not set ctl for mixer cmd - %s, ret %d", __func__, ip_hdlr->ref_cnt,
+ mixer_ctl_name, ret);
+ goto dlclose;
+ }
+ }
ip_hdlr->ref_cnt++;
ALOGD("%s:[%d] init done", __func__, ip_hdlr->ref_cnt);
diff --git a/hal/audio_extn/ip_hdlr_intf.h b/hal/audio_extn/ip_hdlr_intf.h
index 1f2c304..6040620 100644
--- a/hal/audio_extn/ip_hdlr_intf.h
+++ b/hal/audio_extn/ip_hdlr_intf.h
@@ -35,17 +35,20 @@
int audio_extn_ip_hdlr_intf_open(void *handle, bool is_dsp_decode, void *aud_sess_handle,
audio_usecase_t usecase);
int audio_extn_ip_hdlr_intf_close(void *handle, bool is_dsp_decode, void *aud_sess_handle);
-int audio_extn_ip_hdlr_intf_init(void **handle, char *lib_path, void **lib_handle);
+int audio_extn_ip_hdlr_intf_init(void **handle, char *lib_path, void **lib_handle,
+ struct audio_device *dev, audio_usecase_t usecase);
int audio_extn_ip_hdlr_intf_deinit(void *handle);
-bool audio_extn_ip_hdlr_intf_supported(audio_format_t format, bool is_direct_passthru);
+bool audio_extn_ip_hdlr_intf_supported(audio_format_t format,
+ bool is_direct_passthru,
+ bool is_transcode_loopback);
#else
#define audio_extn_ip_hdlr_intf_open(handle, is_dsp_decode, aud_sess_handle, usecase) (0)
-#define audio_extn_ip_hdlr_intf_close(handle, is_dsp_decode, aud_sess_handle) (0)
-#define audio_extn_ip_hdlr_intf_init(handle, lib_path, lib_handle) (0)
+#define audio_extn_ip_hdlr_intf_close(handle, is_dsp_decode, aud_sess_handle) (0)
+#define audio_extn_ip_hdlr_intf_init(handle, lib_path, lib_handlei, adev, usecase) (0)
#define audio_extn_ip_hdlr_intf_deinit(handle) (0)
-#define audio_extn_ip_hdlr_intf_supported(format, is_direct_passthru) (0)
+#define audio_extn_ip_hdlr_intf_supported(format, is_direct_passthru, is_loopback) (0)
#endif
diff --git a/hal/audio_extn/keep_alive.c b/hal/audio_extn/keep_alive.c
index 8bd1da1..3e9a91c 100644
--- a/hal/audio_extn/keep_alive.c
+++ b/hal/audio_extn/keep_alive.c
@@ -49,6 +49,7 @@
STATE_DEINIT = -1,
STATE_IDLE,
STATE_ACTIVE,
+ STATE_DISABLED,
} state_t;
typedef enum {
@@ -93,6 +94,13 @@
ka.userdata = adev;
ka.state = STATE_IDLE;
ka.pcm = NULL;
+
+ if (property_get_bool("audio.keep_alive.disabled", false)) {
+ ALOGE("keep alive disabled");
+ ka.state = STATE_DISABLED;
+ return;
+ }
+
pthread_mutex_init(&ka.lock, (const pthread_mutexattr_t *) NULL);
pthread_cond_init(&ka.cond, (const pthread_condattr_t *) NULL);
pthread_cond_init(&ka.wake_up_cond, (const pthread_condattr_t *) NULL);
@@ -108,7 +116,7 @@
static void send_cmd_l(request_t r)
{
- if (ka.state == STATE_DEINIT)
+ if (ka.state == STATE_DEINIT || ka.state == STATE_DISABLED)
return;
struct keep_alive_cmd *cmd =
@@ -193,6 +201,9 @@
struct audio_usecase *usecase;
int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+ if (ka.state == STATE_DISABLED)
+ return;
+
pthread_mutex_lock(&ka.lock);
if (ka.state == STATE_DEINIT) {
@@ -317,6 +328,9 @@
{
struct audio_device * adev = (struct audio_device *)ka.userdata;
+ if (ka.state == STATE_DISABLED)
+ return;
+
pthread_mutex_lock(&ka.lock);
if ((ka.state == STATE_DEINIT) || (ka.state == STATE_IDLE))
@@ -359,6 +373,9 @@
char value[32];
int ret;
+ if (ka.state == STATE_DISABLED)
+ return;
+
ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
if (ret >= 0) {
int val = atoi(value);
diff --git a/hal/audio_extn/passthru.c b/hal/audio_extn/passthru.c
index ee9995c..701084a 100644
--- a/hal/audio_extn/passthru.c
+++ b/hal/audio_extn/passthru.c
@@ -90,7 +90,7 @@
static volatile int32_t compress_passthru_active;
#ifdef DTSHD_PARSER_ENABLED
-static void passthru_update_stream_configuration_from_dts_parser( struct stream_out *out,
+int audio_extn_passthru_update_dts_stream_configuration(struct stream_out *out,
const void *buffer, size_t bytes)
{
struct audio_parser_codec_info codec_info;
@@ -100,6 +100,27 @@
bool is_valid_transmission_rate = false;
bool is_valid_transmission_channels = false;
+ if (!out) {
+ ALOGE("Invalid session");
+ return -EINVAL;
+ }
+
+ if ((out->format != AUDIO_FORMAT_DTS) &&
+ (out->format != AUDIO_FORMAT_DTS_HD)) {
+ ALOGE("Non DTS format %d", out->format);
+ return -EINVAL;
+ }
+
+ if (!buffer || bytes <= 0) {
+ ALOGD("Invalid buffer %p size %d skipping dts stream conf update",
+ buffer, bytes);
+ out->sample_rate = 48000;
+ out->compr_config.codec->sample_rate = out->sample_rate;
+ out->compr_config.codec->ch_in = 2;
+ out->channel_mask = audio_channel_out_mask_from_count(2);
+ return -EINVAL;
+ }
+
/* codec format is AUDIO_PARSER_CODEC_DTSHD for both DTS and DTSHD as
* DTSHD parser can support both DTS and DTSHD
*/
@@ -135,9 +156,9 @@
}
if (!is_valid_transmission_rate) {
- ALOGE("%s:: Invalid dts transmission rate %d\n using default sample rate 192000",
+ ALOGE("%s:: Invalid dts transmission rate %d\n using default sample rate 48000",
dtshd_tr_info.sample_rate);
- out->sample_rate = 192000;
+ out->sample_rate = 48000;
out->compr_config.codec->sample_rate = out->sample_rate;
}
@@ -147,14 +168,15 @@
out->compr_config.codec->ch_in = 2;
out->channel_mask = audio_channel_out_mask_from_count(2);
}
+ return 0;
}
#else
-static void passthru_update_stream_configuration_from_dts_parser(
+int audio_extn_passthru_update_dts_stream_configuration(
struct stream_out *out __unused,
const void *buffer __unused,
size_t bytes __unused)
{
- return;
+ return -ENOSYS;
}
#endif
@@ -391,7 +413,7 @@
void audio_extn_passthru_update_stream_configuration(
struct audio_device *adev, struct stream_out *out,
- const void *buffer, size_t bytes)
+ const void *buffer __unused, size_t bytes __unused)
{
if (audio_extn_passthru_is_passt_supported(adev, out)) {
ALOGV("%s:PASSTHROUGH", __func__);
@@ -406,28 +428,6 @@
ALOGV("%s:NO PASSTHROUGH", __func__);
out->compr_config.codec->compr_passthr = LEGACY_PCM;
}
-
- /*
- * for DTS passthrough, need to get sample rate from bitstream,
- * based on this sample rate hdmi backend will be configured
- */
- if ((out->format == AUDIO_FORMAT_DTS) ||
- (out->format == AUDIO_FORMAT_DTS_HD))
- passthru_update_stream_configuration_from_dts_parser(out, buffer, bytes);
-
-}
-
-bool audio_extn_passthru_is_direct_passthrough(struct stream_out *out)
-{
- //check passthrough system property
- if (!property_get_bool("audio.offload.passthrough", false)) {
- return false;
- }
-
- if ((out != NULL) && (out->compr_config.codec->compr_passthr == PASSTHROUGH || out->compr_config.codec->compr_passthr == PASSTHROUGH_IEC61937))
- return true;
- else
- return false;
}
bool audio_extn_passthru_is_passthrough_stream(struct stream_out *out)
@@ -464,6 +464,15 @@
return false;
}
+bool audio_extn_passthru_is_direct_passthrough(struct stream_out *out)
+{
+ if (((out != NULL) && audio_extn_passthru_is_passthrough_stream(out)) &&
+ !audio_extn_passthru_is_convert_supported(out->dev, out))
+ return true;
+ else
+ return false;
+}
+
int audio_extn_passthru_get_buffer_size(audio_offload_info_t* info)
{
uint32_t fragment_size = MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE;
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
index 90b054c..6320b94 100644
--- a/hal/audio_extn/qaf.c
+++ b/hal/audio_extn/qaf.c
@@ -765,8 +765,7 @@
DEBUG_MSG_VV("ret [%d]", (int)ret);
if (ret >= 0) {
- bytes = ret;
- out->written += bytes / ((popcount(out->channel_mask) * sizeof(short)));
+ out->written += ret / ((popcount(out->channel_mask) * sizeof(short)));
}
@@ -786,6 +785,11 @@
/ audio_stream_out_frame_size(stream)
/ out->stream.common.get_sample_rate(&out->stream.common));
}
+ } else if (ret < bytes) {
+ //partial buffer copied to the module.
+ DEBUG_MSG_VV("Not enough space available in mm module, post msg to cb thread");
+ (void)qaf_send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
+ bytes = ret;
}
return bytes;
}
@@ -1665,12 +1669,14 @@
}
DEBUG_MSG_VV("Bytes written = %d", ret);
}
- else if (event_id == AUDIO_EOS_MAIN_DD_DDP_EVENT
+ else if (event_id == AUDIO_EOS_EVENT
+ || event_id == AUDIO_EOS_MAIN_DD_DDP_EVENT
|| event_id == AUDIO_EOS_MAIN_2_DD_DDP_EVENT
|| event_id == AUDIO_EOS_MAIN_AAC_EVENT
|| event_id == AUDIO_EOS_MAIN_AC4_EVENT
|| event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT) {
struct stream_out *out = qaf_mod->stream_in[QAF_IN_MAIN];
+ struct stream_out *out_pcm = qaf_mod->stream_in[QAF_IN_PCM];
struct stream_out *out_main2 = qaf_mod->stream_in[QAF_IN_MAIN_2];
struct stream_out *out_assoc = qaf_mod->stream_in[QAF_IN_ASSOC];
@@ -1678,7 +1684,16 @@
* TODO:: Only DD/DDP Associate Eos is handled, need to add support
* for other formats.
*/
- if (event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT
+ if (event_id == AUDIO_EOS_EVENT
+ && (out_pcm != NULL)
+ && (check_stream_state(out_pcm, STOPPING))) {
+
+ lock_output_stream(out_pcm);
+ out_pcm->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out_pcm->client_cookie);
+ set_stream_state(out_pcm, STOPPED);
+ unlock_output_stream(out_pcm);
+ DEBUG_MSG("sent pcm DRAIN_READY");
+ } else if (event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT
&& (out_assoc != NULL)
&& (check_stream_state(out_assoc, STOPPING))) {
@@ -1915,13 +1930,16 @@
struct qaf_module* qaf_mod = NULL;
DEBUG_MSG("Flags 0x%x, Device 0x%x", flags, devices);
- if (mmtype >= MAX_MM_MODULE_TYPE
- || p_qaf->qaf_mod[mmtype].qaf_audio_session_open == NULL
- || p_qaf->qaf_mod[mmtype].qaf_audio_stream_open == NULL) {
+ if (mmtype >= MAX_MM_MODULE_TYPE) {
ERROR_MSG("Unsupported Stream");
return -ENOTSUP;
}
+ if (p_qaf->qaf_mod[mmtype].qaf_audio_session_open == NULL ||
+ p_qaf->qaf_mod[mmtype].qaf_audio_stream_open == NULL) {
+ ERROR_MSG("Session or Stream is NULL");
+ return status;
+ }
//Open the module session, if not opened already.
status = audio_extn_qaf_session_open(mmtype, out);
qaf_mod = &(p_qaf->qaf_mod[mmtype]);
@@ -2136,7 +2154,7 @@
parms = str_parms_create_str(kvpairs);
ret = str_parms_get_int(parms, "buf_available", &value);
if (ret >= 0) {
- if (value >= (int)out->compr_config.fragment_size) {
+ if (value > 0) {
DEBUG_MSG_VV("buffer available");
str_parms_destroy(parms);
parms = NULL;
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index 3784197..a33d432 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -430,6 +430,20 @@
return -EINVAL;
}
+void destroy_thread_params()
+{
+ pthread_mutex_destroy(&handle.mutex_spkr_prot);
+ pthread_mutex_destroy(&handle.spkr_calib_cancelack_mutex);
+ pthread_mutex_destroy(&handle.cal_wait_cond_mutex);
+ pthread_cond_destroy(&handle.cal_wait_condition);
+ pthread_cond_destroy(&handle.spkr_calib_cancel);
+ pthread_cond_destroy(&handle.spkr_calibcancel_ack);
+ if(!handle.wsa_found) {
+ pthread_mutex_destroy(&handle.spkr_prot_thermalsync_mutex);
+ pthread_cond_destroy(&handle.spkr_prot_thermalsync);
+ }
+}
+
static int spkr_calibrate(int t0_spk_1, int t0_spk_2)
{
struct audio_device *adev = handle.adev_handle;
@@ -443,6 +457,7 @@
bool acquire_device = false;
status.status = 0;
+ memset(&protCfg, 0, sizeof(protCfg));
if (!adev) {
ALOGE("%s: Invalid params", __func__);
return -EINVAL;
@@ -1314,11 +1329,7 @@
handle.init_check = true;
} else {
ALOGE("%s: speaker calibration thread creation failed", __func__);
- pthread_mutex_destroy(&handle.mutex_spkr_prot);
- pthread_mutex_destroy(&handle.spkr_calib_cancelack_mutex);
- pthread_mutex_destroy(&handle.cal_wait_cond_mutex);
- pthread_cond_destroy(&handle.spkr_calib_cancel);
- pthread_cond_destroy(&handle.spkr_calibcancel_ack);
+ destroy_thread_params();
}
return;
} else {
@@ -1366,13 +1377,7 @@
handle.init_check = true;
} else {
ALOGE("%s: speaker calibration thread creation failed", __func__);
- pthread_mutex_destroy(&handle.mutex_spkr_prot);
- pthread_mutex_destroy(&handle.spkr_calib_cancelack_mutex);
- pthread_mutex_destroy(&handle.cal_wait_cond_mutex);
- pthread_cond_destroy(&handle.spkr_calib_cancel);
- pthread_cond_destroy(&handle.spkr_calibcancel_ack);
- pthread_mutex_destroy(&handle.spkr_prot_thermalsync_mutex);
- pthread_cond_destroy(&handle.spkr_prot_thermalsync);
+ destroy_thread_params();
}
} else {
ALOGE("%s: thermal_client_request failed", __func__);
@@ -1400,7 +1405,8 @@
{
int result = 0;
- ALOGD("%s: Entering deinit init_check :%d", __func__, handle.init_check);
+ ALOGD("%s: Entering deinit init_check :%d",
+ __func__, handle.init_check);
if(!handle.init_check)
return -1;
@@ -1411,15 +1417,7 @@
ALOGE("%s:Unable to join the calibration thread", __func__);
return -1;
}
- pthread_mutex_destroy(&handle.mutex_spkr_prot);
- pthread_mutex_destroy(&handle.spkr_calib_cancelack_mutex);
- pthread_mutex_destroy(&handle.cal_wait_cond_mutex);
- pthread_cond_destroy(&handle.spkr_calib_cancel);
- pthread_cond_destroy(&handle.spkr_calibcancel_ack);
- if(!handle.wsa_found) {
- pthread_mutex_destroy(&handle.spkr_prot_thermalsync_mutex);
- pthread_cond_destroy(&handle.spkr_prot_thermalsync);
- }
+ destroy_thread_params();
memset(&handle, 0, sizeof(handle));
return 0;
}
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 8c4f313..3923818 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -845,6 +845,19 @@
&usecase->stream.in->app_type_cfg);
ALOGV("%s Selected apptype: %d", __func__, usecase->stream.in->app_type_cfg.app_type);
break;
+ case TRANSCODE_LOOPBACK :
+ audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
+ &adev->streams_output_cfg_list,
+ usecase->stream.inout->out_config.devices,
+ 0,
+ usecase->stream.inout->out_config.format,
+ usecase->stream.inout->out_config.sample_rate,
+ usecase->stream.inout->out_config.bit_width,
+ usecase->stream.inout->out_config.channel_mask,
+ usecase->stream.inout->profile,
+ &usecase->stream.inout->out_app_type_cfg);
+ ALOGV("%s Selected apptype: %d", __func__, usecase->stream.inout->out_app_type_cfg.app_type);
+ break;
default:
ALOGE("%s: app type cfg not supported for usecase type (%d)",
__func__, usecase->type);
@@ -872,7 +885,8 @@
platform_get_snd_device_name(usecase->in_snd_device),
platform_get_snd_device_name(split_snd_device));
- if (usecase->type != PCM_PLAYBACK && usecase->type != PCM_CAPTURE) {
+ if (usecase->type != PCM_PLAYBACK && usecase->type != PCM_CAPTURE &&
+ usecase->type != TRANSCODE_LOOPBACK) {
ALOGE("%s: not a playback/capture path, no need to cfg app type", __func__);
rc = 0;
goto exit_send_app_type_cfg;
@@ -882,6 +896,7 @@
(usecase->id != USECASE_AUDIO_PLAYBACK_MULTI_CH) &&
(usecase->id != USECASE_AUDIO_PLAYBACK_ULL) &&
(usecase->id != USECASE_AUDIO_PLAYBACK_VOIP) &&
+ (usecase->id != USECASE_AUDIO_TRANSCODE_LOOPBACK) &&
(!is_interactive_usecase(usecase->id)) &&
(!is_offload_usecase(usecase->id)) &&
(usecase->type != PCM_CAPTURE)) {
@@ -897,7 +912,7 @@
goto exit_send_app_type_cfg;
}
- if (usecase->type == PCM_PLAYBACK) {
+ if (usecase->type == PCM_PLAYBACK || usecase->type == TRANSCODE_LOOPBACK) {
pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_PLAYBACK);
snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
"Audio Stream %d App Type Cfg", pcm_device_id);
@@ -980,7 +995,8 @@
if (((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
(usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC) ||
(usecase->stream.out->format == AUDIO_FORMAT_DOLBY_TRUEHD))
- && audio_extn_passthru_is_passthrough_stream(usecase->stream.out)) {
+ && audio_extn_passthru_is_passthrough_stream(usecase->stream.out)
+ && !audio_extn_passthru_is_convert_supported(adev, usecase->stream.out)) {
sample_rate = sample_rate * 4;
if (sample_rate > HDMI_PASSTHROUGH_MAX_SAMPLE_RATE)
@@ -1006,6 +1022,10 @@
__func__, app_type, acdb_dev_id, sample_rate, snd_device_be_idx);
} else {
app_type = platform_get_default_app_type_v2(adev->platform, usecase->type);
+ if(usecase->type == TRANSCODE_LOOPBACK) {
+ sample_rate = usecase->stream.inout->out_config.sample_rate;
+ app_type = usecase->stream.inout->out_app_type_cfg.app_type;
+ }
app_type_cfg[len++] = app_type;
app_type_cfg[len++] = acdb_dev_id;
app_type_cfg[len++] = sample_rate;
@@ -1015,7 +1035,8 @@
__func__, app_type, acdb_dev_id, sample_rate, snd_device_be_idx);
}
- mixer_ctl_set_array(ctl, app_type_cfg, len);
+ if(ctl)
+ mixer_ctl_set_array(ctl, app_type_cfg, len);
rc = 0;
exit_send_app_type_cfg:
return rc;
@@ -1030,6 +1051,7 @@
switch (usecase->type) {
case PCM_PLAYBACK:
+ case TRANSCODE_LOOPBACK:
ALOGD("%s: usecase->out_snd_device %s",
__func__, platform_get_snd_device_name(usecase->out_snd_device));
/* check for out combo device */
@@ -1222,7 +1244,8 @@
*be multiple of (number of channels * bytes per sample)
*For writes to succeed, the buffer must be written at address which is multiple of 32
*/
- fragment_size = ALIGN(fragment_size, (bytes_per_sample * noOfChannels * 32));
+ fragment_size = ALIGN(fragment_size, (bytes_per_sample * noOfChannels));
+ fragment_size = ALIGN(fragment_size, 32);
ALOGI("PCM offload Fragment size to %d bytes", fragment_size);
return fragment_size;
@@ -1369,6 +1392,13 @@
platform_send_audio_calibration(adev->platform, usecase,
platform_get_default_app_type_v2(adev->platform, usecase->type),
48000);
+ } else if (type == TRANSCODE_LOOPBACK && usecase->stream.inout != NULL) {
+ int snd_device = usecase->out_snd_device;
+ snd_device = (snd_device == SND_DEVICE_OUT_SPEAKER) ?
+ platform_get_spkr_prot_snd_device(snd_device) : snd_device;
+ platform_send_audio_calibration(adev->platform, usecase,
+ platform_get_default_app_type_v2(adev->platform, usecase->type),
+ usecase->stream.inout->out_config.sample_rate);
} else {
/* No need to send audio calibration for voice and voip call usecases */
if ((type != VOICE_CALL) && (type != VOIP_CALL))
@@ -2302,9 +2332,11 @@
out->downmix_params.has_mixer_coeffs = mm_params->has_mixer_coeffs;
for (i = 0; i < mm_params->num_output_channels; i++)
- for (j = 0; j < mm_params->num_input_channels; j++)
+ for (j = 0; j < mm_params->num_input_channels; j++) {
+ //Convert the channel coefficient gains in Q14 format
out->downmix_params.mixer_coeffs[i][j] =
- mm_params->mixer_coeffs[i][j];
+ mm_params->mixer_coeffs[i][j] * (2 << 13);
+ }
ret = platform_set_stream_downmix_params(out->dev->platform,
out->pcm_device_id,
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 5cfc3f8..12bc76b 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1645,6 +1645,10 @@
ret = true;
}
+ if (usecase->stream.out->stream_config_changed) {
+ ALOGD("Force stream_config_changed to update iec61937 transmission config");
+ return true;
+ }
return ret;
}
@@ -2544,7 +2548,7 @@
if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
audio_extn_keep_alive_start();
- if (audio_extn_ip_hdlr_intf_supported(out->format, audio_extn_passthru_is_direct_passthrough(out)) && out->ip_hdlr_handle) {
+ if (out->ip_hdlr_handle) {
ret = audio_extn_ip_hdlr_intf_close(out->ip_hdlr_handle, true, out);
if (ret < 0)
ALOGE("%s: audio_extn_ip_hdlr_intf_close failed %d",__func__, ret);
@@ -2799,7 +2803,7 @@
audio_extn_perf_lock_release(&adev->perf_lock_handle);
ALOGD("%s: exit", __func__);
- if (audio_extn_ip_hdlr_intf_supported(out->format, audio_extn_passthru_is_direct_passthrough(out)) && out->ip_hdlr_handle) {
+ if (out->ip_hdlr_handle) {
ret = audio_extn_ip_hdlr_intf_open(out->ip_hdlr_handle, true, out, out->usecase);
if (ret < 0)
ALOGE("%s: audio_extn_ip_hdlr_intf_open failed %d",__func__, ret);
@@ -2966,7 +2970,7 @@
struct stream_out *out = (struct stream_out *)stream;
if (is_interactive_usecase(out->usecase)) {
- return out->config.period_size;
+ return out->config.period_size * out->config.period_count;
} else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP)
return out->compr_config.fragment_size - sizeof(struct snd_codec_metadata);
@@ -3704,6 +3708,7 @@
struct stream_out *out = (struct stream_out *)stream;
struct audio_device *adev = out->dev;
ssize_t ret = 0;
+ int channels = 0;
lock_output_stream(out);
@@ -3733,12 +3738,44 @@
}
if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
- /*ADD audio_extn_passthru_is_passthrough_stream(out) check*/
- if ((audio_extn_passthru_is_enabled()) &&
- (!out->is_iec61937_info_available)) {
+ channels = platform_edid_get_max_channels(out->dev->platform);
+ if (audio_extn_passthru_is_enabled() &&
+ !out->is_iec61937_info_available &&
+ audio_extn_passthru_is_passthrough_stream(out)) {
audio_extn_passthru_update_stream_configuration(adev, out,
buffer, bytes);
out->is_iec61937_info_available = true;
+
+ if((out->format == AUDIO_FORMAT_DTS) ||
+ (out->format == AUDIO_FORMAT_DTS_HD)) {
+ ret = audio_extn_passthru_update_dts_stream_configuration(out,
+ buffer, bytes);
+ if (ret) {
+ if (ret != -ENOSYS) {
+ out->is_iec61937_info_available = false;
+ ALOGD("iec61937 transmission info not yet updated retry");
+ }
+ } else {
+ /* if stream has started and after that there is
+ * stream config change (iec transmission config)
+ * then trigger select_device to update backend configuration.
+ */
+ out->stream_config_changed = true;
+ pthread_mutex_lock(&adev->lock);
+ select_devices(adev, out->usecase);
+ pthread_mutex_unlock(&adev->lock);
+ out->stream_config_changed = false;
+ out->is_iec61937_info_available = true;
+ }
+ }
+
+ if ((channels < (int)audio_channel_count_from_out_mask(out->channel_mask)) &&
+ (out->compr_config.codec->compr_passthr == PASSTHROUGH) &&
+ (out->is_iec61937_info_available == true)) {
+ ALOGE("%s: ERROR: Unsupported channel config in passthrough mode", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
}
}
@@ -3944,6 +3981,11 @@
if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))
usleep((uint64_t)bytes * 1000000 / audio_stream_out_frame_size(stream) /
out_get_sample_rate(&out->stream.common));
+
+ if (audio_extn_passthru_is_passthrough_stream(out)) {
+ ALOGE("%s: write error, ret = %ld", __func__, ret);
+ return ret;
+ }
}
return bytes;
}
@@ -4459,6 +4501,7 @@
pthread_mutex_lock(&adev->lock);
in->standby = true;
if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
+ do_stop = false;
voice_extn_compress_voip_close_input_stream(stream);
ALOGD("VOIP input entered standby");
} else if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
@@ -4467,20 +4510,15 @@
} else {
if (audio_extn_cin_attached_usecase(in->usecase))
audio_extn_cin_stop_input_stream(in);
+ }
+
+ if (do_stop) {
if (in->pcm) {
pcm_close(in->pcm);
in->pcm = NULL;
}
status = stop_input_stream(in);
}
- if (in->pcm) {
- pcm_close(in->pcm);
- in->pcm = NULL;
- }
-
- if (do_stop) {
- status = stop_input_stream(in);
- }
pthread_mutex_unlock(&adev->lock);
}
pthread_mutex_unlock(&in->lock);
@@ -4958,6 +4996,7 @@
int ret = 0;
audio_format_t format;
struct adsp_hdlr_stream_cfg hdlr_stream_cfg;
+ bool is_direct_passthough = false;
*stream_out = NULL;
@@ -4998,7 +5037,7 @@
out->a2dp_compress_mute = false;
out->dynamic_pm_qos_enabled = 0;
- if ((flags & AUDIO_OUTPUT_FLAG_BD10) &&
+ if ((flags & AUDIO_OUTPUT_FLAG_BD) &&
(property_get_bool("audio.matrix.limiter.enable", false)))
platform_set_device_params(out, DEVICE_PARAM_LIMITER_ID, 1);
@@ -5020,7 +5059,7 @@
}
/* Init use case and pcm_config */
-#ifndef COMPRESS_VOIP_ENABLED
+#ifndef COMPRES_ENABLED
if (out->flags == (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_VOIP_RX) &&
(out->sample_rate == 8000 || out->sample_rate == 16000 ||
out->sample_rate == 32000 || out->sample_rate == 48000)) {
@@ -5033,7 +5072,7 @@
out->config.rate = out->sample_rate;
#else
- if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION || voice_extn_compress_voip_is_active(out->dev)) &&
+ } else if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION || voice_extn_compress_voip_is_active(out->dev)) &&
(out->flags == (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_VOIP_RX)) &&
(voice_extn_compress_voip_is_config_supported(config))) {
ret = voice_extn_compress_voip_open_output_stream(out);
@@ -5491,9 +5530,10 @@
audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
popcount(out->channel_mask), out->playback_started);
/* setup a channel for client <--> adsp communication for stream events */
+ is_direct_passthough = audio_extn_passthru_is_direct_passthrough(out);
if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) ||
(out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) ||
- (audio_extn_ip_hdlr_intf_supported(config->format, audio_extn_passthru_is_direct_passthrough(out)))) {
+ (audio_extn_ip_hdlr_intf_supported(config->format, is_direct_passthough, false))) {
hdlr_stream_cfg.pcm_device_id = platform_get_pcm_device_id(
out->usecase, PCM_PLAYBACK);
hdlr_stream_cfg.flags = out->flags;
@@ -5505,8 +5545,8 @@
out->adsp_hdlr_stream_handle = NULL;
}
}
- if (audio_extn_ip_hdlr_intf_supported(config->format, audio_extn_passthru_is_direct_passthrough(out))) {
- ret = audio_extn_ip_hdlr_intf_init(&out->ip_hdlr_handle, NULL, NULL);
+ if (audio_extn_ip_hdlr_intf_supported(config->format, is_direct_passthough, false)) {
+ ret = audio_extn_ip_hdlr_intf_init(&out->ip_hdlr_handle, NULL, NULL, adev, out->usecase);
if (ret < 0) {
ALOGE("%s: audio_extn_ip_hdlr_intf_init failed %d",__func__, ret);
out->ip_hdlr_handle = NULL;
@@ -5545,7 +5585,7 @@
out->adsp_hdlr_stream_handle = NULL;
}
- if (audio_extn_ip_hdlr_intf_supported(out->format, audio_extn_passthru_is_direct_passthrough(out)) && out->ip_hdlr_handle) {
+ if (out->ip_hdlr_handle) {
audio_extn_ip_hdlr_intf_deinit(out->ip_hdlr_handle);
out->ip_hdlr_handle = NULL;
}
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 0a6d85b..f0b7077 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -239,6 +239,8 @@
pthread_cond_t cond;
struct stream_config in_config;
struct stream_config out_config;
+ struct stream_app_type_cfg out_app_type_cfg;
+ char profile[MAX_STREAM_PROFILE_STR_LEN];
struct audio_device *dev;
void *adsp_hdlr_stream_handle;
void *ip_hdlr_handle;
@@ -321,6 +323,7 @@
char pm_qos_mixer_path[MAX_MIXER_PATH_LEN];
int dynamic_pm_qos_enabled;
+ bool stream_config_changed;
mix_matrix_params_t pan_scale_params;
mix_matrix_params_t downmix_params;
};
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index fcc9ade..f8c0aba 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -3206,6 +3206,9 @@
snd_device = voice_get_incall_rec_snd_device(usecase->in_snd_device);
else if ((usecase->type == PCM_HFP_CALL) || (usecase->type == PCM_CAPTURE))
snd_device = usecase->in_snd_device;
+ else if (usecase->type == TRANSCODE_LOOPBACK)
+ snd_device = usecase->out_snd_device;
+
acdb_dev_id = acdb_device_table[platform_get_spkr_prot_snd_device(snd_device)];
if (platform_split_snd_device(platform, snd_device, &num_devices,
@@ -5604,12 +5607,11 @@
__func__, DEFAULT_HDMI_OUT_CHANNELS);
channels = DEFAULT_HDMI_OUT_CHANNELS;
}
-
- if ((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
+ if (((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
(usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC) ||
- (usecase->stream.out->format == AUDIO_FORMAT_DOLBY_TRUEHD)) {
- sample_rate = sample_rate * 4 ;
-
+ (usecase->stream.out->format == AUDIO_FORMAT_DOLBY_TRUEHD))
+ && (usecase->stream.out->compr_config.codec->compr_passthr == PASSTHROUGH)) {
+ sample_rate = sample_rate * 4;
if (sample_rate > HDMI_PASSTHROUGH_MAX_SAMPLE_RATE)
sample_rate = HDMI_PASSTHROUGH_MAX_SAMPLE_RATE;
}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index f368d17..a29aa9d 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -2969,6 +2969,8 @@
snd_device = voice_get_incall_rec_snd_device(usecase->in_snd_device);
else if ((usecase->type == PCM_HFP_CALL) || (usecase->type == PCM_CAPTURE))
snd_device = usecase->in_snd_device;
+ else if (usecase->type == TRANSCODE_LOOPBACK)
+ snd_device = usecase->out_snd_device;
acdb_dev_id = acdb_device_table[platform_get_spkr_prot_snd_device(snd_device)];
if (acdb_dev_id < 0) {
@@ -5474,10 +5476,10 @@
__func__, DEFAULT_HDMI_OUT_CHANNELS);
channels = DEFAULT_HDMI_OUT_CHANNELS;
}
- if ((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
+ if (((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
(usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC) ||
- (usecase->stream.out->format == AUDIO_FORMAT_DOLBY_TRUEHD)) {
-
+ (usecase->stream.out->format == AUDIO_FORMAT_DOLBY_TRUEHD))
+ && (usecase->stream.out->compr_config.codec->compr_passthr == PASSTHROUGH)) {
sample_rate = sample_rate * 4;
if (sample_rate > HDMI_PASSTHROUGH_MAX_SAMPLE_RATE)
sample_rate = HDMI_PASSTHROUGH_MAX_SAMPLE_RATE;
@@ -6070,12 +6072,7 @@
int iter_i = 0;
int iter_j = 0;
int length = 0;
- int pan_scale_data[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
-
- if (sizeof(mm_params) > MAX_LENGTH_MIXER_CONTROL_IN_INT) {
- ret = -EINVAL;
- goto end;
- }
+ int *pan_scale_data = NULL;
snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
"Audio Stream %d Pan Scale Control", snd_id);
@@ -6088,6 +6085,11 @@
ret = -EINVAL;
goto end;
}
+ pan_scale_data = (int* ) calloc(1, sizeof(mm_params));
+ if (!pan_scale_data) {
+ ret = -ENOMEM;
+ goto end;
+ }
pan_scale_data[length++] = mm_params.num_output_channels;
pan_scale_data[length++] = mm_params.num_input_channels;
@@ -6121,6 +6123,8 @@
ret = mixer_ctl_set_array(ctl, pan_scale_data, length);
end:
+ if (pan_scale_data)
+ free(pan_scale_data);
return ret;
}
@@ -6133,20 +6137,13 @@
struct audio_device *adev = my_data->adev;
struct mixer_ctl *ctl;
char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
- int downmix_param_data[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+ int *downmix_param_data = NULL;
int ret = 0;
int iter_i = 0;
int iter_j = 0;
int length = 0;
int be_idx = 0;
- if ((sizeof(mm_params) +
- sizeof(be_idx)) >
- MAX_LENGTH_MIXER_CONTROL_IN_INT) {
- ret = -EINVAL;
- goto end;
- }
-
snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
"Audio Device %d Downmix Control", snd_id);
ALOGD("%s mixer_ctl_name:%s", __func__, mixer_ctl_name);
@@ -6158,8 +6155,13 @@
ret = -EINVAL;
}
+ downmix_param_data = (int* ) calloc(1, sizeof(mm_params) + sizeof(be_idx));
+ if (!downmix_param_data) {
+ ret = -ENOMEM;
+ goto end;
+ }
be_idx = platform_get_snd_device_backend_index(snd_device);
- downmix_param_data[length] = be_idx;
+ downmix_param_data[length++] = be_idx;
downmix_param_data[length++] = mm_params.num_output_channels;
downmix_param_data[length++] = mm_params.num_input_channels;
@@ -6194,6 +6196,8 @@
ret = mixer_ctl_set_array(ctl, downmix_param_data, length);
end:
+ if (downmix_param_data)
+ free(downmix_param_data);
return ret;
}
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index a15c399..930bae0 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -298,7 +298,7 @@
/* Used in calculating fragment size for pcm offload */
-#define PCM_OFFLOAD_BUFFER_DURATION 40 /* 40 millisecs */
+#define PCM_OFFLOAD_BUFFER_DURATION 80 /* 80 millisecs */
/* MAX PCM fragment size cannot be increased further due
* to flinger's cblk size of 1mb,and it has to be a multiple of
diff --git a/qahw_api/Makefile.am b/qahw_api/Makefile.am
index f2c1060..ca1839a 100644
--- a/qahw_api/Makefile.am
+++ b/qahw_api/Makefile.am
@@ -17,8 +17,8 @@
lib_LTLIBRARIES = libqahw.la
libqahw_la_SOURCES = src/qahw.c \
src/qahw_effect.c
-libqahw_la_CFLAGS = $(AM_CFLAGS) -include stddef.h
+libqahw_la_CFLAGS = -Dstrlcpy=g_strlcpy $(GLIB_CFLAGS) -include glib.h $(AM_CFLAGS) -include stddef.h
libqahw_la_CFLAGS += -D__unused=__attribute__\(\(__unused__\)\)
libqahw_la_CFLAGS += -Wno-sign-compare -Werror
-libqahw_la_LIBADD = -llog -lcutils -lhardware
+libqahw_la_LIBADD = $(GLIB_LIBS) -llog -lcutils -lhardware
libqahw_la_LDFLAGS = -module -shared -avoid-version
diff --git a/qahw_api/inc/qahw_defs.h b/qahw_api/inc/qahw_defs.h
index fa780bd..c13a1a4 100644
--- a/qahw_api/inc/qahw_defs.h
+++ b/qahw_api/inc/qahw_defs.h
@@ -180,6 +180,23 @@
#define MAX_OUT_CHANNELS 8
#define MAX_INP_CHANNELS 8
+#define QAHW_PCM_CHANNEL_FL 1 /* Front left channel. */
+#define QAHW_PCM_CHANNEL_FR 2 /* Front right channel. */
+#define QAHW_PCM_CHANNEL_FC 3 /* Front center channel. */
+#define QAHW_PCM_CHANNEL_LS 4 /* Left surround channel. */
+#define QAHW_PCM_CHANNEL_RS 5 /* Right surround channel. */
+#define QAHW_PCM_CHANNEL_LFE 6 /* Low frequency effect channel. */
+#define QAHW_PCM_CHANNEL_CS 7 /* Center surround channel; Rear center channel. */
+#define QAHW_PCM_CHANNEL_LB 8 /* Left back channel; Rear left channel. */
+#define QAHW_PCM_CHANNEL_RB 9 /* Right back channel; Rear right channel. */
+#define QAHW_PCM_CHANNEL_TS 10 /* Top surround channel. */
+#define QAHW_PCM_CHANNEL_CVH 11 /* Center vertical height channel. */
+#define QAHW_PCM_CHANNEL_MS 12 /* Mono surround channel. */
+#define QAHW_PCM_CHANNEL_FLC 13 /* Front left of center. */
+#define QAHW_PCM_CHANNEL_FRC 14 /* Front right of center. */
+#define QAHW_PCM_CHANNEL_RLC 15 /* Rear left of center. */
+#define QAHW_PCM_CHANNEL_RRC 16 /* Rear right of center. */
+
/* type of asynchronous write callback events. Mutually exclusive */
typedef enum {
QAHW_STREAM_CBK_EVENT_WRITE_READY, /* non blocking write completed */
diff --git a/qahw_api/test/Makefile.am b/qahw_api/test/Makefile.am
index d87962b..b4bbea7 100644
--- a/qahw_api/test/Makefile.am
+++ b/qahw_api/test/Makefile.am
@@ -6,9 +6,19 @@
hal_play_test_SOURCES = qahw_playback_test.c \
qahw_effect_test.c
-hal_play_test_CPPFLAGS = $(PLAY_CPPFLAGS) $(PLAY_INCLUDES)
+
hal_play_test_LDADD = -lutils ../libqahw.la
+if QAP
+AM_CFLAGS = -DQAP
+AM_CFLAGS += -I ${WORKSPACE}/audio/mm-audio/qap_wrapper/inc/
+hal_play_test_SOURCES += qap_wrapper_extn.c
+hal_play_test_LDADD += -lqap_wrapper
+endif
+
+hal_play_test_CPPFLAGS = $(PLAY_CPPFLAGS) $(PLAY_INCLUDES)
+hal_play_test_CFLAGS = $(AM_CFLAGS)
+hal_play_test_CFLAGS = -DLINUX_ENABLED
bin_PROGRAMS += hal_rec_test
@@ -18,6 +28,7 @@
hal_rec_test_SOURCES = qahw_multi_record_test.c
hal_rec_test_CPPFLAGS = -Dstrlcat=g_strlcat $(GLIB_CFLAGS) -include glib.h
hal_rec_test_CPPFLAGS += $(REC_CPPFLAGS) $(REC_INCLUDES)
+hal_play_test_CFLAGS += $(AM_CFLAGS)
hal_rec_test_LDADD = -lutils ../libqahw.la $(GLIB_LIBS)
bin_PROGRAMS += trans_loopback_test
diff --git a/qahw_api/test/qahw_playback_test.c b/qahw_api/test/qahw_playback_test.c
index c27f920..fb69d93 100644
--- a/qahw_api/test/qahw_playback_test.c
+++ b/qahw_api/test/qahw_playback_test.c
@@ -18,22 +18,7 @@
/* Test app to play audio at the HAL layer */
-#include <getopt.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.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"
-#include "qahw_effect_api.h"
-#include "qahw_effect_test.h"
+#include "qahw_playback_test.h"
#define nullptr NULL
@@ -51,9 +36,9 @@
#define KV_PAIR_MAX_LENGTH 1000
#define FORMAT_PCM 1
-#define WAV_HEADER_LENGTH_MAX 46
+#define WAV_HEADER_LENGTH_MAX 128
-#define MAX_PLAYBACK_STREAMS 9
+#define MAX_PLAYBACK_STREAMS 105 //This value is changed to suppport 100 clips in playlist
#define PRIMARY_STREAM_INDEX 0
#define KVPAIRS_MAX 100
@@ -69,50 +54,10 @@
#define DTSHD_CHUNK_STREAM_KEYWORD "STRMDATA"
#define DTSHD_META_KEYWORD_SIZE 8 /*in bytes */
-static int get_wav_header_length (FILE* file_stream);
static ssize_t get_bytes_to_read(FILE* file, int filetype);
static void init_streams(void);
int pthread_cancel(pthread_t thread);
-
-enum {
- FILE_WAV = 1,
- FILE_MP3,
- FILE_AAC,
- FILE_AAC_ADTS,
- FILE_FLAC,
- FILE_ALAC,
- FILE_VORBIS,
- FILE_WMA,
- FILE_AC3,
- FILE_AAC_LATM,
- FILE_EAC3,
- FILE_EAC3_JOC,
- FILE_DTS,
- FILE_MP2,
- FILE_APTX,
- FILE_TRUEHD,
- FILE_IEC61937
-};
-
-typedef enum {
- USB_MODE_DEVICE,
- USB_MODE_HOST,
- USB_MODE_NONE
-} usb_mode_type_t;
-
-typedef enum {
- AAC_LC = 1,
- AAC_HE_V1,
- AAC_HE_V2
-} aac_format_type_t;
-
-typedef enum {
- WMA = 1,
- WMA_PRO,
- WMA_LOSSLESS
-} wma_format_type_t;
-
struct wav_header {
uint32_t riff_id;
uint32_t riff_sz;
@@ -129,18 +74,6 @@
uint32_t data_sz;
};
-struct audio_config_params {
- qahw_module_handle_t *qahw_mod_handle;
- audio_io_handle_t handle;
- audio_devices_t input_device;
- audio_config_t config;
- audio_input_flags_t flags;
- const char* kStreamName ;
- audio_source_t kInputSource;
- char *file_name;
- volatile bool thread_exit;
-};
-
struct proxy_data {
struct audio_config_params acp;
struct wav_header hdr;
@@ -162,42 +95,6 @@
uint32_t config_mask;
};
-typedef struct {
- qahw_module_handle_t *qahw_in_hal_handle;
- qahw_module_handle_t *qahw_out_hal_handle;
- audio_io_handle_t handle;
- char* filename;
- FILE* file_stream;
- int filetype;
- int stream_index;
- audio_devices_t output_device;
- audio_devices_t input_device;
- audio_config_t config;
- audio_output_flags_t flags;
- qahw_stream_handle_t* out_handle;
- qahw_stream_handle_t* in_handle;
- int channels;
- aac_format_type_t aac_fmt_type;
- wma_format_type_t wma_fmt_type;
- char *kvpair_values;
- bool flags_set;
- usb_mode_type_t usb_mode;
- int effect_index;
- int effect_preset_strength;
- bool drift_query;
- bool drift_correction;
- bool play_later;
- char *device_url;
- thread_func_t ethread_func;
- thread_data_t *ethread_data;
- cmd_data_t cmd_data;
- pthread_cond_t write_cond;
- pthread_mutex_t write_lock;
- pthread_cond_t drain_cond;
- pthread_mutex_t drain_lock;
- bool interactive_strm;
-}stream_config;
-
/* Lock for dual main usecase */
pthread_cond_t dual_main_cond;
pthread_mutex_t dual_main_lock;
@@ -211,13 +108,12 @@
FILE * log_file = NULL;
volatile bool stop_playback = false;
const char *log_filename = NULL;
-float vol_level = 0.01;
struct proxy_data proxy_params;
pthread_t playback_thread[MAX_PLAYBACK_STREAMS];
bool thread_active[MAX_PLAYBACK_STREAMS] = { false };
+bool qap_wrapper_session_active = false;
stream_config stream_param[MAX_PLAYBACK_STREAMS];
-bool kpi_mode;
bool event_trigger;
/*
@@ -262,11 +158,11 @@
"music_offload_wma_format_tag=%d;"
#ifndef AUDIO_OUTPUT_FLAG_ASSOCIATED
-#define AUDIO_OUTPUT_FLAG_ASSOCIATED 0x8000
+#define AUDIO_OUTPUT_FLAG_ASSOCIATED 0x10000000
#endif
#ifndef AUDIO_OUTPUT_FLAG_INTERACTIVE
-#define AUDIO_OUTPUT_FLAG_INTERACTIVE 0x40000
+#define AUDIO_OUTPUT_FLAG_INTERACTIVE 0x80000000
#endif
static bool request_wake_lock(bool wakelock_acquired, bool enable)
@@ -667,7 +563,7 @@
size_t bytes_wanted = 0;
size_t write_length = 0;
size_t bytes_remaining = 0;
- size_t bytes_written = 0;
+ ssize_t bytes_written = 0;
size_t bytes_read = 0;
char *data_ptr = NULL;
@@ -1000,6 +896,7 @@
case AAC_LC:
case AAC_HE_V1:
case AAC_HE_V2:
+ case AAC_LOAS:
valid_format_type = true;
break;
default:
@@ -1067,7 +964,7 @@
return aac_format;
}
-static void get_file_format(stream_config *stream_info)
+void get_file_format(stream_config *stream_info)
{
int rc = 0;
@@ -1171,6 +1068,7 @@
fprintf(log_file, "Does not support given filetype\n");
fprintf(stderr, "Does not support given filetype\n");
usage();
+ hal_test_qap_usage();
return;
}
stream_info->config.sample_rate = stream_info->config.offload_info.sample_rate;
@@ -1608,10 +1506,7 @@
printf(" -m --mode - usb operating mode(Device Mode is default)\n");
printf(" 0:Device Mode(host drives the stream and its params and so no need to give params as input)\n");
printf(" 1:Host Mode(user can give stream and stream params via a stream(SD card file) or setup loopback with given params\n");
- printf(" -O --output-ch-map - output channel map");
- printf(" -I --input-ch-map - input channel map");
- printf(" -M --mixer-coeffs - mixer coefficient matrix");
- printf(" -i --intr-strm - interactive stream indicator");
+ printf(" -i --intr-strm - interactive stream indicator\n");
printf(" -C --Device Config - Device Configuration params\n");
printf(" Params should be in the order defined in struct qahw_device_cfg_param. Order is: \n");
printf(" <sample_rate>, <channels>, <bit_width>, <format>, <device>, <channel_map[channels]>, <channel_allocation> \n");
@@ -1681,9 +1576,11 @@
printf(" ->full duplex, setup both primary to usb and usb to primary loopbacks\n");
printf(" ->Note:-P separates the steam params for both the loopbacks\n");
printf(" ->Note:all the USB device commmands(above) should be accompanied with the host side commands\n\n");
+ printf("hal_play_test -f interactive_audio.wav -d 2 -l out.txt -k \"mixer_ctrl=pan_scale;c=1;o=6;I=fc;O=fl,fr,fc,lfe,bl,br;M=0.5,0.5,0,0,0,0\" -i 1\n");
+ printf(" ->kv_pair for downmix or pan_scale should folow the above sequence, one can pass downmix & pan_scale params/coeff matrices. For each control params should be sent separately \n");
}
-static int get_wav_header_length (FILE* file_stream)
+int get_wav_header_length (FILE* file_stream)
{
int subchunk_size = 0, wav_header_len = 0;
@@ -1800,7 +1697,7 @@
return file_read_size;
}
-static qahw_module_handle_t * load_hal(audio_devices_t dev) {
+qahw_module_handle_t * load_hal(audio_devices_t dev) {
qahw_module_handle_t *hal = NULL;
if ((AUDIO_DEVICE_IN_USB_DEVICE == dev) ||
@@ -1844,7 +1741,7 @@
* this function unloads all the loaded hal modules so this should be called
* after all the stream playback are concluded.
*/
-static int unload_hals() {
+int unload_hals() {
if (usb_hal_handle) {
fprintf(log_file,"\nUnLoading usb HAL\n");
@@ -1878,41 +1775,37 @@
if (NULL == name)
return channel_type;
else if (strncmp(name, "fl", 2) == 0)
- channel_type = AUDIO_CHANNEL_OUT_FRONT_LEFT;
+ channel_type = QAHW_PCM_CHANNEL_FL;
else if (strncmp(name, "fr", 2) == 0)
- channel_type = AUDIO_CHANNEL_OUT_FRONT_RIGHT;
+ channel_type = QAHW_PCM_CHANNEL_FR;
else if (strncmp(name, "fc", 2) == 0)
- channel_type = AUDIO_CHANNEL_OUT_FRONT_CENTER;
+ channel_type = QAHW_PCM_CHANNEL_FC;
else if (strncmp(name, "lfe", 2) == 0)
- channel_type = AUDIO_CHANNEL_OUT_LOW_FREQUENCY;
+ channel_type = QAHW_PCM_CHANNEL_LFE;
else if (strncmp(name, "bl", 2) == 0)
- channel_type = AUDIO_CHANNEL_OUT_BACK_LEFT;
+ channel_type = QAHW_PCM_CHANNEL_LB;
else if (strncmp(name, "br", 2) == 0)
- channel_type = AUDIO_CHANNEL_OUT_BACK_RIGHT;
+ channel_type = QAHW_PCM_CHANNEL_RB;
else if (strncmp(name, "flc", 3) == 0)
- channel_type = AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER;
+ channel_type = QAHW_PCM_CHANNEL_FLC;
else if (strncmp(name, "frc", 3) == 0)
- channel_type = AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER;
- else if (strncmp(name, "bc", 2) == 0)
- channel_type = AUDIO_CHANNEL_OUT_BACK_CENTER;
- else if (strncmp(name, "sl", 2) == 0)
- channel_type = AUDIO_CHANNEL_OUT_SIDE_LEFT;
- else if (strncmp(name, "sr", 2) == 0)
- channel_type = AUDIO_CHANNEL_OUT_SIDE_RIGHT;
- else if (strncmp(name, "tc", 2) == 0)
- channel_type = AUDIO_CHANNEL_OUT_TOP_CENTER;
- else if (strncmp(name, "tfl", 3) == 0)
- channel_type = AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT;
- else if (strncmp(name, "tfc", 3) == 0)
- channel_type = AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER;
- else if (strncmp(name, "tfr", 3) == 0)
- channel_type = AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT;
- else if (strncmp(name, "tbl", 3) == 0)
- channel_type = AUDIO_CHANNEL_OUT_TOP_BACK_LEFT;
- else if (strncmp(name, "tbc", 3) == 0)
- channel_type = AUDIO_CHANNEL_OUT_TOP_BACK_CENTER;
- else if (strncmp(name, "tbr", 3) == 0)
- channel_type = AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT;
+ channel_type = QAHW_PCM_CHANNEL_FRC;
+ else if (strncmp(name, "cs", 2) == 0)
+ channel_type = QAHW_PCM_CHANNEL_CS;
+ else if (strncmp(name, "ls", 2) == 0)
+ channel_type = QAHW_PCM_CHANNEL_LS;
+ else if (strncmp(name, "rs", 2) == 0)
+ channel_type = QAHW_PCM_CHANNEL_RS;
+ else if (strncmp(name, "ts", 2) == 0)
+ channel_type = QAHW_PCM_CHANNEL_TS;
+ else if (strncmp(name, "cvh", 3) == 0)
+ channel_type = QAHW_PCM_CHANNEL_CVH;
+ else if (strncmp(name, "ms", 3) == 0)
+ channel_type = QAHW_PCM_CHANNEL_MS;
+ else if (strncmp(name, "rlc", 3) == 0)
+ channel_type = QAHW_PCM_CHANNEL_RLC;
+ else if (strncmp(name, "rrc", 3) == 0)
+ channel_type = QAHW_PCM_CHANNEL_RRC;
return channel_type;
}
@@ -1994,18 +1887,60 @@
token_string = NULL;
} else
return -EINVAL;
+}
+
+#ifdef QAP
+int start_playback_through_qap(char * kvp_string, int num_of_streams, qahw_module_handle_t *hal_handle) {
+ stream_config *stream = NULL;
+ int rc = 0;
+ int i;
+
+ fprintf(stdout, "kvp_string %s and num_of_streams %d\n", kvp_string, num_of_streams);
+ for (i = 0; i < num_of_streams; i++) {
+ stream = &stream_param[i];
+ if (stream->filename) {
+ if ((stream->file_stream = fopen(stream->filename, "r"))== NULL) {
+ fprintf(log_file, "Cannot open audio file %s\n", stream->filename);
+ fprintf(stderr, "Cannot open audio file %s\n", stream->filename);
+ return -EINVAL;
+ }
+ }
+ get_file_format(stream);
+ fprintf(stdout, "Playing from:%s\n", stream->filename);
+ qap_module_handle_t qap_module_handle = NULL;
+ if (!qap_wrapper_session_active) {
+ rc = qap_wrapper_session_open(kvp_string, 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);
+ rc = pthread_create(&playback_thread[i], NULL, qap_wrapper_start_stream, (void *)&stream_param[i]);
+ if (rc) {
+ fprintf(stderr, "stream %d: failed to create thread\n", stream->stream_index);
+ return -EINVAL;
+ }
+ thread_active[i] = true;
+ }
+ }
+ }
return 0;
}
+#endif
int main(int argc, char* argv[]) {
char *ba = NULL;
- char *temp_input_channel_map = NULL;
- char *temp_output_channel_map = NULL;
- char *temp_mixer_coeffs = NULL;
qahw_param_payload payload;
qahw_param_id param_id;
struct qahw_aptx_dec_param aptx_params;
- qahw_mix_matrix_params_t mm_params;
int rc = 0;
int i = 0;
int iter_i = 0;
@@ -2014,7 +1949,11 @@
kpi_mode = false;
char mixer_ctrl_name[64] = {0};
- int mixer_ctrl_type = 0;
+ char input_ch[64] = {0};
+ char output_ch[64] = {0};
+ char input_ch_map[64] = {0};
+ char output_ch_map[64] = {0};
+ char mixer_coeff[64] = {0};
event_trigger = false;
bool wakelock_acquired = false;
@@ -2028,6 +1967,7 @@
init_streams();
int num_of_streams = 1;
+ char kvp_string[KV_PAIR_MAX_LENGTH] = {0};
struct option long_options[] = {
/* These options set a flag. */
@@ -2038,6 +1978,7 @@
{"channels", required_argument, 0, 'c'},
{"bitwidth", required_argument, 0, 'b'},
{"volume", required_argument, 0, 'v'},
+ {"enable-dump", required_argument, 0, 'V'},
{"log-file", required_argument, 0, 'l'},
{"dump-file", required_argument, 0, 'D'},
{"file-type", required_argument, 0, 't'},
@@ -2056,13 +1997,12 @@
{"mode", required_argument, 0, 'm'},
{"effect-preset", required_argument, 0, 'p'},
{"effect-strength", required_argument, 0, 'S'},
- {"device-config", required_argument, 0, 'C'},
- {"help", no_argument, 0, 'h'},
- {"output-ch-map", required_argument, 0, 'O'},
- {"input-ch-map", required_argument, 0, 'I'},
- {"mixer-coeffs", required_argument, 0, 'M'},
- {"num-out-ch", required_argument, 0, 'o'},
+ {"render-format", required_argument, 0, 'x'},
+ {"timestamp-file", required_argument, 0, 'y'},
{"intr-strm", required_argument, 0, 'i'},
+ {"device-config", required_argument, 0, 'C'},
+ {"play-list", required_argument, 0, 'g'},
+ {"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
@@ -2085,7 +2025,7 @@
while ((opt = getopt_long(argc,
argv,
- "-f:r:c:b:d:s:v:l:t:a:w:k:PD:KF:Ee:A:u:m:S:C:p:qQhI:O:M:o:i:",
+ "-f:r:c:b:d:s:v:V:l:t:a:w:k:PD:KF:Ee:A:u:m:S:C:p::x:y:qQh:i:h:g:",
long_options,
&option_index)) != -1) {
@@ -2102,7 +2042,6 @@
case 'c':
stream_param[i].channels = atoi(optarg);
stream_param[i].config.channel_mask = audio_channel_out_mask_from_count(atoi(optarg));
- mm_params.num_input_channels = stream_param[i].channels;
break;
case 'b':
stream_param[i].config.offload_info.bit_width = atoi(optarg);
@@ -2116,6 +2055,9 @@
case 'v':
vol_level = atof(optarg);
break;
+ case 'V':
+ enable_dump = atof(optarg);
+ break;
case 'l':
log_filename = optarg;
if (strcasecmp(log_filename, "stdout") &&
@@ -2141,12 +2083,77 @@
break;
case 'k':
get_kvpairs_string(optarg, "mixer_ctrl", mixer_ctrl_name);
+ printf("%s, mixer_ctrl_name- %s\n", __func__, mixer_ctrl_name);
if(strncmp(mixer_ctrl_name, "downmix", 7) == 0) {
- mixer_ctrl_type = QAHW_PARAM_CH_MIX_MATRIX_PARAMS;
+ stream_param[i].mix_ctrl = QAHW_PARAM_CH_MIX_MATRIX_PARAMS;
+
+ get_kvpairs_string(optarg, "c", input_ch);
+ stream_param[i].mm_params_downmix.num_input_channels = atoi(input_ch);
+ get_kvpairs_string(optarg, "o", output_ch);
+ stream_param[i].mm_params_downmix.num_output_channels = atoi(output_ch);
+ get_kvpairs_string(optarg, "I", input_ch_map);
+ get_kvpairs_string(optarg, "O", output_ch_map);
+ get_kvpairs_string(optarg, "M", mixer_coeff);
+
+ extract_channel_mapping(stream_param[i].mm_params_downmix.input_channel_map, input_ch_map);
+ stream_param[i].mm_params_downmix.has_input_channel_map = 1;
+ fprintf(log_file, "\ndownmix Input channel mapping: ");
+ for (iter_i= 0; iter_i < stream_param[i].mm_params_downmix.num_input_channels; iter_i++) {
+ fprintf(log_file, "0x%x, ", stream_param[i].mm_params_downmix.input_channel_map[iter_i]);
+ }
+
+ extract_channel_mapping(stream_param[i].mm_params_downmix.output_channel_map, output_ch_map);
+ stream_param[i].mm_params_downmix.has_output_channel_map = 1;
+ fprintf(log_file, "\ndownmix Output channel mapping: ");
+ for (iter_i = 0; iter_i < stream_param[i].mm_params_downmix.num_output_channels; iter_i++)
+ fprintf(log_file, "0x%x, ", stream_param[i].mm_params_downmix.output_channel_map[iter_i]);
+
+
+ extract_mixer_coeffs(&stream_param[i].mm_params_downmix, mixer_coeff);
+ stream_param[i].mm_params_downmix.has_mixer_coeffs = 1;
+ fprintf(log_file, "\ndownmix mixer coeffs:\n");
+ for (iter_i = 0; iter_i < stream_param[i].mm_params_downmix.num_output_channels; iter_i++){
+ for (iter_j = 0; iter_j < stream_param[i].mm_params_downmix.num_input_channels; iter_j++){
+ fprintf(log_file, "%.2f ",stream_param[i].mm_params_downmix.mixer_coeffs[iter_i][iter_j]);
+ }
+ fprintf(log_file, "\n");
+ }
+
} else if(strncmp(mixer_ctrl_name, "pan_scale", 9) == 0) {
- mixer_ctrl_type = QAHW_PARAM_OUT_MIX_MATRIX_PARAMS;
+ stream_param[i].pan_scale_ctrl = QAHW_PARAM_OUT_MIX_MATRIX_PARAMS;
+
+ get_kvpairs_string(optarg, "c", input_ch);
+ stream_param[i].mm_params_pan_scale.num_input_channels = atoi(input_ch);
+ get_kvpairs_string(optarg, "o", output_ch);
+ stream_param[i].mm_params_pan_scale.num_output_channels = atoi(output_ch);
+ get_kvpairs_string(optarg, "I", input_ch_map);
+ get_kvpairs_string(optarg, "O", output_ch_map);
+ get_kvpairs_string(optarg, "M", mixer_coeff);
+
+ extract_channel_mapping(stream_param[i].mm_params_pan_scale.input_channel_map, input_ch_map);
+ stream_param[i].mm_params_pan_scale.has_input_channel_map = 1;
+ fprintf(log_file, "\n pan_sclae Input channel mapping: ");
+ for (iter_i= 0; iter_i < stream_param[i].mm_params_pan_scale.num_input_channels; iter_i++) {
+ fprintf(log_file, "0x%x, ", stream_param[i].mm_params_pan_scale.input_channel_map[iter_i]);
+ }
+
+ extract_channel_mapping(stream_param[i].mm_params_pan_scale.output_channel_map, output_ch_map);
+ stream_param[i].mm_params_pan_scale.has_output_channel_map = 1;
+ fprintf(log_file, "\n pan_scale Output channel mapping: ");
+ for (iter_i = 0; iter_i < stream_param[i].mm_params_pan_scale.num_output_channels; iter_i++)
+ fprintf(log_file, "0x%x, ", stream_param[i].mm_params_pan_scale.output_channel_map[iter_i]);
+
+ extract_mixer_coeffs(&stream_param[i].mm_params_pan_scale, mixer_coeff);
+ stream_param[i].mm_params_pan_scale.has_mixer_coeffs = 1;
+ fprintf(log_file, "\n pan_scale mixer coeffs:\n");
+ for (iter_i = 0; iter_i < stream_param[i].mm_params_pan_scale.num_output_channels; iter_i++){
+ for (iter_j = 0; iter_j < stream_param[i].mm_params_pan_scale.num_input_channels; iter_j++){
+ fprintf(log_file, "%.2f ",stream_param[i].mm_params_pan_scale.mixer_coeffs[iter_i][iter_j]);
+ }
+ fprintf(log_file, "\n");
+ }
+
} else {
- mixer_ctrl_type = 0;
stream_param[i].kvpair_values = optarg;
}
break;
@@ -2209,17 +2216,12 @@
case 'm':
stream_param[i].usb_mode = atoi(optarg);
break;
- case 'O':
- temp_output_channel_map = strdup(optarg);
+ case 'x':
+ render_format = atoi(optarg);
break;
- case 'I':
- temp_input_channel_map = strdup(optarg);
+ case 'y':
+ stream_param[i].timestamp_filename = optarg;
break;
- case 'M':
- temp_mixer_coeffs = strdup(optarg);
- break;
- case 'o':
- mm_params.num_output_channels = atoi(optarg);
case 'C':
fprintf(log_file, " In Device config \n");
fprintf(stderr, " In Device config \n");
@@ -2281,57 +2283,17 @@
fprintf(stderr, " Device config :::: channel_allocation - %d \n", device_cfg_params.channel_allocation);
}
break;
+ case 'g':
+ break;
case 'h':
usage();
+ hal_test_qap_usage();
return 0;
break;
}
}
- /*
- * Process Input channel map's input
- */
- if (NULL != temp_input_channel_map) {
- extract_channel_mapping(mm_params.input_channel_map, temp_input_channel_map);
- mm_params.has_input_channel_map = 1;
- fprintf(log_file, "\nInput channel mapping: ");
- for (iter_i= 0; iter_i < mm_params.num_input_channels; iter_i++) {
- fprintf(log_file, "0x%x, ", mm_params.input_channel_map[iter_i]);
- }
- free(temp_input_channel_map);
- temp_input_channel_map = NULL;
- }
-
- /*
- * Process Output channel map's input
- */
- if (NULL != temp_output_channel_map) {
- extract_channel_mapping(mm_params.output_channel_map, temp_output_channel_map);
- mm_params.has_output_channel_map = 1;
- fprintf(log_file, "\nOutput channel mapping: ");
- for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
- fprintf(log_file, "0x%x, ", mm_params.output_channel_map[iter_i]);
-
- free(temp_output_channel_map);
- temp_output_channel_map = NULL;
- }
-
- /*
- * Process mixer-coeffs input
- */
- if (NULL != temp_mixer_coeffs) {
- extract_mixer_coeffs(&mm_params, temp_mixer_coeffs);
- mm_params.has_mixer_coeffs = 1;
- fprintf(log_file, "\nmixer coeffs:\n");
- for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++){
- for (iter_j = 0; iter_j < mm_params.num_input_channels; iter_j++){
- fprintf(log_file, "%.2f ",mm_params.mixer_coeffs[iter_i][iter_j]);
- }
- fprintf(log_file, "\n");
- }
- }
-
wakelock_acquired = request_wake_lock(wakelock_acquired, true);
num_of_streams = i+1;
/* Caution: Below ADL log shouldnt be altered without notifying automation APT since it used
@@ -2373,20 +2335,59 @@
}
+ if (is_qap_session_active(argc, argv, kvp_string)) {
+ char *file_name = NULL;
+ char *file_name_tmp = NULL;
+ char *cmd_kvp_str[100] = {NULL};
+ char *play_list_kvp_str[100] = {NULL};
+ int i = 0, j = 0;
+ qahw_module_handle_t *qap_out_hal_handle = NULL;
+
+ stream = &stream_param[i];
+ qap_out_hal_handle = load_hal(stream->output_device);
+ if (qap_out_hal_handle == NULL) {
+ fprintf(stderr, "Failed log load HAL\n");
+ goto exit;
+ }
+
+ file_name = (char*) check_for_playlist(kvp_string);
+ fprintf(stderr, "%s file_name is %s \n", __FUNCTION__, file_name);
+ if (file_name != NULL) {
+ FILE *fp = fopen(file_name, "r+");
+ if (fp != NULL) {
+ get_play_list(fp, &stream_param, &num_of_streams, cmd_kvp_str);
+ for (j = 0; j < num_of_streams; j++) {
+ play_list_kvp_str[j] = strdup(cmd_kvp_str[j]);
+ }
+ rc = start_playback_through_qap_playlist(play_list_kvp_str, num_of_streams, kvp_string, stream_param, qap_wrapper_session_active, qap_out_hal_handle);
+ if (rc != 0) {
+ fprintf(stderr, "QAP playback failed\n");
+ }
+ } else {
+ fprintf(stderr, "%s file open failed\nnd errno is %d", __FUNCTION__, errno);
+ }
+ } else {
+ rc = start_playback_through_qap(kvp_string, num_of_streams, qap_out_hal_handle);
+ if (rc != 0) {
+ fprintf(stderr, "QAP playback failed\n");
+ }
+ }
+ goto exit;
+ }
for (i = 0; i < num_of_streams; i++) {
stream = &stream_param[i];
if ((kpi_mode == false) &&
(AUDIO_DEVICE_NONE == stream->input_device)){
- if (stream_param[PRIMARY_STREAM_INDEX].filename == nullptr) {
- fprintf(log_file, "Primary file name is must for non kpi-mode\n");
- fprintf(stderr, "Primary file name is must for non kpi-mode\n");
- goto exit;
- }
+ if (stream_param[PRIMARY_STREAM_INDEX].filename == nullptr) {
+ fprintf(log_file, "Primary file name is must for non kpi-mode\n");
+ fprintf(stderr, "Primary file name is must for non kpi-mode\n");
+ goto exit;
+ }
}
if (stream->output_device != AUDIO_DEVICE_NONE)
- if ((stream->qahw_out_hal_handle = load_hal(stream->output_device)) <= 0)
+ if ((stream->qahw_out_hal_handle = load_hal(stream->output_device)) <= 0)
goto exit;
if (stream->input_device != AUDIO_DEVICE_NONE)
@@ -2397,8 +2398,8 @@
(AUDIO_DEVICE_NONE != stream->input_device))
/*
* hal loopback at what params we need to probably detect.
- */
- if(detect_stream_params(stream) < 0)
+ */
+ if(detect_stream_params(stream) < 0)
goto exit;
if (stream->filename) {
@@ -2508,29 +2509,33 @@
thread_active[i] = true;
usleep(500000); //Wait until stream is created
- if(mixer_ctrl_type == QAHW_PARAM_OUT_MIX_MATRIX_PARAMS) {
- payload = (qahw_param_payload) mm_params;
+ if(stream_param[i].pan_scale_ctrl == QAHW_PARAM_OUT_MIX_MATRIX_PARAMS) {
+ payload = (qahw_param_payload) stream_param[i].mm_params_pan_scale;
param_id = QAHW_PARAM_OUT_MIX_MATRIX_PARAMS;
rc = qahw_out_set_param_data(stream->out_handle, param_id, &payload);
if (rc != 0) {
fprintf(log_file, "QAHW_PARAM_OUT_MIX_MATRIX_PARAMS could not be sent!\n");
}
}
- if(mixer_ctrl_type == QAHW_PARAM_CH_MIX_MATRIX_PARAMS) {
- payload = (qahw_param_payload) mm_params;
+ if(stream_param[i].mix_ctrl == QAHW_PARAM_CH_MIX_MATRIX_PARAMS) {
+ payload = (qahw_param_payload) stream_param[i].mm_params_downmix;
param_id = QAHW_PARAM_CH_MIX_MATRIX_PARAMS;
rc = qahw_out_set_param_data(stream->out_handle, param_id, &payload);
if (rc != 0) {
fprintf(log_file, "QAHW_PARAM_CH_MIX_MATRIX_PARAMS could not be sent!\n");
}
}
+
}
exit:
-
for (i=0; i<MAX_PLAYBACK_STREAMS; i++) {
if(thread_active[i])
- pthread_join(playback_thread[i], NULL);
+ pthread_join(playback_thread[i], NULL);
+ }
+
+ if(qap_wrapper_session_active) {
+ qap_wrapper_session_close();
}
/*
diff --git a/qahw_api/test/qahw_playback_test.h b/qahw_api/test/qahw_playback_test.h
new file mode 100644
index 0000000..1f524b9
--- /dev/null
+++ b/qahw_api/test/qahw_playback_test.h
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+
+#ifndef QAHW_PLAYBACK_TEST_H
+#define QAHW_PLAYBACK_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"
+#include "qahw_effect_api.h"
+#include "qahw_effect_test.h"
+
+#define MAX_STR_LEN 256
+typedef void* qap_module_handle_t;
+bool kpi_mode;
+bool enable_dump;
+float vol_level;
+uint8_t render_format;
+
+
+enum {
+ FILE_WAV = 1,
+ FILE_MP3,
+ FILE_AAC,
+ FILE_AAC_ADTS,
+ FILE_FLAC,
+ FILE_ALAC,
+ FILE_VORBIS,
+ FILE_WMA,
+ FILE_AC3,
+ FILE_AAC_LATM,
+ FILE_EAC3,
+ FILE_EAC3_JOC,
+ FILE_DTS,
+ FILE_MP2,
+ FILE_APTX,
+ FILE_TRUEHD,
+ FILE_IEC61937
+};
+
+typedef enum {
+ USB_MODE_DEVICE,
+ USB_MODE_HOST,
+ USB_MODE_NONE
+} usb_mode_type_t;
+
+typedef enum {
+ AAC_LC = 1,
+ AAC_HE_V1,
+ AAC_HE_V2,
+ AAC_LOAS
+} aac_format_type_t;
+
+typedef enum {
+ WMA = 1,
+ WMA_PRO,
+ WMA_LOSSLESS
+} wma_format_type_t;
+
+struct audio_config_params {
+ qahw_module_handle_t *qahw_mod_handle;
+ audio_io_handle_t handle;
+ audio_devices_t input_device;
+ audio_config_t config;
+ audio_input_flags_t flags;
+ const char* kStreamName ;
+ audio_source_t kInputSource;
+ char *file_name;
+ volatile bool thread_exit;
+};
+
+typedef struct {
+ qahw_module_handle_t *qahw_in_hal_handle;
+ qahw_module_handle_t *qahw_out_hal_handle;
+ audio_io_handle_t handle;
+ char* filename;
+ FILE* file_stream;
+ char* timestamp_filename;
+ FILE* timestamp_file_ptr;
+ FILE* framesize_file_ptr;
+ int filetype;
+ int stream_index;
+ audio_devices_t output_device;
+ audio_devices_t input_device;
+ audio_config_t config;
+ audio_output_flags_t flags;
+ qahw_stream_handle_t* out_handle;
+ qahw_stream_handle_t* in_handle;
+ int channels;
+ aac_format_type_t aac_fmt_type;
+ wma_format_type_t wma_fmt_type;
+ char *kvpair_values;
+ bool flags_set;
+ usb_mode_type_t usb_mode;
+ int effect_index;
+ int effect_preset_strength;
+ bool drift_query;
+ bool drift_correction;
+ bool play_later;
+ char *device_url;
+ thread_func_t ethread_func;
+ thread_data_t *ethread_data;
+ cmd_data_t cmd_data;
+ int bytes_to_read;
+ qap_module_handle_t qap_module_handle;
+ bool sec_input;
+ bool system_input;
+ pthread_cond_t write_cond;
+ pthread_mutex_t write_lock;
+ pthread_cond_t drain_cond;
+ pthread_mutex_t drain_lock;
+ bool interactive_strm;
+ qahw_mix_matrix_params_t mm_params_pan_scale;
+ qahw_mix_matrix_params_t mm_params_downmix;
+ int mix_ctrl;
+ int pan_scale_ctrl;
+}stream_config;
+
+
+qahw_module_handle_t * load_hal(audio_devices_t dev);
+int unload_hals();
+int get_wav_header_length (FILE* file_stream);
+
+#ifndef QAP
+#define hal_test_qap_usage() (0)
+#define qap_wrapper_get_single_kvp(key, kv_pairs, status) (0)
+#define qap_wrapper_session_open(kv_pairs, stream_data, num_of_streams,\
+ qap_out_hal_handle_t) (0)
+#define qap_wrapper_session_close() (0)
+#define qap_wrapper_stream_open(stream_data) (0)
+#define qap_wrapper_get_cmd_string_from_arg_array(argc, argv, status) (0)
+#define qap_wrapper_start_stream (stream_data) (0)
+#define is_qap_session_active(argc, argv, kvp_string) (0)
+#define get_play_list(fp, stream_param, num_of_streams, kvp_str) (0)
+#define check_for_playlist(kvp_string) (0)
+#define start_playback_through_qap(kvp_string, num_of_streams,\
+ qap_out_hal_handle_t) (0)
+#define start_playback_through_qap_playlist(cmd_kvp_str, num_of_streams,\
+ kvp_string, stream_param, qap_wrapper_session_active,\
+ qap_out_hal_handle_t) (0)
+#else
+void hal_test_qap_usage();
+char * qap_wrapper_get_single_kvp(const char *key, const char *kv_pairs, int *status);
+int qap_wrapper_session_open(char *kv_pairs, void* stream_data, int num_of_streams,\
+ qahw_module_handle_t *qap_out_hal_handle_t);
+int qap_wrapper_session_close();
+qap_module_handle_t qap_wrapper_stream_open(void* stream_data);
+char * qap_wrapper_get_cmd_string_from_arg_array(int argc, char * argv[], int *status);
+void *qap_wrapper_start_stream (void* stream_data);
+void get_file_format(stream_config *stream_info);
+bool is_qap_session_active(int argc, char* argv[], char *kvp_string);
+void get_play_list(FILE *fp, stream_config (*stream_param)[], int *num_of_streams, char *kvp_str[]);
+char* check_for_playlist(char *kvp_string);
+int start_playback_through_qap(char * kvp_string, int num_of_streams,\
+ qahw_module_handle_t *qap_out_hal_handle_t);
+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 *qap_out_hal_handle_t);
+#endif
+#endif /* QAHW_PLAYBACK_TEST_H */
diff --git a/qahw_api/test/qap_wrapper_extn.c b/qahw_api/test/qap_wrapper_extn.c
new file mode 100644
index 0000000..5c76d40
--- /dev/null
+++ b/qahw_api/test/qap_wrapper_extn.c
@@ -0,0 +1,1659 @@
+/*
+ * 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 32768 /* 32k size */
+#define MAX_BUFFER_SIZE 32768 /* 32k size */
+#define CONTIGUOUS_TIMESTAMP 0x7fffffff
+#define TIMESTAMP_ARRAY_SIZE 2048
+#define DOLBY 1
+#define DTS 2
+#define FRAME_SIZE_FOR_2CH_PCM 6144 /* For 48k samplerate, 2 ch, 2 bytes */
+
+#define MAX_QAP_MODULE_OUT 3
+
+qap_output_config_t qap_out_configs[MAX_QAP_MODULE_OUT];
+bool is_media_fmt_changed[MAX_QAP_MODULE_OUT];
+int new_output_conf_index = 0;
+
+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;
+uint32_t dsp_latency = 0;
+
+static int get_qap_out_config_index_for_id(int32_t out_id)
+{
+ int index = -1, i;
+
+ for (i = 0; i < MAX_QAP_MODULE_OUT; i++)
+ if (qap_out_configs[i].id == out_id)
+ index = i;
+
+ return index;
+}
+
+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);
+ if (dsp_latency)
+ fprintf(stdout, "Dsp latency = %lu ms \n", dsp_latency);
+}
+
+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] = {0};
+ 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);
+ }
+ }
+ } else {
+ buffer->common_params.timestamp = CONTIGUOUS_TIMESTAMP;
+ buffer->common_params.size = 0;
+ }
+ }
+}
+
+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 = calloc(1, 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:
+ break;
+ case QAP_CALLBACK_EVENT_OUTPUT_CFG_CHANGE:
+ if (data != NULL) {
+ qap_audio_buffer_t *buffer = (qap_audio_buffer_t *) data;
+ qap_output_config_t *new_conf = &buffer->buffer_parms.output_buf_params.output_config;
+ qap_output_config_t *cached_conf = NULL;
+ int index = -1;
+
+ ALOGV("%s %d Received Output cfg change", __func__, __LINE__);
+ if (buffer) {
+ index = get_qap_out_config_index_for_id(
+ buffer->buffer_parms.output_buf_params.output_id);
+ if (index < 0 && new_output_conf_index < MAX_QAP_MODULE_OUT) {
+ index = new_output_conf_index;
+ cached_conf = &qap_out_configs[index];
+ new_output_conf_index++;
+ }
+ }
+
+ if (cached_conf == NULL) {
+ ALOGE("Maximum output from QAP is reached");
+ return;
+ }
+ if (memcmp(cached_conf, new_conf, sizeof(qap_output_config_t)) != 0) {
+ memcpy(cached_conf, new_conf, sizeof(qap_output_config_t));
+ cached_conf->id = buffer->buffer_parms.output_buf_params.output_id;
+ is_media_fmt_changed[index] = true;
+ }
+ }
+ 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) {
+ int index = -1;
+ bool is_reopen_stream = false;
+ index = get_qap_out_config_index_for_id(buffer->buffer_parms.output_buf_params.output_id);
+ if (index > -1 && is_media_fmt_changed[index]) {
+ session_output_config.output_config->sample_rate = qap_out_configs[index].sample_rate;
+ session_output_config.output_config->bit_width = qap_out_configs[index].bit_width;
+ session_output_config.output_config->channels = qap_out_configs[index].channels;
+ is_reopen_stream = true;
+ is_media_fmt_changed[index] = false;
+ }
+
+ 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 (is_reopen_stream && qap_out_hdmi_handle) {
+ qahw_close_output_stream(qap_out_hdmi_handle);
+ qap_out_hdmi_handle = NULL;
+ is_reopen_stream = false;
+ }
+
+ 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 == 6)
+ dsp_latency = qahw_out_get_latency(qap_out_hdmi_handle);
+ }
+ 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 (is_reopen_stream && qap_out_hp_handle) {
+ qahw_close_output_stream(qap_out_hp_handle);
+ qap_out_hp_handle = NULL;
+ is_reopen_stream = false;
+ }
+
+ 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 == 6)
+ dsp_latency = qahw_out_get_latency(qap_out_hp_handle);
+ }
+ 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 (is_reopen_stream && qap_out_spk_handle) {
+ qahw_close_output_stream(qap_out_spk_handle);
+ qap_out_spk_handle = NULL;
+ is_reopen_stream = false;
+ }
+ 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 == 6)
+ dsp_latency = qahw_out_get_latency(qap_out_spk_handle);
+ }
+ 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);
+ }
+ if (stream_info->channels > 6)
+ stream_info->bytes_to_read = (FRAME_SIZE_FOR_2CH_PCM * 4);
+ else
+ stream_info->bytes_to_read = (FRAME_SIZE_FOR_2CH_PCM * 3);
+ }
+ 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;
+ int time_index = data_write_count;
+ 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);
+ }
+
+ if(kpi_mode && time_index > 5) {
+ gettimeofday(&tcont_ts1, NULL);
+ data_input_st_arr[time_index] = (tcont_ts1.tv_sec) * 1000 + (tcont_ts1.tv_usec) / 1000;
+ }
+ }
+ }
+ } 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) && !(kpi_mode)) {
+ 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 = FRAME_SIZE;
+ 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");
+}
diff --git a/qahw_api/test/trans_loopback_test.c b/qahw_api/test/trans_loopback_test.c
index 009e288..1ba2c55 100644
--- a/qahw_api/test/trans_loopback_test.c
+++ b/qahw_api/test/trans_loopback_test.c
@@ -45,6 +45,7 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <utils/Log.h>
+#include <math.h>
#include <cutils/list.h>
#include "qahw_api.h"
@@ -87,6 +88,7 @@
FILE * log_file = NULL;
volatile bool stop_loopback = false;
+static float loopback_gain = 1.0;
const char *log_filename = NULL;
#define TRANSCODE_LOOPBACK_SOURCE_PORT_ID 0x4C00
@@ -138,6 +140,34 @@
stop_loopback = true;
}
+int poll_data_event_init()
+{
+ struct sockaddr_nl sock_addr;
+ int sz = (64*1024);
+ int soc;
+
+ memset(&sock_addr, 0, sizeof(sock_addr));
+ sock_addr.nl_family = AF_NETLINK;
+ sock_addr.nl_pid = getpid();
+ sock_addr.nl_groups = 0xffffffff;
+
+ soc = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+ if (soc < 0) {
+ return 0;
+ }
+
+ setsockopt(soc, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
+
+ if (bind(soc, (struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0) {
+ close(soc);
+ return 0;
+ }
+
+ sock_event_fd = soc;
+
+ return (soc > 0);
+}
+
void init_transcode_loopback_config(transcode_loopback_config_t **p_transcode_loopback_config)
{
fprintf(log_file,"\nInitializing global transcode loopback config\n");
@@ -366,6 +396,23 @@
&transcode_loopback_config->sink_config,
&transcode_loopback_config->patch_handle);
fprintf(log_file,"\nCreate patch returned %d\n",rc);
+ if(!rc) {
+ struct audio_port_config sink_gain_config;
+ /* Convert loopback gain to millibels */
+ int loopback_gain_in_millibels = 2000 * log10(loopback_gain);
+ sink_gain_config.gain.index = 0;
+ sink_gain_config.gain.mode = AUDIO_GAIN_MODE_JOINT;
+ sink_gain_config.gain.channel_mask = 1;
+ sink_gain_config.gain.values[0] = loopback_gain_in_millibels;
+ sink_gain_config.id = transcode_loopback_config->sink_config.id;
+ sink_gain_config.role = transcode_loopback_config->sink_config.role;
+ sink_gain_config.type = transcode_loopback_config->sink_config.type;
+ sink_gain_config.config_mask = AUDIO_PORT_CONFIG_GAIN;
+
+ (void)qahw_set_audio_port_config(transcode_loopback_config->hal_handle,
+ &sink_gain_config);
+ }
+
return rc;
}
@@ -396,34 +443,6 @@
}
-int poll_data_event_init()
-{
- struct sockaddr_nl sock_addr;
- int sz = (64*1024);
- int soc;
-
- memset(&sock_addr, 0, sizeof(sock_addr));
- sock_addr.nl_family = AF_NETLINK;
- sock_addr.nl_pid = getpid();
- sock_addr.nl_groups = 0xffffffff;
-
- soc = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
- if (soc < 0) {
- return 0;
- }
-
- setsockopt(soc, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
-
- if (bind(soc, (struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0) {
- close(soc);
- return 0;
- }
-
- sock_event_fd = soc;
-
- return (soc > 0);
-}
-
void source_data_event_handler(transcode_loopback_config_t *transcode_loopback_config)
{
int status =0;
@@ -494,7 +513,7 @@
j++;
}
- if ((dev_path != NULL) && (switch_name != NULL))
+ if ((dev_path != NULL) && (switch_name != NULL))
fprintf(log_file,"devpath = %s, switch_name = %s \n",dev_path, switch_name);
if((DEV_NODE_CHECK(tlb_hdmi_in_audio_dev_path, dev_path) == 0) || (DEV_NODE_CHECK(tlb_hdmi_in_audio_sample_rate_dev_path, dev_path) == 0)
@@ -512,23 +531,9 @@
pthread_exit(0);
}
-bool is_device_supported(uint32_t device_id)
-{
- switch(device_id)
- {
- case AUDIO_DEVICE_OUT_SPEAKER :
- case AUDIO_DEVICE_OUT_WIRED_HEADSET :
- case AUDIO_DEVICE_OUT_WIRED_HEADPHONE :
- return true;
- default :
- return false;
- }
-}
-
void set_device(uint32_t device_type, uint32_t device_id)
{
transcode_loopback_config_t *transcode_loopback_config = &g_trnscode_loopback_config;
- device_id = is_device_supported(device_id) ? device_id : AUDIO_DEVICE_OUT_SPEAKER;
switch( device_type )
{
case DEVICE_SINK:
@@ -543,7 +548,7 @@
int main(int argc, char *argv[]) {
int status = 0;
- uint32_t play_duration_in_seconds = 600,play_duration_elapsed_msec = 0,play_duration_in_msec = 0, sink_device = 2;
+ uint32_t play_duration_in_seconds = 600,play_duration_elapsed_msec = 0,play_duration_in_msec = 0, sink_device = 2, volume_in_millibels = 0;
source_port_type_t source_port_type = SOURCE_PORT_NONE;
log_file = stdout;
transcode_loopback_config_t *transcode_loopback_config = NULL;
@@ -553,6 +558,7 @@
/* These options set a flag. */
{"sink-device", required_argument, 0, 'd'},
{"play-duration", required_argument, 0, 'p'},
+ {"play-volume", required_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
@@ -562,7 +568,7 @@
while ((opt = getopt_long(argc,
argv,
- "-d:p:h",
+ "-d:p:v:h",
long_options,
&option_index)) != -1) {
@@ -575,6 +581,9 @@
case 'p':
play_duration_in_seconds = atoi(optarg);
break;
+ case 'v':
+ loopback_gain = atof(optarg);
+ break;
case 'h':
default :
usage();
@@ -584,9 +593,9 @@
}
fprintf(log_file,"\nTranscode loopback test begin\n");
- if (play_duration_in_seconds < 0 | play_duration_in_seconds > 3600) {
+ if (play_duration_in_seconds < 0 | play_duration_in_seconds > 360000) {
fprintf(log_file,
- "\nPlayback duration %d invalid or unsupported(range : 1 to 3600, defaulting to 600 seconds )\n",
+ "\nPlayback duration %d invalid or unsupported(range : 1 to 360000, defaulting to 600 seconds )\n",
play_duration_in_seconds);
play_duration_in_seconds = 600;
}
@@ -654,8 +663,8 @@
void usage()
{
- fprintf(log_file,"\nUsage : trans_loopback_test -p <duration_in_seconds> -d <sink_device_id>\n");
- fprintf(log_file,"\nExample to play for 1 minute on speaker device: trans_loopback_test -p 60 -d 2\n");
+ fprintf(log_file,"\nUsage : trans_loopback_test -p <duration_in_seconds> -d <sink_device_id> -v <loopback_volume(range 0 to 4.0)>\n");
+ fprintf(log_file,"\nExample to play for 1 minute on speaker device with volume unity: trans_loopback_test -p 60 -d 2 -v 1.0\n");
fprintf(log_file,"\nExample to play for 5 minutes on headphone device: trans_loopback_test -p 300 -d 8\n");
fprintf(log_file,"\nHelp : trans_loopback_test -h\n");
}