2015-10-11 127 views
0

我最初注意到與timeupdate事件只在Firefox上出現的這個問題,但發現它適用於其它事件偵聽器,以及(到目前爲止我已經看到它在canplay音頻事件監聽器入門稱爲非停止

基本上,我有一個在角度指令內創建的元素;我綁定功能ontimeupdate,甚至當currentTime的值是0

代碼小結該事件被炒魷魚馬不停蹄:

// angular directive controller function 
... 

DOMAudioObject = createAudioObject(src); 
DOMAudioObject.audio.ontimeupdate = onTimeUpdate; 

function createAudioObject(src) { 
    return { 
     audio: new Audio(src), 
     playback: $scope.playback, 
     name: $scope.name 
    }; 
} 

function onTimeUpdate() { 
    var currentTime = DOMAudioObject.audio.currentTime; 
    console.log(currentTime); 
    $scope.currentTime = currentTime; 
    $scope.audio.currentTime = currentTime;     
    $scope.$apply(); 
} 

全部控制器代碼:

function audioCtrl($scope) { 

     // private reference to the DOM object that plays the audio 
     var DOMAudioObject, 
      watchers = {unbind: {}}; 

     // register watchers once the model is available, we need at least the id field 
     watchers.unbind.model = $scope.$watch('model', init); 
     // remove watchers when the user navigates away 
     $scope.$on('$destroy', destroyWatchers); 

     function applyAudioPropertiesAsync() { 
      DOMAudioObject.audio.volume = $scope.volume; 
      DOMAudioObject.audio.currentTime = $scope.currentTime; 
      $scope.audio.duration = DOMAudioObject.audio.duration; 
     } 

     function applyAudioMetaProperties() { 
      $scope.audio = $scope.audio || {}; 
      $scope.audio.id = $scope.model.id; 
      $scope.audio.playback = $scope.playback; 
      $scope.audio.name = $scope.model.name; 
      $scope.audio.volume = $scope.volume; 
      $scope.audio.currentTime = $scope.currentTime; 
      $scope.audio.duration = DOMAudioObject.audio.duration || 0; 
     } 

     // fired when the audio object has been loaded from src 
     function bindAudio(src, oldSrc) { 
      if (src === undefined) { 
       return; 
      } 

      // now safe to register watchers since they rely on the audio object 
      registerWatchers(); 

      // if there is already a stored audio object associated with this visual, use it 
      DOMAudioObject = $audio.get($scope.model.id); 

      // audio src has been updated, reflect by pausing and creating a new audio object 
      if (oldSrc && src !== oldSrc) { 
       $scope.playback.play = false; 
       $scope.currentTime = 0.0; 
       pause(DOMAudioObject); 
       DOMAudioObject = null; 
      } 

      // create a new audio object or use stored values instead of reinitializing each time 
      if (!DOMAudioObject) { 
       DOMAudioObject = createAudioObject(src); 
       // set in $audio service for persistence across views and controllers 
       $audio.set($scope.model.id, DOMAudioObject); 
      } else { 
       $scope.playback = DOMAudioObject.playback || $scope.playback; 
       $scope.currentTime = DOMAudioObject.audio.currentTime || $scope.currentTime; 
       $scope.volume = DOMAudioObject.audio.volume || $scope.volume; 
      } 

      // only bind meta properties, binding actual Audio object causes problems in some browsers 
      applyAudioMetaProperties(); 

      // add values that must be calculated after initial load 
      DOMAudioObject.audio.oncanplay = applyAudioPropertiesAsync; 
      // tell playback progress indicator to move on timeupdate event by firing a digest cycle 
      DOMAudioObject.audio.ontimeupdate = onTimeUpdate; 
      // tell animate directive to stop scrolling when the audio has ended 
      DOMAudioObject.audio.onended = onAudioEnded; 

      // tell parent this directive is ready when the audio has fully loaded 
      watchers.unbind.duration = $scope.$watch('audio.duration', function (val) { 
       if (val > 0) { 
        $scope.$emit('audio.ready', {id: $scope.model.id, audio: $scope.audio}); 
        watchers.unbind.duration(); 
       } 
      }); 
     } 

     // create a dom audio object 
     function createAudioObject(src) { 
      return { 
       audio: new Audio(src), 
       playback: $scope.playback, 
       name: $scope.model.name 
      }; 
     } 

     function destroyWatchers() { 
      if (watchers.unbind.audio) { 
       watchers.unbind.audio(); 
      } 
      if (watchers.unbind.playback) { 
       watchers.unbind.playback(); 
      } 
      if (watchers.unbind.progress) { 
       watchers.unbind.progress(); 
      } 
      if (watchers.unbind.volume) { 
       watchers.unbind.volume(); 
      } 
     } 

     function init(visual) { 
      if (visual === undefined) { 
       return; 
      } 
      // prevent updates to visual model from rebinding audio 
      watchers.unbind.model(); 
      // when the audio-src is available and fully loaded, create audio objects 
      watchers.unbind.audio = $scope.$watch('audioSrc', bindAudio); 
     } 

     function onAudioEnded() { 
      // ensure playback variables are updated 
      $scope.$apply($scope.playback.play = false); 
      $scope.currentTime = 0; 
     } 

     // timeupdate event to update scope attribute with that of the Audio object 
     function onTimeUpdate() { 
      var currentTime = DOMAudioObject.audio.currentTime; 
      $scope.currentTime = currentTime; 
      $scope.audio.currentTime = currentTime; 
      $scope.$apply(); 
     } 

     // pause the current track 
     function pause(audio) { 
      if (audio) { 
       audio.audio.pause(); 
      } 
     } 

     // play the current track 
     function play(audio) { 
      if (audio) { 
       audio.audio.play(); 
      } 
     } 

     function registerWatchers() { 
      // allow audio to be toggled on/off 
      watchers.unbind.playback = $scope.$watch('playback.play', togglePlay); 
      // allow volume changes 
      watchers.unbind.volume = $scope.$watch('volume', updateVolume); 
      // allow seeking of audio 
      watchers.unbind.progress = $scope.$watch('currentTime', seek); 
      // update the name variable on the audio object so it reflects in global scope 
      watchers.unbind.name = $scope.$watch('model.name', applyAudioMetaProperties); 
     } 

     // move audio position pointer to a new place 
     function seek(val) { 
      var threshold = 1, 
       curr = DOMAudioObject.audio.currentTime; 

      if ((val >= curr + threshold) || (val <= curr - threshold)) { 
       DOMAudioObject.audio.currentTime = val; 
      } 
     } 

     // toggle play/pause 
     function togglePlay(val) { 
      if (val) { 
       play(DOMAudioObject); 
       $audio.setGlobal($scope.audio); 
      } else { 
       pause(DOMAudioObject); 
      } 
     } 

     // allow the volume to be changed, scope reference updates automatically (pass by reference) 
     function updateVolume(val) { 
      if (val) { 
       DOMAudioObject.audio.volume = val; 
      } 
     } 
    } 

enter image description here

然後,當你的圖像中看到的,onTimeUpdate()函數不斷變得叫了一遍又一遍,即使currentT的價值IME處理不當改變(它是每個時間0)

再次,這僅發生在Firefox。 Chrome瀏覽器,Safari瀏覽器,甚至Internet Explorer的行爲都很好。我在Mac OS X 10.11埃爾卡皮坦運行Firefox 40.0.3,角1.4.6

有誰有一些洞察可能被這裏發生的一切,以及任何可能的解決方案來解決這個問題?

+0

是否有可能以某種方式'DOMAudioObject.audio === $ scope.audio'?如果是這樣的話,我認爲FF可以在'currentTime'的'set()'中放置一個EventDispatcher,這是正常的行爲。解決方法就是簡單地'if(this!== $ scope.audio)$ scope.audio.currentTime = currentTime;' – Kaiido

+0

我試着做你說的話,仍然沒有修復它。我甚至嘗試用angular.copy()包裝$ scope和DOMAudioObject之間的任何綁定,問題仍然存在。如果您有興趣查看,我確實更新了我的文章以提供更多控制器代碼 – jasonaibrahim

回答