void OpenStream() { if (IsStreamActive) { throw new InvalidOp("Stream alreadly opened"); } try { _stream = SoundIO.InStream.Create(_device); if (_stream.IsInvalid) { throw new InvalidOp("Stream allocation error"); } if (_device.Layouts.Length == 0) { throw new InvalidOp("No channel layout"); } // Calculate the best latency. // TODO: Should we use the target frame rate instead of 1/60? var bestLatency = Math.Max(1.0 / 60, _device.SoftwareLatencyMin); // Stream properties _stream.Format = SoundIO.Format.Float32LE; _stream.Layout = _device.Layouts[0]; _stream.SoftwareLatency = bestLatency; _stream.ReadCallback = _readCallback; _stream.OverflowCallback = _overflowCallback; _stream.ErrorCallback = _errorCallback; _stream.UserData = GCHandle.ToIntPtr(_self); var err = _stream.Open(); if (err != SoundIO.Error.None) { throw new InvalidOp($"Stream initialization error ({err})"); } // We want the buffers to meet the following requirements: // - Doesn't overflow if the main thread pauses for 4 frames. // - Doesn't overflow if the callback is invoked 4 times a frame. var latency = Math.Max(_stream.SoftwareLatency, bestLatency); var bufferSize = CalculateBufferSize((float)(latency * 4)); // Ring/window buffer allocation _ring = new RingBuffer(bufferSize); _window = new byte[bufferSize]; // Start streaming. _stream.Start(); } catch { // Dispose the stream on an exception. _stream?.Dispose(); _stream = null; throw; } _audioLevels = new LevelMeter(_stream.Layout.ChannelCount) { SampleRate = _stream.SampleRate }; }
readonly float _bufferingTimeSec = 0.5f; // 0.5[sec] #endregion #region Stream initialization void OpenStream() { if (_device is null) { throw new InvalidOp("Invalid device"); } try { _stream = SoundIO.InStream.Create(_device); if (_stream.IsInvalid) { throw new InvalidOp("Stream allocation error"); } if (_device.Layouts.Length == 0) { throw new InvalidOp("No channel layout"); } // Calculate the best latency. // TODO: Should we use the target frame rate instead of 1/60? var bestLatency = Math.Max(1.0 / 60, _device.SoftwareLatencyMin); // Stream properties _stream.Format = SoundIO.Format.Float32LE; _stream.Layout = _device.Layouts[0]; _stream.SoftwareLatency = bestLatency; _stream.ReadCallback = _readCallback; _stream.OverflowCallback = _overflowCallback; _stream.ErrorCallback = _errorCallback; _stream.UserData = GCHandle.ToIntPtr(_self); var err = _stream.Open(); if (err != SoundIO.Error.None) { throw new InvalidOp($"Stream initialization error ({err})"); } // Calculate buffer size var ringBufferSize = (int)(_stream.Layout.ChannelCount * _stream.SampleRate * _bufferingTimeSec); var frameBufferSize = (int)(_frameDurationMs / 1000.0f * _stream.Layout.ChannelCount * _stream.SampleRate); // Ring/frame buffer allocation _ring = new RingBuffer <float>(ringBufferSize); _frameBuffer = new float[frameBufferSize]; // Start streaming. _stream.Start(); } catch { // Dispose the stream on an exception. _stream?.Dispose(); _stream = null; _device?.Dispose(); _device = null; throw; } }