Bug 1235612 - part3 : implement the logic of audible state notification for agent owners. draft
authorAlastor Wu <alwu@mozilla.com>
Tue, 03 May 2016 10:03:11 +0800
changeset 362833 b070159203dbb61acfa04eadb300f020ddd28124
parent 362832 7ac65d7f58b84d6297d16c12149be9703a34bb86
child 362834 73aa5b705aed82a15e49e285f60eb726e6911949
push id17042
push useralwu@mozilla.com
push dateTue, 03 May 2016 09:54:00 +0000
bugs1235612
milestone49.0a1
Bug 1235612 - part3 : implement the logic of audible state notification for agent owners. MozReview-Commit-ID: FDj491A3OxD
dom/fmradio/FMRadio.cpp
dom/html/HTMLMediaElement.cpp
dom/html/HTMLMediaElement.h
dom/media/webaudio/AudioDestinationNode.cpp
dom/media/webspeech/synth/nsSpeechTask.cpp
dom/plugins/base/nsNPAPIPlugin.cpp
dom/telephony/Telephony.cpp
--- a/dom/fmradio/FMRadio.cpp
+++ b/dom/fmradio/FMRadio.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/Hal.h"
 #include "mozilla/HalTypes.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/FMRadioBinding.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/PFMRadioChild.h"
 #include "mozilla/dom/FMRadioService.h"
 #include "mozilla/dom/TypedArray.h"
+#include "AudioChannelService.h"
 #include "DOMRequest.h"
 #include "nsDOMClassInfo.h"
 #include "nsIDocShell.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIAudioManager.h"
 
 #undef LOG
 #define LOG(args...) FM_LOG("FMRadio", args)
@@ -448,17 +449,18 @@ FMRadio::DisableRDS()
 }
 
 void
 FMRadio::EnableAudioChannelAgent()
 {
   NS_ENSURE_TRUE_VOID(mAudioChannelAgent);
 
   AudioPlaybackConfig config;
-  nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&config);
+  nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&config,
+                                                         AudioChannelService::AudibleState::eAudible);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   WindowVolumeChanged(config.mVolume, config.mMuted);
   WindowSuspendChanged(config.mSuspend);
 
   mAudioChannelAgentEnabled = true;
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -3362,16 +3362,20 @@ void HTMLMediaElement::UpdateSrcMediaStr
     // called and that will remove all listeners/outputs.
 
     mWatchManager.Unwatch(*mMediaStreamListener,
         &HTMLMediaElement::UpdateReadyStateInternal);
 
     mMediaStreamListener->Forget();
     mMediaStreamListener = nullptr;
   }
