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

Commit b9058113 authored by vivek mehta's avatar vivek mehta Committed by android-build-merger
Browse files

hal: speaker swap: fix pause rotation issue

am: e59cfb2f

Change-Id: I92326c47411d4af1f30fc5da3a6239ac799c1f70
parents dc27d51b e59cfb2f
Loading
Loading
Loading
Loading
+24 −1
Original line number Diff line number Diff line
@@ -680,9 +680,15 @@ int disable_snd_device(struct audio_device *adev,
    if (adev->snd_dev_ref_cnt[snd_device] == 0) {
        audio_extn_dsm_feedback_enable(adev, snd_device, false);
        if ((snd_device == SND_DEVICE_OUT_SPEAKER ||
            snd_device == SND_DEVICE_OUT_SPEAKER_REVERSE ||
            snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) &&
            audio_extn_spkr_prot_is_enabled()) {
            audio_extn_spkr_prot_stop_processing(snd_device);

            // when speaker device is disabled, reset swap.
            // will be renabled on usecase start
            platform_set_swap_channels(adev, false);

        } else if (platform_can_split_snd_device(snd_device,
                                                 &num_devices,
                                                 new_snd_devices) == 0) {
@@ -1871,6 +1877,14 @@ int start_output_stream(struct stream_out *out)
    audio_extn_utils_send_app_type_gain(out->dev,
                                        out->app_type_cfg.app_type,
                                        &out->app_type_cfg.gain[0]);

    // consider a scenario where on pause lower layers are tear down.
    // so on resume, swap mixer control need to be sent only when
    // backend is active, hence rather than sending from enable device
    // sending it from start of streamtream

    platform_set_swap_channels(adev, true);

    ALOGV("%s: exit", __func__);
    return 0;
error_open:
@@ -2192,6 +2206,12 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
                }
                select_devices(adev, out->usecase);
                audio_extn_tfa_98xx_update();

                // on device switch force swap, lower functions will make sure
                // to check if swap is allowed or not.

                if (!same_dev)
                    platform_set_swap_channels(adev, true);
            }

        }
@@ -3904,7 +3924,10 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
            status = -EINVAL;
        }
        if (status == 0) {
            platform_swap_lr_channels(adev, reverse_speakers);
            // check and set swap
            //   - check if orientation changed and speaker active
            //   - set rotation and cache the rotation value
            platform_check_and_set_swap_lr_channels(adev, reverse_speakers);
        }
    }

+78 −31
Original line number Diff line number Diff line
@@ -2258,16 +2258,70 @@ int ramp_speaker_gain(struct audio_device *adev, bool ramp_up, int target_ramp_u
    return start_gain;
}

int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels)
int platform_set_swap_mixer(struct audio_device *adev, bool swap_channels)
{
    const char *mixer_ctl_name = "Swap channel";
    struct mixer_ctl *ctl;
    const char *mixer_path;
    struct platform_data *my_data = (struct platform_data *)adev->platform;

    // forced to set to swap, but device not rotated ... ignore set
    if (swap_channels && !my_data->speaker_lr_swap)
        return 0;

    ALOGV("%s:", __func__);

    if (swap_channels) {
        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_REVERSE);
        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
    } else {
        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER);
        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
    }

    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;
    }

    if (mixer_ctl_set_value(ctl, 0, swap_channels) < 0) {
        ALOGE("%s: Could not set reverse cotrol %d",__func__, swap_channels);
        return -EINVAL;
    }

    ALOGV("platfor_force_swap_channel :: Channel orientation ( %s ) ",
           swap_channels?"R --> L":"L --> R");

    return 0;
}

