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

Commit b7ea4f58 authored by Ravi Kumar Alamanda's avatar Ravi Kumar Alamanda Committed by Eric Laurent
Browse files

hal: update combo device handling

If the wired headset/headphone/line devices are handled by
a different backend than speaker/earpiece devices, the combo
devices such as speaker+headphones can be split into individual
devices and enabled/disabled independently.

Bug: 21581860.

Change-Id: Icdd962a4dc1da536fe89c4de2202e7383275603d
parent ff864719
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -758,7 +758,8 @@ void audio_extn_spkr_prot_init(void *adev)
        property_get("ro.board.platform", platform, "");
        if (!strncmp("apq8084", platform, sizeof("apq8084"))) {
            platform_set_snd_device_backend(SND_DEVICE_OUT_VOICE_SPEAKER,
                                            "speaker-protected");
                                            "speaker-protected",
                                            "SLIMBUS_0_RX");
        }
    }
}
+22 −7
Original line number Diff line number Diff line
@@ -265,6 +265,9 @@ int disable_audio_route(struct audio_device *adev,
int enable_snd_device(struct audio_device *adev,
                      snd_device_t snd_device)
{
    int i, num_devices = 0;
    snd_device_t new_snd_devices[2];

    if (snd_device < SND_DEVICE_MIN ||
        snd_device >= SND_DEVICE_MAX) {
        ALOGE("%s: Invalid sound device %d", __func__, snd_device);
@@ -306,6 +309,10 @@ int enable_snd_device(struct audio_device *adev,
            ALOGE("%s: spkr_start_processing failed", __func__);
            return -EINVAL;
        }
    } else if (platform_can_split_snd_device(snd_device, &num_devices, new_snd_devices)) {
        for (i = 0; i < num_devices; i++) {
            enable_snd_device(adev, new_snd_devices[i]);
        }
    } else {
        const char * dev_path = platform_get_snd_device_name(snd_device);
        ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, dev_path);
@@ -318,6 +325,9 @@ int enable_snd_device(struct audio_device *adev,
int disable_snd_device(struct audio_device *adev,
                       snd_device_t snd_device)
{
    int i, num_devices = 0;
    snd_device_t new_snd_devices[2];

    if (snd_device < SND_DEVICE_MIN ||
        snd_device >= SND_DEVICE_MAX) {
        ALOGE("%s: Invalid sound device %d", __func__, snd_device);
@@ -337,6 +347,10 @@ int disable_snd_device(struct audio_device *adev,
            snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) &&
            audio_extn_spkr_prot_is_enabled()) {
            audio_extn_spkr_prot_stop_processing(snd_device);
        } else if (platform_can_split_snd_device(snd_device, &num_devices, new_snd_devices)) {
            for (i = 0; i < num_devices; i++) {
                disable_snd_device(adev, new_snd_devices[i]);
            }
        } else {
            audio_route_reset_and_update_path(adev->audio_route, dev_path);
        }
@@ -346,7 +360,7 @@ int disable_snd_device(struct audio_device *adev,
    return 0;
}

static void check_usecases_codec_backend(struct audio_device *adev,
static void check_and_route_playback_usecases(struct audio_device *adev,
                                              struct audio_usecase *uc_info,
                                              snd_device_t snd_device)
{
@@ -375,7 +389,8 @@ static void check_usecases_codec_backend(struct audio_device *adev,
        if (usecase->type != PCM_CAPTURE &&
                usecase != uc_info &&
                usecase->out_snd_device != snd_device &&
                usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
                usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND &&
                platform_check_backends_match(snd_device, usecase->out_snd_device)) {
            ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
                  __func__, use_case_table[usecase->id],
                  platform_get_snd_device_name(usecase->out_snd_device));
@@ -565,7 +580,7 @@ int select_devices(struct audio_device *adev,
         * so that it would not result any device switch. All the usecases will
         * be switched to new device when select_devices() is called for voice call
         * usecase. This is to avoid switching devices for voice call when
         * check_usecases_codec_backend() is called below.
         * check_and_route_playback_usecases() is called below.
         */
        if (voice_is_in_call(adev)) {
            vc_usecase = get_usecase_from_list(adev,
@@ -660,7 +675,7 @@ int select_devices(struct audio_device *adev,
    /* Enable new sound devices */
    if (out_snd_device != SND_DEVICE_NONE) {
        if (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)
            check_usecases_codec_backend(adev, usecase, out_snd_device);
            check_and_route_playback_usecases(adev, usecase, out_snd_device);
        enable_snd_device(adev, out_snd_device);
    }

@@ -1349,7 +1364,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)

        /*
         * select_devices() call below switches all the usecases on the same
         * backend to the new device. Refer to check_usecases_codec_backend() in
         * backend to the new device. Refer to check_and_route_playback_usecases() in
         * the select_devices(). But how do we undo this?
         *
         * For example, music playback is active on headset (deep-buffer usecase)
+21 −1
Original line number Diff line number Diff line
@@ -1002,7 +1002,8 @@ int platform_set_usecase_pcm_id(audio_usecase_t usecase __unused, int32_t type _
}

int platform_set_snd_device_backend(snd_device_t device __unused,
                                    const char *backend __unused)
                                    const char *backend __unused,
                                    const char *hw_interface __unused)
{
    return -ENOSYS;
}
@@ -1041,3 +1042,22 @@ int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels)
    }
    return status;
}

bool platform_send_gain_dep_cal(void *platform __unused,
                                int level __unused)
{
    return 0;
}

bool platform_can_split_snd_device(snd_device_t in_snd_device __unused,
                                   int *num_devices __unused,
                                   snd_device_t *out_snd_devices __unused)
{
    return false;
}

bool platform_check_backends_match(snd_device_t snd_device1 __unused,
                                   snd_device_t snd_device2 __unused)
{
    return true;
}
+132 −30
Original line number Diff line number Diff line
@@ -343,6 +343,7 @@ static const struct name_to_index snd_device_name_index[SND_DEVICE_MAX] = {
    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_STEREO)},

    {TO_NAME_INDEX(SND_DEVICE_IN_HEADSET_MIC)},
    {TO_NAME_INDEX(SND_DEVICE_IN_HEADSET_MIC_AEC)},

    {TO_NAME_INDEX(SND_DEVICE_IN_HDMI_MIC)},
    {TO_NAME_INDEX(SND_DEVICE_IN_BT_SCO_MIC)},
@@ -367,7 +368,8 @@ static const struct name_to_index snd_device_name_index[SND_DEVICE_MAX] = {
    {TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)},
};

static char * backend_table[SND_DEVICE_MAX] = {0};
static char * backend_tag_table[SND_DEVICE_MAX] = {0};
static char * hw_interface_table[SND_DEVICE_MAX] = {0};

static const struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = {
    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_DEEP_BUFFER)},
@@ -634,42 +636,67 @@ done:
#endif
}

static void set_platform_defaults(struct platform_data * my_data)
static void set_platform_defaults(struct platform_data * my_data __unused)
{
    int32_t dev;
    for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
        backend_table[dev] = NULL;
        backend_tag_table[dev] = NULL;
        hw_interface_table[dev] = NULL;
    }

    // TBD - do these go to the platform-info.xml file.
    // will help in avoiding strdups here
    backend_table[SND_DEVICE_IN_BT_SCO_MIC] = strdup("bt-sco");
    backend_table[SND_DEVICE_OUT_BT_SCO] = strdup("bt-sco");
    backend_table[SND_DEVICE_OUT_HDMI] = strdup("hdmi");
    backend_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = strdup("speaker-and-hdmi");
    backend_table[SND_DEVICE_OUT_BT_SCO_WB] = strdup("bt-sco-wb");
    backend_table[SND_DEVICE_IN_BT_SCO_MIC_WB] = strdup("bt-sco-wb");
    backend_table[SND_DEVICE_OUT_VOICE_TX] = strdup("afe-proxy");
    backend_table[SND_DEVICE_IN_VOICE_RX] = strdup("afe-proxy");
    // To overwrite these go to the audio_platform_info.xml file.
    backend_tag_table[SND_DEVICE_IN_BT_SCO_MIC] = strdup("bt-sco");
    backend_tag_table[SND_DEVICE_OUT_BT_SCO] = strdup("bt-sco");
    backend_tag_table[SND_DEVICE_OUT_HDMI] = strdup("hdmi");
    backend_tag_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = strdup("speaker-and-hdmi");
    backend_tag_table[SND_DEVICE_OUT_BT_SCO_WB] = strdup("bt-sco-wb");
    backend_tag_table[SND_DEVICE_IN_BT_SCO_MIC_WB] = strdup("bt-sco-wb");
    backend_tag_table[SND_DEVICE_OUT_VOICE_TX] = strdup("afe-proxy");
    backend_tag_table[SND_DEVICE_IN_VOICE_RX] = strdup("afe-proxy");

    if (my_data->ext_speaker) {
        backend_table[SND_DEVICE_OUT_SPEAKER] = strdup("speaker");
        backend_table[SND_DEVICE_OUT_SPEAKER_SAFE] = strdup("speaker");
        backend_table[SND_DEVICE_OUT_VOICE_SPEAKER] = strdup("speaker");
        backend_table[SND_DEVICE_OUT_SPEAKER_REVERSE] = strdup("speaker");
        backend_table[SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] =
        backend_tag_table[SND_DEVICE_OUT_SPEAKER] = strdup("speaker");
        backend_tag_table[SND_DEVICE_OUT_SPEAKER_SAFE] = strdup("speaker");
        backend_tag_table[SND_DEVICE_OUT_VOICE_SPEAKER] = strdup("speaker");
        backend_tag_table[SND_DEVICE_OUT_SPEAKER_REVERSE] = strdup("speaker");
        backend_tag_table[SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] =
            strdup("speaker-and-headphones");
        backend_table[SND_DEVICE_OUT_SPEAKER_AND_LINE] =
        backend_tag_table[SND_DEVICE_OUT_SPEAKER_AND_LINE] =
            strdup("speaker-and-line");
    }

    if (my_data->ext_earpiece) {
        backend_table[SND_DEVICE_OUT_VOICE_HANDSET] = strdup("handset");
        backend_table[SND_DEVICE_OUT_VOICE_HAC_HANDSET] = strdup("handset");
        backend_table[SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = strdup("handset");
        backend_table[SND_DEVICE_OUT_HANDSET] = strdup("handset");
        backend_table[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = strdup("handset");
    }
        backend_tag_table[SND_DEVICE_OUT_VOICE_HANDSET] = strdup("handset");
        backend_tag_table[SND_DEVICE_OUT_VOICE_HAC_HANDSET] = strdup("handset");
        backend_tag_table[SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = strdup("handset");
        backend_tag_table[SND_DEVICE_OUT_HANDSET] = strdup("handset");
        backend_tag_table[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = strdup("handset");
    }

    hw_interface_table[SND_DEVICE_OUT_HANDSET] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_SPEAKER] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_SPEAKER_REVERSE] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_SPEAKER_SAFE] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_HEADPHONES] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_LINE] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_SPEAKER_AND_LINE] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_VOICE_HANDSET] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_VOICE_HAC_HANDSET] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_VOICE_SPEAKER] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_VOICE_HEADPHONES] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_VOICE_LINE] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_HDMI] = strdup("HDMI_RX");
    hw_interface_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = strdup("SLIMBUS_0_RX-and-HDMI_RX");
    hw_interface_table[SND_DEVICE_OUT_BT_SCO] = strdup("SEC_AUX_PCM_RX");
    hw_interface_table[SND_DEVICE_OUT_BT_SCO_WB] = strdup("SEC_AUX_PCM_RX");
    hw_interface_table[SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_VOICE_TX] = strdup("AFE_PCM_RX");
    hw_interface_table[SND_DEVICE_OUT_SPEAKER_PROTECTED] = strdup("SLIMBUS_0_RX");
    hw_interface_table[SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = strdup("SLIMBUS_0_RX");
}

void *platform_init(struct audio_device *adev)
@@ -852,7 +879,7 @@ void platform_add_backend_name(void *platform, char *mixer_path,
        return;
    }

    const char * suffix = backend_table[snd_device];
    const char * suffix = backend_tag_table[snd_device];

    if (suffix != NULL) {
        strcat(mixer_path, " ");
@@ -860,6 +887,36 @@ void platform_add_backend_name(void *platform, char *mixer_path,
    }
}

bool platform_check_backends_match(snd_device_t snd_device1, snd_device_t snd_device2)
{
    bool result = true;

    ALOGV("%s: snd_device1 = %s, snd_device2 = %s", __func__,
                platform_get_snd_device_name(snd_device1),
                platform_get_snd_device_name(snd_device2));

    if ((snd_device1 < SND_DEVICE_MIN) || (snd_device1 >= SND_DEVICE_MAX)) {
        ALOGE("%s: Invalid snd_device = %s", __func__,
                platform_get_snd_device_name(snd_device1));
        return false;
    }
    if ((snd_device2 < SND_DEVICE_MIN) || (snd_device2 >= SND_DEVICE_MAX)) {
        ALOGE("%s: Invalid snd_device = %s", __func__,
                platform_get_snd_device_name(snd_device2));
        return false;
    }
    const char * be_itf1 = hw_interface_table[snd_device1];
    const char * be_itf2 = hw_interface_table[snd_device2];

    if (NULL != be_itf1 && NULL != be_itf2) {
        if (0 != strcmp(be_itf1, be_itf2))
            result = false;
    }

    ALOGV("%s: be_itf1 = %s, be_itf2 = %s, match %d", __func__, be_itf1, be_itf2, result);
    return result;
}

int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type)
{
    int device_id;
@@ -922,6 +979,8 @@ int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_i
        goto done;
    }

    ALOGV("%s: acdb_device_table[%s]: old = %d new = %d", __func__,
          platform_get_snd_device_name(snd_device), acdb_device_table[snd_device], acdb_id);
    acdb_device_table[snd_device] = acdb_id;
done:
    return ret;
@@ -1220,6 +1279,37 @@ int platform_set_device_mute(void *platform, bool state, char *dir)
    return ret;
}

bool platform_can_split_snd_device(snd_device_t snd_device,
                                   int *num_devices,
                                   snd_device_t *new_snd_devices)
{
    bool status = false;

    if (NULL == num_devices || NULL == new_snd_devices) {
        ALOGE("%s: NULL pointer ..", __func__);
        return false;
    }

    /*
     * If wired headset/headphones/line devices share the same backend
     * with speaker/earpiece this routine returns false.
     */
    if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES &&
        !platform_check_backends_match(SND_DEVICE_OUT_SPEAKER, SND_DEVICE_OUT_HEADPHONES)) {
        *num_devices = 2;
        new_snd_devices[0] = SND_DEVICE_OUT_SPEAKER;
        new_snd_devices[1] = SND_DEVICE_OUT_HEADPHONES;
        status = true;
    } else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_LINE &&
               !platform_check_backends_match(SND_DEVICE_OUT_SPEAKER, SND_DEVICE_OUT_LINE)) {
        *num_devices = 2;
        new_snd_devices[0] = SND_DEVICE_OUT_SPEAKER;
        new_snd_devices[1] = SND_DEVICE_OUT_LINE;
        status = true;
    }
    return status;
}

snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices)
{
    struct platform_data *my_data = (struct platform_data *)platform;
@@ -1744,7 +1834,8 @@ int64_t platform_render_latency(audio_usecase_t usecase)
    }
}

int platform_set_snd_device_backend(snd_device_t device, const char *backend)
int platform_set_snd_device_backend(snd_device_t device, const char *backend_tag,
                                    const char * hw_interface)
{
    int ret = 0;

@@ -1755,10 +1846,20 @@ int platform_set_snd_device_backend(snd_device_t device, const char *backend)
        goto done;
    }

    if (backend_table[device]) {
        free(backend_table[device]);
    ALOGV("%s: backend_tag_table[%s]: old = %s new = %s", __func__,
          platform_get_snd_device_name(device),
          backend_tag_table[device] != NULL ? backend_tag_table[device]: "null", backend_tag);
    if (backend_tag_table[device]) {
        free(backend_tag_table[device]);
    }
    backend_tag_table[device] = strdup(backend_tag);

    if (hw_interface != NULL) {
        if (hw_interface_table[device])
            free(hw_interface_table[device]);
        ALOGV("%s: hw_interface_table[%d] = %s", __func__, device, hw_interface);
        hw_interface_table[device] = strdup(hw_interface);
    }
    backend_table[device] = strdup(backend);
done:
    return ret;
}
@@ -1776,6 +1877,7 @@ int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t p
        ALOGE("%s: invalid usecase type", __func__);
        ret = -EINVAL;
    }
    ALOGV("%s: pcm_device_table[%d][%d] = %d", __func__, usecase, type, pcm_id);
    pcm_device_table[usecase][type] = pcm_id;
done:
    return ret;
+0 −6
Original line number Diff line number Diff line
@@ -195,12 +195,6 @@ enum {
#define VOLTE_CALL_PCM_DEVICE 21
#define QCHAT_CALL_PCM_DEVICE 33
#define VOWLAN_CALL_PCM_DEVICE -1
#elif PLATFORM_MSM8994
#define VOICE_CALL_PCM_DEVICE 2
#define VOICE2_CALL_PCM_DEVICE 22
#define VOLTE_CALL_PCM_DEVICE 14
#define QCHAT_CALL_PCM_DEVICE 20
#define VOWLAN_CALL_PCM_DEVICE 36
#else
#define VOICE_CALL_PCM_DEVICE 2
#define VOICE2_CALL_PCM_DEVICE 22
Loading