#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. // #endregion using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using OpenTK.Audio.OpenAL; namespace OpenTK.Audio { internal static class AudioDeviceEnumerator { #region All device strings private static readonly List available_playback_devices = new List(); private static readonly List available_recording_devices = new List(); internal static IList AvailablePlaybackDevices { get { return available_playback_devices.AsReadOnly(); } } internal static IList AvailableRecordingDevices { get { return available_recording_devices.AsReadOnly(); } } #endregion All device strings #region Default device strings private static string default_playback_device; internal static string DefaultPlaybackDevice { get { return default_playback_device; } } private static string default_recording_device; internal static string DefaultRecordingDevice { get { return default_recording_device; } } #endregion Default device strings #region Is OpenAL supported? private static bool openal_supported = true; internal static bool IsOpenALSupported { get { return openal_supported; } } #endregion Is OpenAL supported? #region Alc Version number internal enum AlcVersion { Alc1_0, Alc1_1 } private static AlcVersion version; internal static AlcVersion Version { get { return version; } } #endregion Alc Version number #region Constructors // 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(); // 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); } } #endregion } }