OSDN Git Service

Version 0.6.113, fix X.Net.XHR, etc...
[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 \r
19 /*\r
20  * TODO preplayerror play してみたら error が出た、backend の変更。\r
21  */\r
22 \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
28                 ext, sup;\r
29         \r
30         if( source && backend ){\r
31                 sup      = [ proxy, option, sourceList, source, ext ];\r
32                 sup[ 5 ] = sup;\r
33                 \r
34                 proxy.listenOnce( [ 'support', 'nosupport' ], backend, X_Audio_detectComplete, sup );\r
35                 backend.detect( proxy, source, ext );   \r
36         } else {\r
37                 proxy.asyncDispatch( 'nobackend' );\r
38         };\r
39 };\r
40 \r
41 function X_Audio_detectComplete( e, proxy, option, sourceList, source, ext, sup ){\r
42         var i = X_Audio_BACKENDS.indexOf( this ), backend;\r
43         \r
44         proxy.unlisten( [ 'support', 'nosupport' ], backend, X_Audio_detectComplete, sup );\r
45         \r
46         switch( e.type ){\r
47                 case 'support' :\r
48                         proxy._backend = i;\r
49                         proxy.asyncDispatch( { type : 'backendfound', option : option, source : source } );\r
50                         break;\r
51                 case 'nosupport' :\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
55                         } else\r
56                         if( sourceList.length ){\r
57                                 X_Audio_detectBackend( proxy, sourceList, option );\r
58                         } else {\r
59                                 proxy.asyncDispatch( 'nobackend' );\r
60                         };\r
61                         break;\r
62         };\r
63 };\r
64 \r
65 \r
66 var X_AudioProxy = X.EventDispatcher.inherits(\r
67         'X.AV.AudioProxy',\r
68         X.Class.POOL_OBJECT,\r
69         {\r
70                 source      : '',\r
71                 backendName : '',\r
72                 _backend    : -1,\r
73                 \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
77                 },\r
78                 \r
79                 close : function(){\r
80                         return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].close( this );\r
81                 },\r
82                 \r
83                 play : function( startTime, endTime, loop, loopStartTime ){\r
84                         var state, duration;\r
85                         if( startTime ){\r
86                                 this.state( {\r
87                                         startTime     : startTime,\r
88                                         endTime       : endTime,\r
89                                         loop          : loop,\r
90                                         loopStartTime : loopStartTime\r
91                                 } );\r
92                         };\r
93                         this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].play( this );\r
94                         return this;\r
95                 },\r
96                 \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
101                         } else {\r
102                                 this.state( { startTime : seekTime } );\r
103                         };\r
104                         return this;\r
105                 },\r
106                 \r
107                 pause : function(){\r
108                         this.state().playing && X_Audio_BACKENDS[ this._backend ].pause( this );\r
109                         return this;\r
110                 },\r
111                 \r
112                 state : function( obj ){\r
113                         var backend = this._backend !== -1 && X_Audio_BACKENDS[ this._backend ];\r
114 \r
115                         if( obj === undefined ){\r
116                                 return backend ?\r
117                                         backend.state( this ) :\r
118                                         {\r
119                                         startTime     : -1,\r
120                                         endTime       : -1,\r
121                                         loopStartTime : -1,\r
122                                         currentTime   : -1,\r
123                                         loop          : false,\r
124                                         loaded        : false,\r
125                                         error         : false,\r
126                                         playing       : false,\r
127                                         \r
128                                         source        : this.source || '',\r
129                                         duration      : 0\r
130                                         };\r
131                         };\r
132                         backend && backend.state( this, obj );\r
133                         return this;\r
134                 },              \r
135                 \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
140                         };\r
141                         backend && backend.state( this, { loop : v } );\r
142                         return this;\r
143                 },\r
144 \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
149                         };\r
150                         backend && backend.state( this, { volume : v } );\r
151                         return this;\r
152                 },\r
153 \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
158                         };\r
159                         backend && backend.state( this, { currentTime : v } );\r
160                         return this;\r
161                 },\r
162 \r
163                 isPlaying : function(){\r
164                         return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].state( this ).playing;\r
165                 }\r
166                 \r
167         }\r
168 );\r
169 \r
170 function X_AudioProxy_handleEvent( e ){\r
171         switch( e.type ){\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
177                         break;\r
178                 \r
179                 case 'nobackend' :\r
180                         this.kill();\r
181                         break;\r
182                 \r
183                 case X.Event.KILL_INSTANCE :\r
184                         this.close();\r
185                         break;\r
186         };\r
187 };\r
188 \r
189 function X_AudioWrapper_updateStates( audioWrapper, obj ){\r
190         var playing = audioWrapper.playing,\r
191                 k, v,\r
192                 end = 0, seek = 0, volume = 0;\r
193         \r
194         for( k in obj ){\r
195                 v = obj[ k ];\r
196                 switch( k ){\r
197                         case 'currentTime' :\r
198                                 v = X_AudioWrapper_timeStringToNumber( v );\r
199                                 if( X.Type.isNumber( v ) ){\r
200                                         if( playing ){\r
201                                                 if( audioWrapper.state().currentTime !== v ){\r
202                                                         audioWrapper.seekTime = v;\r
203                                                         seek = 2;\r
204                                                 };\r
205                                                 break;\r
206                                         };                      \r
207                                 } else {\r
208                                         continue;\r
209                                 };\r
210                                 k = 'startTime';\r
211                                         \r
212                         case 'startTime'     :\r
213                         case 'endTime'       :\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
220                                 };\r
221                                 break;\r
222 \r
223                         case 'loop' :\r
224                                 if( X.Type.isBoolean( v ) && audioWrapper[ k ] !== v ){\r
225                                         audioWrapper[ k ] = v;\r
226                                 };\r
227                                 break;\r
228 \r
229                         case 'volume' :\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
236                                         };\r
237                                 };\r
238                                 break;\r
239                 };\r
240         };\r
241         \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
246         ){\r
247                 //alert( 'error @updateStateObject() begin:' + audioWrapper.startTime + ' end:' + audioWrapper.endTime + ' d:' + audioWrapper.duration + ' ls:' + audioWrapper.loopStartTime );\r
248                 return 0;\r
249         };\r
250         \r
251         return end + seek + volume;\r
252 };\r
253 \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
258 \r
259         ary = time.split( '.' );\r
260         ms  = parseInt( ( ary[ 1 ] + '000' ).substr( 0, 3 ) ) || 0;\r
261         \r
262         ary = ary[ 0 ].split( ':' );\r
263         if( 3 < ary.length ) return;\r
264         \r
265         switch( ary.length ){\r
266                 case 0 :\r
267                         break;\r
268                 case 1 :\r
269                         s = parseInt( ary[ 0 ] ) || 0;\r
270                         break;\r
271                 case 2 :\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
275                         break;\r
276                 case 3 :\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
282                         break;\r
283                 default :\r
284                         alert( 'invalid time string ' + time );\r
285         };\r
286         ms = ( h * 3600 + m * 60 + s ) * 1000 + ms;\r
287         return ms < 0 ? 0 : ms;\r
288 };\r