Bug 520417 Redesign nsSound structure r+sr=roc
authorMasayuki Nakano <masayuki@d-toybox.com>
Sat, 17 Oct 2009 21:53:47 +0900
changeset 33985 d2ac46221368caa82fc65931677b441dfcde5a8e
parent 33984 5ae7b09f730f9dc9ee364755b588e8028a7a24a0
child 33986 4f3a789f3c3ff341d481927c57ab50304742bb35
push idunknown
push userunknown
push dateunknown
bugs520417
milestone1.9.3a1pre
Bug 520417 Redesign nsSound structure r+sr=roc
content/base/public/Makefile.in
content/base/public/nsContentCID.h
content/base/public/nsContentUtils.h
content/base/public/nsISoundPlayer.idl
content/base/src/Makefile.in
content/base/src/nsContentUtils.cpp
content/base/src/nsSoundPlayer.cpp
content/base/src/nsSoundPlayer.h
content/media/test/Makefile.in
content/media/test/test_sound.xul
embedding/components/windowwatcher/src/nsPromptService.cpp
layout/build/nsLayoutModule.cpp
layout/xul/base/src/nsMenuBarFrame.cpp
layout/xul/base/src/nsMenuFrame.cpp
layout/xul/base/src/nsMenuPopupFrame.cpp
toolkit/content/commonDialog.js
toolkit/content/selectDialog.js
widget/public/Makefile.in
widget/public/nsISound.idl
widget/public/nsISystemSoundService.idl
widget/public/nsWidgetsCID.h
widget/src/beos/Makefile.in
widget/src/beos/nsSound.cpp
widget/src/beos/nsSound.h
widget/src/beos/nsSystemSoundService.cpp
widget/src/beos/nsSystemSoundService.h
widget/src/beos/nsWidgetFactory.cpp
widget/src/build/nsWinWidgetFactory.cpp
widget/src/cocoa/Makefile.in
widget/src/cocoa/nsSound.h
widget/src/cocoa/nsSound.mm
widget/src/cocoa/nsSystemSoundService.h
widget/src/cocoa/nsSystemSoundService.mm
widget/src/cocoa/nsWidgetFactory.mm
widget/src/gtk2/Makefile.in
widget/src/gtk2/nsSound.cpp
widget/src/gtk2/nsSound.h
widget/src/gtk2/nsSystemSoundService.cpp
widget/src/gtk2/nsSystemSoundService.h
widget/src/gtk2/nsWidgetFactory.cpp
widget/src/os2/Makefile.in
widget/src/os2/nsSound.cpp
widget/src/os2/nsSound.h
widget/src/os2/nsSystemSoundService.cpp
widget/src/os2/nsSystemSoundService.h
widget/src/os2/nsWidgetFactory.cpp
widget/src/photon/Makefile.in
widget/src/photon/nsSound.cpp
widget/src/photon/nsSound.h
widget/src/photon/nsSystemSoundService.cpp
widget/src/photon/nsSystemSoundService.h
widget/src/photon/nsWidgetFactory.cpp
widget/src/qt/Makefile.in
widget/src/qt/nsSound.cpp
widget/src/qt/nsSound.h
widget/src/qt/nsSystemSoundService.cpp
widget/src/qt/nsSystemSoundService.h
widget/src/qt/nsWidgetFactory.cpp
widget/src/windows/Makefile.in
widget/src/windows/nsSound.cpp
widget/src/windows/nsSound.h
widget/src/windows/nsSystemSoundService.cpp
widget/src/windows/nsSystemSoundService.h
widget/src/xpwidgets/Makefile.in
widget/src/xpwidgets/nsBaseAppShell.cpp
widget/src/xpwidgets/nsSound.cpp
widget/src/xpwidgets/nsSound.h
--- a/content/base/public/Makefile.in
+++ b/content/base/public/Makefile.in
@@ -105,16 +105,17 @@ XPIDLSRCS	= \
 		nsISelectionDisplay.idl  \
 		nsISelectionListener.idl  \
 		nsISelectionPrivate.idl  \
 		nsIScriptLoaderObserver.idl  \
 		nsISyncLoadDOMService.idl  \
 		nsIDragDropHandler.idl \
 		nsIScriptEventHandler.idl \
 		nsIScriptEventManager.idl \
+		nsISoundPlayer.idl \
 		nsIImageLoadingContent.idl \
 		nsIObjectLoadingContent.idl \
 		nsIFrameLoader.idl \
 		nsIXMLHttpRequest.idl \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
--- a/content/base/public/nsContentCID.h
+++ b/content/base/public/nsContentCID.h
@@ -114,16 +114,21 @@
 { /* d9783472-8fe9-11d2-9d3c-0060088f9ff7 */      \
  0xd9783472, 0x8fe9, 0x11d2,                      \
  {0x9d, 0x3c, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}}
 
 /* a6cf90d7-15b3-11d2-932e-00805f8add32 */
 #define NS_FRAME_UTIL_CID \
  { 0xa6cf90d5, 0x15b3, 0x11d2,{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
 
+// {1C3F4572-FF54-4e7f-994C-6F9C8A4B85FF}
+#define NS_SOUNDPLAYER_CID \
+{ 0x1c3f4572, 0xff54, 0x4e7f, \
+  { 0x99, 0x4c, 0x6f, 0x9c, 0x8a, 0x4b, 0x85, 0xff } }
+
 
 // XXX This should really be factored into a style-specific DLL so
 // that all the HTML, generic layout, and style stuff isn't munged
 // together.
 
 // {2E363D60-872E-11d2-B531-000000000000}
 #define NS_CSSPARSER_CID \
 { 0x2e363d60, 0x872e, 0x11d2, { 0xb5, 0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1492,16 +1492,20 @@ public:
                              // If non-null aHolder will keep the jsval alive
                              // while there's a ref to it
                              nsIXPConnectJSObjectHolder** aHolder = nsnull,
                              PRBool aAllowWrapping = PR_FALSE)
   {
     return WrapNative(cx, scope, native, nsnull, vp, aHolder, aAllowWrapping);
   }
 
+  // Play an event sound of the aEventID.  aEventID must be a value that is
+  // declared in nsISystemSoundService.
+  static nsresult PlayEventSound(PRUint32 aEventID);
+
 private:
 
   static PRBool InitializeEventTable();
 
   static nsresult doReparentContentWrapper(nsIContent *aChild,
                                            JSContext *cx,
                                            JSObject *aOldGlobal,
                                            JSObject *aNewGlobal,
new file mode 100644
--- /dev/null
+++ b/content/base/public/nsISoundPlayer.idl
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Japan.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Masayuki Nakano <masayuki@d-toybox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIURL;
+
+/**
+ *  nsISoundPlayer provides simple sound playback.
+ *
+ *  The implementation uses the HTML5 <audio> element, so supports any format
+ *  supported by <audio>. Gecko in its default configuration supports Wave (with
+ *  8-bit or 16-bit PCM samples and at most 2 channels), and Ogg Vorbis.
+ *
+ *  When you call play() before the previously playing sound is finished,
+ *  the previous sound isn't stopped automatically, so the sounds overlap.
+ *
+ *  If you don't want the overlap, you should call stop() before play().
+ *  The stop() method stops playing all in-progress sounds that are being played
+ *  via this interface.
+ *
+ *  NOTE: nsISystemSoundService calls stops() method automatically before it
+ *        plays a system sound.
+ */
+
+[scriptable, uuid(8AAB1533-7B56-4861-9390-094658447A0C)]
+interface nsISoundPlayer : nsISupports
+{
+  void play(in nsIURL aURL);
+  void stop();
+};
+
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -113,16 +113,17 @@ CPPSRCS		= \
 		nsParserUtils.cpp \
 		nsPlainTextSerializer.cpp \
 		nsPropertyTable.cpp \
 		nsRange.cpp \
 		nsReferencedElement.cpp \
 		nsScriptElement.cpp \
 		nsScriptEventManager.cpp \
 		nsScriptLoader.cpp \
+		nsSoundPlayer.cpp \
 		nsStubDocumentObserver.cpp \
 		nsStubImageDecoderObserver.cpp \
 		nsStubMutationObserver.cpp \
 		nsStyledElement.cpp \
 		nsStyleLinkElement.cpp \
 		nsSyncLoadService.cpp \
 		nsTextFragment.cpp \
 		nsTextNode.cpp \
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -162,16 +162,17 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_
 #include "nsIMIMEHeaderParam.h"
 #include "nsIDOMXULCommandEvent.h"
 #include "nsIDOMAbstractView.h"
 #include "nsIDOMDragEvent.h"
 #include "nsDOMDataTransfer.h"
 #include "nsHtml5Module.h"
 #include "nsPresContext.h"
 #include "nsLayoutStatics.h"
+#include "nsISystemSoundService.h"
 
 #ifdef IBMBIDI
 #include "nsIBidiKeyboard.h"
 #endif
 #include "nsCycleCollectionParticipant.h"
 
 // for ReportToConsole
 #include "nsIStringBundle.h"
@@ -5167,8 +5168,21 @@ nsContentUtils::WrapNative(JSContext *cx
                                      vp, aHolder);
 
   if (push) {
     sThreadJSContextStack->Pop(nsnull);
   }
 
   return rv;
 }
+
+// static
+nsresult
+nsContentUtils::PlayEventSound(PRUint32 aEventID)
+{
+  nsresult rv;
+  nsCOMPtr<nsISystemSoundService> sysSound =
+    do_GetService("@mozilla.org/systemsoundservice;1", &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_TRUE(sysSound, NS_ERROR_FAILURE);
+  return sysSound->PlayEventSound(aEventID);
+}
+
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsSoundPlayer.cpp
@@ -0,0 +1,183 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Japan.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Masayuki Nakano <masayuki@d-toybox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsSoundPlayer.h"
+#include "nsString.h"
+#include "nsIURL.h"
+#include "nsServiceManagerUtils.h"
+#include "nsGkAtoms.h"
+#include "nsIDOMEvent.h"
+#include "nsIDOMEventTarget.h"
+#include "nsCOMPtr.h"
+
+#ifdef DEBUG
+#include "nsPrintfCString.h"
+#endif
+
+nsSoundPlayer* nsSoundPlayer::sInstance = nsnull;
+
+NS_IMPL_ISUPPORTS2(nsSoundPlayer, nsISoundPlayer, nsIDOMEventListener)
+
+
+nsSoundPlayer::nsSoundPlayer()
+{
+}
+
+nsSoundPlayer::~nsSoundPlayer()
+{
+  if (this == sInstance) {
+    sInstance = nsnull;
+  }
+#ifdef MOZ_MEDIA
+  for (PRInt32 i = mAudioElements.Count() - 1; i >= 0; i--) {
+    RemoveEventListeners(mAudioElements[i]);
+  }
+#endif // MOZ_MEDIA
+}
+
+/* static */ nsSoundPlayer*
+nsSoundPlayer::GetInstance()
+{
+  if (!sInstance) {
+    sInstance = new nsSoundPlayer();
+  }
+  NS_IF_ADDREF(sInstance);
+  return sInstance;
+}
+
+#ifdef MOZ_MEDIA
+
+void
+nsSoundPlayer::RemoveEventListeners(nsIDOMHTMLMediaElement *aElement)
+{
+  nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(aElement));
+  target->RemoveEventListener(NS_LITERAL_STRING("ended"), this, PR_TRUE);
+  target->RemoveEventListener(NS_LITERAL_STRING("error"), this, PR_TRUE);
+}
+
+nsresult
+nsSoundPlayer::CreateAudioElement(nsIDOMHTMLMediaElement **aElement)
+{
+  nsresult rv;
+  nsCOMPtr<nsIDOMHTMLMediaElement> audioElement =
+    do_CreateInstance("@mozilla.org/content/element/html;1?name=audio", &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ASSERTION(audioElement,
+               "do_CreateInterface succeeded, but the result is null");
+  audioElement->SetAutoplay(PR_TRUE);
+  nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(audioElement));
+  target->AddEventListener(NS_LITERAL_STRING("ended"), this, PR_TRUE);
+  target->AddEventListener(NS_LITERAL_STRING("error"), this, PR_TRUE);
+  NS_ADDREF(*aElement = audioElement);
+  return NS_OK;
+}
+
+#endif // MOZ_MEDIA
+
+NS_IMETHODIMP
+nsSoundPlayer::Play(nsIURL* aURL)
+{
+#ifdef MOZ_MEDIA
+  nsCAutoString spec;
+  nsresult rv = aURL->GetSpec(spec);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (spec.IsEmpty()) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIDOMHTMLMediaElement> audioElement;
+  rv = CreateAudioElement(getter_AddRefs(audioElement));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  mAudioElements.AppendObject(audioElement);
+
+  rv = audioElement->SetAttribute(NS_LITERAL_STRING("src"),
+                                  NS_ConvertUTF8toUTF16(spec));
+  NS_ENSURE_SUCCESS(rv, rv);
+  audioElement->Load();
+  return NS_OK;
+#else
+  return NS_ERROR_NOT_IMPLEMENTED;
+#endif // MOZ_MEDIA
+}
+
+NS_IMETHODIMP
+nsSoundPlayer::Stop()
+{
+#ifdef MOZ_MEDIA
+  for (PRInt32 i = mAudioElements.Count() - 1; i >= 0; i--) {
+    nsCOMPtr<nsIDOMHTMLMediaElement> audioElement = mAudioElements[i];
+    if (!audioElement) {
+      NS_WARNING("mAudioElements has null item");
+      continue;
+    }
+    RemoveEventListeners(audioElement);
+    audioElement->Pause();
+  }
+  mAudioElements.Clear();
+  return NS_OK;
+#else
+  return NS_ERROR_NOT_IMPLEMENTED;
+#endif // MOZ_MEDIA
+}
+
+NS_IMETHODIMP
+nsSoundPlayer::HandleEvent(nsIDOMEvent *aEvent)
+{
+#ifdef MOZ_MEDIA
+  NS_ENSURE_ARG_POINTER(aEvent);
+
+  nsresult rv;
+  nsCOMPtr<nsIDOMEventTarget> target;
+  rv = aEvent->GetTarget(getter_AddRefs(target));
+  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_TRUE(target, NS_OK);
+
+  nsCOMPtr<nsIDOMHTMLMediaElement> audioElement = do_QueryInterface(target);
+  NS_ENSURE_TRUE(audioElement, NS_OK);
+
+  RemoveEventListeners(audioElement);
+
+  mAudioElements.RemoveObject(audioElement);
+
+  return NS_OK;
+#else
+  return NS_ERROR_NOT_IMPLEMENTED;
+#endif // MOZ_MEDIA
+}
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsSoundPlayer.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Japan.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Masayuki Nakano <masayuki@d-toybox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __nsSoundPlayer_h__
+#define __nsSoundPlayer_h__
+
+#include "nsISoundPlayer.h"
+#include "nsIDOMEventListener.h"
+
+#ifdef MOZ_MEDIA
+#include "nsIDOMHTMLMediaElement.h"
+#include "nsCOMArray.h"
+#endif // MOZ_MEDIA
+
+class nsSoundPlayer : public nsISoundPlayer,
+                      public nsIDOMEventListener
+{
+public:
+  nsSoundPlayer();
+  virtual ~nsSoundPlayer();
+
+  static nsSoundPlayer* GetInstance();
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISOUNDPLAYER
+  NS_DECL_NSIDOMEVENTLISTENER
+
+protected:
+  static nsSoundPlayer* sInstance;
+
+#ifdef MOZ_MEDIA
+  nsCOMArray<nsIDOMHTMLMediaElement> mAudioElements;
+
+  nsresult CreateAudioElement(nsIDOMHTMLMediaElement **aElement);
+  void RemoveEventListeners(nsIDOMHTMLMediaElement *aElement);
+#endif // MOZ_MEDIA
+};
+
+#endif /* __nsSoundPlayer_h__ */
--- a/content/media/test/Makefile.in
+++ b/content/media/test/Makefile.in
@@ -244,16 +244,17 @@ ifdef MOZ_WAVE
 _TEST_FILES += \
 		test_bug463162.xhtml \
 		test_bug465498.html \
 		test_bug468190_wav.html \
 		test_bug495145_wav.html \
 		test_paused_after_ended.html \
 		test_progress2.html \
 		test_progress4.html \
+		test_sound.xul \
 		test_wav_ended1.html \
 		test_wav_ended2.html \
 		test_wav_onloadedmetadata.html \
 		test_wav_timeupdate1.html \
 		test_wav_timeupdate2.html \
 		test_wav_trunc_seek.html \
 		$(NULL)
 # Disabled since we don't play Wave files standalone, for now
new file mode 100644
--- /dev/null
+++ b/content/media/test/test_sound.xul
@@ -0,0 +1,242 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+<window title="sound tests"
+  onload="runTests()"
+  xmlns:html="http://www.w3.org/1999/xhtml"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <title>sound tests</title>
+  <script type="application/javascript" 
+   src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+
+<body  xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+function runTests()
+{
+  SimpleTest.waitForExplicitFinish();
+
+  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+
+  const nsISystemSoundService = Components.interfaces.nsISystemSoundService;
+  var sysSoundService = Components.classes["@mozilla.org/systemsoundservice;1"].
+                                   getService(nsISystemSoundService);
+  isnot(sysSoundService, null, "failed to get the nsISystemSoundService");
+
+  const nsISoundPlayer = Components.interfaces.nsISoundPlayer;
+  var soundPlayer =
+    Components.classes["@mozilla.org/content/media/soundplayer;1"].
+               getService(nsISoundPlayer);
+  isnot(soundPlayer, null, "failed to get the shared sound player");
+
+  const nsISound = Components.interfaces.nsISound;
+  var sound = Components.classes["@mozilla.org/sound;1"].getService(nsISound);
+  isnot(sound, null, "failed to get the shared nsISound instance");
+
+  function getCurrentURL() {
+    var url = Components.classes["@mozilla.org/network/io-service;1"].
+                         getService(Components.interfaces.nsIIOService).
+                         newURI(location.href, null, null);
+    url.QueryInterface(Components.interfaces.nsIURL);
+    return url;
+  }
+
+  // All tests should run asynchronously because some methods of the interfaces
+  // play the sound in another thread.
+  testSysSoundBeep();
+
+  const kDelay = 500;
+
+  function testSysSoundBeep()
+  {
+    ok(true, "running testSysSoundBeep...");
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    sysSoundService.beep();
+
+    setTimeout(testSysSoundPlayAlias, kDelay);
+  }
+
+  function testSysSoundPlayAlias()
+  {
+    ok(true, "running testSysSoundPlayAlias...");
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    sysSoundService.playAlias("foobar");
+
+    setTimeout(testSysSoundPlayEventSound1, kDelay);
+  }
+
+  function testSysSoundPlayEventSound1()
+  {
+    ok(true, "running testSysSoundPlayEventSound1...");
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    // EVENT_NEW_MAIL_RECEIVED is supported on all platforms now.
+    sysSoundService.playEventSound(
+      nsISystemSoundService.EVENT_NEW_MAIL_RECEIVED);
+
+    setTimeout(testSysSoundPlayEventSound2, kDelay);
+  }
+
+  function testSysSoundPlayEventSound2()
+  {
+    ok(true, "running testSysSoundPlayEventSound2...");
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    // EVENT_SELECT_DIALOG_OPEN isn't supported on all platforms now.
+    sysSoundService.playEventSound(
+      nsISystemSoundService.EVENT_SELECT_DIALOG_OPEN);
+
+    setTimeout(createAnotherSystemSoundService, kDelay);
+  }
+
+  function createAnotherSystemSoundService()
+  {
+    ok(true, "running createAnotherSystemSoundService...");
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    var sysSound2 = Components.classes["@mozilla.org/systemsoundservice;1"].
+                               createInstance(nsISystemSoundService);
+    isnot(sysSound2, null, "failed to create another nsISystemSoundService");
+    // The createInstance should return the same instance as the service.
+    // The implementation have to be singleton.
+    is(sysSound2, sysSoundService, "the new instance is created");
+    sysSound2.playEventSound(nsISystemSoundService.EVENT_NEW_MAIL_RECEIVED);
+
+    // The reference will be released, but it shouldn't release the instance.
+
+    setTimeout(testSoundPlayerPlay1, kDelay);
+  }
+
+  function testSoundPlayerPlay1()
+  {
+    ok(true, "running testSoundPlayerPlay1...");
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    var url = getCurrentURL();
+    url.fileName = "r11025_u8_c1.wav";
+    soundPlayer.play(url);
+
+    setTimeout(testSoundPlayerPlay2, kDelay);
+  }
+
+  function testSoundPlayerPlay2()
+  {
+    ok(true, "running testSoundPlayerPlay2...");
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    var url = getCurrentURL();
+    url.fileName = "dont_be_this_file_name.wav";
+
+    soundPlayer.play(url);
+
+    setTimeout(testSoundPlayerStop, kDelay);
+  }
+
+  function testSoundPlayerStop()
+  {
+    ok(true, "running testSoundPlayerStop...");
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    soundPlayer.stop();
+
+    setTimeout(createAnotherSoundPlayer, kDelay);
+  }
+
+  function createAnotherSoundPlayer()
+  {
+    ok(true, "running createAnotherSoundPlayer...");
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    var soundPlayer2 =
+      Components.classes["@mozilla.org/content/media/soundplayer;1"].
+                 createInstance(nsISoundPlayer);
+    isnot(soundPlayer2, null, "failed to create another sound player");
+    // The createInstance should return the same instance as the service.
+    // The implementation have to be singleton.
+    is(soundPlayer2, soundPlayer, "new sound player instance is created");
+    var url = getCurrentURL();
+    url.fileName = "r11025_u8_c1.wav";
+    soundPlayer2.play(url);
+
+    // The reference will be released, but it shouldn't release the instance.
+
+    setTimeout(testSoundPlay, kDelay);
+  }
+
+  function testSoundPlay()
+  {
+    ok(true, "running testSoundPlay...");
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    var url = getCurrentURL();
+    url.fileName = "r11025_u8_c1.wav";
+    sound.play(url);
+
+    setTimeout(testSoundPlaySystemSound1, kDelay);
+  }
+
+  function testSoundPlaySystemSound1()
+  {
+    ok(true, "running testSoundPlaySystemSound1...");
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    sound.playSystemSound("foobar");
+
+    setTimeout(testSoundPlaySystemSound2, kDelay);
+  }
+
+  function testSoundPlaySystemSound2()
+  {
+    ok(true, "running testSoundPlaySystemSound2...");
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    sound.playSystemSound("_moz_mailbeep");
+
+    setTimeout(testSoundPlaySystemSound3, kDelay);
+  }
+
+  function testSoundPlaySystemSound3()
+  {
+    ok(true, "running testSoundPlaySystemSound3...");
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    sound.playSystemSound("_moz_selectdialog");
+
+    setTimeout(testSoundBeep, kDelay);
+  }
+
+  function testSoundBeep()
+  {
+    ok(true, "running testSoundBeep...");
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    sound.beep();
+
+    setTimeout(testSoundPlayEventSound1, kDelay);
+  }
+
+  function testSoundPlayEventSound1()
+  {
+    ok(true, "running testPlayEventSound1...");
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    sound.playEventSound(nsISound.EVENT_NEW_MAIL_RECEIVED);
+
+    setTimeout(testSoundPlayEventSound2, kDelay);
+  }
+
+  function testSoundPlayEventSound2()
+  {
+    ok(true, "running testSoundPlayEventSound2...");
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    sound.playEventSound(nsISound.EVENT_SELECT_DIALOG_OPEN);
+
+    setTimeout(SimpleTest.finish, kDelay);
+  }
+}
+
+]]>
+</script>
+
+</window>
--- a/embedding/components/windowwatcher/src/nsPromptService.cpp
+++ b/embedding/components/windowwatcher/src/nsPromptService.cpp
@@ -48,16 +48,17 @@
 #include "nsIPrivateDOMEvent.h"
 #include "nsIDOMDocumentEvent.h"
 #include "nsIServiceManager.h"
 #include "nsISupportsUtils.h"
 #include "nsString.h"
 #include "nsIStringBundle.h"
 #include "nsXPIDLString.h"
 #include "nsISound.h"
+#include "nsISystemSoundService.h"
 
 static const char kPromptURL[] = "chrome://global/content/commonDialog.xul";
 static const char kSelectPromptURL[] = "chrome://global/content/selectDialog.xul";
 static const char kQuestionIconClass[] = "question-icon";
 static const char kAlertIconClass[] = "alert-icon";
 // We include question-icon for backwards compatibility
 static const char kAuthenticationIconClass[] = "authentication-icon question-icon";
 
@@ -135,17 +136,17 @@ nsPromptService::Alert(nsIDOMWindow *par
   block->SetString(eMsg, text);
 
   block->SetString(eDialogTitle, dialogTitle);
 
   nsString url;
   NS_ConvertASCIItoUTF16 styleClass(kAlertIconClass);
   block->SetString(eIconClass, styleClass.get());
   block->SetString(eOpeningSound, NS_SYSSOUND_ALERT_DIALOG.get());
-  block->SetInt(eSoundEventId, nsISound::EVENT_ALERT_DIALOG_OPEN);
+  block->SetInt(eSoundEventId, nsISystemSoundService::EVENT_ALERT_DIALOG_OPEN);
 
   rv = DoDialog(parent, block, kPromptURL);
 
   return rv;
 }
 
 
 
@@ -181,17 +182,17 @@ nsPromptService::AlertCheck(nsIDOMWindow
 
   block->SetString(eDialogTitle, dialogTitle);
 
   NS_ConvertASCIItoUTF16 styleClass(kAlertIconClass);
   block->SetString(eIconClass, styleClass.get());
   block->SetString(eCheckboxMsg, checkMsg);
   block->SetInt(eCheckboxState, *checkValue);
   block->SetString(eOpeningSound, NS_SYSSOUND_ALERT_DIALOG.get());
-  block->SetInt(eSoundEventId, nsISound::EVENT_ALERT_DIALOG_OPEN);
+  block->SetInt(eSoundEventId, nsISystemSoundService::EVENT_ALERT_DIALOG_OPEN);
 
   rv = DoDialog(parent, block, kPromptURL);
   if (NS_FAILED(rv))
     return rv;
 
   block->GetInt(eCheckboxState, checkValue);
 
   return rv;
@@ -228,17 +229,18 @@ nsPromptService::Confirm(nsIDOMWindow *p
   block->SetInt(eNumberButtons, 2);
   block->SetString(eMsg, text);
   
   block->SetString(eDialogTitle, dialogTitle);
 
   NS_ConvertASCIItoUTF16 styleClass(kQuestionIconClass);
   block->SetString(eIconClass, styleClass.get());
   block->SetString(eOpeningSound, NS_SYSSOUND_CONFIRM_DIALOG.get());
-  block->SetInt(eSoundEventId, nsISound::EVENT_CONFIRM_DIALOG_OPEN);
+  block->SetInt(eSoundEventId,
+                nsISystemSoundService::EVENT_CONFIRM_DIALOG_OPEN);
 
   rv = DoDialog(parent, block, kPromptURL);
   if (NS_FAILED(rv))
     return rv;
   
   PRInt32 buttonPressed = 0;
   block->GetInt(eButtonPressed, &buttonPressed);
   *_retval = buttonPressed ? PR_FALSE : PR_TRUE;
@@ -279,17 +281,18 @@ nsPromptService::ConfirmCheck(nsIDOMWind
 
   block->SetString(eDialogTitle, dialogTitle);
 
   NS_ConvertASCIItoUTF16 styleClass(kQuestionIconClass);
   block->SetString(eIconClass, styleClass.get());
   block->SetString(eCheckboxMsg, checkMsg);
   block->SetInt(eCheckboxState, *checkValue);
   block->SetString(eOpeningSound, NS_SYSSOUND_CONFIRM_DIALOG.get());
-  block->SetInt(eSoundEventId, nsISound::EVENT_CONFIRM_DIALOG_OPEN);
+  block->SetInt(eSoundEventId,
+                nsISystemSoundService::EVENT_CONFIRM_DIALOG_OPEN);
 
   rv = DoDialog(parent, block, kPromptURL);
   if (NS_FAILED(rv))
     return rv;
 
   PRInt32 tempInt = 0;
   block->GetInt(eButtonPressed, &tempInt);
   *_retval = tempInt ? PR_FALSE : PR_TRUE;
@@ -382,17 +385,18 @@ nsPromptService::ConfirmEx(nsIDOMWindow 
       ++numberButtons;
     }
     buttonFlags >>= 8;
   }
   block->SetInt(eNumberButtons, numberButtons);
 
   block->SetString(eIconClass, NS_ConvertASCIItoUTF16(kQuestionIconClass).get());
   block->SetString(eOpeningSound, NS_SYSSOUND_CONFIRM_DIALOG.get());
-  block->SetInt(eSoundEventId, nsISound::EVENT_CONFIRM_DIALOG_OPEN);
+  block->SetInt(eSoundEventId,
+                nsISystemSoundService::EVENT_CONFIRM_DIALOG_OPEN);
 
   if (checkMsg && checkValue) {
     block->SetString(eCheckboxMsg, checkMsg);
     // since we're setting a PRInt32, we have to sanitize the PRBool first.
     // (myBool != PR_FALSE) is guaranteed to return either 1 or 0.
     block->SetInt(eCheckboxState, *checkValue != PR_FALSE);
   }
   
@@ -459,17 +463,17 @@ nsPromptService::Prompt(nsIDOMWindow *pa
   block->SetInt(eNumberEditfields, 1);
   if (*value)
     block->SetString(eEditfield1Value, *value);
   if (checkMsg && checkValue) {
     block->SetString(eCheckboxMsg, checkMsg);
     block->SetInt(eCheckboxState, *checkValue);
   }
   block->SetString(eOpeningSound, NS_SYSSOUND_PROMPT_DIALOG.get());
-  block->SetInt(eSoundEventId, nsISound::EVENT_PROMPT_DIALOG_OPEN);
+  block->SetInt(eSoundEventId, nsISystemSoundService::EVENT_PROMPT_DIALOG_OPEN);
 
   rv = DoDialog(parent, block, kPromptURL);
   if (NS_FAILED(rv))
     return rv;
 
   PRInt32 tempInt = 0;
   block->GetInt(eButtonPressed, &tempInt);
   *_retval = tempInt ? PR_FALSE : PR_TRUE;
@@ -536,17 +540,17 @@ nsPromptService::PromptUsernameAndPasswo
     block->SetString(eEditfield1Value, *username);
   if (*password)
     block->SetString(eEditfield2Value, *password);
   if (checkMsg && checkValue) {
     block->SetString(eCheckboxMsg, checkMsg);
     block->SetInt(eCheckboxState, *checkValue);
   }
   block->SetString(eOpeningSound, NS_SYSSOUND_PROMPT_DIALOG.get());
-  block->SetInt(eSoundEventId, nsISound::EVENT_PROMPT_DIALOG_OPEN);
+  block->SetInt(eSoundEventId, nsISystemSoundService::EVENT_PROMPT_DIALOG_OPEN);
 
   rv = DoDialog(parent, block, kPromptURL);
   if (NS_FAILED(rv))
     return rv;
 
   PRInt32 tempInt = 0;
   block->GetInt(eButtonPressed, &tempInt);
   *_retval = tempInt ? PR_FALSE : PR_TRUE;
@@ -617,17 +621,17 @@ NS_IMETHODIMP nsPromptService::PromptPas
   block->SetInt(eEditField1Password, 1);
   if (*password)
     block->SetString(eEditfield1Value, *password);
   if (checkMsg && checkValue) {
     block->SetString(eCheckboxMsg, checkMsg);
     block->SetInt(eCheckboxState, *checkValue);
   }
   block->SetString(eOpeningSound, NS_SYSSOUND_PROMPT_DIALOG.get());
-  block->SetInt(eSoundEventId, nsISound::EVENT_PROMPT_DIALOG_OPEN);
+  block->SetInt(eSoundEventId, nsISystemSoundService::EVENT_PROMPT_DIALOG_OPEN);
 
   rv = DoDialog(parent, block, kPromptURL);
   if (NS_FAILED(rv))
     return rv;
 
   PRInt32 tempInt = 0;
   block->GetInt(eButtonPressed, &tempInt);
   *_retval = tempInt ? PR_FALSE : PR_TRUE;
@@ -753,17 +757,18 @@ nsPromptService::ShowNonBlockingAlert(ns
   if (!paramBlock)
     return NS_ERROR_FAILURE;
 
   paramBlock->SetInt(eNumberButtons, 1);
   paramBlock->SetString(eIconClass, NS_LITERAL_STRING("alert-icon").get());
   paramBlock->SetString(eDialogTitle, aDialogTitle);
   paramBlock->SetString(eMsg, aText);
   paramBlock->SetString(eOpeningSound, NS_SYSSOUND_ALERT_DIALOG.get());
-  paramBlock->SetInt(eSoundEventId, nsISound::EVENT_ALERT_DIALOG_OPEN);
+  paramBlock->SetInt(eSoundEventId,
+                     nsISystemSoundService::EVENT_ALERT_DIALOG_OPEN);
 
   nsCOMPtr<nsIDOMWindow> dialog;
   mWatcher->OpenWindow(aParent, "chrome://global/content/commonDialog.xul",
                        "_blank", "dependent,centerscreen,chrome,titlebar",
                        paramBlock, getter_AddRefs(dialog));
   return NS_OK;
 }
 
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -94,16 +94,17 @@
 #include "nsSyncLoadService.h"
 #include "nsBox.h"
 #include "nsIFrameTraversal.h"
 #include "nsLayoutCID.h"
 #include "nsILanguageAtomService.h"
 #include "nsStyleSheetService.h"
 #include "nsXULPopupManager.h"
 #include "nsFocusManager.h"
+#include "nsSoundPlayer.h"
 
 #include "nsIEventListenerService.h"
 // Transformiix stuff
 #include "nsXPathEvaluator.h"
 #include "txMozillaXSLTProcessor.h"
 #include "txNodeSetAdaptor.h"
 #include "nsXPath1Scheme.h"
 
@@ -290,16 +291,18 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(txMozilla
 NS_GENERIC_AGGREGATED_CONSTRUCTOR_INIT(nsXPathEvaluator, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(txNodeSetAdaptor, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDOMSerializer)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsXMLHttpRequest, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsDOMFileRequest, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDOMParser)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsDOMStorageManager,
                                          nsDOMStorageManager::GetInstance)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSoundPlayer,
+                                         nsSoundPlayer::GetInstance)
 
 //-----------------------------------------------------------------------------
 
 // Per bug 209804, it is necessary to observe the "xpcom-shutdown" event and
 // perform shutdown of the layout modules at that time instead of waiting for
 // our module destructor to run.  If we do not do this, then we risk holding
 // references to objects in other component libraries that have already been
 // shutdown (and possibly unloaded if 60709 is ever fixed).
@@ -1064,16 +1067,21 @@ static const nsModuleComponentInfo gComp
   { "HTML audio element",
     NS_HTMLAUDIOELEMENT_CID,
     NS_HTMLAUDIOELEMENT_CONTRACTID,
     CreateHTMLAudioElement,
     RegisterHTMLAudioElement,
     UnregisterHTMLAudioElement },
 #endif
 
+  { "Sound player",
+    NS_SOUNDPLAYER_CID,
+    "@mozilla.org/content/media/soundplayer;1",
+    nsSoundPlayerConstructor },
+
   { "Canvas 2D Rendering Context",
     NS_CANVASRENDERINGCONTEXT2D_CID,
     "@mozilla.org/content/canvas-rendering-context;1?id=2d",
     CreateCanvasRenderingContext2D },
   { "Canvas WebGL Rendering Context",
     NS_CANVASRENDERINGCONTEXTWEBGL_CID,
     "@mozilla.org/content/canvas-rendering-context;1?id=moz-webgl",
     CreateCanvasRenderingContextWebGL },
--- a/layout/xul/base/src/nsMenuBarFrame.cpp
+++ b/layout/xul/base/src/nsMenuBarFrame.cpp
@@ -54,17 +54,17 @@
 #include "nsGUIEvent.h"
 #include "nsUnicharUtils.h"
 #include "nsIDOMWindowInternal.h"
 #include "nsIDOMDocument.h"
 #include "nsPIDOMWindow.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsCSSFrameConstructor.h"
 #ifdef XP_WIN
-#include "nsISound.h"
+#include "nsISystemSoundService.h"
 #include "nsWidgetsCID.h"
 #endif
 #include "nsContentUtils.h"
 #include "nsUTF8Utils.h"
 
 
 //
 // NS_NewMenuBarFrame
@@ -261,19 +261,17 @@ nsMenuBarFrame::FindMenuWithShortcut(nsI
     return (foundMenu->GetType() == nsGkAtoms::menuFrame) ?
            static_cast<nsMenuFrame *>(foundMenu) : nsnull;
   }
 
   // didn't find a matching menu item
 #ifdef XP_WIN
   // behavior on Windows - this item is on the menu bar, beep and deactivate the menu bar
   if (mIsActive) {
-    nsCOMPtr<nsISound> soundInterface = do_CreateInstance("@mozilla.org/sound;1");
-    if (soundInterface)
-      soundInterface->Beep();
+    nsContentUtils::PlayEventSound(nsISystemSoundService::EVENT_MENU_NOT_FOUND);
   }
 
   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
   if (pm) {
     nsIFrame* popup = pm->GetTopPopup(ePopupTypeAny);
     if (popup)
       pm->HidePopup(popup->GetContent(), PR_TRUE, PR_TRUE, PR_TRUE);
   }
--- a/layout/xul/base/src/nsMenuFrame.cpp
+++ b/layout/xul/base/src/nsMenuFrame.cpp
@@ -75,17 +75,17 @@
 #include "nsXPIDLString.h"
 #include "nsReadableUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsIStringBundle.h"
 #include "nsGUIEvent.h"
 #include "nsContentUtils.h"
 #include "nsDisplayList.h"
 #include "nsIReflowCallback.h"
-#include "nsISound.h"
+#include "nsISystemSoundService.h"
 
 #define NS_MENU_POPUP_LIST_INDEX 0
 
 #if defined(XP_WIN) || defined(XP_OS2)
 #define NSCONTEXTMENUISMOUSEUP 1
 #endif
 
 static PRInt32 gEatMouseMove = PR_FALSE;
@@ -1169,19 +1169,17 @@ nsMenuFrame::Execute(nsGUIEvent *aEvent)
       else {
         mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, NS_LITERAL_STRING("true"),
                           PR_TRUE);
         ENSURE_TRUE(weakFrame.IsAlive());
       }
     }
   }
 
