OSDN Git Service

Version 0.6.183, refactoring X.HTMLAudio.
[pettanr/clientJs.git] / 0.6.x / js / 07_audio / 02_XHTMLAudio.js
index 4095242..2c64eeb 100644 (file)
@@ -79,26 +79,27 @@ if( X_Audio_constructor ){
                X_Class.POOL_OBJECT,\r
                {\r
                        _closed               : true,\r
-                       _loaded               : false,\r
-                       _ready            : false,\r
-                       _src                      : '',\r
-                       \r
-                       //  0:\r
-                       //  1: touch 要求完了\r
-                       //  2: touch による play 中\r
-                       //  4: duration 取得完了 currentTime へのセット\r
-                       //  8: playing || loadeddata or canplaythrought\r
-                       // 16: READY 発火済\r
+\r
+                       // 1: canplaythrought|timeupdateに達している、またはdurationFixが終了している\r
+                       // 2: READY イベント発火済\r
                        _readyState       : 0,\r
+                       _src                      : '',\r
                        \r
-                       _touchRequested   : false,\r
-                       _touched          : false,\r
+                       // 0:ok\r
+                       // 1:touch 要求済\r
+                       // 2:touch による play 済\r
+                       _touchState       : X_HTMLAudio_need1stTouch ? 1 : 0,\r
                        \r
                        _currentFixStart  : 0,\r
                        _currentFixBegin  : 0,\r
 \r
+                       // 0:durationFix不要 または 完了\r
+                       // 1:durationFix未着手(touchState=1なら play() に入れる)\r
+                       // 2:canplay イベント発生 -> play()\r
+                       // 4:play() 実施済\r
+                       // 8:duration 取得済\r
+                       //  :timeupdate イベントで durationFixは完了\r
                        _durationFixPhase : X_HTMLAudio_durationFix ? 1 : 0,\r
-                       _durationFixSkip  : X_HTMLAudio_durationFix && !X_HTMLAudio_need1stTouch,\r
                        _lastCurrentTime  : 0,\r
 \r
                        _shortPlayFixON   : false,\r
@@ -132,8 +133,7 @@ if( X_Audio_constructor ){
                                        X_elmBody.appendChild( raw );\r
                                } else {\r
                                        raw = X_TEMP.rawAudio || new X_Audio_constructor( '' );\r
-                                       // X_Doc_create( 'audio', { src : source } )[ 'appendTo' ]( X.Doc.body );\r
-                                       //raw.autoplay = raw.autobuffer = raw.loop = false; // loop を使えば ended で止まること回避できるかも 但し ended イベントが起きなくなる\r
+                                       // raw.loop = false; // loop を使えば ended で止まること回避できるかも 但し ended イベントが起きなくなる\r
                                        \r
                                        if( X_TEMP.rawAudio ) delete X_TEMP.rawAudio;\r
                                };\r
@@ -163,8 +163,10 @@ if( X_Audio_constructor ){
                                if( X_HTMLAudio_need1stTouch ){\r
                                        raw.src = source;\r
                                } else {\r
-                                       raw.preload  = 'auto';\r
-                                       raw.autoplay = true; // Android 4.0-4.1.x で必要\r
+                                       // if( this.autoplay ){\r
+                                               raw.preload  = 'auto';\r
+                                               raw.autoplay = true; // Android 4.0-4.1.x で必要\r
+                                       //};\r
                                        //raw.autobuffer = true;\r
                                        raw.src = source;\r
                                        raw.load(); // Android4.1.1 HTL21 では必要!\r
@@ -175,17 +177,21 @@ if( X_Audio_constructor ){
                                this.disatcher[ 'dispatch' ]( {\r
                                        type       : X_EVENT_DEBUG,\r
                                        'rawEvent' : e.type,\r
-                                       current    : this.getActualCurrentTime() | 0,\r
+                                       current    : this[ '_rawObject' ].currentTime,\r
                                        duration   : this[ '_rawObject' ].duration } );\r
                        },\r
                        \r
                        handleEvent : function( e ){\r
+                               if( !e || !e.type ) alert( 888 );\r
+                               \r
                                var raw    = this[ '_rawObject' ],\r
                                        actualEnded = e.type === 'ended',\r
                                        ended       = actualEnded,\r
                                        ready,\r
                                        eventType, duration, end, now;\r
                                \r
+                               if( this._closed ) return;\r
+                               \r
                                // global に公開\r
                                //window[ '__rawAudio' ] = this[ '_rawObject' ];\r
                                \r
@@ -194,13 +200,12 @@ if( X_Audio_constructor ){
                                switch( e.type ){\r
 \r
                                        case X_EVENT_KILL_INSTANCE :\r
-                                               // 【javascript】モバイル向けブラウザでも音を鳴らしたい【WebAudio】\r
-                                               // http://ingaouhou.com/archives/3633\r
-                                               // ・使い終わったインスタンスはload()しておくとやや安定\r
-                                               this.playing && this.actualPause();\r
                                                delete this._closed;\r
-                                               delete this._loaded;\r
+                                               this.playing && this.actualPause();\r
                                                \r
+                                               // 【javascript】モバイル向けブラウザでも音を鳴らしたい【WebAudio】\r
+                                               // http://ingaouhou.com/archives/3633\r
+                                               // ・使い終わったインスタンスはload()しておくとやや安定                                          \r
                                                raw.src = '';\r
                                                raw.load();\r
                                                \r
@@ -218,13 +223,14 @@ if( X_Audio_constructor ){
                                        \r
                                        case 'loadeddata' :      //     コンテンツの表示を現在の再生位置で初めて行えるようになった場合に発生\r
                                        case 'canplaythrough' : //      今すぐに再生を開始してもバッファリングで停止することなく最後まで表示できると予測している場合に発生\r
-                                               if( !this._endedFixON ){\r
-                                                       ready = true;\r
+                                               if( !this._endedFixON && !X_HTMLAudio_durationFix && !X_HTMLAudio_need1stTouch ){\r
+                                                       this._readyState |= 1;\r
                                                };\r
                                        case 'canplay' :                //      今すぐに再生を再開できるが、バッファリングが不十分でコンテンツを最後まで表示できないと予測している場合に発生\r
-                                               if( X_HTMLAudio_durationFix && !X_HTMLAudio_need1stTouch && this._durationFixPhase === 1 ){\r
+                                               if( this._durationFixPhase === 1 && !X_HTMLAudio_need1stTouch ){\r
+                                                       this._durationFixPhase = 2;\r
                                                        this.actualPlay();\r
-                                                       raw.currentTime = 0; // å¿\85è¦\81ï¼\81\r
+                                                       raw.currentTime = 0; // Win8 + Opera12 ã\81§å¿\85è¦\81\r
                                                };\r
                                                if( this._endedFixON ){\r
                                                        console.log( '▽ onEndedFix の終了 @' + e.type  );\r
@@ -240,32 +246,38 @@ if( X_Audio_constructor ){
        \r
                                        // TODO firefox で 短い音声でtimeupdate, ended が発火しない <- 最後の音に無音部分を追加する\r
                                        case 'timeupdate' :      //     通常の再生が行われ現在の再生位置の変化が起こった場合に発生\r
-                                               if( this._durationFixPhase & 3 ){ // 1 or 2\r
+                                               if( this._durationFixPhase === 8 ){\r
+                                                       this._durationFixPhase = 0;\r
+                                                       this._readyState |= 1;\r
+                                               } else\r
+                                               if( this._durationFixPhase === 4 ){ // 1 or 2\r
                                                        duration = raw.duration;\r
+                                                       eventType = X_EVENT_MEDIA_WAITING;\r
+                                               } else\r
+                                               if( !X_HTMLAudio_durationFix && X_HTMLAudio_need1stTouch && this._touchState === 3 ){\r
+                                                       this._touchState  = 0;\r
+                                                       this._readyState |= 1;\r
                                                } else\r
                                                if( ( now = this.getActualCurrentTime() ) === this._lastCurrentTime ){\r
                                                        eventType = X_EVENT_MEDIA_WAITING;\r
-                                               } else {\r
-                                                       this._lastCurrentTime = now; // *1 rm\r
-\r
-                                                       if( this.playing ){\r
-                                                               end = X_Audio_getEndTime( this ) + this._shortPlayFixTime;\r
-                                                               //console.log( now + ' / ' + end );\r
-                                                               // || now < this._lastCurrentTime // loop した場合\r
-                                                               if( 0 + end <= 0 + now ){ // 0+ なぜか iem9 で必要,,,\r
-                                                                       if( this.autoLoop ){\r
-                                                                               console.log( '☆★☆ 曲の最後に到達 @timeupdate now-end:' + ( now - end ) );\r
-                                                                               ended = true;\r
-                                                                               if( X_HTMLAudio_endedFixIOS ) actualEnded = true;\r
-                                                                       } else {\r
-                                                                               this.actualPause();\r
-                                                                               eventType = X_EVENT_MEDIA_ENDED;\r
-                                                                       };\r
+                                               } else\r
+                                               if( this.playing ){\r
+                                                       end = X_Audio_getEndTime( this ) + this._shortPlayFixTime;\r
+                                                       //console.log( now + ' / ' + end );\r
+                                                       // || now < this._lastCurrentTime // loop した場合\r
+                                                       if( 0 + end <= 0 + now ){ // 0+ なぜか iem9 で必要,,,\r
+                                                               if( this.autoLoop ){\r
+                                                                       console.log( '☆★☆ 曲の最後に到達 @timeupdate now-end:' + ( now - end ) );\r
+                                                                       ended = true;\r
+                                                                       if( X_HTMLAudio_endedFixIOS ) actualEnded = true;\r
                                                                } else {\r
-                                                                       eventType = X_EVENT_MEDIA_PLAYING;\r
-                                                                       // *1 this._lastCurrentTime = now;\r
+                                                                       this.actualPause();\r
+                                                                       eventType = X_EVENT_MEDIA_ENDED;\r
                                                                };\r
+                                                       } else {\r
+                                                               eventType = X_EVENT_MEDIA_PLAYING;\r
                                                        };\r
+                                                       this._lastCurrentTime = now;\r
                                                };\r
                                                break;\r
        \r
@@ -289,7 +301,7 @@ if( X_Audio_constructor ){
                                                //if( X_HTMLAudio_currentTimeFix && !this._currentFixStart ){\r
                                                        //this._currentFixStart = X_Timer_now(); // 正確な再生開始時間に補正\r
                                                //};\r
-                                               eventType = !this._durationFixSkip && !this._endedFixON ? X_EVENT_MEDIA_PLAYING : X_EVENT_MEDIA_WAITING;\r
+                                               eventType = !this._durationFixPhase && !this._endedFixON ? X_EVENT_MEDIA_PLAYING : X_EVENT_MEDIA_WAITING;\r
                                        //case 'play' :            //   再生が開始された。play()メソッドからの復帰後に発生する場合に発生\r
                                        //case 'pause' :                  //    再生が一時停止された。pauseメソッドからの復帰後に発生する場合に発生\r
                                        //case 'seeked' : \r
@@ -309,15 +321,12 @@ if( X_Audio_constructor ){
                                if( 0 < duration && X_Type_isFinite( duration ) ){\r
                                        this.duration = duration * 1000;\r
 \r
-                                       if( this._durationFixPhase === 2 ){\r
+                                       if( this._durationFixPhase === 4 ){\r
                                                console.log( '▼ DurationFix の終了 @' + e.type );\r
-                                               this._durationFixPhase = 4;\r
+                                               this._durationFixPhase = 8;\r
                                                \r
-                                               ready = true;\r
-                                               \r
-                                               if( this.autoplay || this._loaded ){\r
+                                               if( this.autoplay ){\r
                                                        console.log( '☆ 再生 <- DurationFix の終了' );\r
-                                                       this._durationFixSkip = false;\r
                                                        this.actualPlay();\r
                                                } else\r
                                                if( X_HTMLAudio_pauseFix ){\r
@@ -327,23 +336,20 @@ if( X_Audio_constructor ){
                                                        this.actualPause();                             \r
                                                };\r
                                        } else\r
-                                       if( this._durationFixPhase ){\r
-                                               this._durationFixPhase = 4;\r
+                                       if( this._durationFixPhase & 3 ){ // === 1 | 2\r
+                                               this._durationFixPhase = 8;\r
                                        };                                      \r
                                };\r
 \r
-                               this._loaded  = this._loaded || ready;\r
-\r
                                //\r
-                               if( X_HTMLAudio_need1stTouch && !this._touchRequested ){ // !this._readyState\r
+                               if( this._touchState === 1 ){\r
                                        if( e.type === X_HTMLAudio_playTrigger ){\r
-                                               this._touchRequested = true;\r
-                                               this._readyState     = 1;\r
-                                               this.disatcher[ 'asyncDispatch' ]( X_EVENT_MEDIA_CAN_TOUCH_LOAD );                                              \r
+                                               this._touchState = 2;\r
+                                               this.disatcher[ 'asyncDispatch' ]( X_EVENT_MEDIA_TOUCH_FOR_LOAD );                                              \r
                                        };\r
                                } else\r
                                if( ended ){\r
-                                       if( !this._closed && this.autoLoop ){\r
+                                       if( this.autoLoop ){\r
                                                if( !( this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){\r
                                                        this.looped = true;\r
                                                        this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );\r
@@ -358,49 +364,45 @@ if( X_Audio_constructor ){
                                                this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
                                        };\r
                                } else\r
-                               if( this._loaded && this.duration && !this._ready ){\r
-                                       this._ready = true;\r
+                               if( this._readyState === 1 && this.duration ){\r
+                                       this._readyState = 3;\r
                                        this.disatcher[ 'asyncDispatch' ]( X_EVENT_READY );\r
-                                       this.autoplay && !X_HTMLAudio_need1stTouch && X_Timer_once( 16, this, this.actualPlay );\r
+                                       this.autoplay && X_Timer_once( 16, this, this.actualPlay );\r
                                        console.log( '> Audio Loaded!! ' + e.type + ' d:' + ( this.duration | 0 ) );\r
                                } else\r
                                if( eventType ){\r
                                        this.disatcher[ 'dispatch' ]( eventType );\r
-                                       // eventType === X_EVENT_ERROR && this[ 'kill' ]();\r
                                };\r
                        },\r
 \r
                        actualPlay : function( forcePlay, forceReload ){\r
                                var raw = this[ '_rawObject' ],\r
                                        e, begin, end;\r
-                               \r
-                               // もし kill 後に autoplayTimer で呼ばれても、_closed==true なので平気\r
+\r
                                if( this._closed ) return;\r
                                \r
-                               \r
                                if( !raw.src ){ // X_HTMLAudio_pauseFix によって src が空になっている\r
                                        console.log( '○ 削除された audio.src の復帰' );\r
                                        raw.src = this._src;\r
-                                       //return;\r
+                                       return;\r
                                };                              \r
-                               \r
-                               if( this._touchRequested && !this._touched ){ // this._readyState === 1\r
+\r
+                               if( this._touchState === 2 ){\r
                                        e = X_EventDispatcher_CURRENT_EVENTS[ X_EventDispatcher_CURRENT_EVENTS.length - 1 ];\r
                                        if( !e || !e[ 'pointerType' ] ){\r
-                                               alert( 'タッチイベント以外での play! ' + e.type );\r
+                                               alert( 'タッチイベント以外での play! ' + ( e ? e.type : '' ) );\r
                                                return;\r
                                        };\r
-                                       this._touched = true;\r
-                                       this._readyState = 2;\r
+                                       this._touchState = 3;\r
                                } else\r
-                               if( !this._ready && ( !X_HTMLAudio_durationFix || !X_HTMLAudio_need1stTouch ) ){ // this._readyState < 2\r
+                               if( this._readyState !== 3 && this._durationFixPhase < 2 ){\r
                                        this.autoplay = true;\r
                                        return;\r
                                };\r
-\r
-                               if( X_HTMLAudio_durationFix && X_HTMLAudio_need1stTouch && this._durationFixPhase === 1 ){\r
-                                       console.log( '▲ DurationFix の開始(タッチ用)' );\r
-                                       this._durationFixPhase = 2;\r
+                               \r
+                               if( this._durationFixPhase & 3 ){ // 1 or 2\r
+                                       console.log( '▲ DurationFix の開始' );\r
+                                       this._durationFixPhase = 4;\r
                                };\r
 \r
                                end   = X_Audio_getEndTime( this );\r
@@ -415,7 +417,7 @@ if( X_Audio_constructor ){
                                        };\r
                                };\r
 \r
-                               if( this._durationFixSkip || this._endedFixON ){\r
+                               if( this._endedFixON ){\r
                                        console.log( '☆ audio.play をスキップ ' + begin + ' -> ' + end + ' crt:' + ( raw.currentTime | 0 ) );\r
                                } else {\r
                                        if( !this.playing ){\r
@@ -437,7 +439,8 @@ if( X_Audio_constructor ){
                                        //また、GoogleChrome7 では currentTime = 0 直後に play() すると、pause()した位置前後の音が混ざることがある。(少なくとも自分の環境では)\r
 \r
                                        // iOS で duration が 0 の時に触ると error\r
-                                       if( !X_HTMLAudio_durationFix || this.duration ) raw.currentTime = this._lastCurrentTime; // 2 < this._readyState\r
+                                       // 0 or 8\r
+                                       if( !( this._durationFixPhase % 8 ) && this.duration ) raw.currentTime = this._lastCurrentTime;\r
 \r
                                        console.log( '[HTMLAudio] play ' + begin + ' -> ' + end + ' crt:' + ( raw.currentTime | 0 ) + ' last:' + this._lastCurrentTime );\r
 \r
@@ -474,7 +477,6 @@ if( X_Audio_constructor ){
                                        raw.src = '';\r
                                        if( X_HTMLAudio_durationFix ){\r
                                                delete this._durationFixPhase;\r
-                                               delete this._durationFixSkip;\r
                                        };\r
                                };\r
                                delete this.playing;\r