X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=0.6.x%2Fjs%2F07_audio%2F02_XHTMLAudio.js;h=61f3ddde743b272164944c326d9ed4267a6a876c;hb=527f50d3e1930a335a6525b5c973ab27fe385868;hp=154e4ac0be7b89e7990cc0121a50ff9d6573d4ad;hpb=34431df46635079c1ce6626c9caf1456f88e91bd;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 154e4ac..61f3ddd 100644 --- a/0.6.x/js/07_audio/02_XHTMLAudio.js +++ b/0.6.x/js/07_audio/02_XHTMLAudio.js @@ -15,17 +15,36 @@ * 8. BlinkOpera32 Win8 は HTMLAudio が壊れている、WebAudio は mp3 がデコードに失敗、ogg が動作 * * memo - * 1. Android4.1 iframe 内の Audio は親に focus が移っても再生を継続する + * 1. AOSP4.1 iframe 内の Audio は親に focus が移っても再生を継続する + * 2. AOSP4.2(Genymotion) どこかのタイミングでタッチによる play を行う + * 3. AOSP oggはシークが乱れる m4a, mp3 は優秀 */ + /* + * durationFix + * duration が取得できるタイミングが遅くそれまでは infinity(PC Opera12), NaN(WP9), 0(Android 標準ブラウザ ChromeWebView) が入っている + * + * 1. touch が不要の場合、自動で再生を開始して duration を取得するまで再生する + * -> 取得後に pause or 通常再生 + * 2. touch が必要な場合、タッチイベント内の audio.play() で duration 取得 + * + * PC Opera12 + * 1. loadeddata 等では duration が infinity で、再生後の durationchange 時に duration が判明する + * 2. duration 判明後には currentTime によるシークと、現在時間の取得が可能になる。 + * 3. Opera12.17 Win32(XP) portable apps は勝手に再生が始まる、、、Win8+Opera では発生しない + * -> その際には timeupdate が発行されない、、、 iframe+image+audio で使わないときは破棄する、とか。 + * -> opera11、10.54 WinXP はまとも、、、 portable が怪しい?? + */ var X_HTMLAudio_playTrigger = - 6 <= X_UA[ 'iOS' ] ? 'loadeddata' : - X_UA[ 'iOS' ] < 5 ? 'stalled' : - X_UA[ 'iOS' ] ? 'suspend' : + X_UA[ 'iOS' ] < 5 ? 'stalled' : + X_UA[ 'iOS' ] < 6 ? 'suspend' : + X_UA[ 'iOS' ] < 7 ? 'suspend' : + X_UA[ 'iOS' ] ? 'loadeddata' : X_UA[ 'Safari' ] < 4 ? 'canplaythrough' : X_UA[ 'ChromeWV' ] ? 'canplaythrough' : // Android 2.3.5(SBM101SH) では stalled は発生しない,,, ので必ず loadeddata もチェックする - X_UA[ 'AOSP' ] ? 'stalled' : + //X_UA[ 'AOSP' ] < 3 ? 'stalled' : + //X_UA[ 'AOSP' ] ? 'playing' : X_UA[ 'OperaMobile' ] || X_UA[ 'OperaTablet' ] ? 'loadeddata' : 'loadeddata', //'canplay', X_HTMLAudio, @@ -37,7 +56,9 @@ var X_HTMLAudio_playTrigger = // Android 3.1 で ended 時に src='';src=src を実施。 X_HTMLAudio_endedFixAOSP3 = !X_HTMLAudio_endedFixAOSP2 && X_UA[ 'AOSP' ] < 4, // ended 時に play() を実施, currentTime が duration に張り付き更新されなければ src='';src=src を実施。 - X_HTMLAudio_endedFixAOSP4 = 4 <= X_UA[ 'AOSP' ] || X_UA[ 'ChromeWV' ], + X_HTMLAudio_endedFixAOSP4 = 4 <= X_UA[ 'AOSP' ], + // ended 時に play() を実施 + X_HTMLAudio_endedFixCWV = X_UA[ 'ChromeWV' ], // Opera Mobile 12 は 2回目以降の currentTime へのセットで currentTime が更新されなくなるため、タイマーを使用する X_HTMLAudio_currentTimeFix = !!X_UA[ 'OperaMobile' ] || !!X_UA[ 'OperaTablet' ], @@ -51,25 +72,11 @@ var X_HTMLAudio_playTrigger = X_HTMLAudio_needPlayForSeek = X_UA[ 'Gecko' ], // X_HTMLAudio_pauseFix = ( X_UA[ 'Windows' ] && 12 <= X_UA[ 'Opera' ] && 0 < ' XP XPSP2 2003|XP64'.indexOf( X_UA[ 'Windows' ] ) ), // XP + Opera12 のみ? - /* - * durationFix - * duration が取得できるタイミングが遅くそれまでは infinity(PC Opera12), NaN(WP9), 0(Android 標準ブラウザ ChromeWebView) が入っている - * - * 1. touch が不要の場合、自動で再生を開始して duration を取得するまで再生する - * -> 取得後に pause or 通常再生 - * 2. touch が必要な場合、タッチイベント内の audio.play() で duration 取得 - * - * PC Opera12 - * 1. loadeddata 等では duration が infinity で、再生後の durationchange 時に duration が判明する - * 2. duration 判明後には currentTime によるシークと、現在時間の取得が可能になる。 - * 3. Opera12.17 Win32(XP) portable apps は勝手に再生が始まる、、、Win8+Opera では発生しない - * -> その際には timeupdate が発行されない、、、 iframe+image+audio で使わないときは破棄する、とか。 - * -> opera11、10.54 WinXP はまとも、、、 portable が怪しい?? - */ - X_HTMLAudio_need1stTouch = X_UA[ 'iOS' ] || X_UA[ 'ChromeWV' ] || ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ), - X_HTMLAudio_durationFix = ( X_UA[ 'Windows' ] && 12 <= X_UA[ 'Opera' ] ) || X_UA[ 'ChromeWV' ] || ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ), + + X_HTMLAudio_need1stTouch = X_UA[ 'iOS' ] || 4 <= X_UA[ 'AOSP' ] || X_UA[ 'ChromeWV' ] || X_UA[ 'WinPhone' ], + X_HTMLAudio_durationFix = X_UA[ 'iOS' ] || X_UA[ 'ChromeWV' ] || ( X_UA[ 'Windows' ] && 12 <= X_UA[ 'Opera' ] ) || ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ), - X_HTMLAudio_shortPlayFix = X_UA[ 'AOSP' ]; // Android 4.1.1 でも遭遇(ただしm4a, mp3は優秀, oggはシークが乱れる) + X_HTMLAudio_shortPlayFix = X_UA[ 'AOSP' ]; // Android 4.1.1 でも遭遇 @@ -88,7 +95,7 @@ if( X_Audio_constructor ){ _currentFixBegin : 0, _durationFixPhase : X_HTMLAudio_durationFix ? 1 : 0, - _durationFixSkip : X_HTMLAudio_durationFix && !X_HTMLAudio_need1stTouch, + _durationFixSkip : X_HTMLAudio_durationFix && !X_HTMLAudio_need1stTouch, _lastCurrentTime : 0, _shortPlayFixON : false, @@ -96,9 +103,6 @@ if( X_Audio_constructor ){ _endedFixON : false, - _kickTimerID : false, // 処理が混み入ると AOSP で音声が再生されない - _lastKickTime : 0, - 'Constructor' : function( disatcher, source, option ){ var raw; @@ -143,13 +147,31 @@ if( X_Audio_constructor ){ 'playing', 'waiting', 'seeking', 'durationchange', 'timeupdate', 'ended' ] ); + + this[ 'listen' ]( [ + 'loadstart', 'load', + 'progress', 'error', + 'suspend', 'abort', 'emptied', 'stalled', + 'play', 'pause', 'seeked', 'ratechange', 'volumechange', + 'loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough', + 'playing', 'waiting', 'seeking', + 'durationchange', 'timeupdate', 'ended' ], this.onDebug ); + if( X_TEMP.rawAudio ){ raw.src = source; - raw.load(); // AOSP2 で必要 + X_UA[ 'AOSP' ] < 3 && raw.load(); delete X_TEMP.rawAudio; }; }, + onDebug : function( e ){ + this.disatcher[ 'dispatch' ]( { + type : X_EVENT_DEBUG, + 'rawEvent' : e.type, + current : this.getActualCurrentTime() | 0, + duration : this.duration | 0 } ); + }, + handleEvent : function( e ){ var raw = this[ '_rawObject' ], actualEnded = e.type === 'ended', @@ -216,10 +238,10 @@ if( X_Audio_constructor ){ if( this._durationFixPhase & 3 ){ // 1 or 2 duration = raw.duration; } else - if( raw.currentTime === this._lastCurrentTime ){ + if( this.getActualCurrentTime() === this._lastCurrentTime ){ eventType = X_EVENT_MEDIA_WAITING; } else { - this._lastCurrentTime = raw.currentTime; + this._lastCurrentTime = this.getActualCurrentTime(); if( this.playing ){ end = X_Audio_getEndTime( this ) + this._shortPlayFixTime; @@ -258,8 +280,8 @@ if( X_Audio_constructor ){ if( X_HTMLAudio_volumeFix ){ raw.volume = this.gain; }; - if( X_HTMLAudio_currentTimeFix ){ - this._currentFixStart = X_Timer_now(); // 正確な再生開始時間に補正 + if( X_HTMLAudio_currentTimeFix && !this._currentFixStart ){ + //this._currentFixStart = X_Timer_now(); // 正確な再生開始時間に補正 }; eventType = !this._durationFixSkip && !this._endedFixON ? X_EVENT_MEDIA_PLAYING : X_EVENT_MEDIA_WAITING; //case 'play' : // 再生が開始された。play()メソッドからの復帰後に発生する場合に発生 @@ -312,9 +334,9 @@ if( X_Audio_constructor ){ if( !( this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){ this.looped = true; this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED ); - ( X_HTMLAudio_endedFixAOSP3 || X_HTMLAudio_endedFixAOSP4 || X_HTMLAudio_endedFixIOS ) && actualEnded && console.log( '☆★☆ 音声の継続用の play() @ended' ); + ( X_HTMLAudio_endedFixAOSP3 || X_HTMLAudio_endedFixAOSP4 || X_HTMLAudio_endedFixCWV || X_HTMLAudio_endedFixIOS ) && actualEnded && console.log( '☆★☆ 音声の継続用の play() @ended' ); this.actualPlay( - ( X_HTMLAudio_endedFixAOSP4 || X_HTMLAudio_endedFixIOS ) && actualEnded, + ( X_HTMLAudio_endedFixAOSP4 || X_HTMLAudio_endedFixCWV || X_HTMLAudio_endedFixIOS ) && actualEnded, ( X_HTMLAudio_endedFixAOSP3 || X_HTMLAudio_endedFixAOSP2 ) && actualEnded ); }; } else { @@ -325,8 +347,8 @@ if( X_Audio_constructor ){ } else if( this._loaded && this.duration && !this._ready ){ this._ready = true; - this.autoplay && X_Timer_once( 16, this, this.play ); this.disatcher[ 'asyncDispatch' ]( X_EVENT_READY ); + this.autoplay && !X_WebAudio_need1stTouch && X_Timer_once( 16, this, this.play ); console.log( '> Audio Loaded!! ' + e.type + ' d:' + ( this.duration | 0 ) ); } else if( eventType ){ @@ -382,10 +404,6 @@ if( X_Audio_constructor ){ }; raw.play(); this.playing = true; - - if( X_UA[ 'AOSP' ] && !this._kickTimerID ){ - this._kickTimerID = X_Timer_add( 100, 0, this, this._kick ); - }; } else if( X_HTMLAudio_needPlayForSeek || forcePlay ){ raw.play(); @@ -395,10 +413,9 @@ if( X_Audio_constructor ){ //http://himaxoff.blog111.fc2.com/blog-entry-97.html //Firefox3.6では一度も play() していない状態で currentTime = 0 を実行するとエラーになる。 //また、GoogleChrome7 では currentTime = 0 直後に play() すると、pause()した位置前後の音が混ざることがある。(少なくとも自分の環境では) - raw.currentTime = this._lastKickTime = this._lastCurrentTime; + raw.currentTime = this._lastCurrentTime; console.log( '[HTMLAudio] play ' + begin + ' -> ' + end + ' crt:' + ( raw.currentTime | 0 ) + ' last:' + this._lastCurrentTime ); - - // Android4.0.5 で ended イベント時に currentTime が duration に張り付いたまま変更できない + if( forceReload || ( X_HTMLAudio_endedFixAOSP4 && raw.duration && raw.currentTime === raw.duration ) ){ raw.src = ''; raw.src = this._src; @@ -408,7 +425,7 @@ if( X_Audio_constructor ){ raw.currentTime = this._lastCurrentTime; this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING ); X_HTMLAudio_endedFixAOSP2 && raw.load(); - }; + }; }; if( X_HTMLAudio_currentTimeFix ){ @@ -417,20 +434,6 @@ if( X_Audio_constructor ){ }; }, - _kick : function(){ - var raw = this[ '_rawObject' ]; - - console.log( ' >> KICK ? ct:' + ( raw.currentTime ) + ' lkt:' + this._lastKickTime ); - if( this.playing && raw.currentTime === this._lastKickTime ){ - this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING ); - console.log( ' >> KICK !!' ); - raw.play(); - } else { - delete this._kickTimerID; - return X_CALLBACK_UN_LISTEN; - }; - }, - actualPause : function(){ console.log( '[HTMLAudio] pause' );