-  nsCOMPtr<nsISound> sound(do_CreateInstance("@mozilla.org/sound;1"));
-  if (sound)
-    sound->PlayEventSound(nsISound::EVENT_MENU_EXECUTE);
+  nsContentUtils::PlayEventSound(nsISystemSoundService::EVENT_MENU_EXECUTE);
 
   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
   if (pm && mMenuParent)
     pm->ExecuteMenu(mContent, aEvent);
 }
 
 NS_IMETHODIMP
 nsMenuFrame::RemoveFrame(nsIAtom*        aListName,
--- a/layout/xul/base/src/nsMenuPopupFrame.cpp
+++ b/layout/xul/base/src/nsMenuPopupFrame.cpp
@@ -78,17 +78,17 @@
 #include "nsCSSFrameConstructor.h"
 #include "nsIEventStateManager.h"
 #include "nsIBoxLayout.h"
 #include "nsIPopupBoxObject.h"
 #include "nsIReflowCallback.h"
 #include "nsBindingManager.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIBaseWindow.h"
-#include "nsISound.h"
+#include "nsISystemSoundService.h"
 #include "nsIRootBox.h"
 #include "nsIScreenManager.h"
 #include "nsIServiceManager.h"
 
 PRInt8 nsMenuPopupFrame::sDefaultLevelParent = -1;
 
 // NS_NewMenuPopupFrame
 //
@@ -632,19 +632,17 @@ nsMenuPopupFrame::ShowPopup(PRBool aIsCo
     }
     else {
       hasChildren = PR_TRUE;
       PresContext()->PresShell()->
         FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                          NS_FRAME_HAS_DIRTY_CHILDREN);
     }
     if (mPopupType == ePopupTypeMenu) {
-      nsCOMPtr<nsISound> sound(do_CreateInstance("@mozilla.org/sound;1"));
-      if (sound)
-        sound->PlayEventSound(nsISound::EVENT_MENU_POPUP);
+      nsContentUtils::PlayEventSound(nsISystemSoundService::EVENT_MENU_POPUP);
     }
   }
 
   mShouldAutoPosition = PR_TRUE;
   return hasChildren;
 }
 
 void
