Example #1
0
        void CloseStream()
        {
            if (!IsStreamActive)
            {
                throw new InvalidOp("Stream not opened");
            }

            _stream?.Dispose();
            _stream = null;
        }
Example #2
0
        // IDisposable implementation
        public void Dispose()
        {
            _stream?.Dispose();
            _stream = null;

            _device?.Dispose();
            _device = null;

            if (_self.IsAllocated)
            {
                _self.Free();
            }
        }
Example #3
0
        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;
            }
        }