Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
how to handle write_callback API when creating language bindings #28
I've noticed that the write callback is called from a different thread (using WASAPI on a Win7 x64 here). This makes it difficult to bind to dynamic languages (I was about to attempt a LuaJIT binding for instance). Is there anything that can be done about that, like, say a lock/write/unlock API like DirectSound?
How do you push data in the write callback if you can't even use locking primitives?
The safest way to push data to the write callback is to use a ring buffer. libsoundio provides an efficient ring buffer implementation (docs) for your convenience.
luajit is garbage collected, which means that it's generally not real-time safe. This means that the binding code you write in C will probably want to implement the write callback without exposing it directly in the API and do some internal buffering (via a ring buffer probably). Then you can have your lock/write/unlock API on top of that. At this point I would probably implement it without a callback style, but just allow the API user to push sound to or clear the ring buffer, and as long as it has enough sound buffered up you will get no underruns.
Some backends (PulseAudio) have large buffers already. In this situation, your internal buffering can be smaller to compensate. So I suggest calculating the internal buffering size after opening the stream and the
changed the title from
Make libsoundio reentrant
tips on implementing bindings for garbage collected language
Oct 2, 2015
Thanks for answering. I have a few more questions.
In sio_record.c, I see that you use the ring buffer without locking. Does that mean that you can read from it in one thread and write to it in another thread safely without locking? That would solve the issue entirely.
[btw, I don't think garbage collection has anything to do with this, other than adding to the latency -- the problem I have is with the fact that the Lua interpreter state is not re-entrant so I can't enter into it from a callback called from another thread]
Yes :-) The libsoundio ring buffer implementation is a fixed size, one reader, one writer, lock-free queue. It uses atomic integers for the read index and the write index.
I see - let me attempt to rename it again.