aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/pcm.h1
-rw-r--r--sound/core/pcm_native.c8
-rw-r--r--sound/usb/usbaudio.c14
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 */
641static int retire_playback_urb(struct snd_usb_substream *subs, 642static 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);