content/media/webspeech/synth/nsSpeechTask.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "AudioSegment.h"
michael@0 8 #include "nsSpeechTask.h"
michael@0 9 #include "SpeechSynthesis.h"
michael@0 10
michael@0 11 // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
michael@0 12 // GetTickCount() and conflicts with nsSpeechTask::GetCurrentTime().
michael@0 13 #ifdef GetCurrentTime
michael@0 14 #undef GetCurrentTime
michael@0 15 #endif
michael@0 16
michael@0 17 #undef LOG
michael@0 18 #ifdef PR_LOGGING
michael@0 19 extern PRLogModuleInfo* GetSpeechSynthLog();
michael@0 20 #define LOG(type, msg) PR_LOG(GetSpeechSynthLog(), type, msg)
michael@0 21 #else
michael@0 22 #define LOG(type, msg)
michael@0 23 #endif
michael@0 24
michael@0 25 namespace mozilla {
michael@0 26 namespace dom {
michael@0 27
michael@0 28 class SynthStreamListener : public MediaStreamListener
michael@0 29 {
michael@0 30 public:
michael@0 31 SynthStreamListener(nsSpeechTask* aSpeechTask) :
michael@0 32 mSpeechTask(aSpeechTask),
michael@0 33 mStarted(false)
michael@0 34 {
michael@0 35 }
michael@0 36
michael@0 37 void DoNotifyStarted()
michael@0 38 {
michael@0 39 if (mSpeechTask) {
michael@0 40 mSpeechTask->DispatchStartImpl();
michael@0 41 }
michael@0 42 }
michael@0 43
michael@0 44 void DoNotifyFinished()
michael@0 45 {
michael@0 46 if (mSpeechTask) {
michael@0 47 mSpeechTask->DispatchEndImpl(mSpeechTask->GetCurrentTime(),
michael@0 48 mSpeechTask->GetCurrentCharOffset());
michael@0 49 }
michael@0 50 }
michael@0 51
michael@0 52 virtual void NotifyFinished(MediaStreamGraph* aGraph)
michael@0 53 {
michael@0 54 nsCOMPtr<nsIRunnable> event =
michael@0 55 NS_NewRunnableMethod(this, &SynthStreamListener::DoNotifyFinished);
michael@0 56 aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
michael@0 57 }
michael@0 58
michael@0 59 virtual void NotifyBlockingChanged(MediaStreamGraph* aGraph, Blocking aBlocked)
michael@0 60 {
michael@0 61 if (aBlocked == MediaStreamListener::UNBLOCKED && !mStarted) {
michael@0 62 mStarted = true;
michael@0 63 nsCOMPtr<nsIRunnable> event =
michael@0 64 NS_NewRunnableMethod(this, &SynthStreamListener::DoNotifyStarted);
michael@0 65 aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
michael@0 66 }
michael@0 67 }
michael@0 68
michael@0 69 virtual void NotifyRemoved(MediaStreamGraph* aGraph)
michael@0 70 {
michael@0 71 mSpeechTask = nullptr;
michael@0 72 }
michael@0 73
michael@0 74 private:
michael@0 75 // Raw pointer; if we exist, the stream exists,
michael@0 76 // and 'mSpeechTask' exclusively owns it and therefor exists as well.
michael@0 77 nsSpeechTask* mSpeechTask;
michael@0 78
michael@0 79 bool mStarted;
michael@0 80 };
michael@0 81
michael@0 82 // nsSpeechTask
michael@0 83
michael@0 84 NS_IMPL_CYCLE_COLLECTION(nsSpeechTask, mSpeechSynthesis, mUtterance);
michael@0 85
michael@0 86 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSpeechTask)
michael@0 87 NS_INTERFACE_MAP_ENTRY(nsISpeechTask)
michael@0 88 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechTask)
michael@0 89 NS_INTERFACE_MAP_END
michael@0 90
michael@0 91 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSpeechTask)
michael@0 92 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSpeechTask)
michael@0 93
michael@0 94 nsSpeechTask::nsSpeechTask(SpeechSynthesisUtterance* aUtterance)
michael@0 95 : mUtterance(aUtterance)
michael@0 96 , mCallback(nullptr)
michael@0 97 , mIndirectAudio(false)
michael@0 98 {
michael@0 99 mText = aUtterance->mText;
michael@0 100 mVolume = aUtterance->Volume();
michael@0 101 }
michael@0 102
michael@0 103 nsSpeechTask::nsSpeechTask(float aVolume, const nsAString& aText)
michael@0 104 : mUtterance(nullptr)
michael@0 105 , mVolume(aVolume)
michael@0 106 , mText(aText)
michael@0 107 , mCallback(nullptr)
michael@0 108 , mIndirectAudio(false)
michael@0 109 {
michael@0 110 }
michael@0 111
michael@0 112 nsSpeechTask::~nsSpeechTask()
michael@0 113 {
michael@0 114 if (mStream) {
michael@0 115 if (!mStream->IsDestroyed()) {
michael@0 116 mStream->Destroy();
michael@0 117 }
michael@0 118
michael@0 119 mStream = nullptr;
michael@0 120 }
michael@0 121 }
michael@0 122
michael@0 123 NS_IMETHODIMP
michael@0 124 nsSpeechTask::Setup(nsISpeechTaskCallback* aCallback,
michael@0 125 uint32_t aChannels, uint32_t aRate, uint8_t argc)
michael@0 126 {
michael@0 127 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
michael@0 128
michael@0 129 LOG(PR_LOG_DEBUG, ("nsSpeechTask::Setup"));
michael@0 130
michael@0 131 mCallback = aCallback;
michael@0 132
michael@0 133 if (argc < 2) {
michael@0 134 return NS_OK;
michael@0 135 }
michael@0 136
michael@0 137 if (mIndirectAudio) {
michael@0 138 NS_WARNING("Audio info arguments in Setup() are ignored for indirect audio services.");
michael@0 139 }
michael@0 140
michael@0 141 // XXX: Is there setup overhead here that hurtls latency?
michael@0 142 mStream = MediaStreamGraph::GetInstance()->CreateSourceStream(nullptr);
michael@0 143 mStream->AddListener(new SynthStreamListener(this));
michael@0 144
michael@0 145 // XXX: Support more than one channel
michael@0 146 NS_ENSURE_TRUE(aChannels == 1, NS_ERROR_FAILURE);
michael@0 147
michael@0 148 mChannels = aChannels;
michael@0 149
michael@0 150 AudioSegment* segment = new AudioSegment();
michael@0 151 mStream->AddTrack(1, aRate, 0, segment);
michael@0 152 mStream->AddAudioOutput(this);
michael@0 153 mStream->SetAudioOutputVolume(this, mVolume);
michael@0 154
michael@0 155 return NS_OK;
michael@0 156 }
michael@0 157
michael@0 158 NS_IMETHODIMP
michael@0 159 nsSpeechTask::SendAudio(JS::Handle<JS::Value> aData, JS::Handle<JS::Value> aLandmarks,
michael@0 160 JSContext* aCx)
michael@0 161 {
michael@0 162 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
michael@0 163
michael@0 164 NS_ENSURE_TRUE(mStream, NS_ERROR_NOT_AVAILABLE);
michael@0 165 NS_ENSURE_FALSE(mStream->IsDestroyed(), NS_ERROR_NOT_AVAILABLE);
michael@0 166 NS_ENSURE_TRUE(mChannels, NS_ERROR_FAILURE);
michael@0 167
michael@0 168 if (mIndirectAudio) {
michael@0 169 NS_WARNING("Can't call SendAudio from an indirect audio speech service.");
michael@0 170 return NS_ERROR_FAILURE;
michael@0 171 }
michael@0 172
michael@0 173 JS::Rooted<JSObject*> darray(aCx, &aData.toObject());
michael@0 174 JSAutoCompartment ac(aCx, darray);
michael@0 175
michael@0 176 JS::Rooted<JSObject*> tsrc(aCx, nullptr);
michael@0 177
michael@0 178 // Allow either Int16Array or plain JS Array
michael@0 179 if (JS_IsInt16Array(darray)) {
michael@0 180 tsrc = darray;
michael@0 181 } else if (JS_IsArrayObject(aCx, darray)) {
michael@0 182 tsrc = JS_NewInt16ArrayFromArray(aCx, darray);
michael@0 183 }
michael@0 184
michael@0 185 if (!tsrc) {
michael@0 186 return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
michael@0 187 }
michael@0 188
michael@0 189 SendAudioImpl(JS_GetInt16ArrayData(tsrc),
michael@0 190 JS_GetTypedArrayLength(tsrc));
michael@0 191
michael@0 192 return NS_OK;
michael@0 193 }
michael@0 194
michael@0 195 NS_IMETHODIMP
michael@0 196 nsSpeechTask::SendAudioNative(int16_t* aData, uint32_t aDataLen)
michael@0 197 {
michael@0 198 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
michael@0 199
michael@0 200 NS_ENSURE_TRUE(mStream, NS_ERROR_NOT_AVAILABLE);
michael@0 201 NS_ENSURE_FALSE(mStream->IsDestroyed(), NS_ERROR_NOT_AVAILABLE);
michael@0 202 NS_ENSURE_TRUE(mChannels, NS_ERROR_FAILURE);
michael@0 203
michael@0 204 if (mIndirectAudio) {
michael@0 205 NS_WARNING("Can't call SendAudio from an indirect audio speech service.");
michael@0 206 return NS_ERROR_FAILURE;
michael@0 207 }
michael@0 208
michael@0 209 SendAudioImpl(aData, aDataLen);
michael@0 210
michael@0 211 return NS_OK;
michael@0 212 }
michael@0 213
michael@0 214 void
michael@0 215 nsSpeechTask::SendAudioImpl(int16_t* aData, uint32_t aDataLen)
michael@0 216 {
michael@0 217 if (aDataLen == 0) {
michael@0 218 mStream->EndAllTrackAndFinish();
michael@0 219 return;
michael@0 220 }
michael@0 221
michael@0 222 nsRefPtr<mozilla::SharedBuffer> samples =
michael@0 223 SharedBuffer::Create(aDataLen * sizeof(int16_t));
michael@0 224 int16_t* frames = static_cast<int16_t*>(samples->Data());
michael@0 225
michael@0 226 for (uint32_t i = 0; i < aDataLen; i++) {
michael@0 227 frames[i] = aData[i];
michael@0 228 }
michael@0 229
michael@0 230 AudioSegment segment;
michael@0 231 nsAutoTArray<const int16_t*, 1> channelData;
michael@0 232 channelData.AppendElement(frames);
michael@0 233 segment.AppendFrames(samples.forget(), channelData, aDataLen);
michael@0 234 mStream->AppendToTrack(1, &segment);
michael@0 235 mStream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
michael@0 236 }
michael@0 237
michael@0 238 NS_IMETHODIMP
michael@0 239 nsSpeechTask::DispatchStart()
michael@0 240 {
michael@0 241 if (!mIndirectAudio) {
michael@0 242 NS_WARNING("Can't call DispatchStart() from a direct audio speech service");
michael@0 243 return NS_ERROR_FAILURE;
michael@0 244 }
michael@0 245
michael@0 246 return DispatchStartImpl();
michael@0 247 }
michael@0 248
michael@0 249 nsresult
michael@0 250 nsSpeechTask::DispatchStartImpl()
michael@0 251 {
michael@0 252 LOG(PR_LOG_DEBUG, ("nsSpeechTask::DispatchStart"));
michael@0 253
michael@0 254 MOZ_ASSERT(mUtterance);
michael@0 255 NS_ENSURE_TRUE(mUtterance->mState == SpeechSynthesisUtterance::STATE_PENDING,
michael@0 256 NS_ERROR_NOT_AVAILABLE);
michael@0 257
michael@0 258 mUtterance->mState = SpeechSynthesisUtterance::STATE_SPEAKING;
michael@0 259 mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("start"), 0, 0,
michael@0 260 NS_LITERAL_STRING(""));
michael@0 261
michael@0 262 return NS_OK;
michael@0 263 }
michael@0 264
michael@0 265 NS_IMETHODIMP
michael@0 266 nsSpeechTask::DispatchEnd(float aElapsedTime, uint32_t aCharIndex)
michael@0 267 {
michael@0 268 if (!mIndirectAudio) {
michael@0 269 NS_WARNING("Can't call DispatchEnd() from a direct audio speech service");
michael@0 270 return NS_ERROR_FAILURE;
michael@0 271 }
michael@0 272
michael@0 273 return DispatchEndImpl(aElapsedTime, aCharIndex);
michael@0 274 }
michael@0 275
michael@0 276 nsresult
michael@0 277 nsSpeechTask::DispatchEndImpl(float aElapsedTime, uint32_t aCharIndex)
michael@0 278 {
michael@0 279 LOG(PR_LOG_DEBUG, ("nsSpeechTask::DispatchEnd\n"));
michael@0 280
michael@0 281 MOZ_ASSERT(mUtterance);
michael@0 282 NS_ENSURE_FALSE(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED,
michael@0 283 NS_ERROR_NOT_AVAILABLE);
michael@0 284
michael@0 285 // XXX: This should not be here, but it prevents a crash in MSG.
michael@0 286 if (mStream) {
michael@0 287 mStream->Destroy();
michael@0 288 }
michael@0 289
michael@0 290 nsRefPtr<SpeechSynthesisUtterance> utterance = mUtterance;
michael@0 291
michael@0 292 if (mSpeechSynthesis) {
michael@0 293 mSpeechSynthesis->OnEnd(this);
michael@0 294 }
michael@0 295
michael@0 296 if (utterance->mState == SpeechSynthesisUtterance::STATE_PENDING) {
michael@0 297 utterance->mState = SpeechSynthesisUtterance::STATE_NONE;
michael@0 298 } else {
michael@0 299 utterance->mState = SpeechSynthesisUtterance::STATE_ENDED;
michael@0 300 utterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("end"),
michael@0 301 aCharIndex, aElapsedTime,
michael@0 302 EmptyString());
michael@0 303 }
michael@0 304
michael@0 305 return NS_OK;
michael@0 306 }
michael@0 307
michael@0 308 NS_IMETHODIMP
michael@0 309 nsSpeechTask::DispatchPause(float aElapsedTime, uint32_t aCharIndex)
michael@0 310 {
michael@0 311 if (!mIndirectAudio) {
michael@0 312 NS_WARNING("Can't call DispatchPause() from a direct audio speech service");
michael@0 313 return NS_ERROR_FAILURE;
michael@0 314 }
michael@0 315
michael@0 316 return DispatchPauseImpl(aElapsedTime, aCharIndex);
michael@0 317 }
michael@0 318
michael@0 319 nsresult
michael@0 320 nsSpeechTask::DispatchPauseImpl(float aElapsedTime, uint32_t aCharIndex)
michael@0 321 {
michael@0 322 LOG(PR_LOG_DEBUG, ("nsSpeechTask::DispatchPause"));
michael@0 323 MOZ_ASSERT(mUtterance);
michael@0 324 NS_ENSURE_FALSE(mUtterance->mPaused, NS_ERROR_NOT_AVAILABLE);
michael@0 325 NS_ENSURE_FALSE(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED,
michael@0 326 NS_ERROR_NOT_AVAILABLE);
michael@0 327
michael@0 328 mUtterance->mPaused = true;
michael@0 329 mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("pause"),
michael@0 330 aCharIndex, aElapsedTime,
michael@0 331 NS_LITERAL_STRING(""));
michael@0 332 return NS_OK;
michael@0 333 }
michael@0 334
michael@0 335 NS_IMETHODIMP
michael@0 336 nsSpeechTask::DispatchResume(float aElapsedTime, uint32_t aCharIndex)
michael@0 337 {
michael@0 338 if (!mIndirectAudio) {
michael@0 339 NS_WARNING("Can't call DispatchResume() from a direct audio speech service");
michael@0 340 return NS_ERROR_FAILURE;
michael@0 341 }
michael@0 342
michael@0 343 return DispatchResumeImpl(aElapsedTime, aCharIndex);
michael@0 344 }
michael@0 345
michael@0 346 nsresult
michael@0 347 nsSpeechTask::DispatchResumeImpl(float aElapsedTime, uint32_t aCharIndex)
michael@0 348 {
michael@0 349 LOG(PR_LOG_DEBUG, ("nsSpeechTask::DispatchResume"));
michael@0 350 MOZ_ASSERT(mUtterance);
michael@0 351 NS_ENSURE_TRUE(mUtterance->mPaused, NS_ERROR_NOT_AVAILABLE);
michael@0 352 NS_ENSURE_FALSE(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED,
michael@0 353 NS_ERROR_NOT_AVAILABLE);
michael@0 354
michael@0 355 mUtterance->mPaused = false;
michael@0 356 mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("resume"),
michael@0 357 aCharIndex, aElapsedTime,
michael@0 358 NS_LITERAL_STRING(""));
michael@0 359 return NS_OK;
michael@0 360 }
michael@0 361
michael@0 362 NS_IMETHODIMP
michael@0 363 nsSpeechTask::DispatchError(float aElapsedTime, uint32_t aCharIndex)
michael@0 364 {
michael@0 365 if (!mIndirectAudio) {
michael@0 366 NS_WARNING("Can't call DispatchError() from a direct audio speech service");
michael@0 367 return NS_ERROR_FAILURE;
michael@0 368 }
michael@0 369
michael@0 370 return DispatchErrorImpl(aElapsedTime, aCharIndex);
michael@0 371 }
michael@0 372
michael@0 373 nsresult
michael@0 374 nsSpeechTask::DispatchErrorImpl(float aElapsedTime, uint32_t aCharIndex)
michael@0 375 {
michael@0 376 MOZ_ASSERT(mUtterance);
michael@0 377 NS_ENSURE_FALSE(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED,
michael@0 378 NS_ERROR_NOT_AVAILABLE);
michael@0 379
michael@0 380 mUtterance->mState = SpeechSynthesisUtterance::STATE_ENDED;
michael@0 381 mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("error"),
michael@0 382 aCharIndex, aElapsedTime,
michael@0 383 NS_LITERAL_STRING(""));
michael@0 384 return NS_OK;
michael@0 385 }
michael@0 386
michael@0 387 NS_IMETHODIMP
michael@0 388 nsSpeechTask::DispatchBoundary(const nsAString& aName,
michael@0 389 float aElapsedTime, uint32_t aCharIndex)
michael@0 390 {
michael@0 391 if (!mIndirectAudio) {
michael@0 392 NS_WARNING("Can't call DispatchBoundary() from a direct audio speech service");
michael@0 393 return NS_ERROR_FAILURE;
michael@0 394 }
michael@0 395
michael@0 396 return DispatchBoundaryImpl(aName, aElapsedTime, aCharIndex);
michael@0 397 }
michael@0 398
michael@0 399 nsresult
michael@0 400 nsSpeechTask::DispatchBoundaryImpl(const nsAString& aName,
michael@0 401 float aElapsedTime, uint32_t aCharIndex)
michael@0 402 {
michael@0 403 MOZ_ASSERT(mUtterance);
michael@0 404 NS_ENSURE_TRUE(mUtterance->mState == SpeechSynthesisUtterance::STATE_SPEAKING,
michael@0 405 NS_ERROR_NOT_AVAILABLE);
michael@0 406
michael@0 407 mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("boundary"),
michael@0 408 aCharIndex, aElapsedTime,
michael@0 409 aName);
michael@0 410 return NS_OK;
michael@0 411 }
michael@0 412
michael@0 413 NS_IMETHODIMP
michael@0 414 nsSpeechTask::DispatchMark(const nsAString& aName,
michael@0 415 float aElapsedTime, uint32_t aCharIndex)
michael@0 416 {
michael@0 417 if (!mIndirectAudio) {
michael@0 418 NS_WARNING("Can't call DispatchMark() from a direct audio speech service");
michael@0 419 return NS_ERROR_FAILURE;
michael@0 420 }
michael@0 421
michael@0 422 return DispatchMarkImpl(aName, aElapsedTime, aCharIndex);
michael@0 423 }
michael@0 424
michael@0 425 nsresult
michael@0 426 nsSpeechTask::DispatchMarkImpl(const nsAString& aName,
michael@0 427 float aElapsedTime, uint32_t aCharIndex)
michael@0 428 {
michael@0 429 MOZ_ASSERT(mUtterance);
michael@0 430 NS_ENSURE_TRUE(mUtterance->mState == SpeechSynthesisUtterance::STATE_SPEAKING,
michael@0 431 NS_ERROR_NOT_AVAILABLE);
michael@0 432
michael@0 433 mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("mark"),
michael@0 434 aCharIndex, aElapsedTime,
michael@0 435 aName);
michael@0 436 return NS_OK;
michael@0 437 }
michael@0 438
michael@0 439 void
michael@0 440 nsSpeechTask::Pause()
michael@0 441 {
michael@0 442 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
michael@0 443
michael@0 444 if (mUtterance->IsPaused() ||
michael@0 445 mUtterance->GetState() == SpeechSynthesisUtterance::STATE_ENDED) {
michael@0 446 return;
michael@0 447 }
michael@0 448
michael@0 449 if (mCallback) {
michael@0 450 DebugOnly<nsresult> rv = mCallback->OnPause();
michael@0 451 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Unable to call onPause() callback");
michael@0 452 }
michael@0 453
michael@0 454 if (mStream) {
michael@0 455 mStream->ChangeExplicitBlockerCount(1);
michael@0 456 }
michael@0 457
michael@0 458 DispatchPauseImpl(GetCurrentTime(), GetCurrentCharOffset());
michael@0 459 }
michael@0 460
michael@0 461 void
michael@0 462 nsSpeechTask::Resume()
michael@0 463 {
michael@0 464 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
michael@0 465
michael@0 466 if (!mUtterance->IsPaused()) {
michael@0 467 return;
michael@0 468 }
michael@0 469
michael@0 470 if (mCallback) {
michael@0 471 DebugOnly<nsresult> rv = mCallback->OnResume();
michael@0 472 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Unable to call onResume() callback");
michael@0 473 }
michael@0 474
michael@0 475 if (mStream) {
michael@0 476 mStream->ChangeExplicitBlockerCount(-1);
michael@0 477 }
michael@0 478
michael@0 479 DispatchResumeImpl(GetCurrentTime(), GetCurrentCharOffset());
michael@0 480 }
michael@0 481
michael@0 482 void
michael@0 483 nsSpeechTask::Cancel()
michael@0 484 {
michael@0 485 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
michael@0 486
michael@0 487 LOG(PR_LOG_DEBUG, ("nsSpeechTask::Cancel"));
michael@0 488
michael@0 489 if (mCallback) {
michael@0 490 DebugOnly<nsresult> rv = mCallback->OnCancel();
michael@0 491 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Unable to call onCancel() callback");
michael@0 492 }
michael@0 493
michael@0 494 if (mStream) {
michael@0 495 mStream->ChangeExplicitBlockerCount(1);
michael@0 496 }
michael@0 497
michael@0 498 DispatchEndImpl(GetCurrentTime(), GetCurrentCharOffset());
michael@0 499 }
michael@0 500
michael@0 501 float
michael@0 502 nsSpeechTask::GetCurrentTime()
michael@0 503 {
michael@0 504 return mStream ? (float)(mStream->GetCurrentTime() / 1000000.0) : 0;
michael@0 505 }
michael@0 506
michael@0 507 uint32_t
michael@0 508 nsSpeechTask::GetCurrentCharOffset()
michael@0 509 {
michael@0 510 return mStream && mStream->IsFinished() ? mText.Length() : 0;
michael@0 511 }
michael@0 512
michael@0 513 void
michael@0 514 nsSpeechTask::SetSpeechSynthesis(SpeechSynthesis* aSpeechSynthesis)
michael@0 515 {
michael@0 516 mSpeechSynthesis = aSpeechSynthesis;
michael@0 517 }
michael@0 518
michael@0 519 } // namespace dom
michael@0 520 } // namespace mozilla

mercurial