/* * AL.GetError (); * string deviceName = Alc.GetString (IntPtr.Zero, AlcGetString.CaptureDefaultDeviceSpecifier); * Console.WriteLine ("device: " + deviceName); * IntPtr device = Alc.CaptureOpenDevice (deviceName, SRATE, ALFormat.Mono16, SSIZE); * if (Error (device)) * return; * Console.WriteLine ("c"); * Alc.CaptureStart (device); * if (Error (device)) * return; * * while (true) { * byte[] buffer = new byte[SRATE]; * int sample = 0; * Alc.GetInteger (device, AlcGetInteger.CaptureSamples, sizeof (int), out sample); * if (Error (device)) * return; * Console.WriteLine ("sample: " + sample.ToString ()); * Alc.CaptureSamples (device, buffer, sample); * if (Error (device)) * return; * SDL2.SDL.SDL_Delay (100); * } * Alc.CaptureStop (device); * Alc.CaptureCloseDevice (device); */ /* * ALCdevice *device = alcCaptureOpenDevice (NULL, SRATE, AL_FORMAT_STEREO16, SSIZE); * if (alGetError () != AL_NO_ERROR) { * return 0; * } * alcCaptureStart (device); * * while (true) { * alcGetIntegerv (device, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof (ALint), &sample); * alcCaptureSamples (device, (ALCvoid *)buffer, sample); * * // ... do something with the buffer * } * * alcCaptureStop (device); * alcCaptureCloseDevice (device); * * return 0; */ private static bool Error(IntPtr device) { AlcError err = Alc.GetError(device); if (err != AlcError.NoError) { Console.WriteLine("Error: " + err.ToString()); return(true); } else { return(false); } }
private VoipCapture(string deviceName) : base(GameMain.Client?.ID ?? 0, true, false) { VoipConfig.SetupEncoding(); //set up capture device captureDevice = Alc.CaptureOpenDevice(deviceName, VoipConfig.FREQUENCY, ALFormat.Mono16, VoipConfig.BUFFER_SIZE * 5); if (captureDevice == IntPtr.Zero) { if (!GUIMessageBox.MessageBoxes.Any(mb => mb.UserData as string == "capturedevicenotfound")) { GUI.SettingsMenuOpen = false; new GUIMessageBox(TextManager.Get("Error"), TextManager.Get("VoipCaptureDeviceNotFound")) { UserData = "capturedevicenotfound" }; } GameMain.Config.VoiceSetting = GameSettings.VoiceMode.Disabled; Instance?.Dispose(); Instance = null; return; } ALError alError = AL.GetError(); AlcError alcError = Alc.GetError(captureDevice); if (alcError != AlcError.NoError) { throw new Exception("Failed to open capture device: " + alcError.ToString() + " (ALC)"); } if (alError != ALError.NoError) { throw new Exception("Failed to open capture device: " + alError.ToString() + " (AL)"); } Alc.CaptureStart(captureDevice); alcError = Alc.GetError(captureDevice); if (alcError != AlcError.NoError) { throw new Exception("Failed to start capturing: " + alcError.ToString()); } capturing = true; captureThread = new Thread(UpdateCapture) { IsBackground = true, Name = "VoipCapture" }; captureThread.Start(); }
internal static void CheckError(string message = "", params object[] args) { AlcError error; if ((error = Alc.GetError()) != AlcError.NoError) { if (args != null && args.Length > 0) { message = String.Format(message, args); } throw new InvalidOperationException(message + " (Reason: " + error.ToString() + ")"); } }
private void FillBuffer() { if (overrideSound != null) { int totalSampleCount = 0; while (totalSampleCount < VoipConfig.BUFFER_SIZE) { int sampleCount = overrideSound.FillStreamBuffer(overridePos, overrideBuf); overridePos += sampleCount * 2; Array.Copy(overrideBuf, 0, uncompressedBuffer, totalSampleCount, sampleCount); totalSampleCount += sampleCount; if (sampleCount == 0) { overridePos = 0; } } int sleepMs = VoipConfig.BUFFER_SIZE * 800 / VoipConfig.FREQUENCY; Thread.Sleep(sleepMs - 1); } else { int sampleCount = 0; while (sampleCount < VoipConfig.BUFFER_SIZE) { Alc.GetInteger(captureDevice, Alc.EnumCaptureSamples, out sampleCount); int alcError = Alc.GetError(captureDevice); if (alcError != Alc.NoError) { throw new Exception("Failed to determine sample count: " + alcError.ToString()); } if (sampleCount < VoipConfig.BUFFER_SIZE) { int sleepMs = (VoipConfig.BUFFER_SIZE - sampleCount) * 800 / VoipConfig.FREQUENCY; if (sleepMs >= 1) { Thread.Sleep(sleepMs); } } if (!capturing) { return; } } Alc.CaptureSamples(captureDevice, nativeBuffer, VoipConfig.BUFFER_SIZE); Marshal.Copy(nativeBuffer, uncompressedBuffer, 0, uncompressedBuffer.Length); } }
internal void CheckALCError(string operation) { AlcError error = Alc.GetError(_captureDevice); if (error == AlcError.NoError) { return; } string errorFmt = "OpenAL Error: {0}"; throw new NoMicrophoneConnectedException(String.Format("{0} - {1}", operation, string.Format(errorFmt, error))); }
public void CheckALError(string operation) { _lastOpenALError = Alc.GetError(_device); if (_lastOpenALError == AlcError.NoError) { return; } string errorFmt = "OpenAL Error: {0}"; Console.WriteLine(String.Format("{0} - {1}", operation, //string.Format (errorFmt, Alc.GetString (_device, _lastOpenALError)))); string.Format(errorFmt, _lastOpenALError))); }
/// <summary> /// Checks the error state of the OpenAL driver. If a value that is not AlcError.NoError /// is returned, then the operation message and the error code is thrown in an Exception. /// </summary> /// <param name="operation">the operation message</param> public void CheckALError(string operation) { _lastOpenALError = Alc.GetError(_device); if (_lastOpenALError == AlcError.NoError) { return; } CleanUpOpenAL(); string errorFmt = "OpenAL Error: {0}"; throw new NoAudioHardwareException(String.Format("{0} - {1}", operation, //string.Format (errorFmt, Alc.GetString (_device, _lastOpenALError)))); string.Format(errorFmt, _lastOpenALError))); }
public static void checkForErrors() { { IntPtr device = Alc.GetContextsDevice(Alc.GetCurrentContext()); AlcError error = Alc.GetError(device); if (error != AlcError.NoError) { Trace.WriteLine("ALC ERROR: (" + error + ") " + Alc.GetString(device, (AlcGetString)error)); } } { ALError error = AL.GetError(); if (error != ALError.NoError) { Trace.WriteLine("AL ERROR: (" + error + ") " + AL.GetErrorString(error)); } } }
public void Dispose() { AlcError err = Alc.GetError(Device); switch (err) { case AlcError.OutOfMemory: throw new OutOfMemoryException(String.Format(ErrorString, Device, err)); case AlcError.InvalidValue: throw new AudioValueException(String.Format(ErrorString, Device, err)); case AlcError.InvalidDevice: throw new AudioDeviceException(String.Format(ErrorString, Device, err)); case AlcError.InvalidContext: throw new AudioContextException(String.Format(ErrorString, Device, err)); case AlcError.NoError: default: // everything went fine, do nothing break; } }
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); }
private void UpdateCapture() { Array.Copy(uncompressedBuffer, 0, prevUncompressedBuffer, 0, VoipConfig.BUFFER_SIZE); Array.Clear(uncompressedBuffer, 0, VoipConfig.BUFFER_SIZE); while (capturing && !Disconnected) { int alcError; if (CanDetectDisconnect) { Alc.GetInteger(captureDevice, Alc.EnumConnected, out int isConnected); alcError = Alc.GetError(captureDevice); if (alcError != Alc.NoError) { throw new Exception("Failed to determine if capture device is connected: " + alcError.ToString()); } if (isConnected == 0) { DebugConsole.ThrowError("Capture device has been disconnected. You can select another available device in the settings."); Disconnected = true; break; } } Alc.GetInteger(captureDevice, Alc.EnumCaptureSamples, out int sampleCount); alcError = Alc.GetError(captureDevice); if (alcError != Alc.NoError) { throw new Exception("Failed to determine sample count: " + alcError.ToString()); } if (sampleCount < VoipConfig.BUFFER_SIZE) { int sleepMs = (VoipConfig.BUFFER_SIZE - sampleCount) * 800 / VoipConfig.FREQUENCY; if (sleepMs < 5) { sleepMs = 5; } Thread.Sleep(sleepMs); continue; } GCHandle handle = GCHandle.Alloc(uncompressedBuffer, GCHandleType.Pinned); try { Alc.CaptureSamples(captureDevice, handle.AddrOfPinnedObject(), VoipConfig.BUFFER_SIZE); } finally { handle.Free(); } alcError = Alc.GetError(captureDevice); if (alcError != Alc.NoError) { throw new Exception("Failed to capture samples: " + alcError.ToString()); } double maxAmplitude = 0.0f; for (int i = 0; i < VoipConfig.BUFFER_SIZE; i++) { uncompressedBuffer[i] = (short)MathHelper.Clamp((uncompressedBuffer[i] * Gain), -short.MaxValue, short.MaxValue); double sampleVal = uncompressedBuffer[i] / (double)short.MaxValue; maxAmplitude = Math.Max(maxAmplitude, Math.Abs(sampleVal)); } double dB = Math.Min(20 * Math.Log10(maxAmplitude), 0.0); LastdB = dB; LastAmplitude = maxAmplitude; bool allowEnqueue = false; if (GameMain.WindowActive) { ForceLocal = captureTimer > 0 ? ForceLocal : false; bool pttDown = false; if ((PlayerInput.KeyDown(InputType.Voice) || PlayerInput.KeyDown(InputType.LocalVoice)) && GUI.KeyboardDispatcher.Subscriber == null) { pttDown = true; if (PlayerInput.KeyDown(InputType.LocalVoice)) { ForceLocal = true; } else { ForceLocal = false; } } if (GameMain.Config.VoiceSetting == GameSettings.VoiceMode.Activity) { if (dB > GameMain.Config.NoiseGateThreshold) { allowEnqueue = true; } } else if (GameMain.Config.VoiceSetting == GameSettings.VoiceMode.PushToTalk) { if (pttDown) { allowEnqueue = true; } } } if (allowEnqueue || captureTimer > 0) { LastEnqueueAudio = DateTime.Now; if (GameMain.Client?.Character != null) { var messageType = !ForceLocal && ChatMessage.CanUseRadio(GameMain.Client.Character, out _) ? ChatMessageType.Radio : ChatMessageType.Default; GameMain.Client.Character.ShowSpeechBubble(1.25f, ChatMessage.MessageColor[(int)messageType]); } //encode audio and enqueue it lock (buffers) { if (!prevCaptured) //enqueue the previous buffer if not sent to avoid cutoff { int compressedCountPrev = VoipConfig.Encoder.Encode(prevUncompressedBuffer, 0, VoipConfig.BUFFER_SIZE, BufferToQueue, 0, VoipConfig.MAX_COMPRESSED_SIZE); EnqueueBuffer(compressedCountPrev); } int compressedCount = VoipConfig.Encoder.Encode(uncompressedBuffer, 0, VoipConfig.BUFFER_SIZE, BufferToQueue, 0, VoipConfig.MAX_COMPRESSED_SIZE); EnqueueBuffer(compressedCount); } captureTimer -= (VoipConfig.BUFFER_SIZE * 1000) / VoipConfig.FREQUENCY; if (allowEnqueue) { captureTimer = GameMain.Config.VoiceChatCutoffPrevention; } prevCaptured = true; } else { captureTimer = 0; prevCaptured = false; //enqueue silence lock (buffers) { EnqueueBuffer(0); } } Thread.Sleep(10); } }
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); }
public void Dispose() { lock (playingChannels) { for (int i = 0; i < SOURCE_COUNT; i++) { if (playingChannels[i] != null) { playingChannels[i].Dispose(); } } } if (streamingThread != null && streamingThread.ThreadState == ThreadState.Running) { streamingThread.Join(); } for (int i = loadedSounds.Count - 1; i >= 0; i--) { loadedSounds[i].Dispose(); } for (int i = 0; i < SOURCE_COUNT; i++) { AL.DeleteSource(ref alSources[i]); ALError alError = AL.GetError(); if (alError != ALError.NoError) { throw new Exception("Failed to delete alSources[" + i.ToString() + "]: " + AL.GetErrorString(alError)); } } if (!Alc.MakeContextCurrent(OpenTK.ContextHandle.Zero)) { throw new Exception("Failed to detach the current ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + ")"); } Alc.DestroyContext(alcContext); if (!Alc.CloseDevice(alcDevice)) { throw new Exception("Failed to close ALC device!"); } }
public SoundManager() { loadedSounds = new List <Sound>(); streamingThread = null; categoryModifiers = null; int alcError = Alc.NoError; string deviceName = Alc.GetString(IntPtr.Zero, Alc.DefaultDeviceSpecifier); DebugConsole.NewMessage($"Attempting to open ALC device \"{deviceName}\""); alcDevice = IntPtr.Zero; for (int i = 0; i < 3; i++) { alcDevice = Alc.OpenDevice(deviceName); if (alcDevice == IntPtr.Zero) { DebugConsole.NewMessage($"ALC device initialization attempt #{i + 1} failed: device is null"); } 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; } } } if (alcDevice == IntPtr.Zero) { DebugConsole.ThrowError("ALC device creation failed too many times!"); Disabled = true; return; } 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; } 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; } alcError = Alc.GetError(alcDevice); if (alcError != Alc.NoError) { DebugConsole.ThrowError("Error after assigning ALC context: " + Alc.GetErrorString(alcError) + ". Disabling audio playback..."); Disabled = true; return; } sourcePools = new SoundSourcePool[2]; sourcePools[(int)SourcePoolIndex.Default] = new SoundSourcePool(SOURCE_COUNT); playingChannels[(int)SourcePoolIndex.Default] = new SoundChannel[SOURCE_COUNT]; sourcePools[(int)SourcePoolIndex.Voice] = new SoundSourcePool(16); playingChannels[(int)SourcePoolIndex.Voice] = new SoundChannel[16]; 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; } ListenerPosition = Vector3.Zero; ListenerTargetVector = new Vector3(0.0f, 0.0f, 1.0f); ListenerUpVector = new Vector3(0.0f, -1.0f, 0.0f); CompressionDynamicRangeGain = 1.0f; }
public void Update() { if (Disconnected || Disabled) { return; } if (CanDetectDisconnect) { Alc.GetInteger(alcDevice, Alc.EnumConnected, out int isConnected); int alcError = Alc.GetError(alcDevice); if (alcError != Alc.NoError) { throw new Exception("Failed to determine if device is connected: " + alcError.ToString()); } if (isConnected == 0) { DebugConsole.ThrowError("Playback device has been disconnected. You can select another available device in the settings."); GameMain.Config.AudioOutputDevice = "<disconnected>"; Disconnected = true; return; } } if (GameMain.Client != null && GameMain.Config.VoipAttenuationEnabled) { if (Timing.TotalTime > lastAttenuationTime + 0.2) { voipAttenuatedGain = voipAttenuatedGain * 0.9f + 0.1f; } } else { voipAttenuatedGain = 1.0f; } SetCategoryGainMultiplier("default", VoipAttenuatedGain, 1); SetCategoryGainMultiplier("ui", VoipAttenuatedGain, 1); SetCategoryGainMultiplier("waterambience", VoipAttenuatedGain, 1); SetCategoryGainMultiplier("music", VoipAttenuatedGain, 1); if (GameMain.Config.DynamicRangeCompressionEnabled) { float targetGain = (Math.Min(1.0f, 1.0f / PlaybackAmplitude) - 1.0f) * 0.5f + 1.0f; if (targetGain < CompressionDynamicRangeGain) { //if the target gain is lower than the current gain, lower the current gain immediately to prevent clipping CompressionDynamicRangeGain = targetGain; } else { //otherwise, let it rise back smoothly CompressionDynamicRangeGain = (targetGain) * 0.05f + CompressionDynamicRangeGain * 0.95f; } } else { CompressionDynamicRangeGain = 1.0f; } if (streamingThread == null || streamingThread.ThreadState.HasFlag(ThreadState.Stopped)) { bool startedStreamThread = false; for (int i = 0; i < playingChannels.Length; i++) { lock (playingChannels[i]) { for (int j = 0; j < playingChannels[i].Length; j++) { if (playingChannels[i][j] == null) { continue; } if (playingChannels[i][j].IsStream && playingChannels[i][j].IsPlaying) { InitStreamThread(); startedStreamThread = true; } if (startedStreamThread) { break; } } } if (startedStreamThread) { break; } } } }
public void Dispose() { if (Disabled) { return; } ReleaseResources(false); if (!Alc.MakeContextCurrent(IntPtr.Zero)) { throw new Exception("Failed to detach the current ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + ")"); } Alc.DestroyContext(alcContext); if (!Alc.CloseDevice(alcDevice)) { throw new Exception("Failed to close ALC device!"); } }
public SoundManager() { loadedSounds = new List <Sound>(); streamingThread = null; categoryModifiers = null; alcDevice = Alc.OpenDevice(null); if (alcDevice == null) { DebugConsole.ThrowError("Failed to open an ALC device! Disabling audio playback..."); Disabled = true; return; } int alcError = Alc.GetError(alcDevice); if (alcError != Alc.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 != Alc.NoError) { DebugConsole.ThrowError("Error initializing ALC device: " + alcError.ToString() + ". Disabling audio playback..."); Disabled = true; return; } } 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; } 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; } alcError = Alc.GetError(alcDevice); if (alcError != Alc.NoError) { DebugConsole.ThrowError("Error after assigning ALC context: " + alcError.ToString() + ". Disabling audio playback..."); Disabled = true; return; } sourcePools = new SoundSourcePool[2]; sourcePools[(int)SourcePoolIndex.Default] = new SoundSourcePool(SOURCE_COUNT); playingChannels[(int)SourcePoolIndex.Default] = new SoundChannel[SOURCE_COUNT]; sourcePools[(int)SourcePoolIndex.Voice] = new SoundSourcePool(16); playingChannels[(int)SourcePoolIndex.Voice] = new SoundChannel[16]; 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; } ListenerPosition = Vector3.Zero; ListenerTargetVector = new Vector3(0.0f, 0.0f, 1.0f); ListenerUpVector = new Vector3(0.0f, -1.0f, 0.0f); CompressionDynamicRangeGain = 1.0f; }
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 void Dispose() { if (Disabled) { return; } for (int i = 0; i < playingChannels.Length; i++) { lock (playingChannels[i]) { for (int j = 0; j < playingChannels[i].Length; j++) { if (playingChannels[i][j] != null) { playingChannels[i][j].Dispose(); } } } } streamingThread?.Join(); for (int i = loadedSounds.Count - 1; i >= 0; i--) { loadedSounds[i].Dispose(); } sourcePools[(int)SourcePoolIndex.Default]?.Dispose(); sourcePools[(int)SourcePoolIndex.Voice]?.Dispose(); if (!Alc.MakeContextCurrent(IntPtr.Zero)) { throw new Exception("Failed to detach the current ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + ")"); } Alc.DestroyContext(alcContext); if (!Alc.CloseDevice(alcDevice)) { throw new Exception("Failed to close ALC 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; } } } }
void UpdateCapture() { short[] uncompressedBuffer = new short[VoipConfig.BUFFER_SIZE]; while (capturing) { int alcError; Alc.GetInteger(captureDevice, Alc.EnumCaptureSamples, out int sampleCount); alcError = Alc.GetError(captureDevice); if (alcError != Alc.NoError) { throw new Exception("Failed to determine sample count: " + alcError.ToString()); } if (sampleCount < VoipConfig.BUFFER_SIZE) { int sleepMs = (VoipConfig.BUFFER_SIZE - sampleCount) * 800 / VoipConfig.FREQUENCY; if (sleepMs < 5) { sleepMs = 5; } Thread.Sleep(sleepMs); continue; } GCHandle handle = GCHandle.Alloc(uncompressedBuffer, GCHandleType.Pinned); try { Alc.CaptureSamples(captureDevice, handle.AddrOfPinnedObject(), VoipConfig.BUFFER_SIZE); } finally { handle.Free(); } alcError = Alc.GetError(captureDevice); if (alcError != Alc.NoError) { throw new Exception("Failed to capture samples: " + alcError.ToString()); } double maxAmplitude = 0.0f; for (int i = 0; i < VoipConfig.BUFFER_SIZE; i++) { uncompressedBuffer[i] = (short)MathHelper.Clamp((uncompressedBuffer[i] * Gain), -short.MaxValue, short.MaxValue); double sampleVal = uncompressedBuffer[i] / (double)short.MaxValue; maxAmplitude = Math.Max(maxAmplitude, Math.Abs(sampleVal)); } double dB = Math.Min(20 * Math.Log10(maxAmplitude), 0.0); LastdB = dB; bool allowEnqueue = false; if (GameMain.WindowActive) { if (GameMain.Config.VoiceSetting == GameSettings.VoiceMode.Activity) { if (dB > GameMain.Config.NoiseGateThreshold) { allowEnqueue = true; } } else if (GameMain.Config.VoiceSetting == GameSettings.VoiceMode.PushToTalk) { if (PlayerInput.KeyDown(InputType.Voice) && GUI.KeyboardDispatcher.Subscriber == null) { allowEnqueue = true; } } } if (allowEnqueue) { LastEnqueueAudio = DateTime.Now; //encode audio and enqueue it lock (buffers) { int compressedCount = VoipConfig.Encoder.Encode(uncompressedBuffer, 0, VoipConfig.BUFFER_SIZE, BufferToQueue, 0, VoipConfig.MAX_COMPRESSED_SIZE); EnqueueBuffer(compressedCount); } } else { //enqueue silence lock (buffers) { EnqueueBuffer(0); } } Thread.Sleep(10); } }