1 /**
  2  * Hilo
  3  * Copyright 2015 alibaba.com
  4  * Licensed under the MIT License
  5  */
  6 
  7 /**
  8  * @class HTMLAudio声音播放模块。此模块使用HTMLAudioElement播放音频。
  9  * 使用限制:iOS平台需用户事件触发才能播放,很多Android浏览器仅能同时播放一个音频。
 10  * @param {Object} properties 创建对象的属性参数。可包含此类所有可写属性。
 11  * @module hilo/media/HTMLAudio
 12  * @requires hilo/core/Hilo
 13  * @requires hilo/core/Class
 14  * @requires hilo/event/EventMixin
 15  * @property {String} src 播放的音频的资源地址。
 16  * @property {Boolean} loop 是否循环播放。默认为false。
 17  * @property {Boolean} autoPlay 是否自动播放。默认为false。
 18  * @property {Boolean} loaded 音频资源是否已加载完成。只读属性。
 19  * @property {Boolean} playing 是否正在播放音频。只读属性。
 20  * @property {Number} duration 音频的时长。只读属性。
 21  * @property {Number} volume 音量的大小。取值范围:0-1。
 22  * @property {Boolean} muted 是否静音。默认为false。
 23  */
 24 var HTMLAudio = Class.create(/** @lends HTMLAudio.prototype */{
 25     Mixes: EventMixin,
 26     constructor: function(properties){
 27         Hilo.copy(this, properties, true);
 28 
 29         this._onAudioEvent = this._onAudioEvent.bind(this);
 30     },
 31 
 32     src: null,
 33     loop: false,
 34     autoPlay: false,
 35     loaded: false,
 36     playing: false,
 37     duration: 0,
 38     volume: 1,
 39     muted: false,
 40 
 41     _element: null, //HTMLAudioElement对象
 42 
 43     /**
 44      * 加载音频文件。
 45      */
 46     load: function(){
 47         if(!this._element){
 48             try{
 49                 var elem = this._element = new Audio();
 50                 elem.addEventListener('canplaythrough', this._onAudioEvent, false);
 51                 elem.addEventListener('ended', this._onAudioEvent, false);
 52                 elem.addEventListener('error', this._onAudioEvent, false);
 53                 elem.src = this.src;
 54                 elem.volume = this.volume;
 55                 elem.load();
 56             }
 57             catch(err){
 58                 //ie9 某些版本有Audio对象,但是执行play,pause会报错!
 59                 var elem = this._element = {};
 60                 elem.play = elem.pause = function(){
 61 
 62                 };
 63             }
 64         }
 65         return this;
 66     },
 67 
 68     /**
 69      * @private
 70      */
 71     _onAudioEvent: function(e){
 72         // console.log('onAudioEvent:', e.type);
 73         var type = e.type;
 74 
 75         switch(type){
 76             case 'canplaythrough':
 77                 e.target.removeEventListener(type, this._onAudioEvent);
 78                 this.loaded = true;
 79                 this.duration = this._element.duration;
 80                 this.fire('load');
 81                 if(this.autoPlay) this._doPlay();
 82                 break;
 83             case 'ended':
 84                 this.playing = false;
 85                 this.fire('end');
 86                 if(this.loop) this._doPlay();
 87                 break;
 88             case 'error':
 89                 this.fire('error');
 90                 break;
 91         }
 92     },
 93 
 94     /**
 95      * @private
 96      */
 97     _doPlay: function(){
 98         if(!this.playing){
 99             this._element.volume = this.muted ? 0 : this.volume;
100             this._element.play();
101             this.playing = true;
102         }
103     },
104 
105     /**
106      * 播放音频。如果正在播放,则会重新开始。
107      * 注意:为了避免第一次播放不成功,建议在load音频后再播放。
108      */
109     play: function(){
110         if(this.playing) this.stop();
111 
112         if(!this._element){
113             this.autoPlay = true;
114             this.load();
115         }else if(this.loaded){
116             this._doPlay();
117         }
118 
119         return this;
120     },
121 
122     /**
123      * 暂停音频。
124      */
125     pause: function(){
126         if(this.playing){
127             this._element.pause();
128             this.playing = false;
129         }
130         return this;
131     },
132 
133     /**
134      * 恢复音频播放。
135      */
136     resume: function(){
137         if(!this.playing){
138             this._doPlay();
139         }
140         return this;
141     },
142 
143     /**
144      * 停止音频播放。
145      */
146     stop: function(){
147         if(this.playing){
148             this._element.pause();
149             this._element.currentTime = 0;
150             this.playing = false;
151         }
152         return this;
153     },
154 
155     /**
156      * 设置音量。注意: iOS设备无法设置音量。
157      */
158     setVolume: function(volume){
159         if(this.volume != volume){
160             this.volume = volume;
161             this._element.volume = volume;
162         }
163         return this;
164     },
165 
166     /**
167      * 设置静音模式。注意: iOS设备无法设置静音模式。
168      */
169     setMute: function(muted){
170         if(this.muted != muted){
171             this.muted = muted;
172             this._element.volume = muted ? 0 : this.volume;
173         }
174         return this;
175     },
176 
177     Statics: /** @lends HTMLAudio */ {
178         /**
179          * 浏览器是否支持HTMLAudio。
180          */
181         isSupported: window.Audio !== null
182     }
183 
184 });