summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hal/audio_extn/audio_extn.h11
-rw-r--r--hal/audio_extn/dolby.c133
-rw-r--r--hal/audio_hw.c124
-rw-r--r--hal/audio_hw.h3
-rw-r--r--hal/edid.c14
-rw-r--r--hal/msm8960/platform.c7
-rw-r--r--hal/msm8974/platform.c206
-rw-r--r--hal/msm8974/platform.h7
-rw-r--r--hal/platform_api.h3
-rw-r--r--hal/voice.c21
-rw-r--r--hal/voice.h4
-rw-r--r--hal/voice_extn/compress_voip.c9
-rw-r--r--hal/voice_extn/voice_extn.c31
-rw-r--r--hal/voice_extn/voice_extn.h6
-rw-r--r--policy_hal/AudioPolicyManager.cpp164
-rw-r--r--policy_hal/AudioPolicyManager.h6
16 files changed, 470 insertions, 279 deletions
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 6f0ea7e5..c5052721 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -185,6 +185,7 @@ void audio_extn_dolby_set_endpoint(struct audio_device *adev);
#ifndef DS1_DOLBY_DDP_ENABLED
#define AUDIO_FORMAT_AC3 0x0a000000UL
#define AUDIO_FORMAT_EAC3 0x12000000UL
+#define AUDIO_FORMAT_E_AC3_JOC 0x19000000UL
#define audio_extn_ddp_set_parameters(adev, parms) (0)
#define audio_extn_is_dolby_format(format) (0)
#define audio_extn_dolby_get_snd_codec_id(format) (0)
@@ -208,6 +209,8 @@ void audio_extn_dolby_send_ddp_endp_params(struct audio_device *adev);
#define audio_extn_dolby_is_passthrough_stream(flags) (0)
#define audio_extn_dolby_set_hdmi_format_and_samplerate(adev, out) (0)
#define audio_extn_dolby_get_passt_buffer_size(info) (0)
+#define audio_extn_dolby_set_passt_volume(out, mute) (0)
+#define audio_extn_dolby_set_passt_latency(out, latency) (0)
#else
int audio_extn_dolby_update_passt_formats(struct audio_device *adev,
struct stream_out *out);
@@ -221,6 +224,8 @@ bool audio_extn_dolby_is_passthrough_stream(int flags);
int audio_extn_dolby_set_hdmi_format_and_samplerate(struct audio_device *adev,
struct stream_out *out);
int audio_extn_dolby_get_passt_buffer_size(audio_offload_info_t* info);
+int audio_extn_dolby_set_passt_volume(struct stream_out *out, int mute);
+int audio_extn_dolby_set_passt_latency(struct stream_out *out, int latency);
#endif
#ifndef HFP_ENABLED
@@ -249,7 +254,7 @@ int audio_extn_dap_hal_init(int snd_card);
int audio_extn_dap_hal_deinit();
void audio_extn_dolby_ds2_set_endpoint(struct audio_device *adev);
int audio_extn_ds2_enable(struct audio_device *adev);
-int audio_extn_dolby_set_dap_bypass(struct audio_device *adev, bool state);
+int audio_extn_dolby_set_dap_bypass(struct audio_device *adev, int state);
#else
#define audio_extn_dap_hal_init(snd_card) (0)
#define audio_extn_dap_hal_deinit() (0)
@@ -257,4 +262,8 @@ int audio_extn_dolby_set_dap_bypass(struct audio_device *adev, bool state);
#define audio_extn_ds2_enable(adev) (0)
#define audio_extn_dolby_set_dap_bypass(adev, state) (0)
#endif
+typedef enum {
+ DAP_STATE_ON = 0,
+ DAP_STATE_BYPASS,
+};
#endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c
index 9bba0784..76e4f57e 100644
--- a/hal/audio_extn/dolby.c
+++ b/hal/audio_extn/dolby.c
@@ -246,7 +246,8 @@ void send_ddp_endp_params(struct audio_device *adev,
(usecase->devices & ddp_dev) &&
(usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
((usecase->stream.out->format == AUDIO_FORMAT_AC3) ||
- (usecase->stream.out->format == AUDIO_FORMAT_EAC3))) {
+ (usecase->stream.out->format == AUDIO_FORMAT_EAC3) ||
+ (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC))) {
send_ddp_endp_params_stream(usecase->stream.out, ddp_dev,
dev_ch_cap, false /* set cache */);
}
@@ -263,7 +264,8 @@ void audio_extn_dolby_send_ddp_endp_params(struct audio_device *adev)
(usecase->devices & AUDIO_DEVICE_OUT_ALL) &&
(usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
((usecase->stream.out->format == AUDIO_FORMAT_AC3) ||
- (usecase->stream.out->format == AUDIO_FORMAT_EAC3))) {
+ (usecase->stream.out->format == AUDIO_FORMAT_EAC3) ||
+ (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC))) {
send_ddp_endp_params_stream(usecase->stream.out, usecase->devices,
usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ?
adev->cur_hdmi_channels : 2, false /* set cache */);
@@ -355,6 +357,7 @@ int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev,
#endif
break;
case AUDIO_FORMAT_EAC3:
+ case AUDIO_FORMAT_E_AC3_JOC:
id = SND_AUDIOCODEC_EAC3;
send_ddp_endp_params_stream(out, out->devices,
out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ?
@@ -373,7 +376,8 @@ int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev,
bool audio_extn_is_dolby_format(audio_format_t format)
{
if (format == AUDIO_FORMAT_AC3 ||
- format == AUDIO_FORMAT_EAC3)
+ format == AUDIO_FORMAT_EAC3 ||
+ format == AUDIO_FORMAT_E_AC3_JOC)
return true;
else
return false;
@@ -386,17 +390,13 @@ int audio_extn_dolby_update_passt_formats(struct audio_device *adev,
struct stream_out *out) {
int32_t i = 0, ret = -ENOSYS;
- /*
- * We can iterate through the list and return all formats if passthrough
- * needs to be supported on all the HDMI formats.
- */
- if(platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_AC3)) {
- out->supported_formats[i++] = AUDIO_FORMAT_AC3;
- ret = 0;
- }
- if(platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_EAC3)) {
- out->supported_formats[i++] = AUDIO_FORMAT_EAC3;
- ret = 0;
+ if (platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_AC3) ||
+ platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_EAC3)) {
+ out->supported_formats[i++] = AUDIO_FORMAT_AC3;
+ out->supported_formats[i++] = AUDIO_FORMAT_EAC3;
+ /* Reciever must support JOC and advertise, otherwise JOC is treated as DDP */
+ out->supported_formats[i++] = AUDIO_FORMAT_E_AC3_JOC;
+ ret = 0;
}
ALOGV("%s: ret = %d", __func__, ret);
return ret;
@@ -405,33 +405,57 @@ int audio_extn_dolby_update_passt_formats(struct audio_device *adev,
bool audio_extn_dolby_is_passt_convert_supported(struct audio_device *adev,
struct stream_out *out) {
- uint32_t i = 0;
-
- if(out->format == AUDIO_FORMAT_EAC3) {
- for(i = 0; i < MAX_SUPPORTED_FORMATS; i++) {
- if(out->supported_formats[i] == AUDIO_FORMAT_AC3) {
- ALOGV("%s:PASSTHROUGH_CONVERT supported", __func__);
- return true;
- }
+ bool convert = false;
+ switch (out->format) {
+ case AUDIO_FORMAT_EAC3:
+ case AUDIO_FORMAT_E_AC3_JOC:
+ if (!platform_is_edid_supported_format(adev->platform,
+ AUDIO_FORMAT_EAC3)) {
+ ALOGV("%s:PASSTHROUGH_CONVERT supported", __func__);
+ convert = true;
}
+ break;
+ default:
+ ALOGE("%s: PASSTHROUGH_CONVERT not supported for format 0x%x",
+ __func__, out->format);
+ break;
}
- ALOGV("%s:PASSTHROUGH_CONVERT inot supported", __func__);
- return false;
-
+ ALOGE("%s: convert %d", __func__, convert);
+ return convert;
}
bool audio_extn_dolby_is_passt_supported(struct audio_device *adev,
struct stream_out *out) {
- uint32_t i = 0;
-
- for(i = 0; i < MAX_SUPPORTED_FORMATS; i++) {
- if(out->supported_formats[i] == out->format) {
- ALOGV("%s:PASSTHROUGH supported", __func__);
- return true;
+ bool passt = false;
+ switch (out->format) {
+ case AUDIO_FORMAT_EAC3:
+ if (platform_is_edid_supported_format(adev->platform, out->format)) {
+ ALOGV("%s:PASSTHROUGH supported for format %x",
+ __func__, out->format);
+ passt = true;
}
+ break;
+ case AUDIO_FORMAT_AC3:
+ if (platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_AC3)
+ || platform_is_edid_supported_format(adev->platform,
+ AUDIO_FORMAT_EAC3)) {
+ ALOGV("%s:PASSTHROUGH supported for format %x",
+ __func__, out->format);
+ passt = true;
+ }
+ break;
+ case AUDIO_FORMAT_E_AC3_JOC:
+ /* Check for DDP capability in edid for JOC contents.*/
+ if (platform_is_edid_supported_format(adev->platform,
+ AUDIO_FORMAT_EAC3)) {
+ ALOGV("%s:PASSTHROUGH supported for format %x",
+ __func__, out->format);
+ passt = true;
+ }
+ default:
+ ALOGV("%s:Passthrough not supported", __func__);
}
- ALOGV("%s:Passthrough not supported", __func__);
- return false;
+ return passt;
}
void audio_extn_dolby_update_passt_stream_configuration(
@@ -445,38 +469,7 @@ void audio_extn_dolby_update_passt_stream_configuration(
} else {
ALOGV("%s:NO PASSTHROUGH", __func__);
out->compr_config.codec->compr_passthr = LEGACY_PCM;
- return;
}
-
- /* Logic to test convert */
-#ifdef TEST_PASSTHROUGH_CONVERT
- if (out->format == AUDIO_FORMAT_EAC3) {
- ALOGV("%s:PASSTHROUGH_CONVERT", __func__);
- out->compr_config.codec->compr_passthr = PASSTHROUGH_CONVERT;
- }
-#endif
- /*
- * For EC3 passthrough input sample rate should be 4 times the original
- * sample rate. For AC3 no change is required. The channel count should
- * be stereo irrespective of input channel count.
- */
- switch (out->format) {
- case AUDIO_FORMAT_EAC3:
- if(out->compr_config.codec->compr_passthr == PASSTHROUGH) {
- ALOGV("update samplerate %d-->%d",
- out->sample_rate, (out->sample_rate *4));
- out->sample_rate = out->sample_rate *4;
- out->compr_config.codec->sample_rate =
- compress_get_alsa_rate(out->sample_rate);
- }
- break;
- case AUDIO_FORMAT_AC3:
- default:
- ALOGV("No update of sample rate required");
- break;
- }
- out->compr_config.codec->ch_out = out->compr_config.codec->ch_in = 2;
- out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
}
bool audio_extn_dolby_is_passthrough_stream(int flags) {
@@ -494,6 +487,14 @@ int audio_extn_dolby_set_hdmi_format_and_samplerate(struct audio_device *adev,
int audio_extn_dolby_get_passt_buffer_size(audio_offload_info_t* info) {
return platform_get_compress_passthrough_buffer_size(info);
}
+
+int audio_extn_dolby_set_passt_volume(struct stream_out *out, int mute) {
+ return platform_set_device_params(out, DEVICE_PARAM_MUTE_ID, mute);
+}
+
+int audio_extn_dolby_set_passt_latency(struct stream_out *out, int latency) {
+ return platform_set_device_params(out, DEVICE_PARAM_LATENCY_ID, latency);
+}
#endif /* HDMI_PASSTHROUGH_ENABLED */
#ifdef DS1_DOLBY_DAP_ENABLED
@@ -690,9 +691,9 @@ int audio_extn_ds2_enable(struct audio_device *adev) {
return 0;
}
-int audio_extn_dolby_set_dap_bypass(struct audio_device *adev, bool state) {
+int audio_extn_dolby_set_dap_bypass(struct audio_device *adev, int state) {
- ALOGV("%s:", __func__);
+ ALOGV("%s: state %d", __func__, state);
if (ds2extnmod.dap_hal_set_hw_info) {
ds2extnmod.dap_hal_set_hw_info(DAP_BYPASS, (void*)(&state));
ALOGV("%s: Dolby set bypas :0x%x", __func__, state);
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 0eb8dbee..c328ccef 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -156,6 +156,7 @@ static const struct string_to_enum out_channels_name_to_enum_table[] = {
static const struct string_to_enum out_formats_name_to_enum_table[] = {
STRING_TO_ENUM(AUDIO_FORMAT_AC3),
STRING_TO_ENUM(AUDIO_FORMAT_EAC3),
+ STRING_TO_ENUM(AUDIO_FORMAT_E_AC3_JOC),
};
static struct audio_device *adev = NULL;
@@ -611,23 +612,23 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
* usecase. This is to avoid switching devices for voice call when
* check_usecases_codec_backend() is called below.
*/
- if (voice_is_in_call(adev)) {
+ if (adev->voice.in_call && adev->mode == AUDIO_MODE_IN_CALL) {
vc_usecase = get_usecase_from_list(adev,
get_voice_usecase_id_from_list(adev));
- if ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
- (usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL)) {
+ if ((vc_usecase) && ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
+ (usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL))) {
in_snd_device = vc_usecase->in_snd_device;
out_snd_device = vc_usecase->out_snd_device;
}
} else if (voice_extn_compress_voip_is_active(adev)) {
voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
- if (voip_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
+ if ((voip_usecase) && (voip_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)) {
in_snd_device = voip_usecase->in_snd_device;
out_snd_device = voip_usecase->out_snd_device;
}
} else if (audio_extn_hfp_is_active(adev)) {
hfp_usecase = get_usecase_from_list(adev, USECASE_AUDIO_HFP_SCO);
- if (hfp_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
+ if ((hfp_usecase) && (hfp_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)) {
in_snd_device = hfp_usecase->in_snd_device;
out_snd_device = hfp_usecase->out_snd_device;
}
@@ -1065,18 +1066,25 @@ static int check_and_set_hdmi_channels(struct audio_device *adev,
struct audio_usecase *usecase;
int ret;
+ unsigned int supported_channels = platform_edid_get_max_channels(
+ adev->platform);
+ ALOGV("supported_channels %d, channels %d", supported_channels, channels);
/* Check if change in HDMI channel config is allowed */
if (!allow_hdmi_channel_config(adev))
return 0;
+ if (channels > supported_channels)
+ channels = supported_channels;
+
if (channels == adev->cur_hdmi_channels) {
- ALOGD("%s: Requested channels are same as current channels(%d)", __func__, channels);
+ ALOGD("%s: Requested channels are same as current channels(%d)",
+ __func__, channels);
return 0;
}
/*TODO: CHECK for passthrough don't set channel map for passthrough*/
-
platform_set_hdmi_channels(adev->platform, channels);
+ platform_set_edid_channels_configuration(adev->platform, channels);
adev->cur_hdmi_channels = channels;
/*
@@ -1140,12 +1148,12 @@ static int stop_output_stream(struct stream_out *out)
free(uc_info);
if (is_offload_usecase(out->usecase) &&
- (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+ (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+ (audio_extn_dolby_is_passthrough_stream(out->flags))) {
ALOGV("Disable passthrough , reset mixer to pcm");
/* NO_PASSTHROUGH */
out->compr_config.codec->compr_passthr = 0;
audio_extn_dolby_set_hdmi_format_and_samplerate(adev, out);
- audio_extn_dolby_set_dap_bypass(adev, false);
}
/* Must be called after removing the usecase from list */
if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
@@ -1194,9 +1202,13 @@ int start_output_stream(struct stream_out *out)
__func__, sink_channels);
check_and_set_hdmi_channels(adev, sink_channels);
} else {
- if (is_offload_usecase(out->usecase))
- check_and_set_hdmi_channels(adev, out->compr_config.codec->ch_in);
- else
+ if (is_offload_usecase(out->usecase)) {
+ unsigned int ch_count = out->compr_config.codec->ch_in;
+ if (audio_extn_dolby_is_passthrough_stream(out->flags))
+ /* backend channel config for passthrough stream is stereo */
+ ch_count = 2;
+ check_and_set_hdmi_channels(adev, ch_count);
+ } else
check_and_set_hdmi_channels(adev, out->config.channels);
}
audio_extn_dolby_set_hdmi_format_and_samplerate(adev, out);
@@ -1233,7 +1245,7 @@ int start_output_stream(struct stream_out *out)
goto error_open;
}
if (out->offload_callback)
- compress_nonblock(out->compr, out->non_blocking);
+ compress_nonblock(out->compr, out->non_blocking);
#ifdef DS1_DOLBY_DDP_ENABLED
if (audio_extn_is_dolby_format(out->format))
@@ -1515,18 +1527,18 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
select_devices(adev, out->usecase);
if ((adev->mode == AUDIO_MODE_IN_CALL) &&
- !voice_is_in_call(adev) &&
+ !adev->voice.in_call &&
(out == adev->primary_output)) {
ret = voice_start_call(adev);
} else if ((adev->mode == AUDIO_MODE_IN_CALL) &&
- voice_is_in_call(adev) &&
+ adev->voice.in_call &&
(out == adev->primary_output)) {
voice_update_devices_for_all_voice_usecases(adev);
}
}
if ((adev->mode == AUDIO_MODE_NORMAL) &&
- voice_is_in_call(adev) &&
+ adev->voice.in_call &&
(out == adev->primary_output)) {
ret = voice_stop_call(adev);
}
@@ -1561,6 +1573,12 @@ static char* out_get_parameters(const struct audio_stream *stream, const char *k
size_t i, j;
int ret;
bool first = true;
+
+ if (!query || !reply) {
+ ALOGE("out_get_parameters: failed to allocate mem for query or reply");
+ return NULL;
+ }
+
ALOGV("%s: enter: keys - %s", __func__, keys);
ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value));
if (ret >= 0) {
@@ -1620,8 +1638,20 @@ static uint32_t out_get_latency(const struct audio_stream_out *stream)
{
struct stream_out *out = (struct stream_out *)stream;
- if (is_offload_usecase(out->usecase))
- return COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
+ if (is_offload_usecase(out->usecase)) {
+ if ((out->format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD) &&
+ (!out->non_blocking) &&
+ (out->sample_rate) &&
+ (out->compr_config.codec->ch_in) &&
+ (audio_bytes_per_sample(AUDIO_FORMAT_PCM_16_BIT_OFFLOAD)))
+ /* ToDo: Add check for 24 bit offload */
+ return (out->compr_config.fragments *
+ out->compr_config.fragment_size * 1000) /
+ (out->sample_rate * out->compr_config.codec->ch_in *
+ audio_bytes_per_sample(AUDIO_FORMAT_PCM_16_BIT_OFFLOAD));
+ else
+ return COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
+ }
return (out->config.period_count * out->config.period_size * 1000) /
(out->config.rate);
@@ -1638,24 +1668,33 @@ static int out_set_volume(struct audio_stream_out *stream, float left,
out->muted = (left == 0.0f);
return 0;
} else if (is_offload_usecase(out->usecase)) {
- char mixer_ctl_name[128];
- struct audio_device *adev = out->dev;
- struct mixer_ctl *ctl;
- int pcm_device_id = platform_get_pcm_device_id(out->usecase,
+ if (audio_extn_dolby_is_passthrough_stream(out->flags)) {
+ /*
+ * Set mute or umute on HDMI passthrough stream.
+ * Only take left channel into account.
+ * Mute is 0 and unmute 1
+ */
+ audio_extn_dolby_set_passt_volume(out, (left == 0.0f));
+ } else {
+ char mixer_ctl_name[128];
+ struct audio_device *adev = out->dev;
+ struct mixer_ctl *ctl;
+ int pcm_device_id = platform_get_pcm_device_id(out->usecase,
PCM_PLAYBACK);
- snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
- "Compress Playback %d Volume", pcm_device_id);
- 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;
+ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "Compress Playback %d Volume", pcm_device_id);
+ 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;
+ }
+ volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX);
+ volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
+ mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
+ return 0;
}
- volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX);
- volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
- mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
- return 0;
}
return -ENOSYS;
@@ -2029,6 +2068,12 @@ static char* in_get_parameters(const struct audio_stream *stream,
char *str;
char value[256];
struct str_parms *reply = str_parms_create();
+
+ if (!query || !reply) {
+ ALOGE("in_get_parameters: failed to create query or reply");
+ return NULL;
+ }
+
ALOGV("%s: enter: keys - %s", __func__, keys);
voice_extn_in_get_parameters(in, query, reply);
@@ -2080,7 +2125,7 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
* Instead of writing zeroes here, we could trust the hardware
* to always provide zeroes when muted.
*/
- if (ret == 0 && voice_get_mic_mute(adev) && !voice_is_in_call(adev))
+ if (ret == 0 && voice_get_mic_mute(adev) && !adev->voice.in_call)
memset(buffer, 0, bytes);
exit:
@@ -2229,10 +2274,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
if ((out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
((audio_extn_dolby_is_passthrough_stream(out->flags)))) {
ALOGV("read and update_pass through formats");
- ret = audio_extn_dolby_set_dap_bypass(adev, true);
- if(ret != 0) {
- goto error_open;
- }
ret = audio_extn_dolby_update_passt_formats(adev, out);
if(ret != 0) {
goto error_open;
@@ -2292,6 +2333,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
out->compr_config.codec->ch_in =
popcount(config->channel_mask);
out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
+ /*TODO: Do we need to change it for passthrough */
out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
if (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD)
@@ -2302,6 +2344,12 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
out->non_blocking = 1;
+ if (config->offload_info.use_small_bufs) {
+ out->non_blocking = 0;
+ ALOGI("Keep write blocking for small buff: non_blockling %d",
+ out->non_blocking);
+ }
+
out->send_new_metadata = 1;
out->offload_state = OFFLOAD_STATE_IDLE;
out->playback_started = 0;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 6623b4ef..6aa65d64 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -50,9 +50,10 @@
#define ACDB_DEV_TYPE_IN 2
#define MAX_SUPPORTED_CHANNEL_MASKS 2
-#define MAX_SUPPORTED_FORMATS 2
+#define MAX_SUPPORTED_FORMATS 3
#define DEFAULT_HDMI_OUT_CHANNELS 2
+#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (4 * 1024)
typedef int snd_device_t;
/* These are the supported use cases by the hardware.
diff --git a/hal/edid.c b/hal/edid.c
index 0b4b80d3..31a0d039 100644
--- a/hal/edid.c
+++ b/hal/edid.c
@@ -18,8 +18,8 @@
*/
#define LOG_TAG "audio_hw_edid"
-//#define LOG_NDEBUG 0
-//#define LOG_NDDEBUG 0
+/*#define LOG_NDEBUG 0*/
+/*#define LOG_NDDEBUG 0*/
#include <errno.h>
#include <cutils/properties.h>
@@ -259,7 +259,7 @@ static void update_channel_map(edid_audio_info* pInfo)
pInfo->channel_map[7] = 0; // PCM_CHANNEL_FRH; but not defined by LPASS
}
}
- ALOGD("%s channel map updated to [%d %d %d %d %d %d %d %d ] [%x %x %x]", __func__
+ ALOGV("%s channel map updated to [%d %d %d %d %d %d %d %d ] [%x %x %x]", __func__
, pInfo->channel_map[0], pInfo->channel_map[1], pInfo->channel_map[2]
, pInfo->channel_map[3], pInfo->channel_map[4], pInfo->channel_map[5]
, pInfo->channel_map[6], pInfo->channel_map[7]
@@ -358,7 +358,7 @@ static void update_channel_allocation(edid_audio_info* pInfo)
case (BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(7)): ca = 0x31; break;
default: ca = 0x0; break;
}
- ALOGD("%s channel Allocation: %x", __func__, ca);
+ ALOGV("%s channel Allocation: %x", __func__, ca);
pInfo->channel_allocation = ca;
}
}
@@ -609,7 +609,7 @@ static void update_channel_map_lpass(edid_audio_info* pInfo)
break;
}
- ALOGD("%s channel map updated to [%d %d %d %d %d %d %d %d ]", __func__
+ ALOGV("%s channel map updated to [%d %d %d %d %d %d %d %d ]", __func__
, pInfo->channel_map[0], pInfo->channel_map[1], pInfo->channel_map[2]
, pInfo->channel_map[3], pInfo->channel_map[4], pInfo->channel_map[5]
, pInfo->channel_map[6], pInfo->channel_map[7]);
@@ -674,7 +674,7 @@ static void dump_edid_data(edid_audio_info *info) {
ALOGV("%s:FormatId:%d rate:%d bps:%d channels:%d", __func__,
info->audio_blocks_array[i].format_id,
info->audio_blocks_array[i].sampling_freq,
- info->audio_blocksArray[i].bits_per_sample,
+ info->audio_blocks_array[i].bits_per_sample,
info->audio_blocks_array[i].channels);
}
ALOGV("%s:nAudioBlocks:%d", __func__, info->audio_blocks);
@@ -688,7 +688,7 @@ static void dump_edid_data(edid_audio_info *info) {
info->channel_map[6], info->channel_map[7]);
ALOGV("%s:channelAllocation:%d", __func__, info->channel_allocation);
ALOGV("%s:[%d %d %d %d %d %d %d %d ]", __func__,
- info->channel_map[0], info.channel_map[1],
+ info->channel_map[0], info->channel_map[1],
info->channel_map[2], info->channel_map[3],
info->channel_map[4], info->channel_map[5],
info->channel_map[6], info->channel_map[7]);
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index cd65f8df..73749718 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1005,7 +1005,7 @@ int platform_set_default_channel_map(void *platform __unused,
return 0;
}
-int platform_get_channels_from_edid_info(void *platform __unused,
+int platform_set_edid_channels_configuration(void *platform __unused,
int channels __unused)
{
return 0;
@@ -1030,3 +1030,8 @@ int platform_set_hdmi_format_and_samplerate(struct stream_out *out __unused)
{
return 0;
}
+int platform_set_device_params(struct stream_out *out __unused,
+ int param __unused, int value __unused)
+{
+ return 0;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 22961677..78e47fcb 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -67,6 +67,7 @@
*/
#define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (4 * 1024)
+#define PCM_OFFLOAD_SMALL_BUFFER_DURATION 20 /* 20 msec */
/*
* Offload buffer size for compress passthrough
@@ -1698,56 +1699,28 @@ int platform_set_hdmi_channels(void *platform, int channel_count)
int platform_edid_get_max_channels(void *platform)
{
+ int channel_count;
+ int max_channels = 2;
+ int i = 0, ret = 0;
struct platform_data *my_data = (struct platform_data *)platform;
struct audio_device *adev = my_data->adev;
- char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE];
- char *sad = block;
- int num_audio_blocks;
- int channel_count;
- int max_channels = 0;
- int i, ret, count;
-
- struct mixer_ctl *ctl;
-
- ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_DATA_BLOCK_MIXER_CTL);
- if (!ctl) {
- ALOGE("%s: Could not get ctl for mixer cmd - %s",
- __func__, AUDIO_DATA_BLOCK_MIXER_CTL);
- return 0;
- }
-
- mixer_ctl_update(ctl);
-
- count = mixer_ctl_get_num_values(ctl);
-
- /* Read SAD blocks, clamping the maximum size for safety */
- if (count > (int)sizeof(block))
- count = (int)sizeof(block);
-
- ret = mixer_ctl_get_array(ctl, block, count);
- if (ret != 0) {
- ALOGE("%s: mixer_ctl_get_array() failed to get EDID info", __func__);
- return 0;
- }
-
- /* Calculate the number of SAD blocks */
- num_audio_blocks = count / SAD_BLOCK_SIZE;
+ edid_audio_info *info = NULL;
+ ret = platform_get_edid_info(platform);
+ info = (edid_audio_info *)my_data->edid_info;
- for (i = 0; i < num_audio_blocks; i++) {
- /* Only consider LPCM blocks */
- if ((sad[0] >> 3) != EDID_FORMAT_LPCM) {
- sad += 3;
- continue;
+ if(ret == 0 && info != NULL) {
+ for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
+ ALOGV("%s:format %d channel %d", __func__,
+ info->audio_blocks_array[i].format_id,
+ info->audio_blocks_array[i].channels);
+ if (info->audio_blocks_array[i].format_id == LPCM) {
+ channel_count = info->audio_blocks_array[i].channels;
+ if (channel_count > max_channels) {
+ max_channels = channel_count;
+ }
+ }
}
-
- channel_count = (sad[0] & 0x7) + 1;
- if (channel_count > max_channels)
- max_channels = channel_count;
-
- /* Advance to next block */
- sad += 3;
}
-
return max_channels;
}
@@ -2032,37 +2005,62 @@ uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info)
uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info)
{
- uint32_t fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
+ uint32_t fragment_size = 0;
uint32_t bits_per_sample = 16;
+ char value[PROPERTY_VALUE_MAX] = {0};
+ char propValue[PROPERTY_VALUE_MAX] = {0};
+ bool track_offload = false;
+
+ property_get("audio.offload.track.enabled", value, "0");
+ track_offload = atoi(value) || !strncmp("true", propValue, sizeof("true"));
if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) {
bits_per_sample = 32;
}
- if (!info->has_video) {
- fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
-
- } else if (info->has_video && info->is_streaming) {
- fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING
- * info->sample_rate
- * (bits_per_sample >> 3)
- * popcount(info->channel_mask))/1000;
-
- } else if (info->has_video) {
- fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV
- * info->sample_rate
- * (bits_per_sample >> 3)
- * popcount(info->channel_mask))/1000;
- }
-
- char value[PROPERTY_VALUE_MAX] = {0};
if((property_get("audio.offload.pcm.buffer.size", value, "")) &&
atoi(value)) {
fragment_size = atoi(value) * 1024;
ALOGV("Using buffer size from sys prop %d", fragment_size);
}
- fragment_size = ALIGN( fragment_size, 1024);
+ if(track_offload && info->use_small_bufs &&
+ (property_get("audio.offload.track.buffer.size", value, "")) &&
+ atoi(value)) {
+ ALOGV("Track offload Fragment size set by property to %dkb", atoi(value));
+ fragment_size = atoi(value) * 1024;
+ } else if (info->use_small_bufs) {
+ fragment_size = (PCM_OFFLOAD_SMALL_BUFFER_DURATION
+ * info->sample_rate
+ * audio_bytes_per_sample(info->format)
+ * popcount(info->channel_mask))/1000;
+ ALOGV("%s: fragment size for small buffer mode = %d"
+ "sample_rate=%d bytes_per_sample=%d channel_count=%d\n",
+ __func__, fragment_size,
+ info->sample_rate,
+ audio_bytes_per_sample(info->format),
+ popcount(info->channel_mask));
+ } else {
+ fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
+ }
+
+ if(!info->use_small_bufs) {
+ if (!info->has_video) {
+ fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
+ } else if (info->has_video && info->is_streaming) {
+ fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING
+ * info->sample_rate
+ * bits_per_sample
+ * popcount(info->channel_mask))/1000;
+ } else if (info->has_video) {
+ fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV
+ * info->sample_rate
+ * bits_per_sample
+ * popcount(info->channel_mask))/1000;
+ }
+ }
+
+ fragment_size = ALIGN(fragment_size, 1024);
if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
@@ -2142,6 +2140,8 @@ int platform_get_edid_info(void *platform)
goto fail;
}
+ mixer_ctl_update(ctl);
+
count = mixer_ctl_get_num_values(ctl);
ALOGV("Count: %d",count);
@@ -2195,7 +2195,8 @@ int platform_set_channel_allocation(void *platform, int channelAlloc)
__func__, mixer_ctl_name);
ret = EINVAL;
}
- ALOGD(":%s channel allocation = 0x%x", __func__, channelAlloc);
+
+ ALOGV(":%s channel allocation = 0x%x", __func__, channelAlloc);
ret = mixer_ctl_set_value(ctl, 0, channelAlloc);
if (ret < 0) {
@@ -2225,7 +2226,7 @@ int platform_set_channel_map(void *platform, int ch_count, char *ch_map, int snd
strncat(mixer_ctl_name, device_num, 13);
}
- ALOGD("%s mixer_ctl_name:%s", __func__, mixer_ctl_name);
+ ALOGV("%s mixer_ctl_name:%s", __func__, mixer_ctl_name);
ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
if (!ctl) {
@@ -2233,11 +2234,12 @@ int platform_set_channel_map(void *platform, int ch_count, char *ch_map, int snd
__func__, mixer_ctl_name);
return -EINVAL;
}
+
for (i = 0; i< 8; i++) {
set_values[i] = ch_map[i];
}
- ALOGD("%s: set mapping(%d %d %d %d %d %d %d %d) for channel:%d", __func__,
+ ALOGV("%s: set mapping(%d %d %d %d %d %d %d %d) for channel:%d", __func__,
set_values[0], set_values[1], set_values[2], set_values[3], set_values[4],
set_values[5], set_values[6], set_values[7], ch_count);
@@ -2309,11 +2311,18 @@ bool platform_is_edid_supported_format(void *platform, int format) {
info = (edid_audio_info *)my_data->edid_info;
if(ret == 0 && info != NULL) {
for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
+ ALOGV("%s:platform_is_edid_supported_format true %x, %x",
+ __func__, format, info->audio_blocks_array[i].format_id);
+#ifdef CONFIG_HDMI_PASSTHROUGH_CONVERT
+ if (info->audio_blocks_array[i].format_id == DOLBY_DIGITAL_PLUS)
+ continue;
+#endif
if(info->audio_blocks_array[i].format_id ==
- platform_map_to_edid_format(format))
+ platform_map_to_edid_format(format)) {
ALOGV("%s:platform_is_edid_supported_format true %x",
__func__, format);
return true;
+ }
}
}
ALOGV("%s:platform_is_edid_supported_format false %x",
@@ -2321,21 +2330,20 @@ bool platform_is_edid_supported_format(void *platform, int format) {
return false;
}
-int platform_get_channels_from_edid_info(void *platform, int channels) {
+int platform_set_edid_channels_configuration(void *platform, int channels) {
struct platform_data *my_data = (struct platform_data *)platform;
struct audio_device *adev = my_data->adev;
edid_audio_info *info = NULL;
int num_audio_blocks;
int channel_count = 2;
- int max_channels = 0;
int i, ret, count;
char default_channelMap[MAX_CHANNELS_SUPPORTED] = {0};
ret = platform_get_edid_info(platform);
info = (edid_audio_info *)my_data->edid_info;
if(ret == 0 && info != NULL) {
- if (channels > 2){
+ if (channels > 2) {
ALOGV("%s:able to get HDMI sink capabilities multi channel playback",
__func__);
@@ -2347,8 +2355,13 @@ int platform_get_channels_from_edid_info(void *platform, int channels) {
}
}
ALOGVV("%s:channel_count:%d", __func__, channel_count);
- platform_set_channel_map(platform,channel_count,info->channel_map, -1);
- platform_set_channel_allocation(platform,info->channel_allocation);
+ /*
+ * Channel map is set for supported hdmi max channel count even
+ * though the input channel count set on adm is less than or equal to
+ * max supported channel count
+ */
+ platform_set_channel_map(platform, channel_count, info->channel_map, -1);
+ platform_set_channel_allocation(platform, info->channel_allocation);
} else {
default_channelMap[0] = 1;
default_channelMap[1] = 2;
@@ -2357,7 +2370,7 @@ int platform_get_channels_from_edid_info(void *platform, int channels) {
}
}
- return max_channels;
+ return 0;
}
int platform_set_mixer_control(struct stream_out *out, const char * mixer_ctl_name,
@@ -2365,7 +2378,7 @@ int platform_set_mixer_control(struct stream_out *out, const char * mixer_ctl_na
{
struct audio_device *adev = out->dev;
struct mixer_ctl *ctl = NULL;
- ALOGD("setting mixer ctl %s with value %s", mixer_ctl_name, mixer_val);
+ ALOGV("setting mixer ctl %s with value %s", mixer_ctl_name, mixer_val);
ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
if (!ctl) {
ALOGE("%s: could not get ctl for mixer cmd - %s",
@@ -2383,14 +2396,20 @@ int platform_set_hdmi_format_and_samplerate(struct stream_out *out)
struct audio_device *adev = out->dev;
const char *hdmi_format_ctrl = "HDMI RX Format";
const char *hdmi_rate_ctrl = "HDMI_RX SampleRate";
-
+ int sample_rate = out->sample_rate;
+ /*TODO: Add rules and check if this needs to be done.*/
if((is_offload_usecase(out->usecase)) &&
(out->compr_config.codec->compr_passthr == PASSTHROUGH ||
out->compr_config.codec->compr_passthr == PASSTHROUGH_CONVERT)) {
- ALOGD("%s:HDMI compress format and samplerate %d", __func__,
- out->sample_rate);
+ /* TODO: can we add mixer control for channels here avoid setting */
+ if ((out->format == AUDIO_FORMAT_EAC3 ||
+ out->format == AUDIO_FORMAT_E_AC3_JOC) &&
+ (out->compr_config.codec->compr_passthr == PASSTHROUGH))
+ sample_rate = out->sample_rate * 4;
+ ALOGD("%s:HDMI compress format and samplerate %d, sample_rate %d",
+ __func__, out->sample_rate, sample_rate);
platform_set_mixer_control(out, hdmi_format_ctrl, "Compr");
- switch (out->sample_rate) {
+ switch (sample_rate) {
case 32000:
platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_32");
break;
@@ -2421,7 +2440,7 @@ int platform_set_hdmi_format_and_samplerate(struct stream_out *out)
platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_48");
}
- /*
+ /*
* Deroute all the playback streams routed to HDMI so that
* the back end is deactivated. Note that backend will not
* be deactivated if any one stream is connected to it.
@@ -2452,3 +2471,30 @@ int platform_set_hdmi_format_and_samplerate(struct stream_out *out)
return 0;
}
+
+int platform_set_device_params(struct stream_out *out, int param, int value)
+{
+ struct audio_device *adev = out->dev;
+ struct mixer_ctl *ctl;
+ char *mixer_ctl_name = "Device PP Params";
+ int ret = 0;
+ uint32_t set_values[] = {0,0};
+
+ set_values[0] = param;
+ set_values[1] = 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);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ ALOGV("%s: Setting device pp params param: %d, value %d mixer ctrl:%s",
+ __func__,param, value, mixer_ctl_name);
+ mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+end:
+ return ret;
+}
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index f2354c39..e3c89f44 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -329,5 +329,10 @@ enum {
PASSTHROUGH,
PASSTHROUGH_CONVERT
};
-
+/*
+ * ID for setting mute and lateny on the device side
+ * through Device PP Params mixer control.
+ */
+#define DEVICE_PARAM_MUTE_ID 0
+#define DEVICE_PARAM_LATENCY_ID 1
#endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 9d301653..bedfb750 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -82,9 +82,10 @@ int platform_get_edid_info(void *platform);
int platform_set_channel_map(void *platform, int ch_count, char *ch_map,
int snd_id);
int platform_set_default_channel_map(void *platform, int channels, int snd_id);
-int platform_get_channels_from_edid_info(void *platform, int channels);
+int platform_set_edid_channels_configuration(void *platform, int channels);
void platform_reset_edid_info(void *platform);
unsigned char platform_map_to_edid_format(int format);
bool platform_is_edid_supported_format(void *platform, int format);
int platform_set_hdmi_format_and_samplerate(struct stream_out *out);
+int platform_set_device_params(struct stream_out *out, int param, int value);
#endif // AUDIO_PLATFORM_API_H
diff --git a/hal/voice.c b/hal/voice.c
index 62d01dbe..ac3c125b 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -175,26 +175,27 @@ int start_call(struct audio_device *adev, audio_usecase_t usecase_id)
}
session->state.current = CALL_ACTIVE;
- return 0;
+ goto done;
error_start_voice:
stop_call(adev, usecase_id);
+done:
ALOGD("%s: exit: status(%d)", __func__, ret);
return ret;
}
-bool voice_is_in_call(struct audio_device *adev)
+bool voice_is_call_state_active(struct audio_device *adev)
{
- bool in_call = false;
+ bool call_state = false;
int ret = 0;
- ret = voice_extn_is_in_call(adev, &in_call);
+ ret = voice_extn_is_call_state_active(adev, &call_state);
if (ret == -ENOSYS) {
- in_call = (adev->voice.session[VOICE_SESS_IDX].state.current == CALL_ACTIVE) ? true : false;
+ call_state = (adev->voice.session[VOICE_SESS_IDX].state.current == CALL_ACTIVE) ? true : false;
}
- return in_call;
+ return call_state;
}
uint32_t voice_get_active_session_id(struct audio_device *adev)
@@ -217,7 +218,7 @@ int voice_check_and_set_incall_rec_usecase(struct audio_device *adev,
int usecase_id;
int rec_mode = INCALL_REC_NONE;
- if (voice_is_in_call(adev)) {
+ if (voice_is_call_state_active(adev)) {
switch (in->source) {
case AUDIO_SOURCE_VOICE_UPLINK:
if (audio_extn_compr_cap_enabled() &&
@@ -343,6 +344,7 @@ int voice_start_call(struct audio_device *adev)
if (ret == -ENOSYS) {
ret = start_call(adev, USECASE_VOICE_CALL);
}
+ adev->voice.in_call = true;
return ret;
}
@@ -351,6 +353,7 @@ int voice_stop_call(struct audio_device *adev)
{
int ret = 0;
+ adev->voice.in_call = false;
ret = voice_extn_stop_call(adev);
if (ret == -ENOSYS) {
ret = stop_call(adev, USECASE_VOICE_CALL);
@@ -404,7 +407,7 @@ int voice_set_parameters(struct audio_device *adev, struct str_parms *parms)
if (tty_mode != adev->voice.tty_mode) {
adev->voice.tty_mode = tty_mode;
adev->acdb_settings = (adev->acdb_settings & TTY_MODE_CLEAR) | tty_mode;
- if (voice_is_in_call(adev))
+ if (voice_is_call_state_active(adev))
voice_update_devices_for_all_voice_usecases(adev);
}
}
@@ -433,7 +436,7 @@ void voice_init(struct audio_device *adev)
adev->voice.tty_mode = TTY_MODE_OFF;
adev->voice.volume = 1.0f;
adev->voice.mic_mute = false;
- adev->voice.voice_device_set = false;
+ adev->voice.in_call = false;
for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
adev->voice.session[i].pcm_rx = NULL;
adev->voice.session[i].pcm_tx = NULL;
diff --git a/hal/voice.h b/hal/voice.h
index d160569d..abb8c559 100644
--- a/hal/voice.h
+++ b/hal/voice.h
@@ -60,7 +60,7 @@ struct voice {
int tty_mode;
bool mic_mute;
float volume;
- bool voice_device_set;
+ bool in_call;
};
enum {
@@ -76,7 +76,7 @@ int voice_set_parameters(struct audio_device *adev, struct str_parms *parms);
void voice_get_parameters(struct audio_device *adev, struct str_parms *query,
struct str_parms *reply);
void voice_init(struct audio_device *adev);
-bool voice_is_in_call(struct audio_device *adev);
+bool voice_is_call_state_active(struct audio_device *adev);
int voice_set_mic_mute(struct audio_device *dev, bool state);
bool voice_get_mic_mute(struct audio_device *dev);
int voice_set_volume(struct audio_device *adev, float volume);
diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c
index deb3172c..9937a612 100644
--- a/hal/voice_extn/compress_voip.c
+++ b/hal/voice_extn/compress_voip.c
@@ -564,8 +564,13 @@ int voice_extn_compress_voip_start_output_stream(struct stream_out *out)
ret = voip_start_call(adev, &out->config);
out->pcm = voip_data.pcm_rx;
uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
- uc_info->stream.out = out;
- uc_info->devices = out->devices;
+ if (uc_info) {
+ uc_info->stream.out = out;
+ uc_info->devices = out->devices;
+ } else {
+ ret = -EINVAL;
+ ALOGE("%s: exit(%d): failed to get use case info", __func__, ret);
+ }
ALOGV("%s: exit: status(%d)", __func__, ret);
return ret;
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
index f6aad9a8..12bf9a5c 100644
--- a/hal/voice_extn/voice_extn.c
+++ b/hal/voice_extn/voice_extn.c
@@ -72,7 +72,7 @@ struct pcm_config pcm_config_incall_music = {
extern int start_call(struct audio_device *adev, audio_usecase_t usecase_id);
extern int stop_call(struct audio_device *adev, audio_usecase_t usecase_id);
-int voice_extn_is_in_call(struct audio_device *adev, bool *in_call);
+int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active);
static bool is_valid_call_state(int call_state)
{
@@ -152,7 +152,6 @@ static int update_calls(struct audio_device *adev)
struct voice_session *session = NULL;
int fd = 0;
int ret = 0;
- bool is_in_call = false;
ALOGD("%s: enter:", __func__);
@@ -212,10 +211,6 @@ static int update_calls(struct audio_device *adev)
ALOGE("%s: voice_end_call() failed for usecase: %d\n",
__func__, usecase_id);
} else {
- voice_extn_is_in_call(adev, &is_in_call);
- if (!is_in_call) {
- adev->voice.voice_device_set = false;
- }
session->state.current = session->state.new;
}
break;
@@ -287,8 +282,7 @@ static int update_call_states(struct audio_device *adev,
{
struct voice_session *session = NULL;
int i = 0;
- bool is_in_call;
- int no_of_calls_active = 0;
+ bool is_call_active;
for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
if (vsid == adev->voice.session[i].vsid) {
@@ -297,21 +291,16 @@ static int update_call_states(struct audio_device *adev,
}
}
- for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
- if (CALL_INACTIVE != adev->voice.session[i].state.current)
- no_of_calls_active++;
- }
-
if (session) {
session->state.new = call_state;
- voice_extn_is_in_call(adev, &is_in_call);
- ALOGD("%s is_in_call:%d voice_device_set:%d, mode:%d\n",
- __func__, is_in_call, adev->voice.voice_device_set, adev->mode);
+ voice_extn_is_call_state_active(adev, &is_call_active);
+ ALOGD("%s is_call_active:%d in_call:%d, mode:%d\n",
+ __func__, is_call_active, adev->voice.in_call, adev->mode);
/* Dont start voice call before device routing for voice usescases has
* occured, otherwise voice calls will be started unintendedly on
* speaker.
*/
- if (is_in_call || adev->voice.voice_device_set) {
+ if (is_call_active || adev->voice.in_call) {
/* Device routing is not triggered for voice calls on the subsequent
* subs, Hence update the call states if voice call is already
* active on other sub.
@@ -333,16 +322,16 @@ int voice_extn_get_active_session_id(struct audio_device *adev,
return 0;
}
-int voice_extn_is_in_call(struct audio_device *adev, bool *in_call)
+int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active)
{
struct voice_session *session = NULL;
int i = 0;
- *in_call = false;
+ *is_call_active = false;
for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
session = &adev->voice.session[i];
if(session->state.current != CALL_INACTIVE){
- *in_call = true;
+ *is_call_active = true;
break;
}
}
@@ -401,7 +390,6 @@ int voice_extn_start_call(struct audio_device *adev)
* udpated.
*/
ALOGV("%s: enter:", __func__);
- adev->voice.voice_device_set = true;
return update_calls(adev);
}
@@ -448,6 +436,7 @@ int voice_extn_set_parameters(struct audio_device *adev,
err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_CALL_STATE, &value);
if (err >= 0) {
call_state = value;
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_CALL_STATE);
} else {
ALOGE("%s: call_state key not found", __func__);
ret = -EINVAL;
diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h
index f7d20e4c..a31aefee 100644
--- a/hal/voice_extn/voice_extn.h
+++ b/hal/voice_extn/voice_extn.h
@@ -32,7 +32,8 @@ int voice_extn_set_parameters(struct audio_device *adev,
void voice_extn_get_parameters(const struct audio_device *adev,
struct str_parms *query,
struct str_parms *reply);
-int voice_extn_is_in_call(struct audio_device *adev, bool *in_call);
+int voice_extn_is_call_state_active(struct audio_device *adev,
+ bool *is_call_active);
int voice_extn_get_active_session_id(struct audio_device *adev,
uint32_t *session_id);
void voice_extn_in_get_parameters(struct stream_in *in,
@@ -75,7 +76,8 @@ static void voice_extn_get_parameters(const struct audio_device *adev,
{
}
-static int voice_extn_is_in_call(struct audio_device *adev, bool *in_call)
+static int voice_extn_is_call_state_active(struct audio_device *adev,
+ bool *is_call_active)
{
return -ENOSYS;
}
diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp
index 89f0c49a..c7566ad8 100644
--- a/policy_hal/AudioPolicyManager.cpp
+++ b/policy_hal/AudioPolicyManager.cpp
@@ -1126,11 +1126,6 @@ audio_io_handle_t AudioPolicyManager::getOutput(AudioSystem::stream_type stream,
// Change device to speaker in case of system tone & message tone
device = AUDIO_DEVICE_OUT_SPEAKER;
}
-
- if (device & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
- ALOGV("check and invalidate");
- //updateAndCloseOutputs();
- }
#endif
#ifdef AUDIO_POLICY_TEST
@@ -1183,6 +1178,20 @@ audio_io_handle_t AudioPolicyManager::getOutput(AudioSystem::stream_type stream,
} else {
ALOGV("getPassthroughOutput:No passthrough o/p returned,try other o/p");
}
+
+ if (device & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+ // Invalidate and close the passthrough output if there is an incoming
+ // non passthrough music streams.
+ // Condition is ignores for for system streams and message tone as they
+ // will be played out on speaker.
+ if ((stream == AudioSystem::SYSTEM) ||
+ (strategy == STRATEGY_SONIFICATION_RESPECTFUL)) {
+ ALOGV("Do not update and close output system tones/sonification");
+ } else {
+ ALOGV("check and invalidate");
+ updateAndCloseOutputs();
+ }
+ }
#endif
if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
@@ -1718,7 +1727,11 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
// and kernel buffers. Also the latency does not always include additional delay in the
// audio path (audio DSP, CODEC ...)
#ifdef HDMI_PASSTHROUGH_ENABLED
- newDevice = handleHDMIPassthrough(newDevice, output, stream);
+ // Use the stream ref count to check if ringtone/ notification
+ // needs to be on speaker. Input stream type should be used only
+ // when a particular stream is started. On stop if stream type is
+ // used, the device is changed to speaker even when ringtone ends.
+ newDevice = handleHDMIPassthrough(newDevice, output);
#endif
setOutputDevice(output, newDevice, false, outputDesc->mLatency*2);
@@ -1875,19 +1888,20 @@ void AudioPolicyManager::closeOutput(audio_io_handle_t output)
void AudioPolicyManager::checkAndSuspendOutputs() {
AudioOutputDescriptor *desc;
- char value[PROPERTY_VALUE_MAX] = {0};
- property_get("audio.offload.passthrough", value, NULL);
- if (!(atoi(value) || !strncmp("true", value, 4))) {
+
+ if (!isHDMIPassthroughEnabled()) {
ALOGV("checkAndSuspendOutputs: passthrough not enabled");
return;
}
+
for (size_t i = 0; i < mOutputs.size(); i++) {
desc = mOutputs.valueAt(i);
ALOGV("checkAndSuspendOutputs:device 0x%x, flag %x, music refcount %d",
desc->mDevice, desc->mFlags, desc->mRefCount[AudioSystem::MUSIC]);
if (desc->mDevice & AUDIO_DEVICE_OUT_AUX_DIGITAL ||
desc->mDevice == AUDIO_DEVICE_NONE) {
- // check if already suspended before suspending the output
+ // check if fast/deep buffer/multichannel outputs are already
+ // suspended before suspending the output
if (((desc->mFlags &
(AudioSystem::output_flags)AUDIO_OUTPUT_FLAG_FAST) &&
!mFastSuspended) ||
@@ -1896,11 +1910,17 @@ void AudioPolicyManager::checkAndSuspendOutputs() {
!mPrimarySuspended) ||
((desc->mFlags &
(AudioSystem::output_flags)AUDIO_OUTPUT_FLAG_PRIMARY) &&
- !mPrimarySuspended)) {
+ !mPrimarySuspended) ||
+ ((desc->mFlags & (AudioSystem::output_flags)
+ AUDIO_OUTPUT_FLAG_DIRECT) &&
+ !(desc->mFlags & (AudioSystem::output_flags)
+ AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
+ !mMultiChannelSuspended)) {
/*TODO : is other streams needed here. */
ALOGD("suspend Ouput");
mpClientInterface->suspendOutput(mOutputs.keyAt(i));
- // Update the reference count after suspend
+ // Update the reference count of fast/deep buffer/multichannel
+ // after suspend.
if (desc->mFlags &
(AudioSystem::output_flags)AUDIO_OUTPUT_FLAG_DEEP_BUFFER ||
desc->mFlags &
@@ -1909,6 +1929,11 @@ void AudioPolicyManager::checkAndSuspendOutputs() {
} else if (desc->mFlags &
(AudioSystem::output_flags)AUDIO_OUTPUT_FLAG_FAST) {
mFastSuspended++;
+ } else if ((desc->mFlags & (AudioSystem::output_flags)
+ AUDIO_OUTPUT_FLAG_DIRECT) &&
+ !(desc->mFlags & (AudioSystem::output_flags)
+ AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
+ mMultiChannelSuspended++;
}
} else {
continue;
@@ -1916,26 +1941,27 @@ void AudioPolicyManager::checkAndSuspendOutputs() {
}
}
}
- ALOGV("Suspend : mPrimarySuspended %d, mFastSuspended %d",
- mPrimarySuspended, mFastSuspended);
+ ALOGV("Suspend count: primary %d, fast %d, multichannel %d",
+ mPrimarySuspended, mFastSuspended, mMultiChannelSuspended);
}
void AudioPolicyManager::checkAndRestoreOutputs() {
AudioOutputDescriptor *desc;
- char value[PROPERTY_VALUE_MAX] = {0};
- property_get("audio.offload.passthrough", value, NULL);
- if (!(atoi(value) || !strncmp("true", value, 4))) {
+
+ if (!isHDMIPassthroughEnabled()) {
ALOGV("checkAndRestoreOutputs: passthrough not enabled");
return;
}
+
for (size_t i = 0; i < mOutputs.size(); i++) {
desc = mOutputs.valueAt(i);
ALOGV("checkAndRestoreOutputs: device 0x%x, flag %x, music refcount %d",
desc->mDevice, desc->mFlags, desc->mRefCount[AudioSystem::MUSIC]);
if (desc->mDevice & AUDIO_DEVICE_OUT_AUX_DIGITAL ||
desc->mDevice == AUDIO_DEVICE_NONE) {
- // check if the outputs were suspended before restore
+ // check if the deep buffer/fast/multichannel outputs were
+ // suspended before restore.
if (((desc->mFlags &
(AudioSystem::output_flags)AUDIO_OUTPUT_FLAG_FAST) &&
mFastSuspended) ||
@@ -1944,11 +1970,17 @@ void AudioPolicyManager::checkAndRestoreOutputs() {
mPrimarySuspended) ||
((desc->mFlags &
(AudioSystem::output_flags)AUDIO_OUTPUT_FLAG_PRIMARY) &&
- mPrimarySuspended)) {
+ mPrimarySuspended) ||
+ ((desc->mFlags & (AudioSystem::output_flags)
+ AUDIO_OUTPUT_FLAG_DIRECT) &&
+ !(desc->mFlags & (AudioSystem::output_flags)
+ AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
+ mMultiChannelSuspended)) {
ALOGD("restore Output");
mpClientInterface->restoreOutput(mOutputs.keyAt(i));
- // update the reference count after restore
+ // update the reference count for fast/deep buffer/multichannel
+ // after restore.
if (desc->mFlags &
(AudioSystem::output_flags)AUDIO_OUTPUT_FLAG_DEEP_BUFFER ||
desc->mFlags &
@@ -1957,6 +1989,11 @@ void AudioPolicyManager::checkAndRestoreOutputs() {
} else if (desc->mFlags &
(AudioSystem::output_flags)AUDIO_OUTPUT_FLAG_FAST) {
mFastSuspended--;
+ } else if ((desc->mFlags & (AudioSystem::output_flags)
+ AUDIO_OUTPUT_FLAG_DIRECT) &&
+ !(desc->mFlags & (AudioSystem::output_flags)
+ AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
+ mMultiChannelSuspended--;
}
} else {
continue;
@@ -1964,8 +2001,8 @@ void AudioPolicyManager::checkAndRestoreOutputs() {
}
}
}
- ALOGV("Restore: mPrimarySuspended %d, mFastSuspended %d",
- mPrimarySuspended, mFastSuspended);
+ ALOGV("Restore count: primary %d, fast %d, multichannel %d",
+ mPrimarySuspended, mFastSuspended, mMultiChannelSuspended);
}
audio_devices_t AudioPolicyManager::handleHDMIPassthrough(audio_devices_t device,
@@ -1975,9 +2012,7 @@ audio_devices_t AudioPolicyManager::handleHDMIPassthrough(audio_devices_t device
routing_strategy strategy = (routing_strategy)audio_strategy;
AudioSystem::stream_type stream = (AudioSystem::stream_type)audio_stream;
- char value[PROPERTY_VALUE_MAX] = {0};
- property_get("audio.offload.passthrough", value, NULL);
- if (!(atoi(value) || !strncmp("true", value, 4))) {
+ if (!isHDMIPassthroughEnabled()) {
ALOGV("handleHDMIPassthrough: passthrough not enabled");
return device;
}
@@ -2058,20 +2093,19 @@ audio_io_handle_t AudioPolicyManager::getPassthroughOutput(
// The function should return error if it cannot find valid passthrough
// output. This is required if client sets passthrough flag directly.
bool shouldReturnError = false;
- char value[PROPERTY_VALUE_MAX] = {0};
- property_get("audio.offload.passthrough", value, NULL);
- if (!(atoi(value) || !strncmp("true", value, 4))) {
+ if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH)
+ shouldReturnError = true;
+
+ if (!isHDMIPassthroughEnabled()) {
ALOGV("getPassthroughOutput: passthrough not enabled");
goto noPassthrough;
}
- if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH)
- shouldReturnError = true;
-
// Passthrough used for dolby formats and if device is HDMI
- if ((format == AUDIO_FORMAT_EAC3 || format == AUDIO_FORMAT_AC3) &&
- (device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+ if ((format == AUDIO_FORMAT_EAC3 || format == AUDIO_FORMAT_AC3 ||
+ format == AUDIO_FORMAT_E_AC3_JOC) &&
+ (device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
//stream based effects enabled, ignore passthrough
if (isEffectEnabled()) {
@@ -2091,16 +2125,20 @@ audio_io_handle_t AudioPolicyManager::getPassthroughOutput(
AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) &&
(desc->mRefCount[AudioSystem::MUSIC] > 0))
goto no_passthrough;
- else*/ if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT ||
- desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
- desc->mDirectOpenCount > 0) {
- ALOGD("Ignore passthrough,offload session active");
- goto noPassthrough;
+ else*/
+ // Check is compress offload stream is active before allowing
+ // passthrough stream
+ if ((desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
+ (!desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH)
+ && desc->mDirectOpenCount > 0) {
+ ALOGD("Ignore passthrough,offload session active");
+ goto noPassthrough;
}
}
}
checkAndSuspendOutputs();
+ closeOffloadOutputs();
flags = (AudioSystem::output_flags)(flags|AUDIO_OUTPUT_FLAG_DIRECT|
AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH);
@@ -2214,10 +2252,8 @@ void AudioPolicyManager::updateAndCloseOutputs() {
bool passthroughActive = false;
AudioOutputDescriptor *desc;
- char value[PROPERTY_VALUE_MAX] = {0};
- property_get("audio.offload.passthrough", value, NULL);
- if (!(atoi(value) || !strncmp("true", value, 4))) {
+ if (!isHDMIPassthroughEnabled()) {
ALOGV("updateAndCloseOutputs: passthrough not enabled");
return;
}
@@ -2239,14 +2275,50 @@ void AudioPolicyManager::updateAndCloseOutputs() {
if (passthroughActive) {
// Move tracks associated to this strategy from previous
// output to new output
- for (int i = AudioSystem::SYSTEM;
- i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
- ALOGV("\n Invalidate on call mode for stream :: %d \n", i);
- mpClientInterface->setStreamOutput((AudioSystem::stream_type)i,
- 0 /* ignored */);
+ ALOGV("\n Invalidate stream\n");
+ mpClientInterface->setStreamOutput(AudioSystem::MUSIC, 0/* ignored */);
+ }
+}
+
+void AudioPolicyManager::closeOffloadOutputs() {
+
+ bool passthroughActive = false;
+ AudioOutputDescriptor *desc;
+
+ if (!isHDMIPassthroughEnabled())
+ return;
+ ALOGV("closeOffloadOutputs");
+ // Invalidate and close offload output before starting a pasthrough output.
+ // This allows compressed stream to be restarted from correct position.
+ // If compressed output is not closed, passthrough session is stopped on
+ // de-routing offload session when offload session runs into standy after
+ // 1 minute standby time.
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ desc = mOutputs.valueAt(i);
+ ALOGV("closeOffloadOutputs:desc->mFlags %x, refCount %d",
+ desc->mFlags, desc->mRefCount[AudioSystem::MUSIC]);
+ if (((desc->mFlags &
+ (AudioSystem::output_flags)AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
+ (!(desc->mFlags &
+ (AudioSystem::output_flags)AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH))
+ ) && desc->mRefCount[AudioSystem::MUSIC] == 0) {
+ mpClientInterface->setStreamOutput(AudioSystem::MUSIC, 0);
+ closeOutput(desc->mId);
}
}
}
+bool AudioPolicyManager::isHDMIPassthroughEnabled() {
+
+ char value[PROPERTY_VALUE_MAX] = {0};
+
+ property_get("audio.offload.passthrough", value, NULL);
+ if (atoi(value) || !strncmp("true", value, 4)) {
+ ALOGD("HDMI Passthrough is enabled");
+ return true;
+ }
+ ALOGV("HDMI Passthrough is not enabled");
+ return false;
+}
#endif
bool AudioPolicyManager::isExternalModem()
diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h
index 12ac751a..aaafe96d 100644
--- a/policy_hal/AudioPolicyManager.h
+++ b/policy_hal/AudioPolicyManager.h
@@ -36,7 +36,8 @@ class AudioPolicyManager: public AudioPolicyManagerBase
public:
AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
: AudioPolicyManagerBase(clientInterface) {
- mPrimarySuspended = 0; mFastSuspended = 0;}
+ mPrimarySuspended = 0; mFastSuspended = 0;
+ mMultiChannelSuspended = 0;}
virtual ~AudioPolicyManager() {}
@@ -131,10 +132,13 @@ protected:
const audio_offload_info_t *offloadInfo,
audio_devices_t device);
bool isEffectEnabled();
+ void closeOffloadOutputs();
void updateAndCloseOutputs();
+ bool isHDMIPassthroughEnabled();
#endif
uint32_t mPrimarySuspended;
uint32_t mFastSuspended;
+ uint32_t mMultiChannelSuspended;
int mOldPhoneState;
bool isExternalModem();