/// \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; } } } }