Merge "ASoC: msm: Disable gapless offload playback by default"

This commit is contained in:
Linux Build Service Account 2014-01-12 12:58:38 -08:00 committed by Gerrit - the friendly Code Review server
commit 850e5020fd
1 changed files with 71 additions and 9 deletions

View File

@ -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;
@ -1066,9 +1087,9 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
}
spin_unlock_irqrestore(&prtd->lock, flags);
rc = q6asm_stream_open_write_v2(prtd->audio_client,
prtd->codec, 16,
stream_id,
true /*gapless*/);
prtd->codec, 16,
stream_id,
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;
@ -1626,7 +1685,10 @@ static struct snd_compr_ops msm_compr_ops = {
static struct snd_soc_platform_driver msm_soc_platform = {
.probe = msm_compr_probe,
.compr_ops = &msm_compr_ops,
.pcm_new = msm_compr_new,
.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)