void DecoderCallbackFuzzingWrapper::InputExhausted() { if (!mTaskQueue->IsCurrentThreadIn()) { nsCOMPtr<nsIRunnable> task = NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::InputExhausted); mTaskQueue->Dispatch(task.forget()); return; } if (!mDontDelayInputExhausted && !mDelayedOutput.empty()) { MediaDataAndInputExhausted& last = mDelayedOutput.back(); CFW_LOGD("InputExhausted delayed until after output of [email protected]%lld", last.first()->mTime); last.second() = true; return; } CFW_LOGV(""); MOZ_ASSERT(mCallback); mCallback->InputExhausted(); }
void DecoderCallbackFuzzingWrapper::DrainComplete() { if (!mTaskQueue->IsCurrentThreadIn()) { nsCOMPtr<nsIRunnable> task = NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::DrainComplete); mTaskQueue->Dispatch(task.forget()); return; } MOZ_ASSERT(mCallback); if (mDelayedOutput.empty()) { // No queued output -> Draining is complete now. CFW_LOGV("No delayed output -> DrainComplete now"); mCallback->DrainComplete(); } else { // Queued output waiting -> Make sure we call DrainComplete when it's empty. CFW_LOGD("Delayed output -> DrainComplete later"); mDraining = true; } }
nsresult LazyIdleThread::EnsureThread() { ASSERT_OWNING_THREAD(); if (mShutdown) { return NS_ERROR_UNEXPECTED; } if (mThread) { return NS_OK; } MOZ_ASSERT(!mPendingEventCount, "Shouldn't have events yet!"); MOZ_ASSERT(!mIdleNotificationCount, "Shouldn't have idle events yet!"); MOZ_ASSERT(!mIdleTimer, "Should have killed this long ago!"); MOZ_ASSERT(!mThreadIsShuttingDown, "Should have cleared that!"); nsresult rv; if (mShutdownMethod == AutomaticShutdown && NS_IsMainThread()) { nsCOMPtr<nsIObserverService> obs = do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = obs->AddObserver(this, "xpcom-shutdown-threads", false); NS_ENSURE_SUCCESS(rv, rv); } mIdleTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); NS_ENSURE_TRUE(mIdleTimer, NS_ERROR_FAILURE); nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableMethod(this, &LazyIdleThread::InitThread); NS_ENSURE_TRUE(runnable, NS_ERROR_FAILURE); rv = NS_NewThread(getter_AddRefs(mThread), runnable); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
NS_IMETHODIMP_(MozExternalRefCountType) SharedThreadPool::Release(void) { MOZ_ASSERT(sMonitor); bool dispatchShutdownEvent; { ReentrantMonitorAutoEnter mon(*sMonitor); nsrefcnt count = --mRefCnt; NS_LOG_RELEASE(this, count, "SharedThreadPool"); if (count) { return count; } // Zero refcount. Must shutdown and then delete the thread pool. // First, dispatch an event to the main thread to call Shutdown() on // the nsIThreadPool. The Runnable here will add a refcount to the pool, // and when the Runnable releases the nsIThreadPool it will be deleted. RefPtr<nsIRunnable> r = NS_NewRunnableMethod(mPool, &nsIThreadPool::Shutdown); NS_DispatchToMainThread(r); // Remove SharedThreadPool from table of pools. sPools->Remove(mName); MOZ_ASSERT(!sPools->Get(mName)); // Stabilize refcount, so that if something in the dtor QIs, // it won't explode. mRefCnt = 1; delete this; dispatchShutdownEvent = sPools->Count() == 0; } if (dispatchShutdownEvent) { // No more SharedThreadPools alive. Destroy the hash table. // Ensure that we only run on the main thread. // Do this in an event so that if something holds the monitor we won't // be deleting the monitor while it's held. NS_DispatchToMainThread(new ShutdownPoolsEvent()); } return 0; }
nsresult AudioSink::Init() { nsresult rv = NS_NewNamedThread("Media Audio", getter_AddRefs(mThread), nullptr, MEDIA_THREAD_STACK_SIZE); if (NS_FAILED(rv)) { mStateMachine->OnAudioSinkError(); return rv; } nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &AudioSink::AudioLoop); rv = mThread->Dispatch(event, NS_DISPATCH_NORMAL); if (NS_FAILED(rv)) { mStateMachine->OnAudioSinkError(); return rv; } return NS_OK; }
nsresult MediaCodecDataDecoder::InitDecoder(Surface::Param aSurface) { mDecoder = CreateDecoder(mMimeType); if (!mDecoder) { INVOKE_CALLBACK(Error); return NS_ERROR_FAILURE; } nsresult rv; NS_ENSURE_SUCCESS(rv = mDecoder->Configure(mFormat, aSurface, nullptr, 0), rv); NS_ENSURE_SUCCESS(rv = mDecoder->Start(), rv); NS_ENSURE_SUCCESS(rv = ResetInputBuffers(), rv); NS_ENSURE_SUCCESS(rv = ResetOutputBuffers(), rv); NS_NewNamedThread("MC Decoder", getter_AddRefs(mThread), NS_NewRunnableMethod(this, &MediaCodecDataDecoder::DecoderLoop)); return NS_OK; }
// Called on the control thread. nsresult BackgroundFileSaver::GetWorkerThreadAttention(bool aShouldInterruptCopy) { nsresult rv; MutexAutoLock lock(mLock); // We only require attention one time. If this function is called two times // before the worker thread wakes up, and the first has aShouldInterruptCopy // false and the second true, we won't forcibly interrupt the copy from the // control thread. However, that never happens, because calling Finish with a // success code is the only case that may result in aShouldInterruptCopy being // false. In that case, we won't call this function again, because consumers // should not invoke other methods on the control thread after calling Finish. // And in any case, Finish already closes one end of the pipe, causing the // copy to finish properly on its own. if (mWorkerThreadAttentionRequested) { return NS_OK; } if (!mAsyncCopyContext) { // Copy is not in progress, post an event to handle the change manually. nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &BackgroundFileSaver::ProcessAttention); NS_ENSURE_TRUE(event, NS_ERROR_FAILURE); rv = mWorkerThread->Dispatch(event, NS_DISPATCH_NORMAL); NS_ENSURE_SUCCESS(rv, rv); } else if (aShouldInterruptCopy) { // Interrupt the copy. The copy will be resumed, if needed, by the // ProcessAttention function, invoked by the AsyncCopyCallback function. NS_CancelAsyncCopy(mAsyncCopyContext, NS_ERROR_ABORT); } // Indicate that attention has been requested successfully, there is no need // to post another event until the worker thread processes the current one. mWorkerThreadAttentionRequested = true; return NS_OK; }
void CacheStorageService::OnMemoryConsumptionChange(CacheMemoryConsumer* aConsumer, uint32_t aCurrentMemoryConsumption) { LOG(("CacheStorageService::OnMemoryConsumptionChange [consumer=%p, size=%u]", aConsumer, aCurrentMemoryConsumption)); uint32_t savedMemorySize = aConsumer->mReportedMemoryConsumption; if (savedMemorySize == aCurrentMemoryConsumption) return; // Exchange saved size with current one. aConsumer->mReportedMemoryConsumption = aCurrentMemoryConsumption; mMemorySize -= savedMemorySize; mMemorySize += aCurrentMemoryConsumption; LOG((" mMemorySize=%u (+%u,-%u)", uint32_t(mMemorySize), aCurrentMemoryConsumption, savedMemorySize)); // Bypass purging when memory has not grew up significantly if (aCurrentMemoryConsumption <= savedMemorySize) return; if (mPurging) { LOG((" already purging")); return; } if (mMemorySize <= CacheObserver::MemoryLimit()) return; // Throw the oldest data or whole entries away when over certain limits mPurging = true; // Must always dipatch, since this can be called under e.g. a CacheFile's lock. nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &CacheStorageService::PurgeOverMemoryLimit); Dispatch(event); }
nsRefPtr<GenericPromise> AudioSink::Init() { nsRefPtr<GenericPromise> p = mEndPromise.Ensure(__func__); nsresult rv = NS_NewNamedThread("Media Audio", getter_AddRefs(mThread), nullptr, MEDIA_THREAD_STACK_SIZE); if (NS_FAILED(rv)) { mEndPromise.Reject(rv, __func__); return p; } nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &AudioSink::AudioLoop); rv = mThread->Dispatch(event, NS_DISPATCH_NORMAL); if (NS_FAILED(rv)) { mEndPromise.Reject(rv, __func__); return p; } return p; }
nsresult MediaSourceDecoder::SetCDMProxy(CDMProxy* aProxy) { nsresult rv = MediaDecoder::SetCDMProxy(aProxy); NS_ENSURE_SUCCESS(rv, rv); rv = mReader->SetCDMProxy(aProxy); NS_ENSURE_SUCCESS(rv, rv); if (aProxy) { // The sub readers can't decrypt EME content until they have a CDMProxy, // and the CDMProxy knows the capabilities of the CDM. The MediaSourceReader // remains in "waiting for resources" state until then. We need to kick the // reader out of waiting if the CDM gets added with known capabilities. CDMCaps::AutoLock caps(aProxy->Capabilites()); if (!caps.AreCapsKnown()) { nsCOMPtr<nsIRunnable> task( NS_NewRunnableMethod(this, &MediaDecoder::NotifyWaitingForResourcesStatusChanged)); caps.CallOnMainThreadWhenCapsAvailable(task); } } return NS_OK; }
NS_IMETHODIMP LazyIdleThread::AfterProcessNextEvent(nsIThreadInternal* /* aThread */, uint32_t /* aRecursionDepth */, bool aEventWasProcessed) { bool shouldNotifyIdle; { MutexAutoLock lock(mMutex); if (aEventWasProcessed) { MOZ_ASSERT(mPendingEventCount, "Mismatched calls to observer methods!"); --mPendingEventCount; } if (mThreadIsShuttingDown) { // We're shutting down, no need to fire any timer. return NS_OK; } shouldNotifyIdle = !mPendingEventCount; if (shouldNotifyIdle) { MOZ_ASSERT(mIdleNotificationCount < UINT32_MAX, "Way too many!"); mIdleNotificationCount++; } } if (shouldNotifyIdle) { nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableMethod(this, &LazyIdleThread::ScheduleTimer); if (NS_WARN_IF(!runnable)) return NS_ERROR_UNEXPECTED; nsresult rv = mOwningThread->Dispatch(runnable, NS_DISPATCH_NORMAL); if (NS_WARN_IF(NS_FAILED(rv))) return rv; } return NS_OK; }
void CacheStorageService::Shutdown() { if (mShutdown) return; LOG(("CacheStorageService::Shutdown - start")); mShutdown = true; nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &CacheStorageService::ShutdownBackground); if (mThread) mThread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); mozilla::MutexAutoLock lock(mLock); sGlobalEntryTables->Clear(); delete sGlobalEntryTables; sGlobalEntryTables = nullptr; LOG(("CacheStorageService::Shutdown - done")); }
void Tickler::MaybeStartTickler() { mLock.AssertCurrentThreadOwns(); if (!NS_IsMainThread()) { NS_DispatchToMainThread( NS_NewRunnableMethod(this, &Tickler::MaybeStartTicklerUnlocked), NS_DISPATCH_NORMAL); return; } if (!mPrefs) mPrefs = do_GetService(NS_PREFSERVICE_CONTRACTID); if (mPrefs) { int32_t val; bool boolVal; if (NS_SUCCEEDED(mPrefs->GetBoolPref("network.tickle-wifi.enabled", &boolVal))) mEnabled = boolVal; if (NS_SUCCEEDED(mPrefs->GetIntPref("network.tickle-wifi.duration", &val))) { if (val < 1) val = 1; if (val > 100000) val = 100000; mDuration = TimeDuration::FromMilliseconds(val); } if (NS_SUCCEEDED(mPrefs->GetIntPref("network.tickle-wifi.delay", &val))) { if (val < 1) val = 1; if (val > 1000) val = 1000; mDelay = static_cast<uint32_t>(val); } } PostCheckTickler(); }
void CacheStorageService::OnMemoryConsumptionChange(CacheMemoryConsumer* aConsumer, uint32_t aCurrentMemoryConsumption) { LOG(("CacheStorageService::OnMemoryConsumptionChange [consumer=%p, size=%u]", aConsumer, aCurrentMemoryConsumption)); uint32_t savedMemorySize = aConsumer->mReportedMemoryConsumption; if (savedMemorySize == aCurrentMemoryConsumption) return; // Exchange saved size with current one. aConsumer->mReportedMemoryConsumption = aCurrentMemoryConsumption; bool usingDisk = !(aConsumer->mFlags & CacheMemoryConsumer::MEMORY_ONLY); bool overLimit = Pool(usingDisk).OnMemoryConsumptionChange( savedMemorySize, aCurrentMemoryConsumption); if (!overLimit) return; // It's likely the timer has already been set when we get here, // check outside the lock to save resources. if (mPurgeTimer) return; // We don't know if this is called under the service lock or not, // hence rather dispatch. nsRefPtr<nsIEventTarget> cacheIOTarget = Thread(); if (!cacheIOTarget) return; // Dispatch as a priority task, we want to set the purge timer // ASAP to prevent vain redispatch of this event. nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &CacheStorageService::SchedulePurgeOverMemoryLimit); cacheIOTarget->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); }
void MediaSourceDecoder::ScheduleDurationChange(double aOldDuration, double aNewDuration, MSRangeRemovalAction aAction) { if (aAction == MSRangeRemovalAction::SKIP) { if (NS_IsMainThread()) { MediaDecoder::DurationChanged(); } else { nsCOMPtr<nsIRunnable> task = NS_NewRunnableMethod(this, &MediaDecoder::DurationChanged); NS_DispatchToMainThread(task); } } else { if (NS_IsMainThread()) { DurationChanged(aOldDuration, aNewDuration); } else { nsCOMPtr<nsIRunnable> task = new DurationChangedRunnable(this, aOldDuration, aNewDuration); NS_DispatchToMainThread(task); } } }
nsresult HTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, nsIContent* aBindingParent, bool aCompileEventHandlers) { Link::ResetLinkState(false, Link::ElementHasHref()); nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent, aBindingParent, aCompileEventHandlers); NS_ENSURE_SUCCESS(rv, rv); if (aDocument) { aDocument->RegisterPendingLinkUpdate(this); } void (HTMLLinkElement::*update)() = &HTMLLinkElement::UpdateStyleSheetInternal; nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, update)); CreateAndDispatchEvent(aDocument, NS_LITERAL_STRING("DOMLinkAdded")); return rv; }
NS_IMETHOD Run() { MOZ_ASSERT(!NS_IsMainThread()); bool continueThread; do { continueThread = mDBusWatcher->Poll(); } while (continueThread); mDBusWatcher->CleanUp(); nsIThread* thread; nsresult rv = NS_GetCurrentThread(&thread); NS_ENSURE_SUCCESS(rv, rv); nsRefPtr<nsIRunnable> runnable = NS_NewRunnableMethod(thread, &nsIThread::Shutdown); rv = NS_DispatchToMainThread(runnable); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder, MediaTaskQueue* aBorrowedTaskQueue) : mAudioCompactor(mAudioQueue) , mDecoder(aDecoder) , mTaskQueue(aBorrowedTaskQueue ? aBorrowedTaskQueue : new MediaTaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK), /* aSupportsTailDispatch = */ true)) , mDuration(mTaskQueue, NullableTimeUnit(), "MediaDecoderReader::mDuration (Mirror)") , mIgnoreAudioOutputFormat(false) , mStartTime(-1) , mHitAudioDecodeError(false) , mShutdown(false) , mTaskQueueIsBorrowed(!!aBorrowedTaskQueue) , mAudioDiscontinuity(false) , mVideoDiscontinuity(false) { MOZ_COUNT_CTOR(MediaDecoderReader); MOZ_ASSERT(NS_IsMainThread()); // Dispatch initialization that needs to happen on that task queue. nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(this, &MediaDecoderReader::InitializationTask); mTaskQueue->Dispatch(r.forget()); }
MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder) : mAudioCompactor(mAudioQueue) , mDecoder(aDecoder) , mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK), /* aSupportsTailDispatch = */ true)) , mWatchManager(this, mTaskQueue) , mTimer(new MediaTimer()) , mBuffered(mTaskQueue, TimeIntervals(), "MediaDecoderReader::mBuffered (Canonical)") , mDuration(mTaskQueue, NullableTimeUnit(), "MediaDecoderReader::mDuration (Mirror)") , mThrottleDuration(TimeDuration::FromMilliseconds(500)) , mLastThrottledNotify(TimeStamp::Now() - mThrottleDuration) , mIgnoreAudioOutputFormat(false) , mHitAudioDecodeError(false) , mShutdown(false) , mAudioDiscontinuity(false) , mVideoDiscontinuity(false) { MOZ_COUNT_CTOR(MediaDecoderReader); MOZ_ASSERT(NS_IsMainThread()); // Dispatch initialization that needs to happen on that task queue. nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(this, &MediaDecoderReader::InitializationTask); mTaskQueue->Dispatch(r.forget()); }
nsresult HTMLTrackElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, nsIContent* aBindingParent, bool aCompileEventHandlers) { nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent, aBindingParent, aCompileEventHandlers); NS_ENSURE_SUCCESS(rv, rv); if (!aDocument) { return NS_OK; } LOG(PR_LOG_DEBUG, ("Track Element bound to tree.")); if (!aParent || !aParent->IsNodeOfType(nsINode::eMEDIA)) { return NS_OK; } // Store our parent so we can look up its frame for display. if (!mMediaParent) { mMediaParent = static_cast<HTMLMediaElement*>(aParent); HTMLMediaElement* media = static_cast<HTMLMediaElement*>(aParent); // TODO: separate notification for 'alternate' tracks? media->NotifyAddedSource(); LOG(PR_LOG_DEBUG, ("Track element sent notification to parent.")); mMediaParent->RunInStableState( NS_NewRunnableMethod(this, &HTMLTrackElement::LoadResource)); } return NS_OK; }
nsresult nsPACMan::LoadPACFromURI(nsIURI *pacURI) { NS_ENSURE_STATE(!mShutdown); NS_ENSURE_ARG(pacURI || mPACURI); nsCOMPtr<nsIStreamLoader> loader = do_CreateInstance(NS_STREAMLOADER_CONTRACTID); NS_ENSURE_STATE(loader); // Since we might get called from nsProtocolProxyService::Init, we need to // post an event back to the main thread before we try to use the IO service. // // But, we need to flag ourselves as loading, so that we queue up any PAC // queries the enter between now and when we actually load the PAC file. if (!mLoadPending) { nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &nsPACMan::StartLoading); nsresult rv; if (NS_FAILED(rv = NS_DispatchToCurrentThread(event))) return rv; mLoadPending = true; } CancelExistingLoad(); mLoader = loader; if (pacURI) { mPACURI = pacURI; mLoadFailureCount = 0; // reset } mScheduledReload = LL_MAXINT; mPAC = nsnull; return NS_OK; }
NS_IMETHODIMP EventSource::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext, nsresult aStatusCode) { mWaitingForOnStopRequest = false; if (mReadyState == CLOSED) { return NS_ERROR_ABORT; } if (NS_FAILED(aStatusCode)) { DispatchFailConnection(); return aStatusCode; } nsresult rv; nsresult healthOfRequestResult = CheckHealthOfRequestCallback(aRequest); if (NS_SUCCEEDED(healthOfRequestResult) && mLastConvertionResult == NS_PARTIAL_MORE_INPUT) { // we had an incomplete UTF8 char at the end of the stream rv = ParseCharacter(REPLACEMENT_CHAR); NS_ENSURE_SUCCESS(rv, rv); } ClearFields(); nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &EventSource::ReestablishConnection); NS_ENSURE_STATE(event); rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); NS_ENSURE_SUCCESS(rv, rv); return healthOfRequestResult; }
nsresult EMEAudioDecoder::Flush() { MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue. { MonitorAutoLock mon(mMonitor); mFlushComplete = false; } nsRefPtr<nsIRunnable> task; task = NS_NewRunnableMethod(this, &EMEAudioDecoder::GmpFlush); nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL); NS_ENSURE_SUCCESS(rv, rv); { MonitorAutoLock mon(mMonitor); while (!mFlushComplete) { mon.Wait(); } } return NS_OK; }
void AudioOffloadPlayer::NotifyAudioEOS() { nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver, &MediaDecoder::PlaybackEnded); NS_DispatchToMainThread(nsEvent); }
nsresult GonkMediaDataDecoder::Drain() { mTaskQueue->Dispatch(NS_NewRunnableMethod(this, &GonkMediaDataDecoder::ProcessDrain)); return NS_OK; }
void nsPicoService::Init() { MOZ_ASSERT(!NS_IsMainThread()); MOZ_ASSERT(!mInitialized); if (!sPicoApi.Init()) { NS_WARNING("Failed to initialize pico library"); return; } // Use environment variable, or default android/b2g path nsAutoCString langPath(PR_GetEnv("PICO_LANG_PATH")); if (langPath.IsEmpty()) { langPath.AssignLiteral(GONK_PICO_LANG_PATH); } nsCOMPtr<nsIFile> voicesDir; NS_NewNativeLocalFile(langPath, true, getter_AddRefs(voicesDir)); nsCOMPtr<nsISimpleEnumerator> dirIterator; nsresult rv = voicesDir->GetDirectoryEntries(getter_AddRefs(dirIterator)); if (NS_FAILED(rv)) { NS_WARNING(nsPrintfCString("Failed to get contents of directory: %s", langPath.get()).get()); return; } bool hasMoreElements = false; rv = dirIterator->HasMoreElements(&hasMoreElements); MOZ_ASSERT(NS_SUCCEEDED(rv)); MonitorAutoLock autoLock(mVoicesMonitor); while (hasMoreElements && NS_SUCCEEDED(rv)) { nsCOMPtr<nsISupports> supports; rv = dirIterator->GetNext(getter_AddRefs(supports)); MOZ_ASSERT(NS_SUCCEEDED(rv)); nsCOMPtr<nsIFile> voiceFile = do_QueryInterface(supports); MOZ_ASSERT(voiceFile); nsAutoCString leafName; voiceFile->GetNativeLeafName(leafName); nsAutoString lang; if (GetVoiceFileLanguage(leafName, lang)) { nsAutoString uri; uri.AssignLiteral("urn:moz-tts:pico:"); uri.Append(lang); bool found = false; PicoVoice* voice = mVoices.GetWeak(uri, &found); if (!found) { voice = new PicoVoice(lang); mVoices.Put(uri, voice); } // Each voice consists of two lingware files: A language resource file, // suffixed by _ta.bin, and a speaker resource file, suffixed by _sb.bin. // We currently assume that there is a pair of files for each language. if (StringEndsWith(leafName, NS_LITERAL_CSTRING("_ta.bin"))) { rv = voiceFile->GetPersistentDescriptor(voice->mTaFile); MOZ_ASSERT(NS_SUCCEEDED(rv)); } else if (StringEndsWith(leafName, NS_LITERAL_CSTRING("_sg.bin"))) { rv = voiceFile->GetPersistentDescriptor(voice->mSgFile); MOZ_ASSERT(NS_SUCCEEDED(rv)); } } rv = dirIterator->HasMoreElements(&hasMoreElements); } NS_DispatchToMainThread(NS_NewRunnableMethod(this, &nsPicoService::RegisterVoices)); }
void AudioOffloadPlayer::NotifyPositionChanged() { nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver, &MediaOmxCommonDecoder::PlaybackPositionChanged); NS_DispatchToMainThread(nsEvent); }
void DASHRepDecoder::LoadNextByteRange() { NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); NS_ASSERTION(mResource, "Error: resource is reported as null!"); // Return silently if shutting down. if (mShuttingDown) { LOG1("Shutting down! Ignoring LoadNextByteRange()."); return; } ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); NS_ASSERTION(mMainDecoder, "Error: main decoder is null!"); NS_ASSERTION(mMainDecoder->IsDecoderAllowedToDownloadData(this), "Should not be called on non-active decoders!"); // Cannot have empty byte ranges. if (mByteRanges.IsEmpty()) { LOG1("Error getting list of subsegment byte ranges."); DecodeError(); return; } // Get byte range for subsegment. int32_t subsegmentIdx = mMainDecoder->GetSubsegmentIndex(this); NS_ASSERTION(0 <= subsegmentIdx, "Subsegment index should be >= 0 for active decoders"); if (subsegmentIdx >= 0 && (uint32_t)subsegmentIdx < mByteRanges.Length()) { mCurrentByteRange = mByteRanges[subsegmentIdx]; mSubsegmentIdx = subsegmentIdx; } else { mCurrentByteRange.Clear(); mSubsegmentIdx = -1; LOG("End of subsegments: index [%d] out of range.", subsegmentIdx); return; } // Request a seek for the first reader. Required so that the reader is // primed to start here, and will block subsequent subsegment seeks unless // the subsegment has been read. if (subsegmentIdx == 0) { ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); mReader->RequestSeekToSubsegment(0); } // Query resource for cached ranges; only download if it's not there. if (IsSubsegmentCached(mSubsegmentIdx)) { LOG("Subsegment [%d] bytes [%lld] to [%lld] already cached. No need to " "download.", mSubsegmentIdx, mCurrentByteRange.mStart, mCurrentByteRange.mEnd); nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &DASHRepDecoder::DoNotifyDownloadEnded); nsresult rv = NS_DispatchToMainThread(event); if (NS_FAILED(rv)) { LOG("Error notifying subsegment [%d] cached: rv[0x%x].", mSubsegmentIdx, rv); NetworkError(); } return; } // Open byte range corresponding to subsegment. nsresult rv = mResource->OpenByteRange(nullptr, mCurrentByteRange); if (NS_FAILED(rv)) { LOG("Error opening byte range [%lld - %lld]: subsegmentIdx [%d] rv [%x].", mCurrentByteRange.mStart, mCurrentByteRange.mEnd, mSubsegmentIdx, rv); NetworkError(); return; } }
size_t AudioOffloadPlayer::FillBuffer(void* aData, size_t aSize) { CHECK(mAudioSink.get()); if (mReachedEOS) { return 0; } size_t sizeDone = 0; size_t sizeRemaining = aSize; while (sizeRemaining > 0) { MediaSource::ReadOptions options; bool refreshSeekTime = false; { android::Mutex::Autolock autoLock(mLock); if (mSeeking) { options.setSeekTo(mSeekTimeUs); refreshSeekTime = true; if (mInputBuffer) { mInputBuffer->release(); mInputBuffer = nullptr; } mSeeking = false; } } if (!mInputBuffer) { status_t err; err = mSource->read(&mInputBuffer, &options); CHECK((!err && mInputBuffer) || (err && !mInputBuffer)); android::Mutex::Autolock autoLock(mLock); if (err != OK) { AUDIO_OFFLOAD_LOG(PR_LOG_ERROR, ("Error while reading media source %d " "Ok to receive EOS error at end", err)); if (!mReachedEOS) { // After seek there is a possible race condition if // OffloadThread is observing state_stopping_1 before // framesReady() > 0. Ensure sink stop is called // after last buffer is released. This ensures the // partial buffer is written to the driver before // stopping one is observed.The drawback is that // there will be an unnecessary call to the parser // after parser signalled EOS. if (sizeDone > 0) { AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("send Partial buffer down")); AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("skip calling stop till next" " fillBuffer")); break; } // no more buffers to push - stop() and wait for STREAM_END // don't set mReachedEOS until stream end received mAudioSink->Stop(); } break; } if(mInputBuffer->range_length() != 0) { CHECK(mInputBuffer->meta_data()->findInt64( kKeyTime, &mPositionTimeMediaUs)); } if (refreshSeekTime) { if (mDispatchSeekEvents && !mSeekDuringPause) { mDispatchSeekEvents = false; AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("FillBuffer posting SEEK_COMPLETE")); nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver, &MediaDecoder::SeekingStopped); NS_DispatchToMainThread(nsEvent, NS_DISPATCH_NORMAL); } else if (mSeekDuringPause) { // Callback is already called for seek during pause. Just reset the // flag AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Not posting seek complete as its" " already faked")); mSeekDuringPause = false; } NotifyPositionChanged(); // need to adjust the mStartPosUs for offload decoding since parser // might not be able to get the exact seek time requested. mStartPosUs = mPositionTimeMediaUs; AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Adjust seek time to: %.2f", mStartPosUs / 1E6)); // clear seek time with mLock locked and once we have valid // mPositionTimeMediaUs // before clearing mSeekTimeUs check if a new seek request has been // received while we were reading from the source with mLock released. if (!mSeeking) { mSeekTimeUs = 0; } } } if (mInputBuffer->range_length() == 0) { mInputBuffer->release(); mInputBuffer = nullptr; continue; } size_t copy = sizeRemaining; if (copy > mInputBuffer->range_length()) { copy = mInputBuffer->range_length(); } memcpy((char *)aData + sizeDone, (const char *)mInputBuffer->data() + mInputBuffer->range_offset(), copy); mInputBuffer->set_range(mInputBuffer->range_offset() + copy, mInputBuffer->range_length() - copy); sizeDone += copy; sizeRemaining -= copy; } return sizeDone; }
void AudioOffloadPlayer::NotifyAudioTearDown() { nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver, &MediaOmxCommonDecoder::AudioOffloadTearDown); NS_DispatchToMainThread(nsEvent); }