Soundboard with Ember.js
I have a friend who’s a pretty fun guy. He’s been sending these bigger-than-life one-liners, small songs and what-not to our gang’s WhatsApp group and we’ve been having a laugh at them over a period of time. They’re mostly alcohol related and heavily tied to the Finnish culture. But I digress.
Looking for these sound clips in our WhatsApp group is tedious. It’s also impossible to anyone except our group. I wanted to make these clips easily available to everyone so I built a quick Ember app called Simo Soundboard just for that, and here’s how I did it.
TL;DR: Quick soundboard
If you just want to build a similar soundboard quickly—and don’t care about my story—you can clone my simo-soundboard GitHub repo, replace the audio files, give each file a nice name, change the secrets, compile the code and deploy it somewhere. And there you go.
Getting started
I picked Ember because I’ve been working with Ember for 3 years and I’m very comfortable working with it. I simply love the workflow you get with ember-cli – even if an app doesn’t need Ember all that much, just like this soundboard didn’t! I used only Ember as there wasn’t any backend stuff required. Just static resources and some client-side logic.
Next, I started creating a mockup of the app in HTML & CSS. Soundboards are usually very simple and I wanted to follow that convention. I also wanted it to work well on mobiles so I started the design with the small screen sizes in mind. I made it responsive so it didn’t look like a stretched up mobile UI on desktop.
The actual Ember part of the app was very simple: just one ApplicationRoute as the root object, a template, and one play-button component that would wrap each sound clip and its logic.
Playing sound
After getting the initial design and the basic Ember app structure done, the next hurdle was to get the browser to play the sound clip. Having worked on Beatstream, I know from experience how tricky playing sound in a wide range of browsers and devices can be. I’ve tested a bunch of different audio playing libraries and my experience is that SoundManager2 does it best. So I pulled that into the app with bower install --save ember-cli-soundmanager-shim
, updated the ember-cli-build.js to include SoundManager2’s files in the build, and made the play-button
component use SM2 to play the audio file it was given. You can see the code in https://github.com/Darep/simo-soundboard/blob/master/app/components/play-button.js.
Deployment with secrets
ember-cli-deploy is another tool that I really like. It’s a “root” addon for creating a deployment pipeline. Basically, you stack a bunch of addons on top of it and they are run on deploy. I wanted to deploy the soundboard onto my cheap RamNode server so I went with rsync and ember-cli-rsync.
Secrets such as passwords, encryption keys and access keys should not be checked into the source code repository. At least not in plain text. I still like to have the secrets in the repo so I encrypt them with EJSON. It’s a Go app/Ruby gem by Shopify and I’ve been using it for a while. I would love to have a JS version of the gem for these JS based apps but none exist so far.
EJSON works simply by encrypting a given JSON file into “encrypted JSON” using a certain private key. Later you can use the same private key to decrypt the EJSON back to regular JSON. I wrote a simple Node.js script to decrypt EJSON which I use in this project as well. It requires the Ruby ejson gem, sadly.
After you have the secrets you can actually deploy. Running ember deploy production
will walk through the ember-cli-deploy chain: build according to build config, create some manifest & revision data, and finally transfer the files to the destination host & directory specified in my secrets.ejson.
Testing in production
After I deployed the app to my server I noticed a usability problem related to bandwidth: there was no indication in the UI (like a loading gif) when a sound clip was being downloaded in the background. The user was just left there hanging wondering if something was going to happen soon. I know Chrome has a network throttling feature and I do use it, but I rarely remember to use it while developing unless I know I’m e.g. fixing a network latency related problem. So deploying and testing in the real production environment revealed a bug I hadn’t thought of. It’s good to deploy early and often to catch stuff like this.
And there you have it. Finished soundboard. “Vois hakkee Vammalasta Kossun” as our friend Simo once said.