X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=0.6.x%2Fjs%2F07_audio%2F02_XHTMLAudio.js;h=b15b06475ad6e0c76f19b3750a2d069fefb15f4e;hb=7973f3ff61f1ef5bd9732f527b175010d0c0971b;hp=14aee23e5ba7b849425c85d43cacaac5d80aa066;hpb=42e0982b02a99c71702ce8cd8740645aefdc8097;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 14aee23..b15b064 100644 --- a/0.6.x/js/07_audio/02_XHTMLAudio.js +++ b/0.6.x/js/07_audio/02_XHTMLAudio.js @@ -6,12 +6,15 @@ var X_Audio_HTMLAudio_playTrigger = 6 <= X_UA[ 'iOS' ] ? 'loadeddata' : - X_UA[ 'iOS' ] ? 'suspend' : - X_UA[ 'AndroidBrowser2' ] ? 'stalled' : // Android 2.3.5(SBM101SH) では stalled は発生しない,,, + X_UA[ 'iOS' ] < 5 ? 'stalled' : + X_UA[ 'iOS' ] ? 'suspend' : + X_UA[ 'AndroidBrowser2' ] || X_UA[ 'AndroidBrowser3' ] ? 'stalled' : // Android 2.3.5(SBM101SH) では stalled は発生しない,,, X_UA[ 'AndroidBrowser4' ] ? 'loadeddata' : - X_UA[ 'OperaMobile' ] || X_UA[ 'OperaTablet' ] ? 'loadeddata' : 'canplay', + X_UA[ 'OperaMobile' ] || X_UA[ 'OperaTablet' ] ? 'loadeddata' : + //X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ? 'canplay' : + 'loadeddata', //'canplay', X_Audio_HTMLAudioWrapper, - X_Audio_constructor = window.Audio || window.HTMLAudioElement, + X_Audio_constructor = window[ 'Audio' ] || window.HTMLAudioElement, X_Audio_rawAudio, // Opera Mobile 12 android4.4.4 & 2.3.5 は 2回目以降の currentTime へのセットで currentTime が更新されなくなるため、タイマーを使用する X_Audio_HTMLAudioWrapper_currentTimeFix = !!X_UA[ 'OperaMobile' ] || !!X_UA[ 'OperaTablet' ], // || ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ), @@ -29,7 +32,7 @@ var X_Audio_HTMLAudio_playTrigger = X_Audio_HTMLAudioWrapper_ieMobile9Fix = ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ), X_Audio_HTMLAudioWrapper_durationFix = ( !X_Audio_HTMLAudioWrapper_currentTimeFix && 12 <= X_UA[ 'Opera' ] ), - X_Audio_HTMLAudioWrapper_shortPlayFix = !!X_UA[ 'AndroidBrowser4' ], + X_Audio_HTMLAudioWrapper_shortPlayFix = X_UA[ 'AndroidBrowser' ] && X_UA[ 'AndroidWebkit' ] <= 534.3, // Android 4.1.1 でも遭遇 X_Audio_codecs; @@ -38,16 +41,18 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ //引数なしで new Audio() とすると、Operaでエラーになるそうなので注意。 X_Audio_rawAudio = new X_Audio_constructor( '' ); + // https://html5experts.jp/miyuki-baba/3766/ + // Chrome for Android31 で HE-AAC が低速再生されるバグ if( X_Audio_rawAudio.canPlayType ){ X_Audio_codecs = { - mp3 : X_Audio_rawAudio.canPlayType('audio/mpeg'), - opus : X_Audio_rawAudio.canPlayType('audio/ogg; codecs="opus"'), - ogg : X_Audio_rawAudio.canPlayType('audio/ogg; codecs="vorbis"'), - wav : X_Audio_rawAudio.canPlayType('audio/wav; codecs="1"'), - aac : X_Audio_rawAudio.canPlayType('audio/aac'), - m4a : X_Audio_rawAudio.canPlayType('audio/x-m4a') + X_Audio_rawAudio.canPlayType('audio/m4a') + X_Audio_rawAudio.canPlayType('audio/aac'), - mp4 : X_Audio_rawAudio.canPlayType('audio/x-mp4') + X_Audio_rawAudio.canPlayType('audio/mp4') + X_Audio_rawAudio.canPlayType('audio/aac'), - weba : X_Audio_rawAudio.canPlayType('audio/webm; codecs="vorbis"') + 'mp3' : X_Audio_rawAudio.canPlayType('audio/mpeg'), + 'opus' : X_Audio_rawAudio.canPlayType('audio/ogg; codecs="opus"'), + 'ogg' : X_Audio_rawAudio.canPlayType('audio/ogg; codecs="vorbis"'), + 'wav' : X_Audio_rawAudio.canPlayType('audio/wav; codecs="1"'), + 'aac' : X_Audio_rawAudio.canPlayType('audio/aac'), + 'm4a' : X_Audio_rawAudio.canPlayType('audio/x-m4a') + X_Audio_rawAudio.canPlayType('audio/m4a') + X_Audio_rawAudio.canPlayType('audio/aac'), + 'mp4' : X_Audio_rawAudio.canPlayType('audio/x-mp4') + X_Audio_rawAudio.canPlayType('audio/mp4') + X_Audio_rawAudio.canPlayType('audio/aac'), + 'weba' : X_Audio_rawAudio.canPlayType('audio/webm; codecs="vorbis"') }; (function( k, v ){ for( k in X_Audio_codecs ){ @@ -60,37 +65,20 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ } else { // iOS3.2.3 X_Audio_codecs = { - mp3 : X_UA[ 'IE' ] || X_UA[ 'Chrome' ] || ( X_UA[ 'Windows' ] && X_UA[ 'Safari' ] ), - ogg : 5 <= X_UA[ 'Gecko' ] || X_UA[ 'Chrome' ] || X_UA[ 'Opera' ] , - wav : X_UA[ 'Gecko' ] || X_UA[ 'Opera' ] || ( X_UA[ 'Windows' ] && X_UA[ 'Safari' ] ), - aac : X_UA[ 'IE' ] || X_UA[ 'WebKit' ], - m4a : X_UA[ 'IE' ] || X_UA[ 'WebKit' ], - mp4 : X_UA[ 'IE' ] || X_UA[ 'WebKit' ], - weba : 2 <= X_UA[ 'Gecko' ] || 10.6 <= X_UA[ 'Opera' ] // firefox4+(Gecko2+) + 'mp3' : X_UA[ 'IE' ] || X_UA[ 'Chrome' ] || ( X_UA[ 'Windows' ] && X_UA[ 'Safari' ] ), + 'ogg' : 5 <= X_UA[ 'Gecko' ] || X_UA[ 'Chrome' ] || X_UA[ 'Opera' ] , + 'wav' : X_UA[ 'Gecko' ] || X_UA[ 'Opera' ] || ( X_UA[ 'Windows' ] && X_UA[ 'Safari' ] ), + 'aac' : X_UA[ 'IE' ] || X_UA[ 'WebKit' ], + 'm4a' : X_UA[ 'IE' ] || X_UA[ 'WebKit' ], + 'mp4' : X_UA[ 'IE' ] || X_UA[ 'WebKit' ], + 'weba' : 2 <= X_UA[ 'Gecko' ] || 10.6 <= X_UA[ 'Opera' ] // firefox4+(Gecko2+) }; }; - X_Audio_HTMLAudioWrapper = X_EventDispatcher[ 'inherits' ]( + X_Audio_HTMLAudioWrapper = X_Audio_AbstractAudioBackend[ 'inherits' ]( 'X.AV.HTML5AudioWrapper', - X.Class.POOL_OBJECT, + X_Class.POOL_OBJECT, { - - proxy : null, - - startTime : 0, - endTime : -1, - loopStartTime : -1, - loopEndTime : -1, - seekTime : -1, - duration : 0, - - playing : false, - error : 0, - loop : false, - looped : false, - autoplay : false, - volume : 0.5, - _playTime : 0, _closed : true, _loaded : false, @@ -99,26 +87,26 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ _lastCurrentTime : 0, _src : '', - Constructor : function( proxy, source, option ){ + Constructor : function( target, source, option ){ var raw; - this.proxy = proxy; + this.target = target || this; this._closed = false; - X_AudioWrapper_updateStates( this, option ); + this.setState( option ); if( option[ 'useVideo' ] ){ - this[ '_rawObject' ] = raw = document.createElement( 'video' ); + this[ '_rawObject' ] = raw = document.createElement( 'video' ); raw.preload = 'none'; // auto, metadata, none //raw.autoplay = false, // no-auto - raw.loop = false; - raw.muted = false; - //raw.crossorigin = option[ 'crossorigin' ] || ''; //crossorigin: "anonymous", X.URL.isSameDomain() で切り替え + raw.loop = false; + raw.muted = false; + raw.crossorigin = option[ 'crossorigin' ] || ''; //crossorigin: "anonymous", X.URL.isSameDomain() で切り替え raw.style.cssText = 'position:absolute;bottom:0;left:-50px;width:100px;height:100px;opacity:0;'; raw.controls = false; raw.WebKitPlaysInline = true; raw.src = source; - //raw.onclick = "alert('play');this.play();"; + //raw.onclick = "alert('play');this.actualPlay();"; document.body.appendChild( raw ); //raw.load(); } else { @@ -158,6 +146,17 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ switch( e.type ){ case X_EVENT_KILL_INSTANCE : + // 【javascript】モバイル向けブラウザでも音を鳴らしたい【WebAudio】 + // http://ingaouhou.com/archives/3633 + // ・使い終わったインスタンスはload()しておくとやや安定 + this.playing && this.actualPause(); + delete this._closed; + delete this._loaded; + + this[ '_rawObject' ].src = ''; + this[ '_rawObject' ].load(); + + // removeChild for video break; }; }, @@ -169,7 +168,7 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ X_Audio_HTMLAudioWrapper_badOperaAndroid && alert( e.type ); - console.log( e.type ); + X_Audio_HTMLAudioWrapper_ieMobile9Fix && e.type !== 'timeupdate' && console.log( e.type ); switch( e.type ){ case 'loadstart' : // ブラウザがコンテンツの検索を開始した場合に発生 @@ -229,11 +228,11 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ break; case 'ended' : - if( !this._closed && this.loop ){ - if( !( this.proxy[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_Callback_PREVENT_DEFAULT ) ){ + if( !this._closed && this.autoLoop ){ + if( !( this.target[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_Callback_PREVENT_DEFAULT ) ){ this.looped = true; - this.proxy[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED ); - this.play(); + this.target[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED ); + this.actualPlay(); }; return; }; @@ -249,11 +248,6 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ if( !this.duration && X_Type_isFinite( this[ '_rawObject' ].duration ) ){ this.duration = this.duration || this[ '_rawObject' ].duration * 1000; this._playForDuration = 2; - - //this.proxy[ 'asyncDispatch' ]( 'loadedmetadata' ); - //this.proxy[ 'asyncDispatch' ]( 'loadeddata' ); - //this.proxy[ 'asyncDispatch' ]( 'canplay' ); - //this.proxy[ 'asyncDispatch' ]( 'canplaythrough' ); loaded = true; //console.log( 'durationFix が完了' + this.duration ); break; @@ -263,8 +257,8 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ }; } else if( this[ '_rawObject' ].currentTime === this._lastCurrentTime ){ - //this.proxy[ 'dispatch' ]( 'seeking' ); - this.proxy[ 'dispatch' ]( X_EVENT_MEDIA_WAITING ); + //this.target[ 'dispatch' ]( 'seeking' ); + this.target[ 'dispatch' ]( X_EVENT_MEDIA_WAITING ); return; }; this._lastCurrentTime = this[ '_rawObject' ].currentTime; @@ -273,17 +267,18 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ if( this.playing ){ end = X_AudioWrapper_getEndTime( this ); - now = X_Audio_HTMLAudioWrapper_currentTimeFix ? X_Timer_now() - this._playTime + this._beginTime : this[ '_rawObject' ].currentTime * 1000 | 0; + now = this.getActualCurrentTime(); + console.log( end + ' / ' + now ); if( 0 + end <= 0 + now ){ // なぜか iem9 で必要,,, - if( this.loop ){ - if( !( this.proxy[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_Callback_PREVENT_DEFAULT ) ){ + if( this.autoLoop ){ + if( !( this.target[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_Callback_PREVENT_DEFAULT ) ){ this.looped = true; - this.proxy[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED ); - this.play(); + this.target[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED ); + this.actualPlay(); }; } else { - this.pause(); - this.proxy[ 'dispatch' ]( X_EVENT_MEDIA_ENDED ); + this.actualPause(); + this.target[ 'dispatch' ]( X_EVENT_MEDIA_ENDED ); }; return; }; @@ -317,14 +312,7 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ console.log( '設定 ' + this._beginTime ); return; }; - - /* - this.proxy[ 'asyncDispatch' ]( 'loadedmetadata' ); - this.proxy[ 'asyncDispatch' ]( 'loadeddata' ); - this.proxy[ 'asyncDispatch' ]( 'canplay' ); - this.proxy[ 'asyncDispatch' ]( 'canplaythrough' ); */ - - + loaded = true; console.log( 'durationFix が完了' + this.duration ); @@ -347,36 +335,27 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ if( !this._loaded && ( loaded || e.type === X_Audio_HTMLAudio_playTrigger || e.type === 'loadeddata' ) ){ this.autoplay && X_Timer_once( 16, this, this.play ); this._loaded = true; - this.proxy[ 'dispatch' ]( X_EVENT_READY ); + this.target[ 'asyncDispatch' ]( X_EVENT_READY ); console.log( 'Loaded! ' + e.type + ' d:' + ( this.duration | 0 ) ); return; }; - loaded || ( type && this.proxy[ 'dispatch' ]( type ) ); - }, - - close : function(){ - // 【javascript】モバイル向けブラウザでも音を鳴らしたい【WebAudio】 - // http://ingaouhou.com/archives/3633 - // ・使い終わったインスタンスはload()しておくとやや安定 - this.playing && this.pause(); - delete this._closed; - delete this._loaded; - - this[ '_rawObject' ].src = ''; - this[ '_rawObject' ].load(); + if( !loaded && type ){ + this.target[ 'dispatch' ]( type ); + type === X_EVENT_ERROR && this[ 'kill' ](); + }; }, - - play : function(){ + + actualPlay : function(){ var begin, end; // もし kill 後に autoplayTimer で呼ばれても、_closed==true なので平気 if( this._closed ) return; - if( !this._loaded /* && !X_Audio_Sprite_inTouchAction */ ){ + if( !this._loaded && !X_Audio_HTMLAudioWrapper_ieMobile9Fix /* && !X_Audio_Sprite_inTouchAction */ ){ this.autoplay = true; return; }; - + if( X_Audio_HTMLAudioWrapper_ieMobile9Fix && this._playForDuration === 0 ){ console.log( 'DurationFix開始 - ' + this[ '_rawObject' ].duration ); this._playForDuration = 1; @@ -396,14 +375,13 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ delete this._playForDuration; }; - if( !this.playing ){ if( X_UA[ 'Chrome' ] ){ // [CHROME][FIX] volume TODO どの version で 修正される? // [!] delay X_Timer_once( 0, this, this._fixForChrome ); this[ '_rawObject' ].volume = 0; } else { - this[ '_rawObject' ].volume = this.volume; + this[ '_rawObject' ].volume = X_Audio_HTMLAudioWrapper_ieMobile9Fix ? 1 : this.gain; }; this[ '_rawObject' ].play(); this.playing = true; @@ -424,13 +402,13 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ // [CHROME][FIX] volume _fixForChrome : X_UA[ 'Chrome' ] && function(){ - !this._closed && ( this[ '_rawObject' ].volume = this.volume ); + !this._closed && ( this[ '_rawObject' ].volume = this.gain ); }, - pause : function(){ + actualPause : function(){ if( !this.playing ) return; - this.seekTime = this.state().currentTime; + this.seekTime = this.getActualCurrentTime(); delete this._playTime; @@ -442,55 +420,30 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ }; delete this.playing; }, - - state : function( obj ){ - var result; - - if( obj === undefined ){ - return { - startTime : this.startTime, - 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.playing ? - ( X_Audio_HTMLAudioWrapper_currentTimeFix ? + + getActualCurrentTime : function(){ + return ( X_Audio_HTMLAudioWrapper_currentTimeFix ? X_Timer_now() - this._playTime + this._beginTime : - this[ '_rawObject' ].currentTime * 1000 | 0 ) : - this.seekTime, - /* - http://www.w3schools.com/tags/av_prop_error.asp - 1 = MEDIA_ERR_ABORTED - fetching process aborted by user - 2 = MEDIA_ERR_NETWORK - error occurred when downloading - 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 - }; - }; + this[ '_rawObject' ].currentTime * 1000 | 0 ); + }, + /* + http://www.w3schools.com/tags/av_prop_error.asp + 1 = MEDIA_ERR_ABORTED - fetching process aborted by user + 2 = MEDIA_ERR_NETWORK - error occurred when downloading + 3 = MEDIA_ERR_DECODE - error occurred when decoding + 4 = MEDIA_ERR_SRC_NOT_SUPPORTED - audio/video not supported + */ + getActualError : function(){ + return this[ '_rawObject' ].error || 0; + }, - result = X_AudioWrapper_updateStates( this, obj ); - - if( result & 2 ){ // seek - this.play(); - //} else - //if( result & 1 ){ - //if( X_Audio_HTMLAudioWrapper_currentTimeFix ){ - // this.play(); - //}; - + afterUpdateState : function( result ){ + if( result & 3 ){ // seek + this.actualPlay(); } else if( result & 4 ){ - this[ '_rawObject' ].volume = this.volume; - }; - + this[ '_rawObject' ].volume = X_Audio_HTMLAudioWrapper_ieMobile9Fix ? 1 : this.gain; + }; } } @@ -499,6 +452,8 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ X_Audio_BACKENDS.push( { backendName : 'HTML Audio', + + canPlay : X_Audio_codecs, /* * HTML5 の audio 要素と video 要素でサポートされているメディアフォーマット * https://developer.mozilla.org/ja/docs/Web/HTML/Supported_media_formats