int platform_check_and_set_swap_lr_channels(struct audio_device *adev, bool swap_channels)
{
    // only update if there is active pcm playback on speaker
    struct audio_usecase *usecase;
    struct listnode *node;
    struct platform_data *my_data = (struct platform_data *)adev->platform;

    if (my_data->speaker_lr_swap != swap_channels) {
    my_data->speaker_lr_swap = swap_channels;

    return platform_set_swap_channels(adev, swap_channels);
}

int platform_set_swap_channels(struct audio_device *adev, bool swap_channels)
{
    // only update if there is active pcm playback on speaker
    struct audio_usecase *usecase;
    struct listnode *node;
    struct platform_data *my_data = (struct platform_data *)adev->platform;

    // do not swap channels in audio modes with concurrent capture and playback
    // as this may break the echo reference
    if ((adev->mode == AUDIO_MODE_IN_COMMUNICATION) || (adev->mode == AUDIO_MODE_IN_CALL)) {
        ALOGV("%s: will not swap due to audio mode %d", __func__, adev->mode);
        return 0;
    }

    list_for_each(node, &adev->usecase_list) {
        usecase = node_to_item(node, struct audio_usecase, list);
        if (usecase->type == PCM_PLAYBACK &&
@@ -2281,23 +2335,16 @@ int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels)
                acdb_device_table[SND_DEVICE_OUT_SPEAKER_REVERSE]) {
                const int initial_skpr_gain = ramp_speaker_gain(adev, false /*ramp_up*/, -1);
                select_devices(adev, usecase->id);
                    if (initial_skpr_gain != -EINVAL) {
                if (initial_skpr_gain != -EINVAL)
                    ramp_speaker_gain(adev, true /*ramp_up*/, initial_skpr_gain);
                    }
                } else {
                    const char *mixer_path;
                    if (swap_channels) {
                        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_REVERSE);
                        audio_route_apply_and_update_path(adev->audio_route, mixer_path);

            } else {
                        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER);
                        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
                    }
                platform_set_swap_mixer(adev, swap_channels);
            }
            break;
        }
    }
    }

    return 0;
}

+139 −18
Original line number Diff line number Diff line
@@ -1056,34 +1056,155 @@ void platform_set_echo_reference(struct audio_device *adev __unused,
    return;
}

int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels)
#define DEFAULT_NOMINAL_SPEAKER_GAIN 20
int ramp_speaker_gain(struct audio_device *adev, bool ramp_up, int target_ramp_up_gain) {
    // backup_gain: gain to try to set in case of an error during ramp
    int start_gain, end_gain, step, backup_gain, i;
    bool error = false;
    const struct mixer_ctl *ctl;
    const char *mixer_ctl_name_gain_left = "Left Speaker Gain";
    const char *mixer_ctl_name_gain_right = "Right Speaker Gain";
    struct mixer_ctl *ctl_left = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name_gain_left);
    struct mixer_ctl *ctl_right = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name_gain_right);
    if (!ctl_left || !ctl_right) {
        ALOGE("%s: Could not get ctl for mixer cmd - %s or %s, not applying speaker gain ramp",
                      __func__, mixer_ctl_name_gain_left, mixer_ctl_name_gain_right);
        return -EINVAL;
    } else if ((mixer_ctl_get_num_values(ctl_left) != 1)
            || (mixer_ctl_get_num_values(ctl_right) != 1)) {
        ALOGE("%s: Unexpected num values for mixer cmd - %s or %s, not applying speaker gain ramp",
                              __func__, mixer_ctl_name_gain_left, mixer_ctl_name_gain_right);
        return -EINVAL;
    }
    if (ramp_up) {
        start_gain = 0;
        end_gain = target_ramp_up_gain > 0 ? target_ramp_up_gain : DEFAULT_NOMINAL_SPEAKER_GAIN;
        step = +1;
        backup_gain = end_gain;
    } else {
        // using same gain on left and right
        const int left_gain = mixer_ctl_get_value(ctl_left, 0);
        start_gain = left_gain > 0 ? left_gain : DEFAULT_NOMINAL_SPEAKER_GAIN;
        end_gain = 0;
        step = -1;
        backup_gain = start_gain;
    }
    for (i = start_gain ; i != (end_gain + step) ; i += step) {
        //ALOGV("setting speaker gain to %d", i);
        if (mixer_ctl_set_value(ctl_left, 0, i)) {
            ALOGE("%s: error setting %s to %d during gain ramp",
                    __func__, mixer_ctl_name_gain_left, i);
            error = true;
            break;
        }
        if (mixer_ctl_set_value(ctl_right, 0, i)) {
            ALOGE("%s: error setting %s to %d during gain ramp",
                    __func__, mixer_ctl_name_gain_right, i);
            error = true;
            break;
        }
        usleep(1000);
    }
    if (error) {
        // an error occured during the ramp, let's still try to go back to a safe volume
        if (mixer_ctl_set_value(ctl_left, 0, backup_gain)) {
            ALOGE("%s: error restoring left gain to %d", __func__, backup_gain);
        }
        if (mixer_ctl_set_value(ctl_right, 0, backup_gain)) {
            ALOGE("%s: error restoring right gain to %d", __func__, backup_gain);
        }
    }
    return start_gain;
}

