/// <summary> /// Sets up the hardware resources used by the controller. /// </summary> private OpenALSoundController() { #if WINDOWS // On Windows, set the DLL search path for correct native binaries NativeHelper.InitDllDirectory(); #endif if (!OpenSoundController()) { throw new NoAudioHardwareException("OpenAL device could not be initialized, see console output for details."); } if (Alc.IsExtensionPresent(_device, "ALC_EXT_CAPTURE")) { Microphone.PopulateCaptureDevices(); } // We have hardware here and it is ready allSourcesArray = new int[MAX_NUMBER_OF_SOURCES]; AL.GenSources(allSourcesArray); ALHelper.CheckError("Failed to generate sources."); Filter = 0; if (Efx.IsInitialized) { Filter = Efx.GenFilter(); } availableSourcesCollection = new List <int>(allSourcesArray); inUseSourcesCollection = new List <int>(); }
/// <summary> /// Sets up the hardware resources used by the controller. /// </summary> private OpenALSoundController() { if (AL.NativeLibrary == IntPtr.Zero) { throw new DllNotFoundException("Couldn't initialize OpenAL because the native binaries couldn't be found."); } if (!OpenSoundController()) { throw new NoAudioHardwareException("OpenAL device could not be initialized, see console output for details."); } if (Alc.IsExtensionPresent(_device, "ALC_EXT_CAPTURE")) { Microphone.PopulateCaptureDevices(); } // We have hardware here and it is ready allSourcesArray = new int[MAX_NUMBER_OF_SOURCES]; AL.GenSources(allSourcesArray); ALHelper.CheckError("Failed to generate sources."); Filter = 0; if (Efx.IsInitialized) { Filter = Efx.GenFilter(); } availableSourcesCollection = new List <int>(allSourcesArray); inUseSourcesCollection = new List <int>(); }
public static IEnumerable <string> GetDeviceNames() { if (!Alc.IsExtensionPresent(IntPtr.Zero, "ALC_ENUMERATION_EXT")) { return(Enumerable.Empty <string>()); } return(Alc.GetString(IntPtr.Zero, AlcGetStringList.AllDevicesSpecifier)); }
/// <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)); }
public static string[] AvailableDevices() { // Returns all devices under Windows Vista and newer if (Alc.IsExtensionPresent(IntPtr.Zero, "ALC_ENUMERATE_ALL_EXT")) { return(QueryDevices("ALC_ENUMERATE_ALL_EXT", AlcGetStringList.AllDevicesSpecifier)); } if (Alc.IsExtensionPresent(IntPtr.Zero, "ALC_ENUMERATION_EXT")) { return(QueryDevices("ALC_ENUMERATION_EXT", AlcGetStringList.DeviceSpecifier)); } return(new string[] { }); }
public AlcDiagnostic(IntPtr dev) { Trace.WriteLine("--- Alc related errors ---"); Alc.GetInteger(dev, AlcGetInteger.MajorVersion, 1, out MajorVersion); Alc.GetInteger(dev, AlcGetInteger.MinorVersion, 1, out MinorVersion); Alc.GetInteger(dev, AlcGetInteger.EfxMajorVersion, 1, out EfxMajorVersion); Alc.GetInteger(dev, AlcGetInteger.EfxMinorVersion, 1, out EfxMinorVersion); Alc.GetInteger(dev, AlcGetInteger.EfxMaxAuxiliarySends, 1, out EfxMaxAuxiliarySends); ExtensionString = Alc.GetString(dev, AlcGetString.Extensions); foreach (string s in Alc_Extension_C_Names) { Extensions.Add(s, Alc.IsExtensionPresent(dev, s)); } }
// 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; } } } }
private VoipCapture(string deviceName) : base(GameMain.Client?.ID ?? 0, true, false) { Disconnected = false; VoipConfig.SetupEncoding(); //set up capture device captureDevice = Alc.CaptureOpenDevice(deviceName, VoipConfig.FREQUENCY, Al.FormatMono16, VoipConfig.BUFFER_SIZE * 5); if (captureDevice == IntPtr.Zero) { DebugConsole.NewMessage("Alc.CaptureOpenDevice attempt 1 failed: error code " + Alc.GetError(IntPtr.Zero).ToString(), Color.Orange); //attempt using a smaller buffer size captureDevice = Alc.CaptureOpenDevice(deviceName, VoipConfig.FREQUENCY, Al.FormatMono16, VoipConfig.BUFFER_SIZE * 2); } if (captureDevice == IntPtr.Zero) { DebugConsole.NewMessage("Alc.CaptureOpenDevice attempt 2 failed: error code " + Alc.GetError(IntPtr.Zero).ToString(), Color.Orange); //attempt using the default device captureDevice = Alc.CaptureOpenDevice("", VoipConfig.FREQUENCY, Al.FormatMono16, VoipConfig.BUFFER_SIZE * 2); } if (captureDevice == IntPtr.Zero) { string errorCode = Alc.GetError(IntPtr.Zero).ToString(); if (!GUIMessageBox.MessageBoxes.Any(mb => mb.UserData as string == "capturedevicenotfound")) { GUI.SettingsMenuOpen = false; new GUIMessageBox(TextManager.Get("Error"), (TextManager.Get("VoipCaptureDeviceNotFound", returnNull: true) ?? "Could not start voice capture, suitable capture device not found.") + " (" + errorCode + ")") { UserData = "capturedevicenotfound" }; } GameAnalyticsManager.AddErrorEventOnce("Alc.CaptureDeviceOpenFailed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Alc.CaptureDeviceOpen(" + deviceName + ") failed. Error code: " + errorCode); GameMain.Config.VoiceSetting = GameSettings.VoiceMode.Disabled; Instance?.Dispose(); Instance = null; return; } int alError = Al.GetError(); int alcError = Alc.GetError(captureDevice); if (alcError != Alc.NoError) { throw new Exception("Failed to open capture device: " + alcError.ToString() + " (ALC)"); } if (alError != Al.NoError) { throw new Exception("Failed to open capture device: " + alError.ToString() + " (AL)"); } CanDetectDisconnect = Alc.IsExtensionPresent(captureDevice, "ALC_EXT_disconnect"); alcError = Alc.GetError(captureDevice); if (alcError != Alc.NoError) { throw new Exception("Error determining if disconnect can be detected: " + alcError.ToString()); } Alc.CaptureStart(captureDevice); alcError = Alc.GetError(captureDevice); if (alcError != Alc.NoError) { throw new Exception("Failed to start capturing: " + alcError.ToString()); } capturing = true; captureThread = new Thread(UpdateCapture) { IsBackground = true, Name = "VoipCapture" }; captureThread.Start(); }
public bool InitializeAlcDevice(string deviceName) { ReleaseResources(true); DebugConsole.NewMessage($"Attempting to open ALC device \"{deviceName}\""); alcDevice = IntPtr.Zero; int alcError = Al.NoError; for (int i = 0; i < 3; i++) { alcDevice = Alc.OpenDevice(deviceName); if (alcDevice == IntPtr.Zero) { alcError = Alc.GetError(IntPtr.Zero); DebugConsole.NewMessage($"ALC device initialization attempt #{i + 1} failed: device is null (error code {Alc.GetErrorString(alcError)})"); if (!string.IsNullOrEmpty(deviceName)) { deviceName = null; DebugConsole.NewMessage($"Switching to default device..."); } } else { alcError = Alc.GetError(alcDevice); if (alcError != Alc.NoError) { DebugConsole.NewMessage($"ALC device initialization attempt #{i + 1} failed: error code {Alc.GetErrorString(alcError)}"); bool closed = Alc.CloseDevice(alcDevice); if (!closed) { DebugConsole.NewMessage($"Failed to close ALC device"); } alcDevice = IntPtr.Zero; } else { break; } } } if (alcDevice == IntPtr.Zero) { DebugConsole.ThrowError("ALC device creation failed too many times!"); Disabled = true; return(false); } CanDetectDisconnect = Alc.IsExtensionPresent(alcDevice, "ALC_EXT_disconnect"); alcError = Alc.GetError(alcDevice); if (alcError != Alc.NoError) { DebugConsole.ThrowError("Error determining if disconnect can be detected: " + alcError.ToString() + ". Disabling audio playback..."); Disabled = true; return(false); } Disconnected = false; int[] alcContextAttrs = new int[] { }; alcContext = Alc.CreateContext(alcDevice, alcContextAttrs); if (alcContext == null) { DebugConsole.ThrowError("Failed to create an ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + "). Disabling audio playback..."); Disabled = true; return(false); } if (!Alc.MakeContextCurrent(alcContext)) { DebugConsole.ThrowError("Failed to assign the current ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + "). Disabling audio playback..."); Disabled = true; return(false); } alcError = Alc.GetError(alcDevice); if (alcError != Alc.NoError) { DebugConsole.ThrowError("Error after assigning ALC context: " + Alc.GetErrorString(alcError) + ". Disabling audio playback..."); Disabled = true; return(false); } Al.DistanceModel(Al.LinearDistanceClamped); int alError = Al.GetError(); if (alError != Al.NoError) { DebugConsole.ThrowError("Error setting distance model: " + Al.GetErrorString(alError) + ". Disabling audio playback..."); Disabled = true; return(false); } sourcePools[(int)SourcePoolIndex.Default] = new SoundSourcePool(SOURCE_COUNT); sourcePools[(int)SourcePoolIndex.Voice] = new SoundSourcePool(16); ReloadSounds(); Disabled = false; return(true); }
/// <summary>Get whether the extension with the given name is present.</summary> /// <param name="extensionName">The name of the extension to test.</param> /// <returns>Wehther the extension exists.</returns> public bool IsExtensionPresent(string extensionName) { return(Alc.IsExtensionPresent(Handle, extensionName)); }
public SoundManager() { loadedSounds = new List <Sound>(); playingChannels = new SoundChannel[SOURCE_COUNT]; streamingThread = null; categoryModifiers = null; alcDevice = Alc.OpenDevice(null); if (alcDevice == null) { throw new Exception("Failed to open an ALC device!"); } AlcError alcError = Alc.GetError(alcDevice); if (alcError != AlcError.NoError) { //The audio device probably wasn't ready, this happens quite often //Just wait a while and try again Thread.Sleep(100); alcDevice = Alc.OpenDevice(null); alcError = Alc.GetError(alcDevice); if (alcError != AlcError.NoError) { throw new Exception("Error initializing ALC device: " + alcError.ToString()); } } int[] alcContextAttrs = new int[] { }; alcContext = Alc.CreateContext(alcDevice, alcContextAttrs); if (alcContext == null) { throw new Exception("Failed to create an ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + ")"); } if (!Alc.MakeContextCurrent(alcContext)) { throw new Exception("Failed to assign the current ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + ")"); } alcError = Alc.GetError(alcDevice); if (alcError != AlcError.NoError) { throw new Exception("Error after assigning ALC context: " + alcError.ToString()); } ALError alError = ALError.NoError; alSources = new uint[SOURCE_COUNT]; for (int i = 0; i < SOURCE_COUNT; i++) { AL.GenSource(out alSources[i]); alError = AL.GetError(); if (alError != ALError.NoError) { throw new Exception("Error generating alSource[" + i.ToString() + "]: " + AL.GetErrorString(alError)); } if (!AL.IsSource(alSources[i])) { throw new Exception("Generated alSource[" + i.ToString() + "] is invalid!"); } AL.SourceStop(alSources[i]); alError = AL.GetError(); if (alError != ALError.NoError) { throw new Exception("Error stopping newly generated alSource[" + i.ToString() + "]: " + AL.GetErrorString(alError)); } AL.Source(alSources[i], ALSourcef.MinGain, 0.0f); alError = AL.GetError(); if (alError != ALError.NoError) { throw new Exception("Error setting min gain: " + AL.GetErrorString(alError)); } AL.Source(alSources[i], ALSourcef.MaxGain, 1.0f); alError = AL.GetError(); if (alError != ALError.NoError) { throw new Exception("Error setting max gain: " + AL.GetErrorString(alError)); } AL.Source(alSources[i], ALSourcef.RolloffFactor, 1.0f); alError = AL.GetError(); if (alError != ALError.NoError) { throw new Exception("Error setting rolloff factor: " + AL.GetErrorString(alError)); } } AL.DistanceModel(ALDistanceModel.LinearDistanceClamped); alError = AL.GetError(); if (alError != ALError.NoError) { throw new Exception("Error setting distance model: " + AL.GetErrorString(alError)); } if (Alc.IsExtensionPresent(IntPtr.Zero, "ALC_EXT_CAPTURE")) { alcCaptureDeviceNames = new List <string>(Alc.GetString(IntPtr.Zero, AlcGetStringList.CaptureDeviceSpecifier)); } else { alcCaptureDeviceNames = null; } listenerOrientation = new float[6]; ListenerPosition = Vector3.Zero; ListenerTargetVector = new Vector3(0.0f, 0.0f, 1.0f); ListenerUpVector = new Vector3(0.0f, -1.0f, 0.0f); }
/// \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> private 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 = Alc.OpenDevice(device); // try to open device by name } if (Device == IntPtr.Zero) { device_name = "IntPtr.Zero (null string)"; Device = Alc.OpenDevice(null); // try to open unnamed default device } if (Device == IntPtr.Zero) { device_name = AudioContext.DefaultDevice; Device = Alc.OpenDevice(AudioContext.DefaultDevice); // try to open named default device } if (Device == 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, "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, AlcGetInteger.EfxMaxAuxiliarySends, 1, out num_slots); break; } attributes.Add((int)AlcContextAttributes.EfxMaxAuxiliarySends); attributes.Add(num_slots); } attributes.Add(0); context_handle = Alc.CreateContext(Device, attributes.ToArray()); if (context_handle == ContextHandle.Zero) { Alc.CloseDevice(Device); 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, AlcGetString.DeviceSpecifier); lock (audio_context_lock) { available_contexts.Add(this.context_handle, this); context_exists = true; } }