diff options
-rw-r--r-- | hal/audio_extn/audio_extn.h | 11 | ||||
-rw-r--r-- | hal/audio_extn/dolby.c | 133 | ||||
-rw-r--r-- | hal/audio_hw.c | 124 | ||||
-rw-r--r-- | hal/audio_hw.h | 3 | ||||
-rw-r--r-- | hal/edid.c | 14 | ||||
-rw-r--r-- | hal/msm8960/platform.c | 7 | ||||
-rw-r--r-- | hal/msm8974/platform.c | 206 | ||||
-rw-r--r-- | hal/msm8974/platform.h | 7 | ||||
-rw-r--r-- | hal/platform_api.h | 3 | ||||
-rw-r--r-- | hal/voice.c | 21 | ||||
-rw-r--r-- | hal/voice.h | 4 | ||||
-rw-r--r-- | hal/voice_extn/compress_voip.c | 9 | ||||
-rw-r--r-- | hal/voice_extn/voice_extn.c | 31 | ||||
-rw-r--r-- | hal/voice_extn/voice_extn.h | 6 | ||||
-rw-r--r-- | policy_hal/AudioPolicyManager.cpp | 164 | ||||
-rw-r--r-- | policy_hal/AudioPolicyManager.h | 6 |
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. @@ -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(); |