int platform_set_swap_mixer(struct audio_device *adev, bool swap_channels)
{
    const char *mixer_ctl_name = "Swap channel";
    struct mixer_ctl *ctl;
    const char *mixer_path;
    struct platform_data *my_data = (struct platform_data *)adev->platform;

    // forced to set to swap, but device not rotated ... ignore set
    if (swap_channels && !my_data->speaker_lr_swap)
        return 0;

    ALOGV("%s:", __func__);

    if (swap_channels) {
        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_REVERSE);
        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
    } else {
        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER);
        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
    }

    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;
    }

    if (mixer_ctl_set_value(ctl, 0, swap_channels) < 0) {
        ALOGE("%s: Could not set reverse cotrol %d",__func__, swap_channels);
        return -EINVAL;
    }

    ALOGV("platfor_force_swap_channel :: Channel orientation ( %s ) ",
           swap_channels?"R --> L":"L --> R");

    return 0;
}

int platform_check_and_set_swap_lr_channels(struct audio_device *adev, bool swap_channels)
{
    // only update the selected device if there is active pcm playback
    // only update if there is active pcm playback on speaker
    struct audio_usecase *usecase;
    struct listnode *node;
    struct platform_data *my_data = (struct platform_data *)adev->platform;
    int status = 0;

    if (my_data->speaker_lr_swap != swap_channels) {
    my_data->speaker_lr_swap = swap_channels;

    return platform_set_swap_channels(adev, swap_channels);
}

int platform_set_swap_channels(struct audio_device *adev, bool swap_channels)
{
    // only update if there is active pcm playback on speaker
    struct audio_usecase *usecase;
    struct listnode *node;
    struct platform_data *my_data = (struct platform_data *)adev->platform;

    // do not swap channels in audio modes with concurrent capture and playback
    // as this may break the echo reference
    if ((adev->mode == AUDIO_MODE_IN_COMMUNICATION) || (adev->mode == AUDIO_MODE_IN_CALL)) {
        ALOGV("%s: will not swap due to audio mode %d", __func__, adev->mode);
        return 0;
    }

    list_for_each(node, &adev->usecase_list) {
        usecase = node_to_item(node, struct audio_usecase, list);
        if (usecase->type == PCM_PLAYBACK &&
                usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
                const char *mixer_path;
                if (swap_channels) {
                    mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_REVERSE);
                    audio_route_apply_and_update_path(adev->audio_route, mixer_path);
            /*
             * If acdb tuning is different for SPEAKER_REVERSE, it is must
             * to perform device switch to disable the current backend to
             * enable it with new acdb data.
             */
            if (acdb_device_table[SND_DEVICE_OUT_SPEAKER] !=
                acdb_device_table[SND_DEVICE_OUT_SPEAKER_REVERSE]) {
                const int initial_skpr_gain = ramp_speaker_gain(adev, false /*ramp_up*/, -1);
                select_devices(adev, usecase->id);
                if (initial_skpr_gain != -EINVAL)
                    ramp_speaker_gain(adev, true /*ramp_up*/, initial_skpr_gain);

            } else {
                    mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER);
                    audio_route_apply_and_update_path(adev->audio_route, mixer_path);
                platform_set_swap_mixer(adev, swap_channels);
            }
            break;
        }
    }
    }
    return status;

    return 0;
}

