OSDN Git Service

Version 0.6.112, fix X.Node.Anime, rewite X.Audio.* for AudioSprite, add X.Audio...
[pettanr/clientJs.git] / 0.6.x / js / 07_audio / 03_XSilverlightAudio.js
1 \r
2 /*\r
3  * original : uupaa-js SilverlightAudio.js\r
4  * https://code.google.com/p/uupaa-js/source/browse/trunk/0.8/src/Audio/SilverlightAudio.js?r=568\r
5  *\r
6  * Silverlight 4 → 5における不具合の状況\r
7  * http://www.slideshare.net/wakabayashiy/silverlight-4-5 \r
8  * \r
9  * IE10以降でSilverlightでF5押したらフリーズする不具合と対処\r
10  * http://katsuyuzu.hatenablog.jp/entry/2014/01/11/003550\r
11  * \r
12  * SilverlLight5 ie6&7(ietester,winxp), ie8(winxp) で動作確認。firefox32 では動作しない。(4以下の方がよい?)\r
13  */\r
14 \r
15 var X_Audio_SLAudio, X_Audio_SLAudioWrapper,\r
16         X_Audio_SLAudio_uid = 0,\r
17         X_Audio_SLAudio_LIVE_LIST = [],\r
18         X_Audio_SLAudio_POOL_LIST = [];\r
19 \r
20 if( X.Pulgin.SilverlightEnabled ){\r
21         \r
22         function getSLAudioWrapper( proxy ){\r
23                 var i = X_Audio_SLAudio_LIVE_LIST.length;\r
24                 for( ; i; ){\r
25                         if( X_Audio_SLAudio_LIVE_LIST[ --i ].proxy === proxy ) return X_Audio_SLAudio_LIVE_LIST[ i ];\r
26                 };\r
27         };\r
28         \r
29         X_Audio_SLAudio = \r
30                 {\r
31                         backendName : 'Silverlight Audio',\r
32 \r
33                         detect : function( proxy, source, ext ){\r
34                                 var ok = ext === 'mp3' || ext === 'wma';\r
35                                 proxy.asyncDispatch( ok ? 'support' : 'nosupport' );                            \r
36                         },\r
37                         \r
38                         register : function( proxy, source, option ){\r
39                                 X_Audio_SLAudio_LIVE_LIST.push( new X_Audio_SLAudioWrapper( proxy, source, option ) );\r
40                         },\r
41                         \r
42                         close : function( proxy ){\r
43                                 return getSLAudioWrapper( proxy ).close();\r
44                         },\r
45                         \r
46                         play : function( proxy ){\r
47                                 return getSLAudioWrapper( proxy ).play();\r
48                         },\r
49                         \r
50                         pause : function( proxy ){\r
51                                 return getSLAudioWrapper( proxy ).pause();\r
52                         },\r
53         \r
54                         state : function( proxy, obj ){\r
55                                 return getSLAudioWrapper( proxy ).state( obj );\r
56                         }\r
57                 };\r
58         \r
59         X_Audio_BACKENDS.push( X_Audio_SLAudio );\r
60         \r
61         function slerror(){\r
62                 alert( 'slerror' );\r
63         };\r
64         \r
65         X_Audio_SLAudioWrapper = X.EventDispatcher.inherits(\r
66                 'X.AV.SilverlightAudioWrapper',\r
67                 X.Class.POOL_OBJECT,\r
68                 {\r
69                         _isSilverlight  : true, // for X.EventDispatcher.listen\r
70                 proxy           : null,\r
71                 \r
72                         startTime       : 0,\r
73                         endTime         : 0,\r
74                         loopStartTime   : 0,\r
75                         seekTime        : 0,\r
76                         duration        : 0,\r
77                         \r
78                         playing         : false,\r
79                         error           : 0,                    \r
80                         loop            : false,\r
81                         volume          : 0.5,\r
82                 \r
83                 _onload         : '',\r
84                 _callback       : null,                 \r
85                 xnodeObject     : null,\r
86                         _source         : '',\r
87                         _ended          : true,\r
88                         _paused         : false,\r
89                         _lastUserAction : '',\r
90                         _lastState      : '',\r
91                         _interval       : 0, // setInterval timer id\r
92                         \r
93                         Constructor : function( proxy, source, option ){\r
94                                 \r
95                                 if( !X_Audio_SLAudio_uid ){\r
96                                         // source\r
97                                         //X.X_Node_systemNode.create( 'script', { type : 'text/xaml', id : 'silverlightaudio' } )\r
98                                         //      .text( '<Canvas xmlns="http://schemas.microsoft.com/client/2007" ' +\r
99                                         // 'xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"></Canvas>');\r
100                                         \r
101                                         // html に以下を書いた                     \r
102                                         // <script id="silverlightaudio" type="text/xaml"><Canvas xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"></Canvas></script>\r
103                                 };\r
104                                 /*\r
105                                  * [Silverlight 2]JavaScriptコードからSilverlightのオブジェクトを利用するには?[C#、VB]\r
106                                  * http://www.atmarkit.co.jp/fdotnet/dotnettips/902slobjcallfromjs/slobjcallfromjs.html\r
107                                  * このページのサンプルは sl5+firefox32 環境で動いている。xaml を js から利用する形ではなく、.xap を sl4 以下で作るのがよさそう.\r
108                                  */\r
109                                 \r
110                                 // TODO embed\r
111                                 this.proxy       = proxy;\r
112                                 this._source     = source;\r
113                         this._onload     = 'XAudioSilverlightOnLoad' + ( ++X_Audio_SLAudio_uid );\r
114                                 this._callback   = window[ this._onload ] = X_Callback_create( this, this.onSLReady, [ option.autoplay ] );\r
115                         this.xnodeObject = X_Node_body\r
116                                 .create( 'object', {\r
117                                                 type   : 'application/x-silverlight-2',\r
118                                                 data   : 'data:application/x-silverlight-2,',\r
119                                                 width  : 1,\r
120                                                 height : 1\r
121                                         })\r
122                                         .html(\r
123                                             '<param name="background" value="#00000000">' +      // transparent\r
124                                             '<param name="windowless" value="true">' +\r
125                                             '<param name="source" value="#silverlightaudio">' +  // XAML ID\r
126                                             '<param name="onload" value="' + this._onload + '">' // + // bond to global\r
127                                             //'<param value="2.0.31005.0" name="minRuntimeVersion">' +\r
128                                             //'<param value="true" name="autoUpgrade">' +\r
129                                             //'<param name="onerror" value="slerror">' // bond to global\r
130                                         );\r
131                                 X_AudioWrapper_updateStates( this, option );\r
132         \r
133                                 this.listenOnce( X.Event.KILL_INSTANCE );\r
134                         },\r
135                         \r
136                         onSLReady : function( sender, autoplay ){\r
137                                 if( !this._onload ) return;\r
138                                 \r
139                                 window[ this._onload ] = null;\r
140                                 delete this._onload;\r
141                                 X_Callback_correct( this._callback );\r
142                                 delete this._callback;\r
143 \r
144                                 sender.children.add(\r
145                                         sender.GetHost().\r
146                                         content.\r
147                                         CreateFromXaml(\r
148                                         '<Canvas xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">' +\r
149                                                 '<MediaElement x:Name="media" Source="' + this._source + '" Volume="' + this.volume + '" AutoPlay="false" />' +\r
150                                         '</Canvas>'));\r
151                 \r
152                                 this._rawObject = sender.findName('media'); // x:Name='media'\r
153                                 \r
154                                 this.listen( [ 'MediaFailed', 'MediaOpened', 'MediaEnded', 'CurrentStateChanged' ] );\r
155                                 \r
156                                 autoplay && X.Timer.once( 100, this, this.play );\r
157                         },\r
158                         \r
159                         handleEvent : function( e ){\r
160                                 var lastState, currentState;\r
161                                 \r
162                                 switch( e.type ){\r
163                                         \r
164                                         case 'MediaFailed' :\r
165                                                 this.error   = 4;\r
166                                                 this.playing = false;\r
167                                                 this._ended  = true;\r
168                                                 this._paused = false;\r
169                                                 this.proxy.dispatch( 'error' ); // open failed\r
170                                                 break;\r
171 \r
172                                         case 'MediaOpened' :\r
173                                                 // http://msdn.microsoft.com/ja-jp/library/bb979710(VS.95).aspx\r
174                                                 this.duration = this._rawObject.NaturalDuration.Seconds * 1000;\r
175                                                 this.endTime  = this.endTime || this.duration;\r
176                                                 // TODO 'canplaythrough'\r
177                                                 this.proxy.asyncDispatch( 'loadstart' );\r
178                                 this.proxy.asyncDispatch( 'loadedmetadata' );\r
179                                 this.proxy.asyncDispatch( 'loadeddata' );\r
180                                 this.proxy.asyncDispatch( 'canplay' );\r
181                                 this.proxy.asyncDispatch( 'canplaythrough' );\r
182                                                 break;\r
183 \r
184                                         case 'MediaEnded' :                             \r
185                                                 this.loop && this.playing && this.play();\r
186                                                 break;\r
187 \r
188                                         case 'CurrentStateChanged' :\r
189                                                 lastState        = this._lastState,\r
190                                                 currentState = this._rawObject.CurrentState;\r
191                                 \r
192                                                 // ignore consecutive events or 'Closed' == 'Error'\r
193                                                 if( lastState === currentState\r
194                                                         || ( (lastState === 'Closed' || lastState === 'Error') && ( currentState === 'Closed' || currentState === 'Error') ) ){\r
195                                                         return;\r
196                                                 };\r
197                                                 this._lastState = currentState; // update last state\r
198                                 \r
199                                                 switch( currentState ){\r
200                                                         case 'Buffering' :\r
201                                                         case 'Opening' :\r
202                                                                 switch( this._lastUserAction ){\r
203                                                                         case 'play' :\r
204                                                                                 this.proxy.dispatch( 'waiting' );\r
205                                                                                 break;\r
206                                                                         case 'seek' :\r
207                                                                                 this.proxy.dispatch( 'seeking' );\r
208                                                                                 break;\r
209                                                                         case 'pause' :\r
210                                                                                 break;\r
211                                                                 };\r
212                                                                 break;\r
213 \r
214                                                         // media.play(none supported file) -> 'Error'\r
215                                                         // media.play(file not found)     -> 'Closed'\r
216                                                         // media.load -> 'Error'\r
217                                                         case 'Error':\r
218                                                         case 'Closed':\r
219                                                                 this.error   = 4;\r
220                                                                 this.playing = false;\r
221                                                                 this._ended  = true;\r
222                                                                 this._paused = false;\r
223                                                                 this.proxy.dispatch( 'error' );\r
224                                                                 break;\r
225 \r
226                                                         // userAction.pause()              -> MediaState('Paused') -> x\r
227                                                         // userAction.stop()                    -> MediaState('Paused') -> x\r
228                                                         // userAction.play() + file end -> MediaState('Paused') -> uueventfire('ended')\r
229                                                         case 'Paused':\r
230                                                                 this.playing = false;\r
231                                                                 \r
232                                                                 switch( this._lastUserAction ){\r
233                                                                         case 'play': // play() -> file end -> event('ended')\r
234                                                                         case 'seek':\r
235                                                                                 this._ended  = true;\r
236                                                                                 this._paused = false;\r
237                                                                                 this.proxy.dispatch( 'ended' );\r
238                                                                                 this._currentTime( this.startTime );\r
239                                                                                 break;\r
240                                                                         case 'pause':\r
241                                                                                 this._ended  = false;\r
242                                                                                 this._paused = true;\r
243                                                                                 break;\r
244                                                                         case 'stop':\r
245                                                                                 this._ended  = true;\r
246                                                                                 this._paused = false;\r
247                                                                 };\r
248                                                                 break;\r
249 \r
250                                                         // media.play -> 'Playing'\r
251                                                         case 'Playing':\r
252                                                                 this.error   = 0;\r
253                                                                 this.playing = true;\r
254                                                                 this._ended  = false;\r
255                                                                 this._paused = false;\r
256                                                                 this.proxy.dispatch( 'playing' );\r
257                                                                 break;\r
258 \r
259                                                         // stop()\r
260                                                         case 'Stopped':\r
261                                                                 this.playing = false;\r
262                                                                 this._ended  = true;\r
263                                                                 this._paused = false;\r
264                                                                 this._currentTime( this.startTime );\r
265                                                                 break;\r
266                                                 };\r
267                                                 break;\r
268 \r
269                                         case X.Event.KILL_INSTANCE :\r
270                                                 if( this._onload ){\r
271                                                         // window への delete に ie5 は対応しないが、そもそも ie5 は Silverlight に非対応\r
272                                                         delete window[ this._onload ];\r
273                                                         delete this._onload;\r
274                                                         X_Callback_correct( this._callback );\r
275                                                 };\r
276                                                 this.xnodeObject.destroy();\r
277                                                 break;\r
278                                 };\r
279                         },\r
280                         \r
281                         close : function(){\r
282                                 this.playing && this.pause();\r
283                                 this.proxy.dispatch( 'ended' );\r
284                                 this.kill();\r
285                         },\r
286                         \r
287                         // SilverlightAudio.play\r
288                         play : function( seekTime ){\r
289                                 var begin, halfway;\r
290                                 \r
291                                 // もし kill 後に autoplayTimer で呼ばれても、_closed==true なので平気\r
292                                 if( this.error ) return;\r
293 \r
294                                 begin = ( seekTime || seekTime === 0 ) ? seekTime : this.playing ? this.loopStartTime : this.startTime;\r
295                                 this._lastUserAction = this.playing ? 'seek' : 'play';\r
296                                 \r
297                             this._currentTime( begin );\r
298                             this._rawObject.Volume = this.volume;\r
299                             \r
300                             if( !this.playing ){\r
301                                     this._rawObject.play();\r
302                             this.proxy.dispatch( 'play' );\r
303                             \r
304                             this.playing = true;\r
305                             };\r
306                     \r
307                     halfway = this.endTime < this.duration;\r
308                     this._timerID && X.Timer.remove( this._timerID );\r
309                     \r
310                 if( halfway ){\r
311                                         this._timerID = X.Timer.once( this.endTime - begin, this, this._onEnded );\r
312                 } else {\r
313                         delete this._timerID;\r
314                 };\r
315                 \r
316                                 if( !this._interval ){\r
317                                         this._interval = X.Timer.add( 1000, 0, this, this._onInterval );\r
318                                 };\r
319                         },\r
320                                 \r
321                                 _onInterval : function(){\r
322                                         if( !this.playing ){\r
323                                                 delete this._interval;\r
324                                                 return X_Callback_UN_LISTEN;\r
325                                         };\r
326                                         this.proxy.dispatch( 'timeupdate' );\r
327                                 },\r
328                                 \r
329                                 _onEnded : function(){\r
330                                         delete this._timerID;\r
331                             if( this.playing ){\r
332                                 if( this.loop ){\r
333                                         this.play();\r
334                                 } else {\r
335                                         this.pause();\r
336                                         this.dispatch( 'ended' );                               \r
337                                 };\r
338                             };\r
339                                 },\r
340                         \r
341                         // SilverlightAudio.pause\r
342                         pause : function(){\r
343                                 if( !this.error ){\r
344                                         this._lastUserAction = 'pause';\r
345                                         this.playing = false;\r
346                                         this._paused = true;\r
347                                         this._ended  = false;\r
348                                         this._rawObject.pause();\r
349                                         this.proxy.dispatch( 'pause' );\r
350                                 };\r
351                         },\r
352                         \r
353                         // SilverlightAudio.state\r
354                         state : function( obj ){ // @return Hash: { loop, error, paused, ended, source, duration }\r
355                                 var result;\r
356                                 \r
357                                 if( obj === undefined ){\r
358                                     return {\r
359                                         startTime     : this.startTime,\r
360                                         endTime       : this.endTime,\r
361                                         loopStartTime : this.loopStartTime,\r
362                                         currentTime   : this._rawObject.Position.Seconds * 1000,\r
363                                         loop          : this.loop,\r
364                                         volume        : this.volume,\r
365                                         error         : this.error,\r
366                                         playing       : this.playing,\r
367                                         duration      : this.duration || 0 // this._rawObject.NaturalDuration.Seconds;\r
368                                     };\r
369                                 };\r
370                         \r
371                                 result = X_AudioWrapper_updateStates( this, obj );\r
372                             \r
373                                 if( result & 2 ){ // seek\r
374                         this.play( this.seekTime );\r
375                         delete this.seekTime;\r
376                                 } else {\r
377                                         if( result & 1 ){\r
378                                                 halfway = this.endTime < this.duration;\r
379                                                 this._timerID && X.Timer.remove( this._timerID );\r
380                                                 \r
381                                                 if( halfway ){\r
382                                                         this._timerID = X.Timer.once( this.endTime - this._rawObject.Position.Seconds * 1000, this, this._onEnded );\r
383                                                 } else {\r
384                                                         delete this._timerID;\r
385                                                 };\r
386 \r
387                                         };\r
388                                         if( result & 4 ){\r
389                                this._rawObject.Volume = this.volume;\r
390                                         };\r
391                                 };\r
392                         },\r
393                         \r
394                                 // SilverlightAudio.currentTime\r
395                                 _currentTime : function( time ){ // @param Number: time\r
396                                         var position = this._rawObject.Position; // [!] create instance\r
397         \r
398                                         position.Seconds = time / 1000; // set current time\r
399                                 \r
400                                         this._rawObject.Position = position; // [!] reattach instance\r
401                                 }\r
402 \r
403                 }\r
404         );\r
405         \r
406 };\r
407 \r
408 \r
409 \r