};\r
if( sys === 'iPad' ){\r
acme.iPad = true;\r
- if( i ) acme.iPod_2Mini1 = true;\r
+ if( i ) acme.iPad_2Mini1 = true;\r
};\r
if( sys === 'iPod' ){\r
acme.iPod = true;\r
case 'WinCE' :\r
acme[ sys ] = true;\r
};\r
+ // winRT\r
} else\r
if( sys.indexOf( 'Mac' ) + 1 ){\r
console.log( 'Mac' );\r
acme.Linux = true;\r
\r
if( ( i = dua.indexOf( 'Android' ) ) !== -1 ){\r
- acme.Android = parseFloat( dua.substr( i + 8 ) ) || 0;\r
+ acme.Android = parseFloat( dua.substr( i + 8 ) ) || 0.1; // Firefox で Version が取れない!\r
console.log( '>> Android : ' + acme.Android );\r
};\r
};\r
acme.IE7 = 7 <= acme.IE && acme.IE < 8;\r
acme.IE8 = 8 <= acme.IE && acme.IE < 9;\r
acme.IE9 = 9 <= acme.IE && acme.IE < 10;\r
- acme.MacIE = dua.indexOf( 'Mac_PowerPC' ) !== -1 || dua.indexOf( 'Mac_PPC' ) !== -1 || dua.indexOf( 'Mac_68K' ) !== -1;\r
+ acme.MacIE = acme.Mac;\r
acme.IEMobile = dua.toLowerCase().indexOf( 'iemobile' ) !== -1 || acme.WinCE;\r
acme.WinPhone = dua.toLowerCase().indexOf( 'windows phone' ) !== -1;\r
console.log( '>> IE : ' + acme.IE + ' ActiveX : ' + acme.ActiveX );\r
\r
// http://qa.support.sony.jp/solution/S0812181056444/common/nfb34_dom_200jp/dom_dom0_JP.html\r
if( ( i = dua.indexOf( 'NetFront\/' ) !== -1 ) ){\r
- acme.NetFront = parseFloat( dua.substr( i + 9 ) ) || 0;\r
+ acme.NetFront = parseFloat( dua.substr( i + 9 ) ) || 0.1;\r
console.log( '>> NetFront : ' + acme.NetFront );\r
return acme;\r
};\r
// Mozilla/5.0 (PLAYSTATION 3; 3.55)\r
// Mozilla/4.0 (PS3 (PlayStation 3); 1.00)\r
if( ( i = dua.toUpperCase().indexOf( 'PLAYSTATION 3' ) !== -1 ) ){\r
- acme.PS3 = parseFloat( dua.substr( i + 15 ) ) || 0;\r
+ acme.PS3 = parseFloat( dua.substr( i + 15 ) ) || 0.1;\r
console.log( '>> PS3 : ' + acme.PS3 );\r
return acme;\r
};\r
// iCab/3.0.2 (Macintosh; U; PPC Mac OS X)\r
// Mozilla/5.0 (Macintosh; U; PPC Mac OS; en) iCab 3\r
if( ( i = dua.indexOf( 'iCab' ) !== -1 ) ){\r
- acme.iCab = parseFloat( dua.substr( i + 5 ) ) || 0;\r
+ acme.iCab = parseFloat( dua.substr( i + 5 ) ) || 0.1;\r
console.log( '>> iCab : ' + acme.iCab );\r
return acme;\r
};\r
\r
} else\r
if( ( i = dua.indexOf( 'Android ' ) ) !== -1 ){\r
- acme.AndroidBrowser = i = parseFloat( dua.substr( i + 8 ) ) || 0;\r
+ acme.AndroidBrowser = i = parseFloat( dua.substr( i + 8 ) ) || 0.1;\r
acme.AndroidBrowser1 = 1 <= i && i < 2;\r
acme.AndroidBrowser2 = 2 <= i && i < 3;\r
acme.AndroidBrowser3 = 3 <= i && i < 4;\r
acme.AndroidBrowser4 = 4 <= i && i < 5;\r
acme.AndroidBrowser5 = 5 <= i && i < 6;\r
console.log( '>> AndroidBrowser : ' + acme.Android );\r
+ \r
+ i = parseFloat(dua.split('WebKit\/')[1]);\r
+ acme.AndroidBrowserWebkit = i;\r
+ alert( 'AudioSprite調査:Android標準ブラウザ Webkit Version ' + i );\r
+ \r
} else\r
if( i = parseFloat(dua.split('WebKit\/')[1]) ){\r
acme.WebKit = i;\r
},\r
\r
isString : function( v ){\r
- return typeof v === 'string'; // v === v + '';\r
+ return typeof v === 'string'; // v === v + ''; // 文字列の加算は IE で遅いかも。\r
},\r
\r
isNumber : function( v ){\r
( X_UA.IE4 || X_UA.MacIE ) ?\r
'return v&&v.tagName&&v.insertAdjacentHTML&&true' : // ie4 or MacIE5.23, v.all <- error\r
X_UA.NetFront < 4 ?\r
- 'return v&&v.nodeType===1' : // instanceof not a function. \r
+ 'return v&&v.nodeType===1' : // instanceof not a function. netfront3.4 は html に instanceof をすると error になる\r
window[ 'HTMLElement' ] ?\r
'return v instanceof HTMLElement' :\r
//window[ 'Element' ] ?\r
),\r
\r
/*\r
- * new Image した場合に HTMLElement の img が作られるブラウザもある\r
+ * new Image した場合に HTMLImageElement が作られるブラウザと,そうでないブラウザ(IE8-)がある\r
*/ \r
isImage :\r
function( v ){\r
};\r
\r
function X_Object_cloneArray( ary ){\r
- var ret = [], i = ary.length;\r
+ var ret = [],\r
+ i = ary.length;\r
if( !i ) return ret;\r
for( ; i; ){\r
ret[ --i ] = ary[ i ];\r
list.slcallback = X_Callback_create( that, X_EventDispatcher_sliverLightDispatch, [ type ] );\r
list.sltoken = raw.AddEventListener( type, list.slcallback );\r
} else\r
- if( X.UA.iOS && ( type === 'webkitTransitionEnd' || type === 'transitionend' ) ){\r
+ // iOS と MacOSX Iron36 で発生。連続してアニメーションが起こると、クロージャの束縛された obj へのアクセスに失敗する。Win では起きない?\r
+ // むしろ、MacOSX のブラウザ全般で起こる??\r
+ if( ( X_UA.WebKit || X_UA.Blink ) &&\r
+ ( type === 'webkitTransitionEnd' || type === 'transitionend' ||\r
+ type === 'animationend' || type === 'webkitAnimationEnd' ||\r
+ type === 'animationstart' || type === 'webkitAnimationStart' ||\r
+ type === 'animationiteration' || type === 'webkitAnimationIteration' ) ){\r
raw.addEventListener( type, X_EventDispatcher_iOSTransitionEndDispatch, false );\r
} else {\r
console.log( 'event > ' + type );\r
delete list.sltoken;\r
delete list.slcallback;\r
} else\r
- if( X.UA.iOS && ( type === 'webkitTransitionEnd' || type === 'transitionend' ) ){\r
+ if( ( X_UA.WebKit || X_UA.Blink ) &&\r
+ ( type === 'webkitTransitionEnd' || type === 'transitionend' ||\r
+ type === 'animationend' || type === 'webkitAnimationEnd' ||\r
+ type === 'animationstart' || type === 'webkitAnimationStart' ||\r
+ type === 'animationiteration' || type === 'webkitAnimationIteration' ) ){\r
raw.removeEventListener( type, X_EventDispatcher_iOSTransitionEndDispatch, false );\r
} else {\r
\r
break;
case 'visibilitychange' :
- X_ViewPort.asyncDispatch( ( X_ViewPort_active = document[ 'hidden' ] ) ? X.Event.VIEW_DEACTIVATE : X.Event.VIEW_ACTIVATE );
+ X_ViewPort.dispatch( ( X_ViewPort_active = document[ 'hidden' ] ) ? X.Event.VIEW_DEACTIVATE : X.Event.VIEW_ACTIVATE );
break;
case 'mozvisibilitychange' :
- X_ViewPort.asyncDispatch( ( X_ViewPort_active = document[ 'mozHidden' ] ) ? X.Event.VIEW_DEACTIVATE : X.Event.VIEW_ACTIVATE );
+ X_ViewPort.dispatch( ( X_ViewPort_active = document[ 'mozHidden' ] ) ? X.Event.VIEW_DEACTIVATE : X.Event.VIEW_ACTIVATE );
break;
case 'webkitvisibilitychange' :
- X_ViewPort.asyncDispatch( ( X_ViewPort_active = document[ 'webkitHidden' ] ) ? X.Event.VIEW_DEACTIVATE : X.Event.VIEW_ACTIVATE );
+ X_ViewPort.dispatch( ( X_ViewPort_active = document[ 'webkitHidden' ] ) ? X.Event.VIEW_DEACTIVATE : X.Event.VIEW_ACTIVATE );
break;
case 'pageshow' :
case 'focus' :
if( !X_ViewPort_active ){
X_ViewPort_active = true;
- X_ViewPort.asyncDispatch( X.Event.VIEW_ACTIVATE );
+ X_ViewPort.dispatch( X.Event.VIEW_ACTIVATE );
};
break;
case 'blur' :
if( X_ViewPort_active ){
X_ViewPort_active = false;
- X_ViewPort.asyncDispatch( X.Event.VIEW_DEACTIVATE );
+ X_ViewPort.dispatch( X.Event.VIEW_DEACTIVATE );
};
break;
};
};\r
\r
/*\r
- * 数値が来たら文字化\r
- * null が来たら ''\r
+ * null が来たら '', 数値等が来たら文字烈化\r
*/\r
function X_Node_text( text ){\r
var xnodes, texts, i, l;\r
// setter\r
if( text !== undefined ){\r
- if( X.Type.isNumber( text ) ) text += '';\r
if( text === null ) text = '';\r
+ text += '';\r
\r
if( this._xnodeType === 3 ){\r
if( this._text !== text ){\r
SELECT : true,\r
BUTTON : true,\r
OBJECT : true,\r
- PARAM : true // FlashVars が flash 側から書き換えられるケースがある\r
+ PARAM : true // FlashVars が flash 側から書き換えられるケースがある??\r
+},\r
+\r
+// <input type=button,hidden,submit,reset,radio,checkbox> の場合、value の値はユーザーで変えることはない\r
+// <input type=text,password,file> はユーザーによって常に変更される HTML5 ではこれにさらにいろいろ加わる\r
+X_Node_Attr_STATIC_VALUE_TYPES = {\r
+ button : true,\r
+ hidden : true,\r
+ submit : true,\r
+ reset : true,\r
+ radio : true,\r
+ checkbox : true\r
},\r
\r
X_Node_Attr_renameForTag = {};\r
// 親ノードの selectedIndex の getter を呼んでおくと値が正しくなる、ということ?( by itozyun )\r
if( X_UA.WebKit ) this._rawObject.parentNode.selectedIndex;\r
case 'value' :\r
+ if( this._tag === 'INPUT' && X_Node_Attr_STATIC_VALUE_TYPES[ attrs[ 'type' ] ] ) break;\r
case 'checked' :\r
case 'disabled' : \r
case 'selectedIndex' :\r
'for(;i<5;){',\r
'try{',\r
'return[v[++i],new ActiveXObject(n[i])]',\r
- '}catch(e){return false}',\r
+ '}catch(e){}',\r
'}'\r
].join( '' ) ) )();\r
\r
break;\r
case 'json' :\r
case 'moz-json' :\r
- raw.responseType = this._type;\r
+ raw.responseType = X_UA.Gecko ? this._type : ''; // Iron 37 でエラー\r
break;\r
case 'document' :\r
case 'xml' :\r
-var X_Audio_WebAudio_context = window.webkitAudioContext || window.AudioContext,
+var X_Audio_WebAudio_context = !X_UA.iPhone_4s && !X_UA.iPad_2Mini1 && !X_UA.iPod_4 &&
+ !( X_UA.Gecko && X_UA.Android ) &&
+ ( window.AudioContext || window.webkitAudioContext ),
X_Audio_WebAudioWrapper;
-if( !X_UA.iPhone_4s && !X_UA.iPod_2Mini1 && !X_UA.iPod_4 && X_Audio_WebAudio_context ){
+/*
+ * iPhone 4s 以下、iPad2以下、iPad mini 1以下, iPod touch 4G 以下は不可
+ */
+if( X_Audio_WebAudio_context ){
X_Audio_WebAudio_context = new X_Audio_WebAudio_context;
if( this.loop ){
this.looped = true;
- ( this.proxy.dispatch( 'looped' ) | X.Callback.PREVENT_DEFAULT ) || this.play();
+ ( this.proxy.dispatch( 'looped' ) & X.Callback.PREVENT_DEFAULT ) || this.play();
} else {
this.pause();
this.proxy.dispatch( 'ended' );
X_Audio_HTMLAudioWrapper,\r
X_Audio_rawAudio,\r
// Opera Mobile 12 android4.4.4 & 2.3.5 は 2回目以降の currentTime へのセットで currentTime が更新されなくなるため、タイマーを使用する\r
- X_Audio_HTMLAudioWrapper_currentTimeFix = !!X_UA.OperaMobile || !!X_UA.OperaTablet;\r
+ X_Audio_HTMLAudioWrapper_currentTimeFix = !!X_UA.OperaMobile || !!X_UA.OperaTablet,\r
+ // 一方 Desktop の Opera12 は、loadeddata 等では duration が infinity で、再生後の durationchange 時に duration が判明する。\r
+ // duration 判明後には currentTime によるシークと、現在時間の取得が可能になる。\r
+ // canplay で play() durationchange で duration が取れたら loadedmetadata->loadeddata -> canplay する\r
+ // boombox.js に書いてあった currentTime の効かないブラウザってこいつのことみたい、、、\r
+ X_Audio_HTMLAudioWrapper_currentTimeFix2 = !X_Audio_HTMLAudioWrapper_currentTimeFix && X_UA.Opera,\r
+ \r
+ X_Audio_HTMLAudioWrapper_shortPlayFix = !!X_UA.AndroidBrowser4;\r
+ \r
\r
if( window.HTMLAudioElement ){\r
\r
autoplay : false,\r
volume : 0.5,\r
\r
- _timerID : 0,\r
- _playTime : 0,\r
- _closed : true,\r
- _loaded : false,\r
+ _timerID : 0,\r
+ _playTime : 0,\r
+ _closed : true,\r
+ _loaded : false,\r
+ _playForDuration : false,\r
+ _currentTimeFix : 0,\r
+ _shortFix : 0,\r
\r
Constructor : function( proxy, source, option ){\r
this.proxy = proxy;\r
this._closed = false;\r
\r
X_AudioWrapper_updateStates( this, option );\r
- \r
- // TODO use video document.createElement('video')\r
- this._rawObject = X_Audio_rawAudio || new Audio( source );// X_Doc_create( 'audio', { src : source } ).appendToRoot();//( X.X_Node_systemNode );\r
+\r
+ if( option[ 'useVideo' ] ){\r
+ this._rawObject = document.createElement( 'video' );\r
+ this._rawObject.preload = 'none'; // auto, metadata, none\r
+ //this._rawObject.autoplay = false, // no-auto\r
+ this._rawObject.loop = false;\r
+ this._rawObject.muted = false;\r
+ //this._rawObject.crossorigin = option[ 'crossorigin' ] || ''; //crossorigin: "anonymous", X.URL.isSameDomain() で切り替え\r
+ this._rawObject.style.cssText = 'position:absolute;bottom:0;left:-50px;width:100px;height:100px;opacity:0;';\r
+ this._rawObject.controls = false;\r
+ this._rawObject.WebKitPlaysInline = true;\r
+ this._rawObject.src = source;\r
+ //this._rawObject.onclick = "alert('play');this.play();";\r
+ document.body.appendChild( this._rawObject );\r
+ //this._rawObject.load();\r
+ } else {\r
+ this._rawObject = X_Audio_rawAudio || new Audio( source );// X_Doc_create( 'audio', { src : source } ).appendToRoot();//( X.X_Node_systemNode );\r
+ };\r
\r
this.listen( [\r
'loadstart', 'load', 'progress', 'suspend', 'abort', 'error', 'emptied', 'stalled', 'play', 'pause', 'loadedmetadata',\r
* http://uguisu.skr.jp/html/table3.html\r
*/\r
handleEventProxy : function( e ){\r
+ var loaded;\r
console.log( 'HTMLAudio ' + e.type );\r
\r
switch( e.type ){\r
case 'loadstart' : // ブラウザがコンテンツの検索を開始した場合に発生\r
break;\r
case 'progress' : // ブラウザがコンテンツの取得を実行した場合に発生\r
- //console.log( e.loaded + ' ' + e.total * 100 + '%' );\r
- this._rawObject.duration &&\r
- console.dir( this._rawObject );\r
+ console.log( e.loaded + ' ' + e.total * 100 + '%' );\r
+ //this._rawObject.duration &&\r
+ // console.dir( this._rawObject );\r
//console.log( this._rawObject.buffered.end(0) / this._rawObject.duration * 100 + '%' );\r
break;\r
+ \r
+ case 'canplay' : // 今すぐに再生を再開できるが、バッファリングが不十分でコンテンツを最後まで表示できないと予測している場合に発生\r
+ if( X_Audio_HTMLAudioWrapper_currentTimeFix2 ){\r
+ console.log( 'play ' + this.duration );\r
+ this._playForDuration = true;\r
+ this._rawObject.currentTime = 0;\r
+ this._rawObject.play();\r
+ this._rawObject.currentTime = 0;\r
+ };\r
case 'loadedmetadata' : // ブラウザがメディアリソースの長さと寸法を判定した場合に発生\r
case 'loadeddata' : // コンテンツの表示を現在の再生位置で初めて行えるようになった場合に発生\r
- case 'canplay' : // 今すぐに再生を再開できるが、バッファリングが不十分でコンテンツを最後まで表示できないと予測している場合に発生\r
case 'canplaythrough' : // 今すぐに再生を開始してもバッファリングで停止することなく最後まで表示できると予測している場合に発生\r
+ if( X_Audio_HTMLAudioWrapper_currentTimeFix2 ) return;\r
this.duration = this._rawObject.duration * 1000;\r
- //console.log( this.duration );\r
+ console.log( this.duration );\r
break;\r
\r
case 'suspend' : // ブラウザが意図的にコンテンツの取得を現在行っていない場合に発生(ダウンロードは未完了)\r
case 'error' : // コンテンツの取得実行中にエラーが発生した場合に発生\r
case 'emptied' : // 読み込み中に致命的なエラーが発生したか、実行状態ででload()メソッドが実行された場合に発生\r
case 'stalled' : // ブラウザがコンテンツの取得を試みたが、データがまだ用意されていない場合に発生\r
+ break;\r
+ \r
+ \r
case 'play' : // 再生が開始された。play()メソッドからの復帰後に発生する場合に発生\r
case 'pause' : // 再生が一時停止された。pauseメソッドからの復帰後に発生する場合に発生\r
-\r
case 'waiting' : // 次のフレームが利用不可のため再生を停止したが、そのフレームがやがて利用可能になると想定している場合に発生\r
- case 'playing' : // 再生が開始された場合に発生\r
-\r
+ case 'playing' : // 再生が開始された場合に発生 \r
case 'seeking' : // シークがtrueに変化し、イベントを発生させるのに十分な時間がシーク操作にかかっている場合に発生\r
case 'seeked' : // シークがfalseに変化した場合に発生\r
+ case 'ratechange' : // defaultPlaybackRate属性とplaybackRate属性のどちらかが更新された場合に発生\r
+ case 'volumechange' : // volume属性とmuted属性のどちらかが変化した場合に発生\r
+ if( this._playForDuration ) return;\r
break;\r
\r
case 'timeupdate' : // 通常の再生が行われ現在の再生位置の変化が起こった場合に発生\r
+ // console.log( this._rawObject.currentTime );\r
+ if( this._playForDuration ) return; \r
this._onEnded();\r
break;\r
\r
case 'ended' :\r
+ if( X_Audio_HTMLAudioWrapper_currentTimeFix2 ){\r
+ delete this._currentTimeFix;\r
+ };\r
if( !this._closed && this.loop ){\r
this.looped = true;\r
- ( this.proxy.dispatch( 'looped' ) | X.Callback.PREVENT_DEFAULT ) || this.play();\r
+ ( this.proxy.dispatch( 'looped' ) & X.Callback.PREVENT_DEFAULT ) || this.play();\r
} else {\r
this._timerID && X.Timer.remove( this._timerID );\r
this.seekTime = 0;\r
};\r
break;\r
\r
- case 'ratechange' : // defaultPlaybackRate属性とplaybackRate属性のどちらかが更新された場合に発生\r
case 'durationchange' : // duration属性が更新された場合に発生\r
- case 'volumechange' : // volume属性とmuted属性のどちらかが変化した場合に発生\r
+ this.duration = this._rawObject.duration * 1000;\r
+ // console.log( this._rawObject.duration );\r
+ \r
+ if( this._playForDuration ){\r
+ this._rawObject.pause();\r
+ this._rawObject.currentTime = 0.001;\r
+ delete this._playForDuration;\r
+ \r
+ this.proxy.asyncDispatch( 'loadedmetadata' );\r
+ this.proxy.asyncDispatch( 'loadeddata' );\r
+ this.proxy.asyncDispatch( 'canplay' );\r
+ this.proxy.asyncDispatch( 'canplaythrough' );\r
+ loaded = true;\r
+ console.log( 'DEsktop Opera のための currentTime と duration の fix が完了' + this.duration );\r
+ };\r
+ if( this._currentTimeFix === 1 ){\r
+ this._currentTimeFix++;\r
+ this._rawObject.currentTime = this._beginTime / 1000;\r
+ return;\r
+ };\r
+ break;\r
+ \r
};\r
//console.log( 'html5 ' + e.type + ' ' + ( this.proxy._listeners && this.proxy._listeners[ e.type ] && this.proxy._listeners[ e.type ].length ) );\r
//e.type === 'canplaythrough' && console.dir( e );\r
- this.proxy.dispatch( e );\r
+ loaded || this.proxy.dispatch( e );\r
\r
- if( X_Audio_HTMLAudio_playTrigger === e.type || ( X_UA.AndroidBrowser2 && e.type === 'loadeddata' ) ){\r
+ if( X_Audio_HTMLAudio_playTrigger === e.type || ( X_UA.AndroidBrowser2 && e.type === 'loadeddata' ) || loaded ){\r
!this._loaded && this.autoplay && X.Timer.once( 16, this, this.play );\r
this._loaded = true;\r
console.log( 'Loaded! ' + e.type );\r
\r
end = X_AudioWrapper_getEndTime( this );\r
begin = X_AudioWrapper_getStartTime( this, end, true );\r
+ \r
+\r
+ if( X_Audio_HTMLAudioWrapper_shortPlayFix ){\r
+ begin -= end - begin > 1000 ? 200 : 400;\r
+ begin = begin < 0 ? 0 : begin;\r
+ }; \r
+ \r
this._rawObject.currentTime = begin / 1000;\r
- \r
+\r
+\r
+ if( X_Audio_HTMLAudioWrapper_currentTimeFix2 ){\r
+ //this._currentTimeFix++;\r
+ this._beginTime = begin;\r
+ };\r
+\r
console.log( '[HTMLAudio] play ' + begin + ' -> ' + end );\r
\r
if( !this.playing ){\r
if( this.playing ){\r
currentTime = X_Audio_HTMLAudioWrapper_currentTimeFix ? X_Timer_now() - this._playTime + this._beginTime : this._rawObject.currentTime * 1000 | 0;\r
time = currentTime - X_AudioWrapper_getEndTime( this );\r
+\r
+ if( X_Audio_HTMLAudioWrapper_shortPlayFix ){\r
+ //time -= this._shortFix;\r
+ };\r
+\r
if( time < 0 ){\r
- console.log( '> onEnd ' + (-time) + ' ' + currentTime + '/' + X_AudioWrapper_getEndTime( this ) );\r
+ console.log( '> onEnd ' + (-time) + ' ' + currentTime + '/' + ( X_AudioWrapper_getEndTime( this ) ) );\r
//if( X_Audio_HTMLAudioWrapper_currentTimeFix ) this._timerID = X.Timer.once( -time, this, this._onEnded );\r
return;\r
};\r
\r
if( this.loop ){\r
this.looped = true;\r
- ( this.proxy.dispatch( 'looped' ) | X.Callback.PREVENT_DEFAULT ) || this.play();\r
+ ( this.proxy.dispatch( 'looped' ) & X.Callback.PREVENT_DEFAULT ) || this.play();\r
} else {\r
this.pause();\r
this.dispatch( 'ended' );\r
\r
this.seekTime = this.state().currentTime;\r
\r
+ if( X_Audio_HTMLAudioWrapper_currentTimeFix2 ){\r
+ delete this._currentTimeFix;\r
+ };\r
+ \r
//this._timerID && X.Timer.remove( this._timerID );\r
//delete this._timerID;\r
delete this._playTime;\r
case 'mp3' :\r
ok = X_UA.IE || X_UA.Chrome || ( X_UA.Windows && X_UA.Safari );\r
mineType = 'audio/mpeg';\r
+ //if( X_UA.Android && X_UA.Gecko ) mineType = '';\r
break;\r
case 'ogg' :\r
ok = 15 <= X_UA.Gecko || X_UA.Chrome || X_UA.Opera;\r
+ if( X_UA.AndroidBrowser ) mineType = '';\r
break;\r
case 'm4a' :\r
ok = X_UA.IE || X_UA.WebKit;\r
\r
if( this.loop ){\r
this.looped = true;\r
- ( this.proxy.dispatch( 'looped' ) | X.Callback.PREVENT_DEFAULT ) || this.play();\r
+ ( this.proxy.dispatch( 'looped' ) & X.Callback.PREVENT_DEFAULT ) || this.play();\r
} else {\r
this.pause();\r
this.proxy.dispatch( 'ended' ); \r
* iframe 内で生成して、Audio Sprite の preset で再生できないか?\r
*/\r
var X_Audio_Sprite_shouldUse = window.HTMLAudioElement && ( X_UA.iOS || X_UA.AndroidBrowser || X_UA.OperaMobile || X_UA.OperaTablet ),\r
- X_Audio_Sprite_needTouchFirst = !!X_UA.iOS,\r
+ X_Audio_Sprite_useVideoForMulti = 4 <= X_UA.AndroidBrowser && 534.3 < X_UA.AndroidBrowserWebkit, // ドスパラパッドはビデオのインライン再生が不可 \r
+ X_Audio_Sprite_needTouchFirst = !!X_UA.iOS || X_Audio_Sprite_useVideoForMulti,\r
X_Audio_Sprite_inTouchAction = false,\r
- X_Audio_Sprite_enableMultiTrack = !( X_UA.iOS < 6 ),\r
+ X_Audio_Sprite_enableMultiTrack = !( X_UA.iOS && !X_Audio_WebAudio_context ) && !( X_UA.AndroidBrowser4 && X_UA.AndroidBrowserWebkit <= 534.3 ),\r
X_Audio_Sprite_enableVolume = window.HTMLAudioElement && ( !X_UA.iOS && !X_UA.AndroidBrowser && !X_UA.OperaMobile && !X_UA.OperaTablet ),\r
- X_Audio_Sprite_useVideoForMulti = 4 <= X_UA.AndroidBrowser,\r
- X_Audio_Sprite_maxTracks = X_UA.iOS < 6 ? 1 : X_Audio_Sprite_useVideoForMulti ? 2 : 9,\r
+ X_Audio_Sprite_maxTracks = !X_Audio_Sprite_enableMultiTrack ? 1 : X_Audio_Sprite_useVideoForMulti ? 2 : 9,\r
X_Audio_Sprite_lengthSilence = 10000, // 一番最初の無音部分の長さ\r
X_Audio_Sprite_lengthDistance = 5000, // 音間の無音の長さ\r
X_Audio_Sprite_uid = 0,\r
presets : {},\r
BGMs : {},\r
tracks : [],\r
+ pauseTracks : [], // X.Event.DEACTIVATE によって pause した再生中のトラックたち。\r
volume : 1,\r
bgmTrack : null,\r
bgmPosition : 0,\r
X_Audio_Sprite_instance.close();\r
} else {\r
X_Audio_Sprite_instance = X_Class_override( new X.EventDispatcher(), X_Audio_Sprite_members );\r
+ X_ViewPort.listen( [ X.Event.VIEW_ACTIVATE, X.Event.VIEW_DEACTIVATE ], X_Audio_Sprite_instance, X_Audio_Sprite_handleEvent );\r
};\r
X_Audio_Sprite_instance.setup( setting );\r
return X_Audio_Sprite_instance;\r
};\r
\r
// 再生が終わっているもの、終わりかけのものを探す\r
-// TODO çµ\82ã\82\8fã\82\8aã\81\8bã\81\91ã\81®ã\82\82ã\81®ã\80\81ã\81¨ä¸\80ç\95ªå\8f¤ã\81\84ã\82\82ã\81®ã\80\81ã\81©ã\81¡ã\82\89ã\82\92å\86\8då\88©ç\94¨ã\81\99ã\82\8bã\81\8bï¼\9fã\81¾ã\81\9fã\81¯ã\80\81å\86\8då\88©ç\94¨ã\82\92å¾\85ã\81¤ã\80\82\r
+// TODO çµ\82ã\82\8fã\82\8aã\81\8bã\81\91ã\81®ã\82\82ã\81®ã\80\81ã\81¨ä¸\80ç\95ªå\8f¤ã\81\84ã\82\82ã\81®ã\80\81ã\81©ã\81¡ã\82\89ã\82\92å\86\8då\88©ç\94¨ã\81\99ã\82\8bã\81\8bï¼\9fã\81\93ã\82\8c以ä¸\8aã\81«ç´°ã\81\8bã\81\84å®\9fè£\85ã\82\92æ\9c\9bã\82\80å ´å\90\88ã\81¯ X.Audio.Sprite ã\81¯ä½¿ã\82\8fã\81\9aè\87ªå\8a\9bã\81§å®\9fè£\85\r
function X_Audio_Sprite_getTrackEnded(){\r
var tracks = X_Audio_Sprite_TEMP.tracks,\r
l = tracks.length,\r
bgms = X_Audio_Sprite_TEMP.BGMs,\r
presets = X_Audio_Sprite_TEMP.presets,\r
urls = setting[ 'urls' ],\r
- n = setting[ 'numTracks' ] || 1,\r
video = setting[ 'useVideo' ],\r
+ n = video ? 1 : setting[ 'numTracks' ] || 1,\r
option = {\r
volume : setting[ 'volume' ] || 0.5,\r
autoplay : false,\r
\r
n = n <= X_Audio_Sprite_maxTracks ? n : X_Audio_Sprite_maxTracks;\r
\r
- video = video || ( 1 < n && X_Audio_Sprite_useVideoForMulti );\r
- \r
for( k in setting ){\r
v = setting[ k ];\r
if( X.Type.isArray( v ) && v !== urls){\r
};\r
\r
for( i = 0; i < n; ++i ){\r
- if( i === 1 && X_Audio_Sprite_useVideoForMulti ){\r
- // TODO use <Video>\r
- tracks.push( X.Audio.create( urls, option ) );\r
- } else {\r
- tracks.push( X.Audio.create( urls, option ) );\r
+ if( video || ( i === 1 && X_Audio_Sprite_useVideoForMulti ) ){\r
+ option[ 'useVideo' ] = true;\r
};\r
+ tracks.push( X.Audio.create( urls, X.Object.clone( option ) ) );\r
};\r
\r
tracks[ n - 1 ].listenOnce( [ 'backendfound', 'nobackend' ], this, X_Audio_Sprite_handleEvent );\r
};\r
\r
function X_Audio_Sprite_handleEvent( e ){\r
+ var i, tracks, track;\r
switch( e.type ){\r
case 'backendfound' :\r
this.asyncDispatch( e );\r
e.target.unlisten( 'nobackend', this, X_Audio_Sprite_handleEvent );\r
\r
if( e.backendName === 'HTML Audio' ){\r
- e.target.listen( [ X_Audio_HTMLAudio_playTrigger, 'loadeddata' ], this, X_Audio_Sprite_handleEvent );\r
+ e.target.listenOnce( [ X_Audio_HTMLAudio_playTrigger, 'loadeddata' ], this, X_Audio_Sprite_handleEvent );\r
} else {\r
- e.target.listen( 'canplaythrough', this, X_Audio_Sprite_handleEvent );\r
+ e.target.listenOnce( 'canplaythrough', this, X_Audio_Sprite_handleEvent );\r
};\r
break;\r
\r
case 'canplaythrough' :\r
case X_Audio_HTMLAudio_playTrigger :\r
case 'loadeddata' :\r
+ e.target.unlisten( [ X_Audio_HTMLAudio_playTrigger, 'loadeddata', 'canplaythrough' ], this, X_Audio_Sprite_handleEvent );\r
+ \r
+ if( X_Audio_Sprite_useVideoForMulti ){\r
+ for( i = 0; i < X_Audio_Sprite_TEMP.tracks.length; ++i ){\r
+ X_Audio_Sprite_instance.pause( i );\r
+ };\r
+ e.target.listenOnce( 'timeupdate', this, X_Audio_Sprite_handleEvent ); // Android 標準ブラウザ\r
+ return;\r
+ };\r
+ case 'timeupdate' :\r
this.asyncDispatch( 'audioSpriteCanPlay' );\r
break;\r
\r
};\r
break;\r
\r
+ case X.Event.VIEW_ACTIVATE :\r
+ // track.play(); or iOS need touch??\r
+ tracks = X_Audio_Sprite_TEMP.pauseTracks;\r
+ while( tracks.length ) tracks.pop().play();\r
+ break;\r
+\r
+ case X.Event.VIEW_DEACTIVATE :\r
+ // track.pause();\r
+ tracks = X_Audio_Sprite_TEMP.tracks;\r
+ i = tracks.length;\r
+ for( ; i; ){\r
+ track = tracks[ --i ];\r
+ track.isPlaying() && X_Audio_Sprite_TEMP.pauseTracks.push( track.pause() );\r
+ };\r
+ break;\r
+ \r
case X.Event.KILL_INSTANCE :\r
+ X_ViewPort.unlisten( [ X.Event.VIEW_ACTIVATE, X.Event.VIEW_DEACTIVATE ], this, X_Audio_Sprite_handleEvent );\r
this.close();\r
break;\r
};\r