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

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

qcom/audio/hal: Fix ringtone playback issue on Speaker

- Start music playback on HDMI, go to settings-->sound-->ringtone
  and select a ringtone for playback. The ringtone audio playback
  starts only after 15sec.
- When ringtone is selected, the low latency path is switched from
  HDMI to Speaker device. The low latency path uses only 2 buffers
  of 10.3msec each. If the device switch takes more time, the data
  filled kernel buffers meet the stop threshold and the ALSA
  framework triggers auto stop on the stream. This results PCM
  stream to be blocked for more than 10sec and hence no audio
  heard until the write is unblocked.
- Fix the issue by setting the stop threshold to INT_MAX to avoid
  auto stop.
- This change also ensures that open_output_stream fails if the
  HDMI sink does not support 5.1 or 7.1 playback.

Bug: 8401042
Change-Id: I4c1e04be2c47d67087b1cdda87e2dce77bde58f1
parent 71c84b70
Loading
Loading
Loading
Loading
+32 −16
Original line number Original line Diff line number Diff line
@@ -308,7 +308,7 @@ static int enable_snd_device(struct audio_device *adev,
            acdb_dev_type = ACDB_DEV_TYPE_IN;
            acdb_dev_type = ACDB_DEV_TYPE_IN;
        adev->acdb_send_audio_cal(acdb_dev_id, acdb_dev_type);
        adev->acdb_send_audio_cal(acdb_dev_id, acdb_dev_type);
    } else {
    } else {
        ALOGW("%s: Could find the symbol acdb_send_audio_cal from %s",
        ALOGW("%s: Could not find the symbol acdb_send_audio_cal from %s",
              __func__, LIB_ACDB_LOADER);
              __func__, LIB_ACDB_LOADER);
    }
    }


@@ -448,10 +448,10 @@ static int set_hdmi_channels(struct mixer *mixer,
}
}


/* must be called with hw device mutex locked */
/* must be called with hw device mutex locked */
static void read_hdmi_channel_masks(struct stream_out *out)
static int read_hdmi_channel_masks(struct stream_out *out)
{
{
    int ret = 0;
    int channels = edid_get_max_channels();
    int channels = edid_get_max_channels();
    ALOGV("%s: enter", __func__);


    switch (channels) {
    switch (channels) {
        /*
        /*
@@ -468,11 +468,11 @@ static void read_hdmi_channel_masks(struct stream_out *out)
        out->supported_channel_masks[1] = AUDIO_CHANNEL_OUT_7POINT1;
        out->supported_channel_masks[1] = AUDIO_CHANNEL_OUT_7POINT1;
        break;
        break;
    default:
    default:
        ALOGE("Unsupported number of channels (%d)", channels);
        ALOGE("HDMI does not support multi channel playback");
        ret = -ENOSYS;
        break;
        break;
    }
    }

    return ret;
    ALOGV("%s: exit", __func__);
}
}


static snd_device_t get_output_snd_device(struct audio_device *adev,
static snd_device_t get_output_snd_device(struct audio_device *adev,
@@ -1410,6 +1410,8 @@ exit:
    pthread_mutex_unlock(&out->lock);
    pthread_mutex_unlock(&out->lock);


    if (ret != 0) {
    if (ret != 0) {
        if (out->pcm)
            ALOGE("%s: error %d - %s", __func__, ret, pcm_get_error(out->pcm));
        out_standby(&out->stream.common);
        out_standby(&out->stream.common);
        usleep(bytes * 1000000 / audio_stream_frame_size(&out->stream.common) /
        usleep(bytes * 1000000 / audio_stream_frame_size(&out->stream.common) /
               out_get_sample_rate(&out->stream.common));
               out_get_sample_rate(&out->stream.common));
@@ -1640,16 +1642,24 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
    /* Init use case and pcm_config */
    /* Init use case and pcm_config */
    if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT &&
    if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT &&
        out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
        out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
        out->usecase = USECASE_AUDIO_PLAYBACK_MULTI_CH;
        out->config = pcm_config_hdmi_multi;

        pthread_mutex_lock(&adev->lock);
        pthread_mutex_lock(&adev->lock);
        read_hdmi_channel_masks(out);
        ret = read_hdmi_channel_masks(out);
        pthread_mutex_unlock(&adev->lock);
        pthread_mutex_unlock(&adev->lock);
        if (ret != 0) {
            /* If HDMI does not support multi channel playback, set the default */
            out->config.channels = popcount(out->channel_mask);
            set_hdmi_channels(adev->mixer, out->config.channels);
            goto error_open;
        }

        if (config->sample_rate == 0)
            config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
        if (config->channel_mask == 0)
            config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;


        if (config->sample_rate == 0) config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
        if (config->channel_mask == 0) config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
        out->channel_mask = config->channel_mask;
        out->channel_mask = config->channel_mask;
        out->usecase = USECASE_AUDIO_PLAYBACK_MULTI_CH;
        out->config = pcm_config_hdmi_multi;
        out->config.rate = config->sample_rate;
        out->config.rate = config->sample_rate;
        out->config.channels = popcount(out->channel_mask);
        out->config.channels = popcount(out->channel_mask);
        out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2);
        out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2);
@@ -1667,7 +1677,8 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
            adev->primary_output = out;
            adev->primary_output = out;
        else {
        else {
            ALOGE("%s: Primary output is already opened", __func__);
            ALOGE("%s: Primary output is already opened", __func__);
            return -EEXIST;
            ret = -EEXIST;
            goto error_open;
        }
        }
    }
    }


