CdrTomalak's picture

Does OpenAL play sound in a separate thread by default?

Hi,

I've just got up and running with OpenTk, and have constructed a simple test harness which plays two sounds via the same AudioContext. So far so good.

I also have buffers set up for each sound I want to play.

However, I'm integrating OpenTK into my game engine to replace another API and I've hit a problem.

I have just triggered a sound to play, but I *think* is persisting for a microsecond, so I'm wondering if AL.SourcePlay(source); plays the sound in a separate thread or not?

If not then all I need to do is play each sound in it's own thread. I'm just getting silence at the moment. Wierd.

Any pointers most appreciated. I'll get back to the coding tonight and post up my code! 8p


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture
Quote:

I have just triggered a sound to play, but I *think* is persisting for a microsecond, so I'm wondering if AL.SourcePlay(source); plays the sound in a separate thread or not?

What do you mean by "persisting"? Do you mean that there is a delay between the AL.SourcePlay() call and hearing the sound on the speakers? What operating system and which OpenAL drivers are you using?

As far as I know, no, the sounds are played on the thread you issue them in. This is an implementation detail of whatever OpenAL driver is installed, so different drivers might behave differently. This should not have any effect on sound delay.

OpenAL contexts, like OpenGL contexts, are specific to the thread they are created in. You can use Alc.MakeContextCurrent() to move a context to a different thread, but you can only issue OpenAL commands on a thread that has an OpenAL context. This means that you cannot simply call AL.SourcePlay() on a different thread, as that will not do anything (or even crash, depending on the driver.)

CdrTomalak's picture
the Fiddler wrote:
Quote:

I have just triggered a sound to play, but I *think* is persisting for a microsecond, so I'm wondering if AL.SourcePlay(source); plays the sound in a separate thread or not?

What do you mean by "persisting"? Do you mean that there is a delay between the AL.SourcePlay() call and hearing the sound on the speakers? What operating system and which OpenAL drivers are you using?

As far as I know, no, the sounds are played on the thread you issue them in. This is an implementation detail of whatever OpenAL driver is installed, so different drivers might behave differently. This should not have any effect on sound delay.

OpenAL contexts, like OpenGL contexts, are specific to the thread they are created in. You can use Alc.MakeContextCurrent() to move a context to a different thread, but you can only issue OpenAL commands on a thread that has an OpenAL context. This means that you cannot simply call AL.SourcePlay() on a different thread, as that will not do anything (or even crash, depending on the driver.)

Thanks for the reply fiddler! 8)