@@ -1325,21 +1323,18 @@ nsMenuPopupFrame::FindMenuWithShortcut(n
 
   if (charCode == 0) {
     if (keyCode == NS_VK_BACK) {
       if (!isMenu && !mIncrementalString.IsEmpty()) {
         mIncrementalString.SetLength(mIncrementalString.Length() - 1);
         return nsnull;
       }
       else {
-#ifdef XP_WIN
-        nsCOMPtr<nsISound> soundInterface = do_CreateInstance("@mozilla.org/sound;1");
-        if (soundInterface)
-          soundInterface->Beep();
-#endif  // #ifdef XP_WIN
+        nsContentUtils::PlayEventSound(
+          nsISystemSoundService::EVENT_MENU_NOT_FOUND);
       }
     }
     return nsnull;
   }
   else {
     PRUnichar uniChar = ToLowerCase(static_cast<PRUnichar>(charCode));
     if (isMenu || // Menu supports only first-letter navigation
         keyTime - lastKeyTime > INC_TYP_INTERVAL) // Interval too long, treat as new typing
@@ -1444,25 +1439,22 @@ nsMenuPopupFrame::FindMenuWithShortcut(n
     return frameAfter;
   else if (frameBefore) // If we haven't, use the item before the current
     return frameBefore;
 
   // If we don't match anything, rollback the last typing
   mIncrementalString.SetLength(mIncrementalString.Length() - 1);
 
   // didn't find a matching menu item
-#ifdef XP_WIN
-  // behavior on Windows - this item is in a menu popup off of the
-  // menu bar, so beep and do nothing else
+
+  // this item is in a menu popup off of the menu bar, so beep and do nothing
+  // else
   if (isMenu) {
-    nsCOMPtr<nsISound> soundInterface = do_CreateInstance("@mozilla.org/sound;1");
-    if (soundInterface)
-      soundInterface->Beep();
+    nsContentUtils::PlayEventSound(nsISystemSoundService::EVENT_MENU_NOT_FOUND);
   }
-#endif  // #ifdef XP_WIN
 
   return nsnull;
 }
 
 NS_IMETHODIMP
 nsMenuPopupFrame::GetWidget(nsIWidget **aWidget)
 {
   nsIView * view = GetRootViewForPopup(this);
--- a/toolkit/content/commonDialog.js
+++ b/toolkit/content/commonDialog.js
@@ -233,18 +233,18 @@ function commonDialogOnLoad()
   }
 
   getAttention();
 
   // play sound
   try {
     var sound = gCommonDialogParam.GetInt(7);
     if (sound) {
-      Cc["@mozilla.org/sound;1"]
-        .createInstance(Ci.nsISound)
+      Cc["@mozilla.org/systemsoundservice;1"]
+        .getService(Ci.nsISystemSoundService)
         .playEventSound(sound);
     }
   } catch (e) { }
 }
 
 function commonDialogOnUnload(){
   var observerService = Cc["@mozilla.org/observer-service;1"]
                           .getService(Ci.nsIObserverService);
--- a/toolkit/content/selectDialog.js
+++ b/toolkit/content/selectDialog.js
@@ -96,20 +96,20 @@ function selectDialogOnLoad() {
 
   // Move to the right location
   moveToAlertPosition();
   param.SetInt(0, 1 );
   centerWindowOnScreen();
 
   // play sound
   try {
-    const nsISound = Components.interfaces.nsISound;
-    Components.classes["@mozilla.org/sound;1"]
-              .createInstance(nsISound)
-              .playEventSound(nsISound.EVENT_SELECT_DIALOG_OPEN);
+    const nsISystemSoundService = Components.interfaces.nsISystemSoundService;
+    Components.classes["@mozilla.org/systemsoundservice;1"]
+              .getService(nsISystemSoundService)
+              .playEventSound(nsISystemSoundService.EVENT_SELECT_DIALOG_OPEN);
   } catch (e) { }
 }
 
 function commonDialogOnOK() {
   for (var i=0; i<numItems; i++) {
     if (elements[i] == list.selectedItems[0]) {
       param.SetInt(2, i );
       break;
--- a/widget/public/Makefile.in
+++ b/widget/public/Makefile.in
@@ -83,16 +83,17 @@ EXPORTS		+= \
 endif
 
 XPIDLSRCS	= \
 		nsIAccelerometer.idl \
 		nsIAppShell.idl \
 		nsIFilePicker.idl \
 		nsIToolkit.idl \
 		nsISound.idl \
+		nsISystemSoundService.idl \
 		nsITransferable.idl \
 		nsIClipboardDragDropHooks.idl \
 		nsIClipboardDragDropHookList.idl \
 		nsIDragSession.idl \
 		nsIDragService.idl \
 		nsIFormatConverter.idl \
 		nsIClipboard.idl \
 		nsIClipboardHelper.idl \
--- a/widget/public/nsISound.idl
+++ b/widget/public/nsISound.idl
@@ -36,33 +36,39 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
 interface nsIURL;
 
+/**
+ * WARNING:  nsISound is now OBSOLETE.
+ *
+ *   nsISound instance just delegates the methods to nsISystemSoundService and
+ *   nsISoundPlayer.  You should use the new interfaces directly.
+ */
+
 [scriptable, uuid(86B75B05-DB60-4c3e-97A7-82B363A41A01)]
 interface nsISound : nsISupports
 {
   void play(in nsIURL aURL);
   /**
    * for playing system sounds
    *
    * NS_SYSSOUND_* params are obsolete. The new events will not be supported by
    * this method.  You should use playEventSound method instaed.
    */
   void playSystemSound(in AString soundAlias);  
   void beep();
 
   /**
-    * Not strictly necessary, but avoids delay before first sound.
-    * The various methods on nsISound call Init() if they need to.
-	*/
+   * init() doesn't do anything now.
+   */
   void init(); 
 
   /**
    * In some situations, playEventSound will be called.  Then, each
    * implementations will play a system sound for the event if it's necessary.
    *
    * NOTE: Don't change these values because they are used in
    * nsPIPromptService.idl. So, if they are changed, that makes big impact for
new file mode 100644
--- /dev/null
+++ b/widget/public/nsISystemSoundService.idl
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Japan.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Masayuki Nakano <masayuki@d-toybox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+[scriptable, uuid(A8948ACA-0C2F-45b2-A4BB-3ED30006EAA4)]
+interface nsISystemSoundService : nsISupports
+{
+  /**
+   * Plays the system beep.
+   */
+  void beep();
+
+  /**
+   * Play the platform's sound with the given alias name. Names and supported
+   * sounds are platform specific. _moz_ alias names are not supported.
+   */
+  void playAlias(in AString aSoundAlias);
+
+  /**
+   * In some situations, playEventSound will be called.  Then, each
+   * implementations will play a system sound for the event if it's necessary.
+   *
+   * NOTE: Don't change these values because they are used in
+   * nsPIPromptService.idl. So, if they are changed, that makes big impact for
+   * the embedders.
+   *
+   * And also they are must be same as the definition in nsISound, however,
+   * when you add new event, you don't need to add the same consts to the
+   * nsISound because the it's obsolete.
+   */
+  const unsigned long EVENT_NEW_MAIL_RECEIVED           = 0;
+  const unsigned long EVENT_ALERT_DIALOG_OPEN           = 1;
+  const unsigned long EVENT_CONFIRM_DIALOG_OPEN         = 2;
+  const unsigned long EVENT_PROMPT_DIALOG_OPEN          = 3;
+  const unsigned long EVENT_SELECT_DIALOG_OPEN          = 4;
+  const unsigned long EVENT_MENU_EXECUTE                = 5;
+  const unsigned long EVENT_MENU_POPUP                  = 6;
+  const unsigned long EVENT_MENU_NOT_FOUND              = 7;
+
+  void playEventSound(in unsigned long aEventID);
+};
+
--- a/widget/public/nsWidgetsCID.h
+++ b/widget/public/nsWidgetsCID.h
@@ -118,16 +118,20 @@
 
 //-----------------------------------------------------------
 //Other
 //-----------------------------------------------------------
 // {B148EED2-236D-11d3-B35C-00A0CC3C1CDE}
 #define NS_SOUND_CID \
 { 0xb148eed2, 0x236d, 0x11d3, { 0xb3, 0x5c, 0x0, 0xa0, 0xcc, 0x3c, 0x1c, 0xde } }
 
+// {F932EFC3-DD10-4d13-80BE-2790609AD9AE}
+#define NS_SYSTEM_SOUND_SERVICE_CID \
+{ 0xf932efc3, 0xdd10, 0x4d13, { 0x80, 0xbe, 0x27, 0x90, 0x60, 0x9a, 0xd9, 0xae } }
+
 // {9f1800ab-f428-4207-b40c-e832e77b01fc}
 #define NS_BIDIKEYBOARD_CID \
 { 0x9f1800ab, 0xf428, 0x4207, { 0xb4, 0x0c, 0xe8, 0x32, 0xe7, 0x7b, 0x01, 0xfc } }
 
 #define NS_SCREENMANAGER_CID \
 { 0xc401eb80, 0xf9ea, 0x11d3, { 0xbb, 0x6f, 0xe7, 0x32, 0xb7, 0x3e, 0xbe, 0x7c } }
 
 // {6987230e-0089-4e78-bc5f-1493ee7519fa}
--- a/widget/src/beos/Makefile.in
+++ b/widget/src/beos/Makefile.in
@@ -53,17 +53,17 @@ LIBXUL_LIBRARY = 1
 
 CPPSRCS		= \
 		nsAppShell.cpp \
 		nsBidiKeyboard.cpp \
 		nsClipboard.cpp \
 		nsDragService.cpp \
 		nsFilePicker.cpp \
 		nsLookAndFeel.cpp \
-		nsSound.cpp \
+		nsSystemSoundService.cpp \
 		nsToolkit.cpp \
 		nsWidgetFactory.cpp \
 		nsWindow.cpp \
 		nsPopupWindow.cpp \
 		nsChildView.cpp \
 		nsScreenBeOS.cpp \
 		nsScreenManagerBeOS.cpp \
 		nsDeviceContextSpecB.cpp \
rename from widget/src/beos/nsSound.cpp
rename to widget/src/beos/nsSystemSoundService.cpp
--- a/widget/src/beos/nsSound.cpp
+++ b/widget/src/beos/nsSystemSoundService.cpp
@@ -16,164 +16,69 @@
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Pierre Phaneuf <pp@ludusdesign.com>
+ *   Masayuki Nakano <masayuki@d-toybox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 
-#include "nscore.h"
-#include "plstr.h"
-#include <stdio.h>
-#include "nsIURL.h"
-#include "nsString.h"
-#include "nsIFileURL.h"
-#include "nsSound.h"
-#include "nsNetUtil.h"
-
-#include "nsDirectoryServiceDefs.h"
-
-#include "nsNativeCharsetUtils.h"
+#include "nsSystemSoundService.h"
 
 #include <OS.h>
 #include <SimpleGameSound.h>
 #include <Beep.h>
 #include <unistd.h>
 
-
-
-NS_IMPL_ISUPPORTS2(nsSound, nsISound, nsIStreamLoaderObserver)
+/*****************************************************************************
+ *  nsSystemSoundService implementation
+ *****************************************************************************/
 
-////////////////////////////////////////////////////////////////////////
-nsSound::nsSound()
- : mSound(0)
+NS_IMPL_ISUPPORTS1(nsSystemSoundService, nsISystemSoundService)
+
+NS_IMPL_ISYSTEMSOUNDSERVICE_GETINSTANCE(nsSystemSoundService)
+
+nsSystemSoundService::nsSystemSoundService() :
+  nsSystemSoundServiceBase()
 {
 }
 
-nsSound::~nsSound()
+nsSystemSoundService::~nsSystemSoundService()
 {
-	Init();
 }
 
-NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
-                                        nsISupports *context,
-                                        nsresult aStatus,
-                                        PRUint32 dataLen,
-                                        const PRUint8 *data)
+NS_IMETHODIMP
+nsSystemSoundService::Beep()
 {
-	// print a load error on bad status
-	if (NS_FAILED(aStatus))
-	{
-#ifdef DEBUG
-		printf("Failed load sound file");
-#endif
-		return aStatus;
-	}
-	// In theory, BeOS can play any sound format supported by MediaKit,
-	// we can also play it from data, but it needs parsing format and 
-	// providing it to sound player, so let MediaKit to do it by self
-	static const char kSoundTmpFileName[] = "mozsound";
-	nsCOMPtr<nsIFile> soundTmp;
-	nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(soundTmp));
-	NS_ENSURE_SUCCESS(rv, rv);
-	rv = soundTmp->AppendNative(nsDependentCString(kSoundTmpFileName));
+	nsresult rv = nsSystemSoundServiceBase::Beep();
 	NS_ENSURE_SUCCESS(rv, rv);
-	nsCAutoString soundFilename;
-	(void) soundTmp->GetNativePath(soundFilename);
-	FILE *fp = fopen(soundFilename.get(), "wb+");
-#ifdef DEBUG
-	printf("Playing sound file%s\n",soundFilename.get());
-#endif
-	if (fp) 
-	{
-		fwrite(data, 1, dataLen, fp);
-		fflush(fp);
-		fclose(fp);
-		Init();
-		mSound = new BSimpleGameSound(soundFilename.get());
-		if (mSound != NULL && mSound->InitCheck() == B_OK)
-		{
-			mSound->SetIsLooping(false);
-			mSound->StartPlaying();
-			rv = NS_OK;
-		}
-		else
-		{
-			rv = NS_ERROR_FAILURE;
-		}
-		unlink(soundFilename.get());
-	}
-	else
-	{
-		return Beep();
-	}
-	return rv;
-}
-
-NS_IMETHODIMP nsSound::Init(void)
-{
-	if (mSound)
-	{
-		mSound->StopPlaying();
-		delete mSound;
-		mSound = NULL;
-	}
-	return NS_OK;
-}
-
-NS_METHOD nsSound::Beep()
-{
 	::beep();
 	return NS_OK;
 }
 
-NS_METHOD nsSound::Play(nsIURL *aURL)
+NS_IMETHODIMP
+nsSystemSoundService::PlayEventSound(PRUint32 aEventID)
 {
-	nsresult rv;
-	nsCOMPtr<nsIStreamLoader> loader;
-	rv = NS_NewStreamLoader(getter_AddRefs(loader), aURL, this);
-	return rv;
-}
-
-NS_IMETHODIMP nsSound::PlaySystemSound(const nsAString &aSoundAlias)
-{
-	nsresult rv = NS_ERROR_FAILURE;
-	if (NS_IsMozAliasSound(aSoundAlias)) {
-		NS_WARNING("nsISound::playSystemSound is called with \"_moz_\" events, they are obsolete, use nsISound::playEventSound instead");
-		if (aSoundAlias.Equals(NS_SYSSOUND_MAIL_BEEP))
-			return Beep();
-		return NS_OK;
+	nsresult rv = nsSystemSoundServiceBase::PlayEventSound(aEventID);
+	NS_ENSURE_SUCCESS(rv, rv);
+	if (aEventID == EVENT_NEW_MAIL_RECEIVED) {
+		StopSoundPlayer();
+		return Beep();
 	}
-	nsCOMPtr <nsIURI> fileURI;
-	// create a nsILocalFile and then a nsIFileURL from that
-	nsCOMPtr <nsILocalFile> soundFile;
-	rv = NS_NewLocalFile(aSoundAlias, PR_TRUE, 
-    					getter_AddRefs(soundFile));
-	NS_ENSURE_SUCCESS(rv, rv);
-	rv = NS_NewFileURI(getter_AddRefs(fileURI), soundFile);
-	NS_ENSURE_SUCCESS(rv, rv);
-	nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(fileURI, &rv);
-	NS_ENSURE_SUCCESS(rv, rv);
-	rv = Play(fileURL);
-	return rv;
+	return NS_OK;
 }
-
-NS_IMETHODIMP nsSound::PlayEventSound(PRUint32 aEventId)
-{
-  return aEventId == EVENT_NEW_MAIL_RECEIVED ? Beep() : NS_OK;
-}
rename from widget/src/beos/nsSound.h
rename to widget/src/beos/nsSystemSoundService.h
--- a/widget/src/beos/nsSound.h
+++ b/widget/src/beos/nsSystemSoundService.h
@@ -15,46 +15,44 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
+ *   Masayuki Nakano <masayuki@d-toybox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#ifndef __nsSound_h__
-#define __nsSound_h__
+#ifndef __nsSystemSoundService_h__
+#define __nsSystemSoundService_h__
 
-#include "nsISound.h"
-#include "nsIStreamLoader.h"
+#include "nsSound.h"
 
-class BSimpleGameSound;
+class nsSystemSoundService : public nsSystemSoundServiceBase
+{
+public:
+	nsSystemSoundService();
+	virtual ~nsSystemSoundService();
 
-class nsSound : public nsISound,
-				public nsIStreamLoaderObserver
-{
-public: 
-	nsSound();
-	virtual ~nsSound();
+	NS_DECL_ISYSTEMSOUNDSERVICE_GETINSTANCE(nsSystemSoundService)
 
 	NS_DECL_ISUPPORTS
-	NS_DECL_NSISOUND
-	NS_DECL_NSISTREAMLOADEROBSERVER
-private:
-	BSimpleGameSound *mSound;
+
+	NS_IMETHOD Beep();
+	NS_IMETHOD PlayEventSound(PRUint32 aEventID);
 };
 
-#endif /* __nsSound_h__ */
+#endif /* __nsSystemSoundService_h__ */
--- a/widget/src/beos/nsWidgetFactory.cpp
+++ b/widget/src/beos/nsWidgetFactory.cpp
@@ -44,16 +44,17 @@
 #include "nsIModule.h"
 #include "nsCOMPtr.h"
 #include "nsWidgetsCID.h"
 
 #include "nsWindow.h"
 #include "nsPopupWindow.h"
 #include "nsChildView.h"
 #include "nsSound.h"
+#include "nsSystemSoundService.h"
 #include "nsToolkit.h"
 #include "nsAppShell.h"
 #include "nsAppShellSingleton.h"
 #include "nsLookAndFeel.h"
 #include "nsFilePicker.h"
 #include "nsBidiKeyboard.h"
 #include "nsScreenManagerBeOS.h" 
 // Printing:
@@ -76,16 +77,18 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsChildVi
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsToolkit)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsLookAndFeel)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsTransferable)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboard)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardHelper)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDragService)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSystemSoundService,
+                                         nsSystemSoundService::GetInstance)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePicker)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsBidiKeyboard)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsScreenManagerBeOS)
  
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceContextSpecBeOS) 
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrintOptionsBeOS, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrintSession, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsPrinterEnumeratorBeOS)
@@ -131,16 +134,20 @@ static const nsModuleComponentInfo compo
   { "HTML Format Converter",
     NS_HTMLFORMATCONVERTER_CID,
     "@mozilla.org/widget/htmlformatconverter;1",
     nsHTMLFormatConverterConstructor },
   { "BeOS Sound",
     NS_SOUND_CID,
     "@mozilla.org/sound;1",
     nsSoundConstructor },
+  { "System Sound Service",
+    NS_SYSTEM_SOUND_SERVICE_CID,
+    "@mozilla.org/systemsoundservice;1",
+    nsSystemSoundServiceConstructor },
   { "BeOS Drag Service",
     NS_DRAGSERVICE_CID,
     "@mozilla.org/widget/dragservice;1",
     nsDragServiceConstructor },
   { "BeOS Bidi Keyboard",
     NS_BIDIKEYBOARD_CID,
     "@mozilla.org/widget/bidikeyboard;1",
     nsBidiKeyboardConstructor },
--- a/widget/src/build/nsWinWidgetFactory.cpp
+++ b/widget/src/build/nsWinWidgetFactory.cpp
@@ -47,16 +47,17 @@
 #include "nsFilePicker.h"
 #include "nsIGenericFactory.h"
 #include "nsIServiceManager.h"
 #include "nsIdleServiceWin.h"
 #include "nsLookAndFeel.h"
 #include "nsNativeThemeWin.h"
 #include "nsScreenManagerWin.h"
 #include "nsSound.h"
+#include "nsSystemSoundService.h"
 #include "nsToolkit.h"
 #include "nsWindow.h"
 #include "WinTaskbar.h"
 #include "JumpListBuilder.h"
 #include "JumpListItem.h"
 
 // Drag & Drop, Clipboard
 
@@ -86,16 +87,18 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(ChildWind
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePicker)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsLookAndFeel)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsToolkit)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsScreenManagerWin)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsIdleServiceWin)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboard)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardHelper)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSystemSoundService,
+                                         nsSystemSoundService::GetInstance)
 
 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
 using namespace mozilla::widget;
 NS_GENERIC_FACTORY_CONSTRUCTOR(WinTaskbar)
 NS_GENERIC_FACTORY_CONSTRUCTOR(JumpListBuilder)
 NS_GENERIC_FACTORY_CONSTRUCTOR(JumpListItem)
 NS_GENERIC_FACTORY_CONSTRUCTOR(JumpListSeparator)
 NS_GENERIC_FACTORY_CONSTRUCTOR(JumpListLink)
@@ -162,16 +165,20 @@ static const nsModuleComponentInfo compo
   { "Clipboard Helper",
     NS_CLIPBOARDHELPER_CID,
     "@mozilla.org/widget/clipboardhelper;1",
     nsClipboardHelperConstructor },
   { "Sound",
     NS_SOUND_CID,
     "@mozilla.org/sound;1",
     nsSoundConstructor },
+  { "System Sound Service",
+    NS_SYSTEM_SOUND_SERVICE_CID,
+    "@mozilla.org/systemsoundservice;1",
+    nsSystemSoundServiceConstructor },
   { "Transferable",
     NS_TRANSFERABLE_CID,
     "@mozilla.org/widget/transferable;1",
     nsTransferableConstructor },
   { "HTML Format Converter",
     NS_HTMLFORMATCONVERTER_CID,
     "@mozilla.org/widget/htmlformatconverter;1",
     nsHTMLFormatConverterConstructor },
--- a/widget/src/cocoa/Makefile.in
+++ b/widget/src/cocoa/Makefile.in
@@ -74,17 +74,17 @@ CMMSRCS = \
 		nsCocoaWindow.mm \
 		nsChildView.mm \
 		nsWindowMap.mm \
 		nsWidgetFactory.mm \
 		nsCursorManager.mm \
 		nsMacCursor.mm \
 		nsScreenCocoa.mm \
 		nsScreenManagerCocoa.mm \
-		nsSound.mm \
+		nsSystemSoundService.mm \
 		nsLookAndFeel.mm \
 		nsNativeThemeCocoa.mm \
 		nsDeviceContextSpecX.mm \
 		nsPrintDialogX.mm \
 		nsPrintOptionsX.mm \
 		nsPrintSettingsX.mm \
 		nsIdleServiceX.mm \
 		nsAccelerometerX.mm \
rename from widget/src/cocoa/nsSound.h
rename to widget/src/cocoa/nsSystemSoundService.h
--- a/widget/src/cocoa/nsSound.h
+++ b/widget/src/cocoa/nsSystemSoundService.h
@@ -18,42 +18,45 @@
  * The Initial Developer of the Original Code is
  * Mozilla Corporation
  * Portions created by the Initial Developer are Copyright (C) 2006
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Stuart Parmenter <stuart@mozilla.com>
  *   Vladimir Vukicevic <vladimir@pobox.com>
+ *   Masayuki Nakano <masayuki@d-toybox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#ifndef nsSound_h_
-#define nsSound_h_
+#ifndef __nsSystemSoundService_h__
+#define __nsSystemSoundService_h__
 
-#include "nsISound.h"
-#include "nsIStreamLoader.h"
+#include "nsSound.h"
 
-class nsSound : public nsISound,
-                public nsIStreamLoaderObserver
+class nsSystemSoundService : public nsSystemSoundServiceBase
 {
-public: 
-    nsSound();
-    virtual ~nsSound();
+public:
+  nsSystemSoundService();
+  virtual ~nsSystemSoundService();
+
+  NS_DECL_ISYSTEMSOUNDSERVICE_GETINSTANCE(nsSystemSoundService)
 
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSISOUND
-    NS_DECL_NSISTREAMLOADEROBSERVER
+  NS_DECL_ISUPPORTS
+
+  NS_IMETHOD Beep();
+  NS_IMETHOD PlayAlias(const nsAString &aSoundAlias);
+  NS_IMETHOD PlayEventSound(PRUint32 aEventID);
 };
 