@@ -1675,10 +1686,9 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
    pthread_mutex_lock(&adev->lock);
    pthread_mutex_lock(&adev->lock);
    if (get_usecase_from_list(adev, out->usecase) != NULL) {
    if (get_usecase_from_list(adev, out->usecase) != NULL) {
        ALOGE("%s: Usecase (%d) is already present", __func__, out->usecase);
        ALOGE("%s: Usecase (%d) is already present", __func__, out->usecase);
        free(out);
        *stream_out = NULL;
        pthread_mutex_unlock(&adev->lock);
        pthread_mutex_unlock(&adev->lock);
        return -EEXIST;
        ret = -EEXIST;
        goto error_open;
    }
    }
    pthread_mutex_unlock(&adev->lock);
    pthread_mutex_unlock(&adev->lock);


@@ -1710,6 +1720,12 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
    *stream_out = &out->stream;
    *stream_out = &out->stream;
    ALOGD("%s: exit", __func__);
    ALOGD("%s: exit", __func__);
    return 0;
    return 0;

error_open:
    free(out);
    *stream_out = NULL;
    ALOGD("%s: exit: ret %d", __func__, ret);
    return ret;
}
}


static void adev_close_output_stream(struct audio_hw_device *dev,
static void adev_close_output_stream(struct audio_hw_device *dev,
+3 −0
Original line number Original line Diff line number Diff line
@@ -270,6 +270,7 @@ struct pcm_config pcm_config_deep_buffer = {
    .period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT,
    .period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT,
    .format = PCM_FORMAT_S16_LE,
    .format = PCM_FORMAT_S16_LE,
    .start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
    .start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
    .stop_threshold = INT_MAX,
    .avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
    .avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
};
};


@@ -280,6 +281,7 @@ struct pcm_config pcm_config_low_latency = {
    .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
    .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
    .format = PCM_FORMAT_S16_LE,
    .format = PCM_FORMAT_S16_LE,
    .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
    .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
    .stop_threshold = INT_MAX,
    .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
    .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
};
};


@@ -290,6 +292,7 @@ struct pcm_config pcm_config_hdmi_multi = {
    .period_count = HDMI_MULTI_PERIOD_COUNT,
    .period_count = HDMI_MULTI_PERIOD_COUNT,
    .format = PCM_FORMAT_S16_LE,
    .format = PCM_FORMAT_S16_LE,
    .start_threshold = 0,
    .start_threshold = 0,
    .stop_threshold = INT_MAX,
    .avail_min = 0,
    .avail_min = 0,
};
};