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

Commit 45fee28d authored by Bhalchandra Gajare's avatar Bhalchandra Gajare Committed by Banajit Goswami
Browse files

hal: Fix sidetone sequence during voice call

When sidetone is enabled during voice call, the RX and TX path mixer
controls are issued back to back, this causes the codec path to be
enabled from TX to RX as the internal loopback for sidetone exists. Due
to enabling this path, pop noise is observed on headphones. This issue
is fixed by treating sidetone as special case and changing the enable
and disable sequence of sidetone mixer controls.

CRs-fixed: 839663
Change-Id: I7aea55af963cf939286e5b349ff25fd783314679
parent 84137880
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -912,6 +912,9 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
        (usecase->in_snd_device != SND_DEVICE_NONE) &&
        (usecase->out_snd_device != SND_DEVICE_NONE)) {
        status = platform_switch_voice_call_device_pre(adev->platform);
        /* Disable sidetone only if voice call already exists */
        if (voice_is_call_state_active(adev))
            voice_set_sidetone(adev, usecase->out_snd_device, false);
    }

    /* Disable current sound devices */
@@ -954,6 +957,9 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
                                                        out_snd_device,
                                                        in_snd_device);
        enable_audio_route_for_voice_usecases(adev, usecase);
        /* Enable sidetone only if voice call already exists */
        if (voice_is_call_state_active(adev))
            voice_set_sidetone(adev, out_snd_device, true);
    }

    usecase->in_snd_device = in_snd_device;
+81 −19
Original line number Diff line number Diff line
/*
 * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
 * Not a contribution.
 *
 * Copyright (C) 2013 The Android Open Source Project
@@ -55,6 +55,59 @@ static struct voice_session *voice_get_session_from_use_case(struct audio_device
    return session;
}

static bool voice_is_sidetone_device(snd_device_t out_device,
            char *mixer_path)
{
    bool is_sidetone_dev;

    switch (out_device) {
    case SND_DEVICE_OUT_VOICE_HANDSET:
        is_sidetone_dev = true;
        strlcpy(mixer_path, "sidetone-handset", MIXER_PATH_MAX_LENGTH);
        break;
    case SND_DEVICE_OUT_VOICE_HEADPHONES:
    case SND_DEVICE_OUT_VOICE_ANC_HEADSET:
    case SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET:
        is_sidetone_dev = true;
        strlcpy(mixer_path, "sidetone-headphones", MIXER_PATH_MAX_LENGTH);
        break;
    default:
        is_sidetone_dev = false;
        break;
    }

    return is_sidetone_dev;
}

void voice_set_sidetone(struct audio_device *adev,
        snd_device_t out_snd_device, bool enable)
{
    char mixer_path[MIXER_PATH_MAX_LENGTH];
    bool is_sidetone_dev;

    ALOGD("%s: %s, out_snd_device: %d\n",
          __func__, (enable ? "enable" : "disable"),
          out_snd_device);

    is_sidetone_dev = voice_is_sidetone_device(out_snd_device, mixer_path);

    if (!is_sidetone_dev) {
        ALOGD("%s: device %d does not support sidetone\n",
              __func__, out_snd_device);
        return;
    }

    ALOGD("%s: sidetone out device = %s\n",
          __func__, mixer_path);

    if (enable)
        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
    else
        audio_route_reset_and_update_path(adev->audio_route, mixer_path);

    return;
}

int voice_stop_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
{
    int i, ret = 0;
@@ -69,10 +122,21 @@ int voice_stop_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
        return -EINVAL;
    }

    uc_info = get_usecase_from_list(adev, usecase_id);
    if (uc_info == NULL) {
        ALOGE("%s: Could not find the usecase (%d) in the list",
              __func__, usecase_id);
        return -EINVAL;
    }

    session->state.current = CALL_INACTIVE;
    if (adev->mode == AUDIO_MODE_NORMAL)
        adev->voice.is_in_call = false;

    /* Disable sidetone only when no calls are active */
    if (!voice_is_call_state_active(adev))
        voice_set_sidetone(adev, uc_info->out_snd_device, false);

    ret = platform_stop_voice_call(adev->platform, session->vsid);

    /* 1. Close the PCM devices */
@@ -85,13 +149,6 @@ int voice_stop_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
        session->pcm_tx = NULL;
    }

    uc_info = get_usecase_from_list(adev, usecase_id);
    if (uc_info == NULL) {
        ALOGE("%s: Could not find the usecase (%d) in the list",
              __func__, usecase_id);
        return -EINVAL;
    }

    /* 2. Get and set stream specific mixer controls */
    disable_audio_route(adev, uc_info);

@@ -159,6 +216,17 @@ int voice_start_usecase(struct audio_device *adev, audio_usecase_t usecase_id)

    voice_set_mic_mute(adev, adev->voice.mic_mute);

    ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
          __func__, adev->snd_card, pcm_dev_tx_id);
    session->pcm_tx = pcm_open(adev->snd_card,
                               pcm_dev_tx_id,
                               PCM_IN, &voice_config);
    if (session->pcm_tx && !pcm_is_ready(session->pcm_tx)) {
        ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_tx));
        ret = -EIO;
        goto error_start_voice;
    }

    ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
          __func__, adev->snd_card, pcm_dev_rx_id);
    session->pcm_rx = pcm_open(adev->snd_card,
@@ -170,18 +238,12 @@ int voice_start_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
        goto error_start_voice;
    }

    ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
          __func__, adev->snd_card, pcm_dev_tx_id);
    session->pcm_tx = pcm_open(adev->snd_card,
                               pcm_dev_tx_id,
                               PCM_IN, &voice_config);
    if (session->pcm_tx && !pcm_is_ready(session->pcm_tx)) {
        ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_tx));
        ret = -EIO;
        goto error_start_voice;
    }
    pcm_start(session->pcm_rx);
    pcm_start(session->pcm_tx);
    pcm_start(session->pcm_rx);

    /* Enable sidetone only when no calls are already active */
    if (!voice_is_call_state_active(adev))
        voice_set_sidetone(adev, uc_info->out_snd_device, true);

    voice_set_volume(adev, adev->voice.volume);

+4 −0
Original line number Diff line number Diff line
@@ -95,4 +95,8 @@ int voice_check_and_stop_incall_rec_usecase(struct audio_device *adev,
                                            struct stream_in *in);
void voice_update_devices_for_all_voice_usecases(struct audio_device *adev);
snd_device_t voice_get_incall_rec_snd_device(snd_device_t in_snd_device);
void voice_set_sidetone(struct audio_device *adev,
                       snd_device_t out_snd_device,
                       bool enable);
bool voice_is_call_state_active(struct audio_device *adev);
#endif //VOICE_H