Tenderlove Making

Streaming KEXP with Ruby

A while back, I ported JustePort from C# to Ruby so that I could play music on my AirportExpress. The result was a library called raop-client. Unfortunately, after writing that, I found that there were no libraries in Ruby to decode MP3s. So I wrote a wrapper around Lame called icanhasaudio. Right now, it only lets you decode MP3s, but I plan on adding new features soon.

So, I decided to write a little program that will stream music from KEXP to my Airport Express.

require 'rubygems'
require 'raop'
require 'icanhasaudio'
require 'socket'

rd, wr = IO.pipe

decoder = Thread.new(rd, wr) { |read, write|
  reader = Audio::MPEG::Decoder.new
  socket = TCPSocket.new('kexp-mp3-128k.cac.washington.edu', '8000')
  socket.puts("GET / HTTP/1.0\r\n\r\n")
  until(socket.readline == "\r\n"); end
  reader.decode(socket, write);
  write.close
}

sleep 2

raop = Net::RAOP::Client.new('192.168.1.173')
raop.connect
raop.play rd
raop.disconnect
rd.close

decoder.join

I’ll try to explain a little how this works. First I open a pipe which will be used to buffer my decoded mp3. The pipe is passed in to a new thread where my poor mans shoutcast client hooks up to KEXP and starts decoding the mp3 into the pipe.

Meanwhile the main thread waits a couple seconds to make sure there is data in the buffer, connects to the Airport Express, then starts streaming the data from the pipe.

« go back