Hi,
I would like to write a simple alsa io plugin that takes some amount of PCM samples and sends them to a socket in a timely manner (this would be playback). Later on it should work the other way round as well (recording). (Well, actually I have been working on this for a month already but so far I still did not manage to get a working solution.)
However, if the PCM stream comes from something prerecorded (i.e. a wav file) there needs to be some kind of delay. If for example the wav file would have a sampling rate of 8 kHz, 16 bit resolution and one period should consist of 160 samples, it would be necessary to write on period exactly each 20ms. For this reason delay needs to be added somewhere so that each 20ms exactly one period is begin sent to the socket. Otherwise all the PCM samples would be just immediately written to the socket without any delay.
I read a lot of other alsa plugin code but still I have found no way to properly solve the delay problem.
* Where and how do I need to add delay ??
My first approach was to add delay by sleeping in the transfer callback function. After I had implemented that solution (and it did not work that well) I was told that this is not the proper way to do it.
* What is the proper way then ?
I was told that the alsa plugin framework is poll based and I should come up with a poll based solution. However, I can not just let the alsa io plugin poll for POLLOUT on the socket as this would not add any delay at all. (It would just wait until new data can be written to the socket.)
After looking at the bluetooth alsa plugin I came up with another idea (and my second approach):
Basically it should be possible to create an independent timing thread in the alsa plugin that writes dummy data (e.g. a single byte) to a pipe each period (thus in my case each 20ms).
The plugin would then poll for POLLIN on the above mentioned pipe and poll for POLLOUT on the socket at the same time. This way the transfer callback function would be called if and only if the following two conditions are met:
* 20 ms period time has passed * the socket can accept new data
* Would this solution be the proper way ?
Another solution (my third one already) would be to introduce *no* delay in the alsa plugin itself, but do everything in the application that is listening on the socket. For this reason the application would read one period, process the data and then sleep for the rest of the time until the time for one period (i.e. 20ms) is over. After that the next period is read from the socket and so forth. The alsa plugin would then "automatically" write new data to the socket each time the application listening to that socket reads data and there is free space in the socket send buffer.
* Once again, would this be a proper solution ?
* If so, how do I know when to increment the hardware pointer ? (- After the send() call in the transfer callback function ? - Using an independent thread in the plugin that just increments the hardware pointer each 20ms ?) - something even more complex ?)
My guess is that the third solution (delay is added in the application that listens to the socket) might work well as the delay is added at the end of the "audio processing chain" which makes it less sensitive to delays that are introduced in between.
* Is this correct ?
I would appreciate any help as I have invested way too much time in this already.
cheers, stefan