-#endif // nsSound_h_
+#endif // __nsSystemSoundService_h__
rename from widget/src/cocoa/nsSound.mm
rename to widget/src/cocoa/nsSystemSoundService.mm
--- a/widget/src/cocoa/nsSound.mm
+++ b/widget/src/cocoa/nsSystemSoundService.mm
@@ -18,119 +18,91 @@
  * The Initial Developer of the Original Code is
  * Mozilla Corporation
  * Portions created by the Initial Developer are Copyright (C) 2006
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Stuart Parmenter <stuart@mozilla.com>
  *   Vladimir Vukicevic <vladimir@pobox.com>
+ *   Masayuki Nakano <masayuki@d-toybox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "nsSound.h"
+#include "nsSystemSoundService.h"
 #include "nsObjCExceptions.h"
-#include "nsNetUtil.h"
-#include "nsCOMPtr.h"
-#include "nsIURL.h"
-#include "nsString.h"
 
 #import <Cocoa/Cocoa.h>
 
-NS_IMPL_ISUPPORTS2(nsSound, nsISound, nsIStreamLoaderObserver)
+/*****************************************************************************
+ *  nsSystemSoundService implementation
+ *****************************************************************************/
 
-nsSound::nsSound()
+NS_IMPL_ISUPPORTS1(nsSystemSoundService, nsISystemSoundService)
+
+NS_IMPL_ISYSTEMSOUNDSERVICE_GETINSTANCE(nsSystemSoundService)
+
+nsSystemSoundService::nsSystemSoundService() :
+  nsSystemSoundServiceBase()
 {
 }
 
-nsSound::~nsSound()
+nsSystemSoundService::~nsSystemSoundService()
 {
 }
 
 NS_IMETHODIMP
-nsSound::Beep()
+nsSystemSoundService::Beep()
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
+  nsresult rv = nsSystemSoundServiceBase::Beep();
+  NS_ENSURE_SUCCESS(rv, rv);
+
   NSBeep();
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 NS_IMETHODIMP
-nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
-                          nsISupports *context,
-                          nsresult aStatus,
-                          PRUint32 dataLen,
-                          const PRUint8 *data)
+nsSystemSoundService::PlayAlias(const nsAString &aSoundAlias)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
-  NSData *value = [NSData dataWithBytes:data length:dataLen];
-
-  NSSound *sound = [[NSSound alloc] initWithData:value];
-
-  [sound play];
-
-  [sound autorelease];
-
-  return NS_OK;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP
-nsSound::Play(nsIURL *aURL)
-{
-  nsCOMPtr<nsIURI> uri(do_QueryInterface(aURL));
-  nsCOMPtr<nsIStreamLoader> loader;
-  return NS_NewStreamLoader(getter_AddRefs(loader), uri, this);
-}
-
-NS_IMETHODIMP
-nsSound::Init()
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSound::PlaySystemSound(const nsAString &aSoundAlias)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  if (NS_IsMozAliasSound(aSoundAlias)) {
-    NS_WARNING("nsISound::playSystemSound is called with \"_moz_\" events, they are obsolete, use nsISound::playEventSound instead");
-    // Mac doesn't have system sound settings for each user actions.
-    return NS_OK;
-  }
+  nsresult rv = nsSystemSoundServiceBase::PlayAlias(aSoundAlias);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   NSString *name = [NSString stringWithCharacters:aSoundAlias.BeginReading()
                                            length:aSoundAlias.Length()];
   NSSound *sound = [NSSound soundNamed:name];
   if (sound) {
+    StopSoundPlayer();
     [sound stop];
     [sound play];
   }
 
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 NS_IMETHODIMP
-nsSound::PlayEventSound(PRUint32 aEventId)
+nsSystemSoundService::PlayEventSound(PRUint32 aEventID)
 {
+  nsresult rv = nsSystemSoundServiceBase::PlayEventSound(aEventID);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   // Mac doesn't have system sound settings for each user actions.
   return NS_OK;
 }
--- a/widget/src/cocoa/nsWidgetFactory.mm
+++ b/widget/src/cocoa/nsWidgetFactory.mm
@@ -54,30 +54,33 @@
 #include "nsTransferable.h"
 #include "nsHTMLFormatConverter.h"
 #include "nsDragService.h"
 
 #include "nsLookAndFeel.h"
 
 #include "nsAccelerometerX.h"
 #include "nsSound.h"
+#include "nsSystemSoundService.h"
 #include "nsIdleServiceX.h"
 
 #include "nsScreenManagerCocoa.h"
 #include "nsDeviceContextSpecX.h"
 #include "nsPrintOptionsX.h"
 #include "nsPrintDialogX.h"
 #include "nsPrintSession.h"
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsCocoaWindow)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsChildView)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePicker)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsToolkit)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsLookAndFeel)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSystemSoundService,
+                                         nsSystemSoundService::GetInstance)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsAccelerometerX)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsTransferable)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboard)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardHelper)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDragService)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsScreenManagerCocoa)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceContextSpecX)
@@ -124,16 +127,20 @@ static const nsModuleComponentInfo gComp
   { "Look And Feel",
     NS_LOOKANDFEEL_CID,
     "@mozilla.org/widget/lookandfeel;1",
     nsLookAndFeelConstructor },
   { "Sound",
     NS_SOUND_CID,
     "@mozilla.org/sound;1",
     nsSoundConstructor },
+  { "System Sound Service",
+    NS_SYSTEM_SOUND_SERVICE_CID,
+    "@mozilla.org/systemsoundservice;1",
+    nsSystemSoundServiceConstructor },
   { "Accelerometer",
     NS_ACCELEROMETER_CID,
     NS_ACCELEROMETER_CONTRACTID,
     nsAccelerometerXConstructor },
   { "Transferable",
     NS_TRANSFERABLE_CID,
     "@mozilla.org/widget/transferable;1",
     nsTransferableConstructor },
--- a/widget/src/gtk2/Makefile.in
+++ b/widget/src/gtk2/Makefile.in
@@ -67,17 +67,17 @@ CPPSRCS		= \
 		nsWindow.cpp \
 		nsAppShell.cpp \
 		nsWidgetFactory.cpp \
 		nsToolkit.cpp \
 		nsBidiKeyboard.cpp \
 		nsLookAndFeel.cpp \
 		nsGtkKeyUtils.cpp \
 		nsFilePicker.cpp \
-		nsSound.cpp \
+		nsSystemSoundService.cpp \
 		nsNativeKeyBindings.cpp \
 		nsScreenGtk.cpp \
 		nsScreenManagerGtk.cpp \
 		nsImageToPixbuf.cpp \
 		nsAccessibilityHelper.cpp \
 		nsAccelerometerUnix.cpp \
 		$(NULL)
 
rename from widget/src/gtk2/nsSound.cpp
rename to widget/src/gtk2/nsSystemSoundService.cpp
--- a/widget/src/gtk2/nsSound.cpp
+++ b/widget/src/gtk2/nsSystemSoundService.cpp
@@ -18,76 +18,41 @@
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 2000
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Stuart Parmenter <pavlov@netscape.com>
+ *   Masayuki Nakano <masayuki@d-toybox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include <string.h>
-
-#include "nscore.h"
-#include "plstr.h"
+#include "nsSystemSoundService.h"
 #include "prlink.h"
 
-#include "nsSound.h"
-
-#include "nsIURL.h"
-#include "nsIFileURL.h"
-#include "nsNetUtil.h"
-#include "nsCOMPtr.h"
-#include "nsAutoPtr.h"
-#include "nsString.h"
-
-#include <stdio.h>
-#include <unistd.h>
-
 #include <gtk/gtk.h>
-/* used with esd_open_sound */
-static int esdref = -1;
-static PRLibrary *elib = nsnull;
+#include <stdint.h>
+
 static PRLibrary *libcanberra = nsnull;
 static PRLibrary* libasound = nsnull;
 
-// the following from esd.h
-
-#define ESD_BITS8  (0x0000)
-#define ESD_BITS16 (0x0001) 
-#define ESD_MONO (0x0010)
-#define ESD_STEREO (0x0020) 
-#define ESD_STREAM (0x0000)
-#define ESD_PLAY (0x1000)
-
-#define WAV_MIN_LENGTH 44
-
-typedef int (*EsdOpenSoundType)(const char *host);
-typedef int (*EsdCloseType)(int);
-
-/* used to play the sounds from the find symbol call */
-typedef int  (*EsdPlayStreamType) (int, int, const char *, const char *);
-typedef int  (*EsdAudioOpenType)  (void);
-typedef int  (*EsdAudioWriteType) (const void *, int);
-typedef void (*EsdAudioCloseType) (void);
-
 /* used to find and play common system event sounds.
    this interfaces with libcanberra.
  */
 typedef struct _ca_context ca_context;
 
 typedef int (*ca_context_create_fn) (ca_context **);
 typedef int (*ca_context_destroy_fn) (ca_context *);
 typedef int (*ca_context_play_fn) (ca_context *c,
@@ -116,430 +81,158 @@ quiet_error_handler(const char* file,
                     int         line,
                     const char* function,
                     int         err,
                     const char* format,
                     ...)
 {
 }
 
-NS_IMPL_ISUPPORTS2(nsSound, nsISound, nsIStreamLoaderObserver)
+/*****************************************************************************
+ *  nsSystemSoundService implementation
+ *****************************************************************************/
+
+NS_IMPL_ISUPPORTS1(nsSystemSoundService, nsISystemSoundService)
 
-////////////////////////////////////////////////////////////////////////
-nsSound::nsSound()
+NS_IMPL_ISYSTEMSOUNDSERVICE_GETINSTANCE(nsSystemSoundService)
+
+nsSystemSoundService::nsSystemSoundService() :
+  nsSystemSoundServiceBase()
 {
-    mInited = PR_FALSE;
 }
 
-nsSound::~nsSound()
+nsSystemSoundService::~nsSystemSoundService()
 {
-    if (esdref >= 0) {
-        EsdCloseType EsdClose = (EsdCloseType) PR_FindFunctionSymbol(elib, "esd_close");
-        if (EsdClose)
-            (*EsdClose)(esdref);
-        esdref = -1;
-    }
 }
 
-NS_IMETHODIMP
-nsSound::Init()
+nsresult
+nsSystemSoundService::Init()
 {
-    // This function is designed so that no library is compulsory, and
-    // one library missing doesn't cause the other(s) to not be used.
-    if (mInited) 
-        return NS_OK;
-
-    mInited = PR_TRUE;
-
-    if (!elib) {
-        elib = PR_LoadLibrary("libesd.so.0");
-        if (elib) {
-            EsdOpenSoundType EsdOpenSound =
-                (EsdOpenSoundType) PR_FindFunctionSymbol(elib, "esd_open_sound");
-            if (!EsdOpenSound) {
-                PR_UnloadLibrary(elib);
-                elib = nsnull;
-            } else {
-                esdref = (*EsdOpenSound)("localhost");
-                if (esdref < 0) {
-                    PR_UnloadLibrary(elib);
-                    elib = nsnull;
-                }
-            }
-        }
+    PRFuncPtr func =
+        PR_FindFunctionSymbolAndLibrary("snd_lib_error_set_handler",
+                                        &libasound);
+    if (libasound) {
+        snd_lib_error_set_handler_fn snd_lib_error_set_handler =
+             (snd_lib_error_set_handler_fn) func;
+        snd_lib_error_set_handler(quiet_error_handler);
     }
 
-    if (!libasound) {
-        PRFuncPtr func = PR_FindFunctionSymbolAndLibrary("snd_lib_error_set_handler",
-                                                         &libasound);
-        if (libasound) {
-            snd_lib_error_set_handler_fn snd_lib_error_set_handler =
-                 (snd_lib_error_set_handler_fn) func;
-            snd_lib_error_set_handler(quiet_error_handler);
-        }
-    }
-
-    if (!libcanberra) {
-        libcanberra = PR_LoadLibrary("libcanberra.so.0");
-        if (libcanberra) {
-            ca_context_create = (ca_context_create_fn) PR_FindFunctionSymbol(libcanberra, "ca_context_create");
-            if (!ca_context_create) {
-                PR_UnloadLibrary(libcanberra);
-                libcanberra = nsnull;
-            } else {
-                // at this point we know we have a good libcanberra library
-                ca_context_destroy = (ca_context_destroy_fn) PR_FindFunctionSymbol(libcanberra, "ca_context_destroy");
-                ca_context_play = (ca_context_play_fn) PR_FindFunctionSymbol(libcanberra, "ca_context_play");
-                ca_context_change_props = (ca_context_change_props_fn) PR_FindFunctionSymbol(libcanberra, "ca_context_change_props");
-            }
+    libcanberra = PR_LoadLibrary("libcanberra.so.0");
+    if (libcanberra) {
+        ca_context_create = (ca_context_create_fn)
+             PR_FindFunctionSymbol(libcanberra, "ca_context_create");
+        if (!ca_context_create) {
+            PR_UnloadLibrary(libcanberra);
+            libcanberra = nsnull;
+        } else {
+            // at this point we know we have a good libcanberra library
+            ca_context_destroy = (ca_context_destroy_fn)
+                PR_FindFunctionSymbol(libcanberra, "ca_context_destroy");
+            ca_context_play = (ca_context_play_fn)
+                PR_FindFunctionSymbol(libcanberra, "ca_context_play");
+            ca_context_change_props = (ca_context_change_props_fn)
+                PR_FindFunctionSymbol(libcanberra, "ca_context_change_props");
         }
     }
 
     return NS_OK;
 }
 
-/* static */ void
-nsSound::Shutdown()
+void
+nsSystemSoundService::OnShutdown()
 {
-    if (elib) {
-        PR_UnloadLibrary(elib);
-        elib = nsnull;
-    }
     if (libcanberra) {
         PR_UnloadLibrary(libcanberra);
         libcanberra = nsnull;
     }
     if (libasound) {
         PR_UnloadLibrary(libasound);
         libasound = nsnull;
     }
 }
 
-#define GET_WORD(s, i) (s[i+1] << 8) | s[i]
-#define GET_DWORD(s, i) (s[i+3] << 24) | (s[i+2] << 16) | (s[i+1] << 8) | s[i]
-
-NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
-                                        nsISupports *context,
-                                        nsresult aStatus,
-                                        PRUint32 dataLen,
-                                        const PRUint8 *data)
+NS_IMETHODIMP
+nsSystemSoundService::Beep()
 {
-
-    // print a load error on bad status, and return
-    if (NS_FAILED(aStatus)) {
-#ifdef DEBUG
-        if (aLoader) {
-            nsCOMPtr<nsIRequest> request;
-            aLoader->GetRequest(getter_AddRefs(request));
-            if (request) {
-                nsCOMPtr<nsIURI> uri;
-                nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
-                if (channel) {
-                      channel->GetURI(getter_AddRefs(uri));
-                      if (uri) {
-                            nsCAutoString uriSpec;
-                            uri->GetSpec(uriSpec);
-                            printf("Failed to load %s\n", uriSpec.get());
-                      }
-                }
-            }
-        }
-#endif
-        return aStatus;
-    }
-
-    int fd, mask = 0;
-    PRUint32 samples_per_sec = 0, avg_bytes_per_sec = 0, chunk_len = 0;
-    PRUint16 format, channels = 1, bits_per_sample = 0;
-    const PRUint8 *audio = nsnull;
-    size_t audio_len = 0;
-
-    if (dataLen < 4) {
-        NS_WARNING("Sound stream too short to determine its type");
-        return NS_ERROR_FAILURE;
-    }
-
-    if (memcmp(data, "RIFF", 4)) {
-#ifdef DEBUG
-        printf("We only support WAV files currently.\n");
-#endif
-        return NS_ERROR_FAILURE;
-    }
-
-    if (dataLen <= WAV_MIN_LENGTH) {
-        NS_WARNING("WAV files should be longer than 44 bytes.");
-        return NS_ERROR_FAILURE;
-    }
-
-    PRUint32 i = 12;
-    while (i + 7 < dataLen) {
-        if (!memcmp(data + i, "fmt ", 4) && !chunk_len) {
-            i += 4;
-
-            /* length of the rest of this subblock (should be 16 for PCM data */
-            chunk_len = GET_DWORD(data, i);
-            i += 4;
-
-            if (chunk_len < 16 || i + chunk_len >= dataLen) {
-                NS_WARNING("Invalid WAV file: bad fmt chunk.");
-                return NS_ERROR_FAILURE;
-            }
-
-            format = GET_WORD(data, i);
-            i += 2;
-
-            channels = GET_WORD(data, i);
-            i += 2;
-
-            samples_per_sec = GET_DWORD(data, i);
-            i += 4;
-
-            avg_bytes_per_sec = GET_DWORD(data, i);
-            i += 4;
-
-            // block align
-            i += 2;
-
-            bits_per_sample = GET_WORD(data, i);
-            i += 2;
-
-            /* we don't support WAVs with odd compression codes */
-            if (chunk_len != 16)
-                NS_WARNING("Extra format bits found in WAV. Ignoring");
-
-            i += chunk_len - 16;
-        } else if (!memcmp(data + i, "data", 4)) {
-            i += 4;
-            if (!chunk_len) {
-                NS_WARNING("Invalid WAV file: no fmt chunk found");
-                return NS_ERROR_FAILURE;
-            }
-
-            audio_len = GET_DWORD(data, i);
-            i += 4;
+    nsresult rv = nsSystemSoundServiceBase::Beep();
+    NS_ENSURE_SUCCESS(rv, rv);
 
-            /* try to play truncated WAVs */
-            if (i + audio_len > dataLen)
-                audio_len = dataLen - i;
-
-            audio = data + i;
-            break;
-        } else {
-            i += 4;
-            i += GET_DWORD(data, i);
-            i += 4;
-        }
-    }
-
-    if (!audio) {
-        NS_WARNING("Invalid WAV file: no data chunk found");
-        return NS_ERROR_FAILURE;
-    }
-
-    /* No audio data? well, at least the WAV was valid. */
-    if (!audio_len)
-        return NS_OK;
-
-#if 0
-    printf("f: %d | c: %d | sps: %li | abps: %li | ba: %d | bps: %d | rate: %li\n",
-         format, channels, samples_per_sec, avg_bytes_per_sec, block_align, bits_per_sample, rate);
-#endif
-
-    /* open up connection to esd */  
-    EsdPlayStreamType EsdPlayStream = 
-        (EsdPlayStreamType) PR_FindFunctionSymbol(elib, 
-                                                  "esd_play_stream");
-    if (!EsdPlayStream)
-        return NS_ERROR_FAILURE;
-
-    mask = ESD_PLAY | ESD_STREAM;
-
-    if (bits_per_sample == 8)
-        mask |= ESD_BITS8;
-    else 
-        mask |= ESD_BITS16;
-
-    if (channels == 1)
-        mask |= ESD_MONO;
-    else 
-        mask |= ESD_STEREO;
-
-    nsAutoArrayPtr<PRUint8> buf;
-
-    // ESD only handle little-endian data. 
-    // Swap the byte order if we're on a big-endian architecture.
-#ifdef IS_BIG_ENDIAN
-    if (bits_per_sample != 8) {
-        buf = new PRUint8[audio_len];
-        if (!buf)
-            return NS_ERROR_OUT_OF_MEMORY;
-        for (PRUint32 j = 0; j + 2 < audio_len; j += 2) {
-            buf[j]     = audio[j + 1];
-            buf[j + 1] = audio[j];
-        }
-
-        audio = buf;
-    }
-#endif
-
-    fd = (*EsdPlayStream)(mask, samples_per_sec, NULL, "mozillaSound"); 
-  
-    if (fd < 0) {
-      int *esd_audio_format = (int *) PR_FindSymbol(elib, "esd_audio_format");
-      int *esd_audio_rate = (int *) PR_FindSymbol(elib, "esd_audio_rate");
-      EsdAudioOpenType EsdAudioOpen = (EsdAudioOpenType) PR_FindFunctionSymbol(elib, "esd_audio_open");
-      EsdAudioWriteType EsdAudioWrite = (EsdAudioWriteType) PR_FindFunctionSymbol(elib, "esd_audio_write");
-      EsdAudioCloseType EsdAudioClose = (EsdAudioCloseType) PR_FindFunctionSymbol(elib, "esd_audio_close");
-
-      if (!esd_audio_format || !esd_audio_rate ||
-          !EsdAudioOpen || !EsdAudioWrite || !EsdAudioClose)
-          return NS_ERROR_FAILURE;
-
-      *esd_audio_format = mask;
-      *esd_audio_rate = samples_per_sec;
-      fd = (*EsdAudioOpen)();
-
-      if (fd < 0)
-        return NS_ERROR_FAILURE;
-
-      (*EsdAudioWrite)(audio, audio_len);
-      (*EsdAudioClose)();
-    } else {
-      while (audio_len > 0) {
-        ssize_t written = write(fd, audio, audio_len);
-        if (written <= 0)
-          break;
-        audio += written;
-        audio_len -= written;
-      }
-      close(fd);
-    }
-
-    return NS_OK;
-}
-
-NS_METHOD nsSound::Beep()
-{
     ::gdk_beep();
     return NS_OK;
 }
 
-NS_METHOD nsSound::Play(nsIURL *aURL)
+NS_IMETHODIMP
+nsSystemSoundService::PlayEventSound(PRUint32 aEventID)
 {
-    nsresult rv;
-
-    if (!mInited)
-        Init();
-
-    if (!elib) 
-	    return NS_ERROR_FAILURE;
-
-    nsCOMPtr<nsIStreamLoader> loader;
-    rv = NS_NewStreamLoader(getter_AddRefs(loader), aURL, this);
-
-    return rv;
-}
-
-NS_IMETHODIMP nsSound::PlayEventSound(PRUint32 aEventId)
-{
-    if (!mInited)
-        Init();
+    nsresult rv = nsSystemSoundServiceBase::PlayEventSound(aEventID);
+    NS_ENSURE_SUCCESS(rv, rv);
 
     if (!libcanberra)
         return NS_OK;
 
     // Do we even want alert sounds?
     // If so, what sound theme are we using?
     GtkSettings* settings = gtk_settings_get_default();
     gchar* sound_theme_name = nsnull;
 
-    if (g_object_class_find_property(G_OBJECT_GET_CLASS(settings), "gtk-sound-theme-name") &&
-        g_object_class_find_property(G_OBJECT_GET_CLASS(settings), "gtk-enable-event-sounds")) {
+    if (g_object_class_find_property(G_OBJECT_GET_CLASS(settings),
+                                     "gtk-sound-theme-name") &&
+        g_object_class_find_property(G_OBJECT_GET_CLASS(settings),
+                                     "gtk-enable-event-sounds")) {
         gboolean enable_sounds = TRUE;
         g_object_get(settings, "gtk-enable-event-sounds", &enable_sounds,
                                "gtk-sound-theme-name", &sound_theme_name,
                                NULL);
 
         if (!enable_sounds) {
             g_free(sound_theme_name);
             return NS_OK;
         }
     }
 
-    // This allows us to avoid race conditions with freeing the context by handing that
-    // responsibility to Glib, and still use one context at a time
+    // This allows us to avoid race conditions with freeing the context by
+    // handing that responsibility to Glib, and still use one context at a time
     ca_context* ctx = nsnull;
     static GStaticPrivate ctx_static_private = G_STATIC_PRIVATE_INIT;
     ctx = (ca_context*) g_static_private_get(&ctx_static_private);
     if (!ctx) {
         ca_context_create(&ctx);
         if (!ctx) {
             g_free(sound_theme_name);
             return NS_ERROR_OUT_OF_MEMORY;
         }
 
-        g_static_private_set(&ctx_static_private, ctx, (GDestroyNotify) ca_context_destroy);
+        g_static_private_set(&ctx_static_private, ctx,
+                             (GDestroyNotify) ca_context_destroy);
     }
 
     if (sound_theme_name) {
-        ca_context_change_props(ctx, "canberra.xdg-theme.name", sound_theme_name, NULL);
+        ca_context_change_props(ctx, "canberra.xdg-theme.name",
+                                sound_theme_name, NULL);
         g_free(sound_theme_name);
     }
 
-    switch (aEventId) {
+    const char* eventID = nsnull;
+    switch (aEventID) {
         case EVENT_ALERT_DIALOG_OPEN:
-            ca_context_play(ctx, 0, "event.id", "dialog-warning", NULL);
+            eventID = "dialog-warning";
             break;
         case EVENT_CONFIRM_DIALOG_OPEN:
-            ca_context_play(ctx, 0, "event.id", "dialog-question", NULL);
+            eventID = "dialog-question";
             break;
         case EVENT_NEW_MAIL_RECEIVED:
-            ca_context_play(ctx, 0, "event.id", "message-new-email", NULL);
+            eventID = "message-new-email";
             break;
         case EVENT_MENU_EXECUTE:
-            ca_context_play(ctx, 0, "event.id", "menu-click", NULL);
+            eventID = "menu-click";
             break;
         case EVENT_MENU_POPUP:
-            ca_context_play(ctx, 0, "event.id", "menu-popup", NULL);
+            eventID = "menu-popup";
             break;
+        default:
+            return NS_OK;
     }
+
+    StopSoundPlayer();
+    ca_context_play(ctx, 0, "event.id", eventID, NULL);
+
     return NS_OK;
 }
-
-NS_IMETHODIMP nsSound::PlaySystemSound(const nsAString &aSoundAlias)
-{
-    if (NS_IsMozAliasSound(aSoundAlias)) {
-        NS_WARNING("nsISound::playSystemSound is called with \"_moz_\" events, they are obsolete, use nsISound::playEventSound instead");
-        PRUint32 eventId;
-        if (aSoundAlias.Equals(NS_SYSSOUND_ALERT_DIALOG))
-            eventId = EVENT_ALERT_DIALOG_OPEN;
-        else if (aSoundAlias.Equals(NS_SYSSOUND_CONFIRM_DIALOG))
-            eventId = EVENT_CONFIRM_DIALOG_OPEN;
-        else if (aSoundAlias.Equals(NS_SYSSOUND_MAIL_BEEP))
-            eventId = EVENT_NEW_MAIL_RECEIVED;
-        else if (aSoundAlias.Equals(NS_SYSSOUND_MENU_EXECUTE))
-            eventId = EVENT_MENU_EXECUTE;
-        else if (aSoundAlias.Equals(NS_SYSSOUND_MENU_POPUP))
-            eventId = EVENT_MENU_POPUP;
-        else
-            return NS_OK;
-        return PlayEventSound(eventId);
-    }
-
-    nsresult rv;
-    nsCOMPtr <nsIURI> fileURI;
-
-    // create a nsILocalFile and then a nsIFileURL from that
-    nsCOMPtr <nsILocalFile> soundFile;
-    rv = NS_NewLocalFile(aSoundAlias, PR_TRUE, 
-                         getter_AddRefs(soundFile));
-    NS_ENSURE_SUCCESS(rv,rv);
-
-    rv = NS_NewFileURI(getter_AddRefs(fileURI), soundFile);
-    NS_ENSURE_SUCCESS(rv,rv);
-
-    nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(fileURI,&rv);
-    NS_ENSURE_SUCCESS(rv,rv);
-
-    rv = Play(fileURL);
-
-    return rv;
-}
rename from widget/src/gtk2/nsSound.h
rename to widget/src/gtk2/nsSystemSoundService.h
--- a/widget/src/gtk2/nsSound.h
+++ b/widget/src/gtk2/nsSystemSoundService.h
@@ -18,50 +18,48 @@
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 2000
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Stuart Parmenter <pavlov@netscape.com>
+ *   Masayuki Nakano <masayuki@d-toybox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#ifndef __nsSound_h__
-#define __nsSound_h__
+#ifndef __nsSystemSoundService_h__
+#define __nsSystemSoundService_h__
 
-#include "nsISound.h"
-#include "nsIStreamLoader.h"
-
-#include <gtk/gtk.h>
+#include "nsSound.h"
 
-class nsSound : public nsISound, 
-                public nsIStreamLoaderObserver
-{ 
-public: 
-    nsSound(); 
-    virtual ~nsSound();
+class nsSystemSoundService : public nsSystemSoundServiceBase
+{
+public:
+    nsSystemSoundService();
+    virtual ~nsSystemSoundService();
 
-    static void Shutdown();
+    NS_DECL_ISYSTEMSOUNDSERVICE_GETINSTANCE(nsSystemSoundService)
 
     NS_DECL_ISUPPORTS
-    NS_DECL_NSISOUND
-    NS_DECL_NSISTREAMLOADEROBSERVER
+
+    NS_IMETHOD Beep();
+    NS_IMETHOD PlayEventSound(PRUint32 aEventID);
 
-private:
-    PRBool mInited;
-
+protected:
+    virtual nsresult Init();
+    virtual void OnShutdown();
 };
 
-#endif /* __nsSound_h__ */
+#endif /* __nsSystemSoundService_h__ */
--- a/widget/src/gtk2/nsWidgetFactory.cpp
+++ b/widget/src/gtk2/nsWidgetFactory.cpp
@@ -47,16 +47,17 @@
 #include "nsHTMLFormatConverter.h"
 #ifdef MOZ_X11
 #include "nsClipboardHelper.h"
 #include "nsClipboard.h"
 #include "nsDragService.h"
 #endif
 #include "nsFilePicker.h"
 #include "nsSound.h"
+#include "nsSystemSoundService.h"
 #include "nsBidiKeyboard.h"
 #include "nsNativeKeyBindings.h"
 #include "nsScreenManagerGtk.h"
 #include "nsAccelerometerUnix.h"
 
 #ifdef NS_PRINTING
 #include "nsPrintOptionsGTK.h"
 #include "nsPrintSession.h"
@@ -95,16 +96,18 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsTransfe
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsBidiKeyboard)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter)
 #ifdef MOZ_X11
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardHelper)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsClipboard, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDragService)
 #endif
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSystemSoundService,
+                                         nsSystemSoundService::GetInstance)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsScreenManagerGtk)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsImageToPixbuf)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsAccelerometerUnix)
 
 
 #ifdef NATIVE_THEME_SUPPORT
 // from nsWindow.cpp
 extern PRBool gDisableNativeTheme;
