aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2017-05-19 14:22:33 -0400
committerTakashi Iwai <tiwai@suse.de>2017-05-25 17:34:47 -0400
commit9027c4639ef1e3254779e3033f229133222445f7 (patch)
tree93d246fb50663aa6c6db6e7a8b4f99b7fcfcf439
parent9ce7b9cf64dc1a48a074033a83c8ea314b38540c (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.c46
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 */
2455static 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 */
2453static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream, 2474static 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 */
2472static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream, 2494static 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
2490static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, 2513static 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