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

Commit baddf9f2 authored by Zhou Song's avatar Zhou Song
Browse files

hal: mute stream and switch to speaker during a2dp suspend

During A2DP to SCO transition, in order to avoid audible
PCM data pumping to BT SoC during suspend, mute stream
from DSP and switch to speaker to tear down slimbus to
avoid glitches heard after SCO connection is established.

Change-Id: Iabe2216e574b462cfc179369e75007998a576480
parent b1976118
Loading
Loading
Loading
Loading

hal/audio_hw.c

100755 → 100644
+70 −65
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@
#define INVALID_OUT_VOLUME -1
#define AUDIO_IO_PORTS_MAX 32

#define PLAYBACK_GAIN_MAX 1.0f
#define RECORD_GAIN_MIN 0.0f
#define RECORD_GAIN_MAX 1.0f
#define RECORD_VOLUME_CTL_MAX 0x2000
@@ -1286,16 +1287,11 @@ int enable_audio_route(struct audio_device *adev,
    if (audio_extn_is_maxx_audio_enabled())
        audio_extn_ma_set_device(usecase);
    audio_extn_utils_send_audio_calibration(adev, usecase);
    if ((usecase->type == PCM_PLAYBACK) &&
            ((out = usecase->stream.out) != NULL)) {
        if (!is_offload_usecase(out->usecase)) {
            pthread_mutex_lock(&out->latch_lock);
            out->muted = false;
            pthread_mutex_unlock(&out->latch_lock);
        } else if (out->compr) {
    if ((usecase->type == PCM_PLAYBACK) && is_offload_usecase(usecase->id)) {
        out = usecase->stream.out;
        if (out && out->compr)
            audio_extn_utils_compress_set_clk_rec_mode(usecase);
    }
    }

    if (usecase->type == PCM_CAPTURE) {
        in = usecase->stream.in;
@@ -3721,6 +3717,8 @@ static int stop_output_stream(struct stream_out *out)
        return -EINVAL;
    }

    out->a2dp_muted = false;

    if (audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
        ALOGE("%s: failed to stop ext hw plugin", __func__);

@@ -3771,9 +3769,6 @@ static int stop_output_stream(struct stream_out *out)

    list_remove(&uc_info->list);
    out->started = 0;
    pthread_mutex_lock(&out->latch_lock);
    out->muted = false;
    pthread_mutex_unlock(&out->latch_lock);
    if (is_offload_usecase(out->usecase) &&
        (audio_extn_passthru_is_passthrough_stream(out))) {
        ALOGV("Disable passthrough , reset mixer to pcm");
@@ -5063,17 +5058,19 @@ int route_output_stream(struct stream_out *out,
                platform_set_swap_channels(adev, true);
                audio_extn_perf_lock_release(&adev->perf_lock_handle);
            }
            if (is_offload_usecase(out->usecase) &&
                 (!is_a2dp_out_device_type(&out->device_list) || audio_extn_a2dp_source_is_ready())) {
            pthread_mutex_lock(&out->latch_lock);
                if (out->a2dp_compress_mute) {
                    out->a2dp_compress_mute = false;
            if (!is_a2dp_out_device_type(&out->device_list) || audio_extn_a2dp_source_is_ready()) {
                if (out->a2dp_muted) {
                    out->a2dp_muted = false;
                    if (is_offload_usecase(out->usecase))
                        out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
                    else if (out->usecase != USECASE_AUDIO_PLAYBACK_VOIP)
                        out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
                }
                pthread_mutex_unlock(&out->latch_lock);
            } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
                out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
            }
            if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP && !out->a2dp_muted)
                out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
            pthread_mutex_unlock(&out->latch_lock);
        }
    }

@@ -5625,9 +5622,7 @@ static int out_set_volume(struct audio_stream_out *stream, float left,
    ALOGD("%s: called with left_vol=%f, right_vol=%f", __func__, left, right);
    if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
        /* only take left channel into account: the API is for stereo anyway */
        pthread_mutex_lock(&out->latch_lock);
        out->muted = (left == 0.0f);
        pthread_mutex_unlock(&out->latch_lock);
        return 0;
    } else if (is_offload_usecase(out->usecase)) {
        if (audio_extn_passthru_is_passthrough_stream(out)) {
@@ -5665,15 +5660,15 @@ static int out_set_volume(struct audio_stream_out *stream, float left,
                }
            }
            pthread_mutex_lock(&out->latch_lock);
            if (!out->a2dp_compress_mute) {
            if (!out->a2dp_muted) {
                ret = out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
            }
            pthread_mutex_unlock(&out->latch_lock);
            return ret;
        } else {
            pthread_mutex_lock(&out->latch_lock);
            ALOGV("%s: compress mute %d", __func__, out->a2dp_compress_mute);
            if (!out->a2dp_compress_mute)
            ALOGV("%s: compress mute %d", __func__, out->a2dp_muted);
            if (!out->a2dp_muted)
                ret = out_set_compr_volume(stream, left, right);
            out->volume_l = left;
            out->volume_r = right;
@@ -5683,14 +5678,17 @@ static int out_set_volume(struct audio_stream_out *stream, float left,
    } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
        out->app_type_cfg.gain[0] = (int)(left * VOIP_PLAYBACK_VOLUME_MAX);
        out->app_type_cfg.gain[1] = (int)(right * VOIP_PLAYBACK_VOLUME_MAX);
        pthread_mutex_lock(&out->latch_lock);
        if (!out->standby) {
            audio_extn_utils_send_app_type_gain(out->dev,
                                                out->app_type_cfg.app_type,
                                                &out->app_type_cfg.gain[0]);
            if (!out->a2dp_muted)
                ret = out_set_voip_volume(stream, left, right);
        }
        out->volume_l = left;
        out->volume_r = right;
        pthread_mutex_unlock(&out->latch_lock);
        return ret;
    } else if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
        ALOGV("%s: MMAP set volume called", __func__);
@@ -5702,21 +5700,25 @@ static int out_set_volume(struct audio_stream_out *stream, float left,
    } else if (out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY ||
               out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
               out->usecase == USECASE_AUDIO_PLAYBACK_ULL) {
        pthread_mutex_lock(&out->latch_lock);
        /* Volume control for pcm playback */
        if (!out->standby)
        if (!out->standby && !out->a2dp_muted)
            ret = out_set_pcm_volume(stream, left, right);
        else
            out->apply_volume = true;

        out->volume_l = left;
        out->volume_r = right;
        pthread_mutex_unlock(&out->latch_lock);
        return ret;
    } else if (audio_extn_auto_hal_is_bus_device_usecase(out->usecase)) {
        ALOGV("%s: bus device set volume called", __func__);
        if (!out->standby)
        pthread_mutex_lock(&out->latch_lock);
        if (!out->standby && !out->a2dp_muted)
            ret = out_set_pcm_volume(stream, left, right);
        out->volume_l = left;
        out->volume_r = right;
        pthread_mutex_unlock(&out->latch_lock);
        return ret;
    }

@@ -6102,10 +6104,8 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
    } else {
        if (out->pcm) {
            size_t bytes_to_write = bytes;
            pthread_mutex_lock(&out->latch_lock);
            if (out->muted)
                memset((void *)buffer, 0, bytes);
            pthread_mutex_unlock(&out->latch_lock);
            ALOGV("%s: frames=%zu, frame_size=%zu, bytes_to_write=%zu",
                     __func__, frames, frame_size, bytes_to_write);

@@ -7857,7 +7857,7 @@ int adev_open_output_stream(struct audio_hw_device *dev,
    out->non_blocking = 0;
    out->convert_buffer = NULL;
    out->started = 0;
    out->a2dp_compress_mute = false;
    out->a2dp_muted = false;
    out->hal_output_suspend_supported = 0;
    out->dynamic_pm_qos_config_supported = 0;
    out->set_dual_mono = false;
@@ -8588,6 +8588,8 @@ int adev_open_output_stream(struct audio_hw_device *dev,
    out->kernel_buffer_size = out->config.period_size * out->config.period_count;

    out->standby = 1;
    out->volume_l = PLAYBACK_GAIN_MAX;
    out->volume_r = PLAYBACK_GAIN_MAX;
    /* out->muted = false; by calloc() */
    /* out->written = 0; by calloc() */

@@ -8728,7 +8730,7 @@ void adev_close_output_stream(struct audio_hw_device *dev __unused,
            free(out->compr_config.codec);
    }

    out->a2dp_compress_mute = false;
    out->a2dp_muted = false;

    if (is_interactive_usecase(out->usecase))
        free_interactive_usecase(adev, out->usecase);
@@ -8981,17 +8983,12 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
                //force device switch to re configure encoder
                select_devices(adev, usecase->id);
                ALOGD("Unmuting the stream after select_devices");
                pthread_mutex_lock(&usecase->stream.out->latch_lock);
                usecase->stream.out->a2dp_compress_mute = false;
                out_set_compr_volume(&usecase->stream.out->stream,
                                     usecase->stream.out->volume_l,
                                     usecase->stream.out->volume_r);
                pthread_mutex_unlock(&usecase->stream.out->latch_lock);
                check_a2dp_restore_l(adev, usecase->stream.out, true);
                audio_extn_a2dp_set_handoff_mode(false);
                break;
            } else if (is_offload_usecase(usecase->stream.out->usecase)) {
                pthread_mutex_lock(&usecase->stream.out->latch_lock);
                if (usecase->stream.out->a2dp_compress_mute) {
                if (usecase->stream.out->a2dp_muted) {
                    pthread_mutex_unlock(&usecase->stream.out->latch_lock);
                    reassign_device_list(&usecase->stream.out->device_list,
                                         AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "");
@@ -10471,8 +10468,8 @@ int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *out, bool
    }
    list_init(&devices);

    ALOGD("%s: enter: usecase(%d: %s)", __func__,
          out->usecase, use_case_table[out->usecase]);
    ALOGD("%s: enter: usecase(%d: %s), a2dp muted %d", __func__,
          out->usecase, use_case_table[out->usecase], out->a2dp_muted);

    if (restore) {
        pthread_mutex_lock(&out->latch_lock);
@@ -10481,43 +10478,51 @@ int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *out, bool
            ALOGD("%s: restoring A2dp and unmuting stream", __func__);
            if (uc_info->out_snd_device != SND_DEVICE_OUT_BT_A2DP)
                select_devices(adev, uc_info->id);
            if (is_offload_usecase(out->usecase) &&
                (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP)) {
                if (out->a2dp_compress_mute) {
                    out->a2dp_compress_mute = false;

            if (is_offload_usecase(out->usecase)) {
                if (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP)
                    out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
            } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
                out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
            } else {
                out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
            }
            out->a2dp_muted = false;
        }
        }
        out->muted = false;
        pthread_mutex_unlock(&out->latch_lock);
    } else {
        pthread_mutex_lock(&out->latch_lock);
        if (is_offload_usecase(out->usecase)) {
            // mute compress stream if suspended
            if (!out->a2dp_compress_mute && !out->standby) {
        // mute stream and switch to speaker if suspended
        if (!out->a2dp_muted && !out->standby) {
            ALOGD("%s: selecting speaker and muting stream", __func__);
            assign_devices(&devices, &out->device_list);
            reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
            left_p = out->volume_l;
            right_p = out->volume_r;
            out->a2dp_muted = true;
            if (is_offload_usecase(out->usecase)) {
                if (out->offload_state == OFFLOAD_STATE_PLAYING)
                    compress_pause(out->compr);
                out_set_compr_volume(&out->stream, (float)0, (float)0);
                out->a2dp_compress_mute = true;
            } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
                out_set_voip_volume(&out->stream, (float)0, (float)0);
            } else {
                out_set_pcm_volume(&out->stream, (float)0, (float)0);
                /* wait for stale pcm drained before switching to speaker */
                uint32_t latency =
                    (out->config.period_count * out->config.period_size * 1000) /
                    (out->config.rate);
                usleep(latency * 1000);
            }
            select_devices(adev, out->usecase);
            if (is_offload_usecase(out->usecase)) {
                if (out->offload_state == OFFLOAD_STATE_PLAYING)
                    compress_resume(out->compr);
            }
            assign_devices(&out->device_list, &devices);
            out->volume_l = left_p;
            out->volume_r = right_p;
        }
        } else {
            // mute for non offloaded streams
            if (audio_extn_a2dp_source_is_suspended()) {
                out->muted = true;
            }
        }
        pthread_mutex_unlock(&out->latch_lock);
    }
    ALOGV("%s: exit", __func__);
+1 −1
Original line number Diff line number Diff line
@@ -455,7 +455,7 @@ struct stream_out {
    qahwi_stream_out_t qahwi_out;

    bool is_iec61937_info_available;
    bool a2dp_compress_mute;
    bool a2dp_muted;
    float volume_l;
    float volume_r;
    bool apply_volume;