summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2016-05-25 15:03:51 +0200
committerTakashi Iwai <tiwai@suse.de>2016-05-31 12:45:26 +0200
commit6d1d620eadf32c6d963468ce56ff52cc3a2f32e2 (patch)
tree5bdfc7066c96cd442d0052b1411c376912aada2c
parent2fa36eb03c000560128f7abce701536546b4a618 (diff)
downloadalsa-lib-6d1d620eadf32c6d963468ce56ff52cc3a2f32e2.tar.gz
pcm: dmix: resume workaround for buggy driver
The previous commit removed the whole handling of resume in dmix, but this seems causing another regression; some buggy drivers assume that the device-resume needs to be triggered before transitioning to PREPARED state. As an ugly workaround, in this patch, when the slave PCM supports resume, snd_pcm_direct_resume() does resume of the slave PCM but immediately drop the stream after that. In that way, the device is brought to the sane active state, then the apps can prepare and restart the stream properly. Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--src/pcm/pcm_direct.c25
1 files changed, 24 insertions, 1 deletions
diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c
index 53c49929..343fd3c6 100644
--- a/src/pcm/pcm_direct.c
+++ b/src/pcm/pcm_direct.c
@@ -837,6 +837,27 @@ int snd_pcm_direct_prepare(snd_pcm_t *pcm)
int snd_pcm_direct_resume(snd_pcm_t *pcm)
{
+ snd_pcm_direct_t *dmix = pcm->private_data;
+ snd_pcm_t *spcm = dmix->spcm;
+
+ snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
+ /* some buggy drivers require the device resumed before prepared;
+ * when a device has RESUME flag and is in SUSPENDED state, resume
+ * here but immediately drop to bring it to a sane active state.
+ */
+ if ((spcm->info & SND_PCM_INFO_RESUME) &&
+ snd_pcm_state(spcm) == SND_PCM_STATE_SUSPENDED) {
+ snd_pcm_resume(spcm);
+ snd_pcm_drop(spcm);
+ snd_pcm_direct_timer_stop(dmix);
+ snd_pcm_direct_clear_timer_queue(dmix);
+ snd_pcm_areas_silence(snd_pcm_mmap_areas(spcm), 0,
+ spcm->channels, spcm->buffer_size,
+ spcm->format);
+ snd_pcm_prepare(spcm);
+ snd_pcm_start(spcm);
+ }
+ snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
return -ENOSYS;
}
@@ -845,7 +866,7 @@ int snd_pcm_direct_resume(snd_pcm_t *pcm)
/* copy the slave setting */
static void save_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm)
{
- spcm->info &= ~(SND_PCM_INFO_PAUSE | SND_PCM_INFO_RESUME);
+ spcm->info &= ~SND_PCM_INFO_PAUSE;
COPY_SLAVE(access);
COPY_SLAVE(format);
@@ -874,6 +895,8 @@ static void save_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm)
COPY_SLAVE(buffer_time);
COPY_SLAVE(sample_bits);
COPY_SLAVE(frame_bits);
+
+ dmix->shmptr->s.info &= ~SND_PCM_INFO_RESUME;
}
#undef COPY_SLAVE