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

Commit 315ace3d authored by Krishnankutty Kolathappilly's avatar Krishnankutty Kolathappilly
Browse files

ASoC: msm: Disable gapless offload playback by default



Add a flag to platform private data to enable/disable gapless
playback. The platform data is updated by mixer control.
If gapless playback is disabled ignore next track and handle
partial drain as full drain. The stream is opened in gapless
mode based on the paltform data.

Change-Id: I36cea976bcb53f50069653aec4f0f8cc869f491a
Signed-off-by: default avatarKrishnankutty Kolathappilly <kkolat@codeaurora.org>
parent 6d52439a
Loading
Loading
Loading
Loading
+71 −9
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ struct msm_compr_gapless_state {
	uint32_t initial_samples_drop;
	uint32_t trailing_samples_drop;
	uint32_t gapless_transition;
	bool use_dsp_gapless_mode;
};

struct msm_compr_pdata {
@@ -74,6 +75,7 @@ struct msm_compr_pdata {
	struct snd_compr_stream *cstream[MSM_FRONTEND_DAI_MAX];
	uint32_t volume[MSM_FRONTEND_DAI_MAX][2]; /* For both L & R */
	struct msm_compr_audio_effects *audio_effects[MSM_FRONTEND_DAI_MAX];
	bool use_dsp_gapless_mode;
};

struct msm_compr_audio {
@@ -175,7 +177,7 @@ static int msm_compr_send_buffer(struct msm_compr_audio *prtd)

