Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d620d114 authored by Eric Laurent's avatar Eric Laurent Committed by Automerger Merge Worker
Browse files

audio hal: fix audio leak when disconnecting A2DP sink am: f030fe8a

Change-Id: If33d51fd24872d153f3b0f2d4417ebe2be4e9b37
parents 9ebc9fcb f030fe8a
Loading
Loading
Loading
Loading
+107 −13
Original line number Diff line number Diff line
@@ -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)
+2 −0
Original line number Diff line number Diff line
@@ -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;