X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=0.6.x%2Fjs%2F07_audio%2F02_XHTMLAudio.js;h=6b7793791c1638bda681426a2009d58257c4c73d;hb=78f2b6b1bb07448d1c314775bf28a41b7111e386;hp=c88e51466ce728ebd9fcae422a73219ae67e86b4;hpb=94c39d10a21853703c90cb09b1e82bd7a2d8923e;p=pettanr%2FclientJs.git diff --git a/0.6.x/js/07_audio/02_XHTMLAudio.js b/0.6.x/js/07_audio/02_XHTMLAudio.js index c88e514..6b77937 100644 --- a/0.6.x/js/07_audio/02_XHTMLAudio.js +++ b/0.6.x/js/07_audio/02_XHTMLAudio.js @@ -4,105 +4,10 @@ * https://code.google.com/p/uupaa-js/source/browse/trunk/0.8/src/Audio/HTML5Audio.js?r=568 */ -var X_Audio_HTML5Audio, X_Audio_HTML5AudioWrapper, X_Audio_rawAudio, - X_Audio_HTML5Audio_LIVE_LIST = [], - X_Audio_HTML5Audio_POOL_LIST = []; +var X_Audio_HTML5AudioWrapper, X_Audio_rawAudio; if( window.HTMLAudioElement ){ - function getHTML5AudioWrapper( proxy ){ - var i = X_Audio_HTML5Audio_LIVE_LIST.length; - for( ; i; ){ - if( X_Audio_HTML5Audio_LIVE_LIST[ --i ].proxy === proxy ) return X_Audio_HTML5Audio_LIVE_LIST[ i ]; - }; - }; - - X_Audio_HTML5Audio = - { - backendName : 'HTML5 Audio', - /* - * HTML5 の audio 要素と video 要素でサポートされているメディアフォーマット - * https://developer.mozilla.org/ja/docs/Web/HTML/Supported_media_formats - * - * 主要ブラウザのHTML5 audioタグで使えるファイル形式の再生対応状況を調べてみた - * http://sothis.blog.so-net.ne.jp/2010-10-27 - * ダメ元で仕様に含まれていない SHOUTcast もテストしてみました。 - * - * IE9 の HTML5 Audio について - * http://kentablog.cluscore.com/2011/05/ie9-html5-audio.html - * 1.Audioオブジェクトを作ることができないので、Audioタグを使う - * 2.クロスドメインアクセスには、「clientaccesspolicy.xml」か「crossdomain.xml」が必要 - * 3.wav が不可 - * - * IE9でHTML5 autio タグが無効になる - * http://bbs.wankuma.com/index.cgi?mode=al2&namber=64886&KLOG=109 - * IEのバージョン9.0.8112.16421では、Audioオブジェクトのnewも対応してました。 - * createElement等で動的生成すると、よろしくない - * - * media-can-play-wav-audio.html - * https://github.com/adobe/webkit/blob/master/LayoutTests/media/media-can-play-wav-audio.html - * testExpected("audio.canPlayType('audio/wav; codecs=1')", "probably"); - * - * HTML5 audioタグ ブラウザ間の違い - * http://wiki.bit-hive.com/tomizoo/pg/HTML5%20audio%A5%BF%A5%B0%20%A5%D6%A5%E9%A5%A6%A5%B6%B4%D6%A4%CE%B0%E3%A4%A4 - * - volume, muted iPhone(iOS4-6)、Android(2.3.6)では動作せず。 - * - FireFox3.6, Android 2.3.6については、src変更後、load()を呼び出さないと切り替わらなかった。iPhoneはload()が不要。 - */ - detect : function( proxy, source, ext ){ - var ok, mineType = 'audio/' + ext; - switch( ext ){ - case 'mp3' : - ok = X_UA.IE || X_UA.Chrome || ( X_UA.Windows && X_UA.Safari ); - mineType = 'audio/mpeg'; - break; - case 'ogg' : - ok = 15 <= X_UA.Gecko || X_UA.Chrome || X_UA.Opera; - break; - case 'm4a' : - ok = X_UA.IE || X_UA.WebKit; - mineType = 'audio/mp4'; - break; - case 'webm' : - ok = 2 <= X_UA.Gecko || 10.6 <= X_UA.Opera; // firefox4+(Gecko2+) - break; - case 'wav' : - ok = X_UA.Gecko || X_UA.Opera || ( X_UA.Windows && X_UA.Safari ); - //mineType = 'audio/wav'; // audio/x-wav ? - break; - default : - mineType = ''; - }; - - if( !ok && mineType ){ - if( !X_Audio_rawAudio ) X_Audio_rawAudio = new Audio; - ok = X_Audio_rawAudio.canPlayType( mineType ); - }; - - proxy.asyncDispatch( ok ? 'support' : 'nosupport' ); - }, - - register : function( proxy, source, option ){ - X_Audio_HTML5Audio_LIVE_LIST.push( new X_Audio_HTML5AudioWrapper( proxy, source, option ) ); - }, - - close : function( proxy ){ - getHTML5AudioWrapper( proxy ).close(); - }, - - play : function( proxy ){ - getHTML5AudioWrapper( proxy ).play(); - }, - - pause : function( proxy ){ - getHTML5AudioWrapper( proxy ).pause(); - }, - - state : function( proxy, obj ){ - return getHTML5AudioWrapper( proxy ).state( obj ); - } - }; - - X_Audio_BACKENDS.push( X_Audio_HTML5Audio ); X_Audio_HTML5AudioWrapper = X.EventDispatcher.inherits( 'X.AV.HTML5AudioWrapper', @@ -112,14 +17,16 @@ if( window.HTMLAudioElement ){ proxy : null, startTime : 0, - endTime : 1 / 0, - loopStartTime : 0, - seekTime : 0, - duration : 1 / 0, + endTime : -1, + loopStartTime : -1, + loopEndTime : -1, + seekTime : -1, + duration : 0, playing : false, error : 0, loop : false, + looped : false, volume : 0.5, _timerID : 0, @@ -132,6 +39,7 @@ if( window.HTMLAudioElement ){ X_AudioWrapper_updateStates( this, option ); + // TODO use video document.createElement('video') this._rawObject = X_Audio_rawAudio || new Audio( source );// X_Doc_create( 'audio', { src : source } ).appendToRoot();//( X.X_Node_systemNode ); this.listen( [ @@ -139,7 +47,7 @@ if( window.HTMLAudioElement ){ 'loadeddata', 'waiting', 'playing', 'canplay', 'canplaythrough', 'seeking', 'seeked', 'timeupdate', 'ended', 'ratechange', 'durationchange', 'volumechange' ], this.handleEventProxy ); - if( X_Audio_rawAudio ){ + if( X_Audio_rawAudio === this._rawObject ){ X_Audio_rawAudio.src = source; X_Audio_rawAudio.load(); // 要る? X_Audio_rawAudio = null; @@ -178,7 +86,6 @@ if( window.HTMLAudioElement ){ case 'canplay' : // 今すぐに再生を再開できるが、バッファリングが不十分でコンテンツを最後まで表示できないと予測している場合に発生 case 'canplaythrough' : // 今すぐに再生を開始してもバッファリングで停止することなく最後まで表示できると予測している場合に発生 this.duration = this._rawObject.duration * 1000; - this.endTime = this.duration < this.endTime ? this.duration : this.endTime; //console.log( this.duration ); break; @@ -200,7 +107,9 @@ if( window.HTMLAudioElement ){ case 'ended' : if( !this._closed && this.loop ){ + this.looped = true; this.play(); + this.proxy.dispatch( 'looped' ); } else { this._timerID && X.Timer.remove( this._timerID ); delete this._timerID; @@ -228,14 +137,17 @@ if( window.HTMLAudioElement ){ this._rawObject.load(); }, - play : function( seekTime ){ - var begin, halfway; + play : function(){ + var begin, end, halfway; // もし kill 後に autoplayTimer で呼ばれても、_closed==true なので平気 if( this._closed ) return; - begin = ( seekTime || seekTime === 0 ) ? seekTime : this.playing ? this.loopStartTime : this.startTime; - this._rawObject.currentTime = begin / 1000; + end = X_AudioWrapper_getEndTime( this ); + begin = X_AudioWrapper_getStartTime( this, end, true ); + this._rawObject.currentTime = begin / 1000; + + console.log( '[HTMLAudio] play ' + begin + ' -> ' + end ); if( !this.playing ){ if( X_UA.Chrome ){ // [CHROME][FIX] volume TODO どの version で 修正される? @@ -249,40 +161,39 @@ if( window.HTMLAudioElement ){ this.playing = true; }; - halfway = this.endTime < this.duration; + halfway = end < this.duration; this._timerID && X.Timer.remove( this._timerID ); if( halfway ){ - this._timerID = X.Timer.once( this.endTime - begin, this, this._onEnded ); + this._timerID = X.Timer.once( end - begin, this, this._onEnded ); } else { delete this._timerID; }; - - if( !this._interval ){ - this._interval = X.Timer.add( 1000, 0, this, this._onInterval ); - }; }, // [CHROME][FIX] volume _fixForChrome : X_UA.Chrome && function(){ !this._closed && ( this._rawObject.volume = this.volume ); }, - - _onInterval : function(){ - if( !this.playing ){ - delete this._interval; - return X_Callback_UN_LISTEN; - }; - this.proxy.dispatch( 'timeupdate' ); - }, _onEnded : function(){ + var time; delete this._timerID; + if( this.playing ){ + + time = this._rawObject.currentTime * 1000 - X_AudioWrapper_getEndTime( this ) | 0; + if( time < -16 ){ + console.log( '> onEnd ' + time + ' ' + ( this._rawObject.currentTime * 1000 | 0 ) + '/' + X_AudioWrapper_getEndTime( this ) ); + this._timerID = X.Timer.once( -time, this, this._onEnded ); + return; + }; + if( this.loop ){ + this.looped = true; this.play(); + this.proxy.dispatch( 'looped' ); } else { - console.log( '中断:' + this._rawObject.currentTime + ' ' + this.endTime ); this.pause(); this.dispatch( 'ended' ); }; @@ -293,8 +204,8 @@ if( window.HTMLAudioElement ){ this._timerID && X.Timer.remove( this._timerID ); delete this._timerID; - if( this.palying && !this._rawObject.error ){ - this._rawObject.pause(); + if( this.playing ){ + !this._rawObject.error && this._rawObject.pause(); delete this.playing; }; }, @@ -305,11 +216,17 @@ if( window.HTMLAudioElement ){ if( obj === undefined ){ return { startTime : this.startTime, - endTime : this.endTime, - loopStartTime : this.loopStartTime, - currentTime : this._rawObject.currentTime * 1000, + endTime : this.endTime < 0 ? this.duration : this.endTime, + loopStartTime : this.loopStartTime < 0 ? this.startTime : this.loopStartTime, + loopEndTime : this.loopEndTime < 0 ? ( this.endTime || this.duration ) : this.loopEndTime, + loop : this.loop, + looped : this.looped, volume : this.volume, + playing : this.playing, // && !this._rawObject.error && !this._rawObject.paused && !this._rawObject.ended, + duration : this.duration, + + currentTime : this._rawObject.currentTime * 1000, /* http://www.w3schools.com/tags/av_prop_error.asp 1 = MEDIA_ERR_ABORTED - fetching process aborted by user @@ -317,24 +234,22 @@ if( window.HTMLAudioElement ){ 3 = MEDIA_ERR_DECODE - error occurred when decoding 4 = MEDIA_ERR_SRC_NOT_SUPPORTED - audio/video not supported */ - error : this._rawObject.error || 0, // 0, 1 ~ 4 - playing : this.palying && !this._rawObject.error && !this._rawObject.paused && !this._rawObject.ended, - duration : this.duration || 0 + error : this._rawObject.error || 0 // 0, 1 ~ 4 }; }; result = X_AudioWrapper_updateStates( this, obj ); if( result & 2 ){ // seek - this.play( this.seekTime ); - delete this.seekTime; + this.play(); } else { if( result & 1 ){ - halfway = this.endTime < this.duration; + end = X_AudioWrapper_getEndTime( this ); + halfway = end < this.duration; this._timerID && X.Timer.remove( this._timerID ); if( halfway ){ - this._timerID = X.Timer.once( this.endTime - this._rawObject.currentTime * 1000, this, this._onEnded ); + this._timerID = X.Timer.once( end - this._rawObject.currentTime * 1000, this, this._onEnded ); } else { delete this._timerID; }; @@ -349,6 +264,89 @@ if( window.HTMLAudioElement ){ } ); + X_Audio_BACKENDS.push( + { + backendName : 'HTML5 Audio', + /* + * HTML5 の audio 要素と video 要素でサポートされているメディアフォーマット + * https://developer.mozilla.org/ja/docs/Web/HTML/Supported_media_formats + * + * 主要ブラウザのHTML5 audioタグで使えるファイル形式の再生対応状況を調べてみた + * http://sothis.blog.so-net.ne.jp/2010-10-27 + * ダメ元で仕様に含まれていない SHOUTcast もテストしてみました。 + * + * IE9 の HTML5 Audio について + * http://kentablog.cluscore.com/2011/05/ie9-html5-audio.html + * 1.Audioオブジェクトを作ることができないので、Audioタグを使う + * 2.クロスドメインアクセスには、「clientaccesspolicy.xml」か「crossdomain.xml」が必要 + * 3.wav が不可 + * + * IE9でHTML5 autio タグが無効になる + * http://bbs.wankuma.com/index.cgi?mode=al2&namber=64886&KLOG=109 + * IEのバージョン9.0.8112.16421では、Audioオブジェクトのnewも対応してました。 + * createElement等で動的生成すると、よろしくない + * + * media-can-play-wav-audio.html + * https://github.com/adobe/webkit/blob/master/LayoutTests/media/media-can-play-wav-audio.html + * testExpected("audio.canPlayType('audio/wav; codecs=1')", "probably"); + * + * HTML5 audioタグ ブラウザ間の違い + * http://wiki.bit-hive.com/tomizoo/pg/HTML5%20audio%A5%BF%A5%B0%20%A5%D6%A5%E9%A5%A6%A5%B6%B4%D6%A4%CE%B0%E3%A4%A4 + * - volume, muted iPhone(iOS4-6)、Android(2.3.6)では動作せず。 + * - FireFox3.6, Android 2.3.6については、src変更後、load()を呼び出さないと切り替わらなかった。iPhoneはload()が不要。 + */ + detect : function( proxy, source, ext ){ + var ok, mineType = 'audio/' + ext; + switch( ext ){ + case 'mp3' : + ok = X_UA.IE || X_UA.Chrome || ( X_UA.Windows && X_UA.Safari ); + mineType = 'audio/mpeg'; + break; + case 'ogg' : + ok = 15 <= X_UA.Gecko || X_UA.Chrome || X_UA.Opera; + break; + case 'm4a' : + ok = X_UA.IE || X_UA.WebKit; + mineType = 'audio/mp4'; + break; + case 'webm' : + ok = 2 <= X_UA.Gecko || 10.6 <= X_UA.Opera; // firefox4+(Gecko2+) + break; + case 'wav' : + ok = X_UA.Gecko || X_UA.Opera || ( X_UA.Windows && X_UA.Safari ); + //mineType = 'audio/wav'; // audio/x-wav ? + break; + default : + mineType = ''; + }; + + if( !ok && mineType ){ + if( !X_Audio_rawAudio ) X_Audio_rawAudio = new Audio; + ok = X_Audio_rawAudio.canPlayType( mineType ); + }; + + proxy.asyncDispatch( ok ? 'support' : 'nosupport' ); + }, + + klass : X_Audio_HTML5AudioWrapper + + } ); + +/* + * + * howler.js + * codecs = { + mp3: !!audioTest.canPlayType('audio/mpeg;').replace(/^no$/, ''), + opus: !!audioTest.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/, ''), + ogg: !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ''), + wav: !!audioTest.canPlayType('audio/wav; codecs="1"').replace(/^no$/, ''), + aac: !!audioTest.canPlayType('audio/aac;').replace(/^no$/, ''), + m4a: !!(audioTest.canPlayType('audio/x-m4a;') || audioTest.canPlayType('audio/m4a;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''), + mp4: !!(audioTest.canPlayType('audio/x-mp4;') || audioTest.canPlayType('audio/mp4;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''), + weba: !!audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, '') + }; + */ + };