@@ -249,16 +252,20 @@ static const nsModuleComponentInfo compo
     { "Gtk2 File Picker",
       NS_FILEPICKER_CID,
       "@mozilla.org/filepicker;1",
       nsFilePickerConstructor },
     { "Gtk2 Sound",
       NS_SOUND_CID,
       "@mozilla.org/sound;1",
       nsSoundConstructor },
+    { "System Sound Service",
+      NS_SYSTEM_SOUND_SERVICE_CID,
+      "@mozilla.org/systemsoundservice;1",
+      nsSystemSoundServiceConstructor },
     { "Accelerometer",
        NS_ACCELEROMETER_CID,
        NS_ACCELEROMETER_CONTRACTID,
        nsAccelerometerUnixConstructor },
     { "Transferable",
       NS_TRANSFERABLE_CID,
       "@mozilla.org/widget/transferable;1",
       nsTransferableConstructor },
@@ -343,17 +350,16 @@ static const nsModuleComponentInfo compo
 #endif
 
 };
 
 static void
 nsWidgetGtk2ModuleDtor(nsIModule *aSelf)
 {
   nsFilePicker::Shutdown();
-  nsSound::Shutdown();
   nsWindow::ReleaseGlobals();
   nsAppShellShutdown(aSelf);
 }
 
 NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(nsWidgetGtk2Module,
                                    components,
                                    nsAppShellInit,
                                    nsWidgetGtk2ModuleDtor)
--- a/widget/src/os2/Makefile.in
+++ b/widget/src/os2/Makefile.in
@@ -60,17 +60,17 @@ CPPSRCS		= \
 		nsAppShell.cpp \
 		nsBidiKeyboard.cpp \
 		nsClipboard.cpp \
 		nsFilePicker.cpp \
 		nsFrameWindow.cpp \
 		nsLookAndFeel.cpp \
 		nsOS2Uni.cpp \
 		nsPrintOS2.cpp \
-		nsSound.cpp \
+		nsSystemSoundService.cpp \
 		nsToolkit.cpp \
 		nsWidgetFactory.cpp \
 		nsWindow.cpp \
 		nsDragService.cpp \
 		nsScreenOS2.cpp	\
 		nsScreenManagerOS2.cpp \
 		nsDeviceContextSpecOS2.cpp \
 		nsPrintOptionsOS2.cpp \
rename from widget/src/os2/nsSound.cpp
rename to widget/src/os2/nsSystemSoundService.cpp
--- a/widget/src/os2/nsSound.cpp
+++ b/widget/src/os2/nsSystemSoundService.cpp
@@ -22,16 +22,17 @@
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Stuart Parmenter <pavlov@netscape.com>
  *   John Fairhurst <john_fairhurst@iname.com>
  *   IBM Corp.
  *   Peter Weilbacher <mozilla@Weilbacher.org>
  *   Lars Erdmann
+ *   Masayuki Nakano <masayuki@d-toybox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -51,29 +52,19 @@
 #define INCL_DOS
 #define INCL_DOSERRORS
 #define INCL_MMIOOS2
 #include <os2.h>
 #include <mmioos2.h>
 #include <mcios2.h>
 #define MCI_ERROR_LENGTH 128
 
-#include "nsSound.h"
-#include "nsIURL.h"
-#include "nsNetUtil.h"
-#include "nsString.h"
-
-#include "nsDirectoryServiceDefs.h"
-
+#include "nsSystemSoundService.h"
 #include "nsNativeCharsetUtils.h"
 
-NS_IMPL_ISUPPORTS2(nsSound, nsISound, nsIStreamLoaderObserver)
-
-static int sInitialized = 0;
-static PRBool sMMPMInstalled = PR_FALSE;
 static HMODULE sHModMMIO = NULLHANDLE;
 
 // function pointer definitions, include underscore (work around redef. warning)
 HMMIO (*APIENTRY _mmioOpen)(PSZ, PMMIOINFO, ULONG);
 USHORT (*APIENTRY _mmioClose)(HMMIO, USHORT);
 ULONG (*APIENTRY _mmioGetFormats)(PMMFORMATINFO, LONG, PVOID, PLONG, ULONG, ULONG);
 ULONG (*APIENTRY _mciSendCommand)(USHORT, USHORT, ULONG, PVOID, USHORT);
 #ifdef DEBUG
@@ -90,29 +81,47 @@ typedef struct _ARGBUFFER
   HEV hev;
   PRUint32 bufLen;
   const char *buffer;
   PSZ pszFilename;
 } ARGBUFFER;
 
 ////////////////////////////////////////////////////////////////////////
 
+static void FinalizeGlobals(void)
+{
+  if (sHModMMIO == NULLHANDLE) {
+    return;
+  }
+
+  ULONG ulrc;
+  ulrc = DosFreeModule(sHModMMIO);
+  // do not free MDM.DLL because it doesn't like to be unloaded repeatedly
+  if (ulrc != NO_ERROR) {
+    NS_WARNING("DosFreeModule did not work");
+  }
+  sHModMMIO = NULLHANDLE;
+}
+
 static void InitGlobals(void)
 {
+  if (sHModMMIO != NULLHANDLE) {
+    return;
+  }
+
   ULONG ulrc = 0;
   char LoadError[CCHMAXPATH];
   HMODULE hModMDM = NULLHANDLE;
 
   ulrc = DosLoadModule(LoadError, CCHMAXPATH, "MMIO", &sHModMMIO);
   ulrc += DosLoadModule(LoadError, CCHMAXPATH, "MDM", &hModMDM);
   if (ulrc == NO_ERROR) {
 #ifdef DEBUG
     printf("InitGlobals: MMOS2 is installed, both DLLs loaded\n");
 #endif
-    sMMPMInstalled = PR_TRUE;
     // MMOS2 is installed, so we can query the necessary functions
     // mmio functions are in MMIO.DLL
     ulrc = DosQueryProcAddr(sHModMMIO, 0L, "mmioOpen", (PFN *)&_mmioOpen);
     ulrc += DosQueryProcAddr(sHModMMIO, 0L, "mmioClose", (PFN *)&_mmioClose);
     ulrc += DosQueryProcAddr(sHModMMIO, 0L, "mmioGetFormats", (PFN *)&_mmioGetFormats);
     // mci functions are in MDM.DLL
     ulrc += DosQueryProcAddr(hModMDM, 0L, "mciSendCommand", (PFN *)&_mciSendCommand);
 #ifdef DEBUG
@@ -122,17 +131,17 @@ static void InitGlobals(void)
     ulrc += DosQueryProcAddr(hModMDM, 0L, "mciGetErrorString", (PFN *)&_mciGetErrorString);
 #endif
 
     ulrc += DosQueryProcAddr(sHModMMIO, 0L, "mmioIniFileHandler", (PFN *)&_mmioIniFileHandler);
 
     // if one of these failed, we have some kind of non-functional MMOS2 installation
     if (ulrc != NO_ERROR) {
       NS_WARNING("MMOS2 is installed, but seems to have corrupt DLLs");
-      sMMPMInstalled = PR_FALSE;
+      FinalizeGlobals();
     }
   }
 }
 
 ////////////////////////////////////////////////////////////////////////
 
 // Tries to determine the data format in the buffer using file "magic"
 // and a loop through MMOS2 audio codecs.
@@ -329,16 +338,19 @@ static void playSound(void *aArgs)
       CHAR errorBuffer[MCI_ERROR_LENGTH];
       _mciGetErrorString(ulrc, errorBuffer, MCI_ERROR_LENGTH);
       printf("playSound: mciSendCommand with MCI_OPEN_MMIO returned %ld: %s\n",
              ulrc, errorBuffer);
 #endif
       break;
     }
 
+    // stop other sounds
+    nsSystemSoundServiceBase::StopSoundPlayer();
+
     // play the sound
     MCI_PLAY_PARMS mpp;
     memset(&mpp, '\0', sizeof(mpp));
     ulrc = _mciSendCommand(mop.usDeviceID, MCI_PLAY, MCI_WAIT, &mpp, 0);
 #ifdef DEBUG
     // just ignore further failures in non-debug mode
     if (ulrc != MCIERR_SUCCESS) {
       CHAR errorBuffer[MCI_ERROR_LENGTH];
@@ -367,142 +379,66 @@ static void playSound(void *aArgs)
   // cleanup after an error
   WinAlarm(HWND_DESKTOP, WA_WARNING); // Beep()
   if (hmmio)
     _mmioClose(hmmio, 0);
   if (mi.pchBuffer)
     DosFreeMem(mi.pchBuffer);
 }
 
-////////////////////////////////////////////////////////////////////////
+/*****************************************************************************
+ *  nsSystemSoundService implementation
+ *****************************************************************************/
 
-nsSound::nsSound()
-{
-  if (!sInitialized) {
-    InitGlobals();
-  }
-  sInitialized++;
-#ifdef DEBUG
-  printf("nsSound::nsSound: sInitialized=%d\n", sInitialized);
-#endif
-}
+NS_IMPL_ISUPPORTS1(nsSystemSoundService, nsISystemSoundService)
 
-nsSound::~nsSound()
+NS_IMPL_ISYSTEMSOUNDSERVICE_GETINSTANCE(nsSystemSoundService)
+
+nsSystemSoundService::nsSystemSoundService() :
+  nsSystemSoundServiceBase()
 {
-  sInitialized--;
-#ifdef DEBUG
-  printf("nsSound::~nsSound: sInitialized=%d\n", sInitialized);
-#endif
-  // (try to) unload modules after last user ended
-  if (!sInitialized) {
-#ifdef DEBUG
-    printf("nsSound::~nsSound: Trying to free modules...\n");
-#endif
-    ULONG ulrc;
-    ulrc = DosFreeModule(sHModMMIO);
-    // do not free MDM.DLL because it doesn't like to be unloaded repeatedly
-    if (ulrc != NO_ERROR) {
-      NS_WARNING("DosFreeModule did not work");
-    }
-  }
 }
 
-NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
-                                        nsISupports *context,
-                                        nsresult aStatus,
-                                        PRUint32 dataLen,
-                                        const PRUint8 *data)
+nsSystemSoundService::~nsSystemSoundService()
 {
-  if (NS_FAILED(aStatus)) {
-#ifdef DEBUG
-    if (aLoader) {
-      nsCOMPtr<nsIRequest> request;
-      aLoader->GetRequest(getter_AddRefs(request));
-      if (request) {
-        nsCOMPtr<nsIURI> uri;
-        nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
-        if (channel) {
-            channel->GetURI(getter_AddRefs(uri));
-            if (uri) {
-                nsCAutoString uriSpec;
-                uri->GetSpec(uriSpec);
-                printf("Failed to load %s\n", uriSpec.get());
-            }
-        }
-      }
-    }
-#endif
-    return NS_ERROR_FAILURE;
-  }
+}
 
-  if (!sMMPMInstalled) {
-    NS_WARNING("Sound output only works with MMOS2 installed");
-    Beep();
-    return NS_OK;
-  }
-
-  ARGBUFFER arg;
-  memset(&arg, '\0', sizeof(arg));
-  APIRET rc = DosCreateEventSem(NULL, &(arg.hev), 0UL, 0UL);
-
-  // Play the sound on a new thread using MMOS2, in this case pass
-  // the memory buffer in the argument structure.
-  arg.bufLen = dataLen;
-  arg.buffer = (char *)data;
-  _beginthread(playSound, NULL, 32768, (void *)&arg);
-
-  // Wait until the buffer was copied, but not indefinitely to not block the
-  // UI in case a really large sound file is copied.
-  rc = DosWaitEventSem(arg.hev, 100);
-  rc = DosCloseEventSem(arg.hev);
-
+nsresult
+nsSystemSoundService::Init()
+{
+  InitGlobals();
   return NS_OK;
 }
 
-NS_IMETHODIMP nsSound::Beep()
+void
+nsSystemSoundService::OnShutdown()
 {
+  FinalizeGlobals();
+}
+
+NS_IMETHODIMP
+nsSystemSoundService::Beep()
+{
+  nsresult rv = nsSystemSoundServiceBase::Beep();
+  NS_ENSURE_SUCCESS(rv, rv);
+
   WinAlarm(HWND_DESKTOP, WA_WARNING);
-
   return NS_OK;
 }
 
