Back to index

lightning-sunbird  0.9+nobinonly
nsSound.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 2000
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Stuart Parmenter <pavlov@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nscore.h"
00041 #include "plstr.h"
00042 #include <stdio.h>
00043 
00044 #include <windows.h>
00045 
00046 // mmsystem.h is needed to build with WIN32_LEAN_AND_MEAN
00047 #include <mmsystem.h>
00048 
00049 #include "nsSound.h"
00050 #include "nsIURL.h"
00051 #include "nsNetUtil.h"
00052 #include "nsCRT.h"
00053 
00054 NS_IMPL_ISUPPORTS2(nsSound, nsISound, nsIStreamLoaderObserver)
00055 
00056 
00057 // This hidden class is used to load the winmm.dll when it's needed.
00058 
00059 class CWinMM {
00060   typedef int (CALLBACK *PlayPtr)(const char*,HMODULE,DWORD);
00061 
00062 public:
00063 
00064   static CWinMM& GetModule() {
00065     static CWinMM gSharedWinMM;  //construct this only after you *really* need it.
00066     return gSharedWinMM;
00067   }
00068 
00069 
00070   CWinMM(const char* aModuleName="WINMM.DLL") {
00071     mInstance=::LoadLibrary(aModuleName);  
00072     mPlay=(mInstance) ? (PlayPtr)GetProcAddress(mInstance,"PlaySound") : 0;
00073     sIsInitialized = PR_TRUE;
00074   }
00075 
00076   ~CWinMM() {
00077     if(mInstance)
00078       ::FreeLibrary(mInstance);
00079     mInstance=0;
00080     mPlay=0;
00081   }
00082 
00083   BOOL PlaySound(const char *aSoundFile,HMODULE aModule,DWORD aOptions) {
00084     return (mPlay) ? mPlay(aSoundFile, aModule, aOptions) : FALSE;
00085   }
00086 
00087   static BOOL IsInitialized() {
00088     return sIsInitialized;
00089   }
00090  
00091 private:
00092   HINSTANCE mInstance;  
00093   PlayPtr mPlay;
00094   static BOOL sIsInitialized;
00095 };
00096 
00097 BOOL CWinMM::sIsInitialized = PR_FALSE;
00098 
00100 
00101 nsSound::nsSound()
00102 {
00103   mLastSound = nsnull;
00104 }
00105 
00106 nsSound::~nsSound()
00107 {
00108   PurgeLastSound();
00109 }
00110 
00111 void nsSound::PurgeLastSound() {
00112   if (mLastSound) {
00113     // Purge the current sound buffer.
00114     CWinMM& theMM = CWinMM::GetModule();
00115     theMM.PlaySound(nsnull, nsnull, SND_PURGE); // This call halts the sound if it was still playing.
00116 
00117     // Now delete the buffer.
00118     free(mLastSound);
00119     mLastSound = nsnull;
00120   }
00121 }
00122 
00123 NS_IMETHODIMP nsSound::Beep()
00124 {
00125   ::MessageBeep(0);
00126 
00127   return NS_OK;
00128 }
00129 
00130 NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
00131                                         nsISupports *context,
00132                                         nsresult aStatus,
00133                                         PRUint32 dataLen,
00134                                         const PRUint8 *data)
00135 {
00136   // print a load error on bad status
00137   if (NS_FAILED(aStatus)) {
00138 #ifdef DEBUG
00139     if (aLoader) {
00140       nsCOMPtr<nsIRequest> request;
00141       nsCOMPtr<nsIChannel> channel;
00142       aLoader->GetRequest(getter_AddRefs(request));
00143       if (request)
00144           channel = do_QueryInterface(request);
00145       if (channel) {
00146         nsCOMPtr<nsIURI> uri;
00147         channel->GetURI(getter_AddRefs(uri));
00148         if (uri) {
00149           nsCAutoString uriSpec;
00150           uri->GetSpec(uriSpec);
00151           printf("Failed to load %s\n", uriSpec.get());
00152         }
00153       }
00154     }
00155 #endif
00156     return aStatus;
00157   }
00158 
00159   PurgeLastSound();
00160 
00161   if (data && dataLen > 0) {
00162     DWORD flags = SND_MEMORY | SND_NODEFAULT;
00163     // We try to make a copy so we can play it async.
00164     mLastSound = (PRUint8 *) malloc(dataLen);
00165     if (mLastSound) {
00166       memcpy(mLastSound, data, dataLen);
00167       data = mLastSound;
00168       flags |= SND_ASYNC;
00169     }
00170 
00171     CWinMM& theMM = CWinMM::GetModule();
00172     theMM.PlaySound(NS_REINTERPRET_CAST(const char*, data), 0, flags);
00173   }
00174 
00175   return NS_OK;
00176 }
00177 
00178 NS_IMETHODIMP nsSound::Play(nsIURL *aURL)
00179 {
00180   nsresult rv;
00181 
00182 #ifdef DEBUG_SOUND
00183   char *url;
00184   aURL->GetSpec(&url);
00185   printf("%s\n", url);
00186 #endif
00187 
00188   nsCOMPtr<nsIStreamLoader> loader;
00189   rv = NS_NewStreamLoader(getter_AddRefs(loader), aURL, this);
00190 
00191   return rv;
00192 }
00193 
00194 
00195 NS_IMETHODIMP nsSound::Init()
00196 {
00197   if (CWinMM::IsInitialized())
00198     return NS_OK;
00199   CWinMM& theMM = CWinMM::GetModule();
00200 
00201   // This call halts a sound if it was still playing.
00202   // We have to use the sound library for something to make sure
00203   // it is initialized.
00204   // If we wait until the first sound is played, there will
00205   // be a time lag as the library gets loaded.
00206   theMM.PlaySound(nsnull, nsnull, SND_PURGE); 
00207 
00208   return NS_OK;
00209 }
00210 
00211 
00212 NS_IMETHODIMP nsSound::PlaySystemSound(const char *aSoundAlias)
00213 {
00214   PurgeLastSound();
00215 
00216   CWinMM& theMM = CWinMM::GetModule();
00217 
00218   if (nsCRT::strcmp("_moz_mailbeep", aSoundAlias) == 0) {
00219     theMM.PlaySound("MailBeep", nsnull, SND_ALIAS | SND_ASYNC);
00220   }
00221   else {
00222     theMM.PlaySound(aSoundAlias, nsnull, SND_ALIAS | SND_ASYNC);
00223   }
00224 
00225   return NS_OK;
00226 }
00227