[alsa-devel] period_size and relation to number of samples
Hello,
one question: If my driver announces the setting below[1], how many samples must an application provide in a single snd_pcm_writei() or snd_pcm_mmap_writei() call?
Shouldn't it always send 8192 bytes or 2048 left and right samples (4096 in total) or is it free to send more or less?
Logging data in my chip_playback_copy() function shows the following (S16_LE, RW_INTERLEAVED):
,----[ mplayer, aplay: ] | chip_playback_copy (0 -> src: 0xffce1000, #bytes: 0x4000) | chip_playback_copy (1 -> src: 0xffce1000, #bytes: 0x2000) | chip_playback_copy (1 -> src: 0xffce1000, #bytes: 0x2000) `----
,----[ alsaplayer: ] | chip_playback_copy (0 -> src: 0xffce1000, #bytes: 0x2000) | chip_playback_copy (0 -> src: 0xffce3000, #bytes: 0x2000) | chip_playback_copy (0 -> src: 0xffce3000, #bytes: 0x2000) | [...] `----
Thus mplayer and aplay provide 16384 bytes (4096 l/r samples) in the first call and 8192 bytes (2048 l/r samples) for all subsequent calls. However, alsaplayer provides 8192 bytes (2048 l/r samples) for all calls.
Now, what is an application allowed to send and what not? For example, could an application only send 1024 l/r samples and is the driver responsible for buffering the data? Or must it obey the announced period_size and *always* provide 2048 l/r samples?
Thanks.
,----[ 1 ] | stream : PLAYBACK | access : RW_INTERLEAVED | format : S16_LE | subformat : STD | channels : 2 | rate : 44100 | exact rate : 44100 (44100/1) | msbits : 16 | buffer_size : 4096 | period_size : 2048 | period_time : 46439 | tick_time : 10000 | tstamp_mode : NONE | period_step : 1 | sleep_min : 0 | avail_min : 2048 | xfer_align : 1 | start_threshold : 2048 | stop_threshold : 4096 | silence_threshold: 0 | silence_size : 0 | boundary : 1073741824 | start_mode: DATA | xrun_mode: STOP | tstamp_mode: NONE | period_step: 1 | sleep_min: 0 | avail_min: 2048 | xfer_align: 1 | silence_threshold: 0 | silence_size: 0 | boundary: 1073741824 `----
Regards, Markus Korber
At Thu, 06 Sep 2007 07:52:37 +0200, Markus Korber wrote:
Hello,
one question: If my driver announces the setting below[1], how many samples must an application provide in a single snd_pcm_writei() or snd_pcm_mmap_writei() call?
Shouldn't it always send 8192 bytes or 2048 left and right samples (4096 in total) or is it free to send more or less?
The transfer size is aligned to xfer_align, but besides that, it's free for apps.
Logging data in my chip_playback_copy() function shows the following (S16_LE, RW_INTERLEAVED):
,----[ mplayer, aplay: ] | chip_playback_copy (0 -> src: 0xffce1000, #bytes: 0x4000) | chip_playback_copy (1 -> src: 0xffce1000, #bytes: 0x2000) | chip_playback_copy (1 -> src: 0xffce1000, #bytes: 0x2000) `----
,----[ alsaplayer: ] | chip_playback_copy (0 -> src: 0xffce1000, #bytes: 0x2000) | chip_playback_copy (0 -> src: 0xffce3000, #bytes: 0x2000) | chip_playback_copy (0 -> src: 0xffce3000, #bytes: 0x2000) | [...] `----
Thus mplayer and aplay provide 16384 bytes (4096 l/r samples) in the first call and 8192 bytes (2048 l/r samples) for all subsequent calls. However, alsaplayer provides 8192 bytes (2048 l/r samples) for all calls.
Now, what is an application allowed to send and what not? For example, could an application only send 1024 l/r samples and is the driver responsible for buffering the data? Or must it obey the announced period_size and *always* provide 2048 l/r samples?
No, as mentioned, the app is free to send any size in general. When the period size is filled up, basically it's supposed to be playable. But, the procedure "fill the whole buffer then start" is the most robust way.
The period size is the minimal chunk size that controls the poll frequency. So, it's natural to send in this size. It's no requirement but a common use case.
Takashi
Thanks.
,----[ 1 ] | stream : PLAYBACK | access : RW_INTERLEAVED | format : S16_LE | subformat : STD | channels : 2 | rate : 44100 | exact rate : 44100 (44100/1) | msbits : 16 | buffer_size : 4096 | period_size : 2048 | period_time : 46439 | tick_time : 10000 | tstamp_mode : NONE | period_step : 1 | sleep_min : 0 | avail_min : 2048 | xfer_align : 1 | start_threshold : 2048 | stop_threshold : 4096 | silence_threshold: 0 | silence_size : 0 | boundary : 1073741824 | start_mode: DATA | xrun_mode: STOP | tstamp_mode: NONE | period_step: 1 | sleep_min: 0 | avail_min: 2048 | xfer_align: 1 | silence_threshold: 0 | silence_size: 0 | boundary: 1073741824 `----
Regards, Markus Korber _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
Takashi Iwai schrieb:
At Thu, 06 Sep 2007 07:52:37 +0200, Markus Korber wrote:
[...] Now, what is an application allowed to send and what not? For example, could an application only send 1024 l/r samples and is the driver responsible for buffering the data? Or must it obey the announced period_size and *always* provide 2048 l/r samples?
No, as mentioned, the app is free to send any size in general. When the period size is filled up, basically it's supposed to be playable. But, the procedure "fill the whole buffer then start" is the most robust way.
The period size is the minimal chunk size that controls the poll frequency. So, it's natural to send in this size. It's no requirement but a common use case.
Thus, is it possible to buffer the data in ALSA before sending them to the driver, in such a way, that the driver always receives period_size samples, regardless of what the application sends to ALSA? And how would I configure ALSA for such a setup?
Regards, Markus Korber
At Thu, 06 Sep 2007 16:30:17 +0200, Markus Korber wrote:
Takashi Iwai schrieb:
At Thu, 06 Sep 2007 07:52:37 +0200, Markus Korber wrote:
[...] Now, what is an application allowed to send and what not? For example, could an application only send 1024 l/r samples and is the driver responsible for buffering the data? Or must it obey the announced period_size and *always* provide 2048 l/r samples?
No, as mentioned, the app is free to send any size in general. When the period size is filled up, basically it's supposed to be playable. But, the procedure "fill the whole buffer then start" is the most robust way.
The period size is the minimal chunk size that controls the poll frequency. So, it's natural to send in this size. It's no requirement but a common use case.
Thus, is it possible to buffer the data in ALSA before sending them to the driver, in such a way, that the driver always receives period_size samples, regardless of what the application sends to ALSA? And how would I configure ALSA for such a setup?
No, it's NOT guaranteed. The application may behave in a very wrong manner.
The point is that it's driver's responsibility to check whether the data filled is OK or not. The ALSA framework is not a style like "fill -> wakeup -> process". Instead, the data transfer is done asynchronously, and the driver is woken up via irq (or whatever).
Takashi
Thus spake Takashi Iwai:
At Thu, 06 Sep 2007 16:30:17 +0200, Markus Korber wrote:
Thus, is it possible to buffer the data in ALSA before sending them to the driver, in such a way, that the driver always receives period_size samples, regardless of what the application sends to ALSA? And how would I configure ALSA for such a setup?
No, it's NOT guaranteed. The application may behave in a very wrong manner.
The point is that it's driver's responsibility to check whether the data filled is OK or not. The ALSA framework is not a style like "fill -> wakeup -> process". Instead, the data transfer is done asynchronously, and the driver is woken up via irq (or whatever).
Thanks for clarification. However, one more question: The application always delivers 0x1200 bytes to ALSA via snd_pcm_mmap_writei() but my driver receives the following (buffer_size=0x4000, period_size=0x2000):
(bufnum refers to buffer 0 or 1 of my two output buffers.)
,----[ 0 ] | Entered chip_playback_copy (bufnum: 0 -> src: 0xffce1000, bytes: 0x2400) | Entered chip_playback_copy (bufnum: 0 -> src: 0xffce3400, bytes: 0x1200) | | Entered chip_playback_copy (bufnum: 1 -> src: 0xffce4600, bytes: 0x0a00) | Entered chip_playback_copy (bufnum: 1 -> src: 0xffce1000, bytes: 0x0800) | Entered chip_playback_copy (bufnum: 1 -> src: 0xffce1800, bytes: 0x1200) | | Entered chip_playback_copy (bufnum: 0 -> src: 0xffce2a00, bytes: 0x1200) | Entered chip_playback_copy (bufnum: 0 -> src: 0xffce3c00, bytes: 0x1200) | | Entered chip_playback_copy (bufnum: 1 -> src: 0xffce4e00, bytes: 0x0200) | Entered chip_playback_copy (bufnum: 1 -> src: 0xffce1000, bytes: 0x1000) | | Entered chip_playback_copy (bufnum: 0 -> src: 0xffce2000, bytes: 0x1200) | Entered chip_playback_copy (bufnum: 0 -> src: 0xffce3200, bytes: 0x1200) | | Entered chip_playback_copy (bufnum: 1 -> src: 0xffce4400, bytes: 0x0c00) | Entered chip_playback_copy (bufnum: 1 -> src: 0xffce1000, bytes: 0x0600) | Entered chip_playback_copy (bufnum: 1 -> src: 0xffce1600, bytes: 0x1200) `----
Now, I'm using the pcm-indirect framework[1] and my hw_ptr always toggles between 0 and period_bytes[2].
,----[ 1 ] | static snd_pcm_uframes_t | chip_pcm_pointer(struct snd_pcm_substream *substream) | { | ... | return snd_pcm_indirect_playback_pointer(substream, &chip->playback, | prtd->playback_hw_ptr); | } `----
,----[ 2 ] | if (bufnum == 0) | prtd->playback_hw_ptr = 0; | else | prtd->playback_hw_ptr = prtd->period_bytes; `----
This is what the application does[3] (for logging see [4]):
,----[ 3 ] | while( number_of_frames > 0) { | if ( (state == SND_PCM_STATE_RUNNING) ) { | snd_pcm_status(this->audio_fd, pcm_stat); | | num_avail = snd_pcm_status_get_avail(pcm_stat); | printf("audio_alsa_out: #avail: %#04x\n", num_avail); | | if (num_avail < number_of_frames) { | wait_result = snd_pcm_wait(this->audio_fd, 1000); | printf("audio_alsa_out:write:loop:wait_result=%d\n",wait_result); | if (wait_result <= 0) return 0; | } | } | | printf ("audio_alsa_out: writing %#04x samples to ALSA\n", number_of_frames); | result = snd_pcm_mmap_writei(this->audio_fd, buffer, number_of_frames); | ... `----
_From my understanding the application blocks until it can send new data. However, although the application always delivers 0x1200 bytes to ALSA, my driver receives different amount of data. Why? Is there some buffering in ALSA?
Secondly, although my period_size is 0x2000 bytes, why do I receive for example 0x0a00+0x0800+0x1200=0x2400 bytes (see [0]) or 0x1200 bytes and not at most 0x2000 bytes?
Thirdly, how is the value returned by snd_pcm_status_get_avail() determined? I mean, if my pointer always toggles between 0 and period_bytes[2], how can ALSA return the values logged below [4]?
(Here 1 sample equals 4 bytes, S16_LE, stereo.)
,----[ 4 ] | loop: writing 0x480 samples to sound device | audio_alsa_out: writing 0x480 samples to ALSA | | loop: writing 0x480 samples to sound device | audio_alsa_out: writing 0x480 samples to ALSA | | loop: writing 0x480 samples to sound device | audio_alsa_out: #avail: 0x700 | audio_alsa_out: writing 0x480 samples to ALSA | | loop: writing 0x480 samples to sound device | audio_alsa_out: #avail: 0xa80 | audio_alsa_out: writing 0x480 samples to ALSA | | loop: writing 0x480 samples to sound device | audio_alsa_out: #avail: 0xe00 | audio_alsa_out: writing 0x480 samples to ALSA | | loop: writing 0x480 samples to sound device | audio_alsa_out: #avail: 0x980 | audio_alsa_out: writing 0x480 samples to ALSA | | loop: writing 0x480 samples to sound device | audio_alsa_out: #avail: 0x500 | audio_alsa_out: writing 0x480 samples to ALSA | | loop: writing 0x480 samples to sound device | audio_alsa_out: #avail: 0x80 | audio_alsa_out: writing 0x480 samples to ALSA | | loop: writing 0x480 samples to sound device | audio_alsa_out: #avail: 0x400 | audio_alsa_out: writing 0x480 samples to ALSA | | loop: writing 0x480 samples to sound device | audio_alsa_out: #avail: 0x780 | audio_alsa_out: writing 0x480 samples to ALSA `----
Thanks in advance.
Regards, Markus Korber
participants (2)
-
Markus Korber
-
Takashi Iwai