@@ -42,56 +42,74 @@ static int fill_silence_frames(struct snd_pcm_substream *substream,
4242 *
4343 * when runtime->silence_size >= runtime->boundary - fill processed area with silence immediately
4444 */
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 )
4646{
4747 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 ;
5149 int err ;
5250
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 ;
7251 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 )
7568 return ;
69+ frames = runtime -> silence_threshold - noise_dist ;
7670 if (frames > runtime -> silence_size )
7771 frames = runtime -> silence_size ;
7872 } 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 ;
8299 }
83-
84100 if (snd_BUG_ON (frames > runtime -> buffer_size ))
85101 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 ) {
88106 transfer = ofs + frames > runtime -> buffer_size ? runtime -> buffer_size - ofs : frames ;
89107 err = fill_silence_frames (substream , ofs , transfer );
90108 snd_BUG_ON (err < 0 );
91109 runtime -> silence_filled += transfer ;
92110 frames -= transfer ;
93111 ofs = 0 ;
94- } while ( frames > 0 );
112+ }
95113 snd_pcm_dma_buffer_sync (substream , SNDRV_DMA_SYNC_DEVICE );
96114}
97115
@@ -425,6 +443,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
425443 return 0 ;
426444 }
427445
446+ if (substream -> stream == SNDRV_PCM_STREAM_PLAYBACK &&
447+ runtime -> silence_size > 0 )
448+ snd_pcm_playback_silence (substream , new_hw_ptr );
449+
428450 if (in_interrupt ) {
429451 delta = new_hw_ptr - runtime -> hw_ptr_interrupt ;
430452 if (delta < 0 )
@@ -442,10 +464,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
442464 runtime -> hw_ptr_wrap += runtime -> boundary ;
443465 }
444466
445- if (substream -> stream == SNDRV_PCM_STREAM_PLAYBACK &&
446- runtime -> silence_size > 0 )
447- snd_pcm_playback_silence (substream );
448-
449467 update_audio_tstamp (substream , & curr_tstamp , & audio_tstamp );
450468
451469 return snd_pcm_update_state (substream , runtime );
0 commit comments