OSDN Git Service

Version 0.6.175, fix X.UA & X.WebAudio.
authoritozyun <itozyun@user.sourceforge.jp>
Mon, 5 Oct 2015 22:31:06 +0000 (07:31 +0900)
committeritozyun <itozyun@user.sourceforge.jp>
Mon, 5 Oct 2015 22:31:06 +0000 (07:31 +0900)
0.6.x/js/01_core/02_XUA.js
0.6.x/js/01_core/16_XTimer.js
0.6.x/js/07_audio/00_XAudio.js
0.6.x/js/07_audio/01_XWebAudio.js
0.6.x/js/07_audio/02_XHTMLAudio.js
0.6.x/js/07_audio/03_XSilverlightAudio.js

index 8302b97..426b486 100644 (file)
@@ -543,44 +543,37 @@ var X_UA = X[ 'UA' ] = {},
        \r
        if( ( dua.indexOf( 'Linux; U; Android ' ) !== -1 || dua.indexOf( 'Linux; Android ' ) !== -1 ) &&\r
                ( dua.indexOf( 'Chrome\/' ) === -1 || dua.indexOf( 'Version\/' ) !== -1 ) ){ // Chrome/ を含まない または Version/ を含む\r
-               /**\r
-                * Android 標準ブラウザ\r
-                * @alias X.UA.AndroidBrowser\r
-                * @type {number}\r
-                */\r
-               X_UA[ 'AndroidBrowser' ] = X_UA[ 'Android' ];\r
-               \r
-               v = X_UA[ 'AndroidMajor' ];\r
-               \r
-               /**\r
-                * @alias X.UA.AndroidBrowser1\r
-                * @type {boolean}\r
-                */\r
-               X_UA[ 'AndroidBrowser1' ] = v === 1;\r
-               /**\r
-                * @alias X.UA.AndroidBrowser2\r
-                * @type {boolean}\r
-                */\r
-               X_UA[ 'AndroidBrowser2' ] = v === 2;\r
-               /**\r
-                * @alias X.UA.AndroidBrowser3\r
-                * @type {boolean}\r
-                */\r
-               X_UA[ 'AndroidBrowser3' ] = v === 3;\r
-               /**\r
-                * @alias X.UA.AndroidBrowser4\r
-                * @type {boolean}\r
-                */\r
-               X_UA[ 'AndroidBrowser4' ] = v === 4;\r
-               /**\r
-                * @alias X.UA.AndroidBrowser5\r
-                * @type {boolean}\r
-                */\r
-               X_UA[ 'AndroidBrowser5' ] = v === 5;\r
                \r
-               console.log( '>> AndroidBrowser : ' + X_UA[ 'Android' ] );\r
+               /* if( window.chrome ){  // Android3.1 のAOSPブラウザで .chrome がいた、、、\r
+                       //X_UA[ 'Blink' ] = X_UA[ 'ChromeWK' ] = tv;\r
+               } else */\r
+               if( dua.indexOf( 'Version\/' ) === -1 && ( v = parseFloat( dua.split( 'Chrome\/' )[ 1 ] ) ) ){\r
+                       /**\r
+                        * Android 標準ブラウザ Chrome Webkit ラップブラウザ\r
+                        * @alias X.UA.ChromeWK\r
+                        * @type {number}\r
+                        */                     \r
+                       X_UA[ 'ChromeWK' ] = v;\r
+               } else\r
+               // http://uupaa.hatenablog.com/entry/2014/04/15/163346\r
+               // Chrome WebView は Android 4.4 の時点では WebGL や WebAudio など一部の機能が利用できません(can i use)。\r
+               // また UserAgent が書き換え可能なため、旧来のAOSPブラウザの UserAgent を偽装した形で配布されているケースがあります。\r
+               // http://caniuse.com/#compare=chrome+40,android+4.2-4.3,android+4.4,android+4.4.3-4.4.4,and_chr+45\r
+               // CustomElement の有無で判定\r
+               if( document[ 'registerElement' ] ){\r
+                       // UA が偽装された ChromeWK\r
+                       X_UA[ 'ChromeWK' ] = tv;\r
+                       alert( 'UA が偽装された Chrome Webkit' );\r
+               } else {\r
+                       /**\r
+                        * Android 標準ブラウザ AOSP\r
+                        * @alias X.UA.AOSP\r
+                        * @type {number}\r
+                        */\r
+                       X_UA[ 'AOSP' ] = X_UA[ 'Android' ];                     \r
+               };\r
                \r
-               i = parseFloat(dua.split('WebKit\/')[1]);\r
+               i = parseFloat( dua.split( 'WebKit\/' )[ 1 ] );\r
                /**\r
                 * @alias X.UA.AndroidWebkit\r
                 * @type {number}\r
@@ -588,26 +581,28 @@ var X_UA = X[ 'UA' ] = {},
                X_UA[ 'AndroidWebkit' ] = i;\r
                //alert( 'AudioSprite調査:Android標準ブラウザ Webkit Version ' + i );\r
                \r
-               if( window.chrome ){\r
-                       //X_UA[ 'Blink' ] = X_UA[ 'AndroidChromeBrowser' ] = tv;\r
-               } else\r
-               if( v = parseFloat(dua.split('Chrome\/')[1]) ){\r
-                       X_UA[ 'Chrome' ] = X_UA[ 'AndroidChromeBrowser' ] = v;\r
-               };\r
-               \r
-               //if( window[ 'webkitRequestFileSystem' ] ) alert( 'requestFileSystem' );\r
-               \r
-               //alert( 'html.style.WebkitAppearance:' + ( document.documentElement.style[ 'WebkitAppearance' ] === undefined ) + ' win.chrome:' + !!( window.chrome ) );\r
-\r
+               /*\r
+                * http://www.flexfirm.jp/blog/article/402\r
+                * Sブラウザ\r
+                * SC-04E、SC-01F、SC-02F、 SC-04F、SCL22、SCL23など\r
+                */\r
        } else\r
        \r
        // TODO Blink\r
