2
Answers

How to work with unmanaged resourcres (SoundPlayer class)

Stefan B

Stefan B

8y
377
1
Hi together,

I have been working on a project which includes something close to a virtual keyboard in its GUI. So there are some Button-like objects you can click and something happens in the background. I now want them to make a clicking sound (async) (e.g. playing a .wav I have) when clicked. If another button gets clicked while the sound is still playing, it shall just stop and start the sound again at the begining.
Now this sounds rather easy, but there seems to be a devil in the details, since I can't get rid of a potential memory problem due to the wrapped unmanaged resource.
Round about everywhere you can read, that you need to dispose your SoundPlayer object or you will run out of memory since GC won't collect the unmanaged resource (Sound). Though, since I can not tell when my sound ends playing, I can not dispose my object properly.
The problems of different solutions are described pretty well in this topic:
http://stackoverflow.com/questions/1161229/how-to-use-system-media-soundplayer-to-asynchronously-play-a-sound-file?lq=1
Now I am not really sure why I should even run into a problem. If I implement something like this:
 
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.ComponentModel;  
  4. using System.Data;  
  5. using System.Drawing;  
  6. using System.Linq;  
  7. using System.Text;  
  8. using System.Windows.Forms;  
  9. using System.Media;  
  10.   
  11. namespace WindowsFormsApplication1  
  12. {  
  13.     public partial class Form1 : Form  
  14.     {  
  15.   
  16.         SoundPlayer player = new SoundPlayer(Resource1.test);  
  17.         public Form1()  
  18.         {  
  19.             InitializeComponent();  
  20.   
  21.         }  
  22.   
  23.         private void Form1_Load(object sender, EventArgs e)  
  24.         {  
  25.             player.Load();  
  26.         }  
  27.   
  28.         private void button1_Click(object sender, EventArgs e)  
  29.         {  
  30.             player.Play();  
  31.             this.button1.Text = (Int32.Parse(this.button1.Text) + 1).ToString();  
  32.         }  
  33.   
  34.         private void timer1_Tick(object sender, EventArgs e)  
  35.         {  
  36.             this.button1.PerformClick();  
  37.         }  
  38.     }  

 
Now in my understanding I create the player object once, which will wrap the test sound resource. I never manually dispose it, since there is no telling when to do so. But since I always use the same object, I still should not run into a memory leak. Or is this still a problem and memory gets blocked with each call of play?

What are good ways to get rid of this? It should solve the problem if I just get the sound from a file, shouln't it? Would I still want to use a "using" around the SoundPlayer object then or is it fine to just create one in this case?

I could of course dispose and reload before every click, the sound is just a few KB big, but that is not really the spirit of a good solution...

Thanks a lot for every advice,
Cheers
Stefan  
Answers (2)
1
Suthish Nair

Suthish Nair

NA 31.7k 4.6m 8y
Interesting...
 
I never got a chance to work on such a project. I need to try it out.
 
Sharing some links, hopes it helps you...
 
http://stackoverflow.com/questions/3502311/how-to-play-a-sound-in-c-net
http://stackoverflow.com/questions/21331412/best-way-to-use-the-system-media-soundplayer-class
 
Here suggesting not to use SoundPlayer due to memory issue...
http://stackoverflow.com/questions/4107886/soundplayer-causing-memory-leaks 
http://www.codeproject.com/Articles/13909/SoundPlayer-bug-Calling-unmanaged-APIs 
 
0
Stefan B

Stefan B

NA 3 376 8y
Hi, thanks a lot,
 
some of those links were  realy heplful! Even though I am still not sure why such a problem might even arise, I guess loading from a file seems to solve it, which is enough for the moment ;)
 
One last question, since this "problem" got me a little hyper nervous regarding memory leaks...

If I have 2 picture resources Pic1 and Pic2 and an ImageButton-Object, which is just some object inherited from UserControl and with a changed OnPaint:
01protected override void OnPaint(PaintEventArgs e)
02 {
03 base.OnPaint(e);
04 //stuff
05 if (this.keyStatus))
06 { this.imageButton.DefaultImage = Resource1.Pic1; }
07 else
08 { this.imageButton.DefaultImage = Resource1.Pic2; }
09 e.Graphics.DrawImage(this.defaultImage, this.ClientRectangle);
10 }

Beside OnPaint not being a good place for assigning DefaultImage (its just here to show you what I mean in a short piece of code), I am just assinging a reference to my precompiled resource here, am I? I am not creating a copy as I would if I would call it with "new Bitmap(Resource1.Pic1)".
So if I change keyStatus every 5 seconds, I would have a very annoying picture on my screen with a lot of chaning, but no problems that the picture changing leaks memory. Correct?


Again, thanks a lot!

Cheers Stefan