More audio options
All code examples are not real code.
My first approach was to just send the audio data with a
uv_async_t handle to the node.js main thread, wrap it in a buffer and call the user provided
Then I took a look at node-libspotify that already has this feature. It buffers the audio data in C++ in a queue (same implementation like the libspotify examples) and calls the musicDelivery callback periodically (every 100ms), emptying the queue into it. I adapted it and it worked. Only at the beginning of a track there where a few chops, then it would catch up.
But I did not really like that approach. The timer to call the callback just feels… hacky. For a long time I didn’t realize why this worked and my implementation not. My mistake was to assume that somehow my chunks were being modified which was not the case. It’s very simple actually:
uv_async_send is not a queue. The handles you send can be executed in any order and I believe even be dropped.
When I wrote the audio data to a file I found a chunk that was in "line" 40 in the working file in "line" 200040 in the corrupt file written with my code. I then inserted a static counter for chunks in C++ and immediately saw that I was missing out a lot of chunks.
So I created a mixture of the two approaches: I buffer the data in C++, too, but will call the callback always when a certain amount of frames is available in the queue. And it works very good.
The implementation of
queue_has_enough_data will maybe have a user settable value.
I will just have to take care of a few more things like pausing, seeking and correct handling of the end of the track/stopping. But a within the next weeks it should be possible to get a stream of audio data from node-spotify.
Leaving pthread for libuv
While browsing to the audio code I also did quite a bit of refactoring. I replaced pthreads with libuv calls. Of course this will use pthreads in the end but it is more consistent. I also hopes this helps with a future Windows build.
A lot of renaming was done since the libspotify guys thought it was a good idea to use very short variable names. I mean,
queue is understandable when you are involved but I believe the four more characters bring more clarity then noise.
Installation flags for native node modules
I have searched for a specific feature of npm/gyp for a long time - how can I enable the user to define installation flags that resolve in preprocessor
#defines? The answer turned out to be very simple, but apparently my google-fu wasn’t good enough. I found it when browsing the code of node-speaker. So I finally added a
--native_audio=true/false flag to node-spotify that allows you to switch the ALSA/OpenAL backend totally of.
How is it done? Have a look:
The % seems to be important, I don’t know why. But it doesn’t work without it. So now I can put code belonging to native audio in
#ifdefs in C/C++ and don’t even compile them when the user doesn’t need them. I guess this also means double the release builds for me…