public void Close() { Closed = true; try { if (!FfmpegProcess.HasExitedSafe()) { FfmpegProcess.Kill(); } } catch { } try { FfmpegProcess.CancelErrorRead(); } catch { } try { FfmpegProcess.StandardInput.Dispose(); } catch { } try { FfmpegProcess.StandardOutput.Dispose(); } catch { } try { FfmpegProcess.Dispose(); } catch { } IcyStream?.Dispose(); }
public void ReadStreamLoop(Id id) { if (IcyStream is null) { throw new InvalidOperationException("Instance is not an icy stream"); } Tools.SetLogId(id.ToString()); const int IcyMaxMeta = 255 * 16; const int ReadBufferSize = 4096; int errorCount = 0; var buffer = new byte[Math.Max(ReadBufferSize, IcyMaxMeta)]; int readCount = 0; while (!Closed) { try { while (readCount < IcyMetaInt) { int read = IcyStream.Read(buffer, 0, Math.Min(ReadBufferSize, IcyMetaInt - readCount)); if (read == 0) { Close(); return; } readCount += read; FfmpegProcess.StandardInput.BaseStream.Write(buffer, 0, read); errorCount = 0; } readCount = 0; var metaByte = IcyStream.ReadByte(); if (metaByte < 0) { Close(); return; } if (metaByte > 0) { metaByte *= 16; while (readCount < metaByte) { int read = IcyStream.Read(buffer, 0, metaByte - readCount); if (read == 0) { Close(); return; } readCount += read; } readCount = 0; var metaString = Tools.Utf8Encoder.GetString(buffer, 0, metaByte).TrimEnd('\0'); Log.Debug("Meta: {0}", metaString); OnMetaUpdated?.Invoke(ParseIcyMeta(metaString)); } } catch (Exception ex) { errorCount++; if (errorCount >= 50) { Log.Error(ex, "Failed too many times trying to access ffmpeg. Closing stream."); Close(); return; } if (ex is InvalidOperationException) { Log.Debug(ex, "Waiting for ffmpeg"); Thread.Sleep(100); } else { Log.Debug(ex, "Stream read/write error"); } } } }