/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * 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/. */
// Hackaround for bug 1644240 // When we call PlaySound for the first time in the process, winmm.dll creates // a new thread and starts a message loop in winmm!mciwindow. After that, // every call of PlaySound communicates with that thread via Window messages. // It seems that Warsaw application hooks USER32!GetMessageA, and there is // a timing window where they free their trampoline region without reverting // the hook on USER32!GetMessageA, resulting in crash when winmm!mciwindow // receives a message because it tries to jump to a freed buffer. // Based on the crash reports, it happened on all versions of Windows x64, and // the possible condition was wslbdhm64.dll was loaded but wslbscrwh64.dll was // unloaded. Therefore we suppress playing a sound under such a condition. staticbool ShouldSuppressPlaySound() { #ifdefined(_M_AMD64) if (::GetModuleHandle(L"wslbdhm64.dll") &&
!::GetModuleHandle(L"wslbscrwh64.dll")) { returntrue;
} #endif// defined(_M_AMD64) returnfalse;
}
class nsSoundPlayer : public mozilla::Runnable { public: explicit nsSoundPlayer(const nsAString& aSoundName)
: mozilla::Runnable("nsSoundPlayer"),
mSoundName(aSoundName),
mSoundData(nullptr) {}
nsSoundPlayer(const uint8_t* aData, size_t aSize)
: mozilla::Runnable("nsSoundPlayer"), mSoundName(u""_ns) {
MOZ_ASSERT(aSize > 0, "Size should not be zero");
MOZ_ASSERT(aData, "Data shoud not be null");
// We will disptach nsSoundPlayer to playerthread, so keep a data copy
mSoundData = new uint8_t[aSize];
memcpy(mSoundData, aData, aSize);
}
NS_DECL_NSIRUNNABLE
protected:
~nsSoundPlayer();
nsString mSoundName;
uint8_t* mSoundData;
};
NS_IMETHODIMP
nsSoundPlayer::Run() { if (ShouldSuppressPlaySound()) { return NS_OK;
}
MOZ_ASSERT(!mSoundName.IsEmpty() || mSoundData, "Sound name or sound data should be specified");
DWORD flags = SND_NODEFAULT | SND_ASYNC;
void nsSound::PurgeLastSound() { // Halt any currently playing sound. if (mSoundPlayer) { if (mPlayerThread) {
mPlayerThread->Dispatch(
NS_NewRunnableFunction("nsSound::PurgeLastSound",
[player = std::move(mSoundPlayer)]() { // Capture move mSoundPlayer to lambda then // PlaySoundW(nullptr, nullptr, SND_PURGE) // will be called before freeing the // nsSoundPlayer. if (ShouldSuppressPlaySound()) { return;
}
::PlaySoundW(nullptr, nullptr, SND_PURGE);
}),
NS_DISPATCH_NORMAL);
}
}
}
NS_IMETHODIMP nsSound::Beep() {
::MessageBeep(0);
return NS_OK;
}
NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader* aLoader,
nsISupports* context, nsresult aStatus,
uint32_t dataLen, const uint8_t* data) {
MOZ_ASSERT(mPlayerThread, "player thread should not be null "); // print a load error on bad status if (NS_FAILED(aStatus)) { #ifdef DEBUG if (aLoader) {
nsCOMPtr<nsIRequest> request;
nsCOMPtr<nsIChannel> channel;
aLoader->GetRequest(getter_AddRefs(request)); if (request) channel = do_QueryInterface(request); if (channel) {
nsCOMPtr<nsIURI> uri;
channel->GetURI(getter_AddRefs(uri)); if (uri) {
nsAutoCString uriSpec;
uri->GetSpec(uriSpec);
MOZ_LOG(gWin32SoundLog, LogLevel::Info,
("Failed to load %s\n", uriSpec.get()));
}
}
} #endif return aStatus;
}
PurgeLastSound();
if (data && dataLen > 0) {
MOZ_ASSERT(!mSoundPlayer, "mSoundPlayer should be null");
mSoundPlayer = new nsSoundPlayer(data, dataLen);
MOZ_ASSERT(mSoundPlayer, "Could not create player");
nsresult nsSound::CreatePlayerThread() { if (mPlayerThread) { return NS_OK;
} if (NS_WARN_IF(NS_FAILED(NS_NewNamedThread("PlayEventSound",
getter_AddRefs(mPlayerThread))))) { return NS_ERROR_FAILURE;
}
// Add an observer for shutdown event to release the thread at that time
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService(); if (!observerService) { return NS_ERROR_FAILURE;
}
if (mPlayerThread) {
mPlayerThread->Shutdown();
mPlayerThread = nullptr;
}
}
return NS_OK;
}
NS_IMETHODIMP nsSound::Init() { if (mInited) { return NS_OK;
}
MOZ_ASSERT(mPlayerThread, "player thread should not be null "); // This call halts a sound if it was still playing. // We have to use the sound library for something to make sure // it is initialized. // If we wait until the first sound is played, there will // be a time lag as the library gets loaded. // This should be done in player thread otherwise it will block main thread // at the first time loading sound library.
mPlayerThread->Dispatch(
NS_NewRunnableFunction("nsSound::Init",
[]() { if (ShouldSuppressPlaySound()) { return;
}
::PlaySoundW(nullptr, nullptr, SND_PURGE);
}),
NS_DISPATCH_NORMAL);
mInited = true;
return NS_OK;
}
NS_IMETHODIMP nsSound::PlayEventSound(uint32_t aEventId) {
MOZ_ASSERT(mPlayerThread, "player thread should not be null ");
PurgeLastSound();
constwchar_t* sound = nullptr; switch (aEventId) { case EVENT_NEW_MAIL_RECEIVED:
sound = L"MailBeep"; break; case EVENT_ALERT_DIALOG_OPEN:
sound = L"SystemExclamation"; break; case EVENT_CONFIRM_DIALOG_OPEN:
sound = L"SystemQuestion"; break; case EVENT_MENU_EXECUTE:
sound = L"MenuCommand"; break; case EVENT_MENU_POPUP:
sound = L"MenuPopup"; break; case EVENT_EDITOR_MAX_LEN:
sound = L".Default"; break; default: // Win32 plays no sounds at NS_SYSSOUND_PROMPT_DIALOG and // NS_SYSSOUND_SELECT_DIALOG. return NS_OK;
}
NS_ASSERTION(sound, "sound is null");
MOZ_ASSERT(!mSoundPlayer, "mSoundPlayer should be null");
mSoundPlayer = new nsSoundPlayer(nsDependentString(sound));
MOZ_ASSERT(mSoundPlayer, "Could not create player");
nsresult rv = mPlayerThread->Dispatch(mSoundPlayer, NS_DISPATCH_NORMAL); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
} return NS_OK;
}
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.