hal: Add support for dynamic qos voting
Add support for adding/removing qos vote
dynamically. Framework will call the
setparams based on whether audio has
finished rendering or not. Support
this feature only for low latency track
based on a property.
CRs-Fixed: 2089196
Change-Id: Ia1f7ae584ab717742e4643fab50f6d404dfce66e
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index ace2a71..996a9a1 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -3158,6 +3158,37 @@
pthread_mutex_unlock(&out->lock);
}
+ //suspend, resume handling block
+ if (out->dynamic_pm_qos_enabled) {
+ //check suspend parameter only for low latency and if the property
+ //is enabled
+ if (str_parms_get_str(parms, "suspend_playback", value, sizeof(value)) >= 0) {
+ ALOGI("%s: got suspend_playback %s", __func__, value);
+ lock_output_stream(out);
+ if (!strncmp(value, "false", 5)) {
+ //suspend_playback=false is supposed to set QOS value back to 75%
+ //the mixer control sent with value Enable will achieve that
+ ret = audio_route_apply_and_update_path(adev->audio_route, out->pm_qos_mixer_path);
+ } else if (!strncmp (value, "true", 4)) {
+ //suspend_playback=true is supposed to remove QOS value
+ //resetting the mixer control will set the default value
+ //for the mixer control which is Disable and this removes the QOS vote
+ ret = audio_route_reset_and_update_path(adev->audio_route, out->pm_qos_mixer_path);
+ } else {
+ ALOGE("%s: Wrong value sent for suspend_playback, expected true/false,"
+ " got %s", __func__, value);
+ ret = -1;
+ }
+
+ if (ret != 0) {
+ ALOGE("%s: %s mixer ctl failed with %d, ignore suspend/resume setparams",
+ __func__, out->pm_qos_mixer_path, ret);
+ }
+
+ pthread_mutex_unlock(&out->lock);
+ }
+ }
+ //end suspend, resume handling block
str_parms_destroy(parms);
error:
ALOGV("%s: exit: code(%d)", __func__, ret);
@@ -3277,6 +3308,16 @@
str = str_parms_to_str(reply);
}
+ if (str_parms_get_str(query, "supports_hw_suspend", value, sizeof(value)) >= 0) {
+ //only low latency track supports suspend_resume
+ str_parms_add_int(reply, "supports_hw_suspend",
+ (out->dynamic_pm_qos_enabled));
+ if (str)
+ free(str);
+ str = str_parms_to_str(reply);
+ }
+
+
str_parms_destroy(query);
str_parms_destroy(reply);
ALOGV("%s: exit: returns - %s", __func__, str);
@@ -4394,6 +4435,7 @@
out->convert_buffer = NULL;
out->started = 0;
out->a2dp_compress_mute = false;
+ out->dynamic_pm_qos_enabled = 0;
if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL &&
(flags & AUDIO_OUTPUT_FLAG_DIRECT)) {
@@ -4737,6 +4779,18 @@
out->config = out->realtime ? pcm_config_rt : pcm_config_low_latency;
} else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
+ out->dynamic_pm_qos_enabled = property_get_bool("vendor.audio.dynamic.qos.enable", false);
+ if (!out->dynamic_pm_qos_enabled) {
+ ALOGI("%s: dynamic qos voting not enabled for platform", __func__);
+ } else {
+ ALOGI("%s: dynamic qos voting enabled for platform", __func__);
+ //the mixer path will be a string similar to "low-latency-playback resume"
+ strlcpy(out->pm_qos_mixer_path, use_case_table[out->usecase], MAX_MIXER_PATH_LEN);
+ strlcat(out->pm_qos_mixer_path,
+ " resume", MAX_MIXER_PATH_LEN);
+ ALOGI("%s: created %s pm_qos_mixer_path" , __func__,
+ out->pm_qos_mixer_path);
+ }
out->config = pcm_config_low_latency;
} else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 561a967..71de46a 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -91,6 +91,8 @@
#define MAX_STREAM_PROFILE_STR_LEN 32
+#define MAX_MIXER_PATH_LEN 64
+
typedef enum card_status_t {
CARD_STATUS_OFFLINE,
CARD_STATUS_ONLINE
@@ -305,6 +307,9 @@
bool a2dp_compress_mute;
float volume_l;
float volume_r;
+
+ char pm_qos_mixer_path[MAX_MIXER_PATH_LEN];
+ int dynamic_pm_qos_enabled;
};
struct stream_in {