☠☠ backed out by 8d2e6a40be15 ☠ ☠ | |
author | Eitan Isaacson <eitan@monotonous.org> |
Wed, 18 May 2016 10:59:08 -0700 | |
changeset 300237 | 4c66c0ddf56267ad34c5a3538a66d7f9fcfaafa2 |
parent 300236 | 6fe5dd5c3f33486f3dddf6c363bd72d7f7687d6a |
child 300238 | ab50796d261607416f6c9b785015d6601edaa348 |
push id | 30309 |
push user | cbook@mozilla.com |
push date | Fri, 03 Jun 2016 10:00:40 +0000 |
treeherder | mozilla-central@e27fe24a746f [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | smaug |
bugs | 1178738 |
milestone | 49.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
|
--- a/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerService.mm +++ b/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerService.mm @@ -30,16 +30,17 @@ class SpeechTaskCallback final : public { public: SpeechTaskCallback(nsISpeechTask* aTask, NSSpeechSynthesizer* aSynth, const nsTArray<size_t>& aOffsets) : mTask(aTask) , mSpeechSynthesizer(aSynth) , mOffsets(aOffsets) + , mCanceled(false) { mStartingTime = TimeStamp::Now(); } NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(SpeechTaskCallback, nsISpeechTaskCallback) NS_DECL_NSISPEECHTASKCALLBACK @@ -56,16 +57,17 @@ private: float GetTimeDurationFromStart(); nsCOMPtr<nsISpeechTask> mTask; NSSpeechSynthesizer* mSpeechSynthesizer; TimeStamp mStartingTime; uint32_t mCurrentIndex; nsTArray<size_t> mOffsets; + bool mCanceled; }; NS_IMPL_CYCLE_COLLECTION(SpeechTaskCallback, mTask); NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechTaskCallback) NS_INTERFACE_MAP_ENTRY(nsISpeechTaskCallback) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechTaskCallback) NS_INTERFACE_MAP_END @@ -73,16 +75,17 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechTaskCallback) NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechTaskCallback) NS_IMETHODIMP SpeechTaskCallback::OnCancel() { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + mCanceled = true; [mSpeechSynthesizer stopSpeaking]; return NS_OK; NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; } NS_IMETHODIMP SpeechTaskCallback::OnPause() @@ -158,17 +161,22 @@ SpeechTaskCallback::OnError(uint32_t aIn // XXX: Provide more specific error messages mTask->DispatchError(GetTimeDurationFromStart(), aIndex, uint32_t(dom::SpeechSynthesisErrorCode::Synthesis_failed)); } void SpeechTaskCallback::OnDidFinishSpeaking() { - mTask->DispatchEnd(GetTimeDurationFromStart(), mCurrentIndex); + if (mCanceled) { + mTask->DispatchError(GetTimeDurationFromStart(), mCurrentIndex, + uint32_t(dom::SpeechSynthesisErrorCode::Interrupted)); + } else { + mTask->DispatchEnd(GetTimeDurationFromStart(), mCurrentIndex); + } // no longer needed [mSpeechSynthesizer setDelegate:nil]; mTask = nullptr; } @interface SpeechDelegate : NSObject<NSSpeechSynthesizerDelegate> { @private
--- a/dom/media/webspeech/synth/nsSpeechTask.cpp +++ b/dom/media/webspeech/synth/nsSpeechTask.cpp @@ -406,39 +406,35 @@ nsSpeechTask::DispatchEndInner(float aEl nsresult nsSpeechTask::DispatchEndImpl(float aElapsedTime, uint32_t aCharIndex) { LOG(LogLevel::Debug, ("nsSpeechTask::DispatchEnd\n")); DestroyAudioChannelAgent(); MOZ_ASSERT(mUtterance); - if(NS_WARN_IF(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED)) { + if(NS_WARN_IF(mUtterance->mState != SpeechSynthesisUtterance::STATE_SPEAKING)) { return NS_ERROR_NOT_AVAILABLE; } // XXX: This should not be here, but it prevents a crash in MSG. if (mStream) { mStream->Destroy(); } RefPtr<SpeechSynthesisUtterance> utterance = mUtterance; if (mSpeechSynthesis) { mSpeechSynthesis->OnEnd(this); } - if (utterance->mState == SpeechSynthesisUtterance::STATE_PENDING) { - utterance->mState = SpeechSynthesisUtterance::STATE_NONE; - } else { - utterance->mState = SpeechSynthesisUtterance::STATE_ENDED; - utterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("end"), - aCharIndex, aElapsedTime, - EmptyString()); - } + utterance->mState = SpeechSynthesisUtterance::STATE_ENDED; + utterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("end"), + aCharIndex, aElapsedTime, + EmptyString()); return NS_OK; } NS_IMETHODIMP nsSpeechTask::DispatchPause(float aElapsedTime, uint32_t aCharIndex) { if (!mIndirectAudio) { @@ -508,16 +504,22 @@ nsSpeechTask::DispatchError(float aElaps { LOG(LogLevel::Debug, ("nsSpeechTask::DispatchError")); if (!mIndirectAudio) { NS_WARNING("Can't call DispatchError() from a direct audio speech service"); return NS_ERROR_FAILURE; } + return DispatchErrorInner(aElapsedTime, aCharIndex, aError); +} + +nsresult +nsSpeechTask::DispatchErrorInner(float aElapsedTime, uint32_t aCharIndex, uint32_t aError) +{ if (!mPreCanceled) { nsSynthVoiceRegistry::GetInstance()->SpeakNext(); } return DispatchErrorImpl(aElapsedTime, aCharIndex, aError); } nsresult @@ -527,19 +529,22 @@ nsSpeechTask::DispatchErrorImpl(float aE if(NS_WARN_IF(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED)) { return NS_ERROR_NOT_AVAILABLE; } if (mSpeechSynthesis) { mSpeechSynthesis->OnEnd(this); } - mUtterance->mState = SpeechSynthesisUtterance::STATE_ENDED; - mUtterance->DispatchSpeechSynthesisErrorEvent(aCharIndex, aElapsedTime, - SpeechSynthesisErrorCode(aError)); + RefPtr<SpeechSynthesisUtterance> utterance = mUtterance; + utterance->mState = (utterance->mState == SpeechSynthesisUtterance::STATE_SPEAKING) ? + SpeechSynthesisUtterance::STATE_ENDED : SpeechSynthesisUtterance::STATE_NONE; + utterance->DispatchSpeechSynthesisErrorEvent(aCharIndex, aElapsedTime, + SpeechSynthesisErrorCode(aError)); + return NS_OK; } NS_IMETHODIMP nsSpeechTask::DispatchBoundary(const nsAString& aName, float aElapsedTime, uint32_t aCharIndex) { if (!mIndirectAudio) { @@ -655,17 +660,18 @@ nsSpeechTask::Cancel() mStream->Suspend(); } if (!mInited) { mPreCanceled = true; } if (!mIndirectAudio) { - DispatchEndInner(GetCurrentTime(), GetCurrentCharOffset()); + DispatchErrorInner(GetCurrentTime(), GetCurrentCharOffset(), + uint32_t(SpeechSynthesisErrorCode::Interrupted)); } } void nsSpeechTask::ForceEnd() { if (mStream) { mStream->Suspend();
--- a/dom/media/webspeech/synth/nsSpeechTask.h +++ b/dom/media/webspeech/synth/nsSpeechTask.h @@ -104,16 +104,18 @@ private: void End(); void SendAudioImpl(RefPtr<mozilla::SharedBuffer>& aSamples, uint32_t aDataLen); nsresult DispatchStartInner(); nsresult DispatchEndInner(float aElapsedTime, uint32_t aCharIndex); + nsresult DispatchErrorInner(float aElapsedTime, uint32_t aCharIndex, uint32_t aError); + void CreateAudioChannelAgent(); void DestroyAudioChannelAgent(); RefPtr<SourceMediaStream> mStream; RefPtr<MediaInputPort> mPort;
--- a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp +++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp @@ -3,16 +3,17 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "SpeechDispatcherService.h" #include "mozilla/dom/nsSpeechTask.h" #include "mozilla/dom/nsSynthVoiceRegistry.h" +#include "mozilla/dom/SpeechSynthesisErrorEvent.h" #include "mozilla/Preferences.h" #include "nsEscape.h" #include "nsISupports.h" #include "nsPrintfCString.h" #include "nsReadableUtils.h" #include "nsServiceManagerUtils.h" #include "nsThreadUtils.h" #include "prlink.h" @@ -246,16 +247,21 @@ SpeechDispatcherCallback::OnSpeechEvent( mTask->DispatchPause((TimeStamp::Now() - mStartTime).ToSeconds(), 0); break; case SPD_EVENT_RESUME: mTask->DispatchResume((TimeStamp::Now() - mStartTime).ToSeconds(), 0); break; case SPD_EVENT_CANCEL: + mTask->DispatchError((TimeStamp::Now() - mStartTime).ToSeconds(), 0, + uint32_t(SpeechSynthesisErrorCode::Interrupted)); + remove = true; + break; + case SPD_EVENT_END: mTask->DispatchEnd((TimeStamp::Now() - mStartTime).ToSeconds(), 0); remove = true; break; case SPD_EVENT_INDEX_MARK: // Not yet supported break;
--- a/dom/media/webspeech/synth/test/file_global_queue_cancel.html +++ b/dom/media/webspeech/synth/test/file_global_queue_cancel.html @@ -36,17 +36,17 @@ https://bugzilla.mozilla.org/show_bug.cg utterance2.lang = 'it-IT-noend'; var utterance3 = new win1.SpeechSynthesisUtterance("u3: hello, losers three"); var utterance4 = new win2.SpeechSynthesisUtterance("u4: hello, losers same!"); utterance4.lang = 'it-IT-noend'; var utterance5 = new win2.SpeechSynthesisUtterance("u5: hello, losers too"); utterance5.lang = 'it-IT-noend'; - var eventOrder = ['start1', 'end1', 'start2', 'end2']; + var eventOrder = ['start1', 'end1', 'start2', 'error2']; utterance1.addEventListener('start', function(e) { is(eventOrder.shift(), 'start1', 'start1'); testSynthState(win1, { speaking: true, pending: true }); testSynthState(win2, { speaking: true, pending: true }); win2.speechSynthesis.cancel(); SpecialPowers.wrap(win1.speechSynthesis).forceEnd(); }); @@ -56,18 +56,18 @@ https://bugzilla.mozilla.org/show_bug.cg testSynthState(win2, { pending: false }); }); utterance2.addEventListener('start', function(e) { is(eventOrder.shift(), 'start2', 'start2'); testSynthState(win1, { speaking: true, pending: true }); testSynthState(win2, { speaking: true, pending: false }); win1.speechSynthesis.cancel(); }); - utterance2.addEventListener('end', function(e) { - is(eventOrder.shift(), 'end2', 'end2'); + utterance2.addEventListener('error', function(e) { + is(eventOrder.shift(), 'error2', 'error2'); testSynthState(win1, { speaking: false, pending: false }); testSynthState(win2, { speaking: false, pending: false }); SimpleTest.finish(); }); function wrongUtterance(e) { ok(false, 'This shall not be uttered: "' + e.target.text + '"'); }
--- a/dom/media/webspeech/synth/test/file_indirect_service_events.html +++ b/dom/media/webspeech/synth/test/file_indirect_service_events.html @@ -45,17 +45,17 @@ function testFunc(done_cb) { }); utterance.addEventListener('resume', function(e) { is(e.charIndex, 1, 'resume event charIndex matches service arguments'); is(e.elapsedTime, 1.5, 'resume event elapsedTime matches service arguments'); speechSynthesis.cancel(); }); - utterance.addEventListener('end', function(e) { + utterance.addEventListener('error', function(e) { ok(e.charIndex, 1, 'resume event charIndex matches service arguments'); ok(e.elapsedTime, 1.5, 'end event elapsedTime matches service arguments'); test_no_events(); }); info('start speak'); speechSynthesis.speak(utterance); }
--- a/dom/media/webspeech/synth/test/file_speech_cancel.html +++ b/dom/media/webspeech/synth/test/file_speech_cancel.html @@ -22,17 +22,17 @@ https://bugzilla.mozilla.org/show_bug.cg </div> <pre id="test"> <script type="application/javascript"> /** Test for Bug 1150315 **/ function testFunc(done_cb) { - var gotEndEvent = false; + var gotErrorEvent = false; // A long utterance that we will interrupt. var utterance = new SpeechSynthesisUtterance("Donec ac nunc feugiat, posuere " + "mauris id, pharetra velit. Donec fermentum orci nunc, sit amet maximus" + "dui tincidunt ut. Sed ultricies ac nisi a laoreet. Proin interdum," + "libero maximus hendrerit posuere, lorem risus egestas nisl, a" + "ultricies massa justo eu nisi. Duis mattis nibh a ligula tincidunt" + "tincidunt non eu erat. Sed bibendum varius vulputate. Cras leo magna," + "ornare ac posuere vel, luctus id metus. Mauris nec quam ac augue" + @@ -58,23 +58,24 @@ function testFunc(done_cb) { "Curabitur velit lacus, mollis vel finibus et, molestie sit amet" + "sapien. Proin vitae dolor ac augue posuere efficitur ac scelerisque" + "diam. Nulla sed odio elit."); utterance2.addEventListener('start', function() { info('start'); speechSynthesis.cancel(); speechSynthesis.speak(utterance3); }); - utterance2.addEventListener('end', function(e) { - gotEndEvent = true; + utterance2.addEventListener('error', function(e) { + gotErrorEvent = true; + is(e.error, "interrupted", "Error event is has right error.") }); var utterance3 = new SpeechSynthesisUtterance("Hello, world 3!"); utterance3.addEventListener('start', function() { - ok(gotEndEvent, "didn't get start event for this utterance"); + ok(gotErrorEvent, "didn't get error event for previous utterance"); }); utterance3.addEventListener('end', done_cb); // Speak/cancel while paused (Bug 1187105) speechSynthesis.pause(); speechSynthesis.speak(new SpeechSynthesisUtterance("hello.")); ok(speechSynthesis.pending, "paused speechSynthesis has an utterance queued."); speechSynthesis.cancel();
--- a/dom/media/webspeech/synth/test/nsFakeSynthServices.cpp +++ b/dom/media/webspeech/synth/test/nsFakeSynthServices.cpp @@ -85,17 +85,18 @@ public: } return NS_OK; } NS_IMETHOD OnCancel() override { if (mTask) { - mTask->DispatchEnd(1.5, 1); + mTask->DispatchError(1.5, 1, + uint32_t(SpeechSynthesisErrorCode::Interrupted)); } return NS_OK; } NS_IMETHOD OnVolumeChanged(float aVolume) override { return NS_OK;
--- a/dom/media/webspeech/synth/windows/SapiService.cpp +++ b/dom/media/webspeech/synth/windows/SapiService.cpp @@ -8,16 +8,17 @@ #include "SapiService.h" #include "nsServiceManagerUtils.h" #include "nsWin32Locale.h" #include "GeckoProfiler.h" #include "nsEscape.h" #include "mozilla/dom/nsSynthVoiceRegistry.h" #include "mozilla/dom/nsSpeechTask.h" +#include "mozilla/dom/SpeechSynthesisErrorEvent.h" #include "mozilla/Preferences.h" namespace mozilla { namespace dom { StaticRefPtr<SapiService> SapiService::sSingleton; class SapiCallback final : public nsISpeechTaskCallback @@ -126,19 +127,23 @@ void SapiCallback::OnSpeechEvent(const SPEVENT& speechEvent) { switch (speechEvent.eEventId) { case SPEI_START_INPUT_STREAM: mTask->DispatchStart(); break; case SPEI_END_INPUT_STREAM: if (mSpeakTextLen) { + // mSpeakTextLen will be > 0 on any utterance except a cancel utterance. mCurrentIndex = mSpeakTextLen; + mTask->DispatchEnd(GetTickCount() - mStartingTime, mCurrentIndex); + } else { + mTask->DispatchError(GetTickCount() - mStartingTime, mCurrentIndex, + uint32_t(SpeechSynthesisErrorCode::Interrupted)); } - mTask->DispatchEnd(GetTickCount() - mStartingTime, mCurrentIndex); mTask = nullptr; break; case SPEI_TTS_BOOKMARK: mCurrentIndex = static_cast<ULONG>(speechEvent.lParam) - mTextOffset; mTask->DispatchBoundary(NS_LITERAL_STRING("mark"), GetTickCount() - mStartingTime, mCurrentIndex); break; case SPEI_WORD_BOUNDARY: