AngularJS Directive that wraps <audio>
or <video
> tag exposing methods and properties to manipulate your player
examples on github pages: http://colthreepv.github.io/angular-media-player/
This library has reached way more users than expected when I first developed it;
I am very happy of that, but this means it has higher contribution and testing requirements that I was expecting!
From what I could see there's another valid (and quite customizable) project in the angular world: videogular
I don't think it covers ALL the use cases but that is not the point, most of them are covered, and documentation is extensive.
There's an example of using it as audio player with playlist, and the project is definitely future-proof.
I've come across a lot of <audio>
players on the web, many using Flash, many being easy-to-use, almost none of them being compatible with AngularJS.
What i really was looking for was a simple audio wrapper without the need to support browser which don't have audio tag support!
Means support for this project is the same as: HTML5 audio draft, jQuery is not necessary, and DOM manipulation is done only with jqLite (IE9+)
angular-media-player is html/css agnostic, meaning you can use it with your browser controls and default style, or bind the methods and properties in your own View
Using bower:
$ bower install angular-media-player
Using github hosting:
<!-- non-minified for debugging -->
<script src="//colthreepv.github.io/angular-media-player/dist/angular-media-player.js" type="text/javascript"></script>
<!-- minified -->
<script src="//colthreepv.github.io/angular-media-player/dist/angular-media-player.min.js" type="text/javascript"></script>
At the moment IE passes only 8 tests of 20, most of them require an <audio>
tag to work with .ogg
files.
IE supports only .mp3
files, works as expected if you use them.
angular.module
changed AGAIN from'audioPlayer'
to'mediaPlayer'
as the library supports<video>
tag aswell- property
'position'
removed. UsecurrentTime
instead.
If you find something is missing from this list please take a couple of minutes to open an Issue
- I've already written it but...
<video>
tag support! - new property
network
- playback rate support
- seeking
- test-driven: both unit tests and asynchronous tests with real audio/video files (requires internet working)
- playlist handling is way more robust, and tested.
mediaPlayer
is not created as an isolated scope, instead it pollutes the father scope. Watch out for name collisions.- Events are no more sent to
$rootScope
, they are handled by the namespacedmediaPlayer
, that is now an angular.js Scope - Minimalist and flexible event system, based off browser implementation.
The new documentation is on-going work, you can keep track of it being developed, but is not ready to be deployed yet.
And this time will be on gh-pages
!
More tests are coming.
This directive it's just a way to expose HTMLMediaElement properties and methods to an AngularJS application, so you have to use custom html and css in order to interface with the audio directive.
In your AngularJS application include in dependency injection mediaPlayer
angular.module('myApp', ['mediaPlayer'])
.controller('MyController', function ($scope) .......)
Then in the html:
<div ng-controller="MyController">
<audio media-player="audio1" data-playlist="playlist1">
<source src="http://upload.wikimedia.org/wikipedia/en/d/d0/Rick_Astley_-_Never_Gonna_Give_You_Up.ogg" type="audio/ogg">
</audio>
<span ng-show="audio1.playing">Player status: Playing</span>
<span ng-show="!audio1.playing">Player status: Paused</span>
</div>
What happens here: a variable called audio1
gets created on the scope bound to the controller that holds the <audio>
tag.
That might be one of your specific controller, or, if you didn't define anyone, it will be $rootScope
.
You can access those methods like this:
angular.module('myApp').controller('MyController', function ($scope) {
// access properties
console.log($scope.audio1.network);
console.log($scope.audio1.ended);
$scope.mySpecialPlayButton = function () {
$scope.customText = 'I started angular-media-player with a custom defined action!';
$scope.audio1.playPause();
};
})
You can use the methods in the controller AND directly in the HTML (as shown in the snippet before), since they are exposed in the $scope.
media-player
is a directive working as an attribute, it must be used either on an <audio>
, or <video>
tag.
Those can be used as any AngularJS directive attributes notation
- playlist: A string, representing the name in the parent scope containing an Array containing audioElements(s)
- player-control: deprecated: A string, referring to the name created in the parent scope to access
media-player
properties. - media-player: A string, referring to the name created in the parent scope to access
media-player
properties.
Those attributes have a one-way binding, the objects gets allocated in the parent scope.
Playlist is an Array containing sourceElement(s)
.
An sourceElement
itself could be an Array of sourceObjects, or a single sourceObject, mimicking the <source>
HTML draft
sourceObject structure:
{ src: 'http://some.where.com', type: 'mime/type', media: '.css.media.query' }
or alternatively
[
{ src: 'http://some.where.com', type: 'audio/ogg' },
{ src: 'http://some.where.com/lowquality', type: 'audio/ogg' },
{ src: 'http://some.where.com/crapquality', type: 'audio/ogg' },
{ src: 'http://some.where.com', type: 'audio/mpeg' },
]
For whoever wondering what media
is: it's just a css media query, so the browser can pick which <source>
tag to load.
It's recent news that media
it's (probably) getting deprecated anyway
Parameter mediaElement
type object
, structure as specified above.
Parameter autoplay
type boolean
Internal function called from the below methods, can still be accessed directly if want to, if no parameter is provided just calls the <audio>
load method (means it starts buffering).
NOTE: this is 0-based exactly as you refer to the elements of an Array.
Parameter index
type number
, referring to the playlist index (0...playlist.length-1)
You can force to play a specific song using the index
param.
Parameter selectivePlay
type boolean
, when this is true
will be only played the specified track
NOTE: this is 0-based exactly as you refer to the elements of an Array.
Parameter index
type number
, referring to the playlist index (0...playlist.length-1)
If you playPause
the same index twice it will alternate start and stop.
Parameter selectivePlay
type boolean
, when this is true
will be only played the specified track
Pauses the player.
Parameter autoplay
type boolean
Goes to next mediaElement if there is one in the playlist.
Autoplay behaviour is the following:
If a song is already playing, it will change to the next mediaElement, and autoplay itas soon as it's loaded.
You can force the autoplay using the autoplay
parameter.
Parameter autoplay
type boolean
Goes to previous mediaElement if there is one in the playlist.
If a song is already playing, it will change to the previous mediaElement, and autoplay it as soon as it's loaded.
You can force the autoplay using the autoplay
parameter.
Toggles mute property.
Parameter value
type number
This method is a setter for the volume
property.
value
is between 0.0
and 1.0
, refer to MDN.
Parameter value
type number
This method is a setter for the playbackRate
property.
value
is between 0.0
and 1.0
, refer to MDN.
Parameter value
can be type number
or string
This method sets currentTime
on the element.
value
can be between 0.0
and max duration
, or it can be expressed in HH:mm:ss
string format.
Default is audioplayer
, it's the name-prefix used in the Events
true
or false
true
or false
'progress'
, 'stalled'
, 'suspend'
, undefined
(at initialization).
This property is a sum-up of the network state, the value changes when the respective events gets fired.
NOTE: this is 1-based exactly as
length
property of an Array.
Tracks the position of the playing track, it might change during playing the same track due to pushing elements into playlistArray
NOTE: this is 0-based exactly as you refer to the elements of an Array.
Number of tracks in the playlist.
Some properties are just forwarded to the scope, but are unchanged HTMLMediaElement spec
player.currentTime
player.duration
player.muted
player.playbackRate
player.volume
Timeranges:
player.buffered
player.played
player.seekable
Version 0.5.8
has a configurable throttle options.
The default is that timeupdate
event gets throttled to trigger not more than once per second (so currentTime aswell, since it reflects timeupdate
value).
Default value, already inside the library, if you want to change it, copy/paste and change values for your (ENTIRE) application:
angular.module('yourModule')
.value('mp.throttleSettings', {
enabled: true,
time: 1000
});
It can be disabled or enabled with a configurable timeout.
The following properties refer to some HTMLMediaElement spec properties, but are formatted for handiness.
player.formatDuration
hh:mm:ss version of player.duration
player.formatTime
hh:mm:ss version of player.duration
player.loadPercent
0-100 version of player.buffered
, it's just a number, not a TimeRange element.
In case of need you can bind directly to the events generated by the browser.
This is done via wrappers, they just call angular.js jqLite methods:
on (type, fn)
- binds a function to an eventoff (type, fn)
- removes a function from an eventone (type, fn)
- binds a function to an event, once
WARNING: the events are not sent to the $rootScope
anymore. Player namespacing is no more nocessary, thus removed.
Example:
angular.module('myApp',['mediaPlayer'])
.controller('MyController', function ($scope) {
$scope.playerName.on('load', function (evt) {
// Tell someone a song is gonna get loaded.
});
})
You can add/remove tracks on-fly from/to the playlist.
If the current track gets removed, the player goes on pause(). (And starts loading the first track of the new playlist)
Try and get the hold of this in the examples
If you wonder all the logic, just check out the source, it has comments!
A lot of guidelines to realize a simple re-usable project like this have come mainly from:
- angular-leaflet-directive: work of tombatossals, i think is a good example of a standalone project. (other than being useful :) )
- angular-socket-io: I think most of AngularJS developers know Brian Ford, I'm out of count how many times i found his posts or works an enlightenment!
- ng-media: thanks to caitp, I've been trying to merge
mediaPlayer
lib andng-media
togheter, I've learned a lot. In the end, that didn't happen because those projects were born for very different usages.
Contributing is always welcome, both via opening Issues, or compiling a Pull Request.
You can clone the repository and start working:
git clone [email protected]:colthreepv/angular-media-player.git
cd angular-media-player
?!?!?
profit!
To test the documentation system you need to:
npm install
# if you don't have bower installed globally
# sudo npm install bower -g
bower install
# if you don't have grunt installed globally
# sudo npm install grunt-cli -g
grunt docs
# keep grunt executing and open a browser on http://localhost:8181/
To create a new release:
npm install
# test before commit
bower install
npm test
grunt build
git commit -m "release X.Y.Z"
git tag X.Y.Z
git push && git push --tags
- 0.5.8 - implemented a config system for throttling the
timeupdate
events, this functionality is on debate in the issues: #50 - 0.5.6 - fixed several bugs reported by the community (thanks contributors!!!): #44, #29, #27
- 0.5.3 - test coverage run on IE aswell (8/20), just not the playback ones (because tests are written to use .ogg files). bugfix from 0.5.2
- 0.5.2 - fixed bug regarding how i used
angular.forEach
, sorry. (closes #26) - 0.5.1
- added selective play functionality on
play
andplayPause
- seek now works correctly and is tested
- 2 more tests
- added selective play functionality on
- 0.5.0 - complete refactor, tests added,
<video>
tag support. - 0.2.2 - backport from the
next
branch to support IE9-10 - 0.2.0 :
angular.module
changed from'angular-audio-player'
to'audioPlayer'
- seemed more ngCompliant to me- property
'playingTrack'
renamed to'currentTrack'
- again, on first directive tapeout names weren't the most important thing
- 0.1.2 - first release, with basic functionalities