snd_pcm_playback_silence
1 silence size的设置
在snd_pcm_hw_params时设置,设置的目的时防止读旧数据,出现nosie,只有playback才需要
capture不需要,因为capture data都是充足的,只会出现读数据慢的情况,不会读到旧数据。
silence size的设置有一定的要求:
static int snd_pcm_sw_params(struct snd_pcm_substream *substream, struct snd_pcm_sw_params *params) { struct snd_pcm_runtime *runtime; int err; ... if (params->avail_min == 0) return -EINVAL; if (params->silence_size >= runtime->boundary) { if (params->silence_threshold != 0) return -EINVAL; } else { if (params->silence_size > params->silence_threshold) return -EINVAL; if (params->silence_threshold > runtime->buffer_size) return -EINVAL; } ...
一共有两个地方会call snd_pcm_playback_silence
一个snd_pcm_update_hw_ptr0,
另一个时初始化过程 snd_pcm_start:
static void snd_pcm_post_start(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
runtime->hw_ptr_jiffies = jiffies;
runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) /
runtime->rate;
runtime->status->state = state;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, ULONG_MAX);//第二个实参为ULONG
snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTART);
}
2 snd_pcm_playback_silence
有两个逻辑
逻辑1:
if (runtime->silence_size < runtime->boundary)
清的时app_ptr之后的旧数据,size为设置的silenc_size?
如果runtime->silence_filled >= runtime->buffer_size),表示dma data充足,无需清旧数据。否则数据不足,就清旧数据
逻辑2:
是else flow
是清old hw_ptr和new hw_ptr之间的数据,就是旧数据。
void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t frames, ofs, transfer; int err; if (runtime->silence_size < runtime->boundary) { snd_pcm_sframes_t noise_dist, n; snd_pcm_uframes_t appl_ptr = READ_ONCE(runtime->control->appl_ptr); if (runtime->silence_start != appl_ptr) { n = appl_ptr - runtime->silence_start; if (n < 0) n += runtime->boundary; if ((snd_pcm_uframes_t)n < runtime->silence_filled) runtime->silence_filled -= n; else runtime->silence_filled = 0; runtime->silence_start = appl_ptr; } if (runtime->silence_filled >= runtime->buffer_size)//表示dma data充足,无需清旧数据,否则就清旧数据 return; noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled; if (noise_dist >= (snd_pcm_sframes_t) runtime->silence_threshold) return; frames = runtime->silence_threshold - noise_dist; if (frames > runtime->silence_size) frames = runtime->silence_size; } else { if (new_hw_ptr == ULONG_MAX) { /* initialization */ //初始化时走的flow,snd_pcm_start call的 snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail(runtime); if (avail > runtime->buffer_size) avail = runtime->buffer_size; runtime->silence_filled = avail > 0 ? avail : 0; runtime->silence_start = (runtime->status->hw_ptr + runtime->silence_filled) % runtime->boundary; } else {//非出初始化走的flow ofs = runtime->status->hw_ptr; frames = new_hw_ptr - ofs; if ((snd_pcm_sframes_t)frames < 0) frames += runtime->boundary; runtime->silence_filled -= frames; if ((snd_pcm_sframes_t)runtime->silence_filled < 0) { runtime->silence_filled = 0; runtime->silence_start = new_hw_ptr; } else { runtime->silence_start = ofs; } } frames = runtime->buffer_size - runtime->silence_filled; } if (snd_BUG_ON(frames > runtime->buffer_size)) return; if (frames == 0) return; ofs = runtime->silence_start % runtime->buffer_size; while (frames > 0) { transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames; err = fill_silence_frames(substream, ofs, transfer);//填0清旧数据 snd_BUG_ON(err < 0); runtime->silence_filled += transfer; frames -= transfer; ofs = 0; } }
行胜于言,自强不息。

浙公网安备 33010602011771号