@@ -42,56 +42,74 @@ static int fill_silence_frames(struct snd_pcm_substream *substream,
42
42
*
43
43
* when runtime->silence_size >= runtime->boundary - fill processed area with silence immediately
44
44
*/
45
- void snd_pcm_playback_silence (struct snd_pcm_substream * substream )
45
+ void snd_pcm_playback_silence (struct snd_pcm_substream * substream , snd_pcm_uframes_t new_hw_ptr )
46
46
{
47
47
struct snd_pcm_runtime * runtime = substream -> runtime ;
48
- snd_pcm_uframes_t appl_ptr = READ_ONCE (runtime -> control -> appl_ptr );
49
- snd_pcm_sframes_t added , hw_avail , frames ;
50
- snd_pcm_uframes_t noise_dist , ofs , transfer ;
48
+ snd_pcm_uframes_t frames , ofs , transfer ;
51
49
int err ;
52
50
53
- added = appl_ptr - runtime -> silence_start ;
54
- if (added ) {
55
- if (added < 0 )
56
- added += runtime -> boundary ;
57
- if (added < runtime -> silence_filled )
58
- runtime -> silence_filled -= added ;
59
- else
60
- runtime -> silence_filled = 0 ;
61
- runtime -> silence_start = appl_ptr ;
62
- }
63
-
64
- // This will "legitimately" turn negative on underrun, and will be mangled
65
- // into a huge number by the boundary crossing handling. The initial state
66
- // might also be not quite sane. The code below MUST account for these cases.
67
- hw_avail = appl_ptr - runtime -> status -> hw_ptr ;
68
- if (hw_avail < 0 )
69
- hw_avail += runtime -> boundary ;
70
-
71
- noise_dist = hw_avail + runtime -> silence_filled ;
72
51
if (runtime -> silence_size < runtime -> boundary ) {
73
- frames = runtime -> silence_threshold - noise_dist ;
74
- if (frames <= 0 )
52
+ snd_pcm_sframes_t noise_dist , n ;
53
+ snd_pcm_uframes_t appl_ptr = READ_ONCE (runtime -> control -> appl_ptr );
54
+ if (runtime -> silence_start != appl_ptr ) {
55
+ n = appl_ptr - runtime -> silence_start ;
56
+ if (n < 0 )
57
+ n += runtime -> boundary ;
58
+ if ((snd_pcm_uframes_t )n < runtime -> silence_filled )
59
+ runtime -> silence_filled -= n ;
60
+ else
61
+ runtime -> silence_filled = 0 ;
62
+ runtime -> silence_start = appl_ptr ;
63
+ }
64
+ if (runtime -> silence_filled >= runtime -> buffer_size )
65
+ return ;
66
+ noise_dist = snd_pcm_playback_hw_avail (runtime ) + runtime -> silence_filled ;
67
+ if (noise_dist >= (snd_pcm_sframes_t ) runtime -> silence_threshold )
75
68
return ;
69
+ frames = runtime -> silence_threshold - noise_dist ;
76
70
if (frames > runtime -> silence_size )
77
71
frames = runtime -> silence_size ;
78
72
} else {
79
- frames = runtime -> buffer_size - noise_dist ;
80
- if (frames <= 0 )
81
- return ;
73
+ /*
74
+ * This filling mode aims at free-running mode (used for example by dmix),
75
+ * which doesn't update the application pointer.
76
+ */
77
+ if (new_hw_ptr == ULONG_MAX ) { /* initialization */
78
+ snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail (runtime );
79
+ if (avail > runtime -> buffer_size )
80
+ avail = runtime -> buffer_size ;
81
+ runtime -> silence_filled = avail > 0 ? avail : 0 ;
82
+ runtime -> silence_start = (runtime -> status -> hw_ptr +
83
+ runtime -> silence_filled ) %
84
+ runtime -> boundary ;
85
+ } else {
86
+ ofs = runtime -> status -> hw_ptr ;
87
+ frames = new_hw_ptr - ofs ;
88
+ if ((snd_pcm_sframes_t )frames < 0 )
89
+ frames += runtime -> boundary ;
90
+ runtime -> silence_filled -= frames ;
91
+ if ((snd_pcm_sframes_t )runtime -> silence_filled < 0 ) {
92
+ runtime -> silence_filled = 0 ;
93
+ runtime -> silence_start = new_hw_ptr ;
94
+ } else {
95
+ runtime -> silence_start = ofs ;
96
+ }
97
+ }
98
+ frames = runtime -> buffer_size - runtime -> silence_filled ;
82
99
}
83
-
84
100
if (snd_BUG_ON (frames > runtime -> buffer_size ))
85
101
return ;
86
- ofs = (runtime -> silence_start + runtime -> silence_filled ) % runtime -> buffer_size ;
87
- do {
102
+ if (frames == 0 )
103
+ return ;
104
+ ofs = runtime -> silence_start % runtime -> buffer_size ;
105
+ while (frames > 0 ) {
88
106
transfer = ofs + frames > runtime -> buffer_size ? runtime -> buffer_size - ofs : frames ;
89
107
err = fill_silence_frames (substream , ofs , transfer );
90
108
snd_BUG_ON (err < 0 );
91
109
runtime -> silence_filled += transfer ;
92
110
frames -= transfer ;
93
111
ofs = 0 ;
94
- } while ( frames > 0 );
112
+ }
95
113
snd_pcm_dma_buffer_sync (substream , SNDRV_DMA_SYNC_DEVICE );
96
114
}
97
115
@@ -425,6 +443,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
425
443
return 0 ;
426
444
}
427
445
446
+ if (substream -> stream == SNDRV_PCM_STREAM_PLAYBACK &&
447
+ runtime -> silence_size > 0 )
448
+ snd_pcm_playback_silence (substream , new_hw_ptr );
449
+
428
450
if (in_interrupt ) {
429
451
delta = new_hw_ptr - runtime -> hw_ptr_interrupt ;
430
452
if (delta < 0 )
@@ -442,10 +464,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
442
464
runtime -> hw_ptr_wrap += runtime -> boundary ;
443
465
}
444
466
445
- if (substream -> stream == SNDRV_PCM_STREAM_PLAYBACK &&
446
- runtime -> silence_size > 0 )
447
- snd_pcm_playback_silence (substream );
448
-
449
467
update_audio_tstamp (substream , & curr_tstamp , & audio_tstamp );
450
468
451
469
return snd_pcm_update_state (substream , runtime );
0 commit comments