aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2005-11-02 05:32:52 -0500
committerJaroslav Kysela <perex@suse.cz>2005-11-04 07:25:06 -0500
commitb55bbf06e850d7561ad7bdded1f4d8c08b1e1f11 (patch)
tree6a556b8170c354224a8c5a4400524bc59f0101db
parent091e95ee7febf894603475c44d51f8ec4fab4328 (diff)
[ALSA] usb-audio: start submitting URBs in the prepared state
Modules: USB generic driver If we submit all our URBs when a playback stream is started, the first hwptr_done update for each URB happens at the same time. This results in an underrun when there isn't enough PCM data available at this point for all URBs. To avoid this, we begin submitting our URBs earlier (when the stream is prepared), with empy packets. When the stream is started, the prepare_playback_urb() call for each URB will be run only when the respective URB has completed previously, so the first hwptr_done updates will be done nicely staggered. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/usb/usbaudio.c100
1 files changed, 62 insertions, 38 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 8818918c4237..99dae024b640 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -41,7 +41,6 @@
41#include <sound/driver.h> 41#include <sound/driver.h>
42#include <linux/bitops.h> 42#include <linux/bitops.h>
43#include <linux/init.h> 43#include <linux/init.h>
44#include <linux/interrupt.h>
45#include <linux/list.h> 44#include <linux/list.h>
46#include <linux/slab.h> 45#include <linux/slab.h>
47#include <linux/string.h> 46#include <linux/string.h>
@@ -185,7 +184,6 @@ struct snd_usb_substream {
185 unsigned int num_formats; /* number of supported audio formats (list) */ 184 unsigned int num_formats; /* number of supported audio formats (list) */
186 struct list_head fmt_list; /* format list */ 185 struct list_head fmt_list; /* format list */
187 spinlock_t lock; 186 spinlock_t lock;
188 struct tasklet_struct start_period_elapsed; /* for start trigger */
189 187
190 struct snd_urb_ops ops; /* callbacks (must be filled at init) */ 188 struct snd_urb_ops ops; /* callbacks (must be filled at init) */
191}; 189};
@@ -480,6 +478,28 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs,
480} 478}
481 479
482/* 480/*
481 * Prepare urb for streaming before playback starts.
482 *
483 * We don't care about (or have) any data, so we just send a transfer delimiter.
484 */
485static int prepare_startup_playback_urb(snd_usb_substream_t *subs,
486 snd_pcm_runtime_t *runtime,
487 struct urb *urb)
488{
489 unsigned int i;
490 snd_urb_ctx_t *ctx = urb->context;
491
492 urb->dev = ctx->subs->dev;
493 urb->number_of_packets = subs->packs_per_ms;
494 for (i = 0; i < subs->packs_per_ms; ++i) {
495 urb->iso_frame_desc[i].offset = 0;
496 urb->iso_frame_desc[i].length = 0;
497 }
498 urb->transfer_buffer_length = 0;
499 return 0;
500}
501
502/*
483 * prepare urb for playback data pipe 503 * prepare urb for playback data pipe
484 * 504 *
485 * Since a URB can handle only a single linear buffer, we must use double 505 * Since a URB can handle only a single linear buffer, we must use double
@@ -568,12 +588,8 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
568 subs->hwptr_done -= runtime->buffer_size; 588 subs->hwptr_done -= runtime->buffer_size;
569 spin_unlock_irqrestore(&subs->lock, flags); 589 spin_unlock_irqrestore(&subs->lock, flags);
570 urb->transfer_buffer_length = offs * stride; 590 urb->transfer_buffer_length = offs * stride;
571 if (period_elapsed) { 591 if (period_elapsed)
572 if (likely(subs->running)) 592 snd_pcm_period_elapsed(subs->pcm_substream);
573 snd_pcm_period_elapsed(subs->pcm_substream);
574 else
575 tasklet_hi_schedule(&subs->start_period_elapsed);
576 }
577 return 0; 593 return 0;
578} 594}
579 595
@@ -588,22 +604,12 @@ static int retire_playback_urb(snd_usb_substream_t *subs,
588 return 0; 604 return 0;
589} 605}
590 606
591/*
592 * Delay the snd_pcm_period_elapsed() call until after the start trigger
593 * callback so that we're not longer in the substream's lock.
594 */
595static void start_period_elapsed(unsigned long data)
596{
597 snd_usb_substream_t *subs = (snd_usb_substream_t *)data;
598 snd_pcm_period_elapsed(subs->pcm_substream);
599}
600
601 607
602/* 608/*
603 */ 609 */
604static struct snd_urb_ops audio_urb_ops[2] = { 610static struct snd_urb_ops audio_urb_ops[2] = {
605 { 611 {
606 .prepare = prepare_playback_urb, 612 .prepare = prepare_startup_playback_urb,
607 .retire = retire_playback_urb, 613 .retire = retire_playback_urb,
608 .prepare_sync = prepare_playback_sync_urb, 614 .prepare_sync = prepare_playback_sync_urb,
609 .retire_sync = retire_playback_sync_urb, 615 .retire_sync = retire_playback_sync_urb,
@@ -618,7 +624,7 @@ static struct snd_urb_ops audio_urb_ops[2] = {
618 624
619static struct snd_urb_ops audio_urb_ops_high_speed[2] = { 625static struct snd_urb_ops audio_urb_ops_high_speed[2] = {
620 { 626 {
621 .prepare = prepare_playback_urb, 627 .prepare = prepare_startup_playback_urb,
622 .retire = retire_playback_urb, 628 .retire = retire_playback_urb,
623 .prepare_sync = prepare_playback_sync_urb_hs, 629 .prepare_sync = prepare_playback_sync_urb_hs,
624 .retire_sync = retire_playback_sync_urb_hs, 630 .retire_sync = retire_playback_sync_urb_hs,
@@ -863,25 +869,40 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(snd_pcm_substream_t *substream)
863 869
864 870
865/* 871/*
866 * start/stop substream 872 * start/stop playback substream
867 */ 873 */
868static int snd_usb_pcm_trigger(snd_pcm_substream_t *substream, int cmd) 874static int snd_usb_pcm_playback_trigger(snd_pcm_substream_t *substream,
875 int cmd)
869{ 876{
870 snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data; 877 snd_usb_substream_t *subs = substream->runtime->private_data;
871 int err;
872 878
873 switch (cmd) { 879 switch (cmd) {
874 case SNDRV_PCM_TRIGGER_START: 880 case SNDRV_PCM_TRIGGER_START:
875 err = start_urbs(subs, substream->runtime); 881 subs->ops.prepare = prepare_playback_urb;
876 break; 882 return 0;
877 case SNDRV_PCM_TRIGGER_STOP: 883 case SNDRV_PCM_TRIGGER_STOP:
878 err = deactivate_urbs(subs, 0, 0); 884 return deactivate_urbs(subs, 0, 0);
879 break;
880 default: 885 default:
881 err = -EINVAL; 886 return -EINVAL;
882 break; 887 }
888}
889
890/*
891 * start/stop capture substream
892 */
893static int snd_usb_pcm_capture_trigger(snd_pcm_substream_t *substream,
894 int cmd)
895{
896 snd_usb_substream_t *subs = substream->runtime->private_data;
897
898 switch (cmd) {
899 case SNDRV_PCM_TRIGGER_START:
900 return start_urbs(subs, substream->runtime);
901 case SNDRV_PCM_TRIGGER_STOP:
902 return deactivate_urbs(subs, 0, 0);
903 default:
904 return -EINVAL;
883 } 905 }
884 return err < 0 ? err : 0;
885} 906}
886 907
887 908
@@ -1413,7 +1434,7 @@ static int snd_usb_hw_free(snd_pcm_substream_t *substream)
1413static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream) 1434static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream)
1414{ 1435{
1415 snd_pcm_runtime_t *runtime = substream->runtime; 1436 snd_pcm_runtime_t *runtime = substream->runtime;
1416 snd_usb_substream_t *subs = (snd_usb_substream_t *)runtime->private_data; 1437 snd_usb_substream_t *subs = runtime->private_data;
1417 1438
1418 if (! subs->cur_audiofmt) { 1439 if (! subs->cur_audiofmt) {
1419 snd_printk(KERN_ERR "usbaudio: no format is specified!\n"); 1440 snd_printk(KERN_ERR "usbaudio: no format is specified!\n");
@@ -1433,7 +1454,13 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream)
1433 deactivate_urbs(subs, 0, 1); 1454 deactivate_urbs(subs, 0, 1);
1434 wait_clear_urbs(subs); 1455 wait_clear_urbs(subs);
1435 1456
1436 return 0; 1457 /* for playback, submit the URBs now; otherwise, the first hwptr_done
1458 * updates for all URBs would happen at the same time when starting */
1459 if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
1460 subs->ops.prepare = prepare_startup_playback_urb;
1461 return start_urbs(subs, runtime);
1462 } else
1463 return 0;
1437} 1464}
1438 1465
1439static snd_pcm_hardware_t snd_usb_playback = 1466static snd_pcm_hardware_t snd_usb_playback =
@@ -1847,7 +1874,7 @@ static snd_pcm_ops_t snd_usb_playback_ops = {
1847 .hw_params = snd_usb_hw_params, 1874 .hw_params = snd_usb_hw_params,
1848 .hw_free = snd_usb_hw_free, 1875 .hw_free = snd_usb_hw_free,
1849 .prepare = snd_usb_pcm_prepare, 1876 .prepare = snd_usb_pcm_prepare,
1850 .trigger = snd_usb_pcm_trigger, 1877 .trigger = snd_usb_pcm_playback_trigger,
1851 .pointer = snd_usb_pcm_pointer, 1878 .pointer = snd_usb_pcm_pointer,
1852 .page = snd_pcm_get_vmalloc_page, 1879 .page = snd_pcm_get_vmalloc_page,
1853}; 1880};
@@ -1859,7 +1886,7 @@ static snd_pcm_ops_t snd_usb_capture_ops = {
1859 .hw_params = snd_usb_hw_params, 1886 .hw_params = snd_usb_hw_params,
1860 .hw_free = snd_usb_hw_free, 1887 .hw_free = snd_usb_hw_free,
1861 .prepare = snd_usb_pcm_prepare, 1888 .prepare = snd_usb_pcm_prepare,
1862 .trigger = snd_usb_pcm_trigger, 1889 .trigger = snd_usb_pcm_capture_trigger,
1863 .pointer = snd_usb_pcm_pointer, 1890 .pointer = snd_usb_pcm_pointer,
1864 .page = snd_pcm_get_vmalloc_page, 1891 .page = snd_pcm_get_vmalloc_page,
1865}; 1892};
@@ -2078,9 +2105,6 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
2078 2105
2079 INIT_LIST_HEAD(&subs->fmt_list); 2106 INIT_LIST_HEAD(&subs->fmt_list);
2080 spin_lock_init(&subs->lock); 2107 spin_lock_init(&subs->lock);
2081 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
2082 tasklet_init(&subs->start_period_elapsed, start_period_elapsed,
2083 (unsigned long)subs);
2084 2108
2085 subs->stream = as; 2109 subs->stream = as;
2086 subs->direction = stream; 2110 subs->direction = stream;