Home | History | Annotate | Download | only in tinyalsa

Lines Matching defs:pcm

0 /* pcm.c
145 struct pcm {
162 unsigned int pcm_get_buffer_size(struct pcm *pcm)
164 return pcm->buffer_size;
167 const char* pcm_get_error(struct pcm *pcm)
169 return pcm->error;
172 static int oops(struct pcm *pcm, int e, const char *fmt, ...)
178 vsnprintf(pcm->error, PCM_ERROR_MAX, fmt, ap);
180 sz = strlen(pcm->error);
183 snprintf(pcm->error + sz, PCM_ERROR_MAX - sz,
210 unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes)
212 return bytes / (pcm->config.channels *
213 (pcm_format_to_bits(pcm->config.format) >> 3));
216 unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames)
218 return frames * pcm->config.channels *
219 (pcm_format_to_bits(pcm->config.format) >> 3);
222 static int pcm_sync_ptr(struct pcm *pcm, int flags) {
223 if (pcm->sync_ptr) {
224 pcm->sync_ptr->flags = flags;
225 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SYNC_PTR, pcm->sync_ptr) < 0)
231 static int pcm_hw_mmap_status(struct pcm *pcm) {
233 if (pcm->sync_ptr)
237 pcm->mmap_status = mmap(NULL, page_size, PROT_READ, MAP_FILE | MAP_SHARED,
238 pcm->fd, SNDRV_PCM_MMAP_OFFSET_STATUS);
239 if (pcm->mmap_status == MAP_FAILED)
240 pcm->mmap_status = NULL;
241 if (!pcm->mmap_status)
244 pcm->mmap_control = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
245 MAP_FILE | MAP_SHARED, pcm->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
246 if (pcm->mmap_control == MAP_FAILED)
247 pcm->mmap_control = NULL;
248 if (!pcm->mmap_control) {
249 munmap(pcm->mmap_status, page_size);
250 pcm->mmap_status = NULL;
253 if (pcm->flags & PCM_MMAP)
254 pcm->mmap_control->avail_min = pcm->config.avail_min;
256 pcm->mmap_control->avail_min = 1;
262 pcm->sync_ptr = calloc(1, sizeof(*pcm->sync_ptr));
263 if (!pcm->sync_ptr)
265 pcm->mmap_status = &pcm->sync_ptr->s.status;
266 pcm->mmap_control = &pcm->sync_ptr->c.control;
267 if (pcm->flags & PCM_MMAP)
268 pcm->mmap_control->avail_min = pcm->config.avail_min;
270 pcm->mmap_control->avail_min = 1;
272 pcm_sync_ptr(pcm, 0);
277 static void pcm_hw_munmap_status(struct pcm *pcm) {
278 if (pcm->sync_ptr) {
279 free(pcm->sync_ptr);
280 pcm->sync_ptr = NULL;
283 if (pcm->mmap_status)
284 munmap(pcm->mmap_status, page_size);
285 if (pcm->mmap_control)
286 munmap(pcm->mmap_control, page_size);
288 pcm->mmap_status = NULL;
289 pcm->mmap_control = NULL;
292 static int pcm_areas_copy(struct pcm *pcm, unsigned int pcm_offset,
296 int size_bytes = pcm_frames_to_bytes(pcm, frames);
297 int pcm_offset_bytes = pcm_frames_to_bytes(pcm, pcm_offset);
298 int src_offset_bytes = pcm_frames_to_bytes(pcm, src_offset);
301 memcpy((char*)pcm->mmap_buffer + pcm_offset_bytes,
306 static int pcm_mmap_write_areas(struct pcm *pcm, char *src,
315 pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames);
316 pcm_areas_copy(pcm, pcm_offset, src, offset, frames);
317 commit = pcm_mmap_commit(pcm, pcm_offset, frames);
319 oops(pcm, commit, "failed to commit %d frames\n", frames);
330 int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail,
337 if (!pcm_is_ready(pcm))
340 rc = pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_APPL|SNDRV_PCM_SYNC_PTR_HWSYNC);
344 if ((pcm->mmap_status->state != PCM_STATE_RUNNING) &&
345 (pcm->mmap_status->state != PCM_STATE_DRAINING))
348 *tstamp = pcm->mmap_status->tstamp;
352 hw_ptr = pcm->mmap_status->hw_ptr;
353 if (pcm->flags & PCM_IN)
354 frames = hw_ptr - pcm->mmap_control->appl_ptr;
356 frames = hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr;
359 frames += pcm->boundary;
360 else if (frames > (int)pcm->boundary)
361 frames -= pcm->boundary;
368 int pcm_write(struct pcm *pcm, void *data, unsigned int count)
372 if (pcm->flags & PCM_IN)
376 x.frames = count / (pcm->config.channels *
377 pcm_format_to_bits(pcm->config.format) / 8);
380 if (!pcm->running) {
381 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE))
382 return oops(pcm, errno, "cannot prepare channel");
383 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x))
384 return oops(pcm, errno, "cannot write initial data");
385 pcm->running = 1;
388 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) {
389 pcm->running = 0;
392 pcm->underruns++;
395 return oops(pcm, errno, "cannot write stream data");
401 int pcm_read(struct pcm *pcm, void *data, unsigned int count)
405 if (!(pcm->flags & PCM_IN))
409 x.frames = count / (pcm->config.channels *
410 pcm_format_to_bits(pcm->config.format) / 8);
413 if (!pcm->running) {
414 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE))
415 return oops(pcm, errno, "cannot prepare channel");
416 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START))
417 return oops(pcm, errno, "cannot start channel");
418 pcm->running = 1;
420 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) {
421 pcm->running = 0;
424 pcm->underruns++;
427 return oops(pcm, errno, "cannot read stream data");
433 static struct pcm bad_pcm = {
437 int pcm_close(struct pcm *pcm)
439 if (pcm == &bad_pcm)
442 pcm_hw_munmap_status(pcm);
444 if (pcm->flags & PCM_MMAP) {
445 pcm_stop(pcm);
446 munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size));
449 if (pcm->fd >= 0)
450 close(pcm->fd);
451 pcm->running = 0;
452 pcm->buffer_size = 0;
453 pcm->fd = -1;
454 free(pcm);
458 struct pcm *pcm_open(unsigned int card, unsigned int device,
461 struct pcm *pcm;
468 pcm = calloc(1, sizeof(struct pcm));
469 if (!pcm || !config)
472 pcm->config = *config;
477 pcm->flags = flags;
478 pcm->fd = open(fn, O_RDWR);
479 if (pcm->fd < 0) {
480 oops(pcm, errno, "cannot open device '%s'", fn);
481 return pcm;
484 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) {
485 oops(pcm, errno, "cannot get info");
507 oops(pcm, -EINVAL, "noirq only currently supported with mmap().");
512 pcm->noirq_frames_per_msec = config->rate / 1000;
522 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, &params)) {
523 oops(pcm, errno, "cannot set hw params");
530 pcm->buffer_size = config->period_count * config->period_size;
533 pcm->mmap_buffer = mmap(NULL, pcm_frames_to_bytes(pcm, pcm->buffer_size),
534 PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, pcm->fd, 0);
535 if (pcm->mmap_buffer == MAP_FAILED) {
536 oops(pcm, -errno, "failed to mmap buffer %d bytes\n",
537 pcm_frames_to_bytes(pcm, pcm->buffer_size));
548 pcm->config.start_threshold = sparams.start_threshold =
555 if (pcm->flags & PCM_IN)
556 pcm
559 pcm->config.stop_threshold = sparams.stop_threshold =
565 if (!pcm->config.avail_min) {
566 if (pcm->flags & PCM_MMAP)
567 pcm->config.avail_min = sparams.avail_min = pcm->config.period_size;
569 pcm->config.avail_min = sparams.avail_min = 1;
576 pcm->boundary = sparams.boundary = pcm->buffer_size;
578 while (pcm->boundary * 2 <= LONG_MAX - pcm->buffer_size)
579 pcm->boundary *= 2;
581 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) {
582 oops(pcm, errno, "cannot set sw params");
586 rc = pcm_hw_mmap_status(pcm);
588 oops(pcm, rc, "mmap status failed");
592 pcm->underruns = 0;
593 return pcm;
597 munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size));
599 close(pcm->fd);
600 pcm->fd = -1;
601 return pcm;
604 int pcm_is_ready(struct pcm *pcm)
606 return pcm->fd >= 0;
609 int pcm_start(struct pcm *pcm)
611 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE) < 0)
612 return oops(pcm, errno, "cannot prepare channel");
614 if (pcm->flags & PCM_MMAP)
615 pcm_sync_ptr(pcm, 0);
617 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START) < 0)
618 return oops(pcm, errno, "cannot start channel");
620 pcm->running = 1;
624 int pcm_stop(struct pcm *pcm)
626 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0)
627 return oops(pcm, errno, "cannot stop channel");
629 pcm->running = 0;
633 static inline int pcm_mmap_playback_avail(struct pcm *pcm)
637 avail = pcm->mmap_status->hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr;
640 avail += pcm->boundary;
641 else if (avail > (int)pcm->boundary)
642 avail -= pcm->boundary;
647 static inline int pcm_mmap_capture_avail(struct pcm *pcm)
649 int avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr;
651 avail += pcm->boundary;
655 static inline int pcm_mmap_avail(struct pcm *pcm)
657 pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_HWSYNC);
658 if (pcm->flags & PCM_IN)
659 return pcm_mmap_capture_avail(pcm);
661 return pcm_mmap_playback_avail(pcm);
664 static void pcm_mmap_appl_forward(struct pcm *pcm, int frames)
666 unsigned int appl_ptr = pcm->mmap_control->appl_ptr;
670 if (appl_ptr > pcm->boundary)
671 appl_ptr -= pcm->boundary;
672 pcm->mmap_control->appl_ptr = appl_ptr;
675 int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset,
681 *areas = pcm->mmap_buffer;
684 *offset = pcm->mmap_control->appl_ptr % pcm->buffer_size;
686 avail = pcm_mmap_avail(pcm);
687 if (avail > pcm->buffer_size)
688 avail = pcm->buffer_size;
689 continuous = pcm->buffer_size - *offset;
702 int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames)
705 pcm_mmap_appl_forward(pcm, frames);
706 pcm_sync_ptr(pcm, 0);
711 int pcm_avail_update(struct pcm *pcm)
713 pcm_sync_ptr(pcm, 0);
714 return pcm_mmap_avail(pcm);
717 int pcm_state(struct pcm *pcm)
719 int err = pcm_sync_ptr(pcm, 0);
723 return pcm->mmap_status->state;
726 int pcm_set_avail_min(struct pcm *pcm, int avail_min)
728 if ((~pcm->flags) & (PCM_MMAP | PCM_NOIRQ))
731 pcm->config.avail_min = avail_min;
735 int pcm_wait(struct pcm *pcm, int timeout)
741 pfd.fd = pcm->fd;
760 switch (pcm_state(pcm)) {
777 int pcm_mmap_write(struct pcm *pcm, void *buffer, unsigned int bytes)
785 count = pcm_bytes_to_frames(pcm, bytes);
790 avail = pcm_avail_update(pcm);
797 if (!pcm->running &&
798 (pcm->buffer_size - avail) >= pcm->config.start_threshold) {
799 if (pcm_start(pcm) < 0) {
801 (unsigned int)pcm->mmap_status->hw_ptr,
802 (unsigned int)pcm->mmap_control->appl_ptr,
806 pcm->wait_for_avail_min = 0;
810 if (pcm->running) {
813 if (!pcm->wait_for_avail_min && (count > (unsigned int)avail))
814 pcm->wait_for_avail_min = 1;
816 if (pcm->wait_for_avail_min && (avail < pcm->config.avail_min)) {
821 pcm->wait_for_avail_min = 0;
823 if (pcm->flags & PCM_NOIRQ)
824 time = (pcm->config.avail_min - avail) / pcm->noirq_frames_per_msec;
826 err = pcm_wait(pcm, time);
828 pcm->running = 0;
829 oops(pcm, err, "wait error: hw 0x%x app 0x%x avail 0x%x\n",
830 (unsigned int)pcm->mmap_status->hw_ptr,
831 (unsigned int)pcm->mmap_control->appl_ptr,
833 pcm->mmap_control->appl_ptr = 0;
848 frames = pcm_mmap_write_areas(pcm, buffer, offset, frames);
851 (unsigned int)pcm->mmap_status->hw_ptr,
852 (unsigned int)pcm->mmap_control->appl_ptr,