12 create : function( sourceList, opt_option ){
\r
13 return new X_AudioProxy( X.Type.isArray( sourceList ) ? X_Object_cloneArray( sourceList ) : [ sourceList ], opt_option || {} );
\r
17 var X_Audio_BACKENDS = [];
\r
20 * TODO preplayerror play してみたら error が出た、backend の変更。
\r
23 function X_Audio_detectBackend( proxy, sourceList, option ){
\r
24 var source = sourceList.shift() || '',
\r
25 parts = X_URL_cleanup( source ).split( '.' ),
\r
26 ext = parts[ parts.length - 1 ],
\r
27 backend = X_Audio_BACKENDS[ 0 ],
\r
30 if( source && backend ){
\r
31 sup = [ proxy, option, sourceList, source, ext ];
\r
34 proxy.listenOnce( [ 'support', 'nosupport' ], backend, X_Audio_detectComplete, sup );
\r
35 backend.detect( proxy, source, ext );
\r
37 proxy.asyncDispatch( 'nobackend' );
\r
41 function X_Audio_detectComplete( e, proxy, option, sourceList, source, ext, sup ){
\r
42 var i = X_Audio_BACKENDS.indexOf( this ), backend;
\r
44 proxy.unlisten( [ 'support', 'nosupport' ], backend, X_Audio_detectComplete, sup );
\r
49 proxy.asyncDispatch( { type : 'backendfound', option : option, source : source } );
\r
52 if( backend = X_Audio_BACKENDS[ i + 1 ] ){
\r
53 proxy.listenOnce( [ 'support', 'nosupport' ], backend, X_Audio_detectComplete, sup );
\r
54 backend.detect( proxy, source, ext );
\r
56 if( sourceList.length ){
\r
57 X_Audio_detectBackend( proxy, sourceList, option );
\r
59 proxy.asyncDispatch( 'nobackend' );
\r
66 var X_AudioProxy = X.EventDispatcher.inherits(
\r
68 X.Class.POOL_OBJECT,
\r
74 Constructor : function( sourceList, option ){
\r
75 X_Audio_detectBackend( this, sourceList, option );
\r
76 this.listenOnce( [ 'backendfound', 'nobackend', X.Event.KILL_INSTANCE ], X_AudioProxy_handleEvent );
\r
80 return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].close( this );
\r
83 play : function( startTime, endTime, loop, loopStartTime ){
\r
84 var state, duration;
\r
87 startTime : startTime,
\r
90 loopStartTime : loopStartTime
\r
93 this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].play( this );
\r
97 seek : function( seekTime ){
\r
98 var state = this.state();
\r
99 if( state.playing ){
\r
100 seekTime < state.endTime && this.state( { currentTime : seekTime } );
\r
102 this.state( { startTime : seekTime } );
\r
107 pause : function(){
\r
108 this.state().playing && X_Audio_BACKENDS[ this._backend ].pause( this );
\r
112 state : function( obj ){
\r
113 var backend = this._backend !== -1 && X_Audio_BACKENDS[ this._backend ];
\r
115 if( obj === undefined ){
\r
117 backend.state( this ) :
\r
121 loopStartTime : -1,
\r
128 source : this.source || '',
\r
132 backend && backend.state( this, obj );
\r
136 loop : function( v ){
\r
137 var backend = this._backend !== -1 && X_Audio_BACKENDS[ this._backend ];
\r
138 if( v === undefined ){
\r
139 return backend && backend.state( this ).loop;
\r
141 backend && backend.state( this, { loop : v } );
\r
145 volume : function( v ){
\r
146 var backend = this._backend !== -1 && X_Audio_BACKENDS[ this._backend ];
\r
147 if( v === undefined ){
\r
148 return backend && backend.state( this ).volume;
\r
150 backend && backend.state( this, { volume : v } );
\r
154 currentTime : function( v ){
\r
155 var backend = this._backend !== -1 && X_Audio_BACKENDS[ this._backend ];
\r
156 if( v === undefined ){
\r
157 return backend && backend.state( this ).currentTime;
\r
159 backend && backend.state( this, { currentTime : v } );
\r
163 isPlaying : function(){
\r
164 return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].state( this ).playing;
\r
170 function X_AudioProxy_handleEvent( e ){
\r
172 case 'backendfound' :
\r
173 this.unlisten( 'nobackend', X_AudioProxy_handleEvent );
\r
174 this.source = e.source;
\r
175 this.backendName = X_Audio_BACKENDS[ this._backend ].backendName;
\r
176 X_Audio_BACKENDS[ this._backend ].register( this, e.source, e.option );
\r
183 case X.Event.KILL_INSTANCE :
\r
189 function X_AudioWrapper_updateStates( audioWrapper, obj ){
\r
190 var playing = audioWrapper.playing,
\r
192 end = 0, seek = 0, volume = 0;
\r
197 case 'currentTime' :
\r
198 v = X_AudioWrapper_timeStringToNumber( v );
\r
199 if( X.Type.isNumber( v ) ){
\r
201 if( audioWrapper.state().currentTime !== v ){
\r
202 audioWrapper.seekTime = v;
\r
214 case 'loopStartTime' :
\r
215 v = X_AudioWrapper_timeStringToNumber( v );
\r
216 if( X.Type.isNumber( v ) && audioWrapper[ k ] !== v ){
\r
217 audioWrapper[ k ] = v;
\r
218 // 再生中の endTime, currentTime の変更
\r
219 if( playing && k === 'endTime' ) end = 1;
\r
224 if( X.Type.isBoolean( v ) && audioWrapper[ k ] !== v ){
\r
225 audioWrapper[ k ] = v;
\r
230 if( X.Type.isNumber( v ) ){
\r
231 v = v < 0 ? 0 : 1 < v ? 1 : v;
\r
232 if( audioWrapper[ k ] !== v ){
\r
233 audioWrapper[ k ] = v;
\r
234 // if playing -> update
\r
235 if( playing ) volume = 4;
\r
242 if( audioWrapper.endTime <= audioWrapper.startTime ||
\r
243 audioWrapper.endTime <= audioWrapper.loopStartTime ||
\r
244 audioWrapper.endTime < audioWrapper.seekTime ||
\r
245 audioWrapper.duration < audioWrapper.endTime
\r
247 //alert( 'error @updateStateObject() begin:' + audioWrapper.startTime + ' end:' + audioWrapper.endTime + ' d:' + audioWrapper.duration + ' ls:' + audioWrapper.loopStartTime );
\r
251 return end + seek + volume;
\r
254 function X_AudioWrapper_timeStringToNumber( time ){
\r
255 var ary, ms, s = 0, m = 0, h = 0;
\r
256 if( X.Type.isNumber( time ) ) return time;
\r
257 if( !X.Type.isString( time ) || !time.length ) return;
\r
259 ary = time.split( '.' );
\r
260 ms = parseInt( ( ary[ 1 ] + '000' ).substr( 0, 3 ) ) || 0;
\r
262 ary = ary[ 0 ].split( ':' );
\r
263 if( 3 < ary.length ) return;
\r
265 switch( ary.length ){
\r
269 s = parseInt( ary[ 0 ] ) || 0;
\r
272 m = parseInt( ary[ 0 ] ) || 0;
\r
273 s = parseInt( ary[ 1 ] ) || 0;
\r
274 if( 60 <= s ) alert( 'invalid time string ' + time );
\r
277 h = parseInt( ary[ 0 ] ) || 0;
\r
278 m = parseInt( ary[ 1 ] ) || 0;
\r
279 s = parseInt( ary[ 2 ] ) || 0;
\r
280 if( 60 <= s ) alert( 'invalid time string ' + time );
\r
281 if( 60 <= m ) alert( 'invalid time string ' + time );
\r
284 alert( 'invalid time string ' + time );
\r
286 ms = ( h * 3600 + m * 60 + s ) * 1000 + ms;
\r
287 return ms < 0 ? 0 : ms;
\r