aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/pcm_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/pcm_lib.c')
-rw-r--r--sound/core/pcm_lib.c57
1 files changed, 50 insertions, 7 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index f42c10a43315..c4840ff75d00 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -316,6 +316,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
316 unsigned long jdelta; 316 unsigned long jdelta;
317 unsigned long curr_jiffies; 317 unsigned long curr_jiffies;
318 struct timespec curr_tstamp; 318 struct timespec curr_tstamp;
319 struct timespec audio_tstamp;
320 int crossed_boundary = 0;
319 321
320 old_hw_ptr = runtime->status->hw_ptr; 322 old_hw_ptr = runtime->status->hw_ptr;
321 323
@@ -327,9 +329,14 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
327 */ 329 */
328 pos = substream->ops->pointer(substream); 330 pos = substream->ops->pointer(substream);
329 curr_jiffies = jiffies; 331 curr_jiffies = jiffies;
330 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) 332 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
331 snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); 333 snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
332 334
335 if ((runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) &&
336 (substream->ops->wall_clock))
337 substream->ops->wall_clock(substream, &audio_tstamp);
338 }
339
333 if (pos == SNDRV_PCM_POS_XRUN) { 340 if (pos == SNDRV_PCM_POS_XRUN) {
334 xrun(substream); 341 xrun(substream);
335 return -EPIPE; 342 return -EPIPE;
@@ -360,8 +367,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
360 hdelta = curr_jiffies - runtime->hw_ptr_jiffies; 367 hdelta = curr_jiffies - runtime->hw_ptr_jiffies;
361 if (hdelta > runtime->hw_ptr_buffer_jiffies/2) { 368 if (hdelta > runtime->hw_ptr_buffer_jiffies/2) {
362 hw_base += runtime->buffer_size; 369 hw_base += runtime->buffer_size;
363 if (hw_base >= runtime->boundary) 370 if (hw_base >= runtime->boundary) {
364 hw_base = 0; 371 hw_base = 0;
372 crossed_boundary++;
373 }
365 new_hw_ptr = hw_base + pos; 374 new_hw_ptr = hw_base + pos;
366 goto __delta; 375 goto __delta;
367 } 376 }
@@ -371,8 +380,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
371 /* pointer crosses the end of the ring buffer */ 380 /* pointer crosses the end of the ring buffer */
372 if (new_hw_ptr < old_hw_ptr) { 381 if (new_hw_ptr < old_hw_ptr) {
373 hw_base += runtime->buffer_size; 382 hw_base += runtime->buffer_size;
374 if (hw_base >= runtime->boundary) 383 if (hw_base >= runtime->boundary) {
375 hw_base = 0; 384 hw_base = 0;
385 crossed_boundary++;
386 }
376 new_hw_ptr = hw_base + pos; 387 new_hw_ptr = hw_base + pos;
377 } 388 }
378 __delta: 389 __delta:
@@ -410,8 +421,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
410 while (hdelta > xrun_threshold) { 421 while (hdelta > xrun_threshold) {
411 delta += runtime->buffer_size; 422 delta += runtime->buffer_size;
412 hw_base += runtime->buffer_size; 423 hw_base += runtime->buffer_size;
413 if (hw_base >= runtime->boundary) 424 if (hw_base >= runtime->boundary) {
414 hw_base = 0; 425 hw_base = 0;
426 crossed_boundary++;
427 }
415 new_hw_ptr = hw_base + pos; 428 new_hw_ptr = hw_base + pos;
416 hdelta -= runtime->hw_ptr_buffer_jiffies; 429 hdelta -= runtime->hw_ptr_buffer_jiffies;
417 } 430 }
@@ -456,8 +469,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
456 /* the delta value is small or zero in most cases */ 469 /* the delta value is small or zero in most cases */
457 while (delta > 0) { 470 while (delta > 0) {
458 new_hw_ptr += runtime->period_size; 471 new_hw_ptr += runtime->period_size;
459 if (new_hw_ptr >= runtime->boundary) 472 if (new_hw_ptr >= runtime->boundary) {
460 new_hw_ptr -= runtime->boundary; 473 new_hw_ptr -= runtime->boundary;
474 crossed_boundary--;
475 }
461 delta--; 476 delta--;
462 } 477 }
463 /* align hw_base to buffer_size */ 478 /* align hw_base to buffer_size */
@@ -507,9 +522,35 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
507 runtime->hw_ptr_base = hw_base; 522 runtime->hw_ptr_base = hw_base;
508 runtime->status->hw_ptr = new_hw_ptr; 523 runtime->status->hw_ptr = new_hw_ptr;
509 runtime->hw_ptr_jiffies = curr_jiffies; 524 runtime->hw_ptr_jiffies = curr_jiffies;
510 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) 525 if (crossed_boundary) {
526 snd_BUG_ON(crossed_boundary != 1);
527 runtime->hw_ptr_wrap += runtime->boundary;
528 }
529 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
511 runtime->status->tstamp = curr_tstamp; 530 runtime->status->tstamp = curr_tstamp;
512 531
532 if (!(runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)) {
533 /*
534 * no wall clock available, provide audio timestamp
535 * derived from pointer position+delay
536 */
537 u64 audio_frames, audio_nsecs;
538
539 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
540 audio_frames = runtime->hw_ptr_wrap
541 + runtime->status->hw_ptr
542 - runtime->delay;
543 else
544 audio_frames = runtime->hw_ptr_wrap
545 + runtime->status->hw_ptr
546 + runtime->delay;
547 audio_nsecs = div_u64(audio_frames * 1000000000LL,
548 runtime->rate);
549 audio_tstamp = ns_to_timespec(audio_nsecs);
550 }
551 runtime->status->audio_tstamp = audio_tstamp;
552 }
553
513 return snd_pcm_update_state(substream, runtime); 554 return snd_pcm_update_state(substream, runtime);
514} 555}
515 556
@@ -1661,8 +1702,10 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
1661 if (snd_pcm_running(substream) && 1702 if (snd_pcm_running(substream) &&
1662 snd_pcm_update_hw_ptr(substream) >= 0) 1703 snd_pcm_update_hw_ptr(substream) >= 0)
1663 runtime->status->hw_ptr %= runtime->buffer_size; 1704 runtime->status->hw_ptr %= runtime->buffer_size;
1664 else 1705 else {
1665 runtime->status->hw_ptr = 0; 1706 runtime->status->hw_ptr = 0;
1707 runtime->hw_ptr_wrap = 0;
1708 }
1666 snd_pcm_stream_unlock_irqrestore(substream, flags); 1709 snd_pcm_stream_unlock_irqrestore(substream, flags);
1667 return 0; 1710 return 0;
1668} 1711}