0

I'm trying to understand what is it in the implementation of SoundPlayer.Play that doesn't allow playing more than 1 sound async (e.g., as explained here or here). I looked into its source code, but I couldn't figured it out.

For convenience, here's the code of both SoundPlayer.Play and SoundPlayer.LoadAndPlay, which is the method called by SoundPlayer.Play:

public void Play() {
            LoadAndPlay(NativeMethods.SND_ASYNC);
        }    

private void LoadAndPlay(int flags) {
            // 
            if (String.IsNullOrEmpty(soundLocation) && stream == null) {
                SystemSounds.Beep.Play();
                return;
            }

            if (uri != null && uri.IsFile) {
                // VSW 580992: With more than one thread, someone could call SoundPlayer::set_Location
                // between the time LoadAndPlay demands FileIO and the time it calls PlaySound under elevation.
                // 
                // Another scenario is someone calling SoundPlayer::set_Location between the time
                // LoadAndPlay validates the sound file and the time it calls PlaySound.
                // The SoundPlayer will end up playing an un-validated sound file.
                // The solution is to store the uri.LocalPath on a local variable
                string localPath = uri.LocalPath;

                // request permission to read the file:
                // pass the full path to the FileIOPermission
                FileIOPermission perm = new FileIOPermission(FileIOPermissionAccess.Read, localPath);
                perm.Demand();

                // play the path
                isLoadCompleted = true;
                System.Media.SoundPlayer.IntSecurity.SafeSubWindows.Demand();

                System.ComponentModel.IntSecurity.UnmanagedCode.Assert();
                // ValidateSoundFile calls into the MMIO API so we need UnmanagedCode permissions to do that.
                // And of course we need UnmanagedCode permissions to all Win32::PlaySound method.
                try {
                    // don't use uri.AbsolutePath because that gives problems when there are whitespaces in file names
                    ValidateSoundFile(localPath);
                    UnsafeNativeMethods.PlaySound(localPath, IntPtr.Zero, NativeMethods.SND_NODEFAULT | flags);
                } finally {
                    System.Security.CodeAccessPermission.RevertAssert();
                }
            } else {
                LoadSync();
                ValidateSoundData(streamData);
                System.Media.SoundPlayer.IntSecurity.SafeSubWindows.Demand();

                System.ComponentModel.IntSecurity.UnmanagedCode.Assert();
                try {
                    UnsafeNativeMethods.PlaySound(streamData, IntPtr.Zero, NativeMethods.SND_MEMORY | NativeMethods.SND_NODEFAULT | flags);
                } finally {
                    System.Security.CodeAccessPermission.RevertAssert();
                }
            }
        }
Community
  • 1
  • 1
OfirD
  • 9,442
  • 5
  • 47
  • 90

1 Answers1

0

UnsafeNativeMethods.PlaySound (winmm.dll) only allows a single sound to be played at a specific time, per process.

superware
  • 389
  • 2
  • 10
  • How can we know that? PlaySound is declared as 'extern'; Where can we see its implementation? – OfirD Dec 18 '16 at 22:37
  • 1
    See [here](https://msdn.microsoft.com/en-us/library/windows/desktop/dd743680(v=vs.85).aspx): "SND_NOSTOP ... If this flag is not specified, PlaySound attempts to stop any sound that is currently playing in the same process. Sounds played in other processes are not affected." – superware Dec 20 '16 at 06:58