widget/windows/nsSound.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 *
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 "nscore.h"
michael@0 8 #include "plstr.h"
michael@0 9 #include <stdio.h>
michael@0 10 #include "nsString.h"
michael@0 11 #include <windows.h>
michael@0 12
michael@0 13 // mmsystem.h is needed to build with WIN32_LEAN_AND_MEAN
michael@0 14 #include <mmsystem.h>
michael@0 15
michael@0 16 #include "nsSound.h"
michael@0 17 #include "nsIURL.h"
michael@0 18 #include "nsNetUtil.h"
michael@0 19 #include "nsCRT.h"
michael@0 20
michael@0 21 #include "prlog.h"
michael@0 22 #include "prtime.h"
michael@0 23 #include "prprf.h"
michael@0 24 #include "prmem.h"
michael@0 25
michael@0 26 #include "nsNativeCharsetUtils.h"
michael@0 27 #include "nsThreadUtils.h"
michael@0 28
michael@0 29 #ifdef PR_LOGGING
michael@0 30 PRLogModuleInfo* gWin32SoundLog = nullptr;
michael@0 31 #endif
michael@0 32
michael@0 33 class nsSoundPlayer: public nsRunnable {
michael@0 34 public:
michael@0 35 nsSoundPlayer(nsSound *aSound, const wchar_t* aSoundName) :
michael@0 36 mSoundName(aSoundName), mSound(aSound)
michael@0 37 {
michael@0 38 Init();
michael@0 39 }
michael@0 40
michael@0 41 nsSoundPlayer(nsSound *aSound, const nsAString& aSoundName) :
michael@0 42 mSoundName(aSoundName), mSound(aSound)
michael@0 43 {
michael@0 44 Init();
michael@0 45 }
michael@0 46
michael@0 47 NS_DECL_NSIRUNNABLE
michael@0 48
michael@0 49 protected:
michael@0 50 nsString mSoundName;
michael@0 51 nsSound *mSound; // Strong, but this will be released from SoundReleaser.
michael@0 52 nsCOMPtr<nsIThread> mThread;
michael@0 53
michael@0 54 void Init()
michael@0 55 {
michael@0 56 NS_GetCurrentThread(getter_AddRefs(mThread));
michael@0 57 NS_ASSERTION(mThread, "failed to get current thread");
michael@0 58 NS_IF_ADDREF(mSound);
michael@0 59 }
michael@0 60
michael@0 61 class SoundReleaser: public nsRunnable {
michael@0 62 public:
michael@0 63 SoundReleaser(nsSound* aSound) :
michael@0 64 mSound(aSound)
michael@0 65 {
michael@0 66 }
michael@0 67
michael@0 68 NS_DECL_NSIRUNNABLE
michael@0 69
michael@0 70 protected:
michael@0 71 nsSound *mSound;
michael@0 72 };
michael@0 73 };
michael@0 74
michael@0 75 NS_IMETHODIMP
michael@0 76 nsSoundPlayer::Run()
michael@0 77 {
michael@0 78 PR_SetCurrentThreadName("Play Sound");
michael@0 79
michael@0 80 NS_PRECONDITION(!mSoundName.IsEmpty(), "Sound name should not be empty");
michael@0 81 ::PlaySoundW(mSoundName.get(), nullptr,
michael@0 82 SND_NODEFAULT | SND_ALIAS | SND_ASYNC);
michael@0 83 nsCOMPtr<nsIRunnable> releaser = new SoundReleaser(mSound);
michael@0 84 // Don't release nsSound from here, because here is not an owning thread of
michael@0 85 // the nsSound. nsSound must be released in its owning thread.
michael@0 86 mThread->Dispatch(releaser, NS_DISPATCH_NORMAL);
michael@0 87 return NS_OK;
michael@0 88 }
michael@0 89
michael@0 90 NS_IMETHODIMP
michael@0 91 nsSoundPlayer::SoundReleaser::Run()
michael@0 92 {
michael@0 93 mSound->ShutdownOldPlayerThread();
michael@0 94 NS_IF_RELEASE(mSound);
michael@0 95 return NS_OK;
michael@0 96 }
michael@0 97
michael@0 98
michael@0 99 #ifndef SND_PURGE
michael@0 100 // Not available on Windows CE, and according to MSDN
michael@0 101 // doesn't do anything on recent windows either.
michael@0 102 #define SND_PURGE 0
michael@0 103 #endif
michael@0 104
michael@0 105 NS_IMPL_ISUPPORTS(nsSound, nsISound, nsIStreamLoaderObserver)
michael@0 106
michael@0 107
michael@0 108 nsSound::nsSound()
michael@0 109 {
michael@0 110 #ifdef PR_LOGGING
michael@0 111 if (!gWin32SoundLog) {
michael@0 112 gWin32SoundLog = PR_NewLogModule("nsSound");
michael@0 113 }
michael@0 114 #endif
michael@0 115
michael@0 116 mLastSound = nullptr;
michael@0 117 }
michael@0 118
michael@0 119 nsSound::~nsSound()
michael@0 120 {
michael@0 121 NS_ASSERTION(!mPlayerThread, "player thread is not null but should be");
michael@0 122 PurgeLastSound();
michael@0 123 }
michael@0 124
michael@0 125 void nsSound::ShutdownOldPlayerThread()
michael@0 126 {
michael@0 127 if (mPlayerThread) {
michael@0 128 mPlayerThread->Shutdown();
michael@0 129 mPlayerThread = nullptr;
michael@0 130 }
michael@0 131 }
michael@0 132
michael@0 133 void nsSound::PurgeLastSound()
michael@0 134 {
michael@0 135 if (mLastSound) {
michael@0 136 // Halt any currently playing sound.
michael@0 137 ::PlaySound(nullptr, nullptr, SND_PURGE);
michael@0 138
michael@0 139 // Now delete the buffer.
michael@0 140 free(mLastSound);
michael@0 141 mLastSound = nullptr;
michael@0 142 }
michael@0 143 }
michael@0 144
michael@0 145 NS_IMETHODIMP nsSound::Beep()
michael@0 146 {
michael@0 147 ::MessageBeep(0);
michael@0 148
michael@0 149 return NS_OK;
michael@0 150 }
michael@0 151
michael@0 152 NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
michael@0 153 nsISupports *context,
michael@0 154 nsresult aStatus,
michael@0 155 uint32_t dataLen,
michael@0 156 const uint8_t *data)
michael@0 157 {
michael@0 158 // print a load error on bad status
michael@0 159 if (NS_FAILED(aStatus)) {
michael@0 160 #ifdef DEBUG
michael@0 161 if (aLoader) {
michael@0 162 nsCOMPtr<nsIRequest> request;
michael@0 163 nsCOMPtr<nsIChannel> channel;
michael@0 164 aLoader->GetRequest(getter_AddRefs(request));
michael@0 165 if (request)
michael@0 166 channel = do_QueryInterface(request);
michael@0 167 if (channel) {
michael@0 168 nsCOMPtr<nsIURI> uri;
michael@0 169 channel->GetURI(getter_AddRefs(uri));
michael@0 170 if (uri) {
michael@0 171 nsAutoCString uriSpec;
michael@0 172 uri->GetSpec(uriSpec);
michael@0 173 PR_LOG(gWin32SoundLog, PR_LOG_ALWAYS,
michael@0 174 ("Failed to load %s\n", uriSpec.get()));
michael@0 175 }
michael@0 176 }
michael@0 177 }
michael@0 178 #endif
michael@0 179 return aStatus;
michael@0 180 }
michael@0 181
michael@0 182 ShutdownOldPlayerThread();
michael@0 183 PurgeLastSound();
michael@0 184
michael@0 185 if (data && dataLen > 0) {
michael@0 186 DWORD flags = SND_MEMORY | SND_NODEFAULT;
michael@0 187 // We try to make a copy so we can play it async.
michael@0 188 mLastSound = (uint8_t *) malloc(dataLen);
michael@0 189 if (mLastSound) {
michael@0 190 memcpy(mLastSound, data, dataLen);
michael@0 191 data = mLastSound;
michael@0 192 flags |= SND_ASYNC;
michael@0 193 }
michael@0 194 ::PlaySoundW(reinterpret_cast<LPCWSTR>(data), 0, flags);
michael@0 195 }
michael@0 196
michael@0 197 return NS_OK;
michael@0 198 }
michael@0 199
michael@0 200 NS_IMETHODIMP nsSound::Play(nsIURL *aURL)
michael@0 201 {
michael@0 202 nsresult rv;
michael@0 203
michael@0 204 #ifdef DEBUG_SOUND
michael@0 205 char *url;
michael@0 206 aURL->GetSpec(&url);
michael@0 207 PR_LOG(gWin32SoundLog, PR_LOG_ALWAYS,
michael@0 208 ("%s\n", url));
michael@0 209 #endif
michael@0 210
michael@0 211 nsCOMPtr<nsIStreamLoader> loader;
michael@0 212 rv = NS_NewStreamLoader(getter_AddRefs(loader), aURL, this);
michael@0 213
michael@0 214 return rv;
michael@0 215 }
michael@0 216
michael@0 217
michael@0 218 NS_IMETHODIMP nsSound::Init()
michael@0 219 {
michael@0 220 // This call halts a sound if it was still playing.
michael@0 221 // We have to use the sound library for something to make sure
michael@0 222 // it is initialized.
michael@0 223 // If we wait until the first sound is played, there will
michael@0 224 // be a time lag as the library gets loaded.
michael@0 225 ::PlaySound(nullptr, nullptr, SND_PURGE);
michael@0 226
michael@0 227 return NS_OK;
michael@0 228 }
michael@0 229
michael@0 230
michael@0 231 NS_IMETHODIMP nsSound::PlaySystemSound(const nsAString &aSoundAlias)
michael@0 232 {
michael@0 233 ShutdownOldPlayerThread();
michael@0 234 PurgeLastSound();
michael@0 235
michael@0 236 if (!NS_IsMozAliasSound(aSoundAlias)) {
michael@0 237 if (aSoundAlias.IsEmpty())
michael@0 238 return NS_OK;
michael@0 239 nsCOMPtr<nsIRunnable> player = new nsSoundPlayer(this, aSoundAlias);
michael@0 240 NS_ENSURE_TRUE(player, NS_ERROR_OUT_OF_MEMORY);
michael@0 241 nsresult rv = NS_NewThread(getter_AddRefs(mPlayerThread), player);
michael@0 242 NS_ENSURE_SUCCESS(rv, rv);
michael@0 243 return NS_OK;
michael@0 244 }
michael@0 245
michael@0 246 NS_WARNING("nsISound::playSystemSound is called with \"_moz_\" events, they are obsolete, use nsISound::playEventSound instead");
michael@0 247
michael@0 248 uint32_t eventId;
michael@0 249 if (aSoundAlias.Equals(NS_SYSSOUND_MAIL_BEEP))
michael@0 250 eventId = EVENT_NEW_MAIL_RECEIVED;
michael@0 251 else if (aSoundAlias.Equals(NS_SYSSOUND_CONFIRM_DIALOG))
michael@0 252 eventId = EVENT_CONFIRM_DIALOG_OPEN;
michael@0 253 else if (aSoundAlias.Equals(NS_SYSSOUND_ALERT_DIALOG))
michael@0 254 eventId = EVENT_ALERT_DIALOG_OPEN;
michael@0 255 else if (aSoundAlias.Equals(NS_SYSSOUND_MENU_EXECUTE))
michael@0 256 eventId = EVENT_MENU_EXECUTE;
michael@0 257 else if (aSoundAlias.Equals(NS_SYSSOUND_MENU_POPUP))
michael@0 258 eventId = EVENT_MENU_POPUP;
michael@0 259 else
michael@0 260 return NS_OK;
michael@0 261
michael@0 262 return PlayEventSound(eventId);
michael@0 263 }
michael@0 264
michael@0 265 NS_IMETHODIMP nsSound::PlayEventSound(uint32_t aEventId)
michael@0 266 {
michael@0 267 ShutdownOldPlayerThread();
michael@0 268 PurgeLastSound();
michael@0 269
michael@0 270 const wchar_t *sound = nullptr;
michael@0 271 switch (aEventId) {
michael@0 272 case EVENT_NEW_MAIL_RECEIVED:
michael@0 273 sound = L"MailBeep";
michael@0 274 break;
michael@0 275 case EVENT_ALERT_DIALOG_OPEN:
michael@0 276 sound = L"SystemExclamation";
michael@0 277 break;
michael@0 278 case EVENT_CONFIRM_DIALOG_OPEN:
michael@0 279 sound = L"SystemQuestion";
michael@0 280 break;
michael@0 281 case EVENT_MENU_EXECUTE:
michael@0 282 sound = L"MenuCommand";
michael@0 283 break;
michael@0 284 case EVENT_MENU_POPUP:
michael@0 285 sound = L"MenuPopup";
michael@0 286 break;
michael@0 287 case EVENT_EDITOR_MAX_LEN:
michael@0 288 sound = L".Default";
michael@0 289 break;
michael@0 290 default:
michael@0 291 // Win32 plays no sounds at NS_SYSSOUND_PROMPT_DIALOG and
michael@0 292 // NS_SYSSOUND_SELECT_DIALOG.
michael@0 293 return NS_OK;
michael@0 294 }
michael@0 295 NS_ASSERTION(sound, "sound is null");
michael@0 296
michael@0 297 nsCOMPtr<nsIRunnable> player = new nsSoundPlayer(this, sound);
michael@0 298 NS_ENSURE_TRUE(player, NS_ERROR_OUT_OF_MEMORY);
michael@0 299 nsresult rv = NS_NewThread(getter_AddRefs(mPlayerThread), player);
michael@0 300 NS_ENSURE_SUCCESS(rv, rv);
michael@0 301 return NS_OK;
michael@0 302 }

mercurial