aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Laurent2011-10-14 13:12:24 -0500
committerEric Laurent2011-10-14 13:35:43 -0500
commit73b9c679a656c7b0f5e265dae5a76664c7d03031 (patch)
treec4778fe02eff8c7f8512f7426fbd17648e4934e6
parente9942c8b1fab1cea4836b5af2dd59a1bf0ad411d (diff)
downloadplatform-external-tinyalsa-73b9c679a656c7b0f5e265dae5a76664c7d03031.tar.gz
platform-external-tinyalsa-73b9c679a656c7b0f5e265dae5a76664c7d03031.tar.xz
platform-external-tinyalsa-73b9c679a656c7b0f5e265dae5a76664c7d03031.zip
Add dynamic change of avail_min for mmap mode
Added support for setting avail_min when opening a stream as well as dynamically changing its value whitout stopping playback when the stream is opened in mmap and no irq mode. Allow writing less than avail_min frames to pcm_mmap_write() without systematically waiting for avail_min frames to be available. Also fixed wait timeout for no irq mode in pcm_mmap_write(). Change-Id: Ief8e05dde8d538185174da9ef14e27a0a470057c
-rw-r--r--include/tinyalsa/asoundlib.h5
-rw-r--r--pcm.c80
2 files changed, 63 insertions, 22 deletions
diff --git a/include/tinyalsa/asoundlib.h b/include/tinyalsa/asoundlib.h
index 3c86c84..741c466 100644
--- a/include/tinyalsa/asoundlib.h
+++ b/include/tinyalsa/asoundlib.h
@@ -84,6 +84,7 @@ struct pcm_config {
84 unsigned int start_threshold; 84 unsigned int start_threshold;
85 unsigned int stop_threshold; 85 unsigned int stop_threshold;
86 unsigned int silence_threshold; 86 unsigned int silence_threshold;
87 int avail_min;
87}; 88};
88 89
89/* Mixer control types */ 90/* Mixer control types */
@@ -150,6 +151,10 @@ int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames);
150int pcm_start(struct pcm *pcm); 151int pcm_start(struct pcm *pcm);
151int pcm_stop(struct pcm *pcm); 152int pcm_stop(struct pcm *pcm);
152 153
154/* Change avail_min after the stream has been opened with no need to stop the stream.
155 * Only accepted if opened with PCM_MMAP and PCM_NOIRQ flags
156 */
157int pcm_set_avail_min(struct pcm *pcm, int avail_min);
153 158
154/* 159/*
155 * MIXER API 160 * MIXER API
diff --git a/pcm.c b/pcm.c
index d12e5da..dbf68e4 100644
--- a/pcm.c
+++ b/pcm.c
@@ -156,6 +156,7 @@ struct pcm {
156 struct snd_pcm_sync_ptr *sync_ptr; 156 struct snd_pcm_sync_ptr *sync_ptr;
157 void *mmap_buffer; 157 void *mmap_buffer;
158 unsigned int noirq_frames_per_msec; 158 unsigned int noirq_frames_per_msec;
159 int wait_for_avail_min;
159}; 160};
160 161
161unsigned int pcm_get_buffer_size(struct pcm *pcm) 162unsigned int pcm_get_buffer_size(struct pcm *pcm)
@@ -249,7 +250,10 @@ static int pcm_hw_mmap_status(struct pcm *pcm) {
249 pcm->mmap_status = NULL; 250 pcm->mmap_status = NULL;
250 goto mmap_error; 251 goto mmap_error;
251 } 252 }
252 pcm->mmap_control->avail_min = 1; 253 if (pcm->flags & PCM_MMAP)
254 pcm->mmap_control->avail_min = pcm->config.avail_min;
255 else
256 pcm->mmap_control->avail_min = 1;
253 257
254 return 0; 258 return 0;
255 259
@@ -260,7 +264,11 @@ mmap_error:
260 return -ENOMEM; 264 return -ENOMEM;
261 pcm->mmap_status = &pcm->sync_ptr->s.status; 265 pcm->mmap_status = &pcm->sync_ptr->s.status;
262 pcm->mmap_control = &pcm->sync_ptr->c.control; 266 pcm->mmap_control = &pcm->sync_ptr->c.control;
263 pcm->mmap_control->avail_min = 1; 267 if (pcm->flags & PCM_MMAP)
268 pcm->mmap_control->avail_min = pcm->config.avail_min;
269 else
270 pcm->mmap_control->avail_min = 1;
271
264 pcm_sync_ptr(pcm, 0); 272 pcm_sync_ptr(pcm, 0);
265 273
266 return 0; 274 return 0;
@@ -344,7 +352,9 @@ int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail,
344 frames = hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr; 352 frames = hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr;
345 353
346 if (frames < 0) 354 if (frames < 0)
347 return -1; 355 frames += pcm->boundary;
356 else if (frames > (int)pcm->boundary)
357 frames -= pcm->boundary;
348 358
349 *avail = (unsigned int)frames; 359 *avail = (unsigned int)frames;
350 360
@@ -529,7 +539,6 @@ struct pcm *pcm_open(unsigned int card, unsigned int device,
529 memset(&sparams, 0, sizeof(sparams)); 539 memset(&sparams, 0, sizeof(sparams));
530 sparams.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE; 540 sparams.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE;
531 sparams.period_step = 1; 541 sparams.period_step = 1;
532 sparams.avail_min = 1;
533 542
534 if (!config->start_threshold) 543 if (!config->start_threshold)
535 pcm->config.start_threshold = sparams.start_threshold = 544 pcm->config.start_threshold = sparams.start_threshold =
@@ -544,6 +553,14 @@ struct pcm *pcm_open(unsigned int card, unsigned int device,
544 else 553 else
545 sparams.stop_threshold = config->stop_threshold; 554 sparams.stop_threshold = config->stop_threshold;
546 555
556 if (!pcm->config.avail_min) {
557 if (pcm->flags & PCM_MMAP)
558 pcm->config.avail_min = sparams.avail_min = pcm->config.period_size;
559 else
560 pcm->config.avail_min = sparams.avail_min = 1;
561 } else
562 sparams.avail_min = config->avail_min;
563
547 sparams.xfer_align = config->period_size / 2; /* needed for old kernels */ 564 sparams.xfer_align = config->period_size / 2; /* needed for old kernels */
548 sparams.silence_size = 0; 565 sparams.silence_size = 0;
549 sparams.silence_threshold = config->silence_threshold; 566 sparams.silence_threshold = config->silence_threshold;
@@ -697,6 +714,15 @@ int pcm_state(struct pcm *pcm)
697 return pcm->mmap_status->state; 714 return pcm->mmap_status->state;
698} 715}
699 716
717int pcm_set_avail_min(struct pcm *pcm, int avail_min)
718{
719 if ((~pcm->flags) & (PCM_MMAP | PCM_NOIRQ))
720 return -ENOSYS;
721
722 pcm->config.avail_min = avail_min;
723 return 0;
724}
725
700int pcm_wait(struct pcm *pcm, int timeout) 726int pcm_wait(struct pcm *pcm, int timeout)
701{ 727{
702 struct pollfd pfd; 728 struct pollfd pfd;
@@ -768,28 +794,38 @@ int pcm_mmap_write(struct pcm *pcm, void *buffer, unsigned int bytes)
768 avail); 794 avail);
769 return -errno; 795 return -errno;
770 } 796 }
797 pcm->wait_for_avail_min = 0;
771 } 798 }
772 799
773 /* sleep until we have space to write new frames */ 800 /* sleep until we have space to write new frames */
774 if (pcm->running && 801 if (pcm->running) {
775 (unsigned int)avail < pcm->mmap_control->avail_min) { 802 /* enable waiting for avail_min threshold when less frames than we have to write
776 int time = -1; 803 * are available. */
777 804 if (!pcm->wait_for_avail_min && (count > (unsigned int)avail))
778 if (pcm->flags & PCM_NOIRQ) 805 pcm->wait_for_avail_min = 1;
779 time = (pcm->buffer_size - avail - pcm->mmap_control->avail_min) 806
780 / pcm->noirq_frames_per_msec; 807 if (pcm->wait_for_avail_min && (avail < pcm->config.avail_min)) {
781 808 int time = -1;
782 err = pcm_wait(pcm, time); 809
783 if (err < 0) { 810 /* disable waiting for avail_min threshold to allow small amounts of data to be
784 pcm->running = 0; 811 * written without waiting as long as there is enough room in buffer. */
785 fprintf(stderr, "wait error: hw 0x%x app 0x%x avail 0x%x\n", 812 pcm->wait_for_avail_min = 0;
786 (unsigned int)pcm->mmap_status->hw_ptr, 813
787 (unsigned int)pcm->mmap_control->appl_ptr, 814 if (pcm->flags & PCM_NOIRQ)
788 avail); 815 time = (pcm->config.avail_min - avail) / pcm->noirq_frames_per_msec;
789 pcm->mmap_control->appl_ptr = 0; 816
790 return err; 817 err = pcm_wait(pcm, time);
818 if (err < 0) {
819 pcm->running = 0;
820 oops(pcm, err, "wait error: hw 0x%x app 0x%x avail 0x%x\n",
821 (unsigned int)pcm->mmap_status->hw_ptr,
822 (unsigned int)pcm->mmap_control->appl_ptr,
823 avail);
824 pcm->mmap_control->appl_ptr = 0;
825 return err;
826 }
827 continue;
791 } 828 }
792 continue;
793 } 829 }
794 830
795 frames = count; 831 frames = count;