Bug 598812 - Fix time attribute of audio available event. r=cpearce a=blocking2.0
authorasync.processingjs@yahoo.com
Thu, 07 Oct 2010 11:58:36 +1300
changeset 54997 f0a151e892714eca6bb77d495f8a17fd80ddbf8a
parent 54996 a8657d2e743d20f31ba71653a384bc9d92648005
child 54998 d08b67f76bfc12ff20a93162ed4fe6a6588557c5
push id16110
push usercpearce@mozilla.com
push dateWed, 06 Oct 2010 23:45:41 +0000
treeherdermozilla-central@2ffbe81d752f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce, blocking2
bugs598812
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 598812 - Fix time attribute of audio available event. r=cpearce a=blocking2.0
content/html/content/public/nsHTMLMediaElement.h
content/html/content/src/nsHTMLMediaElement.cpp
content/media/nsAudioAvailableEventManager.cpp
content/media/nsAudioAvailableEventManager.h
content/media/nsBuiltinDecoder.cpp
content/media/nsBuiltinDecoder.h
content/media/nsBuiltinDecoderStateMachine.cpp
content/media/test/test_a4_tone.html
--- a/content/html/content/public/nsHTMLMediaElement.h
+++ b/content/html/content/public/nsHTMLMediaElement.h
@@ -184,17 +184,17 @@ public:
   // a static document and we're not actually playing video
   gfxASurface* GetPrintSurface() { return mPrintSurface; }
 
   // Dispatch events
   nsresult DispatchEvent(const nsAString& aName);
   nsresult DispatchAsyncEvent(const nsAString& aName);
   nsresult DispatchAudioAvailableEvent(float* aFrameBuffer,
                                        PRUint32 aFrameBufferLength,
-                                       PRUint64 aTime);
+                                       float aTime);
 
   // Dispatch events that were raised while in the bfcache
   nsresult DispatchPendingMediaEvents();
 
   // Called by the decoder when some data has been downloaded or
   // buffering/seeking has ended. aNextFrameAvailable is true when
   // the data for the next frame is available. This method will
   // decide whether to set the ready state to HAVE_CURRENT_DATA,
@@ -291,17 +291,17 @@ public:
    * whether it's appropriate to fire an error event.
    */
   void NotifyLoadError();
 
   /**
    * Called when data has been written to the underlying audio stream.
    */
   void NotifyAudioAvailable(float* aFrameBuffer, PRUint32 aFrameBufferLength,
-                            PRUint64 aTime);
+                            float aTime);
 
   /**
    * Called in order to check whether some node (this window, its document,
    * or content in that document) has a MozAudioAvailable event listener.
    */
   PRBool MayHaveAudioAvailableEventListener();
 
   virtual PRBool IsNodeOfType(PRUint32 aFlags) const;
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -116,18 +116,16 @@ static PRLogModuleInfo* gMediaElementEve
 #define LOG(type, msg)
 #define LOG_EVENT(type, msg)
 #endif
 
 #include "nsIContentSecurityPolicy.h"
 #include "nsIChannelPolicy.h"
 #include "nsChannelPolicy.h"
 
-#define MS_PER_SECOND 1000
-
 using namespace mozilla::layers;
 
 // Under certain conditions there may be no-one holding references to
 // a media element from script, DOM parent, etc, but the element may still
 // fire meaningful events in the future so we can't destroy it yet:
 // 1) If the element is delaying the load event (or would be, if it were
 // in a document), then events up to loadeddata or error could be fired,
 // so we need to stay alive.
