OSDN Git Service

Version 0.6.120, fix audio detection & add X.UAL.PARAMS & fix tree builder & html...
[pettanr/clientJs.git] / 0.6.x / js / 07_audio / 00_XAudio.js
1 \r
2 X.Audio = {\r
3         WebAudio    : 1,\r
4         HTML5       : 2,\r
5         Flash       : 3,\r
6         Silverlight : 4,\r
7         Unity       : 5,\r
8         WMP         : 6,\r
9         RealPlayer  : 7,\r
10         QuickTime   : 8,\r
11         \r
12         create : function( sourceList, opt_option ){\r
13                 return new X_AudioProxy( X.Type.isArray( sourceList ) ? X_Object_cloneArray( sourceList ) : [ sourceList ], opt_option || {} );\r
14         }\r
15 };\r
16 \r
17 var X_Audio_BACKENDS = [],\r
18         X_Audio_WRAPPER_LIST = [];\r
19 \r
20 /*\r
21  * TODO preplayerror play してみたら error が出た、backend の変更。\r
22  */\r
23 \r
24 function X_Audio_startDetectionBackend( backend, proxy, sourceList, option ){\r
25         var source = sourceList[ 0 ] || '', \r
26                 ext    = X_URL_cleanup( source ).split( '.' ).pop(),\r
27                 sup;\r
28         \r
29         if( source && backend ){\r
30                 sup      = [ proxy, sourceList, option, source, ext ];\r
31                 sup[ 5 ] = sup;\r
32                 \r
33                 proxy.listenOnce( [ 'support', 'nosupport' ], backend, X_Audio_onEndDetection, sup );\r
34                 backend.detect( proxy, source, ext );\r
35         } else {\r
36                 proxy.asyncDispatch( 'nobackend' );\r
37         };\r
38 };\r
39 \r
40 function X_Audio_onEndDetection( e, proxy, sourceList, option, source, ext, sup ){\r
41         var i = X_Audio_BACKENDS.indexOf( this ), backend;\r
42         \r
43         proxy.unlisten( [ 'support', 'nosupport' ], this, X_Audio_onEndDetection, sup );\r
44         \r
45         switch( e.type ){\r
46                 case 'support' :\r
47                         proxy._backend = i;\r
48                         proxy.asyncDispatch( {\r
49                                 type        : 'backendfound',\r
50                                 option      : option,\r
51                                 source      : source,\r
52                                 backendName : this.backendName\r
53                         } );\r
54                         break;\r
55                 case 'nosupport' :\r
56                         console.log( 'No ' + source + ' ' + this.backendName );\r
57                         if( sup[ 3 ] = source = sourceList[ sourceList.indexOf( source ) + 1 ] ){\r
58                                 sup[ 4 ] = ext    = X_URL_cleanup( source ).split( '.' ).pop();\r
59                                 proxy.listenOnce( [ 'support', 'nosupport' ], this, X_Audio_onEndDetection, sup );\r
60                                 this.detect( proxy, source, ext );\r
61                         } else\r
62                         if( backend = X_Audio_BACKENDS[ i + 1 ] ){\r
63                                 X_Audio_startDetectionBackend( backend, proxy, sourceList, option );\r
64                         } else {\r
65                                 proxy.asyncDispatch( 'nobackend' );\r
66                         };\r
67                         break;\r
68         };\r
69 };\r
70 \r
71 function X_AudioProxy_getAudioWrapper( proxy ){\r
72         var i = X_Audio_WRAPPER_LIST.length;\r
73         for( ; i; ){\r
74                 if( X_Audio_WRAPPER_LIST[ --i ].proxy === proxy ) return X_Audio_WRAPPER_LIST[ i ];\r
75         };\r
76 };\r
77 \r
78 var X_AudioProxy = X.EventDispatcher.inherits(\r
79         'X.AV.AudioProxy',\r
80         X.Class.POOL_OBJECT,\r
81         {\r
82                 source      : '',\r
83                 backendName : '',\r
84                 _backend    : -1,\r
85                 \r
86                 Constructor : function( sourceList, option ){\r
87                         X_Audio_startDetectionBackend( X_Audio_BACKENDS[ 0 ], this, sourceList, option );\r
88                         this.listenOnce( [ 'backendfound', 'nobackend', X.Event.KILL_INSTANCE ], X_AudioProxy_handleEvent );\r
89                 },\r
90                 \r
91                 close : function(){\r
92                         return this._backend !== -1 && X_AudioProxy_getAudioWrapper( this ).close();\r
93                 },\r
94                 \r
95                 play : function( startTime, endTime, loop, loopStartTime, loopEndTime ){\r
96                         var state, duration;\r
97                         if( 0 <= startTime ){\r
98                                 this.state( {\r
99                                         currentTime   : startTime,\r
100                                         startTime     : startTime,\r
101                                         endTime       : endTime,\r
102                                         loop          : loop,\r
103                                         loopStartTime : loopStartTime,\r
104                                         loopEndTime   : loopEndTime\r
105                                 } );\r
106                         };\r
107                         this._backend !== -1 && X_AudioProxy_getAudioWrapper( this ).play();\r
108                         return this;\r
109                 },\r
110                 \r
111                 seek : function( seekTime ){\r
112                         var state = this.state(),\r
113                                 end   = X_AudioWrapper_getEndTime( X_AudioProxy_getAudioWrapper( this ) );\r
114                         if( seekTime < end ){\r
115                                 this.state( { currentTime : seekTime } );\r
116                         };\r
117                         return this;\r
118                 },\r
119                 \r
120                 pause : function(){\r
121                         this.state().playing && X_AudioProxy_getAudioWrapper( this ).pause();\r
122                         return this;\r
123                 },\r
124                 \r
125                 state : function( obj ){\r
126                         var backend = this._backend !== -1 && X_AudioProxy_getAudioWrapper( this );\r
127 \r
128                         if( obj === undefined ){\r
129                                 return backend ?\r
130                                         backend.state() :\r
131                                         {\r
132                                         startTime     : -1,\r
133                                         endTime       : -1,\r
134                                         loopStartTime : -1,\r
135                                         loopEndTime   : -1,\r
136                                         currentTime   : -1,\r
137                                         loop          : false,\r
138                                         looded        : false,\r
139                                         error         : false,\r
140                                         playing       : false,\r
141                                         \r
142                                         source        : this.source || '',\r
143                                         duration      : 0\r
144                                         };\r
145                         };\r
146                         backend && backend.state( obj );\r
147                         return this;\r
148                 },              \r
149                 \r
150                 loop : function( v ){\r
151                         var backend = this._backend !== -1 && X_AudioProxy_getAudioWrapper( this );\r
152                         if( v === undefined ){\r
153                                 return backend && backend.state().loop;\r
154                         };\r
155                         backend && backend.state( { loop : v } );\r
156                         return this;\r
157                 },\r
158 \r
159                 volume : function( v ){\r
160                         var backend = this._backend !== -1 && X_AudioProxy_getAudioWrapper( this );\r
161                         if( v === undefined ){\r
162                                 return backend && backend.state().volume;\r
163                         };\r
164                         backend && backend.state( { volume : v } );\r
165                         return this;\r
166                 },\r
167 \r
168                 currentTime : function( v ){\r
169                         var backend = this._backend !== -1 && X_AudioProxy_getAudioWrapper( this );\r
170                         if( v === undefined ){\r
171                                 return backend && backend.state().currentTime;\r
172                         };\r
173                         backend && backend.state( { currentTime : v } );\r
174                         return this;\r
175                 },\r
176 \r
177                 isPlaying : function(){\r
178                         return this._backend !== -1 && X_AudioProxy_getAudioWrapper( this ).state().playing;\r
179                 }\r
180                 \r
181         }\r
182 );\r
183 \r
184 function X_AudioProxy_handleEvent( e ){\r
185         switch( e.type ){\r
186                 case 'backendfound' :\r
187                         this.unlisten( 'nobackend', X_AudioProxy_handleEvent );\r
188                         this.source = e.source;\r
189                         this.backendName = X_Audio_BACKENDS[ this._backend ].backendName;\r
190                         X_Audio_WRAPPER_LIST.push( new X_Audio_BACKENDS[ this._backend ].klass( this, e.source, e.option ) );\r
191                         break;\r
192                 \r
193                 case 'nobackend' :\r
194                         this.kill();\r
195                         break;\r
196                 \r
197                 case X.Event.KILL_INSTANCE :\r
198                         this.close();\r
199                         break;\r
200         };\r
201 };\r
202 \r
203 function X_AudioWrapper_updateStates( audioWrapper, obj ){\r
204         var playing = audioWrapper.playing,\r
205                 k, v,\r
206                 end = 0, seek = 0, volume = 0;\r
207         \r
208         for( k in obj ){\r
209                 v = obj[ k ];\r
210                 switch( k ){\r
211                         case 'currentTime' :\r
212                                 v = X_AudioWrapper_timeStringToNumber( v );\r
213                                 if( X.Type.isNumber( v ) ){\r
214                                         if( playing ){\r
215                                                 if( audioWrapper.state().currentTime !== v ){\r
216                                                         audioWrapper.seekTime = v;\r
217                                                         seek = 2;\r
218                                                 };\r
219                                         } else {\r
220                                                 audioWrapper.seekTime = v;\r
221                                         };\r
222                                 } else {\r
223                                         continue;\r
224                                 };\r
225                                 break;\r
226                                         \r
227                         case 'startTime'     :\r
228                         case 'endTime'       :\r
229                         case 'loopStartTime' :\r
230                         case 'loopEndTime'   :\r
231                                 v = X_AudioWrapper_timeStringToNumber( v );\r
232                                 console.log( k + ' ' + v );\r
233                                 if( v || v === 0 ){\r
234                                         if( audioWrapper[ k ] !== v ){\r
235                                                 audioWrapper[ k ] = v;\r
236                                                 \r
237                                                 // 再生中の endTime の変更\r
238                                                 if( playing && ( k === 'endTime' || k === 'loopEndTime' ) ) end = 1;                                            \r
239                                         };\r
240                                 } else {\r
241                                         delete audioWrapper[ k ];\r
242                                         if( playing && ( k === 'endTime' || k === 'loopEndTime' ) ) end = 1;\r
243                                 };\r
244                                 break;\r
245 \r
246                         case 'looped' :\r
247                                 if( playing ) seek = 2;\r
248                         case 'loop' :\r
249                         case 'autoplay' :\r
250                                 if( X.Type.isBoolean( v ) && audioWrapper[ k ] !== v ){\r
251                                         audioWrapper[ k ] = v;\r
252                                 };\r
253                                 break;\r
254 \r
255                         case 'volume' :\r
256                                 if( X.Type.isNumber( v ) ){\r
257                                         v = v < 0 ? 0 : 1 < v ? 1 : v;\r
258                                         if( audioWrapper[ k ] !== v ){\r
259                                                 audioWrapper[ k ] = v;\r
260                                                 // if playing -> update\r
261                                                 if( playing ) volume = 4;\r
262                                         };\r
263                                 };\r
264                                 break;\r
265                 };\r
266         };\r
267         \r
268         if( audioWrapper.endTime < audioWrapper.startTime ||\r
269                 ( audioWrapper.loopEndTime < 0 ? audioWrapper.endTime : audioWrapper.loopEndTime ) < ( audioWrapper.loopStartTime < 0 ? audioWrapper.startTime : audioWrapper.loopStartTime ) ||\r
270                 X_AudioWrapper_getEndTime( audioWrapper ) < audioWrapper.seekTime// ||\r
271                 //audioWrapper.duration < audioWrapper.endTime\r
272         ){\r
273                 console.log( 'error @updateStateObject() begin:' + audioWrapper.startTime + ' end:' + audioWrapper.endTime + ' d:' + audioWrapper.duration + ' ls:' + audioWrapper.loopStartTime );\r
274                 return 0;\r
275         };\r
276         \r
277         return end + seek + volume;\r
278 };\r
279 \r
280 function X_AudioWrapper_timeStringToNumber( time ){\r
281         var ary, ms, s = 0, m = 0, h = 0;\r
282         if( X.Type.isNumber( time ) ) return time;\r
283         if( !X.Type.isString( time ) || !time.length ) return;\r
284 \r
285         ary = time.split( '.' );\r
286         ms  = parseInt( ( ary[ 1 ] + '000' ).substr( 0, 3 ) ) || 0;\r
287         \r
288         ary = ary[ 0 ].split( ':' );\r
289         if( 3 < ary.length ) return;\r
290         \r
291         switch( ary.length ){\r
292                 case 0 :\r
293                         break;\r
294                 case 1 :\r
295                         s = parseInt( ary[ 0 ] ) || 0;\r
296                         break;\r
297                 case 2 :\r
298                         m = parseInt( ary[ 0 ] ) || 0;\r
299                         s = parseInt( ary[ 1 ] ) || 0;\r
300                         if( 60 <= s ) alert( 'invalid time string ' + time );\r
301                         break;\r
302                 case 3 :\r
303                         h = parseInt( ary[ 0 ] ) || 0;\r
304                         m = parseInt( ary[ 1 ] ) || 0;\r
305                         s = parseInt( ary[ 2 ] ) || 0;\r
306                         if( 60 <= s ) alert( 'invalid time string ' + time );\r
307                         if( 60 <= m ) alert( 'invalid time string ' + time );\r
308                         break;\r
309                 default :\r
310                         alert( 'invalid time string ' + time );\r
311         };\r
312         ms = ( h * 3600 + m * 60 + s ) * 1000 + ms;\r
313         return ms < 0 ? 0 : ms;\r
314 };\r
315 \r
316 function X_AudioWrapper_getStartTime( audioWrapper, endTime, delSeekTime ){\r
317         var seek = audioWrapper.seekTime;\r
318         if( delSeekTime ) delete audioWrapper.seekTime;\r
319         \r
320         if( 0 <= seek ){\r
321                 if( audioWrapper.duration <= seek || endTime < seek ) return 0;\r
322                 return seek;\r
323         };\r
324         \r
325         if( audioWrapper.looped && 0 <= audioWrapper.loopStartTime ){\r
326                 if( audioWrapper.duration <= audioWrapper.loopStartTime || endTime < audioWrapper.loopStartTime ) return 0;\r
327                 return audioWrapper.loopStartTime;\r
328         };\r
329         \r
330         if( audioWrapper.startTime < 0 || audioWrapper.duration <= audioWrapper.startTime ) return 0;\r
331         return audioWrapper.startTime;\r
332 };\r
333 \r
334 function X_AudioWrapper_getEndTime( audioWrapper ){\r
335         var duration = audioWrapper.duration;\r
336         \r
337         if( audioWrapper.looped && 0 <= audioWrapper.loopEndTime ){\r
338                 if( duration <= audioWrapper.loopEndTime ) return duration;\r
339                 return audioWrapper.loopEndTime;\r
340         };\r
341         \r
342         if( audioWrapper.endTime < 0 || duration <= audioWrapper.endTime ) return duration;\r
343         return audioWrapper.endTime;\r
344 };\r
345 \r