This matches what we're already calling the server-side subclasses
better, though we'll probably want to find some better names for the
client-side classes eventually.
Client-side connection objects must now provide both client and server
endpoint types. When a message is received from the server side, we try
to decode it using both endpoint types and then send it to the right
place for handling.
This now makes it possible for AudioServer to send unsolicited messages
to its clients. This opens up a ton of possibilities :^)
This patch adds muting to ASMixer, which works by substituting what we
would normally send to the sound card with zero-filled memory instead.
We do it this way to ensure that the queued sample buffers keep getting
played (silently.)
This is obviously not the perfect way of doing this, and in the future
we should improve on this, and also find a way to utilize any hardware
mixing functions in the sound card.
LibAudio now supports pausing playback, clearing the buffer queue,
retrieving the played samples since the last clear and retrieving
the currently playing shared buffer id
This is a variant of the enqueue() API that returns immediately and
may fail. It's useful when you don't want to block until the audio
server can receive your sample buffer.
Fork the IPC Connection classes into Server:: and Client::ConnectionNG.
The new IPC messages are serialized very snugly instead of using the
same generic data structure for all messages.
Remove ASAPI.h since we now generate all of it from AudioServer.ipc :^)
Give the mixer a main volume value (percent) that we scale all the
outgoing samples by (before clipping.)
Also add a simple "avol" program for querying and setting the volume:
- "avol" prints the current volume.
- "avol 200" sets the main mix volume to 200%
Each client connection now sets up an ASBufferQueue, which is basically a
queue of ABuffers. This allows us to immediately start streaming the next
pending buffer whenever our current buffer runs out of samples.
This makes the majority of the skippiness go away for me. :^)
Also get rid of the old PlayBuffer API, since we don't need it anymore.
I had to solve a bunch of things simultaneously to make this work.
Refactor AWavLoader to be a streaming loader rather than a one-shot one.
The constructor parses the header, and if everything looks good, you can
repeatedly ask the AWavLoader for sample buffers until it runs out.
Also send a message from AudioServer when a buffer has finished playing.
That allows us to implement a blocking variant of play().
Use all of this in aplay to play WAV files chunk-at-a-time.
This is definitely not perfect and it's a little glitchy and skippy,
but I think it's a step in the right direction.
Sticking these in a namespace allows us to use a more generic
("Connection") term without clashing, which is way easier to understand
than to try to come up with unique names for both.
As a consequence, move to use an explicit handshake() method rather than
calling virtuals from the constructor. This seemed to not bother
AClientConnection, but LibGUI crashes (rightfully) because of it.
The center of this is now an ABuffer class in LibAudio.
ABuffer contains ASample, which has two channels (left/right) in
floating point for mixing purposes, in 44100hz.
This means that the loaders (AWavLoader in this case) needs to do some
manipulation to get things in the right format, but that we don't need
to care after format loading is done.
While we're at it, do some correctness fixes. PCM data is unsigned if
it's 8 bit, but 16 bit is signed. And /dev/audio also wants signed 16
bit audio, so give it what it wants.
On top of this, AudioServer now accepts requests to play a buffer.
The IPC mechanism here is pretty much a 1:1 copy-paste from
LibGUI/WindowServer. It can be generalized more in the future, but for
now I want to get AudioServer working decently first :)
Additionally, add a little "aplay" tool to load and play a WAV file. It
will break with large WAVs (run out of memory, heh...) but it's a start.
Future work needs to make AudioServer block buffer submission from
clients until it has played the buffer they are requesting to play.
* Add a LibAudio, and move WAV file parsing there (via AWavFile and AWavLoader)
* Add CLocalSocket, and CSocket::connect() variant for local address types.
We make some small use of this in WindowServer (as that's where we
modelled it from), but don't get too invasive as this PR is already
quite large, and the WS I/O is a bit carefully done
* Add an AClientConnection which will eventually be used to talk to
AudioServer (and make use of it in Piano, though right now it really
doesn't do anything except connect, using our new CLocalSocket...)