-NS_IMETHODIMP nsSound::Play(nsIURL *aURL)
+NS_IMETHODIMP
+nsSystemSoundService::PlayAlias(const nsAString &aSoundAlias)
 {
-  nsresult rv;
-
-  nsCOMPtr<nsIStreamLoader> loader;
-  rv = NS_NewStreamLoader(getter_AddRefs(loader), aURL, this);
+  nsresult rv = nsSystemSoundServiceBase::PlayAlias(aSoundAlias);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  return rv;
-}
-
-NS_IMETHODIMP nsSound::Init()
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsSound::PlaySystemSound(const nsAString &aSoundAlias)
-{
-  if (!sMMPMInstalled) {
+  if (sHModMMIO == NULLHANDLE) {
     return Beep();
   }
 
-  if (NS_IsMozAliasSound(aSoundAlias)) {
-    NS_WARNING("nsISound::playSystemSound is called with \"_moz_\" events, they are obsolete, use nsISound::playEventSound instead");
-    PRUint32 eventId;
-    if (aSoundAlias.Equals(NS_SYSSOUND_ALERT_DIALOG))
-        eventId = EVENT_ALERT_DIALOG_OPEN;
-    else if (aSoundAlias.Equals(NS_SYSSOUND_CONFIRM_DIALOG))
-        eventId = EVENT_CONFIRM_DIALOG_OPEN;
-    else if (aSoundAlias.Equals(NS_SYSSOUND_MAIL_BEEP))
-        eventId = EVENT_NEW_MAIL_RECEIVED;
-    else
-        return NS_OK;
-    return PlayEventSound(eventId);
-  }
   nsCAutoString nativeSoundAlias;
   NS_CopyUnicodeToNative(aSoundAlias, nativeSoundAlias);
 
   ARGBUFFER arg;
   memset(&arg, '\0', sizeof(arg));
   APIRET rc = DosCreateEventSem(NULL, &(arg.hev), 0UL, 0UL);
 
   // Play the sound on a new thread using MMOS2, in this case pass
@@ -512,28 +448,34 @@ NS_IMETHODIMP nsSound::PlaySystemSound(c
 
   // Try to wait a while until the file is loaded, but not too long...
   rc = DosWaitEventSem(arg.hev, 100);
   rc = DosCloseEventSem(arg.hev);
 
   return NS_OK;
 }
 
-NS_IMETHODIMP nsSound::PlayEventSound(PRUint32 aEventId)
+NS_IMETHODIMP
+nsSystemSoundService::PlayEventSound(PRUint32 aEventID)
 {
+  nsresult rv = nsSystemSoundServiceBase::PlayEventSound(aEventID);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   // Prompt dialog and select dialog sounds do not correspond to OS/2
   // system sounds, ignore them. Ignore the menu sounds, too. Try to handle
   // the rest. Skip the beeps on systems without MMPM, too many of them are
   // confusing and annoying.
-  switch(aEventId) {
+  switch(aEventID) {
   case EVENT_NEW_MAIL_RECEIVED:
     // We don't have a default mail sound on OS/2, so just "beep"
     return Beep(); // this corresponds to the "Warning" sound
   case EVENT_ALERT_DIALOG_OPEN:
+    StopSoundPlayer();
     WinAlarm(HWND_DESKTOP, WA_ERROR); // play "Error" sound
     break;
   case EVENT_CONFIRM_DIALOG_OPEN:
+    StopSoundPlayer();
     WinAlarm(HWND_DESKTOP, WA_NOTE); // play "Information" sound
     break;
   }
 
   return NS_OK;
 }
rename from widget/src/os2/nsSound.h
rename to widget/src/os2/nsSystemSoundService.h
--- a/widget/src/os2/nsSound.h
+++ b/widget/src/os2/nsSystemSoundService.h
@@ -17,43 +17,52 @@
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 2000
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Stuart Parmenter <pavlov@netscape.com>
+ *   Masayuki Nakano <masayuki@d-toybox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#ifndef __nsSound_h__
-#define __nsSound_h__
+#ifndef __nsSystemSoundService_h__
+#define __nsSystemSoundService_h__
 
-#include "nsISound.h"
-#include "nsIStreamLoader.h"
+#include "nsSound.h"
 
-class nsSound : public nsISound,
-                public nsIStreamLoaderObserver
-
+class nsSystemSoundService : public nsSystemSoundServiceBase
 {
-public: 
-  nsSound();
-  virtual ~nsSound();
+public:
+  nsSystemSoundService();
+  virtual ~nsSystemSoundService();
+
+  NS_DECL_ISYSTEMSOUNDSERVICE_GETINSTANCE(nsSystemSoundService)
 
   NS_DECL_ISUPPORTS
-  NS_DECL_NSISOUND
-  NS_DECL_NSISTREAMLOADEROBSERVER
+
+  NS_IMETHOD Beep();
+  NS_IMETHOD PlayAlias(const nsAString &aSoundAlias);
+  NS_IMETHOD PlayEventSound(PRUint32 aEventID);
+
+protected:
+  virtual nsresult Init();
+  virtual void OnShutdown();
+
+private:
+  nsresult PlayNative(const nsAString &aSoundAlias);
 };
 
-#endif /* __nsSound_h__ */
+#endif /* __nsSystemSoundService_h__ */
--- a/widget/src/os2/nsWidgetFactory.cpp
+++ b/widget/src/os2/nsWidgetFactory.cpp
@@ -66,16 +66,17 @@
 #include "nsAppShellSingleton.h"
 #include "nsBidiKeyboard.h"
 #include "nsWindow.h"
 #include "nsDragService.h"
 #include "nsILocalFile.h"
 #include "nsFilePicker.h"
 #include "nsLookAndFeel.h"
 #include "nsSound.h"
+#include "nsSystemSoundService.h"
 #include "nsToolkit.h"
 
 // Drag & Drop, Clipboard
 #include "nsClipboard.h"
 #include "nsClipboardHelper.h"
 #include "nsTransferable.h"
 #include "nsHTMLFormatConverter.h"
 
@@ -95,16 +96,18 @@
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsBidiKeyboard)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindow)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboard)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardHelper)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePicker)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFrameWindow)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsLookAndFeel)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSystemSoundService,
+                                         nsSystemSoundService::GetInstance)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsToolkit)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsTransferable)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDragService)
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceContextSpecOS2)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrintOptionsOS2, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsPrinterEnumeratorOS2)
@@ -146,16 +149,20 @@ static const nsModuleComponentInfo compo
   { "OS/2 Look And Feel",
     NS_LOOKANDFEEL_CID,
     "@mozilla.org/widget/lookandfeel;1",
     nsLookAndFeelConstructor },
   { "OS/2 Sound",
     NS_SOUND_CID,
     "@mozilla.org/sound;1",
     nsSoundConstructor },
+  { "System Sound Service",
+    NS_SYSTEM_SOUND_SERVICE_CID,
+    "@mozilla.org/systemsoundservice;1",
+    nsSystemSoundServiceConstructor },
   { "OS/2 Toolkit",
     NS_TOOLKIT_CID,
     "@mozilla.org/widget/toolkit/os2;1",
     nsToolkitConstructor },
   { "OS/2 Frame Window",
     NS_WINDOW_CID,
     "@mozilla.org/widget/window/os2;1",
     nsFrameWindowConstructor },
--- a/widget/src/photon/Makefile.in
+++ b/widget/src/photon/Makefile.in
@@ -56,17 +56,17 @@ CPPSRCS		= \
 		nsClipboard.cpp \
 		nsLookAndFeel.cpp \
 		nsToolkit.cpp \
 		nsWidget.cpp \
 		nsWidgetFactory.cpp \
 		nsWindow.cpp \
 		nsBidiKeyboard.cpp \
 		nsFilePicker.cpp \
-		nsSound.cpp \
+		nsSystemSoundService.cpp \
 		$(NULL)
 
 # always include the PHOTON_DND in the build - the bookmarks in firefox require it
 PHOTON_DND=1
 ifdef PHOTON_DND
 CPPSRCS += nsDragService.cpp
 endif
 
rename from widget/src/photon/nsSound.cpp
rename to widget/src/photon/nsSystemSoundService.cpp
--- a/widget/src/photon/nsSound.cpp
+++ b/widget/src/photon/nsSystemSoundService.cpp
@@ -16,140 +16,68 @@
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Pierre Phaneuf <pp@ludusdesign.com>
+ *   Masayuki Nakano <masayuki@d-toybox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-
-#include "nscore.h"
-#include "plstr.h"
-#include "prlink.h"
+#include "nsSystemSoundService.h"
 
-#include "nsSound.h"
-#include "nsString.h"
-
-#include "nsIURL.h"
-#include "nsNetUtil.h"
-#include "nsCOMPtr.h"
+/*****************************************************************************
+ *  nsSystemSoundService implementation
+ *****************************************************************************/
 
-#include <Pt.h>
-
-NS_IMPL_ISUPPORTS2(nsSound, nsISound, nsIStreamLoaderObserver)
+NS_IMPL_ISUPPORTS1(nsSystemSoundService, nsISystemSoundService)
 
-////////////////////////////////////////////////////////////////////////
-nsSound::nsSound()
-{
-  mInited = PR_FALSE;
-}
+NS_IMPL_ISYSTEMSOUNDSERVICE_GETINSTANCE(nsSystemSoundService)
 
-nsSound::~nsSound()
+nsSystemSoundService::nsSystemSoundService() :
+  nsSystemSoundServiceBase()
 {
 }
 
-nsresult nsSound::Init()
+nsSystemSoundService::~nsSystemSoundService()
 {
-  if (mInited) return NS_OK;
-
-  mInited = PR_TRUE;
-  return NS_OK;
 }
 
-NS_METHOD nsSound::Beep()
+NS_IMETHODIMP
+nsSystemSoundService::Beep()
 {
+  nsresult rv = nsSystemSoundServiceBase::Beep();
+  NS_ENSURE_SUCCESS(rv, rv);
+
   ::PtBeep();
   return NS_OK;
 }
 
-NS_METHOD nsSound::Play(nsIURL *aURL)
-{
-  NS_NOTYETIMPLEMENTED("nsSound::Play");
-
-#ifdef DEBUG
-printf( "\n\n\nnsSound::Play\n\n" );
-#endif
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
-                                        nsISupports *context,
-                                        nsresult aStatus,
-                                        PRUint32 stringLen,
-                                        const PRUint8 *stringData)
-{
-  nsresult rv = NS_ERROR_FAILURE;
-
-#ifdef DEBUG
-printf( "\n\n\nnsSound::OnStreamComplete stringData=%s\n\n", stringData );
-#endif
-
-  if (NS_FAILED(aStatus))
-    return NS_ERROR_FAILURE;
-
-  return rv;
-}
-
-static void child_exit( void *data, int status ) { }
-
-NS_IMETHODIMP nsSound::PlaySystemSound(const nsAString &aSoundAlias)
+NS_IMETHODIMP
+nsSystemSoundService::PlayEventSound(PRUint32 aEventID)
 {
-  NS_ConvertUTF16toUTF8 utf8SoundAlias(aSoundAlias);
-
-#ifdef DEBUG
-printf( "\n\n\nnsSound::PlaySystemSound aSoundAlias=%s\n\n",
-        utf8SoundAlias.get() );
-#endif
-
-  const char *soundfile;
+  nsresult rv = nsSystemSoundServiceBase::PlayEventSound(aEventID);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  if( NS_IsMozAliasSound(aSoundAlias) ) {
-    NS_WARNING("nsISound::playSystemSound is called with \"_moz_\" events, they are obsolete, use nsISound::playEventSound instead");
-    if ( aSoundAlias.Equals(NS_SYSSOUND_MAIL_BEEP) )
-      soundfile = "/usr/share/mozilla/gotmail.wav";
-    else
-      return NS_OK;
-  } else {
-    /* the aSoundAlias is the fullpath to the soundfile */
-    if( !access( utf8SoundAlias.get(), F_OK ) )
-      soundfile = utf8SoundAlias.get();
-    else
-      soundfile = "/usr/share/mozilla/rest.wav";
-  }
-
-  const char* argv[] = { "/opt/Mozilla/mozilla/wave", soundfile, NULL };
-  PtSpawn( "/opt/Mozilla/mozilla/wave", ( const char ** ) argv,
-           NULL, NULL, child_exit, NULL, NULL );
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsSound::PlayEventSound(PRUint32 aEventId)
-{
-  if (aEventId != EVENT_NEW_MAIL_RECEIVED) {
+  if (aEventID != EVENT_NEW_MAIL_RECEIVED) {
     return NS_OK;
   }
 
-  soundfile = "/usr/share/mozilla/gotmail.wav";
-  const char* argv[] = { "/opt/Mozilla/mozilla/wave",
-                         "/usr/share/mozilla/gotmail.wav", NULL };
-  PtSpawn( "/opt/Mozilla/mozilla/wave", ( const char ** ) argv,
-           NULL, NULL, child_exit, NULL, NULL );
-
+  StopSoundPlayer();
+  rv = PlayFile(NS_LITERAL_STRING("/usr/share/mozilla/gotmail.wav"));
+  NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
rename from widget/src/photon/nsSound.h
rename to widget/src/photon/nsSystemSoundService.h
--- a/widget/src/photon/nsSound.h
+++ b/widget/src/photon/nsSystemSoundService.h
@@ -15,46 +15,45 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
+ *   Masayuki Nakano <masayuki@d-toybox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#ifndef __nsSound_h__
-#define __nsSound_h__
+#ifndef __nsSystemSoundService_h__
+#define __nsSystemSoundService_h__
 
-#include "nsISound.h"
-#include "nsIStreamLoader.h"
+#include "nsSound.h"
 
-
-class nsSound : public nsISound, 
-                public nsIStreamLoaderObserver
+class nsSystemSoundService : public nsSystemSoundServiceBase
 {
- public: 
+public:
+  nsSystemSoundService();
+  virtual ~nsSystemSoundService();
 
-  nsSound();
-  virtual ~nsSound();
+  NS_DECL_ISYSTEMSOUNDSERVICE_GETINSTANCE(nsSystemSoundService)
+
   NS_DECL_ISUPPORTS
-  NS_DECL_NSISOUND
-  NS_DECL_NSISTREAMLOADEROBSERVER
 
-private:
-  PRBool mInited;
+  NS_IMETHOD Beep();
+  NS_IMETHOD PlayAlias(const nsAString &aSoundAlias);
+  NS_IMETHOD PlayEventSound(PRUint32 aEventID);
 };
 
-#endif /* __nsSound_h__ */
+#endif /* __nsSystemSoundService_h__ */
--- a/widget/src/photon/nsWidgetFactory.cpp
+++ b/widget/src/photon/nsWidgetFactory.cpp
@@ -49,16 +49,17 @@
 #include "nsTransferable.h"
 #include "nsClipboard.h"
 #include "nsClipboardHelper.h"
 #include "nsHTMLFormatConverter.h"
 #ifdef PHOTON_DND
 #include "nsDragService.h"
 #endif
 #include "nsSound.h"
+#include "nsSystemSoundService.h"
 #ifdef IBMBIDI
 #include "nsBidiKeyboard.h"
 #endif
 
 #include "nsFilePicker.h"
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindow)
 NS_GENERIC_FACTORY_CONSTRUCTOR(ChildWindow)
@@ -68,16 +69,18 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsLookAnd
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsTransferable)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboard)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardHelper)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter)
 #ifdef PHOTON_DND
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDragService)
 #endif
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSystemSoundService,
+                                         nsSystemSoundService::GetInstance)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePicker)
 
 #ifdef IBMBIDI
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsBidiKeyboard)
 #endif
 
 static const nsModuleComponentInfo components[] =
 {
@@ -122,16 +125,20 @@ static const nsModuleComponentInfo compo
     NS_DRAGSERVICE_CID,
     "@mozilla.org/widget/dragservice;1",
     nsDragServiceConstructor },
 #endif
   { "Ph Sound",
     NS_SOUND_CID,
     "@mozilla.org/sound;1",
     nsSoundConstructor },
