Back to index

lightning-sunbird  0.9+nobinonly
nsSoundDatasource.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Seth Spitzer <sspitzer@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsSoundDatasource.h"
00040 
00041 #include "nsIRDFService.h"
00042 #include "nsRDFCID.h"
00043 #include "nsIComponentManager.h"
00044 #include "nsXPIDLString.h"
00045 #include "rdf.h"
00046 #include "nsIServiceManager.h"
00047 #include "nsEnumeratorUtils.h"
00048 #include "nsString.h"
00049 #include "nsCOMPtr.h"
00050 #include "nsCRT.h"
00051 #include "nsIPrefService.h"
00052 #include "nsIPrefBranch.h"
00053 #include "nsIFileURL.h"
00054 #include "nsISimpleEnumerator.h"
00055 #include "nsNetCID.h"
00056 #include "nsIFile.h"
00057 #include "nsILocalFile.h"
00058 
00059 #define SOUND_ROOT "moz-mailsounds://"
00060 #define DEFAULT_SOUND_URL "_moz_mailbeep"
00061 #define DEFAULT_SOUND_URL_NAME "System New Mail Sound"  // move to string bundle
00062 #define PREF_NEW_MAIL_URL "mail.biff.play_sound.url"
00063 #define WAV_EXTENSION ".wav"
00064 #define WAV_EXTENSION_LENGTH 4
00065 #define FILE_SCHEME "file://"
00066 #define FILE_SCHEME_LEN 7
00067 
00068 #ifdef XP_WIN
00069 #include <windows.h> 
00070 #endif
00071 
00072 static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
00073 
00074 nsSoundDatasource::nsSoundDatasource()
00075 {
00076 }
00077 
00078 nsSoundDatasource::~nsSoundDatasource()
00079 {
00080 }
00081 
00082 NS_IMPL_ISUPPORTS1(nsSoundDatasource, nsIRDFDataSource)
00083 
00084 nsresult
00085 nsSoundDatasource::Init()
00086 {
00087   nsresult rv;
00088 
00089   mRDFService = do_GetService(kRDFServiceCID, &rv);
00090   NS_ENSURE_SUCCESS(rv,rv);
00091 
00092   rv = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "child"),
00093                                 getter_AddRefs(kNC_Child));
00094   NS_ENSURE_SUCCESS(rv,rv);
00095 
00096   rv = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Name"),
00097                                 getter_AddRefs(kNC_Name));
00098   NS_ENSURE_SUCCESS(rv,rv);
00099 
00100   rv = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "SoundURL"),
00101                                 getter_AddRefs(kNC_SoundURL));
00102   NS_ENSURE_SUCCESS(rv,rv);
00103        return NS_OK;
00104 }
00105 
00106 NS_IMETHODIMP 
00107 nsSoundDatasource::GetURI(char **aURI)
00108 {
00109   if ((*aURI = nsCRT::strdup("rdf:mailsounds")) == nsnull)
00110     return NS_ERROR_OUT_OF_MEMORY;
00111   else
00112     return NS_OK;
00113 }
00114 
00115 NS_IMETHODIMP 
00116 nsSoundDatasource::GetSource(nsIRDFResource *property, nsIRDFNode *target, PRBool tv, nsIRDFResource **source)
00117 {
00118   NS_ENSURE_ARG_POINTER(property);
00119   NS_ENSURE_ARG_POINTER(target);
00120   NS_ENSURE_ARG_POINTER(source);
00121   
00122   *source = nsnull;
00123   return NS_RDF_NO_VALUE;
00124 }
00125 
00126 NS_IMETHODIMP
00127 nsSoundDatasource::GetTarget(nsIRDFResource *source,
00128                                 nsIRDFResource *property,
00129                                 PRBool tv,
00130                                 nsIRDFNode **target /* out */)
00131 {
00132        nsresult rv = NS_RDF_NO_VALUE;
00133 
00134        NS_ENSURE_ARG_POINTER(property);
00135   NS_ENSURE_ARG_POINTER(target);
00136   NS_ENSURE_ARG_POINTER(source);
00137   
00138        *target = nsnull;
00139 
00140        // we only have positive assertions in the sound data source.
00141        if (!tv) 
00142     return NS_RDF_NO_VALUE;
00143 
00144   nsXPIDLCString value;
00145   rv = source->GetValue(getter_Copies(value));
00146   NS_ENSURE_SUCCESS(rv,rv);
00147 
00148   if (property == kNC_Name.get()) {
00149     nsCOMPtr<nsIRDFLiteral> name;
00150     if (strcmp(value.get(), DEFAULT_SOUND_URL)) {
00151       const char *lastSlash = strrchr(value.get(), '/');
00152       // turn "file://C|/winnt/media/foo.wav" into "foo".
00153       nsCAutoString soundName(lastSlash + 1);
00154       soundName.Truncate(soundName.Length() - WAV_EXTENSION_LENGTH);
00155       rv = mRDFService->GetLiteral(NS_ConvertASCIItoUCS2(soundName).get(), getter_AddRefs(name));
00156     }
00157     else {
00158       rv = mRDFService->GetLiteral(NS_ConvertASCIItoUCS2(DEFAULT_SOUND_URL_NAME).get(), getter_AddRefs(name));
00159     }
00160     NS_ENSURE_SUCCESS(rv,rv);
00161     
00162     if (!name) 
00163       return NS_RDF_NO_VALUE;
00164     else
00165       return name->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) target);
00166   }
00167   else if (property == kNC_SoundURL.get()) {
00168     nsCOMPtr<nsIRDFLiteral> name;
00169     rv = mRDFService->GetLiteral(NS_ConvertASCIItoUCS2(value).get(), getter_AddRefs(name));
00170     NS_ENSURE_SUCCESS(rv,rv);
00171     
00172     if (!name) 
00173       return NS_RDF_NO_VALUE;
00174     else
00175       return name->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) target);
00176   }
00177   else if (property == kNC_Child.get()) {
00178     if (strcmp(value.get(),SOUND_ROOT) == 0) {
00179       nsCOMPtr <nsIRDFResource> childResource;
00180       rv = mRDFService->GetResource(NS_LITERAL_CSTRING(DEFAULT_SOUND_URL),
00181                                     getter_AddRefs(childResource));
00182       NS_ENSURE_SUCCESS(rv,rv);
00183       return childResource->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) target);
00184     }
00185     else {
00186       return NS_RDF_NO_VALUE;
00187     }
00188   }
00189   else {
00190     // do nothing
00191   }
00192        return(NS_RDF_NO_VALUE);
00193 }
00194 
00195 #ifdef XP_WIN
00196 BYTE * GetValueBytes( HKEY hKey, const char *pValueName)
00197 {
00198        LONG   err;
00199        DWORD  bufSz;
00200        LPBYTE pBytes = NULL;
00201 
00202        err = ::RegQueryValueEx( hKey, pValueName, NULL, NULL, NULL, &bufSz); 
00203        if (err == ERROR_SUCCESS) {
00204               pBytes = new BYTE[bufSz];
00205               err = ::RegQueryValueEx( hKey, pValueName, NULL, NULL, pBytes, &bufSz);
00206               if (err != ERROR_SUCCESS) {
00207                      delete [] pBytes;
00208                      pBytes = NULL;
00209               }
00210        }
00211        return( pBytes);
00212 }
00213 #endif
00214 
00215 NS_IMETHODIMP
00216 nsSoundDatasource::GetTargets(nsIRDFResource *source,
00217                             nsIRDFResource *property,
00218                             PRBool tv,
00219                             nsISimpleEnumerator **targets /* out */)
00220 {
00221        nsresult rv = NS_OK;
00222 
00223        NS_ENSURE_ARG_POINTER(property);
00224   NS_ENSURE_ARG_POINTER(targets);
00225   NS_ENSURE_ARG_POINTER(source);
00226 
00227   *targets = nsnull;
00228 
00229        // we only have positive assertions in the sound data source.
00230        if (!tv) 
00231     return NS_RDF_NO_VALUE;
00232 
00233   nsXPIDLCString value;
00234   rv = source->GetValue(getter_Copies(value));
00235   NS_ENSURE_SUCCESS(rv,rv);
00236 
00237   if (property == kNC_Child.get()) {
00238     if (strcmp(value.get(), SOUND_ROOT))
00239       return NS_NewEmptyEnumerator(targets);
00240 
00241     nsCOMPtr<nsISupportsArray> children;
00242     rv = NS_NewISupportsArray(getter_AddRefs(children));
00243     NS_ENSURE_SUCCESS(rv,rv);
00244 
00245     nsCOMPtr <nsIRDFResource> res;
00246     rv = mRDFService->GetResource(NS_LITERAL_CSTRING(DEFAULT_SOUND_URL), getter_AddRefs(res));
00247     NS_ENSURE_SUCCESS(rv,rv);
00248     rv = children->AppendElement(res);
00249     NS_ENSURE_SUCCESS(rv,rv);
00250 
00251 #ifdef XP_WIN
00252     nsCAutoString soundFolder;
00253     
00254     HKEY sKey;
00255          if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", 0, KEY_QUERY_VALUE, &sKey) == ERROR_SUCCESS) {
00256                 BYTE *pBytes = GetValueBytes( sKey, "MediaPath");
00257               if (pBytes) {
00258                      soundFolder = (const char *)pBytes;
00259                      delete [] pBytes;
00260       }
00261                 ::RegCloseKey( sKey);
00262     }
00263 
00264     nsCOMPtr <nsILocalFile> directory = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID, &rv);
00265     NS_ENSURE_SUCCESS(rv,rv);
00266 
00267     rv = directory->InitWithPath(NS_ConvertASCIItoUCS2(soundFolder));
00268     NS_ENSURE_SUCCESS(rv,rv);
00269 
00270     nsCOMPtr <nsISimpleEnumerator> dirEntries;
00271     rv = directory->GetDirectoryEntries(getter_AddRefs(dirEntries));
00272     NS_ENSURE_SUCCESS(rv,rv);
00273 
00274     if (dirEntries) {
00275       PRBool hasMore = PR_FALSE;
00276       PRInt32 dirCount = 0, fileCount = 0;
00277  
00278       while (NS_SUCCEEDED(dirEntries->HasMoreElements(&hasMore)) && hasMore) {
00279         nsCOMPtr <nsISupports> nextItem;
00280         dirEntries->GetNext(getter_AddRefs(nextItem));
00281         nsCOMPtr <nsIFile> theFile = do_QueryInterface(nextItem);
00282    
00283         PRBool isDirectory;
00284         theFile->IsDirectory(&isDirectory);
00285    
00286         if (!isDirectory) {
00287           nsCOMPtr<nsIFileURL> theFileURL = do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv);
00288           NS_ENSURE_SUCCESS(rv,rv);
00289           
00290           rv = theFileURL->SetFile(theFile);
00291           NS_ENSURE_SUCCESS(rv,rv);
00292           
00293           nsXPIDLCString theFileSpec;
00294           rv = theFileURL->GetSpec(theFileSpec);
00295           NS_ENSURE_SUCCESS(rv,rv);
00296           
00297           // if it doesn't end with .wav, or it contains a %20, skip it.
00298           if (!strstr(theFileSpec.get(),"%20") && (theFileSpec.Length() > WAV_EXTENSION_LENGTH)) {
00299             if (strcmp(theFileSpec.get() + theFileSpec.Length() - WAV_EXTENSION_LENGTH, WAV_EXTENSION) == 0) {
00300               rv = mRDFService->GetResource(theFileSpec, getter_AddRefs(res));
00301               NS_ENSURE_SUCCESS(rv,rv);
00302               
00303               rv = children->AppendElement(res);
00304               NS_ENSURE_SUCCESS(rv,rv);
00305             }
00306           }
00307         }
00308       }
00309     }
00310 #endif
00311 
00312     // add entry for the pref specified one, if a file:// url
00313     // if not, it's a system sound, and we already added it.
00314     nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
00315     NS_ENSURE_SUCCESS(rv,rv);
00316 
00317     nsXPIDLCString soundURLSpec;
00318     rv = prefBranch->GetCharPref(PREF_NEW_MAIL_URL,getter_Copies(soundURLSpec));
00319     NS_ENSURE_SUCCESS(rv,rv);
00320 
00321     if (!strncmp(soundURLSpec.get(), FILE_SCHEME, FILE_SCHEME_LEN)) {
00322       rv = mRDFService->GetResource(soundURLSpec, getter_AddRefs(res));
00323       NS_ENSURE_SUCCESS(rv,rv);
00324       rv = children->AppendElement(res);
00325       NS_ENSURE_SUCCESS(rv,rv);
00326     }
00327 
00328     nsISimpleEnumerator* result = new nsArrayEnumerator(children);
00329     if (!result) 
00330       return NS_ERROR_OUT_OF_MEMORY;
00331 
00332     NS_ADDREF(*targets = result);
00333     return NS_OK;
00334   }
00335   else if (property == kNC_SoundURL.get()) {
00336     nsCOMPtr<nsIRDFLiteral> name;
00337     rv = mRDFService->GetLiteral(NS_ConvertASCIItoUCS2(value).get(), getter_AddRefs(name));
00338     NS_ENSURE_SUCCESS(rv,rv);
00339 
00340     nsISimpleEnumerator* result = new nsSingletonEnumerator(name);
00341     if (!result) 
00342       return NS_ERROR_OUT_OF_MEMORY;
00343     
00344     NS_ADDREF(*targets = result);
00345     return NS_OK;
00346   }
00347   else if (property == kNC_Name.get()) {
00348     nsCOMPtr<nsIRDFLiteral> name;
00349     if (strcmp(value.get(), DEFAULT_SOUND_URL)) {
00350       const char *lastSlash = strrchr(value.get(), '/');
00351       // turn "file://C|/winnt/media/foo.wav" into "foo".
00352       nsCAutoString soundName(lastSlash + 1);
00353       soundName.Truncate(soundName.Length() - WAV_EXTENSION_LENGTH);
00354       rv = mRDFService->GetLiteral(NS_ConvertASCIItoUCS2(soundName).get(), getter_AddRefs(name));
00355     }
00356     else {
00357       rv = mRDFService->GetLiteral(NS_ConvertASCIItoUCS2(DEFAULT_SOUND_URL_NAME).get(), getter_AddRefs(name));
00358     }
00359     NS_ENSURE_SUCCESS(rv,rv);
00360 
00361     nsISimpleEnumerator* result = new nsSingletonEnumerator(name);
00362     if (!result) 
00363       return NS_ERROR_OUT_OF_MEMORY;
00364     
00365     NS_ADDREF(*targets = result);
00366     return NS_OK;
00367   }
00368   else {
00369     // do nothing
00370   }
00371 
00372        return NS_NewEmptyEnumerator(targets);
00373 }
00374 
00375 NS_IMETHODIMP
00376 nsSoundDatasource::Assert(nsIRDFResource *source,
00377                        nsIRDFResource *property,
00378                        nsIRDFNode *target,
00379                        PRBool tv)
00380 {
00381        return NS_RDF_ASSERTION_REJECTED;
00382 }
00383 
00384 NS_IMETHODIMP
00385 nsSoundDatasource::Unassert(nsIRDFResource *source,
00386                          nsIRDFResource *property,
00387                          nsIRDFNode *target)
00388 {
00389        return NS_RDF_ASSERTION_REJECTED;
00390 }
00391 
00392 NS_IMETHODIMP
00393 nsSoundDatasource::Change(nsIRDFResource* aSource,
00394                                                   nsIRDFResource* aProperty,
00395                                                   nsIRDFNode* aOldTarget,
00396                                                   nsIRDFNode* aNewTarget)
00397 {
00398        return NS_RDF_ASSERTION_REJECTED;
00399 }
00400 
00401 NS_IMETHODIMP
00402 nsSoundDatasource::Move(nsIRDFResource* aOldSource,
00403                                              nsIRDFResource* aNewSource,
00404                                              nsIRDFResource* aProperty,
00405                                              nsIRDFNode* aTarget)
00406 {
00407        return NS_RDF_ASSERTION_REJECTED;
00408 }
00409 
00410 
00411 NS_IMETHODIMP
00412 nsSoundDatasource::HasAssertion(nsIRDFResource *source,
00413                              nsIRDFResource *property,
00414                              nsIRDFNode *target,
00415                              PRBool tv,
00416                              PRBool *hasAssertion /* out */)
00417 {
00418   NS_ENSURE_ARG_POINTER(property);
00419   NS_ENSURE_ARG_POINTER(target);
00420   NS_ENSURE_ARG_POINTER(source);
00421   NS_ENSURE_ARG_POINTER(hasAssertion);
00422 
00423        *hasAssertion = PR_FALSE;
00424 
00425   // we only have positive assertions in the sound data source.
00426        if (!tv) 
00427     return NS_OK;
00428 
00429        if (property == kNC_Child.get()) {
00430     nsXPIDLCString value;
00431     nsresult rv = source->GetValue(getter_Copies(value));
00432     NS_ENSURE_SUCCESS(rv,rv);
00433     // only root has children
00434     *hasAssertion = (strcmp(value.get(), SOUND_ROOT) == 0);
00435     return NS_OK;
00436   }
00437   else if (property == kNC_Name.get() || property == kNC_SoundURL.get()) {
00438     // everything has a name and a url
00439     *hasAssertion = PR_TRUE;
00440   }
00441   else {
00442     // do nothing
00443   }
00444 
00445        return NS_OK;
00446 }
00447 
00448 
00449 NS_IMETHODIMP 
00450 nsSoundDatasource::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, PRBool *result)
00451 {
00452   return NS_ERROR_NOT_IMPLEMENTED;
00453 }
00454 
00455 NS_IMETHODIMP 
00456 nsSoundDatasource::HasArcOut(nsIRDFResource *source, nsIRDFResource *aArc, PRBool *result)
00457 {
00458   nsresult rv = NS_OK;
00459   
00460   if (aArc == kNC_Child.get()) {
00461     nsXPIDLCString value;
00462     rv = source->GetValue(getter_Copies(value));
00463     // only root has children
00464     *result = (strcmp(value.get(), SOUND_ROOT) == 0);
00465     return NS_OK;
00466   }
00467   else if (aArc == kNC_Name.get() || aArc == kNC_SoundURL.get()) {
00468     *result = PR_TRUE;
00469     return NS_OK;
00470   }
00471   
00472   *result = PR_FALSE;
00473   return NS_OK;
00474 }
00475 
00476 NS_IMETHODIMP
00477 nsSoundDatasource::ArcLabelsIn(nsIRDFNode *node,
00478                             nsISimpleEnumerator ** labels /* out */)
00479 {
00480        return NS_ERROR_NOT_IMPLEMENTED;
00481 }
00482 
00483 NS_IMETHODIMP
00484 nsSoundDatasource::ArcLabelsOut(nsIRDFResource *source,
00485                                nsISimpleEnumerator **labels /* out */)
00486 {
00487   NS_ENSURE_ARG_POINTER(labels);
00488   NS_ENSURE_ARG_POINTER(source);
00489 
00490   nsresult rv = NS_OK;
00491 
00492   //return NS_NewEmptyEnumerator(labels);
00493   
00494   nsCOMPtr<nsISupportsArray> array;
00495   rv = NS_NewISupportsArray(getter_AddRefs(array));
00496   NS_ENSURE_SUCCESS(rv,rv);
00497 
00498   array->AppendElement(kNC_Name);
00499   array->AppendElement(kNC_SoundURL);
00500 
00501   nsXPIDLCString value;
00502   rv = source->GetValue(getter_Copies(value));
00503   // only root has children
00504   PRBool hasChildren = (strcmp(value.get(), SOUND_ROOT) == 0);
00505 
00506   if (hasChildren) {
00507    array->AppendElement(kNC_Child);
00508   }
00509 
00510   nsISimpleEnumerator* result = new nsArrayEnumerator(array);
00511   if (!result) 
00512     return NS_ERROR_OUT_OF_MEMORY;
00513 
00514   NS_ADDREF(result);
00515   *labels = result;
00516   return NS_OK;
00517 }
00518 
00519 NS_IMETHODIMP
00520 nsSoundDatasource::GetAllResources(nsISimpleEnumerator** aCursor)
00521 {
00522        NS_NOTYETIMPLEMENTED("sorry!");
00523        return NS_ERROR_NOT_IMPLEMENTED;
00524 }
00525 
00526 NS_IMETHODIMP
00527 nsSoundDatasource::GetAllCmds(nsIRDFResource* source,
00528                                      nsISimpleEnumerator/*<nsIRDFResource>*/** commands)
00529 {
00530        return(NS_NewEmptyEnumerator(commands));
00531 }
00532 
00533 NS_IMETHODIMP
00534 nsSoundDatasource::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
00535                                        nsIRDFResource*   aCommand,
00536                                        nsISupportsArray/*<nsIRDFResource>*/* aArguments,
00537                                        PRBool* aResult)
00538 {
00539        return(NS_ERROR_NOT_IMPLEMENTED);
00540 }
00541 
00542 NS_IMETHODIMP
00543 nsSoundDatasource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
00544                                 nsIRDFResource*   aCommand,
00545                                 nsISupportsArray/*<nsIRDFResource>*/* aArguments)
00546 {
00547        return(NS_ERROR_NOT_IMPLEMENTED);
00548 }
00549 
00550 NS_IMETHODIMP 
00551 nsSoundDatasource::GetSources(nsIRDFResource *aProperty, nsIRDFNode *aTarget, PRBool aTruthValue, nsISimpleEnumerator **_retval)
00552 {
00553   NS_ASSERTION(PR_FALSE, "Not implemented");
00554   return NS_ERROR_NOT_IMPLEMENTED;
00555 }
00556 
00557 NS_IMETHODIMP
00558 nsSoundDatasource::AddObserver(nsIRDFObserver *n)
00559 {
00560   NS_ENSURE_ARG_POINTER(n);
00561 
00562        if (!mObservers)
00563   {
00564     nsresult rv = NS_NewISupportsArray(getter_AddRefs(mObservers));
00565     if (NS_FAILED(rv)) return rv;
00566   }
00567   mObservers->AppendElement(n);
00568   return NS_OK;
00569 }
00570 
00571 
00572 NS_IMETHODIMP
00573 nsSoundDatasource::RemoveObserver(nsIRDFObserver *n)
00574 {
00575   NS_ENSURE_ARG_POINTER(n);
00576   if (!mObservers)
00577               return NS_OK;
00578 
00579        mObservers->RemoveElement(n);
00580        return NS_OK;
00581 }
00582 
00583 NS_IMETHODIMP
00584 nsSoundDatasource::BeginUpdateBatch()
00585 {
00586   return NS_OK;
00587 }
00588 
00589 NS_IMETHODIMP
00590 nsSoundDatasource::EndUpdateBatch()
00591 {
00592   return NS_OK;
00593 }