Пример #1
0
        /*
         *      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);
            }
        }
Пример #2
0
        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();
        }
Пример #3
0
        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() + ")");
            }
        }
Пример #4
0
        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)));
        }
Пример #6
0
        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));
                }
            }
        }
Пример #9
0
        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;
            }
        }
Пример #10
0
        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);
        }
Пример #11
0
        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);
            }
        }
Пример #12
0
        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);
        }
Пример #13
0
        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!");
            }
        }
Пример #14
0
        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;
        }
Пример #15
0
        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;
                    }
                }
            }
        }
Пример #16
0
        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!");
            }
        }
Пример #17
0
        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;
        }
Пример #18
0
        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();
        }
Пример #19
0
        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!");
            }
        }
Пример #20
0
        // 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;
                    }
                }
            }
        }
Пример #21
0
        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);
            }
        }