I have Raspberry Pi hooked up on TV with 2.1 speakers. When I’m on sofa with my notebook, I had to disconnect the audio cable and pull it across the room if I wanted to listen some music on the speakers. I got so agitated I developed a small solution for network audio transmission. In my case this is done from my notebook via Wi-Fi to Raspberry Pi and to speakers.
Application desired functionality:
- transmit audio over wireless network
- one click to enable or disable transmission
- mute the local speakers after enabling the transmission
- capture and transmit all audio on client (even system sounds) without modifying existing applications
- volume control on client
- server must run on low powered devices (Raspberry Pi)
Technology:
- client should be written in C# .NET, because Windows are my primary OS on notebook
- server should be written in Java, because it will run basically everywhere
- transmission protocol will be TCP, because it simplify some implementations. UDP is better and is should be used for low latency application
Server
Server (source) is written in Java. It listens on TCP port, waiting for clients. When client connects, server creates a buffer and fill it with audio stream. This causes a delay in audio playback, but it helps smoothing out the delay that happens due to wireless network latency and gives a client a little more time to send data. It works fine for listening music, but for movies or games we need to develop low latency solution with UDP and a very small buffer (future work). After we fill the buffer on the server, we drain it to audio line. Installation of server is simple. You need to install java and place the server in any directory. Then you can run it with
java -jar PIAudioServer.jar --port 10000 --prebuffer 1000
–prebuffer is the time used for the buffer in milliseconds (I use 1 second, but you can go lower)
Note about Raspberry Pi: you have to enable audio jack if you want to use it. Here is my initialization script:
#!/bin/sh # modprobe snd-bcm2835 amixer cset numid=3 1 # install alsa-utils for this
Client
Client (source code) is written in C# .NET. On windows we can create software audio loopback, just like connecting audio cable from audio out to microphone in. This is done with WASAPI. We can use WasapiLoopbackCapture which is found inside NAudio library. It provides an uncompressed stream of audio in sampling rate of 48.000 Hz and 32 bit depth. Before we can send the stream to the server on Raspberry Pi, we need to process it by reducing bit depth to 16 bit and including the volume.
float sample32 = BitConverter.ToSingle(e.Buffer, index); short sample16 = (short) (sample32 * (32768f * (volume / 100f)));
I have included system tray icon in the client. It shows red icon when client is disabled and green icon when we enable it. It also provides volume control with double click. After we enable the client, it automatically mute all audio on local speakers and redirect it to the server. This is also done with NAudio library.
private static void setMute(Boolean value) { MMDeviceEnumerator devEnum = new MMDeviceEnumerator(); MMDevice defaultDevice = devEnum.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia); defaultDevice.AudioEndpointVolume.Mute = value; }
You must define server IP address and port when running the client. This is done with command line arguments –port and –ip. Installation of the client is simple. Copy executable with naudio.dll anywhere on your computer and place a shortcut with port and ip in windows startup folder. If you have any problems, check out this screenshot.
Developer’s notes:
- never create arrays on the fly in work intensive parts of the code. Allocate them and reuse them in every iteration. Array allocation will give you random delay which causes problems with audio and it’s hard to debug
Future work:
- modify server and client for low latency audio (UDP, smaller buffer)
Attachments:
- Client and source code
- Server and source code
or bitcoin donation: 1AZpTrJbUNHGSaXfG1AwzCxSRRTZGEJQck