+
+  // If the input is a media stream, we don't check its data and always regard
+  // it as audible when it's playing.
+  NotifyAudibleStateChanged(shouldPlay);
 }
 
 void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
 {
   NS_ASSERTION(!mSrcStream && !mMediaStreamListener && !mMediaStreamSizeListener,
                "Should have been ended already");
 
   mSrcStream = aStream;
@@ -5056,18 +5060,25 @@ void
 HTMLMediaElement::NotifyAudioChannelAgent(bool aPlaying)
 {
   // This is needed to pass nsContentUtils::IsCallerChrome().
   // AudioChannel API should not called from content but it can happen that
   // this method has some content JS in its stack.
   AutoNoJSAPI nojsapi;
 
   if (aPlaying) {
+    // The reason we don't call NotifyStartedPlaying after the media element
+    // really becomes audible is because there is another case needs to block
+    // element as early as we can, we would hear sound leaking if we block it
+    // too late. In that case (block autoplay in non-visited-tab), we need to
+    // create a connection before decoding, because we don't want user hearing
+    // any sound.
     AudioPlaybackConfig config;
-    nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&config);
+    nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&config,
+                                                           mIsAudioTrackAudible);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return;
     }
 
     WindowVolumeChanged(config.mVolume, config.mMuted);
     WindowSuspendChanged(config.mSuspend);
   } else {
     mAudioChannelAgent->NotifyStoppedPlaying();
@@ -5613,14 +5624,22 @@ HTMLMediaElement::IsCurrentlyPlaying() c
   return false;
 }
 
 void
 HTMLMediaElement::NotifyAudibleStateChanged(bool aAudible)
 {
   if (mIsAudioTrackAudible != aAudible) {
     mIsAudioTrackAudible = aAudible;
-    // To do ...
+    NotifyAudioPlaybackChanged();
+  }
+}
+
+void
+HTMLMediaElement::NotifyAudioPlaybackChanged()
+{
+  if (mAudioChannelAgent) {
+    mAudioChannelAgent->NotifyStartedAudible(mIsAudioTrackAudible);
   }
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -443,19 +443,23 @@ public:
   {
     return mNetworkState;
   }
 
   // Called by the media decoder object, on the main thread,
   // when the connection between Rtsp server and client gets lost.
   virtual void ResetConnectionState() final override;
 
-  // Called by media decoder when the audible state changed.
+  // Called by media decoder when the audible state changed or when input is
+  // a media stream.
   virtual void NotifyAudibleStateChanged(bool aAudible) final override;
 
+  // Notify agent when the MediaElement changes its audible state.
+  void NotifyAudioPlaybackChanged();
+
   // XPCOM GetPreload() is OK
   void SetPreload(const nsAString& aValue, ErrorResult& aRv)
   {
     SetHTMLAttr(nsGkAtoms::preload, aValue, aRv);
   }
 
   already_AddRefed<TimeRanges> Buffered() const;
 
--- a/dom/media/webaudio/AudioDestinationNode.cpp
+++ b/dom/media/webaudio/AudioDestinationNode.cpp
@@ -660,17 +660,18 @@ AudioDestinationNode::InputMuted(bool aM
   }
 
   if (aMuted) {
     mAudioChannelAgent->NotifyStoppedPlaying();
     return;
   }
 
   AudioPlaybackConfig config;
-  nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&config);
+  nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&config,
+                                                         AudioChannelService::AudibleState::eAudible);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   WindowVolumeChanged(config.mVolume, config.mMuted);
   WindowSuspendChanged(config.mSuspend);
 }
 
--- a/dom/media/webspeech/synth/nsSpeechTask.cpp
+++ b/dom/media/webspeech/synth/nsSpeechTask.cpp
@@ -709,17 +709,18 @@ nsSpeechTask::CreateAudioChannelAgent()
   }
 
   mAudioChannelAgent = new AudioChannelAgent();
   mAudioChannelAgent->InitWithWeakCallback(mUtterance->GetOwner(),
                                            static_cast<int32_t>(AudioChannelService::GetDefaultAudioChannel()),
                                            this);
 
   AudioPlaybackConfig config;
-  nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&config);
+  nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&config,
+                                                         AudioChannelService::AudibleState::eAudible);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   WindowVolumeChanged(config.mVolume, config.mMuted);
   WindowSuspendChanged(config.mSuspend);
 }
 
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -2287,17 +2287,18 @@ NPError
       if (isMuted) {
         rv = agent->NotifyStoppedPlaying();
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return NPERR_NO_ERROR;
         }
       } else {
 
         dom::AudioPlaybackConfig config;
-        rv = agent->NotifyStartedPlaying(&config);
+        rv = agent->NotifyStartedPlaying(&config,
+                                         dom::AudioChannelService::AudibleState::eAudible);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return NPERR_NO_ERROR;
         }
 
         rv = inst->WindowVolumeChanged(config.mVolume, config.mMuted);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return NPERR_NO_ERROR;
         }
--- a/dom/telephony/Telephony.cpp
+++ b/dom/telephony/Telephony.cpp
@@ -557,17 +557,18 @@ Telephony::HandleAudioAgentState()
     rv = mAudioAgent->NotifyStoppedPlaying();
     mAudioAgent = nullptr;
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   } else if (!activeCall.IsNull() && !mIsAudioStartPlaying) {
     mIsAudioStartPlaying = true;
     AudioPlaybackConfig config;
-    rv = mAudioAgent->NotifyStartedPlaying(&config);
+    rv = mAudioAgent->NotifyStartedPlaying(&config,
+                                           AudioChannelService::AudibleState::eAudible);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     // In B2G, the system app manages audio playback policy. If there is a new
     // sound want to be playback, it must wait for the permission from the
     // system app. It means that the sound would be muted first, and then be
     // unmuted. For telephony, the behaviors are hold() first, then resume().