diff options
author | Takashi Iwai <tiwai@suse.de> | 2017-05-19 14:22:33 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2017-05-25 17:34:47 -0400 |
commit | 9027c4639ef1e3254779e3033f229133222445f7 (patch) | |
tree | 93d246fb50663aa6c6db6e7a8b4f99b7fcfcf439 | |
parent | 9ce7b9cf64dc1a48a074033a83c8ea314b38540c (diff) |
ALSA: pcm: Call ack() whenever appl_ptr is updated
Although the ack callback is supposed to be called at each appl_ptr or
hw_ptr update, we missed a few opportunities: namely, forward, rewind
and sync_ptr.
Formerly calling ack at rewind may have leaded to unexpected results
due to the forgotten negative appl_ptr update in indirect-PCM helper,
which is the major user of the PCM ack callback. But now we fixed
this oversights, thus we can call ack callback safely even at rewind
callback -- of course with the proper handling of the error from the
callback.
This patch adds the calls of ack callback in the places mentioned in
the above.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/core/pcm_native.c | 46 |
1 files changed, 37 insertions, 9 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 889364cbced8..5be549cf91e5 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -2449,13 +2449,35 @@ static int do_pcm_hwsync(struct snd_pcm_substream *substream) | |||
2449 | } | 2449 | } |
2450 | } | 2450 | } |
2451 | 2451 | ||
2452 | /* increase the appl_ptr; returns the processed frames */ | 2452 | /* update to the given appl_ptr and call ack callback if needed; |
2453 | * when an error is returned, take back to the original value | ||
2454 | */ | ||
2455 | static int apply_appl_ptr(struct snd_pcm_substream *substream, | ||
2456 | snd_pcm_uframes_t appl_ptr) | ||
2457 | { | ||
2458 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
2459 | snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr; | ||
2460 | int ret; | ||
2461 | |||
2462 | runtime->control->appl_ptr = appl_ptr; | ||
2463 | if (substream->ops->ack) { | ||
2464 | ret = substream->ops->ack(substream); | ||
2465 | if (ret < 0) { | ||
2466 | runtime->control->appl_ptr = old_appl_ptr; | ||
2467 | return ret; | ||
2468 | } | ||
2469 | } | ||
2470 | return 0; | ||
2471 | } | ||
2472 | |||
2473 | /* increase the appl_ptr; returns the processed frames or a negative error */ | ||
2453 | static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream, | 2474 | static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream, |
2454 | snd_pcm_uframes_t frames, | 2475 | snd_pcm_uframes_t frames, |
2455 | snd_pcm_sframes_t avail) | 2476 | snd_pcm_sframes_t avail) |
2456 | { | 2477 | { |
2457 | struct snd_pcm_runtime *runtime = substream->runtime; | 2478 | struct snd_pcm_runtime *runtime = substream->runtime; |
2458 | snd_pcm_sframes_t appl_ptr; | 2479 | snd_pcm_sframes_t appl_ptr; |
2480 | int ret; | ||
2459 | 2481 | ||
2460 | if (avail <= 0) | 2482 | if (avail <= 0) |
2461 | return 0; | 2483 | return 0; |
@@ -2464,17 +2486,18 @@ static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream, | |||
2464 | appl_ptr = runtime->control->appl_ptr + frames; | 2486 | appl_ptr = runtime->control->appl_ptr + frames; |
2465 | if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) | 2487 | if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) |
2466 | appl_ptr -= runtime->boundary; | 2488 | appl_ptr -= runtime->boundary; |
2467 | runtime->control->appl_ptr = appl_ptr; | 2489 | ret = apply_appl_ptr(substream, appl_ptr); |
2468 | return frames; | 2490 | return ret < 0 ? ret : frames; |
2469 | } | 2491 | } |
2470 | 2492 | ||
2471 | /* decrease the appl_ptr; returns the processed frames */ | 2493 | /* decrease the appl_ptr; returns the processed frames or a negative error */ |
2472 | static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream, | 2494 | static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream, |
2473 | snd_pcm_uframes_t frames, | 2495 | snd_pcm_uframes_t frames, |
2474 | snd_pcm_sframes_t avail) | 2496 | snd_pcm_sframes_t avail) |
2475 | { | 2497 | { |
2476 | struct snd_pcm_runtime *runtime = substream->runtime; | 2498 | struct snd_pcm_runtime *runtime = substream->runtime; |
2477 | snd_pcm_sframes_t appl_ptr; | 2499 | snd_pcm_sframes_t appl_ptr; |
2500 | int ret; | ||
2478 | 2501 | ||
2479 | if (avail <= 0) | 2502 | if (avail <= 0) |
2480 | return 0; | 2503 | return 0; |
@@ -2483,8 +2506,8 @@ static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream, | |||
2483 | appl_ptr = runtime->control->appl_ptr - frames; | 2506 | appl_ptr = runtime->control->appl_ptr - frames; |
2484 | if (appl_ptr < 0) | 2507 | if (appl_ptr < 0) |
2485 | appl_ptr += runtime->boundary; | 2508 | appl_ptr += runtime->boundary; |
2486 | runtime->control->appl_ptr = appl_ptr; | 2509 | ret = apply_appl_ptr(substream, appl_ptr); |
2487 | return frames; | 2510 | return ret < 0 ? ret : frames; |
2488 | } | 2511 | } |
2489 | 2512 | ||
2490 | static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, | 2513 | static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, |
@@ -2610,10 +2633,15 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, | |||
2610 | return err; | 2633 | return err; |
2611 | } | 2634 | } |
2612 | snd_pcm_stream_lock_irq(substream); | 2635 | snd_pcm_stream_lock_irq(substream); |
2613 | if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) | 2636 | if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) { |
2614 | control->appl_ptr = sync_ptr.c.control.appl_ptr; | 2637 | err = apply_appl_ptr(substream, sync_ptr.c.control.appl_ptr); |
2615 | else | 2638 | if (err < 0) { |
2639 | snd_pcm_stream_unlock_irq(substream); | ||
2640 | return err; | ||
2641 | } | ||
2642 | } else { | ||
2616 | sync_ptr.c.control.appl_ptr = control->appl_ptr; | 2643 | sync_ptr.c.control.appl_ptr = control->appl_ptr; |
2644 | } | ||
2617 | if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) | 2645 | if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) |
2618 | control->avail_min = sync_ptr.c.control.avail_min; | 2646 | control->avail_min = sync_ptr.c.control.avail_min; |
2619 | else | 2647 | else |