bool platform_send_gain_dep_cal(void *platform __unused,
+75 −37
Original line number Diff line number Diff line
@@ -167,7 +167,6 @@ static int pcm_device_table[AUDIO_USECASE_MAX][2] = {

    [USECASE_AUDIO_RECORD_MMAP] = {MMAP_RECORD_PCM_DEVICE,
            MMAP_RECORD_PCM_DEVICE},

    [USECASE_AUDIO_RECORD_HIFI] = {MULTIMEDIA2_PCM_DEVICE,
                                   MULTIMEDIA2_PCM_DEVICE},

@@ -3172,14 +3171,62 @@ int ramp_speaker_gain(struct audio_device *adev, bool ramp_up, int target_ramp_u
    return start_gain;
}

int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels)
int platform_set_swap_mixer(struct audio_device *adev, bool swap_channels)
{
    const char *mixer_ctl_name = "Swap channel";
    struct mixer_ctl *ctl;
    const char *mixer_path;
    struct platform_data *my_data = (struct platform_data *)adev->platform;

    // forced to set to swap, but device not rotated ... ignore set
    if (swap_channels && !my_data->speaker_lr_swap)
        return 0;

    ALOGV("%s:", __func__);

    if (swap_channels) {
        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_REVERSE);
        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
    } else {
        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER);
        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
    }

    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;
    }

    if (mixer_ctl_set_value(ctl, 0, swap_channels) < 0) {
        ALOGE("%s: Could not set reverse cotrol %d",__func__, swap_channels);
        return -EINVAL;
    }

    ALOGV("platfor_force_swap_channel :: Channel orientation ( %s ) ",
           swap_channels?"R --> L":"L --> R");

    return 0;
}

int platform_check_and_set_swap_lr_channels(struct audio_device *adev, bool swap_channels)
{
    // only update if there is active pcm playback on speaker
    struct audio_usecase *usecase;
    struct listnode *node;
    struct platform_data *my_data = (struct platform_data *)adev->platform;

    if (my_data->speaker_lr_swap != swap_channels) {
    my_data->speaker_lr_swap = swap_channels;

    return platform_set_swap_channels(adev, swap_channels);
}

int platform_set_swap_channels(struct audio_device *adev, bool swap_channels)
{
    // only update if there is active pcm playback on speaker
    struct audio_usecase *usecase;
    struct listnode *node;
    struct platform_data *my_data = (struct platform_data *)adev->platform;

    // do not swap channels in audio modes with concurrent capture and playback
    // as this may break the echo reference
@@ -3188,8 +3235,6 @@ int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels)
        return 0;
    }

        my_data->speaker_lr_swap = swap_channels;

    list_for_each(node, &adev->usecase_list) {
        usecase = node_to_item(node, struct audio_usecase, list);
        if (usecase->type == PCM_PLAYBACK &&
@@ -3203,23 +3248,16 @@ int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels)
                acdb_device_table[SND_DEVICE_OUT_SPEAKER_REVERSE]) {
                const int initial_skpr_gain = ramp_speaker_gain(adev, false /*ramp_up*/, -1);
                select_devices(adev, usecase->id);
                    if (initial_skpr_gain != -EINVAL) {
                if (initial_skpr_gain != -EINVAL)
                    ramp_speaker_gain(adev, true /*ramp_up*/, initial_skpr_gain);
                    }
                } else {
                    const char *mixer_path;
                    if (swap_channels) {
                        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_REVERSE);
                        audio_route_apply_and_update_path(adev->audio_route, mixer_path);

            } else {
                        mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER);
                        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
                    }
                platform_set_swap_mixer(adev, swap_channels);
            }
            break;
        }
    }
    }

    return 0;
}

+2 −1
Original line number Diff line number Diff line
@@ -113,7 +113,8 @@ int snd_card_info_init(const char *filename, void *, set_parameters_fn);
int platform_get_usecase_index(const char * usecase);
int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id);
void platform_set_echo_reference(struct audio_device *adev, bool enable, audio_devices_t out_device);
int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels);
int platform_check_and_set_swap_lr_channels(struct audio_device *adev, bool swap_channels);
int platform_set_swap_channels(struct audio_device *adev, bool swap_channels);

int platform_can_split_snd_device(snd_device_t in_snd_device,
                                  int *num_devices,