Bug 1254378 - Dispatch 'voiceschanged' when notified. r=smaug
authorEitan Isaacson <eitan@monotonous.org>
Wed, 23 Mar 2016 11:01:05 -0700
changeset 291119 70ead871eea8cbc07577cfceb86458bd5a16d478
parent 291118 47390c18d9b12131f4849a2625302cf0588ac720
child 291120 f7a5b2b77a7787af1d12eb027e84038da6228aa0
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1254378
milestone48.0a1
Bug 1254378 - Dispatch 'voiceschanged' when notified. r=smaug MozReview-Commit-ID: 7BAJaqMtVUE
dom/media/webspeech/synth/SpeechSynthesis.cpp
dom/media/webspeech/synth/SpeechSynthesis.h
--- a/dom/media/webspeech/synth/SpeechSynthesis.cpp
+++ b/dom/media/webspeech/synth/SpeechSynthesis.cpp
@@ -60,16 +60,17 @@ SpeechSynthesis::SpeechSynthesis(nsPIDOM
   , mInnerID(aParent->WindowID())
 {
   MOZ_ASSERT(aParent->IsInnerWindow());
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     obs->AddObserver(this, "inner-window-destroyed", true);
+    obs->AddObserver(this, "synth-voices-changed", true);
   }
 
 }
 
 SpeechSynthesis::~SpeechSynthesis()
 {
 }
 
@@ -114,28 +115,43 @@ SpeechSynthesis::Paused() const
 }
 
 bool
 SpeechSynthesis::HasEmptyQueue() const
 {
   return mSpeechQueue.Length() == 0;
 }
 
+bool SpeechSynthesis::HasVoices() const
+{
+  uint32_t voiceCount = mVoiceCache.Count();
+  if (voiceCount == 0) {
+    nsresult rv = nsSynthVoiceRegistry::GetInstance()->GetVoiceCount(&voiceCount);
+    if(NS_WARN_IF(NS_FAILED(rv))) {
+      return false;
+    }
+  }
+
+  return voiceCount != 0;
+}
+
 void
 SpeechSynthesis::Speak(SpeechSynthesisUtterance& aUtterance)
 {
   if (aUtterance.mState != SpeechSynthesisUtterance::STATE_NONE) {
     // XXX: Should probably raise an error
     return;
   }
 
   mSpeechQueue.AppendElement(&aUtterance);
   aUtterance.mState = SpeechSynthesisUtterance::STATE_PENDING;
 
-  if (mSpeechQueue.Length() == 1 && !mCurrentTask && !mHoldQueue) {
+  // If we only have one item in the queue, we aren't pre-paused, and
+  // we have voices available, speak it.
+  if (mSpeechQueue.Length() == 1 && !mCurrentTask && !mHoldQueue && HasVoices()) {
     AdvanceQueue();
   }
 }
 
 void
 SpeechSynthesis::AdvanceQueue()
 {
   LOG(LogLevel::Debug,
@@ -279,35 +295,39 @@ SpeechSynthesis::ForceEnd()
 }
 
 NS_IMETHODIMP
 SpeechSynthesis::Observe(nsISupports* aSubject, const char* aTopic,
                          const char16_t* aData)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (strcmp(aTopic, "inner-window-destroyed")) {
-    return NS_OK;
-  }
+
+  if (strcmp(aTopic, "inner-window-destroyed") == 0) {
+    nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
+    NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
 
-  nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
-  NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
+    uint64_t innerID;
+    nsresult rv = wrapper->GetData(&innerID);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (innerID == mInnerID) {
+      Cancel();
 
-  uint64_t innerID;
-  nsresult rv = wrapper->GetData(&innerID);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (innerID == mInnerID) {
-    if (mCurrentTask) {
-      mCurrentTask->Cancel();
+      nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+      if (obs) {
+        obs->RemoveObserver(this, "inner-window-destroyed");
+      }
     }
-
-    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-    if (obs) {
-      obs->RemoveObserver(this, "inner-window-destroyed");
+  } else if (strcmp(aTopic, "synth-voices-changed") == 0) {
+    LOG(LogLevel::Debug, ("SpeechSynthesis::onvoiceschanged"));
+    DispatchTrustedEvent(NS_LITERAL_STRING("voiceschanged"));
+    // If we have a pending item, and voices become available, speak it.
+    if (!mCurrentTask && !mHoldQueue && HasVoices()) {
+      AdvanceQueue();
     }
   }
 
   return NS_OK;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/media/webspeech/synth/SpeechSynthesis.h
+++ b/dom/media/webspeech/synth/SpeechSynthesis.h
@@ -62,16 +62,18 @@ public:
 
   IMPL_EVENT_HANDLER(voiceschanged)
 
 private:
   virtual ~SpeechSynthesis();
 
   void AdvanceQueue();
 
+  bool HasVoices() const;
+
   nsTArray<RefPtr<SpeechSynthesisUtterance> > mSpeechQueue;
 
   RefPtr<nsSpeechTask> mCurrentTask;
 
   nsRefPtrHashtable<nsStringHashKey, SpeechSynthesisVoice> mVoiceCache;
 
   bool mHoldQueue;