Lines Matching full:pcm

1 /* pcm.c
158 struct pcm { struct
175 unsigned int pcm_get_buffer_size(struct pcm *pcm) in pcm_get_buffer_size() argument
177 return pcm->buffer_size; in pcm_get_buffer_size()
180 const char* pcm_get_error(struct pcm *pcm) in pcm_get_error() argument
182 return pcm->error; in pcm_get_error()
185 static int oops(struct pcm *pcm, int e, const char *fmt, ...) in oops() argument
191 vsnprintf(pcm->error, PCM_ERROR_MAX, fmt, ap); in oops()
193 sz = strlen(pcm->error); in oops()
196 snprintf(pcm->error + sz, PCM_ERROR_MAX - sz, in oops()
228 unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes) in pcm_bytes_to_frames() argument
230 return bytes / (pcm->config.channels * in pcm_bytes_to_frames()
231 (pcm_format_to_bits(pcm->config.format) >> 3)); in pcm_bytes_to_frames()
234 unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames) in pcm_frames_to_bytes() argument
236 return frames * pcm->config.channels * in pcm_frames_to_bytes()
237 (pcm_format_to_bits(pcm->config.format) >> 3); in pcm_frames_to_bytes()
240 static int pcm_sync_ptr(struct pcm *pcm, int flags) { in pcm_sync_ptr() argument
241 if (pcm->sync_ptr) { in pcm_sync_ptr()
242 pcm->sync_ptr->flags = flags; in pcm_sync_ptr()
243 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SYNC_PTR, pcm->sync_ptr) < 0) in pcm_sync_ptr()
249 static int pcm_hw_mmap_status(struct pcm *pcm) { in pcm_hw_mmap_status() argument
251 if (pcm->sync_ptr) in pcm_hw_mmap_status()
255 pcm->mmap_status = mmap(NULL, page_size, PROT_READ, MAP_FILE | MAP_SHARED, in pcm_hw_mmap_status()
256 pcm->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); in pcm_hw_mmap_status()
257 if (pcm->mmap_status == MAP_FAILED) in pcm_hw_mmap_status()
258 pcm->mmap_status = NULL; in pcm_hw_mmap_status()
259 if (!pcm->mmap_status) in pcm_hw_mmap_status()
262 pcm->mmap_control = mmap(NULL, page_size, PROT_READ | PROT_WRITE, in pcm_hw_mmap_status()
263 MAP_FILE | MAP_SHARED, pcm->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); in pcm_hw_mmap_status()
264 if (pcm->mmap_control == MAP_FAILED) in pcm_hw_mmap_status()
265 pcm->mmap_control = NULL; in pcm_hw_mmap_status()
266 if (!pcm->mmap_control) { in pcm_hw_mmap_status()
267 munmap(pcm->mmap_status, page_size); in pcm_hw_mmap_status()
268 pcm->mmap_status = NULL; in pcm_hw_mmap_status()
271 if (pcm->flags & PCM_MMAP) in pcm_hw_mmap_status()
272 pcm->mmap_control->avail_min = pcm->config.avail_min; in pcm_hw_mmap_status()
274 pcm->mmap_control->avail_min = 1; in pcm_hw_mmap_status()
280 pcm->sync_ptr = calloc(1, sizeof(*pcm->sync_ptr)); in pcm_hw_mmap_status()
281 if (!pcm->sync_ptr) in pcm_hw_mmap_status()
283 pcm->mmap_status = &pcm->sync_ptr->s.status; in pcm_hw_mmap_status()
284 pcm->mmap_control = &pcm->sync_ptr->c.control; in pcm_hw_mmap_status()
285 if (pcm->flags & PCM_MMAP) in pcm_hw_mmap_status()
286 pcm->mmap_control->avail_min = pcm->config.avail_min; in pcm_hw_mmap_status()
288 pcm->mmap_control->avail_min = 1; in pcm_hw_mmap_status()
290 pcm_sync_ptr(pcm, 0); in pcm_hw_mmap_status()
295 static void pcm_hw_munmap_status(struct pcm *pcm) { in pcm_hw_munmap_status() argument
296 if (pcm->sync_ptr) { in pcm_hw_munmap_status()
297 free(pcm->sync_ptr); in pcm_hw_munmap_status()
298 pcm->sync_ptr = NULL; in pcm_hw_munmap_status()
301 if (pcm->mmap_status) in pcm_hw_munmap_status()
302 munmap(pcm->mmap_status, page_size); in pcm_hw_munmap_status()
303 if (pcm->mmap_control) in pcm_hw_munmap_status()
304 munmap(pcm->mmap_control, page_size); in pcm_hw_munmap_status()
306 pcm->mmap_status = NULL; in pcm_hw_munmap_status()
307 pcm->mmap_control = NULL; in pcm_hw_munmap_status()
310 static int pcm_areas_copy(struct pcm *pcm, unsigned int pcm_offset, in pcm_areas_copy() argument
314 int size_bytes = pcm_frames_to_bytes(pcm, frames); in pcm_areas_copy()
315 int pcm_offset_bytes = pcm_frames_to_bytes(pcm, pcm_offset); in pcm_areas_copy()
316 int src_offset_bytes = pcm_frames_to_bytes(pcm, src_offset); in pcm_areas_copy()
319 if (pcm->flags & PCM_IN) in pcm_areas_copy()
321 (char*)pcm->mmap_buffer + pcm_offset_bytes, in pcm_areas_copy()
324 memcpy((char*)pcm->mmap_buffer + pcm_offset_bytes, in pcm_areas_copy()
330 static int pcm_mmap_transfer_areas(struct pcm *pcm, char *buf, in pcm_mmap_transfer_areas() argument
339 pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames); in pcm_mmap_transfer_areas()
340 pcm_areas_copy(pcm, pcm_offset, buf, offset, frames); in pcm_mmap_transfer_areas()
341 commit = pcm_mmap_commit(pcm, pcm_offset, frames); in pcm_mmap_transfer_areas()
343 oops(pcm, commit, "failed to commit %d frames\n", frames); in pcm_mmap_transfer_areas()
354 int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail, in pcm_get_htimestamp() argument
361 if (!pcm_is_ready(pcm)) in pcm_get_htimestamp()
364 rc = pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_APPL|SNDRV_PCM_SYNC_PTR_HWSYNC); in pcm_get_htimestamp()
368 if ((pcm->mmap_status->state != PCM_STATE_RUNNING) && in pcm_get_htimestamp()
369 (pcm->mmap_status->state != PCM_STATE_DRAINING)) in pcm_get_htimestamp()
372 *tstamp = pcm->mmap_status->tstamp; in pcm_get_htimestamp()
376 hw_ptr = pcm->mmap_status->hw_ptr; in pcm_get_htimestamp()
377 if (pcm->flags & PCM_IN) in pcm_get_htimestamp()
378 frames = hw_ptr - pcm->mmap_control->appl_ptr; in pcm_get_htimestamp()
380 frames = hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr; in pcm_get_htimestamp()
383 frames += pcm->boundary; in pcm_get_htimestamp()
384 else if (frames > (int)pcm->boundary) in pcm_get_htimestamp()
385 frames -= pcm->boundary; in pcm_get_htimestamp()
392 int pcm_write(struct pcm *pcm, const void *data, unsigned int count) in pcm_write() argument
396 if (pcm->flags & PCM_IN) in pcm_write()
400 x.frames = count / (pcm->config.channels * in pcm_write()
401 pcm_format_to_bits(pcm->config.format) / 8); in pcm_write()
404 if (!pcm->running) { in pcm_write()
405 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE)) in pcm_write()
406 return oops(pcm, errno, "cannot prepare channel"); in pcm_write()
407 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) in pcm_write()
408 return oops(pcm, errno, "cannot write initial data"); in pcm_write()
409 pcm->running = 1; in pcm_write()
412 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) { in pcm_write()
413 pcm->running = 0; in pcm_write()
418 pcm->underruns++; in pcm_write()
419 if (pcm->flags & PCM_NORESTART) in pcm_write()
423 return oops(pcm, errno, "cannot write stream data"); in pcm_write()
429 int pcm_read(struct pcm *pcm, void *data, unsigned int count) in pcm_read() argument
433 if (!(pcm->flags & PCM_IN)) in pcm_read()
437 x.frames = count / (pcm->config.channels * in pcm_read()
438 pcm_format_to_bits(pcm->config.format) / 8); in pcm_read()
441 if (!pcm->running) { in pcm_read()
442 if (pcm_start(pcm) < 0) { in pcm_read()
447 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) { in pcm_read()
448 pcm->running = 0; in pcm_read()
451 pcm->underruns++; in pcm_read()
454 return oops(pcm, errno, "cannot read stream data"); in pcm_read()
460 static struct pcm bad_pcm = {
587 int pcm_close(struct pcm *pcm) in pcm_close() argument
589 if (pcm == &bad_pcm) in pcm_close()
592 pcm_hw_munmap_status(pcm); in pcm_close()
594 if (pcm->flags & PCM_MMAP) { in pcm_close()
595 pcm_stop(pcm); in pcm_close()
596 munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size)); in pcm_close()
599 if (pcm->fd >= 0) in pcm_close()
600 close(pcm->fd); in pcm_close()
601 pcm->running = 0; in pcm_close()
602 pcm->buffer_size = 0; in pcm_close()
603 pcm->fd = -1; in pcm_close()
604 free(pcm); in pcm_close()
608 struct pcm *pcm_open(unsigned int card, unsigned int device, in pcm_open()
611 struct pcm *pcm; in pcm_open() local
618 pcm = calloc(1, sizeof(struct pcm)); in pcm_open()
619 if (!pcm || !config) in pcm_open()
622 pcm->config = *config; in pcm_open()
627 pcm->flags = flags; in pcm_open()
628 pcm->fd = open(fn, O_RDWR); in pcm_open()
629 if (pcm->fd < 0) { in pcm_open()
630 oops(pcm, errno, "cannot open device '%s'", fn); in pcm_open()
631 return pcm; in pcm_open()
634 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) { in pcm_open()
635 oops(pcm, errno, "cannot get info"); in pcm_open()
657 oops(pcm, -EINVAL, "noirq only currently supported with mmap()."); in pcm_open()
662 pcm->noirq_frames_per_msec = config->rate / 1000; in pcm_open()
672 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, &params)) { in pcm_open()
673 oops(pcm, errno, "cannot set hw params"); in pcm_open()
680 pcm->buffer_size = config->period_count * config->period_size; in pcm_open()
683 pcm->mmap_buffer = mmap(NULL, pcm_frames_to_bytes(pcm, pcm->buffer_size), in pcm_open()
684 PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, pcm->fd, 0); in pcm_open()
685 if (pcm->mmap_buffer == MAP_FAILED) { in pcm_open()
686 oops(pcm, -errno, "failed to mmap buffer %d bytes\n", in pcm_open()
687 pcm_frames_to_bytes(pcm, pcm->buffer_size)); in pcm_open()
698 if (pcm->flags & PCM_IN) in pcm_open()
699 pcm->config.start_threshold = sparams.start_threshold = 1; in pcm_open()
701 pcm->config.start_threshold = sparams.start_threshold = in pcm_open()
708 if (pcm->flags & PCM_IN) in pcm_open()
709 pcm->config.stop_threshold = sparams.stop_threshold = in pcm_open()
712 pcm->config.stop_threshold = sparams.stop_threshold = in pcm_open()
718 if (!pcm->config.avail_min) { in pcm_open()
719 if (pcm->flags & PCM_MMAP) in pcm_open()
720 pcm->config.avail_min = sparams.avail_min = pcm->config.period_size; in pcm_open()
722 pcm->config.avail_min = sparams.avail_min = 1; in pcm_open()
729 pcm->boundary = sparams.boundary = pcm->buffer_size; in pcm_open()
731 while (pcm->boundary * 2 <= INT_MAX - pcm->buffer_size) in pcm_open()
732 pcm->boundary *= 2; in pcm_open()
734 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) { in pcm_open()
735 oops(pcm, errno, "cannot set sw params"); in pcm_open()
739 rc = pcm_hw_mmap_status(pcm); in pcm_open()
741 oops(pcm, rc, "mmap status failed"); in pcm_open()
746 if (pcm->flags & PCM_MONOTONIC) { in pcm_open()
748 rc = ioctl(pcm->fd, SNDRV_PCM_IOCTL_TTSTAMP, &arg); in pcm_open()
750 oops(pcm, rc, "cannot set timestamp type"); in pcm_open()
756 pcm->underruns = 0; in pcm_open()
757 return pcm; in pcm_open()
761 munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size)); in pcm_open()
763 close(pcm->fd); in pcm_open()
764 pcm->fd = -1; in pcm_open()
765 return pcm; in pcm_open()
768 int pcm_is_ready(struct pcm *pcm) in pcm_is_ready() argument
770 return pcm->fd >= 0; in pcm_is_ready()
773 int pcm_start(struct pcm *pcm) in pcm_start() argument
775 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE) < 0) in pcm_start()
776 return oops(pcm, errno, "cannot prepare channel"); in pcm_start()
778 if (pcm->flags & PCM_MMAP) in pcm_start()
779 pcm_sync_ptr(pcm, 0); in pcm_start()
781 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START) < 0) in pcm_start()
782 return oops(pcm, errno, "cannot start channel"); in pcm_start()
784 pcm->running = 1; in pcm_start()
788 int pcm_stop(struct pcm *pcm) in pcm_stop() argument
790 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0) in pcm_stop()
791 return oops(pcm, errno, "cannot stop channel"); in pcm_stop()
793 pcm->running = 0; in pcm_stop()
797 static inline int pcm_mmap_playback_avail(struct pcm *pcm) in pcm_mmap_playback_avail() argument
801 avail = pcm->mmap_status->hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr; in pcm_mmap_playback_avail()
804 avail += pcm->boundary; in pcm_mmap_playback_avail()
805 else if (avail > (int)pcm->boundary) in pcm_mmap_playback_avail()
806 avail -= pcm->boundary; in pcm_mmap_playback_avail()
811 static inline int pcm_mmap_capture_avail(struct pcm *pcm) in pcm_mmap_capture_avail() argument
813 int avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr; in pcm_mmap_capture_avail()
815 avail += pcm->boundary; in pcm_mmap_capture_avail()
819 static inline int pcm_mmap_avail(struct pcm *pcm) in pcm_mmap_avail() argument
821 pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_HWSYNC); in pcm_mmap_avail()
822 if (pcm->flags & PCM_IN) in pcm_mmap_avail()
823 return pcm_mmap_capture_avail(pcm); in pcm_mmap_avail()
825 return pcm_mmap_playback_avail(pcm); in pcm_mmap_avail()
828 static void pcm_mmap_appl_forward(struct pcm *pcm, int frames) in pcm_mmap_appl_forward() argument
830 unsigned int appl_ptr = pcm->mmap_control->appl_ptr; in pcm_mmap_appl_forward()
834 if (appl_ptr > pcm->boundary) in pcm_mmap_appl_forward()
835 appl_ptr -= pcm->boundary; in pcm_mmap_appl_forward()
836 pcm->mmap_control->appl_ptr = appl_ptr; in pcm_mmap_appl_forward()
839 int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, in pcm_mmap_begin() argument
845 *areas = pcm->mmap_buffer; in pcm_mmap_begin()
848 *offset = pcm->mmap_control->appl_ptr % pcm->buffer_size; in pcm_mmap_begin()
850 avail = pcm_mmap_avail(pcm); in pcm_mmap_begin()
851 if (avail > pcm->buffer_size) in pcm_mmap_begin()
852 avail = pcm->buffer_size; in pcm_mmap_begin()
853 continuous = pcm->buffer_size - *offset; in pcm_mmap_begin()
866 int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames) in pcm_mmap_commit() argument
869 pcm_mmap_appl_forward(pcm, frames); in pcm_mmap_commit()
870 pcm_sync_ptr(pcm, 0); in pcm_mmap_commit()
875 int pcm_avail_update(struct pcm *pcm) in pcm_avail_update() argument
877 pcm_sync_ptr(pcm, 0); in pcm_avail_update()
878 return pcm_mmap_avail(pcm); in pcm_avail_update()
881 int pcm_state(struct pcm *pcm) in pcm_state() argument
883 int err = pcm_sync_ptr(pcm, 0); in pcm_state()
887 return pcm->mmap_status->state; in pcm_state()
890 int pcm_set_avail_min(struct pcm *pcm, int avail_min) in pcm_set_avail_min() argument
892 if ((~pcm->flags) & (PCM_MMAP | PCM_NOIRQ)) in pcm_set_avail_min()
895 pcm->config.avail_min = avail_min; in pcm_set_avail_min()
899 int pcm_wait(struct pcm *pcm, int timeout) in pcm_wait() argument
904 pfd.fd = pcm->fd; in pcm_wait()
923 switch (pcm_state(pcm)) { in pcm_wait()
940 int pcm_mmap_transfer(struct pcm *pcm, const void *buffer, unsigned int bytes) in pcm_mmap_transfer() argument
948 count = pcm_bytes_to_frames(pcm, bytes); in pcm_mmap_transfer()
953 avail = pcm_avail_update(pcm); in pcm_mmap_transfer()
960 if (!pcm->running && in pcm_mmap_transfer()
961 (pcm->buffer_size - avail) >= pcm->config.start_threshold) { in pcm_mmap_transfer()
962 if (pcm_start(pcm) < 0) { in pcm_mmap_transfer()
964 (unsigned int)pcm->mmap_status->hw_ptr, in pcm_mmap_transfer()
965 (unsigned int)pcm->mmap_control->appl_ptr, in pcm_mmap_transfer()
969 pcm->wait_for_avail_min = 0; in pcm_mmap_transfer()
973 if (pcm->running) { in pcm_mmap_transfer()
976 if (!pcm->wait_for_avail_min && (count > (unsigned int)avail)) in pcm_mmap_transfer()
977 pcm->wait_for_avail_min = 1; in pcm_mmap_transfer()
979 if (pcm->wait_for_avail_min && (avail < pcm->config.avail_min)) { in pcm_mmap_transfer()
984 pcm->wait_for_avail_min = 0; in pcm_mmap_transfer()
986 if (pcm->flags & PCM_NOIRQ) in pcm_mmap_transfer()
987 time = (pcm->config.avail_min - avail) / pcm->noirq_frames_per_msec; in pcm_mmap_transfer()
989 err = pcm_wait(pcm, time); in pcm_mmap_transfer()
991 pcm->running = 0; in pcm_mmap_transfer()
992 oops(pcm, err, "wait error: hw 0x%x app 0x%x avail 0x%x\n", in pcm_mmap_transfer()
993 (unsigned int)pcm->mmap_status->hw_ptr, in pcm_mmap_transfer()
994 (unsigned int)pcm->mmap_control->appl_ptr, in pcm_mmap_transfer()
996 pcm->mmap_control->appl_ptr = 0; in pcm_mmap_transfer()
1011 frames = pcm_mmap_transfer_areas(pcm, (void *)buffer, offset, frames); in pcm_mmap_transfer()
1014 (unsigned int)pcm->mmap_status->hw_ptr, in pcm_mmap_transfer()
1015 (unsigned int)pcm->mmap_control->appl_ptr, in pcm_mmap_transfer()
1027 int pcm_mmap_write(struct pcm *pcm, const void *data, unsigned int count) in pcm_mmap_write() argument
1029 if ((~pcm->flags) & (PCM_OUT | PCM_MMAP)) in pcm_mmap_write()
1032 return pcm_mmap_transfer(pcm, (void *)data, count); in pcm_mmap_write()
1035 int pcm_mmap_read(struct pcm *pcm, void *data, unsigned int count) in pcm_mmap_read() argument
1037 if ((~pcm->flags) & (PCM_IN | PCM_MMAP)) in pcm_mmap_read()
1040 return pcm_mmap_transfer(pcm, data, count); in pcm_mmap_read()