OSDN Git Service

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