2009-07-17 10:26:32 +02:00
#region License
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
2009-02-22 11:43:35 +01:00
#endregion
2009-07-17 10:26:32 +02:00
2009-02-22 11:43:35 +01:00
using System ;
using System.Collections.Generic ;
using System.Text ;
using System.Diagnostics ;
2009-08-17 12:32:20 +02:00
using OpenTK.Audio.OpenAL ;
2009-02-22 11:43:35 +01:00
namespace OpenTK.Audio
{
/// <summary>
2009-07-16 14:49:24 +02:00
/// Provides methods to instantiate, use and destroy an audio context for playback.
/// Static methods are provided to list available devices known by the driver.
2009-02-22 11:43:35 +01:00
/// </summary>
public sealed class AudioContext : IDisposable
{
#region - - - Fields - - -
bool disposed ;
2009-03-25 22:53:12 +01:00
bool is_processing , is_synchronized ;
2009-02-22 11:43:35 +01:00
IntPtr device_handle ;
ContextHandle context_handle ;
bool context_exists ;
string device_name ;
static object audio_context_lock = new object ( ) ;
static Dictionary < ContextHandle , AudioContext > available_contexts = new Dictionary < ContextHandle , AudioContext > ( ) ;
#endregion
#region - - - Constructors - - -
#region static AudioContext ( )
/// <private />
/// <static />
/// <summary>
/// Runs before the actual class constructor, to load available devices.
/// </summary>
static AudioContext ( )
{
2009-07-16 14:49:24 +02:00
if ( AudioDeviceEnumerator . IsOpenALSupported ) // forces enumeration
{ }
2009-02-22 11:43:35 +01:00
}
2009-07-16 14:49:24 +02:00
#endregion static AudioContext ( )
2009-02-22 11:43:35 +01:00
#region public AudioContext ( )
/// <summary>Constructs a new AudioContext, using the default audio device.</summary>
2009-03-13 01:01:17 +01:00
public AudioContext ( )
2009-07-16 14:49:24 +02:00
: this ( null , 0 , 0 , false , true , MaxAuxiliarySends . UseDriverDefault ) { }
2009-02-22 11:43:35 +01:00
#endregion
2009-03-13 01:01:17 +01:00
2009-02-22 11:43:35 +01:00
#region public AudioContext ( string device )
2009-09-04 23:44:39 +02:00
/// <summary>
/// Constructs a new AudioContext instance.
/// </summary>
/// <param name="device">The device name that will host this instance.</param>
2009-07-16 14:49:24 +02:00
public AudioContext ( string device ) : this ( device , 0 , 0 , false , true , MaxAuxiliarySends . UseDriverDefault ) { }
2009-02-22 11:43:35 +01:00
#endregion
#region public AudioContext ( string device , int freq )
/// <summary>Constructs a new AudioContext, using the specified audio device and device parameters.</summary>
/// <param name="device">The name of the audio device to use.</param>
/// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
/// <remarks>
/// Use AudioContext.AvailableDevices to obtain a list of all available audio devices.
/// devices.
/// </remarks>
2009-07-16 14:49:24 +02:00
public AudioContext ( string device , int freq ) : this ( device , freq , 0 , false , true , MaxAuxiliarySends . UseDriverDefault ) { }
2009-02-22 11:43:35 +01:00
#endregion
#region public AudioContext ( string device , int freq , int refresh )
/// <summary>Constructs a new AudioContext, using the specified audio device and device parameters.</summary>
/// <param name="device">The name of the audio device to use.</param>
/// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
/// <param name="refresh">Refresh intervals, in units of Hz. Pass 0 for driver default.</param>
/// <remarks>
/// Use AudioContext.AvailableDevices to obtain a list of all available audio devices.
/// devices.
/// </remarks>
public AudioContext ( string device , int freq , int refresh )
2009-07-16 14:49:24 +02:00
: this ( device , freq , refresh , false , true , MaxAuxiliarySends . UseDriverDefault ) { }
2009-02-22 11:43:35 +01:00
#endregion
2009-07-16 14:49:24 +02:00
#region public AudioContext ( string device , int freq , int refresh , bool sync )
2009-02-22 11:43:35 +01:00
/// <summary>Constructs a new AudioContext, using the specified audio device and device parameters.</summary>
/// <param name="device">The name of the audio device to use.</param>
/// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
/// <param name="refresh">Refresh intervals, in units of Hz. Pass 0 for driver default.</param>
/// <param name="sync">Flag, indicating a synchronous context.</param>
/// <remarks>
/// Use AudioContext.AvailableDevices to obtain a list of all available audio devices.
/// devices.
/// </remarks>
public AudioContext ( string device , int freq , int refresh , bool sync )
2009-07-16 14:49:24 +02:00
: this ( AudioDeviceEnumerator . AvailablePlaybackDevices [ 0 ] , freq , refresh , sync , true ) { }
2009-02-22 11:43:35 +01:00
#endregion
2009-03-25 22:53:12 +01:00
#region public AudioContext ( string device , int freq , int refresh , bool sync , bool enableEfx )
2009-02-22 11:43:35 +01:00
/// <summary>Creates the audio context using the specified device and device parameters.</summary>
/// <param name="device">The device descriptor obtained through AudioContext.AvailableDevices.</param>
/// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
/// <param name="refresh">Refresh intervals, in units of Hz. Pass 0 for driver default.</param>
/// <param name="sync">Flag, indicating a synchronous context.</param>
2009-03-13 01:01:17 +01:00
/// <param name="enableEfx">Indicates whether the EFX extension should be initialized, if present.</param>
2009-02-22 11:43:35 +01:00
/// <exception cref="ArgumentNullException">Occurs when the device string is invalid.</exception>
/// <exception cref="ArgumentOutOfRangeException">Occurs when a specified parameter is invalid.</exception>
2009-03-25 22:53:12 +01:00
/// <exception cref="AudioDeviceException">
2009-02-22 11:43:35 +01:00
/// Occurs when the specified device is not available, or is in use by another program.
/// </exception>
2009-03-25 22:53:12 +01:00
/// <exception cref="AudioContextException">
2009-02-22 11:43:35 +01:00
/// Occurs when an audio context could not be created with the specified parameters.
/// </exception>
/// <exception cref="NotSupportedException">
/// Occurs when an AudioContext already exists.</exception>
/// <remarks>
/// <para>For maximum compatibility, you are strongly recommended to use the default constructor.</para>
/// <para>Multiple AudioContexts are not supported at this point.</para>
/// <para>
/// The number of auxilliary EFX sends depends on the audio hardware and drivers. Most Realtek devices, as well
/// as the Creative SB Live!, support 1 auxilliary send. Creative's Audigy and X-Fi series support 4 sends.
/// Values higher than supported will be clamped by the driver.
/// </para>
/// </remarks>
2009-03-13 01:01:17 +01:00
public AudioContext ( string device , int freq , int refresh , bool sync , bool enableEfx )
2009-02-22 11:43:35 +01:00
{
2009-07-16 14:49:24 +02:00
CreateContext ( device , freq , refresh , sync , enableEfx , MaxAuxiliarySends . UseDriverDefault ) ;
2009-02-22 11:43:35 +01:00
}
#endregion
2009-03-13 01:01:17 +01:00
2009-07-16 14:49:24 +02:00
#region public AudioContext ( string device , int freq , int refresh , bool sync , bool enableEfx , MaxAuxiliarySends efxMaxAuxSends )
2009-02-22 11:43:35 +01:00
2009-07-16 14:49:24 +02:00
/// <summary>Creates the audio context using the specified device and device parameters.</summary>
/// <param name="device">The device descriptor obtained through AudioContext.AvailableDevices.</param>
/// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
/// <param name="refresh">Refresh intervals, in units of Hz. Pass 0 for driver default.</param>
/// <param name="sync">Flag, indicating a synchronous context.</param>
/// <param name="enableEfx">Indicates whether the EFX extension should be initialized, if present.</param>
/// <param name="efxMaxAuxSends">Requires EFX enabled. The number of desired Auxiliary Sends per source.</param>
/// <exception cref="ArgumentNullException">Occurs when the device string is invalid.</exception>
/// <exception cref="ArgumentOutOfRangeException">Occurs when a specified parameter is invalid.</exception>
/// <exception cref="AudioDeviceException">
/// Occurs when the specified device is not available, or is in use by another program.
/// </exception>
/// <exception cref="AudioContextException">
/// Occurs when an audio context could not be created with the specified parameters.
/// </exception>
/// <exception cref="NotSupportedException">
/// Occurs when an AudioContext already exists.</exception>
2009-02-22 11:43:35 +01:00
/// <remarks>
2009-07-16 14:49:24 +02:00
/// <para>For maximum compatibility, you are strongly recommended to use the default constructor.</para>
/// <para>Multiple AudioContexts are not supported at this point.</para>
/// <para>
/// The number of auxilliary EFX sends depends on the audio hardware and drivers. Most Realtek devices, as well
/// as the Creative SB Live!, support 1 auxilliary send. Creative's Audigy and X-Fi series support 4 sends.
/// Values higher than supported will be clamped by the driver.
/// </para>
2009-02-22 11:43:35 +01:00
/// </remarks>
2009-07-16 14:49:24 +02:00
public AudioContext ( string device , int freq , int refresh , bool sync , bool enableEfx , MaxAuxiliarySends efxMaxAuxSends )
2009-02-22 11:43:35 +01:00
{
2009-07-16 14:49:24 +02:00
CreateContext ( device , freq , refresh , sync , enableEfx , efxMaxAuxSends ) ;
2009-02-22 11:43:35 +01:00
}
#endregion
2009-07-16 14:49:24 +02:00
#endregion - - - Constructors - - -
#region - - - Private Methods - - -
2009-03-13 01:01:17 +01:00
#region CreateContext
2009-02-22 11:43:35 +01:00
2009-07-16 14:49:24 +02:00
/// <summary>May be passed at context construction time to indicate the number of desired auxiliary effect slot sends per source.</summary>
public enum MaxAuxiliarySends : int
{
/// <summary>Will chose a reliably working parameter.</summary>
UseDriverDefault = 0 ,
/// <summary>One send per source.</summary>
One = 1 ,
/// <summary>Two sends per source.</summary>
Two = 2 ,
/// <summary>Three sends per source.</summary>
Three = 3 ,
/// <summary>Four sends per source.</summary>
Four = 4 ,
}
2009-02-22 11:43:35 +01:00
/// <private />
/// <summary>Creates the audio context using the specified device.</summary>
/// <param name="device">The device descriptor obtained through AudioContext.AvailableDevices, or null for the default device.</param>
/// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
/// <param name="refresh">Refresh intervals, in units of Hz. Pass 0 for driver default.</param>
/// <param name="sync">Flag, indicating a synchronous context.</param>
2009-03-13 01:01:17 +01:00
/// <param name="enableEfx">Indicates whether the EFX extension should be initialized, if present.</param>
2009-07-16 14:49:24 +02:00
/// <param name="efxAuxiliarySends">Requires EFX enabled. The number of desired Auxiliary Sends per source.</param>
/// <exception cref="ArgumentOutOfRangeException">Occurs when a specified parameter is invalid.</exception>
2009-02-22 11:43:35 +01:00
/// <exception cref="AudioDeviceException">
/// Occurs when the specified device is not available, or is in use by another program.
/// </exception>
2009-03-25 22:53:12 +01:00
/// <exception cref="AudioContextException">
2009-02-22 11:43:35 +01:00
/// Occurs when an audio context could not be created with the specified parameters.
/// </exception>
/// <exception cref="NotSupportedException">
/// Occurs when an AudioContext already exists.</exception>
/// <remarks>
/// <para>For maximum compatibility, you are strongly recommended to use the default constructor.</para>
/// <para>Multiple AudioContexts are not supported at this point.</para>
/// <para>
/// The number of auxilliary EFX sends depends on the audio hardware and drivers. Most Realtek devices, as well
/// as the Creative SB Live!, support 1 auxilliary send. Creative's Audigy and X-Fi series support 4 sends.
/// Values higher than supported will be clamped by the driver.
/// </para>
/// </remarks>
2009-07-16 14:49:24 +02:00
void CreateContext ( string device , int freq , int refresh , bool sync , bool enableEfx , MaxAuxiliarySends efxAuxiliarySends )
2009-02-22 11:43:35 +01:00
{
2009-07-16 14:49:24 +02:00
if ( ! AudioDeviceEnumerator . IsOpenALSupported )
2009-03-13 01:01:17 +01:00
throw new DllNotFoundException ( "openal32.dll" ) ;
2009-07-16 14:49:24 +02:00
if ( AudioDeviceEnumerator . Version = = AudioDeviceEnumerator . AlcVersion . Alc1_1 & & AudioDeviceEnumerator . AvailablePlaybackDevices . Count = = 0 ) // Alc 1.0 does not support device enumeration.
2009-02-22 11:43:35 +01:00
throw new NotSupportedException ( "No audio hardware is available." ) ;
if ( context_exists ) throw new NotSupportedException ( "Multiple AudioContexts are not supported." ) ;
if ( freq < 0 ) throw new ArgumentOutOfRangeException ( "freq" , freq , "Should be greater than zero." ) ;
if ( refresh < 0 ) throw new ArgumentOutOfRangeException ( "refresh" , refresh , "Should be greater than zero." ) ;
2009-07-16 14:49:24 +02:00
2009-02-22 11:43:35 +01:00
if ( ! String . IsNullOrEmpty ( device ) )
2009-07-16 14:49:24 +02:00
{
device_name = device ;
device_handle = Alc . OpenDevice ( device ) ; // try to open device by name
}
2009-02-22 11:43:35 +01:00
if ( device_handle = = IntPtr . Zero )
2009-07-16 14:49:24 +02:00
{
device_name = "IntPtr.Zero (null string)" ;
device_handle = Alc . OpenDevice ( null ) ; // try to open unnamed default device
}
2009-02-22 11:43:35 +01:00
if ( device_handle = = IntPtr . Zero )
2009-07-16 14:49:24 +02:00
{
2009-07-18 01:00:22 +02:00
device_name = AudioContext . DefaultDevice ;
device_handle = Alc . OpenDevice ( AudioContext . DefaultDevice ) ; // try to open named default device
2009-07-16 14:49:24 +02:00
}
2009-02-22 11:43:35 +01:00
if ( device_handle = = IntPtr . Zero )
2009-07-16 14:49:24 +02:00
{
device_name = "None" ;
2009-02-22 11:43:35 +01:00
throw new AudioDeviceException ( String . Format ( "Audio device '{0}' does not exist or is tied up by another application." ,
2009-05-06 11:09:00 +02:00
String . IsNullOrEmpty ( device ) ? "default" : device ) ) ;
2009-07-16 14:49:24 +02:00
}
2009-02-22 11:43:35 +01:00
2009-07-18 01:00:22 +02:00
CheckErrors ( ) ;
2009-02-22 11:43:35 +01:00
// Build the attribute list
List < int > attributes = new List < int > ( ) ;
2009-07-16 14:49:24 +02:00
2009-02-22 11:43:35 +01:00
if ( freq ! = 0 )
{
attributes . Add ( ( int ) AlcContextAttributes . Frequency ) ;
attributes . Add ( freq ) ;
}
2009-07-16 14:49:24 +02:00
2009-02-22 11:43:35 +01:00
if ( refresh ! = 0 )
{
attributes . Add ( ( int ) AlcContextAttributes . Refresh ) ;
attributes . Add ( refresh ) ;
}
2009-07-16 14:49:24 +02:00
2009-05-06 11:09:00 +02:00
attributes . Add ( ( int ) AlcContextAttributes . Sync ) ;
2009-02-22 11:43:35 +01:00
attributes . Add ( sync ? 1 : 0 ) ;
2009-03-13 01:01:17 +01:00
if ( enableEfx & & Alc . IsExtensionPresent ( device_handle , "ALC_EXT_EFX" ) )
2009-02-22 11:43:35 +01:00
{
2009-03-13 01:01:17 +01:00
int num_slots ;
2009-07-16 14:49:24 +02:00
switch ( efxAuxiliarySends )
{
case MaxAuxiliarySends . One :
case MaxAuxiliarySends . Two :
case MaxAuxiliarySends . Three :
case MaxAuxiliarySends . Four :
num_slots = ( int ) efxAuxiliarySends ;
break ;
default :
case MaxAuxiliarySends . UseDriverDefault :
Alc . GetInteger ( device_handle , AlcGetInteger . EfxMaxAuxiliarySends , 1 , out num_slots ) ;
break ;
}
2009-03-13 01:01:17 +01:00
attributes . Add ( ( int ) AlcContextAttributes . EfxMaxAuxiliarySends ) ;
attributes . Add ( num_slots ) ;
2009-02-22 11:43:35 +01:00
}
2009-03-13 01:01:17 +01:00
attributes . Add ( 0 ) ;
2009-02-22 11:43:35 +01:00
context_handle = Alc . CreateContext ( device_handle , attributes . ToArray ( ) ) ;
if ( context_handle = = ContextHandle . Zero )
{
Alc . CloseDevice ( device_handle ) ;
throw new AudioContextException ( "The audio context could not be created with the specified parameters." ) ;
}
2009-07-18 01:00:22 +02:00
CheckErrors ( ) ;
2009-02-22 11:43:35 +01:00
// HACK: OpenAL SI on Linux/ALSA crashes on MakeCurrent. This hack avoids calling MakeCurrent when
// an old OpenAL version is detect - it may affect outdated OpenAL versions different than OpenAL SI,
// but it looks like a good compromise for now.
2009-07-16 14:49:24 +02:00
if ( AudioDeviceEnumerator . AvailablePlaybackDevices . Count > 0 )
2009-02-22 11:43:35 +01:00
MakeCurrent ( ) ;
2009-07-18 01:00:22 +02:00
CheckErrors ( ) ;
2009-07-16 14:49:24 +02:00
2009-03-25 22:53:12 +01:00
device_name = Alc . GetString ( device_handle , AlcGetString . DeviceSpecifier ) ;
2009-07-18 01:00:22 +02:00
2009-03-25 22:53:12 +01:00
2009-02-22 11:43:35 +01:00
lock ( audio_context_lock )
{
available_contexts . Add ( this . context_handle , this ) ;
context_exists = true ;
}
}
2009-07-16 14:49:24 +02:00
#endregion - - - Private Methods - - -
2009-02-22 11:43:35 +01:00
#region static void MakeCurrent ( AudioContext context )
/// <private />
/// <summary>Makes the specified AudioContext current in the calling thread.</summary>
/// <param name="context">The OpenTK.Audio.AudioContext to make current, or null.</param>
/// <exception cref="ObjectDisposedException">
/// Occurs if this function is called after the AudioContext has been disposed.
/// </exception>
/// <exception cref="AudioContextException">
/// Occurs when the AudioContext could not be made current.
/// </exception>
static void MakeCurrent ( AudioContext context )
{
lock ( audio_context_lock )
{
if ( ! Alc . MakeContextCurrent ( context ! = null ? context . context_handle : ContextHandle . Zero ) )
throw new AudioContextException ( String . Format ( "ALC {0} error detected at {1}." ,
Alc . GetError ( context ! = null ? ( IntPtr ) context . context_handle : IntPtr . Zero ) . ToString ( ) ,
context ! = null ? context . ToString ( ) : "null" ) ) ;
}
}
#endregion
#region internal bool IsCurrent
/// <summary>
/// Gets or sets a System.Boolean indicating whether the AudioContext
/// is current.
/// </summary>
/// <remarks>
/// Only one AudioContext can be current in the application at any time,
/// <b>regardless of the number of threads</b>.
/// </remarks>
internal bool IsCurrent
{
get
{
lock ( audio_context_lock )
{
if ( available_contexts . Count = = 0 )
return false ;
else
{
return AudioContext . CurrentContext = = this ;
}
}
}
set
{
if ( value ) AudioContext . MakeCurrent ( this ) ;
else AudioContext . MakeCurrent ( null ) ;
}
}
#endregion
#region IntPtr Device
IntPtr Device { get { return device_handle ; } }
#endregion
#endregion
#region - - - Public Members - - -
2009-07-18 01:00:22 +02:00
#region CheckErrors
/// <summary>
/// Checks for ALC error conditions.
/// </summary>
/// <exception cref="OutOfMemoryException">Raised when an out of memory error is detected.</exception>
/// <exception cref="AudioValueException">Raised when an invalid value is detected.</exception>
/// <exception cref="AudioDeviceException">Raised when an invalid device is detected.</exception>
/// <exception cref="AudioContextException">Raised when an invalid context is detected.</exception>
public void CheckErrors ( )
{
2009-07-18 01:07:17 +02:00
if ( disposed )
throw new ObjectDisposedException ( this . GetType ( ) . FullName ) ;
2009-07-18 01:00:22 +02:00
new AudioDeviceErrorChecker ( device_handle ) . Dispose ( ) ;
}
#endregion
#region CurrentError
2009-07-18 01:07:17 +02:00
/// <summary>
/// Returns the ALC error code for this instance.
/// </summary>
2009-07-18 01:00:22 +02:00
public AlcError CurrentError
{
get
{
2009-07-18 01:07:17 +02:00
if ( disposed )
throw new ObjectDisposedException ( this . GetType ( ) . FullName ) ;
2009-07-18 01:00:22 +02:00
return Alc . GetError ( device_handle ) ;
}
}
#endregion
2009-07-18 01:07:17 +02:00
#region MakeCurrent
2009-02-22 11:43:35 +01:00
/// <summary>Makes the AudioContext current in the calling thread.</summary>
/// <exception cref="ObjectDisposedException">
/// Occurs if this function is called after the AudioContext has been disposed.
/// </exception>
/// <exception cref="AudioContextException">
/// Occurs when the AudioContext could not be made current.
/// </exception>
/// <remarks>
/// Only one AudioContext can be current in the application at any time,
/// <b>regardless of the number of threads</b>.
/// </remarks>
public void MakeCurrent ( )
{
2009-07-18 01:07:17 +02:00
if ( disposed )
throw new ObjectDisposedException ( this . GetType ( ) . FullName ) ;
2009-02-22 11:43:35 +01:00
AudioContext . MakeCurrent ( this ) ;
}
#endregion
2009-07-18 01:07:17 +02:00
#region IsProcessing
2009-02-22 11:43:35 +01:00
/// <summary>
/// Gets a System.Boolean indicating whether the AudioContext is
/// currently processing audio events.
/// </summary>
/// <seealso cref="Process"/>
/// <seealso cref="Suspend"/>
public bool IsProcessing
{
2009-07-18 01:07:17 +02:00
get
{
if ( disposed )
throw new ObjectDisposedException ( this . GetType ( ) . FullName ) ;
return is_processing ;
}
2009-02-22 11:43:35 +01:00
private set { is_processing = value ; }
}
#endregion
2009-07-18 01:07:17 +02:00
#region IsSynchronized
2009-03-25 22:53:12 +01:00
/// <summary>
/// Gets a System.Boolean indicating whether the AudioContext is
/// synchronized.
/// </summary>
/// <seealso cref="Process"/>
public bool IsSynchronized
{
2009-07-18 01:07:17 +02:00
get
{
if ( disposed )
throw new ObjectDisposedException ( this . GetType ( ) . FullName ) ;
return is_synchronized ;
}
2009-03-25 22:53:12 +01:00
private set { is_synchronized = value ; }
}
#endregion
2009-02-22 11:43:35 +01:00
#region public void Process
/// <summary>
/// Processes queued audio events.
/// </summary>
/// <remarks>
/// <para>
/// If AudioContext.IsSynchronized is true, this function will resume
/// the internal audio processing thread. If AudioContext.IsSynchronized is false,
/// you will need to call this function multiple times per second to process
/// audio events.
/// </para>
/// <para>
/// In some implementations this function may have no effect.
/// </para>
/// </remarks>
/// <exception cref="ObjectDisposedException">Occurs when this function is called after the AudioContext had been disposed.</exception>
/// <seealso cref="Suspend"/>
2009-03-25 22:53:12 +01:00
/// <seealso cref="IsProcessing"/>
2009-02-22 11:43:35 +01:00
/// <seealso cref="IsSynchronized"/>
public void Process ( )
{
2009-07-18 01:07:17 +02:00
if ( disposed )
throw new ObjectDisposedException ( this . GetType ( ) . FullName ) ;
2009-02-22 11:43:35 +01:00
Alc . ProcessContext ( this . context_handle ) ;
IsProcessing = true ;
}
#endregion
#region public void Suspend
/// <summary>
/// Suspends processing of audio events.
/// </summary>
/// <remarks>
/// <para>
/// To avoid audio artifacts when calling this function, set audio gain to zero before
/// suspending an AudioContext.
/// </para>
/// <para>
/// In some implementations, it can be faster to suspend processing before changing
/// AudioContext state.
/// </para>
/// <para>
/// In some implementations this function may have no effect.
/// </para>
/// </remarks>
/// <exception cref="ObjectDisposedException">Occurs when this function is called after the AudioContext had been disposed.</exception>
/// <seealso cref="Process"/>
2009-03-25 22:53:12 +01:00
/// <seealso cref="IsProcessing"/>
2009-02-22 11:43:35 +01:00
/// <seealso cref="IsSynchronized"/>
public void Suspend ( )
{
2009-07-18 01:07:17 +02:00
if ( disposed )
throw new ObjectDisposedException ( this . GetType ( ) . FullName ) ;
2009-02-22 11:43:35 +01:00
Alc . SuspendContext ( this . context_handle ) ;
IsProcessing = false ;
}
#endregion
#region public bool SupportsExtension ( string extension )
/// <summary>
/// Checks whether the specified OpenAL extension is supported.
/// </summary>
/// <param name="extension">The name of the extension to check (e.g. "ALC_EXT_EFX").</param>
/// <returns>true if the extension is supported; false otherwise.</returns>
public bool SupportsExtension ( string extension )
{
2009-07-18 01:07:17 +02:00
if ( disposed )
throw new ObjectDisposedException ( this . GetType ( ) . FullName ) ;
2009-02-22 11:43:35 +01:00
return Alc . IsExtensionPresent ( this . Device , extension ) ;
}
#endregion
2009-07-18 01:07:17 +02:00
#region CurrentDevice
/// <summary>
/// Gets a System.String with the name of the device used in this context.
/// </summary>
public string CurrentDevice
{
get
{
if ( disposed )
throw new ObjectDisposedException ( this . GetType ( ) . FullName ) ;
return device_name ;
}
}
#endregion
#endregion - - - Public Members - - -
#region - - - Static Members - - -
2009-02-22 11:43:35 +01:00
#region public static AudioContext CurrentContext
/// <summary>
/// Gets the OpenTK.Audio.AudioContext which is current in the application.
/// </summary>
/// <remarks>
/// Only one AudioContext can be current in the application at any time,
/// <b>regardless of the number of threads</b>.
/// </remarks>
public static AudioContext CurrentContext
{
get
{
lock ( audio_context_lock )
{
if ( available_contexts . Count = = 0 )
return null ;
else
{
AudioContext context ;
AudioContext . available_contexts . TryGetValue (
( ContextHandle ) Alc . GetCurrentContext ( ) ,
out context ) ;
return context ;
}
}
}
}
#endregion
2009-07-18 01:00:22 +02:00
#region AvailableDevices
2009-07-18 01:07:17 +02:00
/// <summary>
/// Returns a list of strings containing all known playback devices.
/// </summary>
2009-07-16 14:49:24 +02:00
public static IList < string > AvailableDevices
{
get
{
return AudioDeviceEnumerator . AvailablePlaybackDevices ;
}
}
#endregion public static IList < string > AvailablePlaybackDevices
2009-02-22 11:43:35 +01:00
2009-07-18 01:00:22 +02:00
#region DefaultDevice
2009-07-18 01:07:17 +02:00
/// <summary>
/// Returns the name of the device that will be used as playback default.
/// </summary>
2009-07-18 01:00:22 +02:00
public static string DefaultDevice
2009-02-22 11:43:35 +01:00
{
get
{
2009-07-16 14:49:24 +02:00
return AudioDeviceEnumerator . DefaultPlaybackDevice ;
2009-02-22 11:43:35 +01:00
}
}
2009-07-18 01:00:22 +02:00
#endregion
2009-02-22 11:43:35 +01:00
2009-07-18 01:07:17 +02:00
#endregion
2009-02-22 11:43:35 +01:00
#region - - - IDisposable Members - - -
/// <summary>
/// Disposes of the AudioContext, cleaning up all resources consumed by it.
/// </summary>
public void Dispose ( )
{
this . Dispose ( true ) ;
GC . SuppressFinalize ( this ) ;
}
void Dispose ( bool manual )
{
if ( ! disposed )
{
if ( this . IsCurrent )
this . IsCurrent = false ;
if ( context_handle ! = ContextHandle . Zero )
{
available_contexts . Remove ( context_handle ) ;
Alc . DestroyContext ( context_handle ) ;
}
if ( device_handle ! = IntPtr . Zero )
Alc . CloseDevice ( device_handle ) ;
if ( manual )
{
}
disposed = true ;
}
}
2009-09-05 01:12:10 +02:00
/// <summary>
/// Finalizes this instance.
/// </summary>
2009-02-22 11:43:35 +01:00
~ AudioContext ( )
{
this . Dispose ( false ) ;
}
#endregion
#region - - - Overrides - - -
2009-09-05 01:12:10 +02:00
/// <summary>
/// Calculates the hash code for this instance.
/// </summary>
/// <returns></returns>
2009-02-22 11:43:35 +01:00
public override int GetHashCode ( )
{
return base . GetHashCode ( ) ;
}
2009-09-05 01:12:10 +02:00
/// <summary>
/// Compares this instance with another.
/// </summary>
/// <param name="obj">The instance to compare to.</param>
/// <returns>True, if obj refers to this instance; false otherwise.</returns>
2009-02-22 11:43:35 +01:00
public override bool Equals ( object obj )
{
return base . Equals ( obj ) ;
}
2009-09-05 01:12:10 +02:00
/// <summary>
/// Returns a <see cref="System.String"/> that desrcibes this instance.
/// </summary>
/// <returns>A <see cref="System.String"/> that desrcibes this instance.</returns>
2009-02-22 11:43:35 +01:00
public override string ToString ( )
{
return String . Format ( "{0} (handle: {1}, device: {2})" ,
this . device_name , this . context_handle , this . device_handle ) ;
}
#endregion
}
}