postdata = obj[ 'postdata' ] || '',\r
timeout = obj[ 'timeout' ] || 20000,\r
noCache = obj[ 'cache' ] !== true,\r
+ dataType = X_XHR._dataType = obj[ 'dataType' ],\r
xDomain = !X_URL_isSameDomain( url ),\r
isFile = X_URL_isLocal( url ),\r
init,\r
type, tmp, p;\r
-\r
- X_XHR._dataType = obj[ 'dataType' ];\r
\r
if( !raw || xDomain !== X_XHR._isXDR || ( X_XHR_createMSXML && isFile !== X_XHR._isMsXML ) ){\r
raw && X_XHR[ 'unlisten' ]( [ 'load', 'readystatechange', 'progress', 'error', 'timeout' ] );\r
raw.open( method, url, async, username, password );\r
\r
if( raw.responseType !== undefined ){\r
- switch( X_XHR._dataType ){\r
+ switch( dataType ){\r
case '' :\r
case 'text' :\r
// js, css\r
raw.responseType = 'text';\r
break;\r
case 'json' : // firefox9- は moz-json\r
- raw.responseType = X_UA[ 'Gecko' ] < 10 ? 'moz-json' : X_UA[ 'Gecko' ] ? X_XHR._dataType : ''; // Iron 37 でエラー\r
+ raw.responseType = X_UA[ 'Gecko' ] < 10 ? 'moz-json' : X_UA[ 'Gecko' ] ? dataType : ''; // Iron 37 でエラー\r
break;\r
case 'document' :\r
case 'xml' :\r
case 'blob' :\r
case 'arraybuffer' :\r
// jpeg,jpg,png,gif,mp3,ogg...\r
- raw.responseType = X_XHR._dataType;\r
+ raw.responseType = dataType;\r
break;\r
};\r
};\r
\r
// http://www.quirksmode.org/blog/archives/2005/09/xmlhttp_notes_r_1.html\r
if( !X_XHR._isMsXML && raw.overrideMimeType ){\r
- type = X_URL_getEXT( url ) || X_XHR._dataType;\r
+ type = X_URL_getEXT( url ) || dataType;\r
switch( type ){\r
case 'html' :\r
case 'htm' :\r
case 'mp4' :\r
tmp = 'audio/x-' + type;\r
break;\r
+ case 'jpeg' :\r
+ case 'jpg' :\r
+ case 'png' :\r
+ case 'gif' :\r
+ case 'bmp' :\r
+ case 'ico' :\r
+ tmp = 'text/plain; charset=x-user-defined';\r
+ break;\r
+ \r
};\r
if( tmp = obj[ 'mimeType' ] || tmp ) raw.overrideMimeType( tmp );\r
};\r
\r
// http://nakigao.sitemix.jp/blog/?p=2040\r
// json 取得時に SafariでHTTP/412のエラー。但し相手が audio の場合この指定があるとロードに失敗する。 iOS8.2, iOS7.1 では遭遇せず\r
- if( X_XHR._dataType === 'json' ){\r
+ if( dataType === 'json' ){\r
headers[ 'If-Modified-Since' ] = ( new Date ).toUTCString();\r
};\r
\r
handleEvent : function( e ){\r
var raw = X_XHR[ '_rawObject' ],\r
live = !X_XHR._canceled,\r
- headers, status, data;\r
+ headers, status, text, data;\r
\r
switch( e && e.type || 'readystatechange' ){\r
/*\r
){\r
/*\r
* opera8, safari2, khtml3 で utf8 日本語文字列の文字化け\r
+ * \r
+ * http://www.kawa.net/works/js/jkl/parsexml.html\r
+ \r
+ text = raw[ 'responseText' ];\r
+ // Safari and Konqueror cannot understand the encoding of text files.\r
+ if( text && ( X_UA[ 'Webkit' ] < 420 || X_UA[ 'KHTML' ] < 4 ) ){\r
+ text = escape( text );\r
+ if ( !text.match( '%u' ) && esc.match( '%' ) ){\r
+ text = decodeURIComponent( text );\r
+ };\r
+ };\r
*/\r
\r
// parse json, html, xml, text, script, css\r
break;\r
case 'blob' :\r
case 'arraybuffer' :\r
+ // TODO resoponceBody if( X_UA[ 'IE' ] < 10 )\r
+ // http://d.hatena.ne.jp/maachang/20130221/1361427565\r
data = raw[ 'response' ] || raw[ 'responseText' ]; // とりあえず\r
break;\r
};\r
return this.req.documentElement; // IXMLDOMDocument\r
}\r
};\r
-\r
-// ================================================================\r
-// method: responseText()\r
-// return: text string in response body\r
-\r
-JKL.ParseXML.HTTP.prototype.responseText = function() {\r
- // debug.print( "responseText: "+this.req );\r
- if ( ! this.req ) return;\r
-\r
- // Safari and Konqueror cannot understand the encoding of text files.\r
- if ( navigator.appVersion.match( "KHTML" ) ) {\r
- var esc = escape( this.req.responseText );\r
-// debug.print( "escape: "+esc );\r
- if ( ! esc.match("%u") && esc.match("%") ) {\r
- return decodeURIComponent(esc);\r
- }\r
- }\r
-\r
- return this.req.responseText;\r
-};\r
*/\r
\r
onTimeout : function(){\r
X_Class.POOL_OBJECT,\r
{\r
_closed : true,\r
- _loaded : false,\r
- _ready : false,\r
- _src : '',\r
- \r
- // 0:\r
- // 1: touch 要求完了\r
- // 2: touch による play 中\r
- // 4: duration 取得完了 currentTime へのセット\r
- // 8: playing || loadeddata or canplaythrought\r
- // 16: READY 発火済\r
+\r
+ // 1: canplaythrought|timeupdateに達している、またはdurationFixが終了している\r
+ // 2: READY イベント発火済\r
_readyState : 0,\r
+ _src : '',\r
\r
- _touchRequested : false,\r
- _touched : false,\r
+ // 0:ok\r
+ // 1:touch 要求済\r
+ // 2:touch による play 済\r
+ _touchState : X_HTMLAudio_need1stTouch ? 1 : 0,\r
\r
_currentFixStart : 0,\r
_currentFixBegin : 0,\r
\r
+ // 0:durationFix不要 または 完了\r
+ // 1:durationFix未着手(touchState=1なら play() に入れる)\r
+ // 2:canplay イベント発生 -> play()\r
+ // 4:play() 実施済\r
+ // 8:duration 取得済\r
+ // :timeupdate イベントで durationFixは完了\r
_durationFixPhase : X_HTMLAudio_durationFix ? 1 : 0,\r
- _durationFixSkip : X_HTMLAudio_durationFix && !X_HTMLAudio_need1stTouch,\r
_lastCurrentTime : 0,\r
\r
_shortPlayFixON : false,\r
X_elmBody.appendChild( raw );\r
} else {\r
raw = X_TEMP.rawAudio || new X_Audio_constructor( '' );\r
- // X_Doc_create( 'audio', { src : source } )[ 'appendTo' ]( X.Doc.body );\r
- //raw.autoplay = raw.autobuffer = raw.loop = false; // loop を使えば ended で止まること回避できるかも 但し ended イベントが起きなくなる\r
+ // raw.loop = false; // loop を使えば ended で止まること回避できるかも 但し ended イベントが起きなくなる\r
\r
if( X_TEMP.rawAudio ) delete X_TEMP.rawAudio;\r
};\r
if( X_HTMLAudio_need1stTouch ){\r
raw.src = source;\r
} else {\r
- raw.preload = 'auto';\r
- raw.autoplay = true; // Android 4.0-4.1.x で必要\r
+ // if( this.autoplay ){\r
+ raw.preload = 'auto';\r
+ raw.autoplay = true; // Android 4.0-4.1.x で必要\r
+ //};\r
//raw.autobuffer = true;\r
raw.src = source;\r
raw.load(); // Android4.1.1 HTL21 では必要!\r
this.disatcher[ 'dispatch' ]( {\r
type : X_EVENT_DEBUG,\r
'rawEvent' : e.type,\r
- current : this.getActualCurrentTime() | 0,\r
+ current : this[ '_rawObject' ].currentTime,\r
duration : this[ '_rawObject' ].duration } );\r
},\r
\r
handleEvent : function( e ){\r
+ if( !e || !e.type ) alert( 888 );\r
+ \r
var raw = this[ '_rawObject' ],\r
actualEnded = e.type === 'ended',\r
ended = actualEnded,\r
ready,\r
eventType, duration, end, now;\r
\r
+ if( this._closed ) return;\r
+ \r
// global に公開\r
//window[ '__rawAudio' ] = this[ '_rawObject' ];\r
\r
switch( e.type ){\r
\r
case X_EVENT_KILL_INSTANCE :\r
- // 【javascript】モバイル向けブラウザでも音を鳴らしたい【WebAudio】\r
- // http://ingaouhou.com/archives/3633\r
- // ・使い終わったインスタンスはload()しておくとやや安定\r
- this.playing && this.actualPause();\r
delete this._closed;\r
- delete this._loaded;\r
+ this.playing && this.actualPause();\r
\r
+ // 【javascript】モバイル向けブラウザでも音を鳴らしたい【WebAudio】\r
+ // http://ingaouhou.com/archives/3633\r
+ // ・使い終わったインスタンスはload()しておくとやや安定 \r
raw.src = '';\r
raw.load();\r
\r
\r
case 'loadeddata' : // コンテンツの表示を現在の再生位置で初めて行えるようになった場合に発生\r
case 'canplaythrough' : // 今すぐに再生を開始してもバッファリングで停止することなく最後まで表示できると予測している場合に発生\r
- if( !this._endedFixON ){\r
- ready = true;\r
+ if( !this._endedFixON && !X_HTMLAudio_durationFix && !X_HTMLAudio_need1stTouch ){\r
+ this._readyState |= 1;\r
};\r
case 'canplay' : // 今すぐに再生を再開できるが、バッファリングが不十分でコンテンツを最後まで表示できないと予測している場合に発生\r
- if( X_HTMLAudio_durationFix && !X_HTMLAudio_need1stTouch && this._durationFixPhase === 1 ){\r
+ if( this._durationFixPhase === 1 && !X_HTMLAudio_need1stTouch ){\r
+ this._durationFixPhase = 2;\r
this.actualPlay();\r
- raw.currentTime = 0; // å¿\85è¦\81ï¼\81\r
+ raw.currentTime = 0; // Win8 + Opera12 ã\81§å¿\85è¦\81\r
};\r
if( this._endedFixON ){\r
console.log( '▽ onEndedFix の終了 @' + e.type );\r
\r
// TODO firefox で 短い音声でtimeupdate, ended が発火しない <- 最後の音に無音部分を追加する\r
case 'timeupdate' : // 通常の再生が行われ現在の再生位置の変化が起こった場合に発生\r
- if( this._durationFixPhase & 3 ){ // 1 or 2\r
+ if( this._durationFixPhase === 8 ){\r
+ this._durationFixPhase = 0;\r
+ this._readyState |= 1;\r
+ } else\r
+ if( this._durationFixPhase === 4 ){ // 1 or 2\r
duration = raw.duration;\r
+ eventType = X_EVENT_MEDIA_WAITING;\r
+ } else\r
+ if( !X_HTMLAudio_durationFix && X_HTMLAudio_need1stTouch && this._touchState === 3 ){\r
+ this._touchState = 0;\r
+ this._readyState |= 1;\r
} else\r
if( ( now = this.getActualCurrentTime() ) === this._lastCurrentTime ){\r
eventType = X_EVENT_MEDIA_WAITING;\r
- } else {\r
- this._lastCurrentTime = now; // *1 rm\r
-\r
- if( this.playing ){\r
- end = X_Audio_getEndTime( this ) + this._shortPlayFixTime;\r
- //console.log( now + ' / ' + end );\r
- // || now < this._lastCurrentTime // loop した場合\r
- if( 0 + end <= 0 + now ){ // 0+ なぜか iem9 で必要,,,\r
- if( this.autoLoop ){\r
- console.log( '☆★☆ 曲の最後に到達 @timeupdate now-end:' + ( now - end ) );\r
- ended = true;\r
- if( X_HTMLAudio_endedFixIOS ) actualEnded = true;\r
- } else {\r
- this.actualPause();\r
- eventType = X_EVENT_MEDIA_ENDED;\r
- };\r
+ } else\r
+ if( this.playing ){\r
+ end = X_Audio_getEndTime( this ) + this._shortPlayFixTime;\r
+ //console.log( now + ' / ' + end );\r
+ // || now < this._lastCurrentTime // loop した場合\r
+ if( 0 + end <= 0 + now ){ // 0+ なぜか iem9 で必要,,,\r
+ if( this.autoLoop ){\r
+ console.log( '☆★☆ 曲の最後に到達 @timeupdate now-end:' + ( now - end ) );\r
+ ended = true;\r
+ if( X_HTMLAudio_endedFixIOS ) actualEnded = true;\r
} else {\r
- eventType = X_EVENT_MEDIA_PLAYING;\r
- // *1 this._lastCurrentTime = now;\r
+ this.actualPause();\r
+ eventType = X_EVENT_MEDIA_ENDED;\r
};\r
+ } else {\r
+ eventType = X_EVENT_MEDIA_PLAYING;\r
};\r
+ this._lastCurrentTime = now;\r
};\r
break;\r
\r
//if( X_HTMLAudio_currentTimeFix && !this._currentFixStart ){\r
//this._currentFixStart = X_Timer_now(); // 正確な再生開始時間に補正\r
//};\r
- eventType = !this._durationFixSkip && !this._endedFixON ? X_EVENT_MEDIA_PLAYING : X_EVENT_MEDIA_WAITING;\r
+ eventType = !this._durationFixPhase && !this._endedFixON ? X_EVENT_MEDIA_PLAYING : X_EVENT_MEDIA_WAITING;\r
//case 'play' : // 再生が開始された。play()メソッドからの復帰後に発生する場合に発生\r
//case 'pause' : // 再生が一時停止された。pauseメソッドからの復帰後に発生する場合に発生\r
//case 'seeked' : \r
if( 0 < duration && X_Type_isFinite( duration ) ){\r
this.duration = duration * 1000;\r
\r
- if( this._durationFixPhase === 2 ){\r
+ if( this._durationFixPhase === 4 ){\r
console.log( '▼ DurationFix の終了 @' + e.type );\r
- this._durationFixPhase = 4;\r
+ this._durationFixPhase = 8;\r
\r
- ready = true;\r
- \r
- if( this.autoplay || this._loaded ){\r
+ if( this.autoplay ){\r
console.log( '☆ 再生 <- DurationFix の終了' );\r
- this._durationFixSkip = false;\r
this.actualPlay();\r
} else\r
if( X_HTMLAudio_pauseFix ){\r
this.actualPause(); \r
};\r
} else\r
- if( this._durationFixPhase ){\r
- this._durationFixPhase = 4;\r
+ if( this._durationFixPhase & 3 ){ // === 1 | 2\r
+ this._durationFixPhase = 8;\r
}; \r
};\r
\r
- this._loaded = this._loaded || ready;\r
-\r
//\r
- if( X_HTMLAudio_need1stTouch && !this._touchRequested ){ // !this._readyState\r
+ if( this._touchState === 1 ){\r
if( e.type === X_HTMLAudio_playTrigger ){\r
- this._touchRequested = true;\r
- this._readyState = 1;\r
- this.disatcher[ 'asyncDispatch' ]( X_EVENT_MEDIA_CAN_TOUCH_LOAD ); \r
+ this._touchState = 2;\r
+ this.disatcher[ 'asyncDispatch' ]( X_EVENT_MEDIA_TOUCH_FOR_LOAD ); \r
};\r
} else\r
if( ended ){\r
- if( !this._closed && this.autoLoop ){\r
+ if( this.autoLoop ){\r
if( !( this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){\r
this.looped = true;\r
this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );\r
this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
};\r
} else\r
- if( this._loaded && this.duration && !this._ready ){\r
- this._ready = true;\r
+ if( this._readyState === 1 && this.duration ){\r
+ this._readyState = 3;\r
this.disatcher[ 'asyncDispatch' ]( X_EVENT_READY );\r
- this.autoplay && !X_HTMLAudio_need1stTouch && X_Timer_once( 16, this, this.actualPlay );\r
+ this.autoplay && X_Timer_once( 16, this, this.actualPlay );\r
console.log( '> Audio Loaded!! ' + e.type + ' d:' + ( this.duration | 0 ) );\r
} else\r
if( eventType ){\r
this.disatcher[ 'dispatch' ]( eventType );\r
- // eventType === X_EVENT_ERROR && this[ 'kill' ]();\r
};\r
},\r
\r
actualPlay : function( forcePlay, forceReload ){\r
var raw = this[ '_rawObject' ],\r
e, begin, end;\r
- \r
- // もし kill 後に autoplayTimer で呼ばれても、_closed==true なので平気\r
+\r
if( this._closed ) return;\r
\r
- \r
if( !raw.src ){ // X_HTMLAudio_pauseFix によって src が空になっている\r
console.log( '○ 削除された audio.src の復帰' );\r
raw.src = this._src;\r
- //return;\r
+ return;\r
}; \r
- \r
- if( this._touchRequested && !this._touched ){ // this._readyState === 1\r
+\r
+ if( this._touchState === 2 ){\r
e = X_EventDispatcher_CURRENT_EVENTS[ X_EventDispatcher_CURRENT_EVENTS.length - 1 ];\r
if( !e || !e[ 'pointerType' ] ){\r
- alert( 'タッチイベント以外での play! ' + e.type );\r
+ alert( 'タッチイベント以外での play! ' + ( e ? e.type : '' ) );\r
return;\r
};\r
- this._touched = true;\r
- this._readyState = 2;\r
+ this._touchState = 3;\r
} else\r
- if( !this._ready && ( !X_HTMLAudio_durationFix || !X_HTMLAudio_need1stTouch ) ){ // this._readyState < 2\r
+ if( this._readyState !== 3 && this._durationFixPhase < 2 ){\r
this.autoplay = true;\r
return;\r
};\r
-\r
- if( X_HTMLAudio_durationFix && X_HTMLAudio_need1stTouch && this._durationFixPhase === 1 ){\r
- console.log( '▲ DurationFix の開始(タッチ用)' );\r
- this._durationFixPhase = 2;\r
+ \r
+ if( this._durationFixPhase & 3 ){ // 1 or 2\r
+ console.log( '▲ DurationFix の開始' );\r
+ this._durationFixPhase = 4;\r
};\r
\r
end = X_Audio_getEndTime( this );\r
};\r
};\r
\r
- if( this._durationFixSkip || this._endedFixON ){\r
+ if( this._endedFixON ){\r
console.log( '☆ audio.play をスキップ ' + begin + ' -> ' + end + ' crt:' + ( raw.currentTime | 0 ) );\r
} else {\r
if( !this.playing ){\r
//また、GoogleChrome7 では currentTime = 0 直後に play() すると、pause()した位置前後の音が混ざることがある。(少なくとも自分の環境では)\r
\r
// iOS で duration が 0 の時に触ると error\r
- if( !X_HTMLAudio_durationFix || this.duration ) raw.currentTime = this._lastCurrentTime; // 2 < this._readyState\r
+ // 0 or 8\r
+ if( !( this._durationFixPhase % 8 ) && this.duration ) raw.currentTime = this._lastCurrentTime;\r
\r
console.log( '[HTMLAudio] play ' + begin + ' -> ' + end + ' crt:' + ( raw.currentTime | 0 ) + ' last:' + this._lastCurrentTime );\r
\r
raw.src = '';\r
if( X_HTMLAudio_durationFix ){\r
delete this._durationFixPhase;\r
- delete this._durationFixSkip;\r
};\r
};\r
delete this.playing;\r