Bug 1269672 - part2 : move audible data checking from MDSM to DecodedAudioDataSink. draft
authorAlastor Wu <alwu@mozilla.com>
Tue, 10 May 2016 15:10:31 +0800
changeset 365184 33edfbf741e967be3e5a1ac80ec763e95f63335c
parent 365183 9abef003d31422ee155bb27c890d52c84fef300c
child 520476 86b8300dd2cdb7016195daeb293b7f4b912373a1
push id17658
push useralwu@mozilla.com
push dateTue, 10 May 2016 07:10:54 +0000
bugs1269672
milestone49.0a1
Bug 1269672 - part2 : move audible data checking from MDSM to DecodedAudioDataSink. MozReview-Commit-ID: DLg75jPZba3
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
dom/media/mediasink/DecodedAudioDataSink.cpp
dom/media/mediasink/DecodedAudioDataSink.h
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -346,25 +346,35 @@ MediaDecoderStateMachine::Initialization
   mWatchManager.Watch(mExplicitDuration, &MediaDecoderStateMachine::RecomputeDuration);
   mWatchManager.Watch(mObservedDuration, &MediaDecoderStateMachine::RecomputeDuration);
   mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged);
 
   // Configure MediaDecoderReaderWrapper.
   SetMediaDecoderReaderWrapperCallback();
 }
 
+void
+MediaDecoderStateMachine::AudioAudibleChanged(bool aAudible)
+{
+  mIsAudioDataAudible = aAudible;
+}
+
 media::MediaSink*
 MediaDecoderStateMachine::CreateAudioSink()
 {
   RefPtr<MediaDecoderStateMachine> self = this;
   auto audioSinkCreator = [self] () {
     MOZ_ASSERT(self->OnTaskQueue());
-    return new DecodedAudioDataSink(
+    DecodedAudioDataSink* audioSink = new DecodedAudioDataSink(
       self->mTaskQueue, self->mAudioQueue, self->GetMediaTime(),
       self->mInfo.mAudio, self->mAudioChannel);
+
+    self->mAudibleListener = audioSink->AudibleEvent().Connect(
+      self->mTaskQueue, self.get(), &MediaDecoderStateMachine::AudioAudibleChanged);
+    return audioSink;
   };
   return new AudioSinkWrapper(mTaskQueue, audioSinkCreator);
 }
 
 already_AddRefed<media::MediaSink>
 MediaDecoderStateMachine::CreateMediaSink(bool aAudioCaptured)
 {
   RefPtr<media::MediaSink> audioSink = aAudioCaptured
@@ -613,39 +623,23 @@ MediaDecoderStateMachine::Push(MediaData
   } else {
     // TODO: Handle MediaRawData, determine which queue should be pushed.
   }
   UpdateNextFrameStatus();
   DispatchDecodeTasksIfNeeded();
 }
 
 void
-MediaDecoderStateMachine::CheckIsAudible(const MediaData* aSample)
-{
-  MOZ_ASSERT(OnTaskQueue());
-  MOZ_ASSERT(aSample->mType == MediaData::AUDIO_DATA);
-
-  const AudioData* data = aSample->As<AudioData>();
-  bool isAudible = data->IsAudible();
-  if (isAudible && !mIsAudioDataAudible) {
-    mIsAudioDataAudible = true;
-  } else if (!isAudible && mIsAudioDataAudible) {
-    mIsAudioDataAudible = false;
-  }
-}
-
-void
 MediaDecoderStateMachine::OnAudioPopped(const RefPtr<MediaData>& aSample)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   mPlaybackOffset = std::max(mPlaybackOffset.Ref(), aSample->mOffset);
   UpdateNextFrameStatus();
   DispatchAudioDecodeTaskIfNeeded();
-  CheckIsAudible(aSample);
 }
 
 void
 MediaDecoderStateMachine::OnVideoPopped(const RefPtr<MediaData>& aSample)
 {
   MOZ_ASSERT(OnTaskQueue());
   mPlaybackOffset = std::max(mPlaybackOffset.Ref(), aSample->mOffset);
   UpdateNextFrameStatus();
@@ -1390,16 +1384,18 @@ MediaDecoderStateMachine::InvokeSeek(See
                      &MediaDecoderStateMachine::Seek, aTarget);
 }
 
 void MediaDecoderStateMachine::StopMediaSink()
 {
   MOZ_ASSERT(OnTaskQueue());
   if (mMediaSink->IsStarted()) {
     DECODER_LOG("Stop MediaSink");
+    mAudibleListener.DisconnectIfExists();
+
     mMediaSink->Stop();
     mMediaSinkAudioPromise.DisconnectIfExists();
     mMediaSinkVideoPromise.DisconnectIfExists();
   }
 }
 
 void
 MediaDecoderStateMachine::DispatchDecodeTasksIfNeeded()
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -380,17 +380,18 @@ protected:
   // Inserts MediaData* samples into their respective MediaQueues.
   // aSample must not be null.
 
   void Push(MediaData* aSample, MediaData::Type aSampleType);
 
   void OnAudioPopped(const RefPtr<MediaData>& aSample);
   void OnVideoPopped(const RefPtr<MediaData>& aSample);
 