+  { "System Sound Service",
+    NS_SYSTEM_SOUND_SERVICE_CID,
+    "@mozilla.org/systemsoundservice;1",
+    nsSystemSoundServiceConstructor },
 #ifdef IBMBIDI
     { "Gtk Bidi Keyboard",
     NS_BIDIKEYBOARD_CID,
     "@mozilla.org/widget/bidikeyboard;1",
     nsBidiKeyboardConstructor },
 #endif // IBMBIDI
 
   { "Photon File Picker",
--- a/widget/src/qt/Makefile.in
+++ b/widget/src/qt/Makefile.in
@@ -73,17 +73,17 @@ CPPSRCS	= \
 		nsScreenManagerQt.cpp \
 		nsQtKeyUtils.cpp \
 		nsClipboard.cpp \
 		nsBidiKeyboard.cpp \
 		nsIdleServiceQt.cpp \
 		nsDragService.cpp \
 		nsNativeThemeQt.cpp \
 		mozqwidget.cpp \
-		nsSound.cpp \
+		nsSystemSoundService.cpp \
 		nsFilePicker.cpp \
 		$(NULL)
 
 SHARED_LIBRARY_LIBS = ../xpwidgets/libxpwidgets_s.a
 
 EXTRA_DSO_LDOPTS = \
 		$(MOZ_COMPONENT_LIBS) \
 		-lgkgfx \
rename from widget/src/qt/nsSound.cpp
rename to widget/src/qt/nsSystemSoundService.cpp
--- a/widget/src/qt/nsSound.cpp
+++ b/widget/src/qt/nsSystemSoundService.cpp
@@ -16,397 +16,68 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 2000
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
+ *   Masayuki Nakano <masayuki@d-toybox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include <string.h>
-
-#include "nscore.h"
-#include "plstr.h"
-#include "prlink.h"
-
-#include "nsSound.h"
-#include "nsString.h"
-
-#include "nsIURL.h"
-#include "nsIFileURL.h"
-#include "nsNetUtil.h"
-#include "nsCOMPtr.h"
-#include "nsNativeCharsetUtils.h"
-#include "nsAutoPtr.h"
+#include "nsSystemSoundService.h"
 
 #include <QApplication>
 #include <QSound>
 
-/* used with esd_open_sound */
-static int esdref = -1;
-static PRLibrary *elib = nsnull;
-
-// the following from esd.h
-
-#define ESD_BITS8  (0x0000)
-#define ESD_BITS16 (0x0001) 
-#define ESD_MONO (0x0010)
-#define ESD_STEREO (0x0020) 
-#define ESD_STREAM (0x0000)
-#define ESD_PLAY (0x1000)
+/*****************************************************************************
+ *  nsSystemSoundService implementation
+ *****************************************************************************/
 
-#define WAV_MIN_LENGTH 44
-
-typedef int (*EsdOpenSoundType)(const char *host);
-typedef int (*EsdCloseType)(int);
+NS_IMPL_ISUPPORTS1(nsSystemSoundService, nsISystemSoundService)
 
-/* used to play the sounds from the find symbol call */
-typedef int  (*EsdPlayStreamType) (int, int, const char *, const char *);
-typedef int  (*EsdAudioOpenType)  (void);
-typedef int  (*EsdAudioWriteType) (const void *, int);
-typedef void (*EsdAudioCloseType) (void);
+NS_IMPL_ISYSTEMSOUNDSERVICE_GETINSTANCE(nsSystemSoundService)
 
-NS_IMPL_ISUPPORTS2(nsSound, nsISound, nsIStreamLoaderObserver)
-
-nsSound::nsSound()
- : mInited( PR_FALSE )
+nsSystemSoundService::nsSystemSoundService() :
+    nsSystemSoundServiceBase()
 {
 }
 
-nsSound::~nsSound()
+nsSystemSoundService::~nsSystemSoundService()
 {
-    /* see above comment */
-    if (esdref != -1) {
-        EsdCloseType EsdClose = (EsdCloseType) PR_FindFunctionSymbol(elib, "esd_close");
-        if (EsdClose)
-            (*EsdClose)(esdref);
-        esdref = -1;
-    }
-}
-
-
-/**
-* unload esd library
-*/
-void
-nsSound::Shutdown()
-{
-    if (elib) {
-        PR_UnloadLibrary(elib);
-        elib = nsnull;
-    }
 }
 
 NS_IMETHODIMP
-nsSound::Init()
+nsSystemSoundService::Beep()
 {
-    /* we don't need to do esd_open_sound if we are only going to play files
-       but we will if we want to do things like streams, etc
-    */
-    if (mInited) 
-        return NS_OK;
-    if (elib) 
-        return NS_OK;
-
-    EsdOpenSoundType EsdOpenSound;
-
-    elib = PR_LoadLibrary("libesd.so.0");
-    if (!elib) return NS_ERROR_FAILURE;
+    nsresult rv = nsSystemSoundServiceBase::Beep();
+    NS_ENSURE_SUCCESS(rv, rv);
 
-    EsdOpenSound = (EsdOpenSoundType) PR_FindFunctionSymbol(elib, "esd_open_sound");
-
-    if (!EsdOpenSound)
-        return NS_ERROR_FAILURE;
-
-    esdref = (*EsdOpenSound)("localhost");
-
-    if (!esdref)
-        return NS_ERROR_FAILURE;
-
-    mInited = PR_TRUE;
-
-    return NS_OK;
-}
-
-NS_METHOD nsSound::Beep()
-{
     QApplication::beep();
     return NS_OK;
 }
 
-
-/**
-* This can't be implemented directly with QT.
-* (We can use QSound to play local files but that was not enough.
-* Also support of media formats is limited)
-*
-* Current implementation is copied from GTK side and implementation uses ESD interface.
-*
-* If we have Qtopia then we can drop ESD implementation and use Qtopia "Multimedia API"
-*/
-NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
-                                        nsISupports *context,
-                                        nsresult aStatus,
-                                        PRUint32 dataLen,
-                                        const PRUint8 *data)
+NS_IMETHODIMP
+nsSystemSoundService::PlayEventSound(PRUint32 aEventID)
 {
-
-#define GET_WORD(s, i) (s[i+1] << 8) | s[i]
-#define GET_DWORD(s, i) (s[i+3] << 24) | (s[i+2] << 16) | (s[i+1] << 8) | s[i]
-
-    // print a load error on bad status, and return
-    if (NS_FAILED(aStatus)) {
-#ifdef DEBUG
-        if (aLoader) {
-            nsCOMPtr<nsIRequest> request;
-            aLoader->GetRequest(getter_AddRefs(request));
-            if (request) {
-                nsCOMPtr<nsIURI> uri;
-                nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
-                if (channel) {
-                      channel->GetURI(getter_AddRefs(uri));
-                      if (uri) {
-                            nsCAutoString uriSpec;
-                            uri->GetSpec(uriSpec);
-                            printf("Failed to load %s\n", uriSpec.get());
-                      }
-                }
-            }
-        }
-#endif
-        return aStatus;
-    }
-
-    int fd, mask = 0;
-    PRUint32 samples_per_sec = 0, avg_bytes_per_sec = 0, chunk_len = 0;
-    PRUint16 format, channels = 1, bits_per_sample = 0;
-    const PRUint8 *audio = nsnull;
-    size_t audio_len = 0;
-
-    if (dataLen < 4) {
-        NS_WARNING("Sound stream too short to determine its type");
-        return NS_ERROR_FAILURE;
-    }
-
-    if (memcmp(data, "RIFF", 4)) {
-#ifdef DEBUG
-        printf("We only support WAV files currently.\n");
-#endif
-        return NS_ERROR_FAILURE;
-    }
-
-    if (dataLen <= WAV_MIN_LENGTH) {
-        NS_WARNING("WAV files should be longer than 44 bytes.");
-        return NS_ERROR_FAILURE;
-    }
-
-    PRUint32 i = 12;
-    while (i + 7 < dataLen) {
-        if (!memcmp(data + i, "fmt ", 4) && !chunk_len) {
-            i += 4;
-
-            /* length of the rest of this subblock (should be 16 for PCM data */
-            chunk_len = GET_DWORD(data, i);
-            i += 4;
-
-            if (chunk_len < 16 || i + chunk_len >= dataLen) {
-                NS_WARNING("Invalid WAV file: bad fmt chunk.");
-                return NS_ERROR_FAILURE;
-            }
-
-            format = GET_WORD(data, i);
-            i += 2;
-
-            channels = GET_WORD(data, i);
-            i += 2;
-
-            samples_per_sec = GET_DWORD(data, i);
-            i += 4;
-
-            avg_bytes_per_sec = GET_DWORD(data, i);
-            i += 4;
-
-            // block align
-            i += 2;
-
-            bits_per_sample = GET_WORD(data, i);
-            i += 2;
-
-            /* we don't support WAVs with odd compression codes */
-            if (chunk_len != 16)
-                NS_WARNING("Extra format bits found in WAV. Ignoring");
+    nsresult rv = nsSystemSoundServiceBase::PlayEventSound(aEventID);
+    NS_ENSURE_SUCCESS(rv, rv);
 
-            i += chunk_len - 16;
-        } else if (!memcmp(data + i, "data", 4)) {
-            i += 4;
-            if (!chunk_len) {
-                NS_WARNING("Invalid WAV file: no fmt chunk found");
-                return NS_ERROR_FAILURE;
-            }
-
-            audio_len = GET_DWORD(data, i);
-            i += 4;
-
-            /* try to play truncated WAVs */
-            if (i + audio_len > dataLen)
-                audio_len = dataLen - i;
-
-            audio = data + i;
-            break;
-        } else {
-            i += 4;
-            i += GET_DWORD(data, i);
-            i += 4;
-        }
-    }
-
-    if (!audio) {
-        NS_WARNING("Invalid WAV file: no data chunk found");
-        return NS_ERROR_FAILURE;
+    if (aEventID == EVENT_NEW_MAIL_RECEIVED) {
+        StopSoundPlayer();
+        return Beep();
     }
-
-    /* No audio data? well, at least the WAV was valid. */
-    if (!audio_len)
-        return NS_OK;
-
-#if 0
-    printf("f: %d | c: %d | sps: %li | abps: %li | ba: %d | bps: %d | rate: %li\n",
-         format, channels, samples_per_sec, avg_bytes_per_sec, block_align, bits_per_sample, rate);
-#endif
-
-    /* open up connection to esd */  
-    EsdPlayStreamType EsdPlayStream = 
-        (EsdPlayStreamType) PR_FindFunctionSymbol(elib, 
-                                                  "esd_play_stream");
-    if (!EsdPlayStream)
-        return NS_ERROR_FAILURE;
-
-    mask = ESD_PLAY | ESD_STREAM;
-
-    if (bits_per_sample == 8)
-        mask |= ESD_BITS8;
-    else 
-        mask |= ESD_BITS16;
-
-    if (channels == 1)
-        mask |= ESD_MONO;
-    else 
-        mask |= ESD_STEREO;
-
-    nsAutoArrayPtr<PRUint8> buf;
-
-    // ESD only handle little-endian data. 
-    // Swap the byte order if we're on a big-endian architecture.
-#ifdef IS_BIG_ENDIAN
-    if (bits_per_sample != 8) {
-        buf = new PRUint8[audio_len];
-        if (!buf)
-            return NS_ERROR_OUT_OF_MEMORY;
-        for (PRUint32 j = 0; j + 2 < audio_len; j += 2) {
-            buf[j]     = audio[j + 1];
-            buf[j + 1] = audio[j];
-        }
-
-    audio = buf;
-    }
-#endif
-
-    fd = (*EsdPlayStream)(mask, samples_per_sec, NULL, "mozillaSound"); 
-  
-    if (fd < 0) {
-      int *esd_audio_format = (int *) PR_FindSymbol(elib, "esd_audio_format");
-      int *esd_audio_rate = (int *) PR_FindSymbol(elib, "esd_audio_rate");
-      EsdAudioOpenType EsdAudioOpen = (EsdAudioOpenType) PR_FindFunctionSymbol(elib, "esd_audio_open");
-      EsdAudioWriteType EsdAudioWrite = (EsdAudioWriteType) PR_FindFunctionSymbol(elib, "esd_audio_write");
-      EsdAudioCloseType EsdAudioClose = (EsdAudioCloseType) PR_FindFunctionSymbol(elib, "esd_audio_close");
-
-      if (!esd_audio_format || !esd_audio_rate ||
-          !EsdAudioOpen || !EsdAudioWrite || !EsdAudioClose)
-          return NS_ERROR_FAILURE;
-
-      *esd_audio_format = mask;
-      *esd_audio_rate = samples_per_sec;
-      fd = (*EsdAudioOpen)();
-
-      if (fd < 0)
-        return NS_ERROR_FAILURE;
-
-      (*EsdAudioWrite)(audio, audio_len);
-      (*EsdAudioClose)();
-    } else {
-      while (audio_len > 0) {
-        size_t written = write(fd, audio, audio_len);
-        if (written <= 0)
-          break;
-        audio += written;
-        audio_len -= written;
-      }
-      close(fd);
-    }
-
     return NS_OK;
 }
-
-NS_METHOD nsSound::Play(nsIURL *aURL)
-{
-    nsresult rv;
-
-    if (!mInited)
-        Init();
-
-    if (!elib) 
-        return NS_ERROR_FAILURE;
-
-    nsCOMPtr<nsIStreamLoader> loader;
-    rv = NS_NewStreamLoader(getter_AddRefs(loader), aURL, this);
-
-    return rv;
-}
-
-NS_IMETHODIMP nsSound::PlaySystemSound(const nsAString &aSoundAlias)
-{
-    if (NS_IsMozAliasSound(aSoundAlias)) {
-      NS_WARNING("nsISound::playSystemSound is called with \"_moz_\" events, they are obsolete, use nsISound::playEventSound instead");
-      if (aSoundAlias.Equals(NS_SYSSOUND_MAIL_BEEP))
-        return Beep();
-      return NS_OK;
-    }
-
-    nsresult rv;
-    nsCOMPtr <nsIURI> fileURI;
-
-    // create a nsILocalFile and then a nsIFileURL from that
-    nsCOMPtr <nsILocalFile> soundFile;
-    rv = NS_NewLocalFile(aSoundAlias, PR_TRUE, 
-                         getter_AddRefs(soundFile));
-    NS_ENSURE_SUCCESS(rv,rv);
-
-    rv = NS_NewFileURI(getter_AddRefs(fileURI), soundFile);
-    NS_ENSURE_SUCCESS(rv,rv);
-
-    nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(fileURI,&rv);
-    NS_ENSURE_SUCCESS(rv,rv);
-
-    rv = Play(fileURL);
-    return rv;
-
-}
-
-NS_IMETHODIMP nsSound::PlayEventSound(PRUint32 aEventId)
-{
-    return aEventId == EVENT_NEW_MAIL_RECEIVED ? Beep() : NS_OK;
-}
-
rename from widget/src/qt/nsSound.h
rename to widget/src/qt/nsSystemSoundService.h
--- a/widget/src/qt/nsSound.h
+++ b/widget/src/qt/nsSystemSoundService.h
@@ -15,49 +15,44 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 2000
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
+ *   Masayuki Nakano <masayuki@d-toybox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#ifndef __nsSound_h__
-#define __nsSound_h__
+#ifndef __nsSystemSoundService_h__
+#define __nsSystemSoundService_h__
 
-#include "nsISound.h"
-#include "nsIStreamLoader.h"
+#include "nsSound.h"
 
-class nsSound : public nsISound,
-                public nsIStreamLoaderObserver
+class nsSystemSoundService : public nsSystemSoundServiceBase
 {
- public:
+public:
+  nsSystemSoundService();
+  virtual ~nsSystemSoundService();
 
-  nsSound();
-  virtual ~nsSound();
-
-  static void Shutdown();
+  NS_DECL_ISYSTEMSOUNDSERVICE_GETINSTANCE(nsSystemSoundService)
 
   NS_DECL_ISUPPORTS
-  NS_DECL_NSISOUND
-  NS_DECL_NSISTREAMLOADEROBSERVER
 
-private:
-  PRBool mInited;
-
+  NS_IMETHOD Beep();
+  NS_IMETHOD PlayEventSound(PRUint32 aEventID);
 };
 
-#endif /* __nsSound_h__ */
+#endif /* __nsSystemSoundService_h__ */
--- a/widget/src/qt/nsWidgetFactory.cpp
+++ b/widget/src/qt/nsWidgetFactory.cpp
@@ -60,16 +60,17 @@
 
 
 #include "nsFilePicker.h"
 #include "nsClipboard.h"
 #include "nsClipboardHelper.h"
 #include "nsIdleServiceQt.h"
 #include "nsDragService.h"
 #include "nsSound.h"
+#include "nsSystemSoundService.h"
 #include "nsBidiKeyboard.h"
 #include "nsNativeThemeQt.h"
 // #include "nsScrollbar.h"
 // 
 // #include "nsGUIEvent.h"
 // #include "nsQtEventDispatcher.h"
 // #include "nsIRenderingContext.h"
 // #include "nsIServiceManager.h"
@@ -94,16 +95,18 @@ static NS_DEFINE_CID(kNativeScrollCID, N
 
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboard)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardHelper)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDragService)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsBidiKeyboard)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsIdleServiceQt)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSystemSoundService,
+                                         nsSystemSoundService::GetInstance)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsNativeThemeQt)
 //NS_GENERIC_FACTORY_CONSTRUCTOR(nsNativeScrollbar)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePicker)
 
 
 static const nsModuleComponentInfo components[] =
 {
     { "Qt nsWindow",
@@ -163,31 +166,34 @@ static const nsModuleComponentInfo compo
        NS_IDLE_SERVICE_CID,
        "@mozilla.org/widget/idleservice;1",
        nsIdleServiceQtConstructor },
 #endif
     { "Qt Sound",
       NS_SOUND_CID,
       "@mozilla.org/sound;1",
       nsSoundConstructor },
+    { "System Sound Service",
+      NS_SYSTEM_SOUND_SERVICE_CID,
+      "@mozilla.org/systemsoundservice;1",
+      nsSystemSoundServiceConstructor },
     { "Native Theme Renderer",
       NS_THEMERENDERER_CID,
       "@mozilla.org/chrome/chrome-native-theme;1",
       nsNativeThemeQtConstructor },
     { "Qt File Picker",
       NS_FILEPICKER_CID,
       "@mozilla.org/filepicker;1",
       nsFilePickerConstructor }
 
 };
 
 static void
 nsWidgetQtModuleDtor(nsIModule *aSelf)
 {
-    nsSound::Shutdown();
     nsAppShellShutdown(aSelf);
 }
 
 NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(nsWidgetQtModule,
                                    components,
                                    nsAppShellInit,
                                    nsWidgetQtModuleDtor)
 
--- a/widget/src/windows/Makefile.in
+++ b/widget/src/windows/Makefile.in
@@ -56,17 +56,17 @@ CPPSRCS		= \
 	nsFilePicker.cpp \
 	nsScreenWin.cpp	\
 	nsScreenManagerWin.cpp \
 	nsLookAndFeel.cpp \
 	nsUXThemeData.cpp \
 	nsNativeThemeWin.cpp \
 	nsWinGesture.cpp \
 	nsIdleServiceWin.cpp \
-	nsSound.cpp \
+	nsSystemSoundService.cpp \
 	nsIMM32Handler.cpp \
 	WindowHook.cpp \
 	nsAccelerometerWin.cpp \
 	WinTaskbar.cpp \
 	TaskbarPreview.cpp \
 	TaskbarTabPreview.cpp \
 	TaskbarWindowPreview.cpp \
 	TaskbarPreviewButton.cpp \
rename from widget/src/windows/nsSound.cpp
rename to widget/src/windows/nsSystemSoundService.cpp
--- a/widget/src/windows/nsSound.cpp
+++ b/widget/src/windows/nsSystemSoundService.cpp
@@ -17,285 +17,192 @@
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 2000
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Stuart Parmenter <pavlov@netscape.com>
+ *   Masayuki Nakano <masayuki@d-toybox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "nscore.h"
-#include "plstr.h"
-#include <stdio.h>
-#include "nsString.h"
+#include "nsSystemSoundService.h"
+#include "nsServiceManagerUtils.h"
 #include <windows.h>
-
-// mmsystem.h is needed to build with WIN32_LEAN_AND_MEAN
 #include <mmsystem.h>
 
