From 283296d6097aa136e89709a1abdce51eb63bbede Mon Sep 17 00:00:00 2001 From: Makoto Kato Date: Fri, 6 May 2016 17:33:20 +0900 Subject: [PATCH] Bug 1258526 - Create SAPI object per speech to clear previous speech state at force. r=eeejay When using the following script, stop method cannot clear pause state on SAPI backend. speech.pause(); speech.stop(); Since SPF_PURGEBEFORESPEAK doesn't clear previous speech state, we should create SAPI object per speech instead of recycling it. MozReview-Commit-ID: 2ajsTbauQpO --HG-- extra : rebase_source : b72d3e1215e136f204afda18497b042112002995 --- .../webspeech/synth/windows/SapiService.cpp | 54 ++++++++++++------- .../webspeech/synth/windows/SapiService.h | 2 +- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/dom/media/webspeech/synth/windows/SapiService.cpp b/dom/media/webspeech/synth/windows/SapiService.cpp index 2337fb48c7d2..02a98d803d0b 100644 --- a/dom/media/webspeech/synth/windows/SapiService.cpp +++ b/dom/media/webspeech/synth/windows/SapiService.cpp @@ -160,10 +160,11 @@ SapiCallback::OnSpeechEvent(const SPEVENT& speechEvent) void __stdcall SapiService::SpeechEventCallback(WPARAM aWParam, LPARAM aLParam) { - RefPtr service = (SapiService*) aWParam; + RefPtr spVoice = (ISpVoice*) aWParam; + RefPtr service = (SapiService*) aLParam; SPEVENT speechEvent; - while (service->mSapiClient->GetEvents(1, &speechEvent, nullptr) == S_OK) { + while (spVoice->GetEvents(1, &speechEvent, nullptr) == S_OK) { for (size_t i = 0; i < service->mCallbacks.Length(); i++) { RefPtr callback = service->mCallbacks[i]; if (callback->GetStreamNum() == speechEvent.ulStreamNum) { @@ -208,11 +209,24 @@ SapiService::Init() return false; } - if (FAILED(CoCreateInstance(CLSID_SpVoice, nullptr, CLSCTX_ALL, IID_ISpVoice, - getter_AddRefs(mSapiClient)))) { + // Get all the voices from sapi and register in the SynthVoiceRegistry + if (!RegisterVoices()) { return false; } + mInitialized = true; + return true; +} + +already_AddRefed +SapiService::InitSapiInstance() +{ + RefPtr spVoice; + if (FAILED(CoCreateInstance(CLSID_SpVoice, nullptr, CLSCTX_ALL, IID_ISpVoice, + getter_AddRefs(spVoice)))) { + return nullptr; + } + // Set interest for all the events we are interested in ULONGLONG eventMask = SPFEI(SPEI_START_INPUT_STREAM) | @@ -221,21 +235,16 @@ SapiService::Init() SPFEI(SPEI_SENTENCE_BOUNDARY) | SPFEI(SPEI_END_INPUT_STREAM); - if (FAILED(mSapiClient->SetInterest(eventMask, eventMask))) { - return false; - } - - // Get all the voices from sapi and register in the SynthVoiceRegistry - if (!RegisterVoices()) { - return false; + if (FAILED(spVoice->SetInterest(eventMask, eventMask))) { + return nullptr; } // Set the callback function for receiving the events - mSapiClient->SetNotifyCallbackFunction( - (SPNOTIFYCALLBACK*) SapiService::SpeechEventCallback, (WPARAM) this, 0); + spVoice->SetNotifyCallbackFunction( + (SPNOTIFYCALLBACK*) SapiService::SpeechEventCallback, + (WPARAM) spVoice.get(), (LPARAM) this); - mInitialized = true; - return true; + return spVoice.forget(); } bool @@ -331,11 +340,16 @@ SapiService::Speak(const nsAString& aText, const nsAString& aUri, return NS_ERROR_NOT_AVAILABLE; } - if (FAILED(mSapiClient->SetVoice(voiceToken))) { + RefPtr spVoice = InitSapiInstance(); + if (!spVoice) { return NS_ERROR_FAILURE; } - if (FAILED(mSapiClient->SetVolume(static_cast(aVolume * 100)))) { + if (FAILED(spVoice->SetVoice(voiceToken))) { + return NS_ERROR_FAILURE; + } + + if (FAILED(spVoice->SetVolume(static_cast(aVolume * 100)))) { return NS_ERROR_FAILURE; } @@ -348,7 +362,7 @@ SapiService::Speak(const nsAString& aText, const nsAString& aUri, // rate by the 10th root of 3" // https://msdn.microsoft.com/en-us/library/ee431826(v=vs.85).aspx long rate = aRate != 0 ? static_cast(10 * log10(aRate) / log10(3)) : 0; - if (FAILED(mSapiClient->SetRate(rate))) { + if (FAILED(spVoice->SetRate(rate))) { return NS_ERROR_FAILURE; } @@ -370,7 +384,7 @@ SapiService::Speak(const nsAString& aText, const nsAString& aUri, xml.AppendLiteral(""); RefPtr callback = - new SapiCallback(aTask, mSapiClient, textOffset, aText.Length()); + new SapiCallback(aTask, spVoice, textOffset, aText.Length()); // The last three parameters doesn't matter for an indirect service nsresult rv = aTask->Setup(callback, 0, 0, 0); @@ -379,7 +393,7 @@ SapiService::Speak(const nsAString& aText, const nsAString& aUri, } ULONG streamNum; - if (FAILED(mSapiClient->Speak(xml.get(), SPF_ASYNC, &streamNum))) { + if (FAILED(spVoice->Speak(xml.get(), SPF_ASYNC, &streamNum))) { aTask->Setup(nullptr, 0, 0, 0); return NS_ERROR_FAILURE; } diff --git a/dom/media/webspeech/synth/windows/SapiService.h b/dom/media/webspeech/synth/windows/SapiService.h index 5216ab5653cb..8a5aa43594cf 100644 --- a/dom/media/webspeech/synth/windows/SapiService.h +++ b/dom/media/webspeech/synth/windows/SapiService.h @@ -43,11 +43,11 @@ public: private: virtual ~SapiService(); + already_AddRefed InitSapiInstance(); bool RegisterVoices(); nsRefPtrHashtable mVoices; nsTArray> mCallbacks; - RefPtr mSapiClient; bool mInitialized;