-  void CheckIsAudible(const MediaData* aSample);
+  void AudioAudibleChanged(bool aAudible);
+
   void VolumeChanged();
   void LogicalPlaybackRateChanged();
   void PreservesPitchChanged();
 
   MediaQueue<MediaData>& AudioQueue() { return mAudioQueue; }
   MediaQueue<MediaData>& VideoQueue() { return mVideoQueue; }
 
   // True if our buffers of decoded audio are not full, and we should
@@ -923,16 +924,17 @@ private:
   RefPtr<MediaResource> mResource;
 
   // Track the complete & error for audio/video separately
   MozPromiseRequestHolder<GenericPromise> mMediaSinkAudioPromise;
   MozPromiseRequestHolder<GenericPromise> mMediaSinkVideoPromise;
 
   MediaEventListener mAudioQueueListener;
   MediaEventListener mVideoQueueListener;
+  MediaEventListener mAudibleListener;
 
   MediaEventProducerExc<nsAutoPtr<MediaInfo>,
                         nsAutoPtr<MetadataTags>,
                         MediaDecoderEventVisibility> mMetadataLoadedEvent;
   MediaEventProducerExc<nsAutoPtr<MediaInfo>,
                         MediaDecoderEventVisibility> mFirstFrameLoadedEvent;
 
   MediaEventProducer<MediaEventType> mOnPlaybackEvent;
--- a/dom/media/mediasink/DecodedAudioDataSink.cpp
+++ b/dom/media/mediasink/DecodedAudioDataSink.cpp
@@ -46,16 +46,17 @@ DecodedAudioDataSink::DecodedAudioDataSi
   , mMonitor("DecodedAudioDataSink")
   , mWritten(0)
   , mErrored(false)
   , mPlaybackComplete(false)
   , mOwnerThread(aThread)
   , mProcessedQueueLength(0)
   , mFramesParsed(0)
   , mLastEndTime(0)
