OSDN Git Service

Version 0.6.149, fix X.Audio & X.UI.
[pettanr/clientJs.git] / 0.6.x / js / 07_audio / 03_XSilverlightAudio.js
index f4b84ab..fd9f694 100644 (file)
@@ -18,27 +18,12 @@ var X_Audio_SLAudioWrapper,
 if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] ){\r
        \r
        // X.Node.inherits はできない。_rawObject は <object> でなく silverlight\r
-       X_Audio_SLAudioWrapper = X_EventDispatcher[ 'inherits' ](\r
+       X_Audio_SLAudioWrapper = X_Audio_AbstractAudioBackend[ 'inherits' ](\r
                'X.AV.SilverlightAudioWrapper',\r
                X_Class.POOL_OBJECT,\r
                {\r
-                       '_rawType'      : X_EventDispatcher_EVENT_TARGET_TYPE.SILVER_LIGHT,\r
-               proxy           : null,\r
-               \r
-                       startTime       : 0,\r
-                       endTime         : -1,\r
-                       loopStartTime   : -1,\r
-                       loopEndTime     : -1,\r
-                       seekTime        : -1,\r
-                       duration        : 0,\r
-                       \r
-                       playing         : false,\r
-                       error           : 0,                    \r
-                       loop            : false,\r
-                       looped          : false,\r
-                       autoplay        : false,\r
-                       volume          : 0.5,\r
-               \r
+                       '_rawType'      : X_EventDispatcher_EVENT_TARGET_SILVER_LIGHT,\r
+\r
                _onload         : '',\r
                _callback       : null,                 \r
                xnodeObject     : null,\r
@@ -49,13 +34,13 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] ){
                        _lastState      : '',\r
                        _interval       : 0, // setInterval timer id\r
                        \r
-                       Constructor : function( proxy, source, option ){\r
+                       Constructor : function( target, source, option ){\r
+                               var xnodeScript;\r
                                \r
                                if( !X_Audio_SLAudio_uid ){\r
                                        // source\r
-                                       // X_Node_systemNode[ 'create' ]( 'script', { type : 'text/xaml', id : 'silverlightaudio' } )\r
-                                       //      [ 'text' ]( '<Canvas xmlns="http://schemas.microsoft.com/client/2007" ' +\r
-                                       // 'xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"></Canvas>');\r
+                                       //xnodeScript = X_Node_head[ 'create' ]( 'script', { type : 'text/xaml', id : 'silverlightaudio' } );\r
+                                       //xnodeScript[ '_rawObject' ].innerHTML = '<Canvas xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"></Canvas>';\r
                                        \r
                                        // html に以下を書いた                     \r
                                        // <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
@@ -67,7 +52,7 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] ){
                                 */\r
                                \r
                                // TODO embed\r
-                               this.proxy       = proxy;\r
+                               this.target      = target || this;\r
                                this._source     = source;\r
                                // X.Audio._slOnload_ は不可\r
                        this._onload     = 'XAudioSilverlightOnLoad' + ( ++X_Audio_SLAudio_uid );\r
@@ -88,31 +73,29 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] ){
                                            //'<param value="true" name="autoUpgrade">' +\r
                                            //'<param name="onerror" value="slerror">' // bond to global\r
                                        );\r
-                               X_AudioWrapper_updateStates( this, option );\r
+                               this.setState( option );\r
        \r
                                this[ 'listenOnce' ]( X_EVENT_KILL_INSTANCE );\r
                        },\r
                        \r
-                       onSLReady : function( sender ){\r
-                               if( !this._onload ) return;\r
-                               \r
-                               window[ this._onload ] = null;\r
-                               delete this._onload;\r
-                               X_Callback_correct( this._callback );\r
-                               delete this._callback;\r
-\r
-                               sender.children.add(\r
-                                       sender.GetHost().\r
-                                       content.\r
-                                       CreateFromXaml(\r
-                                       '<Canvas xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">' +\r
-                                               '<MediaElement x:Name="media" Source="' + this._source + '" Volume="' + this.volume + '" AutoPlay="false" />' +\r
-                                       '</Canvas>'));\r
-               \r
-                               this[ '_rawObject' ] = sender.findName('media'); // x:Name='media'\r
-\r
-                               this[ 'listen' ]( [ 'MediaFailed', 'MediaOpened', 'MediaEnded', 'CurrentStateChanged' ] );\r
-                       },\r
+                               onSLReady : function( sender ){\r
+                                       if( !this._onload ) return;\r
+                                       \r
+                                       window[ this._onload ] = null;\r
+                                       delete this._onload;\r
+                                       X_Callback_correct( this._callback );\r
+                                       delete this._callback;\r
+       \r
+                                       sender[ 'children' ][ 'add' ](\r
+                                               sender[ 'GetHost' ]()[ 'content' ][ 'CreateFromXaml' ](\r
+                                               '<Canvas xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">' +\r
+                                                       '<MediaElement x:Name="media" Source="' + this._source + '" Volume="' + this.gain + '" AutoPlay="false" />' +\r
+                                               '</Canvas>'));\r
+                       \r
+                                       this[ '_rawObject' ] = sender[ 'findName' ]( 'media' ); // x:Name='media'\r
+       \r
+                                       this[ 'listen' ]( [ 'MediaFailed', 'MediaOpened', 'MediaEnded', 'CurrentStateChanged' ] );\r
+                               },\r
                        \r
                        handleEvent : function( e ){\r
                                var lastState, currentState;\r
@@ -125,30 +108,31 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] ){
                                                this.playing = false;\r
                                                this._ended  = true;\r
                                                this._paused = false;\r
-                                               this.proxy[ 'dispatch' ]( X_EVENT_ERROR ); // open failed\r
+                                               if( this.playing ){\r
+                                                       //X_Timer_once( 16, this, this.actualPlay );\r
+                                               } else {\r
+                                                       this.target[ 'dispatch' ]( X_EVENT_ERROR ); // open failed\r
+                                                       this[ 'kill' ]();                                                       \r
+                                               };\r
                                                break;\r
 \r
                                        case 'MediaOpened' :\r
                                                // http://msdn.microsoft.com/ja-jp/library/bb979710(VS.95).aspx\r
-                                               this.duration = this[ '_rawObject' ].NaturalDuration.Seconds * 1000;\r
-                                               // TODO 'canplaythrough'\r
-                                               //this.proxy[ 'asyncDispatch' ]( 'loadstart' );\r
-                               //this.proxy[ 'asyncDispatch' ]( 'loadedmetadata' );\r
-                               //this.proxy[ 'asyncDispatch' ]( 'loadeddata' );\r
-                               //this.proxy[ 'asyncDispatch' ]( 'canplay' );\r
-                               //this.proxy[ 'asyncDispatch' ]( 'canplaythrough' );\r
-                               this.proxy[ 'asyncDispatch' ]( X_EVENT_READY );\r
+                                               this.duration = this[ '_rawObject' ][ 'NaturalDuration' ][ 'Seconds' ] * 1000;\r
+                               this.target[ 'asyncDispatch' ]( X_EVENT_READY );\r
                                \r
-                               this.autoplay && X_Timer_once( 16, this, this.play );\r
+                               this.autoplay && X_Timer_once( 16, this, this.actualPlay );\r
                                                break;\r
 \r
-                                       case 'MediaEnded' :                             \r
-                                               this.loop && this.playing && this.play();\r
+                                       case 'MediaEnded' :\r
+                                               //console.log( ' > ' +  this.autoLoop + ' error:' + this.error );\r
+                                               //this.autoLoop && /* this.playing && */ this.actualPlay();\r
+                                               this._ended   = true;\r
                                                break;\r
 \r
                                        case 'CurrentStateChanged' :\r
                                                lastState        = this._lastState,\r
-                                               currentState = this[ '_rawObject' ].CurrentState;\r
+                                               currentState = this[ '_rawObject' ][ 'CurrentState' ];\r
                                \r
                                                // ignore consecutive events or 'Closed' == 'Error'\r
                                                if( lastState === currentState\r
@@ -157,15 +141,17 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] ){
                                                };\r
                                                this._lastState = currentState; // update last state\r
                                \r
+                                               console.log( ' > ' + currentState + ' - ' + this._lastUserAction );\r
+                               \r
                                                switch( currentState ){\r
                                                        case 'Buffering' :\r
                                                        case 'Opening' :\r
                                                                switch( this._lastUserAction ){\r
                                                                        case 'play' :\r
-                                                                               this.proxy[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );\r
+                                                                               this.target[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );\r
                                                                                break;\r
                                                                        case 'seek' :\r
-                                                                               this.proxy[ 'dispatch' ]( X_EVENT_MEDIA_SEEKING );\r
+                                                                               this.target[ 'dispatch' ]( X_EVENT_MEDIA_SEEKING );\r
                                                                                break;\r
                                                                        case 'pause' :\r
                                                                                break;\r
@@ -182,23 +168,26 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] ){
                                                                this.playing = false;\r
                                                                this._ended  = true;\r
                                                                this._paused = false;\r
-                                                               this.proxy[ 'dispatch' ]( X_EVENT_ERROR );\r
+                                                               this.target[ 'dispatch' ]( X_EVENT_ERROR );\r
+                                                               this[ 'kill' ]();\r
                                                                break;\r
 \r
                                                        // userAction.pause()              -> MediaState('Paused') -> x\r
                                                        // userAction.stop()                    -> MediaState('Paused') -> x\r
                                                        // userAction.play() + file end -> MediaState('Paused') -> uueventfire('ended')\r
                                                        case 'Paused':\r
-                                                               this.playing = false;\r
+                                                       \r
+                                                               this.playing && X_Timer_once( 16, this, this.actualPlay );\r
+                                                               //this.playing = false;\r
                                                                \r
                                                                switch( this._lastUserAction ){\r
                                                                        case 'play': // play() -> file end -> event('ended')\r
                                                                        case 'seek':\r
-                                                                               this.seekTime = 0;\r
+                                                                               //this.seekTime = 0;\r
                                                                                this._ended   = true;\r
                                                                                this._paused  = false;\r
-                                                                               this.proxy[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
-                                                                               this._currentTime( this.startTime );\r
+                                                                               //this.target[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
+                                                                               //this.setCurrentTime( this.startTime );\r
                                                                                break;\r
                                                                        case 'pause':\r
                                                                                this._ended  = false;\r
@@ -213,23 +202,29 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] ){
                                                        // media.play -> 'Playing'\r
                                                        case 'Playing':\r
                                                                this.error   = 0;\r
-                                                               this.playing = true;\r
+                                                               //this.playing = true;\r
                                                                this._ended  = false;\r
                                                                this._paused = false;\r
-                                                               this.proxy[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING );\r
+                                                               this.target[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING );\r
                                                                break;\r
 \r
                                                        // stop()\r
                                                        case 'Stopped':\r
-                                                               this.playing = false;\r
+                                                               this.playing && X_Timer_once( 16, this, this.actualPlay );\r
+                                                               return;\r
+                                                               \r
+                                                               //this.playing = false;\r
                                                                this._ended  = true;\r
                                                                this._paused = false;\r
-                                                               this._currentTime( this.startTime );\r
+                                                               //this.setCurrentTime( this.startTime );\r
                                                                break;\r
                                                };\r
                                                break;\r
 \r
                                        case X_EVENT_KILL_INSTANCE :\r
+                                               this.playing && this.target[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
+                                               this.playing && this.actualPause();\r
+                                       \r
                                                if( this._onload ){\r
                                                        // window への delete に ie5 は対応しないが、そもそも ie5 は Silverlight に非対応\r
                                                        window[ this._onload ] = null;\r
@@ -241,16 +236,10 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] ){
                                };\r
                        },\r
                        \r
-                       close : function(){\r
-                               this.playing && this.pause();\r
-                               this.proxy[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
-                               this[ 'kill' ]();\r
-                       },\r
-                       \r
                        // SilverlightAudio.play\r
-                       play : function(){\r
-                               var begin, end;\r
-                               \r
+                       actualPlay : function(){\r
+                               var begin, offset, end;\r
+\r
                                // もし kill 後に autoplayTimer で呼ばれても、_closed==true なので平気\r
                                if( this.error ) return;\r
                                if( !this.duration ){\r
@@ -262,27 +251,33 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] ){
                                \r
                                end   = X_AudioWrapper_getEndTime( this );\r
                                begin = X_AudioWrapper_getStartTime( this, end, true ) | 0;\r
-                               \r
-                               console.log( '[SLAudio] play ' + begin + ' -> ' + end );\r
-                               \r
-                           this[ '_rawObject' ].Volume = this.volume;\r
-                           this._beginTime = begin;\r
-                           this._currentTime( begin );\r
+\r
+                               // 1 秒以下は指定できないため四捨五入\r
+                               begin = ( begin / 1000 | 0 ) * 1000 + ( 500 < begin % 1000 ? 1000 : 0 ); \r
+\r
+                           this[ '_rawObject' ][ 'Volume' ] = this.gain;\r
                            \r
-                           if( !this.playing ){\r
+                           this.setCurrentTime( this._beginTime = begin );\r
+                           \r
+                           console.log( '[play] ' + begin + ' -> ' + end );\r
+                           \r
+                           /*\r
+                           if( offset = begin - this.getActualCurrentTime() ){\r
+                               this.setCurrentTime( begin + offset );\r
+                               console.log( ' [差補正] ' + offset + ' ct:' + this.getActualCurrentTime() + ' begin:' + begin  );\r
+                               this._beginTime = begin = this.getActualCurrentTime();\r
+                           };*/\r
+                           \r
+                           if( !this.playing || this._ended ){\r
+                               console.log( '[play] play()' + begin + ' -> ' + end );\r
                                    this[ '_rawObject' ].play();\r
-                           //this.proxy[ 'dispatch' ]( 'play' );\r
-                           \r
                            this.playing = true;\r
+                           this._ended  = false;\r
                            };\r
                    \r
                    this._timerID && X_Timer_remove( this._timerID );\r
                    \r
-                if( end < this.duration ){\r
-                                       this._timerID = X_Timer_once( end - begin, this, this._onEnded );\r
-                } else {\r
-                       delete this._timerID;\r
-                };\r
+                this._timerID = X_Timer_once( end - begin, this, this._onEnded );\r
                 \r
                                if( !this._interval ){\r
                                        this._interval = X_Timer_add( 1000, 0, this, this._onInterval );\r
@@ -294,7 +289,7 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] ){
                                                delete this._interval;\r
                                                return X_Callback_UN_LISTEN;\r
                                        };\r
-                                       this.proxy[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING );\r
+                                       this.target[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING );\r
                                },\r
                                \r
                                _onEnded : function(){\r
@@ -302,103 +297,91 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] ){
                                        delete this._timerID;\r
                                        \r
                            if( this.playing ){\r
-                               console.log( '> end ' + X_AudioWrapper_getEndTime( this ) + ' current:' + ( this[ '_rawObject' ].Position.Seconds * 1000 | 0 ) );\r
-                               time = this[ '_rawObject' ].Position.Seconds * 1000 | 0;\r
+                               //console.log( '> end ' + X_AudioWrapper_getEndTime( this ) + ' current:' + ( this.getActualCurrentTime() ) );\r
+                               time = this.getActualCurrentTime();\r
                                \r
-                               if( time <= this._beginTime ){\r
-                                       console.log( '== waiting' );\r
-                                       this.proxy[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );\r
-                                       this._timerID = X_Timer_once( X_AudioWrapper_getEndTime( this ) - this._beginTime, this, this._onEnded );\r
+                               if( time < this._beginTime ){\r
+                                       console.log( '== waiting ' + time + ' < begin:' + this._beginTime );\r
+                                       this.setCurrentTime( this._beginTime );\r
+                                       time = this.getActualCurrentTime();\r
+                                       console.log( '    > ' + time );\r
+                                       this._ended && this[ '_rawObject' ].play();\r
+                                       this._ended = false;\r
+                                       this.target[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );\r
+                                       this._timerID = X_Timer_once( X_AudioWrapper_getEndTime( this ) - time, this, this._onEnded );\r
                                        return;\r
                                };\r
                                \r
                                time -= X_AudioWrapper_getEndTime( this );\r
                                if( time < 0 ){\r
-                                       console.log( '> onEnd ' + time );\r
+                                       console.log( ' > まだ終わらない ' + time );\r
+                                       this._ended && this[ '_rawObject' ].play();\r
+                                       this._ended = false;\r
                                        this._timerID = X_Timer_once( -time, this, this._onEnded );\r
                                        return;\r
                                };\r
                                \r
-                               if( this.loop ){\r
-                                       if( !( this.proxy[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_Callback_PREVENT_DEFAULT ) ){\r
+                               if( this.autoLoop ){\r
+                                       console.log( '========= loop?' );\r
+                                       if( !( this.target[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_Callback_PREVENT_DEFAULT ) ){\r
+                                               console.log( '========== loopした' );\r
                                                this.looped = true;\r
-                                               this.proxy[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );\r
-                                               this.play();\r
+                                               this.target[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );\r
+                                               this.actualPlay();\r
                                        };\r
                                } else {\r
-                                       this.pause();\r
-                                       this.proxy[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
+                                       console.log( '========= pause' );\r
+                                       this.actualPause();\r
+                                       this.target[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
                                };\r
                            };\r
                                },\r
                        \r
                        // SilverlightAudio.pause\r
-                       pause : function(){\r
+                       actualPause : function(){\r
                                if( this.error || !this.playing ) return;\r
                                \r
                                this._lastUserAction = 'pause';\r
-                               this.seekTime = this.state().currentTime;\r
+                               this.seekTime = this.getActualCurrentTime();\r
                                this.playing  = false;\r
                                this._paused  = true;\r
                                this._ended   = false;\r
-                                                       \r
+                               \r
                                this[ '_rawObject' ].pause();\r
-                               //this.proxy[ 'dispatch' ]( 'pause' );\r
+                               //this.target[ 'dispatch' ]( 'pause' );\r
                        },\r
-                       \r
-                       // SilverlightAudio.state\r
-                       state : function( obj ){ // @return Hash: { loop, error, paused, ended, source, duration }\r
-                               var result, end;\r
-                               \r
-                               if( obj === undefined ){\r
-                                   return {\r
-                                       startTime     : this.startTime,\r
-                                       endTime       : this.endTime < 0 ? this.duration : this.endTime,\r
-                                       loopStartTime : this.loopStartTime < 0 ? this.startTime : this.loopStartTime,\r
-                                       loopEndTime   : this.loopEndTime < 0 ? ( this.endTime || this.duration ) : this.loopEndTime,\r
-                                       \r
-                                       // 整数化 しておかないと seek 時に不具合がある。\r
-                                       currentTime   : this.playing ? this[ '_rawObject' ].Position.Seconds * 1000 | 0 : this.seekTime,\r
 \r
-                                       loop          : this.loop,\r
-                                       looped        : this.looped,\r
-                                       volume        : this.volume,\r
-                                       error         : this.error,\r
-                                       playing       : this.playing,\r
-                                       duration      : this.duration // this[ '_rawObject' ].NaturalDuration.Seconds;\r
-                                   };\r
-                               };\r
+                       getActualCurrentTime : function(){\r
+                               return this[ '_rawObject' ][ 'Position' ][ 'Seconds' ] * 1000 | 0;\r
+                       },\r
                        \r
-                               result = X_AudioWrapper_updateStates( this, obj );\r
-                           \r
-                               if( result & 2 ){ // seek\r
-                       this.play();\r
-                               } else {\r
-                                       if( result & 1 ){\r
-                                               end     = X_AudioWrapper_getEndTime( this );\r
-                                               halfway = end < this.duration;\r
-                                               this._timerID && X_Timer_remove( this._timerID );\r
-                                               \r
-                                               if( halfway ){\r
-                                                       this._timerID = X_Timer_once( end - this[ '_rawObject' ].Position.Seconds * 1000 | 0, this, this._onEnded );\r
-                                               } else {\r
-                                                       delete this._timerID;\r
-                                               };\r
-\r
-                                       };\r
-                                       if( result & 4 ){\r
-                              this[ '_rawObject' ].Volume = this.volume;\r
+                       afterUpdateState : function( result ){\r
+                               if( result & 3 ){ // seek\r
+                       this.actualPlay();\r
+                               } else\r
+                               if( result & 1 ){\r
+                                       end     = X_AudioWrapper_getEndTime( this );\r
+                                       halfway = end < this.duration;\r
+                                       this._timerID && X_Timer_remove( this._timerID );\r
+                                       \r
+                                       if( halfway ){\r
+                                               this._timerID = X_Timer_once( end - this.getActualCurrentTime(), this, this._onEnded );\r
+                                       } else {\r
+                                               delete this._timerID;\r
                                        };\r
-                               };\r
+                               } else\r
+                               if( result & 4 ){\r
+                      this[ '_rawObject' ][ 'Volume' ] = this.gain;\r
+                               };                      \r
                        },\r
                        \r
                                // SilverlightAudio.currentTime\r
-                               _currentTime : function( time ){ // @param Number: time\r
-                                       var position = this[ '_rawObject' ].Position; // [!] create instance\r
+                               setCurrentTime : function( time ){ // @param Number: time\r
+                                       var position = this[ '_rawObject' ][ 'Position' ]; // [!] create instance\r
        \r
-                                       position.Seconds = time / 1000 | 0; // set current time\r
+                                       position[ 'Seconds' ] = time / 1000 | 0; // set current time\r
                                \r
-                                       this[ '_rawObject' ].Position = position; // [!] reattach instance\r
+                                       this[ '_rawObject' ][ 'Position' ] = position; // [!] reattach instance\r
                                }\r
 \r
                }\r