/wakamoleguy

Playing a FLAC file over WebRTC with SIP.js and Flac.js

After getting my Raspberry Pi up and running last week, I was really pumped to continue on, find a project, and put it to good use. I spent this weekend exploring the world of Web Audio. Even working with browsers and WebRTC all day at work, I am constantly surprised by the ease with which HTML5 lets you wield a lot of power to do cool things. Here is how to do one thing I learned this weekend: Playing a FLAC file from one computer to another using WebRTC.

What I used:

Update: OnSIP has since removed their developer offering.

  • SIP.js and an OnSIP Developer account
    • This would work using the vanilla WebRTC API as well. I used OnSIP since it's what I'm familiar with (I'm not trying to do a sales pitch here).
  • Flac.js and Aurora.js
    • Put out by Audiocogs, these libraries let you load and play FLAC files in your browser using the Web Audio API. They have several other codecs available as well.
  • A FLAC file to play. I used Coldplay's Sky Full of Stars. The actual song chosen probably doesn't matter.
  • Chrome, for the browser transmitting the FLAC file. Firefox gets finicky about sending certain MediaStreams over WebRTC.

Putting it together

Wiring these pieces up really could not have been much easier. Flac.js and Aurora.js together provide a simple way to preload and decode the FLAC file, and they also spit out events implementing the same interface as SIP.js! Since Aurora.js plays the file using a source context, all we have to do is grab that and connect it to a new MediaStream destination. From there, SIP.js can take the stream and offer it in place of your regularly captured microphone audio.

In the end, the explanation is probably longer than the code itself.

<script src="aurora.js"></script>
<script src="flac.js"></script>
<script src="sip-0.6.3.js"></script>

See the Pen bNbLOx by Will Mitchell (@wakamoleguy) on CodePen.

// Load the FLAC file
window.player = AV.Player.fromURL('http://localhost/path/to/file.flac')
player.preload()

player.on('ready', function () {
  console.log('ready')

  // Aurora doesn't create the audio context until you start playing it.
  player.play()
  player.pause()

  // Wire the WebAudio source and destination together.
  var dest = player.device.device.context.createMediaStreamDestination()
  player.device.device.node.connect(dest)

  // Send the stream to a destination using SIP and WebRTC.
  new SIP.UA()
    .invite('listener@example.onsip.com', { media: { stream: dest.stream } })
    .on('accepted', function () {
      player.play()
    })
})

See the Pen bNbLOx by Will Mitchell (@wakamoleguy) on CodePen.

When you load the page, it will fetch the specified FLAC file and start preloading it, before calling the specified SIP address. I pointed it to my OnSIP address and was able to receive the call in InstaPhone. The call showed up like any normal call, and when I answered it, the music began playing!

What's next?

Playing a FLAC file over WebRTC using under 20 lines of JavaScript! I know I have plans of building some cool things with this. Streaming music from my Pi to my phone? Sure! Preloading my playlist so it can stream even while I am on the subway? You bet! What about you? If you have some crazy ideas, head over to Twitter and share them!

Just remember, if you are playing music over WebRTC, mind the licenses. I plan on sending music only to myself, and only music that I have purchased. I would advise a similar level of copyright caution to any other experimenters.

Cheers!