+  , mIsAudioDataAudible(false)
 {
   bool resampling = gfxPrefs::AudioSinkResampling();
 
   if (resampling) {
     mOutputRate = gfxPrefs::AudioSinkResampleRate();
   } else if (mInfo.mRate == 44100 || mInfo.mRate == 48000) {
     // The original rate is of good quality and we want to minimize unecessary
     // resampling. The common scenario being that the sampling rate is one or
@@ -334,16 +335,31 @@ void
 DecodedAudioDataSink::Drained()
 {
   SINK_LOG("Drained");
   mPlaybackComplete = true;
   mEndPromise.ResolveIfExists(true, __func__);
 }
 
 void
+DecodedAudioDataSink::CheckIsAudible(const AudioData* aData)
+{
+  MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+
+  bool isAudible = aData->IsAudible();
+  if (isAudible && !mIsAudioDataAudible) {
+    mIsAudioDataAudible = true;
+    mAudibleEvent.Notify(mIsAudioDataAudible);
+  } else if (!isAudible && mIsAudioDataAudible) {
+    mIsAudioDataAudible = false;
+    mAudibleEvent.Notify(mIsAudioDataAudible);
+  }
+}
+
+void
 DecodedAudioDataSink::OnAudioPopped(const RefPtr<MediaData>& aSample)
 {
   SINK_LOG_V("AudioStream has used an audio packet.");
   NotifyAudioNeeded();
 }
 
 void
 DecodedAudioDataSink::OnAudioPushed(const RefPtr<MediaData>& aSample)
@@ -366,16 +382,18 @@ DecodedAudioDataSink::NotifyAudioNeeded(
     RefPtr<AudioData> data =
       dont_AddRef(AudioQueue().PopFront().take()->As<AudioData>());
 
     // Ignore the element with 0 frames and try next.
     if (!data->mFrames) {
       continue;
     }
 
+    CheckIsAudible(data);
+
     if (!mConverter ||
         (data->mRate != mConverter->InputConfig().Rate() ||
          data->mChannels != mConverter->InputConfig().Channels())) {
       SINK_LOG_V("Audio format changed from %u@%uHz to %u@%uHz",
                  mConverter? mConverter->InputConfig().Channels() : 0,
                  mConverter ? mConverter->InputConfig().Rate() : 0,
                  data->mChannels, data->mRate);
 
--- a/dom/media/mediasink/DecodedAudioDataSink.h
+++ b/dom/media/mediasink/DecodedAudioDataSink.h
@@ -14,16 +14,17 @@
 #include "mozilla/RefPtr.h"
 #include "nsISupportsImpl.h"
 
 #include "mozilla/dom/AudioChannelBinding.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/Monitor.h"
+#include "mozilla/StateMirroring.h"
 
 namespace mozilla {
 
 class AudioConverter;
 
 namespace media {
 
 class DecodedAudioDataSink : public AudioSink,
@@ -53,28 +54,34 @@ public:
   // Shut down the DecodedAudioDataSink's resources.
   void Shutdown() override;
 
   void SetVolume(double aVolume) override;
   void SetPlaybackRate(double aPlaybackRate) override;
   void SetPreservesPitch(bool aPreservesPitch) override;
   void SetPlaying(bool aPlaying) override;
 
+  MediaEventSource<bool>& AudibleEvent() {
+    return mAudibleEvent;
+  }
+
 private:
   virtual ~DecodedAudioDataSink();
 
   // Allocate and initialize mAudioStream. Returns NS_OK on success.
   nsresult InitializeAudioStream(const PlaybackParams& aParams);
 
   // Interface of AudioStream::DataSource.
   // Called on the callback thread of cubeb.
   UniquePtr<AudioStream::Chunk> PopFrames(uint32_t aFrames) override;
   bool Ended() const override;
   void Drained() override;
 
+  void CheckIsAudible(const AudioData* aData);
+
   // The audio stream resource. Used on the task queue of MDSM only.
   RefPtr<AudioStream> mAudioStream;
 
   // The presentation time of the first audio frame that was played in
   // microseconds. We can add this to the audio stream position to determine
   // the current audio time.
   const int64_t mStartTime;
 
@@ -141,14 +148,19 @@ private:
   // the input stream. It indicates the time in frames since playback started
   // at the current input framerate.
   int64_t mFramesParsed;
   Maybe<RefPtr<AudioData>> mLastProcessedPacket;
   int64_t mLastEndTime;
   // Never modifed after construction.
   uint32_t mOutputRate;
   uint32_t mOutputChannels;
+
+  // True when audio is producing audible sound, false when audio is silent.
+  bool mIsAudioDataAudible;
+
+  MediaEventProducer<bool> mAudibleEvent;
 };
 
 } // namespace media
 } // namespace mozilla
 
 #endif