-       if( window.chrome ){ // Android3.1 の標準ブラウザで .chrome がいた、、、\r
+       if( window.chrome ){\r
                /**\r
                 * @alias X.UA.Blink\r
                 * @type {number}\r
                 */\r
-               X_UA[ 'Blink' ] = tv;\r
+               X_UA[ 'Blink' ] = parseFloat( dua.split( 'Chrome/' )[ 1 ] );\r
+               \r
+               if( v = parseFloat( dua.split( 'OPR/' )[ 1 ] ) ){\r
+                       /**\r
+                        * @alias X.UA.BlinkOpera\r
+                        * @type {number}\r
+                        */\r
+                       X_UA[ 'BlinkOpera' ] = v;\r
+               };\r
                console.log( '>>Blink : ' + X_UA[ 'Blink' ] );\r
                \r
        } else\r
index 6069036..681d5f8 100644 (file)
@@ -58,6 +58,7 @@ var
                false,\r
 \r
        X_Timer_CANCEL_ANIME_FRAME =\r
+               window.cancelAnimationFrame ||\r
                window.cancelRequestAnimationFrame ||\r
                window.webkitCancelAnimationFrame ||\r
                window.webkitCancelRequestAnimationFrame ||\r
index 584755e..33faebf 100644 (file)
@@ -1,7 +1,7 @@
 \r
 /*\r
        WebAudio    : 1,\r
-       HTML5       : 2,\r
+       HTMLAudio   : 2,\r
        Flash       : 3,\r
        Silverlight : 4,\r
        Unity       : 5,\r
@@ -15,9 +15,12 @@ var X_Audio_BACKENDS     = []; // Array.<Hash>
 X_TEMP.onSystemReady.push(\r
        function(){\r
                var canPlay = X[ 'Audio' ][ 'canPlay' ] = {},\r
-                       i = X_Audio_BACKENDS.length;\r
+                       i = X_Audio_BACKENDS.length,\r
+                       be;\r
                for( ; i; ){\r
-                       X_Object_override( canPlay, X_Audio_BACKENDS[ --i ].canPlay );\r
+                       be = X_Audio_BACKENDS[ --i ];\r
+                       X_Object_override( canPlay, be.canPlay );\r
+                       X[ 'Audio' ][ be.backendName ] = be.backendID;\r
                };\r
        });\r
 \r
@@ -42,8 +45,8 @@ X_TEMP.onSystemReady.push(
  * <dt>X.Event.MEDIA_LOOPED  <dd>ループ時に発生\r
  * <dt>X.Event.MEDIA_ENDED   <dd>再生位置の(音声の)最後についた\r
  * <dt>X.Event.MEDIA_PAUSED  <dd>ポーズした\r
- * <dt>X.Event.MEDIA_WAITING <dd>再生中に音声が待機状態に。間もなく X.Event.MEDIA_PLAYING に移行。\r
- * <dt>X.Event.MEDIA_SEEKING <dd>シーク中に音声が待機状態に。間もなく X.Event.MEDIA_PLAYING に移行。\r
+ * <dt>X.Event.MEDIA_WAITING <dd>再生中に音声が待機状態に。\r
+ * <dt>X.Event.MEDIA_SEEKING <dd>シーク中に音声が待機状態に。\r
  * </dl>\r
  * \r
  * @alias X.Audio\r
@@ -246,26 +249,25 @@ function X_Audio_onEndedDetection( e, xaudio, sourceList, option, source, ext, s
 \r
 \r
 \r
-var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ](\r
-       'X.AbstractAudioBackend',\r
+var X_AudioBase = X_EventDispatcher[ 'inherits' ](\r
+       'X.AudioBase',\r
        X_Class.ABSTRACT,\r
        {\r
+               url           : '',   //\r
+               target        : null, //\r
                \r
-               url           : '',\r
-               target        : null,\r
-               \r
-               startTime     : 0,\r
-               endTime       : -1,\r
+               startTime     : 0,    //\r
+               endTime       : -1,   //\r
                loopStartTime : -1,\r
                loopEndTime   : -1,\r
                seekTime      : -1,\r
-               duration      : 0,\r
+               duration      : 0,    //\r
 \r
                playing       : false,\r
-               error         : 0,                      \r
+               error         : 0,    //                \r
                autoLoop      : false,\r
                looped        : false,\r
-               autoplay      : false,\r
+               autoplay      : false,//\r
                gain          : 0.5,\r
                \r
                play : function( startTime, endTime, loop, loopStartTime, loopEndTime ){\r
@@ -280,17 +282,20 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ](
                                        'loopEndTime'   : loopEndTime\r
                                } );\r
                        };\r
+                       // canPlay() : autoplay = true\r
                        this.actualPlay();\r
                },\r
                \r
                seek : function( seekTime ){\r
-                       if( seekTime < X_AudioWrapper_getEndTime( this ) ){\r
+                       if( seekTime < X_Audio_getEndTime( this ) ){\r
                                this.setState( { 'currentTime' : seekTime } );\r
                        };\r
                },\r
                \r
                pause : function(){\r
                        this.playing && this.actualPause();\r
+                       // delete this.autoplay\r
+                       // delete this.playing\r
                },              \r
                \r
                loop : function( v ){\r
@@ -341,7 +346,7 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ](
                                v = obj[ k ];\r
                                switch( k ){\r
                                        case 'currentTime' :\r
-                                               v = X_AudioWrapper_timeStringToNumber( v );\r
+                                               v = X_Audio_timeStringToNumber( v );\r
                                                if( X_Type_isNumber( v ) ){\r
                                                        if( playing ){\r
                                                                if( this.getActualCurrentTime() !== v ){\r
@@ -357,7 +362,7 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ](
                                                break;\r
                                                        \r
                                        case 'startTime'     :\r
-                                               v = X_AudioWrapper_timeStringToNumber( v );\r
+                                               v = X_Audio_timeStringToNumber( v );\r
                                                if( v || v === 0 ){\r
                                                        if( this.startTime !== v ){\r
                                                                this.startTime = v;                                     \r
@@ -368,7 +373,7 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ](
                                                break;\r
                                        \r
                                        case 'endTime'       :\r
-                                               v = X_AudioWrapper_timeStringToNumber( v );\r
+                                               v = X_Audio_timeStringToNumber( v );\r
                                                if( v || v === 0 ){\r
                                                        if( this.endTime !== v ){\r
                                                                this.endTime = v;\r
@@ -381,7 +386,7 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ](
                                                break;\r
                                                \r
                                        case 'loopStartTime' :\r
-                                               v = X_AudioWrapper_timeStringToNumber( v );\r
+                                               v = X_Audio_timeStringToNumber( v );\r
                                                if( v || v === 0 ){\r
                                                        if( this.loopStartTime !== v ){\r
                                                                this.loopStartTime = v;                                 \r
@@ -392,7 +397,7 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ](
                                                break;\r
                                                \r
                                        case 'loopEndTime'   :\r
-                                               v = X_AudioWrapper_timeStringToNumber( v );\r
+                                               v = X_Audio_timeStringToNumber( v );\r
                                                if( v || v === 0 ){\r
                                                        if( this.loopEndTime !== v ){\r
                                                                this.loopEndTime = v;\r
@@ -442,7 +447,7 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ](
                        \r
                        if( this.endTime < this.startTime ||\r
                                ( this.loopEndTime < 0 ? this.endTime : this.loopEndTime ) < ( this.loopStartTime < 0 ? this.startTime : this.loopStartTime ) ||\r
-                               X_AudioWrapper_getEndTime( this ) < this.seekTime// ||\r
+                               X_Audio_getEndTime( this ) < this.seekTime// ||\r
                                //this.duration < this.endTime\r
                        ){\r
                                console.log( 'setState 0:' + this.startTime + ' -> ' + this.endTime + ' looped:' + this.looped + ' 1:' + this.loopStartTime + ' -> ' + this.loopEndTime );\r
@@ -450,14 +455,14 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ](
                        };\r
                        \r
                        v = end + seek + volume;\r
-                       return v && this.afterUpdateState( v );         \r
+                       return v && this.playing && this.afterUpdateState( v );\r
                }\r
                \r
        }\r
 );\r
 \r
 \r
-function X_AudioWrapper_timeStringToNumber( time ){\r
+function X_Audio_timeStringToNumber( time ){\r
        var ary, ms, s = 0, m = 0, h = 0;\r
        if( X_Type_isNumber( time ) ) return time;\r
        if( !X_Type_isString( time ) || !time.length ) return;\r
@@ -493,7 +498,7 @@ function X_AudioWrapper_timeStringToNumber( time ){
        return ms < 0 ? 0 : ms;\r
 };\r
 \r
-function X_AudioWrapper_getStartTime( audioWrapper, endTime, delSeekTime ){\r
+function X_Audio_getStartTime( audioWrapper, endTime, delSeekTime ){\r
        var seek = audioWrapper.seekTime;\r
        \r
        if( delSeekTime ) delete audioWrapper.seekTime;\r
@@ -512,7 +517,7 @@ function X_AudioWrapper_getStartTime( audioWrapper, endTime, delSeekTime ){
        return audioWrapper.startTime;\r
 };\r
 \r
-function X_AudioWrapper_getEndTime( audioWrapper ){\r
+function X_Audio_getEndTime( audioWrapper ){\r
        var duration = audioWrapper.duration;\r
        \r
        if( audioWrapper.looped && 0 <= audioWrapper.loopEndTime ){\r
index 6d63435..bded21f 100644 (file)
+var X_Audio_constructor = 3.1 <= X_UA[ 'Safari' ] && X_UA[ 'Safari' ] < 4 ?
+                                                               function( s, a ){
+                                                                       a = document.createElement( 'audio' );
+                                                                       a.src = s;
+                                                                       a.load();
+                                                                       return a;
+                                                               } :
+                                               // Android1.6 + MobileOpera12 HTMLAudio はいるが呼ぶとクラッシュする
+                                                 !( X_UA[ 'Android' ] < 2 ) ?
+                                                               window[ 'Audio' ] || window.HTMLAudioElement : null,
+       
+       // Blink5 Opera32 Win8 は HTMLAudio が壊れている、WebAudio は mp3 がデコードに失敗、ogg が動作
+       X_Audio_blinkOperaFix = X_UA[ 'BlinkOpera' ] && X_UA[ 'Windows' ],
+
+       X_Audio_codecs;
+
+if( X_Audio_constructor ){
+       //http://himaxoff.blog111.fc2.com/blog-entry-97.html
+       //引数なしで new Audio() とすると、Operaでエラーになるそうなので注意。
+       X_TEMP.rawAudio = new X_Audio_constructor( '' );
+       
+       // https://html5experts.jp/miyuki-baba/3766/
+       // TODO Chrome for Android31 で HE-AAC が低速再生されるバグ
+       // TODO Android4 標準ブラウザで ogg のシークが正しくない!
+       if( X_TEMP.rawAudio.canPlayType ){
+               X_Audio_codecs = {
+                 'mp3'  : X_TEMP.rawAudio.canPlayType('audio/mpeg'),
+                 'opus' : X_TEMP.rawAudio.canPlayType('audio/ogg; codecs="opus"'),
+                 'ogg'  : X_TEMP.rawAudio.canPlayType('audio/ogg; codecs="vorbis"'),
+                 'wav'  : X_TEMP.rawAudio.canPlayType('audio/wav; codecs="1"'),
+                 'aac'  : X_TEMP.rawAudio.canPlayType('audio/aac'),
+                 'm4a'  : X_TEMP.rawAudio.canPlayType('audio/x-m4a') + X_TEMP.rawAudio.canPlayType('audio/m4a') + X_TEMP.rawAudio.canPlayType('audio/aac'),
+                 'mp4'  : X_TEMP.rawAudio.canPlayType('audio/x-mp4') + X_TEMP.rawAudio.canPlayType('audio/mp4') + X_TEMP.rawAudio.canPlayType('audio/aac'),
+                 'weba' : X_TEMP.rawAudio.canPlayType('audio/webm; codecs="vorbis"')
+               };
+               (function( X_Audio_codecs, k, v ){
+                       for( k in X_Audio_codecs ){
+                               //if( X_EMPTY_OBJECT[ k ] ) continue;
+                               v = X_Audio_codecs[ k ];
+                               v = v && !!( v.split( 'no' ).join( '' ) );
+                               if( v ){
+                                       console.log( k + ' ' + X_Audio_codecs[ k ] );
+                                       X_Audio_codecs[ k ] = true;
+                               } else {
+                                       delete X_Audio_codecs[ k ];
+                               };
+                       };
+                       if( X_Audio_blinkOperaFix ) delete X_Audio_codecs[ 'mp3' ];
+               })( X_Audio_codecs );
+       } else {
+               // iOS3.2.3
+               X_Audio_codecs = {
+                 'mp3'  : X_UA[ 'IE' ] || X_UA[ 'Chrome' ] || ( X_UA[ 'Windows' ] && X_UA[ 'Safari' ]  ),
+                 'ogg'  : 5 <= X_UA[ 'Gecko' ] || X_UA[ 'Chrome' ] || X_UA[ 'Opera' ] ,
+                 'wav'  : X_UA[ 'Gecko' ] || X_UA[ 'Opera' ] || ( X_UA[ 'Windows' ] && X_UA[ 'Safari' ]  ),
+                 'aac'  : X_UA[ 'IE' ] || X_UA[ 'WebKit' ],
+                 'm4a'  : X_UA[ 'IE' ] || X_UA[ 'WebKit' ],
+                 'mp4'  : X_UA[ 'IE' ] || X_UA[ 'WebKit' ],
+                 'weba' : 2 <= X_UA[ 'Gecko' ] || 10.6 <= X_UA[ 'Opera' ] // firefox4+(Gecko2+)
+               };
+               (function( X_Audio_codecs, k ){
+                       for( k in X_Audio_codecs ){
+                               //if( X_EMPTY_OBJECT[ k ] ) continue;
+                               if( X_Audio_codecs[ k ] ){
+                                       console.log( k + ' ' + X_Audio_codecs[ k ] );
+                                       X_Audio_codecs[ k ] = true;
+                               } else {
+                                       delete X_Audio_codecs[ k ];
+                               };
+                       };
+               })( X_Audio_codecs );
+       };
+       
+       if( X_Audio_blinkOperaFix ){
+               X_Audio_constructor = null;
+               delete X_TEMP.rawAudio;
+       };
+};
+
 
-var X_Audio_WebAudio_context = !X_UA[ 'iPhone_4s' ]  && !X_UA[ 'iPad_2Mini1' ]  && !X_UA[ 'iPod_4' ]  &&
+var X_WebAudio_context = !X_UA[ 'iPhone_4s' ]  && !X_UA[ 'iPad_2Mini1' ]  && !X_UA[ 'iPod_4' ]  &&
                                                                // TODO なんで fennec を禁止?
                                                                !( X_UA[ 'Gecko' ] && X_UA[ 'Android' ] ) &&
-                                                               // Firefox40.0.5 + Windows8 で音声が鳴らない
-                                                               !( X_UA[ 'Gecko' ] === 40 && X_UA[ 'Windows' ] ) &&
+                                                               // Firefox40.0.5 + Windows8 で音声が途中から鳴らなくなる
+                                                               // Firefox41.0.1 + Windows8 で音声が途中から鳴らなくなる
+                                                               !( 40 <= X_UA[ 'Gecko' ] && X_UA[ 'Gecko' ] < 42 && X_UA[ 'Windows' ] ) &&
                                                                ( window[ 'AudioContext' ] || window[ 'webkitAudioContext' ] ),
-       X_Audio_BUFFER_LIST      = [],
-       X_Audio_WebAudioWrapper,
-       X_Audio_BufferLoader,
-       X_Audio_fpsFix;
+       X_WebAudio_BUFFER_LIST      = [],
+       X_WebAudio,
+       X_WebAudio_BufferLoader,
+       X_WebAudio_fpsFix;
 
 /*
  * iPhone 4s 以下、iPad2以下、iPad mini 1以下, iPod touch 4G 以下は不可
  */
-if( X_Audio_WebAudio_context ){
+if( X_WebAudio_context ){
        
-       X_Audio_WebAudio_context = new X_Audio_WebAudio_context;
+       X_WebAudio_context = new X_WebAudio_context;
        
-       X_Audio_BufferLoader = X_EventDispatcher[ 'inherits' ](
+       X_WebAudio_BufferLoader = X_EventDispatcher[ 'inherits' ](
                'X.WebAudio.BufferLoader',
                X_Class.POOL_OBJECT,
                {
-                       url             : '',
+                       audioUrl        : '',
             xhr             : null,
             onDecodeSuccess : null,
             onDecodeError   : null,
             
-            buffer          : null,
-            error           : 0,
+            audioBuffer     : null,
+            errorState      : 0,
             webAudioList    : null,
             
                        'Constructor' : function( webAudio, url ){
                                this.webAudioList = [ webAudio ];
-                               this.url = url;
+                               this.audioUrl     = url;
                                this.xhr = X[ 'Net' ]( { 'xhr' : url, 'dataType' : 'arraybuffer' } )
                                                                        [ 'listen' ]( X_EVENT_PROGRESS, this )
                                                                        [ 'listenOnce' ]( [ X_EVENT_SUCCESS, X_EVENT_COMPLETE ], this );
+                               X_WebAudio_BUFFER_LIST.push( this );
                        },
                        
                        handleEvent : function( e ){
@@ -52,18 +133,18 @@ if( X_Audio_WebAudio_context ){
                                        // iOS 7.1 で decodeAudioData に処理が入った瞬間にスクリーンを長押しする(スクロールを繰り返す)と
                                        // decoeAudioData の処理がキャンセルされることがある(エラーやコールバックの発火もなく、ただ処理が消滅する)。
                                        // ただし iOS 8.1.2 では エラーになる
-                                               if( X_UA[ 'iOS' ] < 8 || !X_Audio_WebAudio_context[ 'decodeAudioData' ] ){
-                                                       this._onDecodeSuccess( X_Audio_WebAudio_context[ 'createBuffer' ]( e.response, false ) );
+                                               if( X_UA[ 'iOS' ] < 8 || !X_WebAudio_context[ 'decodeAudioData' ] ){
+                                                       this._onDecodeSuccess( X_WebAudio_context[ 'createBuffer' ]( e.response, false ) );
                                                } else
-                                               if( X_Audio_WebAudio_context[ 'decodeAudioData' ] ){
-                                                       X_Audio_WebAudio_context[ 'decodeAudioData' ]( e.response,
+                                               if( X_WebAudio_context[ 'decodeAudioData' ] ){
+                                                       X_WebAudio_context[ 'decodeAudioData' ]( e.response,
                                                                this.onDecodeSuccess = X_Closure_create( this, this._onDecodeSuccess ),
                                                                this.onDecodeError   = X_Closure_create( this, this._onDecodeError ) );
                                                };
                                                break;
 
                                        case X_EVENT_COMPLETE :
-                                               this.error = 1;                         
+                                               this.errorState = 1;                            
                                                this[ 'asyncDispatch' ]( X_EVENT_COMPLETE );
                                                break;
                                };
@@ -72,17 +153,17 @@ if( X_Audio_WebAudio_context ){
                        },
                        
                                _onDecodeSuccess : function( buffer ){
-                                       console.log( 'WebAudio decode success!' );
-                                       
                                        this.onDecodeSuccess && this._onDecodeComplete();
                                        
                        if ( !buffer ) {
-                               this.error = 2;
+                               this.errorState = 2;
                            this[ 'asyncDispatch' ]( X_EVENT_COMPLETE );
                            return;
                        };
+                       
+                       console.log( 'WebAudio decode success!' );
        
-                       this.buffer   = buffer;
+                       this.audioBuffer = buffer;
 
                                        this[ 'asyncDispatch' ]( X_EVENT_COMPLETE );
 
@@ -92,7 +173,7 @@ if( X_Audio_WebAudio_context ){
                                _onDecodeError : function(){
                                        console.log( 'WebAudio decode error!' );
                                        this._onDecodeComplete();
-                                       this.error = 2;
+                                       this.errorState = 2;
                                        this[ 'asyncDispatch' ]( X_EVENT_COMPLETE );
                                },
                                
@@ -119,7 +200,7 @@ if( X_Audio_WebAudio_context ){
        );
        
        
-       X_Audio_WebAudioWrapper = X_Audio_AbstractAudioBackend[ 'inherits' ](
+       X_WebAudio = X_AudioBase[ 'inherits' ](
                'X.WebAudio',
                X_Class.POOL_OBJECT,
                {
@@ -131,14 +212,14 @@ if( X_Audio_WebAudio_context ){
                        _startTime      : 0,
             _timerID        : 0,
             _interval       : 0,
-               buffer          : null,
+               audioBuffer     : null,
                bufferSource    : null,
             gainNode        : null,
             _onended        : null,
             
                        'Constructor' : function( target, url, option ){                                
                                var i = 0,
-                                       l = X_Audio_BUFFER_LIST.length,
+                                       l = X_WebAudio_BUFFER_LIST.length,
                                        loader;
 
                                /*
@@ -146,14 +227,14 @@ if( X_Audio_WebAudio_context ){
                                 * L-01F 等の一部端末で Web Audio API の再生結果に特定条件下でノイズが混ざることがある。
                                 * 描画レート(描画 FPS)が下がるとノイズが混ざり始め、レートを上げると再生結果が正常になるというもので、オーディオ処理が描画スレッドに巻き込まれているような動作を見せる。
                                 */
-                               if( X_UA[ 'Android' ] && X_UA[ 'Chrome' ] && !X_Audio_fpsFix ){
+                               if( X_UA[ 'Android' ] && X_UA[ 'Chrome' ] && !X_WebAudio_fpsFix ){
                                        X_Node_systemNode.create( 'div', { id : 'fps-slowdown-make-sound-noisy' } );
-                                       X_Audio_fpsFix = true;
+                                       X_WebAudio_fpsFix = true;
                                };
 
                                for( ; i < l; ++i ){
-                                       loader = X_Audio_BUFFER_LIST[ i ];
-                                       if( loader.url === url ){
+                                       loader = X_WebAudio_BUFFER_LIST[ i ];
+                                       if( loader.audioUrl === url ){
                                                this.loader = loader;
                                                loader.webAudioList.push( this );
                                                break;
@@ -161,7 +242,7 @@ if( X_Audio_WebAudio_context ){
                                };
                                
                                if( !this.loader ){
-                                       this.loader = loader = new X_Audio_BufferLoader( this, url );
+                                       this.loader = loader = X_WebAudio_BufferLoader( this, url );
                                };
                                
                                this.target  = target || this;
@@ -170,7 +251,7 @@ if( X_Audio_WebAudio_context ){
                                
                                this[ 'listenOnce' ]( X_EVENT_KILL_INSTANCE, this.onKill );
                                
-                               if( loader.buffer || loader.error ){
+                               if( loader.audioBuffer || loader.errorState ){
                                        this._onLoadBufferComplete();
                                } else {
                                        loader[ 'listenOnce' ]( X_EVENT_COMPLETE, this, this._onLoadBufferComplete );
@@ -181,7 +262,7 @@ if( X_Audio_WebAudio_context ){
                                this.loader[ 'unlisten' ]( X_EVENT_COMPLETE, this, this._onLoadBufferComplete )
                                        .unregister( this );
 
-                               delete this.buffer;
+                               delete this.audioBuffer;
                                
                                this.playing      && this.actualPause();
                    this.bufferSource && this._sourceDispose();
@@ -192,17 +273,17 @@ if( X_Audio_WebAudio_context ){
                        },
                                _onLoadBufferComplete : function( e ){
                                        var loader = this.loader,
-                                               buffer = loader.buffer;
+                                               buffer = loader.audioBuffer;
                                        
                                        e && loader[ 'unlisten' ]( X_EVENT_COMPLETE, this, this._onLoadBufferComplete );
                                        
                        if ( !buffer ) {
-                               this.error = loader.error;
+                               this.error = loader.errorState;
                                
                            this.target[ 'dispatch' ]({
                                                                type    : X_EVENT_ERROR,
-                                                               error   : loader.error,
-                                                               message : loader.error === 1 ?
+                                                               error   : loader.errorState,
+                                                               message : loader.errorState === 1 ?
                                                                                        'load buffer network error' :
                                                                                        'buffer decode error'
                                                        });
@@ -210,8 +291,8 @@ if( X_Audio_WebAudio_context ){
                            return;
                        };
        
-                       this.buffer   = buffer;
-                       this.duration = buffer.duration * 1000;
+                       this.audioBuffer = buffer;
+                       this.duration    = buffer.duration * 1000;
 
                                        this.target[ 'asyncDispatch' ]( X_EVENT_READY );
                        
@@ -224,23 +305,23 @@ if( X_Audio_WebAudio_context ){
                        actualPlay : function(){
                                var begin, end;
                                
-                   if( !this.buffer ){
+                   if( !this.audioBuffer ){
                        this.autoplay = true;
                        return;
                    };
                                
-                               end   = X_AudioWrapper_getEndTime( this );
-                               begin = X_AudioWrapper_getStartTime( this, end, true );
+                               end   = X_Audio_getEndTime( this );
+                               begin = X_Audio_getStartTime( this, end, true );
                                
                                console.log( '[WebAudio] play ' + begin + ' -> ' + end );
                                
                                if( this.bufferSource ) this._sourceDispose();
                                if( !this.gainNode ){
-                                       this.gainNode = X_Audio_WebAudio_context[ 'createGain' ] ? X_Audio_WebAudio_context[ 'createGain' ]() : X_Audio_WebAudio_context[ 'createGainNode' ]();
-                       this.gainNode[ 'connect' ]( X_Audio_WebAudio_context[ 'destination' ] );
+                                       this.gainNode = X_WebAudio_context[ 'createGain' ] ? X_WebAudio_context[ 'createGain' ]() : X_WebAudio_context[ 'createGainNode' ]();
+                       this.gainNode[ 'connect' ]( X_WebAudio_context[ 'destination' ] );
                                };
-                   this.bufferSource        = X_Audio_WebAudio_context[ 'createBufferSource' ]();
-                   this.bufferSource.buffer = this.buffer;
+                   this.bufferSource        = X_WebAudio_context[ 'createBufferSource' ]();
+                   this.bufferSource.buffer = this.audioBuffer;
                    this.bufferSource[ 'connect' ]( this.gainNode );
                    
                    this.gainNode[ 'gain' ].value = this.gain;
@@ -264,7 +345,7 @@ if( X_Audio_WebAudio_context ){
                    this.playing      = true;
                    this._startPos    = begin;
                    this._endPosition = end;
-                   this._startTime   = X_Audio_WebAudio_context.currentTime * 1000;
+                   this._startTime   = X_WebAudio_context.currentTime * 1000;
                    this._interval    = this._interval || X_Timer_add( 1000, 0, this, this._onInterval );
                        },
                        
@@ -287,14 +368,14 @@ if( X_Audio_WebAudio_context ){
                                        delete this._timerID;
                                        
                            if( this.playing ){
-                               time = X_Audio_WebAudio_context.currentTime * 1000 - this._startTime - this._endPosition + this._startPos | 0;
-                               //console.log( '> onEnd ' + ( this.playing && ( X_Audio_WebAudio_context.currentTime * 1000 - this._startTime ) ) + ' < ' + ( this._endPosition - this._startPos ) );
+                               time = X_WebAudio_context.currentTime * 1000 - this._startTime - this._endPosition + this._startPos | 0;
+                               //console.log( '> onEnd ' + ( this.playing && ( X_WebAudio_context.currentTime * 1000 - this._startTime ) ) + ' < ' + ( this._endPosition - this._startPos ) );
                                if( this._onended ){
                                        // Firefox 用の対策,,,
                                        if( time < 0 ) return;
                                } else {
                                        if( time < 0 ){
-                                               //console.log( '> onEnd crt:' + ( X_Audio_WebAudio_context.currentTime * 1000 ) + ' startTime:' + this._startTime +
+                                               //console.log( '> onEnd crt:' + ( X_WebAudio_context.currentTime * 1000 ) + ' startTime:' + this._startTime +
                                                //      ' from:' + this._startPos + ' to:' + this._endPosition );
                                                this._timerID = X_Timer_once( -time, this, this._onEnded );
                                                return;
@@ -334,7 +415,7 @@ if( X_Audio_WebAudio_context ){
                        },
                        
                        getActualCurrentTime : function(){
-                               return X_Audio_WebAudio_context.currentTime * 1000 - this._startTime + this._startPos | 0;
+                               return X_WebAudio_context.currentTime * 1000 - this._startTime + this._startPos | 0;
                        },
                        
                        afterUpdateState : function( result ){
@@ -351,16 +432,17 @@ if( X_Audio_WebAudio_context ){
 
        X_Audio_BACKENDS.push(
                {
-                       backendName : 'Web Audio',
+                       backendID   : 1,
+                       
+                       backendName : 'WebAudio',
 
-                       canPlay : {}, // TODO HTMLAudio と同じ
+                       canPlay     : X_Audio_codecs,
 
-                       // 
-                       detect : function( proxy, source, ext ){
+                       detect      : function( proxy, source, ext ){
                                proxy[ 'asyncDispatch' ]( { type : X_EVENT_COMPLETE, canPlay : X_Audio_codecs[ ext ] } );
                        },
                        
-                       klass : X_Audio_WebAudioWrapper
+                       klass : X_WebAudio
                }
        );
 };
index 2082a86..a231e67 100644 (file)
@@ -6,39 +6,40 @@
  * Windows 版 Safari は QuickTime のインストールが必要\r
  * \r
  * 1. iOS4(iPod 2G) で ended に達すると音が鳴らなくなる fix で解決\r
- * 2. iOS6(iPod 4G) で ended に達すると音が鳴らなくなる fix で頻度が改善\r
+ * 2. iOS6(iPod 4G) で ended に達すると音が鳴らなくなる fix で頻度が改善 emded イベントは発しないので、timeupdate 時に currentTime で判断する\r
  * 3. WP7(IS12T) で最後の方にある音が鳴らない? mp3 cbr を使えばいい? 裏に回っても音が鳴り続ける\r
- * 4. Android 3.x で ended に達すると音が鳴らなくなる -> リロード(audio.src='';audio.sr=src)で解決\r
+ * 4. Android 3.x で ended に達すると音が鳴らなくなる -> リロード(audio.src='';audio.sr=src)で解決、但し 2.x 4.x より遅延が大きく 1 秒弱程度ある\r
  * 5. Android 2.x で ended に達すると音が鳴らなくなる -> リロード(audio.src='';audio.src=src;audio.load())でで解決\r
- * 6. Android 4.4.2- は ended に達した際に currentTime が変更できなくなり、リロードが必要になる\r
+ * 6. Android 4.4.2- は ended に達した際に currentTime が変更できなくなり、リロードが必要になる, 4.0, 4.1, 4.2, 4.3 で確認\r
+ * 7. Blink5 Opera32 Win8 は HTMLAudio が壊れている、WebAudio は mp3 がデコードに失敗、ogg が動作\r
+ * \r
+ * memo\r
+ * 1. Android4.1 iframe 内の Audio は親に focus が移っても再生を継続する\r
  */\r
 \r
 var X_HTMLAudio_playTrigger =\r
                6 <= X_UA[ 'iOS' ] ? 'loadeddata' :\r
                X_UA[ 'iOS' ] < 5  ? 'stalled' :\r
-               X_UA[ 'iOS' ]     ? 'suspend' :\r
+               X_UA[ 'iOS' ]      ? 'suspend' :\r
                X_UA[ 'Safari' ] < 4 ? 'canplaythrough' :\r
-               X_UA[ 'AndroidChromeBrowser' ] ? 'canplaythrough' :\r
+               X_UA[ 'ChromeWK' ]   ? 'canplaythrough' :\r
                // Android 2.3.5(SBM101SH) では stalled は発生しない,,, ので必ず loadeddata もチェックする\r
-               X_UA[ 'AndroidBrowser' ] ? 'stalled' :\r
+               X_UA[ 'AOSP' ] ? 'stalled' :\r
                X_UA[ 'OperaMobile' ] || X_UA[ 'OperaTablet' ] ? 'loadeddata' :\r
                        'loadeddata', //'canplay',\r
        X_HTMLAudio,\r
-       X_Audio_constructor         = X_UA[ 'Safari' ] < 4 ? function(a){ a = document.createElement( 'audio' ); return a; } : window[ 'Audio' ] || window.HTMLAudioElement,\r
        \r
        // ended が発生しない timeupdate 内で play() を呼ぶ (未検証) 不具合確認は iOS4,6\r
        X_HTMLAudio_endedFixIOS     = X_UA[ 'iOS' ] < 7,\r
        // Android 2.3.5 で ended 時に audio.src='';audio.src=src;audio.load() を実施。 2.3.4 でも問題なし。\r
-       X_HTMLAudio_endedFixAOSP2   = X_UA[ 'AndroidBrowser' ] < 3,\r
+       X_HTMLAudio_endedFixAOSP2   = X_UA[ 'AOSP' ] < 3,\r
        // Android 3.1 で ended 時に src='';src=src を実施。\r
-       X_HTMLAudio_endedFixAOSP3   = !X_HTMLAudio_endedFixAOSP2 && X_UA[ 'AndroidBrowser' ] < 4,\r
+       X_HTMLAudio_endedFixAOSP3   = !X_HTMLAudio_endedFixAOSP2 && X_UA[ 'AOSP' ] < 4,\r
        // ended 時に play() を実施, currentTime が duration に張り付き更新されなければ  src='';src=src を実施。\r
-       X_HTMLAudio_endedFixAOSP4   = !X_UA[ 'AndroidChromeBrowser' ] && 4 <= X_UA[ 'AndroidBrowser' ],\r
+       X_HTMLAudio_endedFixAOSP4   = 4 <= X_UA[ 'AOSP' ],\r
        \r
        // Opera Mobile 12 は 2回目以降の currentTime へのセットで currentTime が更新されなくなるため、タイマーを使用する\r
        X_HTMLAudio_currentTimeFix  = !!X_UA[ 'OperaMobile' ] || !!X_UA[ 'OperaTablet' ],\r
-       // Android1.6+MobileOpera12では無理っぽい、、、\r
-       X_HTMLAudio_badOperaAndroid = X_HTMLAudio_currentTimeFix && X_UA[ 'Android' ] < 2,\r
 \r
        X_HTMLAudio_volumeFix       = X_UA[ 'Chrome' ],\r
        /*\r
@@ -51,7 +52,7 @@ var X_HTMLAudio_playTrigger =
        X_HTMLAudio_pauseFix            = ( X_UA[ 'Windows' ] && 12 <= X_UA[ 'Opera' ] && 0 < ' XP XPSP2 2003|XP64'.indexOf( X_UA[ 'Windows' ] ) ), // XP + Opera12 のみ?\r
        /*\r
         * durationFix\r
-        *  duration が取得できるタイミングが遅くそれまでは infinity(PC Opera12), NaN(WP9), 0(AndroidBrowser Chrome 系) が入っている\r
+        *  duration が取得できるタイミングが遅くそれまでは infinity(PC Opera12), NaN(WP9), 0(AOSP Chrome 系) が入っている\r
         * \r
         *   1. touch が不要の場合、自動で再生を開始して duration を取得するまで再生する\r
         *        -> 取得後に pause or 通常再生\r
@@ -64,71 +65,17 @@ var X_HTMLAudio_playTrigger =
         *        -> その際には timeupdate が発行されない、、、 iframe+image+audio で使わないときは破棄する、とか。\r
         *        -> opera11、10.54 WinXP はまとも、、、 portable が怪しい??\r
         */\r
-       X_HTMLAudio_need1stTouch        = X_UA[ 'iOS' ] || X_UA[ 'AndroidChromeBrowser' ] || ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ),   \r
-       X_HTMLAudio_durationFix     = ( X_UA[ 'Windows' ] && 12 <= X_UA[ 'Opera' ] ) || X_UA[ 'AndroidChromeBrowser' ] || ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ),\r
+       X_HTMLAudio_need1stTouch        = X_UA[ 'iOS' ] || X_UA[ 'ChromeWK' ] || ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ),       \r
+       X_HTMLAudio_durationFix     = ( X_UA[ 'Windows' ] && 12 <= X_UA[ 'Opera' ] ) || X_UA[ 'ChromeWK' ] || ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ),\r
        \r
-       X_HTMLAudio_shortPlayFix        = !X_UA[ 'AndroidChromeBrowser' ] && X_UA[ 'AndroidBrowser' ], // Android 4.1.1 でも遭遇(ただしm4a, mp3は優秀, oggはシークが乱れる)\r
+       X_HTMLAudio_shortPlayFix        = X_UA[ 'AOSP' ]; // Android 4.1.1 でも遭遇(ただしm4a, mp3は優秀, oggはシークが乱れる)\r
        \r
-       X_Audio_codecs;\r
-\r
-if( X_Audio_constructor && !X_HTMLAudio_badOperaAndroid ){\r
-       //http://himaxoff.blog111.fc2.com/blog-entry-97.html\r
-       //引数なしで new Audio() とすると、Operaでエラーになるそうなので注意。\r
-       X_TEMP.rawAudio = new X_Audio_constructor( '' );\r
        \r
-       // https://html5experts.jp/miyuki-baba/3766/\r
-       // TODO Chrome for Android31 で HE-AAC が低速再生されるバグ\r
-       // TODO Android4 標準ブラウザで ogg のシークが正しくない!\r
-       if( X_TEMP.rawAudio.canPlayType ){\r
-               X_Audio_codecs = {\r
-                 'mp3'  : X_TEMP.rawAudio.canPlayType('audio/mpeg'),\r
-                 'opus' : X_TEMP.rawAudio.canPlayType('audio/ogg; codecs="opus"'),\r
-                 'ogg'  : X_TEMP.rawAudio.canPlayType('audio/ogg; codecs="vorbis"'),\r
-                 'wav'  : X_TEMP.rawAudio.canPlayType('audio/wav; codecs="1"'),\r
-                 'aac'  : X_TEMP.rawAudio.canPlayType('audio/aac'),\r
-                 'm4a'  : X_TEMP.rawAudio.canPlayType('audio/x-m4a') + X_TEMP.rawAudio.canPlayType('audio/m4a') + X_TEMP.rawAudio.canPlayType('audio/aac'),\r
-                 'mp4'  : X_TEMP.rawAudio.canPlayType('audio/x-mp4') + X_TEMP.rawAudio.canPlayType('audio/mp4') + X_TEMP.rawAudio.canPlayType('audio/aac'),\r
-                 'weba' : X_TEMP.rawAudio.canPlayType('audio/webm; codecs="vorbis"')\r
-               };\r
-               (function( X_Audio_codecs, k, v ){\r
-                       for( k in X_Audio_codecs ){\r
-                               //if( X_EMPTY_OBJECT[ k ] ) continue;\r
-                               v = X_Audio_codecs[ k ];\r
-                               v = v && !!( v.split( 'no' ).join( '' ) );\r
-                               if( v ){\r
-                                       console.log( k + ' ' + X_Audio_codecs[ k ] );\r
-                                       X_Audio_codecs[ k ] = true;\r
-                               } else {\r
-                                       delete X_Audio_codecs[ k ];\r
-                               };\r
-                       };\r
-               })( X_Audio_codecs );\r
-       } else {\r
-               // iOS3.2.3\r
-               X_Audio_codecs = {\r
-                 'mp3'  : X_UA[ 'IE' ] || X_UA[ 'Chrome' ] || ( X_UA[ 'Windows' ] && X_UA[ 'Safari' ]  ),\r
-                 'ogg'  : 5 <= X_UA[ 'Gecko' ] || X_UA[ 'Chrome' ] || X_UA[ 'Opera' ] ,\r
-                 'wav'  : X_UA[ 'Gecko' ] || X_UA[ 'Opera' ] || ( X_UA[ 'Windows' ] && X_UA[ 'Safari' ]  ),\r
-                 'aac'  : X_UA[ 'IE' ] || X_UA[ 'WebKit' ],\r
-                 'm4a'  : X_UA[ 'IE' ] || X_UA[ 'WebKit' ],\r
-                 'mp4'  : X_UA[ 'IE' ] || X_UA[ 'WebKit' ],\r
-                 'weba' : 2 <= X_UA[ 'Gecko' ] || 10.6 <= X_UA[ 'Opera' ] // firefox4+(Gecko2+)\r
-               };\r
-               (function( X_Audio_codecs, k ){\r
-                       for( k in X_Audio_codecs ){\r
-                               //if( X_EMPTY_OBJECT[ k ] ) continue;\r
-                               if( X_Audio_codecs[ k ] ){\r
-                                       console.log( k + ' ' + X_Audio_codecs[ k ] );\r
-                                       X_Audio_codecs[ k ] = true;\r
-                               } else {\r
-                                       delete X_Audio_codecs[ k ];\r
-                               };\r
-                       };\r
-               })( X_Audio_codecs );\r
-       };\r
+\r
+if( X_Audio_constructor ){\r
        \r
-       X_HTMLAudio = X_Audio_AbstractAudioBackend[ 'inherits' ](\r
-               'X.AV.HTML5AudioWrapper',\r
+       X_HTMLAudio = X_AudioBase[ 'inherits' ](\r
+               'X.HTMLAudio',\r
                X_Class.POOL_OBJECT,\r
                {\r
                        _closed               : true,\r
@@ -143,7 +90,6 @@ if( X_Audio_constructor && !X_HTMLAudio_badOperaAndroid ){
                        _durationFixSkip  : X_HTMLAudio_durationFix && !X_HTMLAudio_need1stTouch,                       \r
                        _lastCurrentTime  : 0,\r
 \r
-\r
                        _shortPlayFixON   : false,\r
                        _shortPlayFixTime : 0,\r
                        \r
@@ -195,16 +141,16 @@ if( X_Audio_constructor && !X_HTMLAudio_badOperaAndroid ){
 \r
                                if( X_TEMP.rawAudio ){\r
                                        raw.src = source;\r
-                                       raw.load(); // 要る?\r
-                                       X_TEMP.rawAudio = null;\r
+                                       raw.load(); // AOSP2 で必要\r
+                                       delete X_TEMP.rawAudio;\r
                                };\r
                        },\r
                        \r
                        handleEvent : function( e ){\r
                                var raw    = this[ '_rawObject' ],\r
-                                       _ended = e.type === 'ended',\r
-                                       ended  = _ended,\r
-                                       ready  = e.type === X_HTMLAudio_playTrigger,\r
+                                       actualEnded = e.type === 'ended',\r
+                                       ended       = actualEnded,\r
+                                       ready       = e.type === X_HTMLAudio_playTrigger,\r
                                        eventType, duration, end, now;\r
                                \r
                                // global に公開\r
@@ -231,7 +177,7 @@ if( X_Audio_constructor && !X_HTMLAudio_badOperaAndroid ){
                                        //case 'loadstart' :      //    ブラウザがコンテンツの検索を開始した場合に発生\r
                                                //break;\r
                                        case 'progress' :          //   ブラウザがコンテンツの取得を実行した場合に発生\r
-                                               console.log( e.loaded + ' ' + e.total * 100 + '%' );\r
+                                               // console.log( e.loaded + ' ' + e.total * 100 + '%' );\r
                                                // iem9 で常に0 raw.networkState;\r
                                                // opera Android 12 で buffered.end() へのアクセスはエラー try catch も無効、iem9 は常に end(0) = 0\r
                                                //console.log( 'buffered.end ' + raw.buffered && raw.buffered.end(0) ); \r
@@ -250,9 +196,9 @@ if( X_Audio_constructor && !X_HTMLAudio_badOperaAndroid ){
                                                };\r
                                        case 'canplaythrough' : //      今すぐに再生を開始してもバッファリングで停止することなく最後まで表示できると予測している場合に発生\r
                                                if( this._endedFixON ){\r
+                                                       console.log( '▽ onEndedFix の終了 @' + e.type  );\r
                                                        this._endedFixON = false;\r
                                                        this.actualPlay();\r
-                                                       console.log( '▽ onEndedFix @' + e.type  );\r
                                                };\r
                                        case 'loadedmetadata' : //      ブラウザがメディアリソースの長さと寸法を判定した場合に発生\r
                                        case 'durationchange' : //  duration属性が更新された場合に発生\r
@@ -272,14 +218,14 @@ if( X_Audio_constructor && !X_HTMLAudio_badOperaAndroid ){
                                                        this._lastCurrentTime = raw.currentTime;\r
 \r
                                                        if( this.playing ){\r
-                                                               end = X_AudioWrapper_getEndTime( this ) + this._shortPlayFixTime;\r
+                                                               end = X_Audio_getEndTime( this ) + this._shortPlayFixTime;\r
                                                                now = this.getActualCurrentTime();\r
                                                                //console.log( now + ' / ' + end );\r
                                                                if( 0 + end <= 0 + now ){ // 0+ なぜか iem9 で必要,,,\r
                                                                        if( this.autoLoop ){\r
-                                                                               console.log( '☆★☆ 曲の最後に到達 @timeupdate' );\r
+                                                                               console.log( '☆★☆ 曲の最後に到達 @timeupdate now-end:' + ( now - end ) );\r
                                                                                ended = true;\r
-                                                                               if( X_HTMLAudio_endedFixIOS ) _ended = true;\r
+                                                                               if( X_HTMLAudio_endedFixIOS ) actualEnded = true;\r
                                                                        } else {\r
                                                                                this.actualPause();\r
                                                                                eventType = X_EVENT_MEDIA_ENDED;\r
@@ -362,14 +308,15 @@ if( X_Audio_constructor && !X_HTMLAudio_badOperaAndroid ){
                                                if( !( this.target[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){\r
                                                        this.looped = true;\r
                                                        this.target[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );\r
-                                                       ( X_HTMLAudio_endedFixAOSP3 || X_HTMLAudio_endedFixAOSP4 || X_HTMLAudio_endedFixIOS ) && _ended && console.log( '☆★☆ 音声の継続用の play() @ended' );\r
-                                                       this.actualPlay( ( X_HTMLAudio_endedFixAOSP4 || X_HTMLAudio_endedFixIOS ) && _ended, ( X_HTMLAudio_endedFixAOSP3 || X_HTMLAudio_endedFixAOSP2 ) && _ended );\r
+                                                       ( X_HTMLAudio_endedFixAOSP3 || X_HTMLAudio_endedFixAOSP4 || X_HTMLAudio_endedFixIOS ) && actualEnded && console.log( '☆★☆ 音声の継続用の play() @ended' );\r
+                                                       this.actualPlay(\r
+                                                               ( X_HTMLAudio_endedFixAOSP4 || X_HTMLAudio_endedFixIOS ) && actualEnded,\r
+                                                               ( X_HTMLAudio_endedFixAOSP3 || X_HTMLAudio_endedFixAOSP2 ) && actualEnded );\r
                                                };\r
-                                               // Android4.1.1 ended 後に曲の再生が継続できない\r
                                        } else {\r
                                                this.seekTime = 0;\r
                                                delete this.playing;\r
-                                               this.target[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );                                                       \r
+                                               this.target[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
                                        };\r
                                } else\r
                                if( this._loaded && this.duration && !this._ready ){\r
@@ -408,8 +355,8 @@ if( X_Audio_constructor && !X_HTMLAudio_badOperaAndroid ){
                                        this._durationFixPhase = 2;\r
                                };\r
 \r
-                               end   = X_AudioWrapper_getEndTime( this );\r
-                               begin = X_AudioWrapper_getStartTime( this, end, true );\r
+                               end   = X_Audio_getEndTime( this );\r
+                               begin = X_Audio_getStartTime( this, end, true );\r
 \r
                                this._lastCurrentTime = begin / 1000;\r
 \r
@@ -445,20 +392,17 @@ if( X_Audio_constructor && !X_HTMLAudio_badOperaAndroid ){
                                        \r
                                        // Android4.0.5 で ended イベント時に currentTime が duration に張り付いたまま変更できない\r
                                        if( forceReload || ( raw.duration && raw.currentTime === raw.duration ) ){\r
-                                               console.log( '△ onEndedFix の開始' );\r
                                                raw.src          = '';\r
                                                raw.src          = this._src;\r
-                                               raw.currentTime  = this._lastCurrentTime;\r
                                                this.playing     = false;\r
                                                this._endedFixON = true;\r
+                                               console.log( '△ onEndedFix の開始' );\r
+                                               raw.currentTime  = this._lastCurrentTime;\r
                                                this.target[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );                                                                                             \r
                                                X_HTMLAudio_endedFixAOSP2 && raw.load();\r
                                        };                                                      \r
                                };\r
 \r
-                               /* if( X_HTMLAudio_durationFix ){\r
-                                       this._currentFixBegin = begin;\r
-                               } else */\r
                                if( X_HTMLAudio_currentTimeFix ){\r
                                        this._currentFixBegin = begin;\r
                                        this._currentFixStart = X_Timer_now();\r
@@ -512,9 +456,11 @@ if( X_Audio_constructor && !X_HTMLAudio_badOperaAndroid ){
                }\r
        );\r
        \r
-       X_Audio_BACKENDS.push(\r
+       X_HTMLAudio && X_Audio_BACKENDS.push(\r
                {\r
-                       backendName : 'HTML Audio',\r
+                       backendID   : 2,\r
+                       \r
+                       backendName : 'HTMLAudio',\r
                        \r
                        canPlay : X_Audio_codecs,\r
                /*\r
index 30d9548..7133272 100644 (file)
  * SilverlLight5 ie6&7(ietester,winxp), ie8(winxp) で動作確認。firefox32 では動作しない。(4以下の方がよい?)\r
  */\r
 \r
-var X_Audio_SLAudioWrapper,\r
-       X_Audio_SLAudio_uid = 0;\r
+var X_SLAudio,\r
+       X_SLAudio_uid = 0;\r
 \r
-if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] && !X_HTMLAudio ){\r
+if( X[ 'Pulgin' ][ 'Silverlight' ] ){\r
        \r
        X_TEMP.slaudioInit = function(){\r
                //\r
                // http://blog.yuhiisk.com/archive/2014/12/20/dynamic-loading-and-complete-processing-of-script.html\r
-               var s = document.createElement( '<script id="silverlightaudio" type="text/xaml"></script>' );\r
+               var s;\r
+               \r
+               if( X_UA[ 'IE' ] < 9 ){\r
+                       s = document.createElement( '<script id="silverlightaudio" type="text/xaml"></script>' );\r
+               } else {\r
+                       s = document.createElement( 'script' );\r
+                       s.id   = 'silverlightaudio';\r
+                       s.type = 'text/xaml';\r
+               };\r
                \r
                document.getElementsByTagName( 'head' )[ 0 ].appendChild( s );\r
                s.text = '<Canvas xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"></Canvas>';\r
@@ -29,8 +37,8 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] && !X_HTMLAudio ){
        };\r
        \r
        // X.Node.inherits はできない。_rawObject は <object> でなく silverlight\r
-       X_Audio_SLAudioWrapper = X_Audio_AbstractAudioBackend[ 'inherits' ](\r
-               'X.AV.SilverlightAudio',\r
+       X_SLAudio = X_AudioBase[ 'inherits' ](\r
+               'X.SilverlightAudio',\r
                X_Class.POOL_OBJECT,\r
                {\r
                        '_rawType'      : X_EventDispatcher_EVENT_TARGET_SILVER_LIGHT,\r
@@ -46,20 +54,20 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] && !X_HTMLAudio ){
                        _interval       : 0, // setInterval timer id\r
                        \r
                        'Constructor' : function( target, source, option ){\r
-                               !X_Audio_SLAudio_uid && X_TEMP.slaudioInit();\r
+                               !X_SLAudio_uid && X_TEMP.slaudioInit();\r
                                \r
                                /*\r
                                 * [Silverlight 2]JavaScriptコードからSilverlightのオブジェクトを利用するには?[C#、VB]\r
                                 * http://www.atmarkit.co.jp/fdotnet/dotnettips/902slobjcallfromjs/slobjcallfromjs.html\r
                                 * このページのサンプルは sl5+firefox32 環境で動いている。xaml を js から利用する形ではなく、.xap を sl4 以下で作るのがよさそう.\r
                                 */\r
-                               \r
-                               // TODO embed\r
                                this.target      = target || this;\r
                                this._source     = source;\r
                                // X.Audio._slOnload_ は不可\r
-                       this._onload     = 'XAudioSilverlightOnLoad' + ( ++X_Audio_SLAudio_uid );\r
+                       this._onload     = 'XAudioSilverlightOnLoad' + ( ++X_SLAudio_uid );\r
                                this._callback   = window[ this._onload ] = X_Closure_create( this, this.onSLReady );\r
+                               \r
+                               // TODO embed\r
                        this.xnodeObject = X_Node_body\r
                                [ 'create' ]( 'object', {\r
                                                type   : 'application/x-silverlight-2',\r
@@ -252,8 +260,8 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] && !X_HTMLAudio ){
                                \r
                                this._lastUserAction = 0 <= this.seekTime ? 'seek' : 'play';\r
                                \r
-                               end   = X_AudioWrapper_getEndTime( this );\r
-                               begin = X_AudioWrapper_getStartTime( this, end, true ) | 0;\r
+                               end   = X_Audio_getEndTime( this );\r
+                               begin = X_Audio_getStartTime( this, end, true ) | 0;\r
 \r
                                // 1 秒以下は指定できないため四捨五入\r
                                begin = ( begin / 1000 | 0 ) * 1000 + ( 500 < begin % 1000 ? 1000 : 0 ); \r
@@ -300,7 +308,7 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] && !X_HTMLAudio ){
                                        delete this._timerID;\r
                                        \r
                            if( this.playing ){\r
-                               //console.log( '> end ' + X_AudioWrapper_getEndTime( this ) + ' current:' + ( this.getActualCurrentTime() ) );\r
+                               //console.log( '> end ' + X_Audio_getEndTime( this ) + ' current:' + ( this.getActualCurrentTime() ) );\r
                                time = this.getActualCurrentTime();\r
                                \r
                                if( time < this._beginTime ){\r
@@ -311,11 +319,11 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] && !X_HTMLAudio ){
                                        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
+                                       this._timerID = X_Timer_once( X_Audio_getEndTime( this ) - time, this, this._onEnded );\r
                                        return;\r
                                };\r
                                \r
-                               time -= X_AudioWrapper_getEndTime( this );\r
+                               time -= X_Audio_getEndTime( this );\r
                                if( time < 0 ){\r
                                        console.log( ' > まだ終わらない ' + time );\r
                                        this._ended && this[ '_rawObject' ].play();\r
@@ -363,7 +371,7 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] && !X_HTMLAudio ){
                        this.actualPlay();\r
                                } else\r
                                if( result & 1 ){\r
-                                       end     = X_AudioWrapper_getEndTime( this );\r
+                                       end     = X_Audio_getEndTime( this );\r
                                        halfway = end < this.duration;\r
                                        this._timerID && X_Timer_remove( this._timerID );\r
                                        \r
@@ -396,7 +404,9 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] && !X_HTMLAudio ){
        }; */\r
 \r
        X_Audio_BACKENDS.push( {\r
-               backendName : 'Silverlight Audio',\r
+               backendID   : 8,\r
+               \r
+               backendName : 'Silverlight',\r
 \r
                canPlay : {\r
                        'mp3' : true,\r
@@ -408,7 +418,7 @@ if( X[ 'Pulgin' ][ 'SilverlightEnabled' ] && !X_HTMLAudio ){
                        proxy[ 'asyncDispatch' ]( { type : X_EVENT_COMPLETE, canPlay : ext === 'mp3' || ext === 'wma' || ext === 'wav' } );                             \r
                },\r
                \r
-               klass : X_Audio_SLAudioWrapper\r
+               klass : X_SLAudio\r
                \r
        } );\r
 \r