diff options
Diffstat (limited to 'src/pcm.c')
-rw-r--r-- | src/pcm.c | 121 |
1 files changed, 82 insertions, 39 deletions
@@ -59,6 +59,8 @@ #include <tinyalsa/pcm.h> #include <tinyalsa/limits.h> +#include "pcm_io.h" +#include "snd_card_plugin.h" #ifndef PARAM_MAX #define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL @@ -68,6 +70,7 @@ #define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) #endif /* SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP */ + static inline int param_is_mask(int p) { return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) && @@ -234,6 +237,12 @@ struct pcm { long pcm_delay; /** The subdevice corresponding to the PCM */ unsigned int subdevice; + /** Pointer to the pcm ops, either hw or plugin */ + const struct pcm_ops *ops; + /** Private data for pcm_hw or pcm_plugin */ + void *data; + /** Pointer to the pcm node from snd card definition */ + struct snd_node *snd_node; }; static int oops(struct pcm *pcm, int e, const char *fmt, ...) @@ -383,7 +392,7 @@ int pcm_set_config(struct pcm *pcm, const struct pcm_config *config) param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, SNDRV_PCM_ACCESS_RW_INTERLEAVED); - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)) { + if (pcm->ops->ioctl(pcm->data, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)) { int errno_copy = errno; oops(pcm, -errno, "cannot set hw params"); return -errno_copy; @@ -440,7 +449,7 @@ int pcm_set_config(struct pcm *pcm, const struct pcm_config *config) while (pcm->boundary * 2 <= INT_MAX - pcm->buffer_size) pcm->boundary *= 2; - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) { + if (pcm->ops->ioctl(pcm->data, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) { int errno_copy = errno; oops(pcm, -errno, "cannot set sw params"); return -errno_copy; @@ -519,7 +528,8 @@ static int pcm_sync_ptr(struct pcm *pcm, int flags) } } else { pcm->sync_ptr->flags = flags; - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SYNC_PTR, pcm->sync_ptr) < 0) { + if (pcm->ops->ioctl(pcm->data, SNDRV_PCM_IOCTL_SYNC_PTR, + pcm->sync_ptr) < 0) { oops(pcm, errno, "failed to sync mmap ptr"); return -1; } @@ -599,19 +609,30 @@ struct pcm_params *pcm_params_get(unsigned int card, unsigned int device, unsigned int flags) { struct snd_pcm_hw_params *params; - char fn[256]; + void *snd_node = NULL, *data; + const struct pcm_ops *ops; int fd; - snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, - flags & PCM_IN ? 'c' : 'p'); - - if (flags & PCM_NONBLOCK) - fd = open(fn, O_RDWR | O_NONBLOCK); - else - fd = open(fn, O_RDWR); + ops = &hw_ops; + fd = ops->open(card, device, flags, &data, snd_node); +#ifdef TINYALSA_USES_PLUGINS + if (fd < 0) { + int pcm_type; + snd_node = snd_utils_open_pcm(card, device); + pcm_type = snd_utils_get_node_type(snd_node); + if (!snd_node || pcm_type != SND_NODE_TYPE_PLUGIN) { + fprintf(stderr, "no device (hw/plugin) for card(%u), device(%u)", + card, device); + goto err_open; + } + ops = &plug_ops; + fd = ops->open(card, device, flags, &data, snd_node); + } +#endif if (fd < 0) { - fprintf(stderr, "cannot open device '%s': %s\n", fn, strerror(errno)); + fprintf(stderr, "cannot open card(%d) device (%d): %s\n", + card, device, strerror(errno)); goto err_open; } @@ -620,19 +641,27 @@ struct pcm_params *pcm_params_get(unsigned int card, unsigned int device, goto err_calloc; param_init(params); - if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, params)) { + if (ops->ioctl(data, SNDRV_PCM_IOCTL_HW_REFINE, params)) { fprintf(stderr, "SNDRV_PCM_IOCTL_HW_REFINE error (%d)\n", errno); goto err_hw_refine; } - close(fd); +#ifdef TINYALSA_USES_PLUGINS + if (snd_node) + snd_utils_close_dev_node(snd_node); +#endif + ops->close(data); return (struct pcm_params *)params; err_hw_refine: free(params); err_calloc: - close(fd); +#ifdef TINYALSA_USES_PLUGINS + if (snd_node) + snd_utils_close_dev_node(snd_node); +#endif + ops->close(data); err_open: return NULL; } @@ -787,8 +816,8 @@ int pcm_close(struct pcm *pcm) munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size)); } - if (pcm->fd >= 0) - close(pcm->fd); + snd_utils_close_dev_node(pcm->snd_node); + pcm->ops->close(pcm->data); pcm->buffer_size = 0; pcm->fd = -1; free(pcm); @@ -851,29 +880,39 @@ struct pcm *pcm_open(unsigned int card, unsigned int device, { struct pcm *pcm; struct snd_pcm_info info; - char fn[256]; int rc; pcm = calloc(1, sizeof(struct pcm)); if (!pcm) return &bad_pcm; - snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, - flags & PCM_IN ? 'c' : 'p'); - - pcm->flags = flags; - - if (flags & PCM_NONBLOCK) - pcm->fd = open(fn, O_RDWR | O_NONBLOCK); - else - pcm->fd = open(fn, O_RDWR); + /* Default to hw_ops, attemp plugin open only if hw (/dev/snd/pcm*) open fails */ + pcm->ops = &hw_ops; + pcm->fd = pcm->ops->open(card, device, flags, &pcm->data, NULL); +#ifdef TINYALSA_USES_PLUGINS + if (pcm->fd < 0) { + int pcm_type; + pcm->snd_node = snd_utils_open_pcm(card, device); + pcm_type = snd_utils_get_node_type(pcm->snd_node); + if (!pcm->snd_node || pcm_type != SND_NODE_TYPE_PLUGIN) { + oops(pcm, -ENODEV, "no device (hw/plugin) for card(%u), device(%u)", + card, device); + return pcm; + } + pcm->ops = &plug_ops; + pcm->fd = pcm->ops->open(card, device, flags, &pcm->data, pcm->snd_node); + } +#endif if (pcm->fd < 0) { - oops(pcm, errno, "cannot open device '%s'", fn); + oops(pcm, errno, "cannot open device (%u) for card (%u)", + device, card); return pcm; } - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) { + pcm->flags = flags; + + if (pcm->ops->ioctl(pcm->data, SNDRV_PCM_IOCTL_INFO, &info)) { oops(pcm, errno, "cannot get info"); goto fail_close; } @@ -891,7 +930,7 @@ struct pcm *pcm_open(unsigned int card, unsigned int device, #ifdef SNDRV_PCM_IOCTL_TTSTAMP if (pcm->flags & PCM_MONOTONIC) { int arg = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC; - rc = ioctl(pcm->fd, SNDRV_PCM_IOCTL_TTSTAMP, &arg); + rc = pcm->ops->ioctl(pcm->data, SNDRV_PCM_IOCTL_TTSTAMP, &arg); if (rc < 0) { oops(pcm, rc, "cannot set timestamp type"); goto fail; @@ -911,7 +950,11 @@ fail: if (flags & PCM_MMAP) munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size)); fail_close: - close(pcm->fd); +#ifdef TINYALSA_USES_PLUGINS + if (pcm->snd_node) + snd_utils_close_dev_node(pcm->snd_node); +#endif + pcm->ops->close(pcm->data); pcm->fd = -1; return pcm; } @@ -970,7 +1013,7 @@ int pcm_unlink(struct pcm *pcm) */ int pcm_prepare(struct pcm *pcm) { - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE) < 0) + if (pcm->ops->ioctl(pcm->data, SNDRV_PCM_IOCTL_PREPARE) < 0) return oops(pcm, errno, "cannot prepare channel"); /* get appl_ptr and avail_min from kernel */ @@ -991,7 +1034,7 @@ int pcm_start(struct pcm *pcm) return -1; if (pcm->mmap_status->state != PCM_STATE_RUNNING) { - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START) < 0) + if (pcm->ops->ioctl(pcm->data, SNDRV_PCM_IOCTL_START) < 0) return oops(pcm, errno, "cannot start channel"); } @@ -1005,7 +1048,7 @@ int pcm_start(struct pcm *pcm) */ int pcm_stop(struct pcm *pcm) { - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0) + if (pcm->ops->ioctl(pcm->data, SNDRV_PCM_IOCTL_DROP) < 0) return oops(pcm, errno, "cannot stop channel"); return 0; @@ -1288,7 +1331,7 @@ int pcm_mmap_transfer(struct pcm *pcm, void *buffer, unsigned int frames) */ if (!is_playback && state == PCM_STATE_PREPARED && frames >= pcm->config.start_threshold) { - err = ioctl(pcm->fd, SNDRV_PCM_IOCTL_START); + err = pcm->ops->ioctl(pcm->data, SNDRV_PCM_IOCTL_START); if (err == -1) return -1; /* state = PCM_STATE_RUNNING */ @@ -1326,7 +1369,7 @@ int pcm_mmap_transfer(struct pcm *pcm, void *buffer, unsigned int frames) /* start playback if written >= start_threshold */ if (is_playback && state == PCM_STATE_PREPARED && pcm->buffer_size - avail >= pcm->config.start_threshold) { - err = ioctl(pcm->fd, SNDRV_PCM_IOCTL_START); + err = pcm->ops->ioctl(pcm->data, SNDRV_PCM_IOCTL_START); if (err == -1) break; } @@ -1365,9 +1408,9 @@ static int pcm_rw_transfer(struct pcm *pcm, void *data, unsigned int frames) transfer.frames = frames; transfer.result = 0; - res = ioctl(pcm->fd, is_playback - ? SNDRV_PCM_IOCTL_WRITEI_FRAMES - : SNDRV_PCM_IOCTL_READI_FRAMES, &transfer); + res = pcm->ops->ioctl(pcm->data, is_playback + ? SNDRV_PCM_IOCTL_WRITEI_FRAMES + : SNDRV_PCM_IOCTL_READI_FRAMES, &transfer); return res == 0 ? (int) transfer.result : -1; } |