ext: alsa: Set buffer time after period time

This because underlying driver may have constraint on
buffer size to be dependent on period size, so period
time needs to be set first.

For e.g. Xilinx ASoC driver requires
buffer size to be multiple of period size for it's DMA
operation.

alsa-utils also set period time first as seen in below commit :
9b621eeac4

Tested it on zcu106 board with HDMI based record and playback.
Also tested on Intel PC using Logitech C920 Webcam mic and ALC887-VD
Analog for playback.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/1040>
This commit is contained in:
Devarsh Thakkar 2021-02-09 05:16:34 -08:00 committed by GStreamer Marge Bot
parent 01d1bbd1da
commit 9759810d82
2 changed files with 85 additions and 34 deletions

View file

@ -492,10 +492,39 @@ retry:
GST_DEBUG_OBJECT (alsa, "periods min %u, max %u", min, max); GST_DEBUG_OBJECT (alsa, "periods min %u, max %u", min, max);
} }
#endif #endif
if (!alsa->iec958) {
/* now try to configure the buffer time and period time, if one /* Following pulseaudio's approach in
* https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/commit/557c4295107dc7374c850b0bd5331dd35e8fdd0f
* we'll try various configuration to set the buffer time and period time as some
* driver can be picky on the order of the calls.
*/
if (buffer_time != -1 && period_time != -1) {
if (((err = snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params,
&buffer_time, NULL)) >= 0)
&& ((err =
snd_pcm_hw_params_set_period_time_near (alsa->handle, params,
&period_time, NULL)) >= 0)) {
GST_DEBUG_OBJECT (alsa, "buffer time %u period time %u set correctly",
buffer_time, period_time);
alsa->buffer_time = buffer_time;
alsa->period_time = period_time;
goto buffer_period_set;
}
if (((err = snd_pcm_hw_params_set_period_time_near (alsa->handle, params,
&period_time, NULL)) >= 0)
&& ((err =
snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params,
&buffer_time, NULL)) >= 0)) {
GST_DEBUG_OBJECT (alsa, "period time %u buffer time %u set correctly",
period_time, buffer_time);
alsa->buffer_time = buffer_time;
alsa->period_time = period_time;
goto buffer_period_set;
}
}
/* now try to configure the buffer time and period time independently, if one
* of those fail, we fall back to the defaults and emit a warning. */ * of those fail, we fall back to the defaults and emit a warning. */
if (buffer_time != -1 && !alsa->iec958) { if (buffer_time != -1) {
/* set the buffer time */ /* set the buffer time */
if ((err = snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params, if ((err = snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params,
&buffer_time, NULL)) < 0) { &buffer_time, NULL)) < 0) {
@ -506,10 +535,10 @@ retry:
buffer_time = -1; buffer_time = -1;
goto retry; goto retry;
} }
GST_DEBUG_OBJECT (alsa, "buffer time %u", buffer_time); GST_DEBUG_OBJECT (alsa, "buffer time %u set correctly", buffer_time);
alsa->buffer_time = buffer_time; alsa->buffer_time = buffer_time;
} }
if (period_time != -1 && !alsa->iec958) { if (period_time != -1) {
/* set the period time */ /* set the period time */
if ((err = snd_pcm_hw_params_set_period_time_near (alsa->handle, params, if ((err = snd_pcm_hw_params_set_period_time_near (alsa->handle, params,
&period_time, NULL)) < 0) { &period_time, NULL)) < 0) {
@ -520,12 +549,11 @@ retry:
period_time = -1; period_time = -1;
goto retry; goto retry;
} }
GST_DEBUG_OBJECT (alsa, "period time %u", period_time); GST_DEBUG_OBJECT (alsa, "period time %u set correctly", period_time);
alsa->period_time = period_time; alsa->period_time = period_time;
} }
} else {
/* Set buffer size and period size manually for SPDIF */ /* Set buffer size and period size manually for SPDIF */
if (G_UNLIKELY (alsa->iec958)) {
snd_pcm_uframes_t buffer_size = SPDIF_BUFFER_SIZE; snd_pcm_uframes_t buffer_size = SPDIF_BUFFER_SIZE;
snd_pcm_uframes_t period_size = SPDIF_PERIOD_SIZE; snd_pcm_uframes_t period_size = SPDIF_PERIOD_SIZE;
@ -534,7 +562,7 @@ retry:
CHECK (snd_pcm_hw_params_set_period_size_near (alsa->handle, params, CHECK (snd_pcm_hw_params_set_period_size_near (alsa->handle, params,
&period_size, NULL), period_size); &period_size, NULL), period_size);
} }
buffer_period_set:
/* write the parameters to device */ /* write the parameters to device */
CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params); CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params);

View file

@ -415,7 +415,29 @@ set_hwparams (GstAlsaSrc * alsa)
GST_DEBUG_OBJECT (alsa, "periods min %u, max %u", min, max); GST_DEBUG_OBJECT (alsa, "periods min %u, max %u", min, max);
} }
#endif #endif
/* Following pulseaudio's approach in
* https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/commit/557c4295107dc7374c850b0bd5331dd35e8fdd0f
* we'll try various configuration to set the buffer time and period time as some
* driver can be picky on the order of the calls.
*/
if (alsa->period_time != -1 && alsa->buffer_time != -1) {
if ((snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params,
&alsa->buffer_time, NULL) >= 0)
&& (snd_pcm_hw_params_set_period_time_near (alsa->handle, params,
&alsa->period_time, NULL) >= 0)) {
GST_DEBUG_OBJECT (alsa, "buffer time %u period time %u set correctly",
alsa->buffer_time, alsa->period_time);
goto buffer_period_set;
}
if ((snd_pcm_hw_params_set_period_time_near (alsa->handle, params,
&alsa->period_time, NULL) >= 0)
&& (snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params,
&alsa->buffer_time, NULL) >= 0)) {
GST_DEBUG_OBJECT (alsa, "period time %u buffer time %u set correctly",
alsa->period_time, alsa->buffer_time);
goto buffer_period_set;
}
}
if (alsa->buffer_time != -1) { if (alsa->buffer_time != -1) {
/* set the buffer time */ /* set the buffer time */
CHECK (snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params, CHECK (snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params,
@ -429,6 +451,7 @@ set_hwparams (GstAlsaSrc * alsa)
GST_DEBUG_OBJECT (alsa, "period time %u", alsa->period_time); GST_DEBUG_OBJECT (alsa, "period time %u", alsa->period_time);
} }
buffer_period_set:
/* write the parameters to device */ /* write the parameters to device */
CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params); CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params);