diff options
-rw-r--r-- | include/sound/pcm.h | 1 | ||||
-rw-r--r-- | sound/core/pcm_native.c | 8 | ||||
-rw-r--r-- | sound/usb/usbaudio.c | 14 |
3 files changed, 19 insertions, 4 deletions
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 0caf71e16944..2092274212b9 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h | |||
@@ -270,6 +270,7 @@ struct snd_pcm_runtime { | |||
270 | snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ | 270 | snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ |
271 | snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ | 271 | snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ |
272 | unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ | 272 | unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ |
273 | snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ | ||
273 | 274 | ||
274 | /* -- HW params -- */ | 275 | /* -- HW params -- */ |
275 | snd_pcm_access_t access; /* access mode */ | 276 | snd_pcm_access_t access; /* access mode */ |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index b5da656d1ece..45dc53fcfa2f 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -587,14 +587,15 @@ int snd_pcm_status(struct snd_pcm_substream *substream, | |||
587 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 587 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
588 | status->avail = snd_pcm_playback_avail(runtime); | 588 | status->avail = snd_pcm_playback_avail(runtime); |
589 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING || | 589 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING || |
590 | runtime->status->state == SNDRV_PCM_STATE_DRAINING) | 590 | runtime->status->state == SNDRV_PCM_STATE_DRAINING) { |
591 | status->delay = runtime->buffer_size - status->avail; | 591 | status->delay = runtime->buffer_size - status->avail; |
592 | else | 592 | status->delay += runtime->delay; |
593 | } else | ||
593 | status->delay = 0; | 594 | status->delay = 0; |
594 | } else { | 595 | } else { |
595 | status->avail = snd_pcm_capture_avail(runtime); | 596 | status->avail = snd_pcm_capture_avail(runtime); |
596 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) | 597 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) |
597 | status->delay = status->avail; | 598 | status->delay = status->avail + runtime->delay; |
598 | else | 599 | else |
599 | status->delay = 0; | 600 | status->delay = 0; |
600 | } | 601 | } |
@@ -2410,6 +2411,7 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream, | |||
2410 | n = snd_pcm_playback_hw_avail(runtime); | 2411 | n = snd_pcm_playback_hw_avail(runtime); |
2411 | else | 2412 | else |
2412 | n = snd_pcm_capture_avail(runtime); | 2413 | n = snd_pcm_capture_avail(runtime); |
2414 | n += runtime->delay; | ||
2413 | break; | 2415 | break; |
2414 | case SNDRV_PCM_STATE_XRUN: | 2416 | case SNDRV_PCM_STATE_XRUN: |
2415 | err = -EPIPE; | 2417 | err = -EPIPE; |
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a6b88482637b..a8ef2cbcc03b 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
@@ -627,6 +627,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, | |||
627 | subs->hwptr_done += offs; | 627 | subs->hwptr_done += offs; |
628 | if (subs->hwptr_done >= runtime->buffer_size) | 628 | if (subs->hwptr_done >= runtime->buffer_size) |
629 | subs->hwptr_done -= runtime->buffer_size; | 629 | subs->hwptr_done -= runtime->buffer_size; |
630 | runtime->delay += offs; | ||
630 | spin_unlock_irqrestore(&subs->lock, flags); | 631 | spin_unlock_irqrestore(&subs->lock, flags); |
631 | urb->transfer_buffer_length = offs * stride; | 632 | urb->transfer_buffer_length = offs * stride; |
632 | if (period_elapsed) | 633 | if (period_elapsed) |
@@ -636,12 +637,22 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, | |||
636 | 637 | ||
637 | /* | 638 | /* |
638 | * process after playback data complete | 639 | * process after playback data complete |
639 | * - nothing to do | 640 | * - decrease the delay count again |
640 | */ | 641 | */ |
641 | static int retire_playback_urb(struct snd_usb_substream *subs, | 642 | static int retire_playback_urb(struct snd_usb_substream *subs, |
642 | struct snd_pcm_runtime *runtime, | 643 | struct snd_pcm_runtime *runtime, |
643 | struct urb *urb) | 644 | struct urb *urb) |
644 | { | 645 | { |
646 | unsigned long flags; | ||
647 | int stride = runtime->frame_bits >> 3; | ||
648 | int processed = urb->transfer_buffer_length / stride; | ||
649 | |||
650 | spin_lock_irqsave(&subs->lock, flags); | ||
651 | if (processed > runtime->delay) | ||
652 | runtime->delay = 0; | ||
653 | else | ||
654 | runtime->delay -= processed; | ||
655 | spin_unlock_irqrestore(&subs->lock, flags); | ||
645 | return 0; | 656 | return 0; |
646 | } | 657 | } |
647 | 658 | ||
@@ -1520,6 +1531,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
1520 | subs->hwptr_done = 0; | 1531 | subs->hwptr_done = 0; |
1521 | subs->transfer_done = 0; | 1532 | subs->transfer_done = 0; |
1522 | subs->phase = 0; | 1533 | subs->phase = 0; |
1534 | runtime->delay = 0; | ||
1523 | 1535 | ||
1524 | /* clear urbs (to be sure) */ | 1536 | /* clear urbs (to be sure) */ |
1525 | deactivate_urbs(subs, 0, 1); | 1537 | deactivate_urbs(subs, 0, 1); |