At Fri, 13 Jun 2008 16:25:26 +0200, Lennart Poettering wrote:
On Fri, 13.06.08 08:59, Takashi Iwai (tiwai@suse.de) wrote:
About the latency, my proposal is like below:
Renew the definition of hwptr -- make it what you imagned, the pointer where hardware is reading or has read.
This won't change anything for PCI drivers, so the impact is minimal.
And it would suddenly make the USB drivers do the right thing ;-)
This alone wouldn't :)
OTOH I am not a big fan of this solution, since the delay in "snd_pcm_delay()" kind of suggests that it is useful for time synchronization.
Yes, snd_pcm_delay() is the API for synchronization, as even now it explicitly defines as the delay from the position currently being played.
Add some new API functions,
To give the accuracy of the position inquiry (optional)
This requires some new kernel <-> user-space stuff.
I'd really like to have this. Only when I know this I can know how near to the current hw_ptr I can actually still make changes in the playback buffer.
One question is what quantity should it be. In most cases, it's simply a flag -- that is, the hwptr is updated only at the period boundary. But, this isn't maybe appropriate, e.g. if we introduce the stream control via (hr)timer.
To query the known latency
Ditto, or we may reuse snd_pcm_hw_params_fifo_size()?
I am not a fan of snd_pcm_hw_params_fifo_size() because the 'fifo' latency is dynamic in the network case, it changes all the time with the level of network congestion. However if something is part of hw_params it is supposed to stay fixed, right?
Hence I'd rather prefer if we let snd_pcm_hw_params_fifo_size() rest in peace.
Agreed. A new API sounds saner to me.
My personal favourite solution would actually be to have a new call that allows you to query *all* timing related values *atomically*. Why? different programs need different timing information from ALSA. Also, timing information happens to change all the time. If we just export two basic values, than people might end up doing arithmetics on them, in the risk the two values are not consistent with each other, since between querying them some time already passed. So, what I would suggest is this:
typedef enum snd_pcm_timing { SND_PCM_TIMING_ABSOLUTE_WRITE, SND_PCM_TIMING_ABSOLUTE_READ, SND_PCM_TIMING_ABSOLUTE_HEAR, SND_PCM_TIMING_WRITE_TO_READ, SND_PCM_TIMING_WRITE_TO_HEAR, SND_PCM_TIMING_READ_TO_HEAR, SND_PCM_TIMING_CAN_WRITE, SND_PCM_TIMING_LEFT_TO_PLAY } snd_pcm_timing_t;
snd_pcm_sframes_t snd_pcm_get_timing(snd_pcm_t *pcm, snd_pcm_timing_t timing);
The user would just pass which of the timing values he needs. The meaning would be:
ABSOLUTE_WRITE: the current absolute write counter in samples, since the device was opened. ABSOLUTE_READ: the current absolute read counter in samples, since the device was opened. ABSOLUTE_HEAR: the current absolute hear counter in samples, since the device was opened. WRITE_TO_READ: the current fill level of the playback buffer WRITE_TO_HEAR: if i write a sample immediately after this call, how much time takes it to be played. READ_TO_HEAR: the 'fifo' latency, i.e. the time that passes after a sample was read form the playback buffer that it is actually played. CAN_WRITE: how much can be written into the buffer right now (buffer_size - WRITE_TO_READ) LEFT_TO_PLAY: similar to WRITE_TO_HEAR but callable *after* we wrote something, and it will return how much of what we wrote has not been heard yet. In contrast to WRITE_TO_HEAR this will return 0 eventually.
Hmm... at a first glance, this already looks complicated.
What about just providing three pointers: curr_ptr, hw_ptr and appl_ptr? curr_ptr corresponds to the point being played, and hw_ptr is the point where the data was already sent to h/w, and appl_ptr is the point where the data is filled by user. The above definitions are all combinations of these pointers.
I really don't understand why we need to hide hw_ptr and appl_ptr in the current API. To me, exposing these points is much more straightforward.
In addition, there will be an API to provide the position granularity as mentioned in the above. But, this can be a different thing from the pointer APIs.
Takashi