Currently, dmix & co plugins ignore the XRUN state of the slave PCM.
It's (supposedly) because dmix deals with the PCM in a free-wheel
mode, which is equivalent with XRUN. But, this difference (whether
the correct freewheel or XRUN) should be done by the kernel, and we
may have an XRUN state indeed (e.g. via xrun injection).
This patch fixes this lack of behavior, to handle PCM xrun and does
prepare when the slave PCM is in such a state.
Also, the patch consolidates the prepare callback for all dmix, dsnoop
and dshare plugins, and fix/cleanup a bit for dshare/dsnoop codes to
align with dsnoop code.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
return snd_pcm_set_chmap(dmix->spcm, map);
}
+int snd_pcm_direct_prepare(snd_pcm_t *pcm)
+{
+ snd_pcm_direct_t *dmix = pcm->private_data;
+ int err;
+
+ switch (snd_pcm_state(dmix->spcm)) {
+ case SND_PCM_STATE_XRUN:
+ case SND_PCM_STATE_SUSPENDED:
+ case SND_PCM_STATE_DISCONNECTED:
+ err = snd_pcm_prepare(dmix->spcm);
+ if (err < 0)
+ return err;
+ snd_pcm_start(dmix->spcm);
+ break;
+ }
+ snd_pcm_direct_check_interleave(dmix, pcm);
+ dmix->state = SND_PCM_STATE_PREPARED;
+ dmix->appl_ptr = dmix->last_appl_ptr = 0;
+ dmix->hw_ptr = 0;
+ return snd_pcm_direct_set_timer_params(dmix);
+}
+
int snd_pcm_direct_resume(snd_pcm_t *pcm)
{
snd_pcm_direct_t *dmix = pcm->private_data;
snd1_pcm_direct_mmap
#define snd_pcm_direct_munmap \
snd1_pcm_direct_munmap
+#define snd_pcm_direct_prepare \
+ snd1_pcm_direct_prepare
#define snd_pcm_direct_resume \
snd1_pcm_direct_resume
#define snd_pcm_direct_timer_stop \
int snd_pcm_direct_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info);
int snd_pcm_direct_mmap(snd_pcm_t *pcm);
int snd_pcm_direct_munmap(snd_pcm_t *pcm);
+int snd_pcm_direct_prepare(snd_pcm_t *pcm);
int snd_pcm_direct_resume(snd_pcm_t *pcm);
int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix);
void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix);
snd_pcm_state_t state;
state = snd_pcm_state(dmix->spcm);
switch (state) {
+ case SND_PCM_STATE_XRUN:
case SND_PCM_STATE_SUSPENDED:
- return state;
case SND_PCM_STATE_DISCONNECTED:
+ dmix->state = state;
return state;
default:
break;
}
}
-static int snd_pcm_dmix_prepare(snd_pcm_t *pcm)
-{
- snd_pcm_direct_t *dmix = pcm->private_data;
-
- snd_pcm_direct_check_interleave(dmix, pcm);
- dmix->state = SND_PCM_STATE_PREPARED;
- dmix->appl_ptr = dmix->last_appl_ptr = 0;
- dmix->hw_ptr = 0;
- return snd_pcm_direct_set_timer_params(dmix);
-}
-
static void reset_slave_ptr(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
{
dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
.state = snd_pcm_dmix_state,
.hwsync = snd_pcm_dmix_hwsync,
.delay = snd_pcm_dmix_delay,
- .prepare = snd_pcm_dmix_prepare,
+ .prepare = snd_pcm_direct_prepare,
.reset = snd_pcm_dmix_reset,
.start = snd_pcm_dmix_start,
.drop = snd_pcm_dmix_drop,
static snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm)
{
snd_pcm_direct_t *dshare = pcm->private_data;
- switch (snd_pcm_state(dshare->spcm)) {
+ snd_pcm_state_t state;
+ state = snd_pcm_state(dshare->spcm);
+ switch (state) {
+ case SND_PCM_STATE_XRUN:
case SND_PCM_STATE_SUSPENDED:
- return SND_PCM_STATE_SUSPENDED;
case SND_PCM_STATE_DISCONNECTED:
- return SND_PCM_STATE_DISCONNECTED;
+ dshare->state = state;
+ return state;
default:
break;
}
}
}
-static int snd_pcm_dshare_prepare(snd_pcm_t *pcm)
-{
- snd_pcm_direct_t *dshare = pcm->private_data;
-
- snd_pcm_direct_check_interleave(dshare, pcm);
- dshare->state = SND_PCM_STATE_PREPARED;
- dshare->appl_ptr = dshare->last_appl_ptr = 0;
- dshare->hw_ptr = 0;
- return snd_pcm_direct_set_timer_params(dshare);
-}
-
static int snd_pcm_dshare_reset(snd_pcm_t *pcm)
{
snd_pcm_direct_t *dshare = pcm->private_data;
.state = snd_pcm_dshare_state,
.hwsync = snd_pcm_dshare_hwsync,
.delay = snd_pcm_dshare_delay,
- .prepare = snd_pcm_dshare_prepare,
+ .prepare = snd_pcm_direct_prepare,
.reset = snd_pcm_dshare_reset,
.start = snd_pcm_dshare_start,
.drop = snd_pcm_dshare_drop,
static snd_pcm_state_t snd_pcm_dsnoop_state(snd_pcm_t *pcm)
{
snd_pcm_direct_t *dsnoop = pcm->private_data;
- switch (snd_pcm_state(dsnoop->spcm)) {
+ snd_pcm_state_t state;
+ state = snd_pcm_state(dsnoop->spcm);
+ switch (state) {
+ case SND_PCM_STATE_XRUN:
case SND_PCM_STATE_SUSPENDED:
- return SND_PCM_STATE_SUSPENDED;
case SND_PCM_STATE_DISCONNECTED:
- dsnoop->state = SNDRV_PCM_STATE_DISCONNECTED;
- return -ENODEV;
+ dsnoop->state = state;
+ return state;
default:
break;
}
}
}
-static int snd_pcm_dsnoop_prepare(snd_pcm_t *pcm)
-{
- snd_pcm_direct_t *dsnoop = pcm->private_data;
-
- snd_pcm_direct_check_interleave(dsnoop, pcm);
- dsnoop->state = SND_PCM_STATE_PREPARED;
- dsnoop->appl_ptr = 0;
- dsnoop->hw_ptr = 0;
- return snd_pcm_direct_set_timer_params(dsnoop);
-}
-
static int snd_pcm_dsnoop_reset(snd_pcm_t *pcm)
{
snd_pcm_direct_t *dsnoop = pcm->private_data;
.state = snd_pcm_dsnoop_state,
.hwsync = snd_pcm_dsnoop_hwsync,
.delay = snd_pcm_dsnoop_delay,
- .prepare = snd_pcm_dsnoop_prepare,
+ .prepare = snd_pcm_direct_prepare,
.reset = snd_pcm_dsnoop_reset,
.start = snd_pcm_dsnoop_start,
.drop = snd_pcm_dsnoop_drop,