-#include "nsSound.h"
-#include "nsIURL.h"
-#include "nsNetUtil.h"
-#include "nsCRT.h"
-
-#include "nsNativeCharsetUtils.h"
-
-class nsSoundPlayer: public nsRunnable {
-public:
-  nsSoundPlayer(nsISound *aSound, const wchar_t* aSoundName) :
-    mSound(aSound), mSoundName(aSoundName)
-  {
-    Init();
-  }
-
-  nsSoundPlayer(nsISound *aSound, const nsAString& aSoundName) :
-    mSound(aSound), mSoundName(aSoundName)
-  {
-    Init();
-  }
-
-  NS_DECL_NSIRUNNABLE
-
-protected:
-  nsString mSoundName;
-  nsISound *mSound; // Strong, but this will be released from SoundReleaser.
-  nsCOMPtr<nsIThread> mThread;
-
-  void Init()
-  {
-    NS_GetCurrentThread(getter_AddRefs(mThread));
-    NS_ASSERTION(mThread, "failed to get current thread");
-    NS_IF_ADDREF(mSound);
-  }
-
-  class SoundReleaser: public nsRunnable {
-  public:
-    SoundReleaser(nsISound* aSound) :
-      mSound(aSound)
-    {
-    }
-
-    NS_DECL_NSIRUNNABLE
-
-  protected:
-    nsISound *mSound;
-  };
-};
-
-NS_IMETHODIMP
-nsSoundPlayer::Run()
-{
-  NS_PRECONDITION(!mSoundName.IsEmpty(), "Sound name should not be empty");
-  ::PlaySoundW(mSoundName.get(), NULL, SND_NODEFAULT | SND_ALIAS | SND_ASYNC);
-  nsCOMPtr<nsIRunnable> releaser = new SoundReleaser(mSound);
-  // Don't release nsISound from here, because here is not an owning thread of
-  // the nsSound. nsSound must be released in its owning thread.
-  mThread->Dispatch(releaser, NS_DISPATCH_NORMAL);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSoundPlayer::SoundReleaser::Run()
-{
-  NS_IF_RELEASE(mSound);
-  return NS_OK;
-}
-
-
 #ifndef SND_PURGE
 // Not available on Windows CE, and according to MSDN
 // doesn't do anything on recent windows either.
 #define SND_PURGE 0
 #endif
 
-NS_IMPL_ISUPPORTS2(nsSound, nsISound, nsIStreamLoaderObserver)
-
+class nsStopSoundPlayer : public nsRunnable {
+public:
+  nsStopSoundPlayer()
+  {
+  }
 
-nsSound::nsSound()
+  NS_DECL_NSIRUNNABLE
+};
+
+NS_IMETHODIMP
+nsStopSoundPlayer::Run()
 {
-  mLastSound = nsnull;
+  nsSystemSoundServiceBase::StopSoundPlayer();
+  return NS_OK;
 }
 
-nsSound::~nsSound()
+class nsSystemSoundPlayer : public nsRunnable {
+public:
+  nsSystemSoundPlayer(PRUint32 aEventID) :
+    mEventID(aEventID)
+  {
+  }
+
+  nsSystemSoundPlayer(const nsAString &aName) :
+    mEventID(PR_UINT32_MAX), mName(aName)
+  {
+  }
+
+  NS_DECL_NSIRUNNABLE
+
+protected:
+  PRUint32 mEventID;
+  nsString mName;
+};
+
+NS_IMETHODIMP
+nsSystemSoundPlayer::Run()
 {
-  PurgeLastSound();
+  const wchar_t *sound = nsnull;
+  if (!mName.IsEmpty()) {
+    sound = static_cast<const wchar_t*>(mName.get());
+  } else if (mEventID != PR_UINT32_MAX) {
+    switch (mEventID) {
+      case nsISystemSoundService::EVENT_NEW_MAIL_RECEIVED:
+        sound = L"MailBeep";
+        break;
+      case nsISystemSoundService::EVENT_ALERT_DIALOG_OPEN:
+        sound = L"SystemExclamation";
+        break;
+      case nsISystemSoundService::EVENT_CONFIRM_DIALOG_OPEN:
+        sound = L"SystemQuestion";
+        break;
+      case nsISystemSoundService::EVENT_MENU_EXECUTE:
+        sound = L"MenuCommand";
+        break;
+      case nsISystemSoundService::EVENT_MENU_POPUP:
+        sound = L"MenuPopup";
+        break;
+      case nsISystemSoundService::EVENT_MENU_NOT_FOUND:
+        // Just beep
+        ::MessageBeep(0);
+        return NS_OK;
+      default:
+        // Win32 plays no sounds at NS_SYSSOUND_PROMPT_DIALOG and
+        // NS_SYSSOUND_SELECT_DIALOG.
+        return NS_OK;
+    }
+  }
+  if (sound) {
+    nsCOMPtr<nsStopSoundPlayer> stopper = new nsStopSoundPlayer();
+    NS_DispatchToMainThread(stopper, nsIEventTarget::DISPATCH_SYNC);
+    ::PlaySoundW(sound, NULL, SND_NODEFAULT | SND_ALIAS | SND_ASYNC);
+  }
+  return NS_OK;
 }
 
-void nsSound::PurgeLastSound() {
+/*****************************************************************************
+ *  nsSystemSoundService implementation
+ *****************************************************************************/
+
+NS_IMPL_ISUPPORTS1(nsSystemSoundService, nsISystemSoundService)
+
+NS_IMPL_ISYSTEMSOUNDSERVICE_GETINSTANCE(nsSystemSoundService)
+
+nsSystemSoundService::nsSystemSoundService() :
+  nsSystemSoundServiceBase()
+{
+}
+
+nsSystemSoundService::~nsSystemSoundService()
+{
   if (mPlayerThread) {
     mPlayerThread->Shutdown();
     mPlayerThread = nsnull;
   }
-  if (mLastSound) {
-    // Halt any currently playing sound.
-    ::PlaySound(nsnull, nsnull, SND_PURGE);
-
-    // Now delete the buffer.
-    free(mLastSound);
-    mLastSound = nsnull;
-  }
-}
-
-NS_IMETHODIMP nsSound::Beep()
-{
-  ::MessageBeep(0);
-
-  return NS_OK;
 }
 
-NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
-                                        nsISupports *context,
-                                        nsresult aStatus,
-                                        PRUint32 dataLen,
-                                        const PRUint8 *data)
-{
-  // 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) {
-          nsCAutoString uriSpec;
-          uri->GetSpec(uriSpec);
-          printf("Failed to load %s\n", uriSpec.get());
-        }
-      }
-    }
-#endif
-    return aStatus;
-  }
-
-  PurgeLastSound();
-
-  if (data && dataLen > 0) {
-    DWORD flags = SND_MEMORY | SND_NODEFAULT;
-    // We try to make a copy so we can play it async.
-    mLastSound = (PRUint8 *) malloc(dataLen);
-    if (mLastSound) {
-      memcpy(mLastSound, data, dataLen);
-      data = mLastSound;
-      flags |= SND_ASYNC;
-    }
-    ::PlaySoundW(reinterpret_cast<LPCWSTR>(data), 0, flags);
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsSound::Play(nsIURL *aURL)
-{
-  nsresult rv;
-
-#ifdef DEBUG_SOUND
-  char *url;
-  aURL->GetSpec(&url);
-  printf("%s\n", url);
-#endif
-
-  nsCOMPtr<nsIStreamLoader> loader;
-  rv = NS_NewStreamLoader(getter_AddRefs(loader), aURL, this);
-
-  return rv;
-}
-
-
-NS_IMETHODIMP nsSound::Init()
+nsresult
+nsSystemSoundService::Init()
 {
   // 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.
   ::PlaySound(nsnull, nsnull, SND_PURGE);
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsSystemSoundService::Beep()
+{
+  nsresult rv = nsSystemSoundServiceBase::Beep();
+  NS_ENSURE_SUCCESS(rv, rv);
 
-NS_IMETHODIMP nsSound::PlaySystemSound(const nsAString &aSoundAlias)
+  ::MessageBeep(0);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSystemSoundService::PlayAlias(const nsAString &aSoundAlias)
 {
-  PurgeLastSound();
+  nsresult rv = nsSystemSoundServiceBase::PlayAlias(aSoundAlias);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  if (!NS_IsMozAliasSound(aSoundAlias)) {
-    if (aSoundAlias.IsEmpty())
-      return NS_OK;
-    nsCOMPtr<nsIRunnable> player = new nsSoundPlayer(this, aSoundAlias);
-    NS_ENSURE_TRUE(player, NS_ERROR_OUT_OF_MEMORY);
-    nsresult rv = NS_NewThread(getter_AddRefs(mPlayerThread), player);
+  nsCOMPtr<nsSystemSoundPlayer> player = new nsSystemSoundPlayer(aSoundAlias);
+  NS_ENSURE_TRUE(player, NS_ERROR_OUT_OF_MEMORY);
+  return PostPlayer(player);
+}
+
+NS_IMETHODIMP
+nsSystemSoundService::PlayEventSound(PRUint32 aEventID)
+{
+  nsresult rv = nsSystemSoundServiceBase::PlayEventSound(aEventID);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsSystemSoundPlayer> player = new nsSystemSoundPlayer(aEventID);
+  NS_ENSURE_TRUE(player, NS_ERROR_OUT_OF_MEMORY);
+  return PostPlayer(player);
+}
+
+nsresult
+nsSystemSoundService::PostPlayer(nsSystemSoundPlayer *aPlayer)
+{
+  nsresult rv;
+  if (mPlayerThread) {
+    rv = mPlayerThread->Dispatch(aPlayer, NS_DISPATCH_NORMAL);
     NS_ENSURE_SUCCESS(rv, rv);
     return NS_OK;
   }
 
-  NS_WARNING("nsISound::playSystemSound is called with \"_moz_\" events, they are obsolete, use nsISound::playEventSound instead");
-
-  PRUint32 eventId;
-  if (aSoundAlias.Equals(NS_SYSSOUND_MAIL_BEEP))
-    eventId = EVENT_NEW_MAIL_RECEIVED;
-  else if (aSoundAlias.Equals(NS_SYSSOUND_CONFIRM_DIALOG))
-    eventId = EVENT_CONFIRM_DIALOG_OPEN;
-  else if (aSoundAlias.Equals(NS_SYSSOUND_ALERT_DIALOG))
-    eventId = EVENT_ALERT_DIALOG_OPEN;
-  else if (aSoundAlias.Equals(NS_SYSSOUND_MENU_EXECUTE))
-    eventId = EVENT_MENU_EXECUTE;
-  else if (aSoundAlias.Equals(NS_SYSSOUND_MENU_POPUP))
-    eventId = EVENT_MENU_POPUP;
-  else
-    return NS_OK;
-
-  return PlayEventSound(eventId);
-}
-
-NS_IMETHODIMP nsSound::PlayEventSound(PRUint32 aEventId)
-{
-  PurgeLastSound();
-
-  const wchar_t *sound = nsnull;
-  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;
-    default:
-      // Win32 plays no sounds at NS_SYSSOUND_PROMPT_DIALOG and
-      // NS_SYSSOUND_SELECT_DIALOG.
-      return NS_OK;
-  }
-  NS_ASSERTION(sound, "sound is null");
-
-  nsCOMPtr<nsIRunnable> player = new nsSoundPlayer(this, sound);
-  NS_ENSURE_TRUE(player, NS_ERROR_OUT_OF_MEMORY);
-  nsresult rv = NS_NewThread(getter_AddRefs(mPlayerThread), player);
+  rv = NS_NewThread(getter_AddRefs(mPlayerThread), aPlayer);
   NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_TRUE(mPlayerThread, NS_ERROR_OUT_OF_MEMORY);
   return NS_OK;
 }
rename from widget/src/windows/nsSound.h
rename to widget/src/windows/nsSystemSoundService.h
--- a/widget/src/windows/nsSound.h
+++ b/widget/src/windows/nsSystemSoundService.h
@@ -17,51 +17,57 @@
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 2000
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Stuart Parmenter <pavlov@netscape.com>
+ *   Masayuki Nakano <masayuki@d-toybox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#ifndef __nsSound_h__
-#define __nsSound_h__
+#ifndef __nsSystemSoundService_h__
+#define __nsSystemSoundService_h__
 
-#include "nsISound.h"
-#include "nsIStreamLoader.h"
+#include "nsSound.h"
+#include "nsCOMPtr.h"
 #include "nsThreadUtils.h"
 
-class nsSound : public nsISound,
-                public nsIStreamLoaderObserver
+class nsSystemSoundPlayer;
 
+class nsSystemSoundService : public nsSystemSoundServiceBase
 {
-public: 
-  nsSound();
-  virtual ~nsSound();
+public:
+  nsSystemSoundService();
+  virtual ~nsSystemSoundService();
+
+  NS_DECL_ISYSTEMSOUNDSERVICE_GETINSTANCE(nsSystemSoundService)
 
   NS_DECL_ISUPPORTS
-  NS_DECL_NSISOUND
-  NS_DECL_NSISTREAMLOADEROBSERVER
+
+  NS_IMETHOD Beep();
+  NS_IMETHOD PlayAlias(const nsAString &aSoundAlias);
+  NS_IMETHOD PlayEventSound(PRUint32 aEventID);
+
+protected:
+  virtual nsresult Init();
 
 private:
-  void PurgeLastSound();
+  nsCOMPtr<nsIThread> mPlayerThread;
 
-private:
-  PRUint8* mLastSound;
-  nsCOMPtr<nsIThread> mPlayerThread;
+  nsresult PostPlayer(nsSystemSoundPlayer *aPlayer);
 };
 
-#endif /* __nsSound_h__ */
+#endif /* __nsSystemSoundService_h__ */
--- a/widget/src/xpwidgets/Makefile.in
+++ b/widget/src/xpwidgets/Makefile.in
@@ -60,16 +60,17 @@ CPPSRCS		= \
 		nsClipboardHelper.cpp \
 		nsPrintOptionsImpl.cpp \
 		nsPrintSettingsImpl.cpp \
 		nsPrintSession.cpp \
 		nsWidgetAtoms.cpp \
 		nsIdleService.cpp \
 		nsClipboardPrivacyHandler.cpp \
 		nsAccelerometer.cpp \
+		nsSound.cpp \
 		$(NULL)
 
 ifneq (,$(filter beos os2 cocoa windows,$(MOZ_WIDGET_TOOLKIT)))
 CPPSRCS += nsBaseClipboard.cpp
 endif
 
 ifneq (,$(filter beos qt gtk2 os2 cocoa photon windows,$(MOZ_WIDGET_TOOLKIT)))
 CPPSRCS += nsBaseFilePicker.cpp
--- a/widget/src/xpwidgets/nsBaseAppShell.cpp
+++ b/widget/src/xpwidgets/nsBaseAppShell.cpp
@@ -35,16 +35,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsBaseAppShell.h"
 #include "nsThreadUtils.h"
 #include "nsIObserverService.h"
 #include "nsServiceManagerUtils.h"
+#include "nsSound.h"
 
 // When processing the next thread event, the appshell may process native
 // events (if not in performance mode), which can result in suppressing the
 // next thread event for at most this many ticks:
 #define THREAD_EVENT_STARVATION_LIMIT PR_MillisecondsToInterval(20)
 
 NS_IMPL_THREADSAFE_ISUPPORTS3(nsBaseAppShell, nsIAppShell, nsIThreadObserver,
                               nsIObserver)
@@ -75,16 +76,23 @@ nsBaseAppShell::Init()
   NS_ENSURE_STATE(threadInt);
 
   threadInt->SetObserver(this);
 
   nsCOMPtr<nsIObserverService> obsSvc =
       do_GetService("@mozilla.org/observer-service;1");
   if (obsSvc)
     obsSvc->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
+
+  // The nsISystemSoundService might need to load the system library and it
+  // shouldn't cause the delay of the first sound.  So, we need to initialize
+  // the service here, but the actual initializing is going to be run at next
+  // idle time because it shouldn't make the startup process slower.
+  nsSystemSoundServiceBase::InitService();
+
   return NS_OK;
 }
 
 void
 nsBaseAppShell::NativeEventCallback()
 {
   PRInt32 hasPending = PR_AtomicSet(&mNativeEventPending, 0);
   if (hasPending == 0)
new file mode 100644
--- /dev/null
+++ b/widget/src/xpwidgets/nsSound.cpp
@@ -0,0 +1,333 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Japan.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Masayuki Nakano <masayuki@d-toybox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsCOMPtr.h"
+#include "nsSound.h"
+#include "nsString.h"
+#include "nsIURL.h"
+#include "nsNetUtil.h"
+#include "nsServiceManagerUtils.h"
+#include "nsITimer.h"
+
+
+/*****************************************************************************
+ *  nsSound implementation
+ *****************************************************************************/
+
+NS_IMPL_ISUPPORTS1(nsSound, nsISound)
+
+nsSound::nsSound()
+{
+}
+
+nsSound::~nsSound()
+{
+}
+
+nsresult
+nsSound::Stop()
+{
+  nsSystemSoundServiceBase::StopSoundPlayer();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSound::Beep()
+{
+  nsCOMPtr<nsISystemSoundService> sysSound =
+    nsSystemSoundServiceBase::GetSystemSoundService();
+  NS_ENSURE_TRUE(sysSound, NS_ERROR_FAILURE);
+  return sysSound->Beep();
+}
+
+NS_IMETHODIMP
+nsSound::Init()
+{
+  // Nothing to do
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSound::PlayEventSound(PRUint32 aEventID)
+{
+  // Stop all sounds before we play a system sound.
+  nsresult rv = Stop();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsISystemSoundService> sysSound =
+    nsSystemSoundServiceBase::GetSystemSoundService();
+  NS_ENSURE_TRUE(sysSound, NS_ERROR_FAILURE);
+  return sysSound->PlayEventSound(aEventID);
+}
+
+NS_IMETHODIMP
+nsSound::Play(nsIURL *aURL)
+{
+  NS_ENSURE_ARG_POINTER(aURL);
+  nsresult rv = nsSystemSoundServiceBase::Play(aURL);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSound::PlaySystemSound(const nsAString &aSoundAlias)
+{
+  if (aSoundAlias.IsEmpty())
+    return NS_OK;
+
+  // Stop all sounds before we play a system sound.
+  nsresult rv = Stop();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  NS_ASSERTION(!NS_IsMozAliasSound(aSoundAlias),
+    "nsISound::playSystemSound is called with \"_moz_\" events, they are obsolete, use nsISystemSoundService::playEventSound instead");
+  if (aSoundAlias.Equals(NS_SYSSOUND_MAIL_BEEP)) {
+    rv = PlayEventSound(EVENT_NEW_MAIL_RECEIVED);
+  } else if (aSoundAlias.Equals(NS_SYSSOUND_CONFIRM_DIALOG)) {
+    rv = PlayEventSound(EVENT_CONFIRM_DIALOG_OPEN);
+  } else if (aSoundAlias.Equals(NS_SYSSOUND_ALERT_DIALOG)) {
+    rv = PlayEventSound(EVENT_ALERT_DIALOG_OPEN);
+  } else if (aSoundAlias.Equals(NS_SYSSOUND_PROMPT_DIALOG)) {
+    rv = PlayEventSound(EVENT_PROMPT_DIALOG_OPEN);
+  } else if (aSoundAlias.Equals(NS_SYSSOUND_SELECT_DIALOG)) {
+    rv = PlayEventSound(EVENT_SELECT_DIALOG_OPEN);
+  } else if (aSoundAlias.Equals(NS_SYSSOUND_MENU_EXECUTE)) {
+    rv = PlayEventSound(EVENT_MENU_EXECUTE);
+  } else if (aSoundAlias.Equals(NS_SYSSOUND_MENU_POPUP)) {
+    rv = PlayEventSound(EVENT_MENU_POPUP);
+  } else {
+    // First, assume that the given string is an alias sound name.
+    nsCOMPtr<nsISystemSoundService> sysSound =
+      nsSystemSoundServiceBase::GetSystemSoundService();
+    NS_ENSURE_TRUE(sysSound, NS_ERROR_FAILURE);
+    rv = sysSound->PlayAlias(aSoundAlias);
+    NS_ENSURE_SUCCESS(rv, rv);
+    if (rv != NS_SUCCESS_NOT_SUPPORTED) {
+      // The current platform supports the alias sound name, we shouldn't assume
+      // that the given string is a file path.
+      return NS_OK;
+    }
+
+    // If this platform doesn't support the alias system sound names, we should
+    // assume that the given string is a file path.
+    nsCOMPtr<nsIFileURL> fileURL =
+      nsSystemSoundServiceBase::GetFileURL(aSoundAlias);
+    if (!fileURL) {
+      return NS_OK;
+    }
+    rv = Play(fileURL);
+  }
+
+  NS_ENSURE_SUCCESS(rv, rv);
+  return rv;
+}
+
+/*****************************************************************************
+ *  nsSystemSoundServiceBase implementation
+ *****************************************************************************/
+
+nsISystemSoundService* nsSystemSoundServiceBase::sInstance = nsnull;
+PRBool nsSystemSoundServiceBase::sIsInitialized = PR_FALSE;
+
+NS_IMPL_ISUPPORTS1(nsSystemSoundServiceBase, nsISystemSoundService)
+
+nsSystemSoundServiceBase::nsSystemSoundServiceBase()
+{
+}
+
+nsSystemSoundServiceBase::~nsSystemSoundServiceBase()
+{
+  if (sInstance == this) {
+    OnShutdown();
+    sInstance = nsnull;
+    sIsInitialized = PR_FALSE;
+  }
+}
+
+nsresult
+nsSystemSoundServiceBase::Init()
+{
+  return NS_OK;
+}
+
+void
+nsSystemSoundServiceBase::OnShutdown()
+{
+  // Nothing to do.
+}
+
+/* static */ void
+nsSystemSoundServiceBase::InitService()
+{
+  nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
+  if (!timer) {
+    return; // OOM
+  }
+  NS_ADDREF(timer); // will be released in ExecuteInitService
+  nsresult rv =
+    timer->InitWithFuncCallback(ExecuteInitService, nsnull, 0,
+                                nsITimer::TYPE_ONE_SHOT);
+  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "nsITimer::InitWithFuncCallback failed");
+}
+
+/* static */ void
+nsSystemSoundServiceBase::ExecuteInitService(nsITimer* aTimer, void* aClosure)
+{
+  NS_IF_RELEASE(aTimer);
+
+  // The instance should be created this time.
+  nsCOMPtr<nsISystemSoundService> sysSound =
+    do_GetService("@mozilla.org/systemsoundservice;1");
+  if (!sysSound) {
+    return;
+  }
+  nsresult rv = static_cast<nsSystemSoundServiceBase*>(sysSound.get())->Init();
+  sIsInitialized = NS_SUCCEEDED(rv);
+}
+
+/* static */ already_AddRefed<nsIFileURL>
+nsSystemSoundServiceBase::GetFileURL(const nsAString &aFilePath)
+{
+  if (aFilePath.IsEmpty()) {
+    return nsnull;
+  }
+
+  nsresult rv;
+  nsCOMPtr<nsILocalFile> file;
+  rv = NS_NewLocalFile(aFilePath, PR_TRUE, getter_AddRefs(file));
+  if (rv == NS_ERROR_FILE_UNRECOGNIZED_PATH) {
+    return nsnull;
+  }
+  NS_ENSURE_SUCCESS(rv, nsnull);
+  NS_ENSURE_TRUE(file, nsnull);
+
+  PRBool isExists;
+  PRBool isFile;
+  rv = file->Exists(&isExists);
+  NS_ENSURE_SUCCESS(rv, nsnull);
+  rv = file->IsFile(&isFile);
+  NS_ENSURE_SUCCESS(rv, nsnull);
+  if (!isExists || !isFile) {
+    return nsnull;
+  }
+
+  nsCOMPtr<nsIURI> fileURI;
+  rv = NS_NewFileURI(getter_AddRefs(fileURI), file);
+  NS_ENSURE_SUCCESS(rv, nsnull);
+
+  nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(fileURI, &rv);
+  NS_ENSURE_SUCCESS(rv, nsnull);
+
+  // The file URL must not be null here because the given string is a native
+  // file path of an existing file.
+  NS_ENSURE_TRUE(fileURI, nsnull);
+
+  return fileURL.forget();
+}
+
+/* static */ already_AddRefed<nsISystemSoundService>
+nsSystemSoundServiceBase::GetSystemSoundService()
+{
+  NS_ENSURE_TRUE(sInstance, nsnull);
+  NS_ADDREF(sInstance);
+  return sInstance;
+}
+
+/* static */ already_AddRefed<nsISoundPlayer>
+nsSystemSoundServiceBase::GetSoundPlayer()
+{
+  nsCOMPtr<nsISoundPlayer> player =
+    do_GetService("@mozilla.org/content/media/soundplayer;1");
+  NS_ENSURE_TRUE(player, nsnull);
+  return player.forget();
+}
+
+/* static */ nsresult
+nsSystemSoundServiceBase::PlayFile(const nsAString &aFilePath)
+{
+  nsCOMPtr<nsIFileURL> fileURL = GetFileURL(aFilePath);
+  if (!fileURL) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsISoundPlayer> player = GetSoundPlayer();
+  NS_ENSURE_TRUE(player, NS_ERROR_FAILURE);
+
+  return player->Play(fileURL);
+}
+
+/* static */ nsresult
+nsSystemSoundServiceBase::Play(nsIURL *aURL)
+{
+  nsCOMPtr<nsISoundPlayer> player = GetSoundPlayer();
+  NS_ENSURE_TRUE(player, NS_ERROR_FAILURE);
+
+  // We don't need to stop the previous sound before we play a new sound.
+  return player->Play(aURL);
+}
+
+/* static */ void
+nsSystemSoundServiceBase::StopSoundPlayer()
+{
+  nsCOMPtr<nsISoundPlayer> player = GetSoundPlayer();
+  if (player) {
+    player->Stop();
+  }
+}
+
+NS_IMETHODIMP
+nsSystemSoundServiceBase::Beep()
+{
+  NS_ENSURE_TRUE(sIsInitialized, NS_ERROR_NOT_INITIALIZED);
+  return NS_SUCCESS_NOT_SUPPORTED;
+}
+
+NS_IMETHODIMP
+nsSystemSoundServiceBase::PlayAlias(const nsAString &aSoundAlias)
+{
+  NS_ENSURE_TRUE(sIsInitialized, NS_ERROR_NOT_INITIALIZED);
+  return NS_SUCCESS_NOT_SUPPORTED;
+}
+
+NS_IMETHODIMP
+nsSystemSoundServiceBase::PlayEventSound(PRUint32 aEventID)
+{
+  NS_ENSURE_TRUE(sIsInitialized, NS_ERROR_NOT_INITIALIZED);
+  return NS_SUCCESS_NOT_SUPPORTED;
+}
new file mode 100644
--- /dev/null
+++ b/widget/src/xpwidgets/nsSound.h
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Japan.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Masayuki Nakano <masayuki@d-toybox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __nsSound_h__
+#define __nsSound_h__
+
+#include "nsISound.h"
+#include "nsISystemSoundService.h"
+#include "nsCOMPtr.h"
+#include "nsISoundPlayer.h"
+#include "nsString.h"
+#include "nsIFileURL.h"
+
+class nsITimer;
+
+class nsSound : public nsISound
+{
+public:
+  nsSound();
+  virtual ~nsSound();
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISOUND
+
+protected:
+  nsresult Stop();
+};
+
+// Playing system sound methods of nsSystemSoundServiceBase return this code if
+// the platform doesn't support the method.  So, they never return
+// NS_ERROR_NOT_IMPLEMENTED.
+#define NS_SUCCESS_NOT_SUPPORTED \
+  NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_GENERAL, 1)
+
+// The implementation class of nsISystemSoundService should be singleton.
+// These macros declares/implements the GetInstance method.
+#define NS_DECL_ISYSTEMSOUNDSERVICE_GETINSTANCE(_InstanceClass) \
+  static _InstanceClass* GetInstance();
+
+#define NS_IMPL_ISYSTEMSOUNDSERVICE_GETINSTANCE(_InstanceClass)                \
+_InstanceClass*                                                                \
+_InstanceClass::GetInstance()                                                  \
+{                                                                              \
+  if (sInstance) {                                                             \
+    NS_ADDREF(sInstance);                                                      \
+    return static_cast<_InstanceClass*>(sInstance);                            \
+  }                                                                            \
+                                                                               \
+  sInstance = new _InstanceClass();                                            \
+  NS_ENSURE_TRUE(sInstance, nsnull);                                           \
+  NS_ADDREF(sInstance);                                                        \
+  return static_cast<_InstanceClass*>(sInstance);                              \
+}
+
+// Base class of each platform-specific nsSystemSoundService.
+class nsSystemSoundServiceBase : public nsISystemSoundService
+{
+public:
+  nsSystemSoundServiceBase();
+  virtual ~nsSystemSoundServiceBase();
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISYSTEMSOUNDSERVICE
+
+  static void InitService();
+  static already_AddRefed<nsIFileURL> GetFileURL(const nsAString &aFilePath);
+  static already_AddRefed<nsISystemSoundService> GetSystemSoundService();
+  static already_AddRefed<nsISoundPlayer> GetSoundPlayer();
+  static nsresult PlayFile(const nsAString &aFilePath);
+  static nsresult Play(nsIURL *aURL);
+  // Stops playing all in-progress sounds that are played via nsISoundPlayer.
+  // This method should be called by the inherited class before it plays a
+  // system sound by PlayAlias() and PlayEventSound().
+  static void StopSoundPlayer();
+
+protected:
+  static nsISystemSoundService* sInstance;
+  static PRBool sIsInitialized;
+
+  virtual nsresult Init();
+  virtual void OnShutdown();
+
+private:
+  static void ExecuteInitService(nsITimer* aTimer, void* aClosure);
+};
+
+#endif /* __nsSound_h__ */