Example #1
0
        protected override void UpdateBackend()
        {
            try
            {
                // Check if the context is initialized.
                if (!_layerContext.Initialized)
                {
                    // Fill buffer before starting to prevent noise.
                    FillBuffer(_layerContext.RenderClient, _bufferLengthInFrames);
                    _layerContext.Start();
                }

                // Start if not started.
                if (!_layerContext.Started)
                {
                    _layerContext.Start();
                }

                // Get more frames.
                int error = _layerContext.AudioClient.GetCurrentPadding(out int padding);
                if (error != 0)
                {
                    Engine.Log.Warning($"Couldn't get device padding, error {error}.", MessageSource.WasApi);
                }
                FillBuffer(_layerContext.RenderClient, _bufferLengthInFrames - padding);
            }
            catch (COMException ex)
            {
                // Audio device is the same, but the configuration has changed.
                // Tracking these changes in the adapter is a huge drag, so we just catch the error instead.
                // https://www.hresult.info/FACILITY_AUDCLNT/0x88890004
                if ((uint)ex.ErrorCode == 0x88890004)
                {
                    SetDevice(_context.DefaultDevice);
                    Engine.Log.Trace("Default audio device changed.", MessageSource.WasApi);
                }
                else
                {
                    Engine.Log.Error(ex.ToString(), MessageSource.WasApi);
                }
            }
        }
Example #2
0
        private void LayerThread()
        {
            if (Thread.CurrentThread.Name == null)
            {
                Thread.CurrentThread.Name = $"Audio Layer - {Name}";
            }
            Engine.Log.Trace($"Layer {Name} started.", MessageSource.Audio);
            while (_alive && Engine.Status != EngineStatus.Stopped)
            {
                // Check if the device has changed.
                if (_updateDevice)
                {
                    SetDevice(_parent.DefaultDevice);
                    _updateDevice = false;
                }

                // If not playing, wait for it to start playing.
                if (Status != PlaybackStatus.Playing)
                {
                    _playWait.WaitOne();
                    continue;
                }

                if (_playlist.Count == 0 || _currentTrack == -1 || _currentTrack > _playlist.Count - 1)
                {
                    Debug.Assert(false);
                }

                try
                {
                    // Get the number of frames the buffer can hold total.
                    var frameCount = (int)_layerContext.BufferSize;

                    // Check if the context is initialized.
                    if (!_layerContext.Initialized)
                    {
                        FillBuffer(_layerContext.RenderClient, (int)_layerContext.BufferSize);
                        _layerContext.Start();
                    }

                    // Start if not started.
                    if (!_layerContext.Started)
                    {
                        _layerContext.Start();
                    }

                    // Wait until more of the buffer is requested.
                    bool success = _layerContext.WaitHandle.WaitOne(_layerContext.TimeoutPeriod);
                    if (!success)
                    {
                        Engine.Log.Warning($"Layer {Name} audio context timeout.", MessageSource.WasApi);
                        continue;
                    }

                    // Get more frames.
                    int error = _layerContext.AudioClient.GetCurrentPadding(out int padding);
                    if (error != 0)
                    {
                        Engine.Log.Warning($"Couldn't get device padding, error {error}.", MessageSource.WasApi);
                    }
                    if (!FillBuffer(_layerContext.RenderClient, frameCount - padding))
                    {
                        continue;
                    }
                }
                catch (COMException ex)
                {
                    // Audio device has disappeared or whatever.
                    if ((uint)ex.ErrorCode == 0x88890004)
                    {
                        _updateDevice = true;
                        continue;
                    }

                    Engine.Log.Error(ex.ToString(), MessageSource.WasApi);
                }

                // If done, reset the audio client.
                Task.Delay(_layerContext.TimeoutPeriod).Wait();
                _layerContext.Stop();
                _layerContext.Reset();
            }

            Engine.Log.Trace($"Layer {Name} exited.", MessageSource.Audio);
            _layerContext.Stop();
            _layerContext = null;
        }