From 66ccef8a1fdd3994dd3c75dcfede668ea55f1d2e Mon Sep 17 00:00:00 2001 From: itozyun Date: Fri, 21 Oct 2016 15:10:06 +0900 Subject: [PATCH] Version 0.6.218, Fix the bug of X.Net & X.Audio. --- 0.6.x/js/02_dom/10_XNodeAnime.js | 9 +- 0.6.x/js/06_net/00_XNet.js | 2 + 0.6.x/js/06_net/01_XNetXHR.js | 16 +-- 0.6.x/js/06_net/10_XOAuth2.js | 2 +- 0.6.x/js/07_audio/00_XAudio.js | 10 +- 0.6.x/js/07_audio/01_XWebAudio.js | 176 ++++++++++++++++++++---------- 0.6.x/js/07_audio/02_XHTMLAudio.js | 33 +++--- 0.6.x/js/07_audio/03_XSilverlightAudio.js | 30 ++--- 0.6.x/js/07_audio/05_XWMPAudio.js | 22 ++-- 0.6.x/js/07_audio/10_XAudioSprite.js | 25 ++++- 10 files changed, 208 insertions(+), 117 deletions(-) diff --git a/0.6.x/js/02_dom/10_XNodeAnime.js b/0.6.x/js/02_dom/10_XNodeAnime.js index 4320ec1..c851f8e 100644 --- a/0.6.x/js/02_dom/10_XNodeAnime.js +++ b/0.6.x/js/02_dom/10_XNodeAnime.js @@ -525,7 +525,14 @@ function X_NodeAnime_updatePosition( xnode, obj, ratio, useGPU ){ //console.log( 'updatePosition x:' + x + ' gpu:' + !!useGPU ); if( obj.transform ){ - if( ( x === x || y === y ) && ( x !== 0 && y !== 0 ) ) str += ' translate(' + ( x | 0 ) + 'px,' + ( y | 0 ) + 'px)'; + if( ( x === x || y === y ) && ( x !== 0 && y !== 0 ) ){ + if( X_UA[ 'Safari' ] && X_UA[ 'Windows' ] ){ + // http://shinimae.hatenablog.com/entry/2016/01/13/151748 + str = ' -webkit-translate(' + ( x | 0 ) + 'px,' + ( y | 0 ) + 'px)'; + } else { + str = ' translate(' + ( x | 0 ) + 'px,' + ( y | 0 ) + 'px)'; + }; + }; if( rotate < 0 || 0 < rotate ) str += ' rotate(' + rotate + 'deg)'; // opera は rad? if( skewX < 0 || 0 < skewX ) str += ' skewX(' + skewX + 'deg)'; if( skewY < 0 || 0 < skewY ) str += ' skewY(' + skewY + 'deg)'; diff --git a/0.6.x/js/06_net/00_XNet.js b/0.6.x/js/06_net/00_XNet.js index 9069396..3e7b454 100644 --- a/0.6.x/js/06_net/00_XNet.js +++ b/0.6.x/js/06_net/00_XNet.js @@ -279,6 +279,8 @@ function X_NET_proxyDispatch( e ){ this[ 'listenOnce' ]( X_EVENT_COMPLETE, X_NET_proxyDispatch ) [ 'asyncDispatch' ]( 32, { type : X_EVENT_COMPLETE, 'lastEventType' : e.type } ); + // target を上書き X_NET_currentWrapper -> X_NET_currentQueue + e[ 'target' ] = e[ 'currentTarget' ] = this; this[ 'asyncDispatch' ]( e ); break; diff --git a/0.6.x/js/06_net/01_XNetXHR.js b/0.6.x/js/06_net/01_XNetXHR.js index 746f5a3..c03b635 100644 --- a/0.6.x/js/06_net/01_XNetXHR.js +++ b/0.6.x/js/06_net/01_XNetXHR.js @@ -171,7 +171,7 @@ if( X_XHR_w3c || X_XHR_msXML ){ postdata = obj[ 'postdata' ] || '', timeout = obj[ 'timeout' ] || 20000, noCache = obj[ 'cache' ] !== true, - dataType = X_XHR._dataType = obj[ 'dataType' ], + dataType = X_XHR._dataType = obj[ 'dataType' ], // ext が入っている xDomain = !X_URL_isSameDomain( url ), isFile = X_URL_isLocal( url ), init, @@ -204,24 +204,25 @@ if( X_XHR_w3c || X_XHR_msXML ){ if( raw.responseType !== undefined ){ switch( dataType ){ case '' : + case 'txt' : case 'text' : // js, css - raw.responseType = 'text'; + raw.responseType = X_XHR._dataType = 'text'; break; case 'json' : // firefox9- は moz-json - raw.responseType = X_UA[ 'Gecko' ] < 10 ? 'moz-json' : X_UA[ 'Gecko' ] ? dataType : ''; // Iron 37 でエラー + raw.responseType = X_XHR._dataType = X_UA[ 'Gecko' ] < 10 ? 'moz-json' : X_UA[ 'Gecko' ] ? dataType : ''; // Iron 37 でエラー break; case 'document' : case 'xml' : case 'html' : case 'htm' : // svg - raw.responseType = 'document'; + raw.responseType = X_XHR._dataType = 'document'; break; case 'blob' : case 'arraybuffer' : // jpeg,jpg,png,gif,mp3,ogg... - raw.responseType = dataType; + raw.responseType = X_XHR._dataType = dataType; break; }; }; @@ -472,7 +473,6 @@ if( X_XHR_w3c || X_XHR_msXML ){ // parse json, html, xml, text, script, css switch( X_XHR._dataType ){ - case '' : case 'text' : data = X_Script_try( X_Object_find, [ raw, 'responseText' ] ); break; @@ -485,10 +485,6 @@ if( X_XHR_w3c || X_XHR_msXML ){ if( X_Type_isString( data ) ) data = X_JSON_parseTrustableString( data ); break; case 'document' : - case 'xml' : - case 'html' : - case 'htm' : - // svg, vml, xaml, xul, mxml ?? data = raw[ 'responseXML' ] || raw[ 'response' ] || raw[ 'responseText' ]; // とりあえず break; case 'blob' : diff --git a/0.6.x/js/06_net/10_XOAuth2.js b/0.6.x/js/06_net/10_XOAuth2.js index e1f923e..5f23c6c 100644 --- a/0.6.x/js/06_net/10_XOAuth2.js +++ b/0.6.x/js/06_net/10_XOAuth2.js @@ -414,7 +414,7 @@ function X_OAuth2_updateLocalStorage( cmd, that, name, value ){ var action = cmd === '+' ? 'setItem' : cmd === '-' ? 'removeItem' : 'getItem', pair; - if( window.localStorage ){ + if( window.localStorage ){ // TODO http://qiita.com/narikei/items/f55fb9cb398beac52ea9 return window.localStorage[ action ]( X_Pair_get( that )[ 'clientID' ] + name, value ); }; diff --git a/0.6.x/js/07_audio/00_XAudio.js b/0.6.x/js/07_audio/00_XAudio.js index 4664aa0..60bc56e 100644 --- a/0.6.x/js/07_audio/00_XAudio.js +++ b/0.6.x/js/07_audio/00_XAudio.js @@ -89,7 +89,7 @@ X[ 'Audio' ] = X_EventDispatcher[ 'inherits' ]( X_Type_isArray( sourceList ) ? X_Array_copy( sourceList ) : [ sourceList ], opt_option || {} ); this[ 'listenOnce' ]( [ X_EVENT_BACKEND_READY, X_EVENT_BACKEND_NONE, X_EVENT_KILL_INSTANCE ], X_Audio_handleEvent ); - X_ViewPort[ 'listenOnce' ]( X_EVENT_UNLOAD, this, X_AudioSprite_handleEvent ); + X_ViewPort[ 'listenOnce' ]( X_EVENT_UNLOAD, this, X_Audio_handleEvent ); }, /** @@ -231,7 +231,7 @@ function X_Audio_handleEvent( e ){ this[ 'listenOnce' ]( X_EVENT_READY, X_Audio_handleEvent ); break; - case X_EVENT_READY : + case X_EVENT_READY : // TODO AudioBase 側へ行かない? pair = X_Pair_get( this ); ( pair.autoplay || pair._playReserved ) && pair.actualPlay(); delete pair._playReserved; @@ -243,7 +243,7 @@ function X_Audio_handleEvent( e ){ break; case X_EVENT_KILL_INSTANCE : - X_ViewPort[ 'unlisten' ]( X_EVENT_UNLOAD, this, X_AudioSprite_handleEvent ); + X_ViewPort[ 'unlisten' ]( X_EVENT_UNLOAD, this, X_Audio_handleEvent ); if( backend = X_Pair_get( this ) ){ backend[ 'kill' ](); X_Pair_release( this, backend ); @@ -286,7 +286,7 @@ function X_Audio_onEndedDetection( e, xaudio, sourceList, option, source, ext, s 'backendID' : i }; // WebAudio - if( this.backendID === 1 ) _e[ 'needTouchForPlay' ] = X_WebAudio_need1stTouch; + if( this.backendID === 1 ) _e[ 'needTouchForPlay' ] = /* X_WebAudio_need1stTouch && */ X_WebAudio_isNoTouch; // HTMLAudio if( this.backendID === 2 ) _e[ 'needTouchForLoad' ] = X_HTMLAudio_need1stTouch; @@ -313,7 +313,7 @@ var X_AudioBase = X_EventDispatcher[ 'inherits' ]( 'X.AudioBase', X_Class.ABSTRACT, { - disatcher : null, + dispatcher : null, startTime : 0, // state_startTime endTime : -1, // state_startTime diff --git a/0.6.x/js/07_audio/01_XWebAudio.js b/0.6.x/js/07_audio/01_XWebAudio.js index 1cc3cba..910271f 100644 --- a/0.6.x/js/07_audio/01_XWebAudio.js +++ b/0.6.x/js/07_audio/01_XWebAudio.js @@ -14,6 +14,10 @@ var X_Audio_constructor = 3.1 <= X_UA[ 'Safari' ] && X_UA[ 'Safari' ] < 4 ? X_Audio_codecs; +// WebAudioAPIを使っているはずなのに、マナーモードで音が出る!? +// http://qiita.com/gonshi_com/items/e41dbb80f5eb4c176108 +// HTML Audio、もしくはHTML Videoをページ内で1つでも使用していた場合、そのページでは WebAudioAPI の音がマナーモード時にも鳴ってしまう + if( X_Audio_constructor ){ //http://himaxoff.blog111.fc2.com/blog-entry-97.html //引数なしで new Audio() とすると、Operaでエラーになるそうなので注意。 @@ -78,7 +82,7 @@ if( X_Audio_constructor ){ }; -var X_WebAudio_context = // 4s 以下ではない iPad 2G または iPad mini 1G 以下ではない, iPod touch 4G 以下ではない +var X_WebAudio_Context = // 4s 以下ではない iPad 2G または iPad mini 1G 以下ではない, iPod touch 4G 以下ではない !X_UA[ 'iPhone_4s' ] && !X_UA[ 'iPad_2Mini1' ] && !X_UA[ 'iPod_4' ] && // iOS7 以上で HTML Audio が鳴らない問題を見ていくよ // !X_UA[ 'iOS' ] && @@ -90,11 +94,13 @@ var X_WebAudio_context = // 4s 以下ではない iPad 2G または iPad mi //!X_UA[ 'Blink' ] && // Firefox40.0.5 + Windows8 で音声が途中から鳴らなくなる // Firefox41.0.1 + Windows8 で音声が途中から鳴らなくなる - !( 40 <= X_UA[ 'Gecko' ] && X_UA[ 'Gecko' ] < 46 && X_UA[ 'Windows' ] ) && - ( window[ 'AudioContext' ] || window[ 'webkitAudioContext' ] ), + !( 40 <= X_UA[ 'Gecko' ] && /* X_UA[ 'Gecko' ] < 48 && */ X_UA[ 'Windows' ] ) && + ( window[ 'AudioContext' ] || window[ 'webkitAudioContext' ] || window[ 'mozAudioContext' ] ), + X_WebAudio_context, X_WebAudio_BUFFER_LIST = [], X_WebAudio_need1stTouch = X_UA[ 'iOS' ], - X_WebAudio_touchState = X_WebAudio_need1stTouch, + X_WebAudio_isNoTouch = X_WebAudio_need1stTouch, + X_WebAudio_needRateFix = X_WebAudio_need1stTouch, X_WebAudio, X_WebAudio_BufferLoader, X_WebAudio_fpsFix; @@ -102,9 +108,46 @@ var X_WebAudio_context = // 4s 以下ではない iPad 2G または iPad mi /* * iPhone 4s 以下、iPad2以下、iPad mini 1以下, iPod touch 4G 以下は不可 */ -if( X_WebAudio_context ){ +if( X_WebAudio_Context ){ + + X_WebAudio_context = new X_WebAudio_Context; - X_WebAudio_context = new X_WebAudio_context; + // http://lilting.ch/3323.html + // 【間に合わせ】iOS9系でのWebAudioの音割れ対処について + /* + if( X_WebAudio_needRateFix ){ + X_WebAudio_context.close(); + X_WebAudio_context = new X_WebAudio_Context; + }; */ + + /* + * TODO X_TEMP へ + * http://qiita.com/simiraaaa/items/79a9ac972cc76fb58d93 + * [WebAudio API] iOS9で音が歪む、遅い、低い、割れる等の回避方法 + */ + if( X_WebAudio_needRateFix ){ + X_TEMP.webAudioSampleRateFix = function( sampleRate ){ + X_TEMP.webAudioDummyPlay( sampleRate ); + + if( true || X_WebAudio_context[ 'sampleRate' ] !== sampleRate ){ + // alert( '[debug]iOSで音割れを検知、修復コードを実施 ctxSR:' + X_WebAudio_context[ 'sampleRate' ] + ' abfSR:' + sampleRate ); + + X_WebAudio_context.close && X_WebAudio_context.close(); + X_WebAudio_context = new X_WebAudio_Context; + + X_TEMP.webAudioDummyPlay( sampleRate ); + }; + + delete X_TEMP.webAudioSampleRateFix; + delete X_TEMP.webAudioDummyPlay; + }; + X_TEMP.webAudioDummyPlay = function( sampleRate, source ){ + source = X_WebAudio_context[ 'createBufferSource' ](); + source.buffer = X_WebAudio_context[ 'createBuffer' ]( 1, 1, sampleRate ); + source[ 'connect' ]( X_WebAudio_context[ 'destination' ] ); + source.start ? source.start( 0 ) : source[ 'noteOn' ] ? source[ 'noteOn' ]( 0 ) : source[ 'noteGrainOn' ]( 0 ); + }; + }; X_WebAudio_BufferLoader = X_EventDispatcher[ 'inherits' ]( 'X.WebAudio.BufferLoader', @@ -212,8 +255,7 @@ if( X_WebAudio_context ){ } ); - - + X_WebAudio = X_AudioBase[ 'inherits' ]( 'X.WebAudio', X_Class.POOL_OBJECT, @@ -229,9 +271,12 @@ if( X_WebAudio_context ){ audioBuffer : null, bufferSource : null, gainNode : null, + + bufferPlay : '', + bufferStop : '', //_onended : null, - 'Constructor' : function( disatcher, url, option ){ + 'Constructor' : function( dispatcher, url, option ){ var i = 0, l = X_WebAudio_BUFFER_LIST.length, loader; @@ -259,7 +304,7 @@ if( X_WebAudio_context ){ this.loader = loader = X_WebAudio_BufferLoader( this, url ); }; - this.disatcher = disatcher || this; + this.dispatcher = dispatcher || this; this.setState( option ); this[ 'listenOnce' ]( X_EVENT_KILL_INSTANCE, this.onKill ); @@ -269,6 +314,11 @@ if( X_WebAudio_context ){ } else { loader[ 'listenOnce' ]( X_EVENT_COMPLETE, this, this._onLoadBufferComplete ); }; + + if( X_WebAudio_isNoTouch ){ + X_TEMP.xWebAudioInstances = X_TEMP.xWebAudioInstances || []; + X_TEMP.xWebAudioInstances.push( this ); + }; }, onKill : function(){ @@ -283,6 +333,10 @@ if( X_WebAudio_context ){ //this._onended && X_Closure_correct( this._onended ); this.gainNode && this.gainNode.disconnect(); + + if( X_WebAudio_isNoTouch ){ + X_TEMP.xWebAudioInstances.splice( X_TEMP.xWebAudioInstances.indexOf( this ), 1 ); + }; }, _onLoadBufferComplete : function( e ){ var loader = this.loader, @@ -292,7 +346,7 @@ if( X_WebAudio_context ){ if ( !buffer ) { this.error = loader.errorState; - this.disatcher[ 'dispatch' ]({ + this.dispatcher[ 'dispatch' ]({ type : X_EVENT_ERROR, error : loader.errorState, message : loader.errorState === 1 ? @@ -306,11 +360,11 @@ if( X_WebAudio_context ){ this.audioBuffer = buffer; this.duration = buffer.duration * 1000; - this.disatcher[ 'asyncDispatch' ]( X_WebAudio_touchState ? X_EVENT_MEDIA_WAIT_FOR_TOUCH : X_EVENT_READY ); + this.dispatcher[ 'asyncDispatch' ]( X_WebAudio_isNoTouch ? X_EVENT_MEDIA_WAIT_FOR_TOUCH : X_EVENT_READY ); }, actualPlay : function(){ - var e, begin, end; + var xWebAudio, begin, end; console.log( '[WebAudio] play abuf:' + !!this.audioBuffer ); @@ -318,42 +372,48 @@ if( X_WebAudio_context ){ this._playReserved = true; return; }; - - if( X_WebAudio_touchState ){ - e = X_EventDispatcher_CURRENT_EVENTS[ X_EventDispatcher_CURRENT_EVENTS.length - 1 ]; + + if( X_WebAudio_isNoTouch ){ + //@dev{ + var e = X_EventDispatcher_CURRENT_EVENTS[ X_EventDispatcher_CURRENT_EVENTS.length - 1 ]; if( !e || !e[ 'pointerType' ] ){ // alert( 'タッチイベント以外での play! ' + ( e ? e.type : '' ) ); return; }; + //@} + // http://qiita.com/uupaa/items/e5856e3cb2a9fc8c5507 // iOS9 + touchstart で呼んでいた場合、 X_ViewPort['listenOnce']('pointerup',this,this.actualPlay()) - this.disatcher[ 'asyncDispatch' ]( X_EVENT_READY ); + this.dispatcher[ 'asyncDispatch' ]( X_EVENT_READY ); + + // Web Audio インスタンスが複数生成された場合、一つの Web Audio に対してタッチによる play が開始されたら、 + // 1. 同時に生成された他の X.Audio インスタンスに対して READY イベントを発する + // 2. 以降の X.Audio インスタンス生成時に needTouchForPlay フラグは false + // ちなみに HTML Audio インスタンスは各々にタッチが必要 + //X_WebAudio_isNoTouch = false; + + while( xWebAudio = X_TEMP.xWebAudioInstances.pop() ){ + xWebAudio !== this && xWebAudio[ 'asyncDispatch' ]( X_EVENT_READY ); + }; + delete X_TEMP.xWebAudioInstances; + + X_WebAudio_isNoTouch = false; + + X_TEMP.webAudioSampleRateFix && X_TEMP.webAudioSampleRateFix( this.audioBuffer[ 'sampleRate' ] ); }; - X_WebAudio_touchState = false; end = X_Audio_getEndTime( this ); begin = X_Audio_getStartTime( this, end, true ); console.log( '[WebAudio] play ' + begin + ' -> ' + end + ' loop: ' + this.autoLoop + ' :' + this.loopStartTime + ' -> ' + this.loopEndTime ); - - if( this.bufferSource ) this._sourceDispose(); - if( !this.gainNode ){ - this.gainNode = X_WebAudio_context[ 'createGain' ] ? X_WebAudio_context[ 'createGain' ]() : X_WebAudio_context[ 'createGainNode' ](); - this.gainNode[ 'connect' ]( X_WebAudio_context[ 'destination' ] ); - }; - - this.bufferSource = X_WebAudio_context[ 'createBufferSource' ](); - this.bufferSource.buffer = this.audioBuffer; + this._createTree( begin, end ); /* win8.1 Firefox45, win8.1 Chrome48 で動かなくなる... if( this.bufferSource[ 'loop' ] = this.autoLoop ){ this.bufferSource[ 'loopStart' ] = 0 <= this.loopStartTime ? this.loopStartTime / 1000 : begin / 1000; this.bufferSource[ 'loopEnd' ] = 0 <= this.loopEndTime ? this.loopEndTime / 1000 : end / 1000; }; */ - - this.bufferSource[ 'connect' ]( this.gainNode ); - this.gainNode[ 'gain' ].value = this.gain; - + // おかしい、stop 前に外していても呼ばれる、、、@Firefox33.1 // 破棄された X.Callback が呼ばれて、obj.proxy() でエラーになる。Firefox では、onended は使わない // 多くのブラウザで onended は timer を使ったカウントより遅いので使わない @@ -364,16 +424,7 @@ if( X_WebAudio_context ){ //this._timerID && X_Timer_remove( this._timerID ); //this._timerID = X_Timer_once( end - begin, this, this._onEnded ); //}; - - if( this.bufferSource.start ){ - this.bufferSource.start( 0, begin / 1000, ( end - begin ) / 1000 ); - } else - if( this.bufferSource[ 'noteOn' ] ){ - this.bufferSource[ 'noteOn' ]( 0, begin / 1000, ( end - begin ) / 1000 ); - } else { - this.bufferSource[ 'noteGrainOn' ]( 0, begin / 1000, ( end - begin ) / 1000 ); - }; - + this.playing = true; this._startPos = begin; this._endPosition = end; @@ -381,20 +432,34 @@ if( X_WebAudio_context ){ this._interval = this._interval || X_Timer_add( 100, 0, this, this._onInterval ); }, + _createTree : function( begin, end ){ + if( this.bufferSource ) this._sourceDispose(); + + if( !this.gainNode ){ + this.gainNode = X_WebAudio_context[ 'createGain' ] ? X_WebAudio_context[ 'createGain' ]() : X_WebAudio_context[ 'createGainNode' ](); + this.gainNode[ 'connect' ]( X_WebAudio_context[ 'destination' ] ); + }; + + this.bufferSource = X_WebAudio_context[ 'createBufferSource' ](); + this.bufferSource.buffer = this.audioBuffer; + this.bufferSource[ 'connect' ]( this.gainNode ); + + this.gainNode[ 'gain' ].value = this.gain; + + if( !this.bufferPlay ){ + this.bufferPlay = this.bufferSource.start ? 'start' : this.bufferSource[ 'noteOn' ] ? 'noteOn' : 'noteGrainOn'; + this.bufferStop = this.bufferSource.stop ? 'stop' : 'noteOff'; + }; + // https://developer.mozilla.org/ja/docs/Web/API/AudioBufferSourceNode + // AudioBufferSourceNode.start()の呼び出しは一度しかできません。 + this.bufferSource[ this.bufferPlay ]( 0, begin / 1000, ( end - begin ) / 1000 ); + }, + _sourceDispose : function(){ this.bufferSource.disconnect(); //delete this.bufferSource.onended; delete this.bufferSource; }, - - /* - _onInterval : function(){ - if( !this.playing ){ - delete this._interval; - return X_CALLBACK_UN_LISTEN; - }; - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING ); - }, */ _onInterval : function(){ var time; @@ -405,14 +470,14 @@ if( X_WebAudio_context ){ //console.log( '> onEnd ' + ( this.playing && ( X_WebAudio_context.currentTime * 1000 - this._startTime ) ) + ' < ' + ( this._endPosition - this._startPos ) ); if( time < 0 ){ - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING ); return; }; if( this.autoLoop ){ - if( !( this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){ + if( !( this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){ this.looped = true; - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED ); this.actualPlay(); } else { delete this._interval; @@ -420,7 +485,7 @@ if( X_WebAudio_context ){ }; } else { this.actualPause(); - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED ); }; }; }, @@ -433,8 +498,7 @@ if( X_WebAudio_context ){ delete this.playing; if( this.bufferSource ){ - this.bufferSource.stop ? - this.bufferSource.stop( 0 ) : this.bufferSource[ 'noteOff' ]( 0 ); + this.bufferSource[ this.bufferStop ]( 0 ); }; }, diff --git a/0.6.x/js/07_audio/02_XHTMLAudio.js b/0.6.x/js/07_audio/02_XHTMLAudio.js index 1c88ae5..ab98389 100644 --- a/0.6.x/js/07_audio/02_XHTMLAudio.js +++ b/0.6.x/js/07_audio/02_XHTMLAudio.js @@ -54,8 +54,8 @@ var // Opera Mobile 12 は 2回目以降の currentTime へのセットで currentTime が更新されなくなるため、タイマーを使用する X_HTMLAudio_currentTimeFix = !!X_UA[ 'OperaMobile' ] || !!X_UA[ 'OperaTablet' ], - // Firefox44.0.2 で音声の再生開始に難あり... - X_HTMLAudio_playStartFix = X_UA[ 'Windows' ] && X_UA[ 'Gecko' ] === 44, + // Firefox44.0.2 で音声の再生開始に難あり... 49 でも確認, あるいはCGIで動的に生成しているmp3自体に問題があるのかも + X_HTMLAudio_playStartFix = X_UA[ 'Windows' ] && 44 <= X_UA[ 'Gecko' ], X_HTMLAudio_volumeFix = X_UA[ 'Chrome' ], /* @@ -118,10 +118,10 @@ if( X_Audio_constructor ){ _seekingFixON : false, - 'Constructor' : function( disatcher, source, option ){ + 'Constructor' : function( dispatcher, source, option ){ var raw; - this.disatcher = disatcher || this; + this.dispatcher = dispatcher || this; this._src = source; if( X_HTMLAudio_shortPlayFix ){ @@ -188,7 +188,7 @@ if( X_Audio_constructor ){ }, onDebug : function( e ){ - this.disatcher[ 'dispatch' ]( { + this.dispatcher[ 'dispatch' ]( { type : X_EVENT_DEBUG, 'rawEvent' : e.type, 'current' : this[ '_rawObject' ].currentTime, @@ -232,7 +232,7 @@ if( X_Audio_constructor ){ for( i = time = 0, l = buf && buf.length; i < l; ++i ){ time += buf[ 'end' ]( i ) - buf[ 'start' ]( i ); }; - this.disatcher[ 'dispatch' ]( { type : X_EVENT_PROGRESS, 'percent' : time * 1000 / this.duration * 100 } ); + this.dispatcher[ 'dispatch' ]( { type : X_EVENT_PROGRESS, 'percent' : time * 1000 / this.duration * 100 } ); }; break; @@ -379,29 +379,36 @@ if( X_Audio_constructor ){ if( this._touchState === 1 ){ if( e.type === X_HTMLAudio_playTrigger ){ this._touchState = 2; - this.disatcher[ 'asyncDispatch' ]( X_EVENT_MEDIA_WAIT_FOR_TOUCH ); + this.dispatcher[ 'asyncDispatch' ]( X_EVENT_MEDIA_WAIT_FOR_TOUCH ); }; } else if( ended ){ if( this.autoLoop ){ - if( !( this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){ + if( !( this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){ this.looped = true; - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED ); this.actualPlay( X_HTMLAudio_endedFixCWV && actualEnded, X_HTMLAudio_endedFixAOSP3 && actualEnded ); }; } else { this.seekTime = 0; delete this.playing; - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED ); }; } else if( this._readyState === 1 && this.duration ){ this._readyState |= 2; - this.disatcher[ 'asyncDispatch' ]( X_EVENT_READY ); + this.dispatcher[ 'asyncDispatch' ]( X_EVENT_READY ); + + // TODO 勝手に play する環境があるので pause() を実施 + /* + if( !this.playing && !this.autoplay && !this._playReserved && !X_HTMLAudio_pauseFix ){ + this.actualPause(); + }; */ + console.log( '> Audio Loaded!! ' + e.type + ' d:' + ( this.duration | 0 ) ); } else if( eventType ){ - this.disatcher[ 'dispatch' ]( eventType ); + this.dispatcher[ 'dispatch' ]( eventType ); }; }, @@ -488,7 +495,7 @@ if( X_Audio_constructor ){ this._endedFixON = true; raw.src = this._src; console.log( '△ onEndedFix の開始' ); - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING ); }; }; diff --git a/0.6.x/js/07_audio/03_XSilverlightAudio.js b/0.6.x/js/07_audio/03_XSilverlightAudio.js index ea3dad7..09fa4cd 100644 --- a/0.6.x/js/07_audio/03_XSilverlightAudio.js +++ b/0.6.x/js/07_audio/03_XSilverlightAudio.js @@ -53,7 +53,7 @@ if( X_Plugin_SILVER_LIGHT_VERSION ){ _lastState : '', _interval : 0, // setInterval timer id - 'Constructor' : function( disatcher, source, option ){ + 'Constructor' : function( dispatcher, source, option ){ !X_SLAudio_uid && X_TEMP.slaudioInit(); /* @@ -61,7 +61,7 @@ if( X_Plugin_SILVER_LIGHT_VERSION ){ * http://www.atmarkit.co.jp/fdotnet/dotnettips/902slobjcallfromjs/slobjcallfromjs.html * このページのサンプルは sl5+firefox32 環境で動いている。xaml を js から利用する形ではなく、.xap を sl4 以下で作るのがよさそう. */ - this.disatcher = disatcher || this; + this.dispatcher = dispatcher || this; this._source = source; // X.Audio._slOnload_ は不可 this._onload = 'XAudioSilverlightOnLoad' + ( ++X_SLAudio_uid ); @@ -122,7 +122,7 @@ if( X_Plugin_SILVER_LIGHT_VERSION ){ if( this.playing ){ //X_Timer_once( 16, this, this.actualPlay ); } else { - this.disatcher[ 'dispatch' ]( X_EVENT_ERROR ); // open failed + this.dispatcher[ 'dispatch' ]( X_EVENT_ERROR ); // open failed this[ 'kill' ](); }; break; @@ -130,7 +130,7 @@ if( X_Plugin_SILVER_LIGHT_VERSION ){ case 'MediaOpened' : // http://msdn.microsoft.com/ja-jp/library/bb979710(VS.95).aspx this.duration = this[ '_rawObject' ][ 'NaturalDuration' ][ 'Seconds' ] * 1000; - this.disatcher[ 'asyncDispatch' ]( X_EVENT_READY ); + this.dispatcher[ 'asyncDispatch' ]( X_EVENT_READY ); break; case 'MediaEnded' : @@ -157,10 +157,10 @@ if( X_Plugin_SILVER_LIGHT_VERSION ){ case 'Opening' : switch( this._lastUserAction ){ case 'play' : - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING ); break; case 'seek' : - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_SEEKING ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_SEEKING ); break; case 'pause' : break; @@ -177,7 +177,7 @@ if( X_Plugin_SILVER_LIGHT_VERSION ){ this.playing = false; this._ended = true; this._paused = false; - this.disatcher[ 'dispatch' ]( X_EVENT_ERROR ); + this.dispatcher[ 'dispatch' ]( X_EVENT_ERROR ); this[ 'kill' ](); break; @@ -195,7 +195,7 @@ if( X_Plugin_SILVER_LIGHT_VERSION ){ //this.seekTime = 0; this._ended = true; this._paused = false; - //this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED ); + //this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED ); //this.setCurrentTime( this.startTime ); break; case 'pause': @@ -214,7 +214,7 @@ if( X_Plugin_SILVER_LIGHT_VERSION ){ //this.playing = true; this._ended = false; this._paused = false; - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING ); break; // stop() @@ -230,7 +230,7 @@ if( X_Plugin_SILVER_LIGHT_VERSION ){ break; case X_EVENT_KILL_INSTANCE : - this.playing && this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED ); + this.playing && this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED ); this.playing && this.actualPause(); if( this._onload ){ @@ -297,7 +297,7 @@ if( X_Plugin_SILVER_LIGHT_VERSION ){ delete this._interval; return X_CALLBACK_UN_LISTEN; }; - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING ); }, _onEnded : function(){ @@ -315,7 +315,7 @@ if( X_Plugin_SILVER_LIGHT_VERSION ){ console.log( ' > ' + time ); this._ended && this[ '_rawObject' ].play(); this._ended = false; - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING ); this._timerID = X_Timer_once( X_Audio_getEndTime( this ) - time, this, this._onEnded ); return; }; @@ -331,16 +331,16 @@ if( X_Plugin_SILVER_LIGHT_VERSION ){ if( this.autoLoop ){ console.log( '========= loop?' ); - if( !( this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){ + if( !( this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){ console.log( '========== loopした' ); this.looped = true; - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED ); this.actualPlay(); }; } else { console.log( '========= pause' ); this.actualPause(); - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED ); }; }; }, diff --git a/0.6.x/js/07_audio/05_XWMPAudio.js b/0.6.x/js/07_audio/05_XWMPAudio.js index 5ee0c80..cb750fb 100644 --- a/0.6.x/js/07_audio/05_XWMPAudio.js +++ b/0.6.x/js/07_audio/05_XWMPAudio.js @@ -22,8 +22,8 @@ if( X_Plugin_WMP_VERSION ){ // IETester で 6.x は不可 _seekDirection : 0, _timerID : 0, - 'Constructor' : function( disatcher, source, option ){ - this.disatcher = disatcher || this; + 'Constructor' : function( dispatcher, source, option ){ + this.dispatcher = dispatcher || this; this._source = source; if( 7 <= X_Plugin_WMP_VERSION ){ @@ -71,7 +71,7 @@ if( X_Plugin_WMP_VERSION ){ // IETester で 6.x は不可 break; case X_EVENT_KILL_INSTANCE : - this.playing && this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED ); + this.playing && this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED ); this.playing && this.actualPause(); this.wmp.stop(); this.xnodeObject[ 'kill' ](); @@ -120,7 +120,7 @@ if( X_Plugin_WMP_VERSION ){ // IETester で 6.x は不可 progress = this.wmp[ 'BufferingProgress' ]; }; if( progress < 100 ){ - this.disatcher[ 'dispatch' ]( { type : X_EVENT_PROGRESS, 'percent' : progress } ); + this.dispatcher[ 'dispatch' ]( { type : X_EVENT_PROGRESS, 'percent' : progress } ); } else { this._readyState = 2; if( 7 <= X_Plugin_WMP_VERSION ){ @@ -128,7 +128,7 @@ if( X_Plugin_WMP_VERSION ){ // IETester で 6.x は不可 } else { this.duration = this.wmp[ 'Duration' ] * 1000 | 0; }; - this.disatcher[ 'dispatch' ]( X_EVENT_READY ); + this.dispatcher[ 'dispatch' ]( X_EVENT_READY ); }; } else // ended の判定 @@ -138,33 +138,33 @@ if( X_Plugin_WMP_VERSION ){ // IETester で 6.x は不可 // waiting if( this._seekDirection ){ if( this._seekDirection === 1 ? ( time < this._beginTime ) : ( this._lastCurrentTime <= time ) ){ - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_SEEKING ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_SEEKING ); return; }; delete this._seekDirection; }; if( time === this._lastCurrentTime ){ - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING ); return; }; this._lastCurrentTime = time; // ended ではない if( time - X_Audio_getEndTime( this ) < -50 ){ - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING ); return; }; // ended if( this.autoLoop ){ - if( !( this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){ + if( !( this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){ this.looped = true; - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED ); this.actualPlay(); }; } else { this.actualPause(); - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED ); + this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED ); delete this._timerID; return X_CALLBACK_UN_LISTEN; }; diff --git a/0.6.x/js/07_audio/10_XAudioSprite.js b/0.6.x/js/07_audio/10_XAudioSprite.js index f0183bc..dc4ec65 100644 --- a/0.6.x/js/07_audio/10_XAudioSprite.js +++ b/0.6.x/js/07_audio/10_XAudioSprite.js @@ -28,7 +28,7 @@ var X_AudioSprite_shouldUse = X_HTMLAudio && ( X_UA[ 'iOS' ] || X_UA[ 'A bgmName : '', bgmLooped : false, bgmPlaying : false, - event : null + tmpEvent : null }, X_AudioSprite, X_AudioSprite_numTracks, @@ -93,7 +93,7 @@ X[ 'AudioSprite' ] = function( setting ){ X_Audio_startDetectionBackend( X_Audio_BACKENDS[ 0 ], - X_AudioSprite, + X_AudioSprite, // dispatcher として X_Array_copy( urls ), { 'volume' : 0 <= volume && volume <= 1 ? volume : 1, @@ -369,7 +369,7 @@ function X_AudioSprite_backendHandler( e ){ // HTMLAudio ( e[ 'needTouchForLoad' ] && ( _e[ 'needTouchForLoad' ] = true ) ) ){ - X_AudioSprite_TEMP.event = _e; + X_AudioSprite_TEMP.tmpEvent = _e; last[ 'listenOnce' ]( X_EVENT_MEDIA_WAIT_FOR_TOUCH, X_AudioSprite_backendHandler ); } else { X_AudioSprite[ 'asyncDispatch' ]( _e ); @@ -388,8 +388,8 @@ function X_AudioSprite_backendHandler( e ){ case X_EVENT_MEDIA_WAIT_FOR_TOUCH : // TODO 全ての track の MEDIA_WAIT_FOR_TOUCH で! - X_AudioSprite[ 'asyncDispatch' ]( X_AudioSprite_TEMP.event ); - delete X_AudioSprite_TEMP.event; + X_AudioSprite[ 'asyncDispatch' ]( X_AudioSprite_TEMP.tmpEvent ); + delete X_AudioSprite_TEMP.tmpEvent; break; case X_EVENT_PROGRESS : @@ -398,6 +398,21 @@ function X_AudioSprite_backendHandler( e ){ case X_EVENT_READY : console.log( 'X.AudioSprite - Ready!' ); + + if( X_AudioSprite_TEMP.tmpEvent ){ + // このタイミングで tmpEvent が存在する場合は、タッチをスキップして Web Audio が再生可能になった + // つまり他の Web Audio インスタンスでタッチによる再生が開始され、自身も再生可能になった + + _e = X_AudioSprite_TEMP.tmpEvent; + _e[ 'needTouchForPlay' ] = false; + + X_AudioSprite + [ 'unlisten' ]( X_EVENT_MEDIA_WAIT_FOR_TOUCH, X_AudioSprite_backendHandler ) + [ 'asyncDispatch' ]( _e ); + + delete X_AudioSprite_TEMP.tmpEvent; + }; + for( i = 0; i < X_AudioSprite_numTracks; ++i ){ track = X_AudioSprite_TEMP.tracks[ i ]; ( track.autoplay || track._playReserved ) && track.actualPlay(); -- 2.11.0