Bug 1254378 - Dispatch 'voiceschanged' when notified. r=smaug
authorEitan Isaacson <eitan@monotonous.org>
Wed, 23 Mar 2016 11:01:05 -0700
changeset 291060 70ead871eea8cbc07577cfceb86458bd5a16d478
parent 291059 47390c18d9b12131f4849a2625302cf0588ac720
child 291061 f7a5b2b77a7787af1d12eb027e84038da6228aa0
push id74438
push usereisaacson@mozilla.com
push dateFri, 01 Apr 2016 00:05:56 +0000
treeherdermozilla-inbound@f2c661c123c0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1254378
milestone48.0a1
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 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;