OSDN Git Service

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