Continuing the experimentation with cool libraries and ember this time I’ll use SoundManager2, a really useful sound playing library for HTML5 and/or Flash that is compatible with most browsers out there.
It is not very hard to use and it has a pretty decent documentation, what I’ll show is a very simple usage of it that I plan to improve in the future, but this should give an idea on how to start at least.
My app has a Song
model that contains a url
property, there is a ‘songs’ route that lists the songs and a ‘song’ route that shows the player for a given song.
Let’s start by including SoundManager2 into our app, grab your copy from their website, the downloaded zipfile will have several folders, look for soundmanager2.js
in the script
folder and soundmanager2_debug.swf
in the swf folder. You’ll want to change this to the nodebug version when you’re going production.
Once we did that we need to initialize soundmanager with our app. We do that by adding an initializer:
App.initializer({
name: "soundmanager",
initialize: function() {
soundManager.setup({
url: '/swf'
});
}
});
Note the ‘/swf’ path there, that’s where you put the swf file, update accordingly. This initializer will setup soundmanager with all the default options, you can override them by adding more properties to the setup function call. Please refer to the documentation.
Alright, now that we have everything in place we can use soundmanager to manage our sounds. I said that I have a route for each ‘song’ so let’s start by adding the template for that route.
<script type="text/x-handlebars" id="song">
<button class="btn" {{action 'playPause'}}>{{playPauseLink}}</button>
<button class="btn" {{action 'stop'}} {{bindAttr disabled="unstarted"}}>Stop</button>
</script>
This template has some stuff in it, let’s start by looking at the ‘playPause’ button, it’s content is a variable ‘playPauseLink’, we expect that to be either “Play” or “Pause” depending on the current state of the player, and it’s action is ‘playPause’ which will toggle the two.
Let’s take a look at ‘playPauseLink’:
App.SongController = Ember.ObjectController.extend({
// …
playPauseLink: function() {
if (this.get('playing')) {
return 'Pause';
} else {
return 'Play'
}
}.property('playing'),
// …
});
Our controller have a property ‘playing’ which is a boolean for whether the song is playing or not, we use that to compute the play/pause link text with a binding, so it will stay up to date automatically. Now let’s see the playPause action:
App.SongController = Ember.ObjectController.extend({
// ...
playPause: function() {
if (this.get('playing')) {
this.pause();
} else {
this.play();
}
},
play: function() {
var sound = this.get('sound');
if (this.get('unstarted')) {
sound.play();
this.set('started', true);
} else {
sound.resume();
}
this.set('playing', true);
},
pause: function() {
this.get('sound').pause();
this.set('playing', false);
},
// …
Now I’m showing you 3 methods, one is the actual action ‘playPause’, that will call either play or pause depending on the current state of the player, play and pause will set the ‘playing’ state accordingly. Play will either ‘play’ or ‘resume’ depending on whether the player has started or not, we use the property ‘started’ and it’s counterpart ‘unstarted’ for that purpose.
That’s all great but it will do nothing if we don’t load the sound first, we have to do that after soundmanager is ready and the template is inserted, let’s do that in our ‘SongView’ on the ‘didInsertElement’ callback.
App.SongView = Ember.View.extend({
didInsertElement: function() {
var self = this;
soundManager.onready(function() {
self.get('controller').send('loadSound');
});
}
});
Note that we’re calling the ‘loadSound’ method in our controller once soundmanager is ready:
App.SongController = Ember.ObjectController.extend({
// ...
loadSound: function() {
var self = this;
var sound = soundManager.createSound({
url: this.get('url'),
onfinish: function() { self.finish(); }
});
this.set('sound', sound);
},
Loading the sound is as simple as following the soundmanager’s documentation, create a sound passing in the ‘url’ property from our model. We set the ‘onfinish’ callback to reset the player once the sound is over. We’re also missing the ‘stop’ functionality that we have on the template:
App.SongController = Ember.ObjectController.extend({
// ...
finish: function() {
this.set('playing', false);
this.set('started', false);
},
stop: function() {
this.get('sound').stop();
this.finish();
},
‘finish’ is just resetting the states, stop is calling stop on our sound object and then resetting the state by calling finish.
That is about the simplest play/pause/stop player I could think of using soundmanager, I published the full code for this simple implementaiton on this Gist. It has a little bit more to it like position/duration but it’s pretty much what I wrote above.
Library versions used in the post:
- Ember.js: 1.0.0-rc.5
- Handlebars: 1.0.0-rc.4
- Ember Data: 0.13
- jQuery: 1.9.1
- SoundManager2: 2.97a.20130512