@@ -688,17 +686,17 @@ void nsHTMLMediaElement::NotifyLoadError
     NS_ASSERTION(mSourceLoadCandidate, "Must know the source we were loading from!");
     DispatchAsyncSourceError(mSourceLoadCandidate);
     QueueLoadFromSourceTask();
   }
 }
 
 void nsHTMLMediaElement::NotifyAudioAvailable(float* aFrameBuffer,
                                               PRUint32 aFrameBufferLength,
-                                              PRUint64 aTime)
+                                              float aTime)
 {
   // Auto manage the memory for the frame buffer, so that if we add an early
   // return-on-error here in future, we won't forget to release the memory.
   // Otherwise we hand ownership of the memory over to the event created by 
   // DispatchAudioAvailableEvent().
   nsAutoArrayPtr<float> frameBuffer(aFrameBuffer);
   // Do same-origin check on element and media before allowing MozAudioAvailable events.
   if (!mMediaSecurityVerified) {
@@ -2213,17 +2211,17 @@ ImageContainer* nsHTMLMediaElement::GetI
     return nsnull;
 
   mImageContainer = manager->CreateImageContainer();
   return mImageContainer;
 }
 
 nsresult nsHTMLMediaElement::DispatchAudioAvailableEvent(float* aFrameBuffer,
                                                          PRUint32 aFrameBufferLength,
-                                                         PRUint64 aTime)
+                                                         float aTime)
 {
   // Auto manage the memory for the frame buffer. If we fail and return
   // an error, this ensures we free the memory in the frame buffer. Otherwise
   // we hand off ownership of the frame buffer to the audioavailable event,
   // which frees the memory when it's destroyed.
   nsAutoArrayPtr<float> frameBuffer(aFrameBuffer);
 
   nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(GetOwnerDoc()));
@@ -2233,17 +2231,17 @@ nsresult nsHTMLMediaElement::DispatchAud
   nsCOMPtr<nsIDOMEvent> event;
   nsresult rv = docEvent->CreateEvent(NS_LITERAL_STRING("MozAudioAvailableEvent"),
                                       getter_AddRefs(event));
   nsCOMPtr<nsIDOMNotifyAudioAvailableEvent> audioavailableEvent(do_QueryInterface(event));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = audioavailableEvent->InitAudioAvailableEvent(NS_LITERAL_STRING("MozAudioAvailable"),
                                                     PR_TRUE, PR_TRUE, frameBuffer.forget(), aFrameBufferLength,
-                                                    (float)aTime / MS_PER_SECOND, mAllowAudioData);
+                                                    aTime, mAllowAudioData);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRBool dummy;
   return target->DispatchEvent(event, &dummy);
 }
 
 nsresult nsHTMLMediaElement::DispatchEvent(const nsAString& aName)
 {
--- a/content/media/nsAudioAvailableEventManager.cpp
+++ b/content/media/nsAudioAvailableEventManager.cpp
@@ -35,29 +35,29 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsTArray.h"
 #include "nsAudioAvailableEventManager.h"
 
-#define MILLISECONDS_PER_SECOND 1000
+#define MILLISECONDS_PER_SECOND 1000.0f
 #define MAX_PENDING_EVENTS 100
 
 using namespace mozilla;
 
 class nsAudioAvailableEventRunner : public nsRunnable
 {
 private:
   nsCOMPtr<nsBuiltinDecoder> mDecoder;
   nsAutoArrayPtr<float> mFrameBuffer;
 public:
   nsAudioAvailableEventRunner(nsBuiltinDecoder* aDecoder, float* aFrameBuffer,
-                              PRUint32 aFrameBufferLength, PRUint64 aTime) :
+                              PRUint32 aFrameBufferLength, float aTime) :
     mDecoder(aDecoder),
     mFrameBuffer(aFrameBuffer),
     mFrameBufferLength(aFrameBufferLength),
     mTime(aTime)
   {
     MOZ_COUNT_CTOR(nsAudioAvailableEventRunner);
   }
 
@@ -67,17 +67,19 @@ public:
 
   NS_IMETHOD Run()
   {
     mDecoder->AudioAvailable(mFrameBuffer.forget(), mFrameBufferLength, mTime);
     return NS_OK;
   }
 
   const PRUint32 mFrameBufferLength;
-  const PRUint64 mTime;
+
+  // Start time of the buffer data (in seconds).
+  const float mTime;
 };
 
 
 nsAudioAvailableEventManager::nsAudioAvailableEventManager(nsBuiltinDecoder* aDecoder) :
   mDecoder(aDecoder),
   mSignalBuffer(new float[mDecoder->GetFrameBufferLength()]),
   mSignalBufferLength(mDecoder->GetFrameBufferLength()),
   mSignalBufferPosition(0),
