/// <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) { if (disposed) { throw new ObjectDisposedException(this.GetType().FullName); } return(Alc.IsExtensionPresent(this.Device, extension)); }
static AudioDeviceEnumerator() { IntPtr device = IntPtr.Zero; ContextHandle context = ContextHandle.Zero; try { device = Alc.OpenDevice((string)null); int num1 = (int)Alc.GetError(device); context = Alc.CreateContext(device, (int[])null); int num2 = (int)Alc.GetError(device); bool flag = Alc.MakeContextCurrent(context); AlcError error1 = Alc.GetError(device); if (!flag) { throw new AudioContextException("Failed to create dummy Context. Device (" + device.ToString() + ") Context (" + context.Handle.ToString() + ") MakeContextCurrent " + (flag ? "succeeded" : "failed") + ", Alc Error (" + ((object)error1).ToString() + ") " + Alc.GetString(IntPtr.Zero, (AlcGetString)error1)); } else { if (Alc.IsExtensionPresent(IntPtr.Zero, "ALC_ENUMERATION_EXT")) { AudioDeviceEnumerator.version = AudioDeviceEnumerator.AlcVersion.Alc1_1; if (Alc.IsExtensionPresent(IntPtr.Zero, "ALC_ENUMERATE_ALL_EXT")) { AudioDeviceEnumerator.available_playback_devices.AddRange((IEnumerable <string>)Alc.GetString(IntPtr.Zero, AlcGetStringList.AllDevicesSpecifier)); AudioDeviceEnumerator.default_playback_device = Alc.GetString(IntPtr.Zero, AlcGetString.DefaultAllDevicesSpecifier); } else { AudioDeviceEnumerator.available_playback_devices.AddRange((IEnumerable <string>)Alc.GetString(IntPtr.Zero, AlcGetStringList.DeviceSpecifier)); AudioDeviceEnumerator.default_playback_device = Alc.GetString(IntPtr.Zero, AlcGetString.DefaultDeviceSpecifier); } } else { AudioDeviceEnumerator.version = AudioDeviceEnumerator.AlcVersion.Alc1_0; } AlcError error2 = Alc.GetError(device); if (error2 != AlcError.NoError) { throw new AudioContextException("Alc Error occured when querying available playback devices. " + ((object)error2).ToString()); } if (AudioDeviceEnumerator.version == AudioDeviceEnumerator.AlcVersion.Alc1_1 && Alc.IsExtensionPresent(IntPtr.Zero, "ALC_EXT_CAPTURE")) { AudioDeviceEnumerator.available_recording_devices.AddRange((IEnumerable <string>)Alc.GetString(IntPtr.Zero, AlcGetStringList.CaptureDeviceSpecifier)); AudioDeviceEnumerator.default_recording_device = Alc.GetString(IntPtr.Zero, AlcGetString.CaptureDefaultDeviceSpecifier); } AlcError error3 = Alc.GetError(device); if (error3 != AlcError.NoError) { throw new AudioContextException("Alc Error occured when querying available recording devices. " + ((object)error3).ToString()); } } } catch (DllNotFoundException ex) { Trace.WriteLine(ex.ToString()); AudioDeviceEnumerator.openal_supported = false; } catch (AudioContextException ex) { Trace.WriteLine(ex.ToString()); AudioDeviceEnumerator.lastError = ex.ToString(); AudioDeviceEnumerator.openal_supported = false; } finally { Alc.MakeContextCurrent(ContextHandle.Zero); if (context != ContextHandle.Zero && context.Handle != IntPtr.Zero) { Alc.DestroyContext(context); } if (device != IntPtr.Zero) { Alc.CloseDevice(device); } } }
// Loads all available audio devices into the available_*_devices lists. static AudioDeviceEnumerator() { IntPtr dummy_device = IntPtr.Zero; ContextHandle dummy_context = ContextHandle.Zero; try { Debug.WriteLine("Enumerating audio devices."); Debug.Indent(); // need a dummy context for correct results dummy_device = Alc.OpenDevice(null); dummy_context = Alc.CreateContext(dummy_device, (int[])null); bool dummy_success = Alc.MakeContextCurrent(dummy_context); AlcError dummy_error = Alc.GetError(dummy_device); if (!dummy_success || dummy_error != AlcError.NoError) { throw new AudioContextException("Failed to create dummy Context. Device (" + dummy_device.ToString() + ") Context (" + dummy_context.Handle.ToString() + ") MakeContextCurrent " + (dummy_success ? "succeeded" : "failed") + ", Alc Error (" + dummy_error.ToString() + ") " + Alc.GetString(IntPtr.Zero, (AlcGetString)dummy_error)); } // Get a list of all known playback devices, using best extension available if (Alc.IsExtensionPresent(IntPtr.Zero, "ALC_ENUMERATION_EXT")) { version = AlcVersion.Alc1_1; if (Alc.IsExtensionPresent(IntPtr.Zero, "ALC_ENUMERATE_ALL_EXT")) { available_playback_devices.AddRange(Alc.GetString(IntPtr.Zero, AlcGetStringList.AllDevicesSpecifier)); default_playback_device = Alc.GetString(IntPtr.Zero, AlcGetString.DefaultAllDevicesSpecifier); } else { available_playback_devices.AddRange(Alc.GetString(IntPtr.Zero, AlcGetStringList.DeviceSpecifier)); default_playback_device = Alc.GetString(IntPtr.Zero, AlcGetString.DefaultDeviceSpecifier); } } else { version = AlcVersion.Alc1_0; Debug.Print("Device enumeration extension not available. Failed to enumerate playback devices."); } AlcError playback_err = Alc.GetError(dummy_device); if (playback_err != AlcError.NoError) { throw new AudioContextException("Alc Error occured when querying available playback devices. " + playback_err.ToString()); } // Get a list of all known recording devices, at least ALC_ENUMERATION_EXT is needed too if (version == AlcVersion.Alc1_1 && Alc.IsExtensionPresent(IntPtr.Zero, "ALC_EXT_CAPTURE")) { available_recording_devices.AddRange(Alc.GetString(IntPtr.Zero, AlcGetStringList.CaptureDeviceSpecifier)); default_recording_device = Alc.GetString(IntPtr.Zero, AlcGetString.CaptureDefaultDeviceSpecifier); } else { Debug.Print("Capture extension not available. Failed to enumerate recording devices."); } AlcError record_err = Alc.GetError(dummy_device); if (record_err != AlcError.NoError) { throw new AudioContextException("Alc Error occured when querying available recording devices. " + record_err.ToString()); } #if DEBUG Debug.WriteLine("Found playback devices:"); foreach (string s in available_playback_devices) { Debug.WriteLine(s); } Debug.WriteLine("Default playback device: " + default_playback_device); Debug.WriteLine("Found recording devices:"); foreach (string s in available_recording_devices) { Debug.WriteLine(s); } Debug.WriteLine("Default recording device: " + default_recording_device); #endif } catch (DllNotFoundException e) { Trace.WriteLine(e.ToString()); openal_supported = false; } catch (AudioContextException ace) { Trace.WriteLine(ace.ToString()); openal_supported = false; } finally { Debug.Unindent(); if (openal_supported) { try { // clean up the dummy context Alc.MakeContextCurrent(ContextHandle.Zero); if (dummy_context != ContextHandle.Zero && dummy_context.Handle != IntPtr.Zero) { Alc.DestroyContext(dummy_context); } if (dummy_device != IntPtr.Zero) { Alc.CloseDevice(dummy_device); } } catch { openal_supported = false; } } } }
/// \internal /// <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> /// <param name="enableEfx">Indicates whether the EFX extension should be initialized, if present.</param> /// <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> /// <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> /// <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> void CreateContext(string device, int freq, int refresh, bool sync, bool enableEfx, MaxAuxiliarySends efxAuxiliarySends) { if (!AudioDeviceEnumerator.IsOpenALSupported) { throw new DllNotFoundException("openal32.dll"); } if (AudioDeviceEnumerator.Version == AudioDeviceEnumerator.AlcVersion.Alc1_1 && AudioDeviceEnumerator.AvailablePlaybackDevices.Count == 0) // Alc 1.0 does not support device enumeration. { 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."); } if (!String.IsNullOrEmpty(device)) { device_name = device; device_handle = Alc.OpenDevice(device); // try to open device by name } if (device_handle == IntPtr.Zero) { device_name = "IntPtr.Zero (null string)"; device_handle = Alc.OpenDevice(null); // try to open unnamed default device } if (device_handle == IntPtr.Zero) { device_name = AudioContext.DefaultDevice; device_handle = Alc.OpenDevice(AudioContext.DefaultDevice); // try to open named default device } if (device_handle == IntPtr.Zero) { device_name = "None"; throw new AudioDeviceException(String.Format("Audio device '{0}' does not exist or is tied up by another application.", String.IsNullOrEmpty(device) ? "default" : device)); } CheckErrors(); // Build the attribute list List <int> attributes = new List <int>(); if (freq != 0) { attributes.Add((int)AlcContextAttributes.Frequency); attributes.Add(freq); } if (refresh != 0) { attributes.Add((int)AlcContextAttributes.Refresh); attributes.Add(refresh); } attributes.Add((int)AlcContextAttributes.Sync); attributes.Add(sync ? 1 : 0); if (enableEfx && Alc.IsExtensionPresent(device_handle, "ALC_EXT_EFX")) { int num_slots; 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; } attributes.Add((int)AlcContextAttributes.EfxMaxAuxiliarySends); attributes.Add(num_slots); } attributes.Add(0); 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."); } CheckErrors(); // 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. if (AudioDeviceEnumerator.AvailablePlaybackDevices.Count > 0) { MakeCurrent(); } CheckErrors(); device_name = Alc.GetString(device_handle, AlcGetString.DeviceSpecifier); lock (audio_context_lock) { available_contexts.Add(this.context_handle, this); context_exists = true; } }
private void CreateContext(string device, int freq, int refresh, bool sync, bool enableEfx, AudioContext.MaxAuxiliarySends efxAuxiliarySends) { if (!AudioDeviceEnumerator.IsOpenALSupported) { throw new DllNotFoundException("soft_oal.dll"); } if (AudioDeviceEnumerator.Version == AudioDeviceEnumerator.AlcVersion.Alc1_1 && AudioDeviceEnumerator.AvailablePlaybackDevices.Count == 0) { throw new NotSupportedException("No audio hardware is available."); } if (this.context_exists) { throw new NotSupportedException("Multiple AudioContexts are not supported."); } if (freq < 0) { throw new ArgumentOutOfRangeException("freq", (object)freq, "Should be greater than zero."); } if (refresh < 0) { throw new ArgumentOutOfRangeException("refresh", (object)refresh, "Should be greater than zero."); } if (!string.IsNullOrEmpty(device)) { this.device_name = device; this.device_handle = Alc.OpenDevice(device); } if (this.device_handle == IntPtr.Zero) { this.device_name = "IntPtr.Zero (null string)"; this.device_handle = Alc.OpenDevice((string)null); } if (this.device_handle == IntPtr.Zero) { this.device_name = AudioContext.DefaultDevice; this.device_handle = Alc.OpenDevice(AudioContext.DefaultDevice); } if (this.device_handle == IntPtr.Zero) { this.device_name = "None"; throw new AudioDeviceException(string.Format("Audio device '{0}' does not exist or is tied up by another application.", string.IsNullOrEmpty(device) ? (object)"default" : (object)device)); } else { this.CheckErrors(); List <int> list = new List <int>(); if (freq != 0) { list.Add(4103); list.Add(freq); } if (refresh != 0) { list.Add(4104); list.Add(refresh); } list.Add(4105); list.Add(sync ? 1 : 0); if (enableEfx && Alc.IsExtensionPresent(this.device_handle, "ALC_EXT_EFX")) { int data; switch (efxAuxiliarySends) { case AudioContext.MaxAuxiliarySends.One: case AudioContext.MaxAuxiliarySends.Two: case AudioContext.MaxAuxiliarySends.Three: case AudioContext.MaxAuxiliarySends.Four: data = (int)efxAuxiliarySends; break; default: Alc.GetInteger(this.device_handle, AlcGetInteger.EfxMaxAuxiliarySends, 1, out data); break; } list.Add(131075); list.Add(data); } list.Add(0); this.context_handle = Alc.CreateContext(this.device_handle, list.ToArray()); if (this.context_handle == ContextHandle.Zero) { Alc.CloseDevice(this.device_handle); throw new AudioContextException("The audio context could not be created with the specified parameters."); } else { this.CheckErrors(); if (AudioDeviceEnumerator.AvailablePlaybackDevices.Count > 0) { this.MakeCurrent(); } this.CheckErrors(); this.device_name = Alc.GetString(this.device_handle, AlcGetString.DeviceSpecifier); lock (AudioContext.audio_context_lock) { AudioContext.available_contexts.Add(this.context_handle, this); this.context_exists = true; } } } }