All I meant by persisting was that the sound only plays for a fraction of a second. I've done some more experimentation today, and have a really basic routine which plays a sound in the current thread. I need to work from this to the point where I get the result I need.

				using (AudioContext ALcontext = new AudioContext())
				{
					// 3. Set up a source which will play this sound.
					int source = AL.GenSource();
					string ALfilename = "";
					string wavPath = "";
					int channels, bits_per_sample, sample_rate;
					byte[] sound_data;
					int state;
 
					//
					// 4. Play Sound 1
					//
					// Buffer sound 1
					switch(effectsIn)
					{
						case "KILLED_BY_GHOST":
							//wavPath = "D:\\Programming\\SFX\\KILLED_BY_GHOST\\Hit_72.wav";
							wavPath = "D:\\Programming\\SFX\\MUSIC\\IN_GAME_1_s.wav";
							ALfilename = Path.Combine(Path.Combine("Data", "Audio"), wavPath);	
							sound_data = LoadWave(File.Open(ALfilename, FileMode.Open), out channels, out bits_per_sample, out sample_rate);							
							buffer_KILLED_BY_GHOST = AL.GenBuffer();
							AL.BufferData(buffer_KILLED_BY_GHOST, GetSoundFormat(channels, bits_per_sample), sound_data, sound_data.Length, sample_rate);
							AL.Source(source, ALSourcei.Buffer, buffer_KILLED_BY_GHOST);
							AL.SourcePlay(source);
 
							// Query the source to find out when it stops playing.
							do
							{
								Thread.Sleep(250);
								Trace.Write(".");
								AL.GetSource(source, ALGetSourcei.SourceState, out state);
							}
							while ( (ALSourceState)state == ALSourceState.Playing);
 
							break;
						case "EATEN_PILL":
							wavPath = "D:\\Programming\\SFX\\EATEN_PILL\\Hit_43.wav";
							//wavPath = "D:\\Programming\\SFX\\MUSIC\\IN_GAME_1_s.wav";
							ALfilename = Path.Combine(Path.Combine("Data", "Audio"), wavPath);							
							sound_data = LoadWave(File.Open(ALfilename, FileMode.Open), out channels, out bits_per_sample, out sample_rate);
							buffer_EATEN_PILL = AL.GenBuffer();
							AL.BufferData(buffer_EATEN_PILL, GetSoundFormat(channels, bits_per_sample), sound_data, sound_data.Length, sample_rate);
							AL.Source(source, ALSourcei.Buffer, buffer_EATEN_PILL);
							AL.SourcePlay(source);
 
							// Query the source to find out when it stops playing.
							do
							{
								Thread.Sleep(250);
								Trace.Write(".");
								AL.GetSource(source, ALGetSourcei.SourceState, out state);
							}
							while ( (ALSourceState)state == ALSourceState.Playing);
 
							break;
						case "EATEN_GHOST":
							//wavPath = "D:\\Programming\\SFX\\EATEN_GHOST\\Hit_55.wav";
							wavPath = "D:\\Programming\\SFX\\MUSIC\\IN_GAME_1_s.wav";
							ALfilename = Path.Combine(Path.Combine("Data", "Audio"), wavPath);							
							sound_data = LoadWave(File.Open(ALfilename, FileMode.Open), out channels, out bits_per_sample, out sample_rate);
							buffer_EATEN_GHOST = AL.GenBuffer();
							AL.BufferData(buffer_EATEN_GHOST, GetSoundFormat(channels, bits_per_sample), sound_data, sound_data.Length, sample_rate);
							AL.Source(source, ALSourcei.Buffer, buffer_EATEN_GHOST);
							AL.SourcePlay(source);
 
							// Query the source to find out when it stops playing.
							do
							{
								Thread.Sleep(250);
								Trace.Write(".");
								AL.GetSource(source, ALGetSourcei.SourceState, out state);
							}
							while ( (ALSourceState)state == ALSourceState.Playing);
 
							break;
						case "EATEN_POWERPILL":
							//wavPath = "D:\\Programming\\SFX\\EATEN_POWERPILL\\Hit_49.wav";
							wavPath = "D:\\Programming\\SFX\\MUSIC\\IN_GAME_1_s.wav";
							ALfilename = Path.Combine(Path.Combine("Data", "Audio"), wavPath);							
							sound_data = LoadWave(File.Open(ALfilename, FileMode.Open), out channels, out bits_per_sample, out sample_rate);
							buffer_EATEN_POWERPILL = AL.GenBuffer();
							AL.BufferData(buffer_EATEN_POWERPILL, GetSoundFormat(channels, bits_per_sample), sound_data, sound_data.Length, sample_rate);
							AL.Source(source, ALSourcei.Buffer, buffer_EATEN_POWERPILL);
							AL.SourcePlay(source);
 
							// Query the source to find out when it stops playing.
							do
							{
								Thread.Sleep(250);
								Trace.Write(".");
								AL.GetSource(source, ALGetSourcei.SourceState, out state);
							}
							while ( (ALSourceState)state == ALSourceState.Playing);
 
							break;
					} // switch				

That's an extract from my method to play a sound effect if the conditions are right. Obviously at the moment there is a big pause in the game while the sound plays. What I hope to do is introduce threading so there is no delay at all. I'm not sure how expensive the OpenAL operations are that I execute every time I need to play a sound either.

More tomorrow hopefully!

CdrTomalak's picture

Ok I've cracked this one now. Simple really. I created a sound handler object with it's own audio context.

The only problem now is an annoying click at the end of each sound that plays!