@@ -99,17 +101,17 @@ void nsAudioAvailableEventManager::Init(
 
 void nsAudioAvailableEventManager::DispatchPendingEvents(PRUint64 aCurrentTime)
 {
   MonitorAutoEnter mon(mMonitor);
 
   while (mPendingEvents.Length() > 0) {
     nsAudioAvailableEventRunner* e =
       (nsAudioAvailableEventRunner*)mPendingEvents[0].get();
-    if (e->mTime > aCurrentTime) {
+    if (e->mTime * MILLISECONDS_PER_SECOND > aCurrentTime) {
       break;
     }
     nsCOMPtr<nsIRunnable> event = mPendingEvents[0];
     mPendingEvents.RemoveElementAt(0);
     NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
   }
 }
 
@@ -132,21 +134,21 @@ void nsAudioAvailableEventManager::Queue
     mSignalBufferLength = currentBufferSize;
   }
   float* audioData = aAudioData;
   PRUint32 audioDataLength = aAudioDataLength;
   PRUint32 signalBufferTail = mSignalBufferLength - mSignalBufferPosition;
 
   // Group audio samples into optimal size for event dispatch, and queue.
   while (signalBufferTail <= audioDataLength) {
-    PRUint64 time = 0;
+    float time = 0.0;
     // Guard against unsigned number overflow during first frame time calculation.
     if (aEndTimeSampleOffset > mSignalBufferPosition + audioDataLength) {
-      time = MILLISECONDS_PER_SECOND * (aEndTimeSampleOffset -
-             mSignalBufferPosition - audioDataLength) / mSamplesPerSecond;
+      time = (aEndTimeSampleOffset - mSignalBufferPosition - audioDataLength) / 
+             mSamplesPerSecond;
     }
 
     // Fill the signalBuffer.
     memcpy(mSignalBuffer.get() + mSignalBufferPosition,
            audioData, sizeof(float) * signalBufferTail);
     audioData += signalBufferTail;
     audioDataLength -= signalBufferTail;
 
@@ -214,15 +216,17 @@ void nsAudioAvailableEventManager::Drain
   if (0 == mSignalBufferPosition)
     return;
 
   // Zero-pad the end of the signal buffer so it's complete.
   memset(mSignalBuffer.get() + mSignalBufferPosition, 0,
          (mSignalBufferLength - mSignalBufferPosition) * sizeof(float));
 
   // Force this last event to go now.
+  float time = (aEndTime / MILLISECONDS_PER_SECOND) - 
+               (mSignalBufferPosition / mSamplesPerSecond);
   nsCOMPtr<nsIRunnable> lastEvent =
     new nsAudioAvailableEventRunner(mDecoder, mSignalBuffer.forget(),
-                                    mSignalBufferLength, aEndTime);
+                                    mSignalBufferLength, time);
   NS_DispatchToMainThread(lastEvent, NS_DISPATCH_NORMAL);
 
   mSignalBufferPosition = 0;
 }
--- a/content/media/nsAudioAvailableEventManager.h
+++ b/content/media/nsAudioAvailableEventManager.h
@@ -77,17 +77,17 @@ public:
 
 private:
   // The decoder associated with the event manager.  The event manager shares
   // the same lifetime as the decoder (the decoder holds a reference to the
   // manager).
   nsBuiltinDecoder* mDecoder;
 
   // The number of samples per second.
