├── README.md
├── amrnb.js
└── amrplayer.js
/README.md:
--------------------------------------------------------------------------------
1 | amr-player
2 | play remote amr format audio with JavaScript
3 |
4 | inpired by https://github.com/yxl/opencore-amr-js
5 |
6 | -- AmrPlayer --
7 |
8 | params:
9 | >amr_url
10 | >download_success_cb (optional)
11 | >download_progress_cb (optional)
12 |
13 | props:
14 | >bool canPlay
15 | >bool isPlaying
16 |
17 | methods:
18 | >play()
19 | >pause()
20 | >toggle() // play() when paused or pause() when playing
21 | >endWith(callback) // optional, fire callback with ended event
22 |
23 | usage:
24 |
25 |
26 |
27 | var player = new AmrPlayer('http://xxx.com/xxx.amr');
28 | player.endWith(function(){ console.log( xxx ) });
29 | player.play();
30 | // or player.pause();
31 | // or player.toggle();
32 |
--------------------------------------------------------------------------------
/amrplayer.js:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * -- AmrPlayer --
4 | * params:
5 | * 1. amr_url
6 | * 2. download_success_cb (optional)
7 | * 3. download_progress_cb (optional)
8 | * props:
9 | * 1. bool canPlay
10 | * 2. bool isPlaying
11 | * methods:
12 | * 1. play()
13 | * 2. pause()
14 | * 3. toggle() // play() when paused or pause() when playing
15 | * 3. endWith(callback) // fire callback with ended event
16 | * */
17 | var AmrPlayer = function(amr_url, download_success_cb, download_progress_cb){
18 | this.init(amr_url, download_success_cb, download_progress_cb);
19 | };
20 | AmrPlayer.prototype = {
21 | init: function(amr_url, download_success_cb, download_progress_cb){
22 | this.audioContext = null;
23 | this.bufferSource = null;
24 | this.blob = null;
25 | this.canPlay = false;
26 | this.isPlaying = false;
27 | var cnt = 0;
28 | this.ended_cb = function(){
29 | if(cnt === 0){
30 | cnt++;
31 | var msg = "AmrPlayer ended callback\n";
32 | msg += "usage:\n";
33 | msg += "var player = new AmrPlayer('http://xxx.com/xxx.amr');\n";
34 | msg += "player.endedWith( function(){ xxx } );";
35 | console.info(msg);
36 | }
37 | };
38 | this.downloadAmrBlob(amr_url, download_success_cb, download_progress_cb);
39 | },
40 | downloadAmrBlob: function(amr_url, download_success_cb, download_progress_cb){
41 | var self = this;
42 | var xhr = new XMLHttpRequest();
43 | xhr.open('GET', amr_url);
44 | xhr.responseType = 'blob';
45 | xhr.onreadystatechange = function(e) {
46 | if ( xhr.readyState == 4 && xhr.status == 200 ) {
47 | self.blob = new Blob([xhr.response], {type: 'audio/mpeg'});
48 | self.genPLayer();
49 | self.canPlay = true;
50 | download_success_cb && download_success_cb();
51 | }
52 | };
53 | xhr.onprogress = function(e){
54 | if(e.lengthComputable){
55 | download_progress_cb && download_progress_cb(e);
56 | }
57 | };
58 | xhr.send();
59 | },
60 | genPLayer: function(){
61 | var self = this;
62 | this.isPlaying = false;
63 | this.readBlob(this.blob, function(data){
64 | self.readAmrArray(data);
65 | });
66 | },
67 | readBlob: function(blob, callback) {
68 | var reader = new FileReader();
69 | reader.onload = function(e) {
70 | var data = new Uint8Array(e.target.result);
71 | callback(data);
72 | };
73 | reader.readAsArrayBuffer(blob);
74 | },
75 | readAmrArray: function(array) {
76 | var samples = AMR.decode(array);
77 | if (!samples) {
78 | alert('Failed to decode!');
79 | return;
80 | }
81 | this.readPcm(samples);
82 | },
83 | readPcm: function(samples) {
84 | var self = this;
85 | var ctx = this.getAudioContext();
86 | this.bufferSource = ctx.createBufferSource();
87 | var buffer = ctx.createBuffer(1, samples.length, 8000);
88 | if (buffer.copyToChannel) {
89 | buffer.copyToChannel(samples, 0, 0)
90 | } else {
91 | var channelBuffer = buffer.getChannelData(0);
92 | channelBuffer.set(samples);
93 | }
94 | this.bufferSource.buffer = buffer;
95 | this.bufferSource.connect(ctx.destination);
96 | this.bufferSource.onended = function(){
97 | self.ended_cb && self.ended_cb();
98 | self.genPLayer();
99 | };
100 | },
101 | getAudioContext: function(){
102 | if (!this.audioContext) {
103 | if(window.AudioContext) {
104 | this.audioContext = new AudioContext();
105 | } else {
106 | this.audioContext = new window.webkitAudioContext();
107 | }
108 | }
109 | return this.audioContext;
110 | },
111 | play: function(){
112 | if( !this.isPlaying && this.canPlay ){
113 | this.bufferSource.start();
114 | this.isPlaying = true;
115 | }
116 | else{
117 | this.warn('can not play now');
118 | }
119 | },
120 | pause: function(){
121 | if( this.isPlaying && this.canPlay ) {
122 | this.bufferSource.stop();
123 | this.genPLayer();
124 | }
125 | else{
126 | this.warn('can not pause now');
127 | }
128 | },
129 | toggle: function(){
130 | this.isPlaying ? this.pause() : this.play();
131 | },
132 | endedWith: function(cb){
133 | this.ended_cb = cb;
134 | },
135 | warn: function(msg){
136 | console.warn(msg);
137 | }
138 | };
--------------------------------------------------------------------------------