	pr_debug("%s: bytes_received = %d copied_total = %d\n",
		__func__, prtd->bytes_received, prtd->copied_total);
	if (prtd->first_buffer)
	if (prtd->first_buffer &&  prtd->gapless_state.use_dsp_gapless_mode)
		q6asm_send_meta_data(prtd->audio_client,
				prtd->gapless_state.initial_samples_drop,
				prtd->gapless_state.trailing_samples_drop);
@@ -449,7 +451,8 @@ static int msm_compr_configure_dsp(struct snd_compr_stream *cstream)
	pr_debug("%s\n", __func__);
	ret = q6asm_stream_open_write_v2(ac,
				prtd->codec, bits_per_sample,
				ac->stream_id, true/*gapless*/);
				ac->stream_id,
				prtd->gapless_state.use_dsp_gapless_mode);
	if (ret < 0) {
		pr_err("%s: Session out open failed\n", __func__);
		 return -ENOMEM;
@@ -558,6 +561,13 @@ static int msm_compr_open(struct snd_compr_stream *cstream)
	prtd->first_buffer = 1;
	prtd->partial_drain_delay = 0;
	memset(&prtd->gapless_state, 0, sizeof(struct msm_compr_gapless_state));
	/*
	 * Update the use_dsp_gapless_mode from gapless struture with the value
	 * part of platform data.
	 */
	prtd->gapless_state.use_dsp_gapless_mode = pdata->use_dsp_gapless_mode;

	pr_debug("%s: gapless mode %d", __func__, pdata->use_dsp_gapless_mode);

	spin_lock_init(&prtd->lock);

@@ -872,6 +882,10 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
		break;
	case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
		pr_debug("%s: SND_COMPR_TRIGGER_PARTIAL_DRAIN\n", __func__);
		if (!prtd->gapless_state.use_dsp_gapless_mode) {
			pr_debug("%s: set partial drain as drain\n", __func__);
			cmd = SND_COMPR_TRIGGER_DRAIN;
		}
	case SND_COMPR_TRIGGER_DRAIN:
		pr_debug("%s: SNDRV_COMPRESS_DRAIN\n", __func__);
		/* Make sure all the data is sent to DSP before sending EOS */
@@ -919,6 +933,7 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
		if ((cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN) &&
		    (prtd->gapless_state.set_next_stream_id)) {
			/* wait for the last buffer to be returned */

			if (prtd->last_buffer) {
				pr_debug("%s: last buffer drain\n", __func__);
				rc = msm_compr_drain_buffer(prtd, &flags);
@@ -1019,7 +1034,7 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
			rc = -EINTR;

		/*FIXME : what if a flush comes while PC is here */
		if (rc == 0 && (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN)) {
		if (rc == 0) {
			/*
			 * Failed to open second stream in DSP for gapless
			 * so prepare the current stream in session
@@ -1049,12 +1064,18 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
			prtd->first_buffer = 1;
			prtd->last_buffer = 0;
			atomic_set(&prtd->drain, 0);
			atomic_set(&prtd->xrun, 1);
			q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
			spin_unlock_irqrestore(&prtd->lock, flags);
		}
		prtd->cmd_interrupt = 0;
		break;
	case SND_COMPR_TRIGGER_NEXT_TRACK:
		if (!prtd->gapless_state.use_dsp_gapless_mode) {
			pr_debug("%s: ignore trigger next track\n", __func__);
			rc = 0;
			break;
		}
		pr_debug("%s: SND_COMPR_TRIGGER_NEXT_TRACK\n", __func__);
		spin_lock_irqsave(&prtd->lock, flags);
		rc = 0;
@@ -1068,7 +1089,7 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
		rc = q6asm_stream_open_write_v2(prtd->audio_client,
				prtd->codec, 16,
				stream_id,
						true /*gapless*/);
				prtd->gapless_state.use_dsp_gapless_mode);
		if (rc < 0) {
			pr_err("%s: Session out open failed for gapless\n",
				 __func__);
@@ -1323,7 +1344,6 @@ static int msm_compr_set_metadata(struct snd_compr_stream *cstream,
	prtd = cstream->runtime->private_data;
	if (!prtd && !prtd->audio_client)
		return -EINVAL;

	ac = prtd->audio_client;
	if (metadata->key == SNDRV_COMPRESS_ENCODER_PADDING) {
		pr_debug("%s, got encoder padding %u", __func__, metadata->value[0]);
@@ -1479,6 +1499,13 @@ static int msm_compr_probe(struct snd_soc_platform *platform)
		pdata->cstream[i] = NULL;
	}

	/*
	 * use_dsp_gapless_mode part of platform data(pdata) is updated from HAL
	 * through a mixer control before compress driver is opened. The mixer
	 * control is used to decide if dsp gapless mode needs to be enabled.
	 * Gapless is disabled by default.
	 */
	pdata->use_dsp_gapless_mode = false;
	return 0;
}

@@ -1588,7 +1615,7 @@ static int msm_compr_add_audio_effects_control(struct snd_soc_pcm_runtime *rtd)

	fe_audio_effects_config_control[0].name = mixer_str;
	fe_audio_effects_config_control[0].private_value = rtd->dai_link->be_id;
	pr_debug("Registering new mixer ctl %s", mixer_str);
	pr_debug("Registering new mixer ctl %s\n", mixer_str);
	snd_soc_add_platform_controls(rtd->platform,
				fe_audio_effects_config_control,
				ARRAY_SIZE(fe_audio_effects_config_control));
@@ -1596,6 +1623,38 @@ static int msm_compr_add_audio_effects_control(struct snd_soc_pcm_runtime *rtd)
	return 0;
}

static int msm_compr_gapless_put(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
		snd_soc_platform_get_drvdata(platform);
	pdata->use_dsp_gapless_mode =  ucontrol->value.integer.value[0];
	pr_debug("%s: value: %ld\n", __func__,
		ucontrol->value.integer.value[0]);

	return 0;
}

static int msm_compr_gapless_get(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
	struct msm_compr_pdata *pdata =
		snd_soc_platform_get_drvdata(platform);
	pr_debug("%s:gapless mode %d\n", __func__, pdata->use_dsp_gapless_mode);
	ucontrol->value.integer.value[0] = pdata->use_dsp_gapless_mode;

	return 0;
}

static const struct snd_kcontrol_new msm_compr_gapless_controls[] = {
	SOC_SINGLE_EXT("Compress Gapless Playback",
			0, 0, 1, 0,
			msm_compr_gapless_get,
			msm_compr_gapless_put),
};

static int msm_compr_new(struct snd_soc_pcm_runtime *rtd)
{
	int rc;
@@ -1627,6 +1686,9 @@ static struct snd_soc_platform_driver msm_soc_platform = {
	.probe		= msm_compr_probe,
	.compr_ops	= &msm_compr_ops,
	.pcm_new	= msm_compr_new,
	.controls       = msm_compr_gapless_controls,
	.num_controls   = ARRAY_SIZE(msm_compr_gapless_controls),

};

static int msm_compr_dev_probe(struct platform_device *pdev)