-  PRUint64 mSamplesPerSecond;
+  float mSamplesPerSecond;
 
   // A buffer for audio data to be dispatched in DOM events.
   nsAutoArrayPtr<float> mSignalBuffer;
 
   // The current size of the signal buffer, may change due to DOM calls.
   PRUint32 mSignalBufferLength;
 
   // The position of the first available item in mSignalBuffer
--- a/content/media/nsBuiltinDecoder.cpp
+++ b/content/media/nsBuiltinDecoder.cpp
@@ -305,17 +305,17 @@ nsMediaStream* nsBuiltinDecoder::GetCurr
 already_AddRefed<nsIPrincipal> nsBuiltinDecoder::GetCurrentPrincipal()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   return mStream ? mStream->GetCurrentPrincipal() : nsnull;
 }
 
 void nsBuiltinDecoder::AudioAvailable(float* aFrameBuffer,
                                       PRUint32 aFrameBufferLength,
-                                      PRUint64 aTime)
+                                      float aTime)
 {
   // Auto manage the frame buffer's memory. If we return due to an error
   // here, this ensures we free the memory. Otherwise, we pass off ownership
   // to HTMLMediaElement::NotifyAudioAvailable().
   nsAutoArrayPtr<float> frameBuffer(aFrameBuffer);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   if (mShuttingDown) {
     return;
--- a/content/media/nsBuiltinDecoder.h
+++ b/content/media/nsBuiltinDecoder.h
@@ -408,17 +408,17 @@ class nsBuiltinDecoder : public nsMediaD
 
   // Tells our nsMediaStream to put all loads in the background.
   virtual void MoveLoadsToBackground();
 
   // Stop the state machine thread and drop references to the thread and
   // state machine.
   void Stop();
 
-  void AudioAvailable(float* aFrameBuffer, PRUint32 aFrameBufferLength, PRUint64 aTime);
+  void AudioAvailable(float* aFrameBuffer, PRUint32 aFrameBufferLength, float aTime);
 
   // Called by the state machine to notify the decoder that the duration
   // has changed.
   void DurationChanged();
 
   PRBool OnStateMachineThread() {
     return IsCurrentThread(mStateMachineThread);
   }
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -432,17 +432,17 @@ void nsBuiltinDecoderStateMachine::Audio
 
     if (missingSamples > 0) {
       // The next sound chunk begins some time after the end of the last chunk
       // we pushed to the sound hardware. We must push silence into the audio
       // hardware so that the next sound chunk begins playback at the correct
       // time.
       missingSamples = NS_MIN(static_cast<PRInt64>(PR_UINT32_MAX), missingSamples);
       audioDuration += PlaySilence(static_cast<PRUint32>(missingSamples),
-                                   channels, sampleTime);
+                                   channels, playedSamples);
     } else {
       audioDuration += PlayFromAudioQueue(sampleTime, channels);
     }
     {
       MonitorAutoEnter mon(mDecoder->GetMonitor());
       PRInt64 playedMs;
       if (!SamplesToMs(audioDuration, rate, playedMs)) {
         NS_WARNING("Int overflow calculating playedMs");
--- a/content/media/test/test_a4_tone.html
+++ b/content/media/test/test_a4_tone.html
@@ -173,17 +173,17 @@ function audioAvailable(event) {
     if(maxValue < spectrum[i]) {
       maxValue = spectrum[maxIndex = i];
     }
   }
 
   spectrumMaxs.push({ value: maxValue, index: maxIndex, time: (currentSampleOffset / testFileSampleRate) });
 
   if( (typeof event.time !== "number") ||
-      (Math.abs(event.time - currentSampleOffset / testFileSampleRate) > 0.01) ) {
+      (Math.abs(event.time - currentSampleOffset / testFileSampleRate) >= 0.001) ) {
     isTimePropertyValid = false;
   }
 
   currentSampleOffset += buffer.length;
 }
 
 var loadedMetadataCalled = false;
 function loadedMetadata() {