diff options
-rw-r--r-- | src/pcm/pcm.c | 48 | ||||
-rw-r--r-- | src/pcm/pcm_hw.c | 1 | ||||
-rw-r--r-- | src/pcm/pcm_local.h | 1 |
3 files changed, 50 insertions, 0 deletions
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index cd87bc75..f2ca02b5 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -655,6 +655,23 @@ playback devices. #include <limits.h> #include "pcm_local.h" +#ifndef DOC_HIDDEN +#define P_STATE(x) (1U << SND_PCM_STATE_ ## x) +#define P_STATE_RUNNABLE (P_STATE(PREPARED) | \ + P_STATE(RUNNING) | \ + P_STATE(XRUN) | \ + P_STATE(PAUSED) | \ + P_STATE(DRAINING)) + +/* check whether the PCM is in the unexpected state */ +static int bad_pcm_state(snd_pcm_t *pcm, unsigned int supported_states) +{ + if (pcm->own_state_check) + return 0; /* don't care, the plugin checks by itself */ + return !(supported_states & (1U << snd_pcm_state(pcm))); +} +#endif + /** * \brief get identifier of PCM handle * \param pcm PCM handle @@ -1120,6 +1137,8 @@ int snd_pcm_prepare(snd_pcm_t *pcm) SNDMSG("PCM not set up"); return -EIO; } + if (bad_pcm_state(pcm, ~P_STATE(DISCONNECTED))) + return -EBADFD; snd_pcm_lock(pcm); err = pcm->fast_ops->prepare(pcm->fast_op_arg); snd_pcm_unlock(pcm); @@ -1166,6 +1185,8 @@ int snd_pcm_start(snd_pcm_t *pcm) SNDMSG("PCM not set up"); return -EIO; } + if (bad_pcm_state(pcm, P_STATE(PREPARED))) + return -EBADFD; snd_pcm_lock(pcm); err = __snd_pcm_start(pcm); snd_pcm_unlock(pcm); @@ -1194,6 +1215,9 @@ int snd_pcm_drop(snd_pcm_t *pcm) SNDMSG("PCM not set up"); return -EIO; } + if (bad_pcm_state(pcm, P_STATE_RUNNABLE | P_STATE(SETUP) | + P_STATE(SUSPENDED))) + return -EBADFD; snd_pcm_lock(pcm); err = pcm->fast_ops->drop(pcm->fast_op_arg); snd_pcm_unlock(pcm); @@ -1222,6 +1246,8 @@ int snd_pcm_drain(snd_pcm_t *pcm) SNDMSG("PCM not set up"); return -EIO; } + if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) + return -EBADFD; /* lock handled in the callback */ return pcm->fast_ops->drain(pcm->fast_op_arg); } @@ -1247,6 +1273,8 @@ int snd_pcm_pause(snd_pcm_t *pcm, int enable) SNDMSG("PCM not set up"); return -EIO; } + if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) + return -EBADFD; snd_pcm_lock(pcm); err = pcm->fast_ops->pause(pcm->fast_op_arg, enable); snd_pcm_unlock(pcm); @@ -1273,6 +1301,8 @@ snd_pcm_sframes_t snd_pcm_rewindable(snd_pcm_t *pcm) SNDMSG("PCM not set up"); return -EIO; } + if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) + return -EBADFD; snd_pcm_lock(pcm); result = pcm->fast_ops->rewindable(pcm->fast_op_arg); snd_pcm_unlock(pcm); @@ -1299,6 +1329,8 @@ snd_pcm_sframes_t snd_pcm_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) } if (frames == 0) return 0; + if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) + return -EBADFD; snd_pcm_lock(pcm); result = pcm->fast_ops->rewind(pcm->fast_op_arg, frames); snd_pcm_unlock(pcm); @@ -1325,6 +1357,8 @@ snd_pcm_sframes_t snd_pcm_forwardable(snd_pcm_t *pcm) SNDMSG("PCM not set up"); return -EIO; } + if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) + return -EBADFD; snd_pcm_lock(pcm); result = pcm->fast_ops->forwardable(pcm->fast_op_arg); snd_pcm_unlock(pcm); @@ -1355,6 +1389,8 @@ snd_pcm_sframes_t snd_pcm_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) } if (frames == 0) return 0; + if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) + return -EBADFD; snd_pcm_lock(pcm); result = pcm->fast_ops->forward(pcm->fast_op_arg, frames); snd_pcm_unlock(pcm); @@ -1393,6 +1429,8 @@ snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_ufr SNDMSG("invalid access type %s", snd_pcm_access_name(pcm->access)); return -EINVAL; } + if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) + return -EBADFD; return _snd_pcm_writei(pcm, buffer, size); } @@ -1427,6 +1465,8 @@ snd_pcm_sframes_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t SNDMSG("invalid access type %s", snd_pcm_access_name(pcm->access)); return -EINVAL; } + if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) + return -EBADFD; return _snd_pcm_writen(pcm, bufs, size); } @@ -1461,6 +1501,8 @@ snd_pcm_sframes_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t SNDMSG("invalid access type %s", snd_pcm_access_name(pcm->access)); return -EINVAL; } + if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) + return -EBADFD; return _snd_pcm_readi(pcm, buffer, size); } @@ -1495,6 +1537,8 @@ snd_pcm_sframes_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t s SNDMSG("invalid access type %s", snd_pcm_access_name(pcm->access)); return -EINVAL; } + if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) + return -EBADFD; return _snd_pcm_readn(pcm, bufs, size); } @@ -6938,6 +6982,8 @@ int snd_pcm_mmap_begin(snd_pcm_t *pcm, { int err; + if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) + return -EBADFD; snd_pcm_lock(pcm); err = __snd_pcm_mmap_begin(pcm, areas, offset, frames); snd_pcm_unlock(pcm); @@ -7033,6 +7079,8 @@ snd_pcm_sframes_t snd_pcm_mmap_commit(snd_pcm_t *pcm, { snd_pcm_sframes_t result; + if (bad_pcm_state(pcm, P_STATE_RUNNABLE)) + return -EBADFD; snd_pcm_lock(pcm); result = __snd_pcm_mmap_commit(pcm, offset, frames); snd_pcm_unlock(pcm); diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 56e88b6b..30cd5d0f 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -1516,6 +1516,7 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, #ifdef THREAD_SAFE_API pcm->need_lock = 0; /* hw plugin is thread-safe */ #endif + pcm->own_state_check = 1; /* skip the common state check */ ret = snd_pcm_hw_mmap_status(pcm); if (ret < 0) { diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index bba2f15a..32e6dcdf 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -234,6 +234,7 @@ struct _snd_pcm { * use the mmaped buffer of the slave */ unsigned int donot_close: 1; /* don't close this PCM */ + unsigned int own_state_check:1; /* plugin has own PCM state check */ snd_pcm_channel_info_t *mmap_channels; snd_pcm_channel_area_t *running_areas; snd_pcm_channel_area_t *stopped_areas; |