summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2020-05-28 15:51:56 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-05-28 15:51:56 +0000
commit87d923e750e0d0fb62ad06020966dd4e34bce26e (patch)
treee149fb9a335549bb75211c7acdfd99122ddb184a
parente7343b9c1df86004821093bb1a701e0dfcaba0f6 (diff)
parentd620d11473d532f678773dae6728aee8e028f27e (diff)
downloadaudio-87d923e750e0d0fb62ad06020966dd4e34bce26e.tar.gz
audio hal: fix audio leak when disconnecting A2DP sink am: f030fe8ae0 am: d620d11473
Change-Id: Ib575f49851113f06eadb15630f8ae43102f94ed0
-rw-r--r--hal/audio_hw.c120
-rw-r--r--hal/audio_hw.h2
2 files changed, 109 insertions, 13 deletions
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 035b14e..0f868ca 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -72,6 +72,8 @@
/* treat as unsigned Q1.13 */
#define APP_TYPE_GAIN_DEFAULT 0x2000
#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
+#define PCM_PLAYBACK_VOLUME_MAX 0x2000
+#define INVALID_OUT_VOLUME -1
/* treat as unsigned Q1.13 */
#define VOIP_PLAYBACK_VOLUME_MAX 0x2000
@@ -359,7 +361,8 @@ static unsigned int audio_device_ref_count;
static int last_known_cal_step = -1 ;
static int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *out, bool restore);
-static int set_compr_volume(struct audio_stream_out *stream, float left, float right);
+static int out_set_compr_volume(struct audio_stream_out *stream, float left, float right);
+static int out_set_pcm_volume(struct audio_stream_out *stream, float left, float right);
static int in_set_microphone_direction(const struct audio_stream_in *stream,
audio_microphone_direction_t dir);
@@ -2602,6 +2605,11 @@ int start_output_stream(struct stream_out *out)
goto error_open;
}
}
+ if ((out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY
+ || out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER
+ || out->usecase == USECASE_AUDIO_PLAYBACK_ULL)) {
+ out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
+ }
}
register_out_stream(out);
@@ -2969,6 +2977,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
bool select_new_device = false;
int status = 0;
bool bypass_a2dp = false;
+ bool forced_speaker_fallback = false;
ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s",
__func__, out->usecase, use_case_table[out->usecase], kvpairs);
@@ -2990,6 +2999,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
out_standby_l(&out->stream.common);
}
val = AUDIO_DEVICE_OUT_SPEAKER;
+ forced_speaker_fallback = true;
}
pthread_mutex_lock(&adev->lock);
@@ -3004,6 +3014,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
if (out->devices == AUDIO_DEVICE_OUT_AUX_DIGITAL &&
val == AUDIO_DEVICE_NONE) {
val = AUDIO_DEVICE_OUT_SPEAKER;
+ forced_speaker_fallback = true;
}
/*
@@ -3018,6 +3029,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
!audio_extn_a2dp_is_ready() &&
!adev->bt_sco_on) {
val = AUDIO_DEVICE_OUT_SPEAKER;
+ forced_speaker_fallback = true;
}
/* To avoid a2dp to sco overlapping / BT device improper state
@@ -3094,6 +3106,42 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
}
if (!out->standby) {
+ int volume_delay_us = 0;
+ if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ pthread_mutex_lock(&out->compr_mute_lock);
+ if (out->a2dp_compress_mute &&
+ (!(new_dev & AUDIO_DEVICE_OUT_ALL_A2DP) ||
+ audio_extn_a2dp_is_ready())) {
+ out->a2dp_compress_mute = false;
+ }
+ float volume_l = out->volume_l;
+ float volume_r = out->volume_r;
+ if (out->a2dp_compress_mute || forced_speaker_fallback) {
+ volume_l = 0.0;
+ volume_r = 0.0;
+ }
+ if (volume_l != out->applied_volume_l || volume_r != out->applied_volume_r)
+ volume_delay_us = COMPRESS_OFFLOAD_PLAYBACK_LATENCY * 2000;
+
+ out_set_compr_volume(&out->stream, volume_l, volume_r);
+ pthread_mutex_unlock(&out->compr_mute_lock);
+ } else if (out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY ||
+ out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
+ out->usecase == USECASE_AUDIO_PLAYBACK_ULL) {
+ float volume_l = out->volume_l;
+ float volume_r = out->volume_r;
+ if (forced_speaker_fallback) {
+ volume_l = 0.0;
+ volume_r = 0.0;
+ }
+ if (volume_l != out->applied_volume_l || volume_r != out->applied_volume_r)
+ volume_delay_us = (int)platform_render_latency(out) * 2;
+
+ out_set_pcm_volume(&out->stream, volume_l, volume_r);
+ }
+ if (volume_delay_us > 0)
+ usleep(volume_delay_us * 2);
+
if (!same_dev) {
ALOGV("update routing change");
// inform adm before actual routing to prevent glitches.
@@ -3120,14 +3168,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
if (!same_dev)
platform_set_swap_channels(adev, true);
- if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
- out->a2dp_compress_mute &&
- (!(out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) || audio_extn_a2dp_is_ready())) {
- pthread_mutex_lock(&out->compr_mute_lock);
- out->a2dp_compress_mute = false;
- set_compr_volume(&out->stream, out->volume_l, out->volume_r);
- pthread_mutex_unlock(&out->compr_mute_lock);
- }
+
}
}
@@ -3299,7 +3340,7 @@ static uint32_t out_get_latency(const struct audio_stream_out *stream)
return latency;
}
-static int set_compr_volume(struct audio_stream_out *stream, float left,
+static int out_set_compr_volume(struct audio_stream_out *stream, float left,
float right)
{
struct stream_out *out = (struct stream_out *)stream;
@@ -3310,6 +3351,9 @@ static int set_compr_volume(struct audio_stream_out *stream, float left,
int pcm_device_id = platform_get_pcm_device_id(out->usecase,
PCM_PLAYBACK);
+ if (left == out->applied_volume_l && right == out->applied_volume_r)
+ return 0;
+
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);
@@ -3324,9 +3368,49 @@ static int set_compr_volume(struct audio_stream_out *stream, float left,
volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
mixer_ctl_set_array(ctl, volume, sizeof(volume) / sizeof(volume[0]));
+ out->applied_volume_l = left;
+ out->applied_volume_r = right;
return 0;
}
+static int out_set_pcm_volume(struct audio_stream_out *stream, float left,
+ float right)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+
+ if (left == out->applied_volume_l && right == out->applied_volume_r)
+ return 0;
+
+ /* Volume control for pcm playback */
+ if (left != right) {
+ return -EINVAL;
+ } 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), "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;
+ }
+
+ int volume = (int) (left * PCM_PLAYBACK_VOLUME_MAX);
+ int ret = mixer_ctl_set_value(ctl, 0, volume);
+ if (ret < 0) {
+ ALOGE("%s: Could not set ctl, error:%d ", __func__, ret);
+ return -EINVAL;
+ }
+
+ ALOGV("%s : Pcm set volume value %d left %f", __func__, volume, left);
+
+ out->applied_volume_l = left;
+ out->applied_volume_r = right;
+ return 0;
+ }
+}
+
static int out_set_volume(struct audio_stream_out *stream, float left,
float right)
{
@@ -3341,7 +3425,7 @@ static int out_set_volume(struct audio_stream_out *stream, float left,
pthread_mutex_lock(&out->compr_mute_lock);
ALOGV("%s: compress mute %d", __func__, out->a2dp_compress_mute);
if (!out->a2dp_compress_mute)
- ret = set_compr_volume(stream, left, right);
+ ret = out_set_compr_volume(stream, left, right);
out->volume_l = left;
out->volume_r = right;
pthread_mutex_unlock(&out->compr_mute_lock);
@@ -5293,6 +5377,13 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
}
}
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY ||
+ out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
+ out->usecase == USECASE_AUDIO_PLAYBACK_ULL) {
+ out->volume_l = 1.0;
+ out->volume_r = 1.0;
+ }
+
if (config->sample_rate == 0) {
out->sample_rate = out->config.rate;
} else {
@@ -5375,6 +5466,9 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
}
pthread_mutex_unlock(&adev->lock);
+ out->applied_volume_l = INVALID_OUT_VOLUME;
+ out->applied_volume_r = INVALID_OUT_VOLUME;
+
out->stream.common.get_sample_rate = out_get_sample_rate;
out->stream.common.set_sample_rate = out_set_sample_rate;
out->stream.common.get_buffer_size = out_get_buffer_size;
@@ -6387,7 +6481,7 @@ static int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *ou
if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
(out->a2dp_compress_mute)) {
out->a2dp_compress_mute = false;
- set_compr_volume(&out->stream, out->volume_l, out->volume_r);
+ out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
}
pthread_mutex_unlock(&out->compr_mute_lock);
}
@@ -6404,7 +6498,7 @@ static int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *ou
right_p = out->volume_r;
if (out->offload_state == OFFLOAD_STATE_PLAYING)
compress_pause(out->compr);
- set_compr_volume(&out->stream, 0.0f, 0.0f);
+ out_set_compr_volume(&out->stream, 0.0f, 0.0f);
out->a2dp_compress_mute = true;
select_devices(adev, out->usecase);
if (out->offload_state == OFFLOAD_STATE_PLAYING)
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 15cfa60..e980e88 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -256,6 +256,8 @@ struct stream_out {
bool a2dp_compress_mute;
float volume_l;
float volume_r;
+ float applied_volume_l;
+ float applied_volume_r;
error_log_t *error_log;