void dicks() { Logger.pcm.a("prism thread"); long bufSize = settings.samplerate * 10; byte[] buffer = new byte[bufSize * 4]; System.IO.FileStream w = null; if (settings.recPCM) { Logger.pcm.a("open dump target"); w = new System.IO.FileStream(string.Format("Loopstream-{0}.pcm", DateTime.UtcNow.ToString("yyyy-MM-dd_HH.mm.ss")), System.IO.FileMode.Create); } // Create encoders first, but do not feed data if (settings.mp3.enabled) { encoders.Add(new LSLame(settings, this)); } if (settings.ogg.enabled) { encoders.Add(new LSVorbis(settings, this)); } if (settings.opus.enabled) { encoders.Add(new LSOpus(settings, this)); } // Note that encoders handle creation of and connecting to shouters // start the thread watching encoders/shouters and restarting the crashed ones System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(medic)); t.Name = "LSPcm_Medic"; t.Start(); // Finally, reposition PCM pointer to minimize latency // (and chance of lost packets because icecast a bitch) outlet.setReadPtr(0.2); // PCM reader loop, passing on to encoders/shouters //List<string> toclip = new List<string>(); int align = (wp16.WaveFormat.BitsPerSample / 8) * wp16.WaveFormat.Channels; try { while (true) { Logger.pcm.a("awaiting pcm"); int avail = 0; while (!qt("dicks")) { avail = outlet.avail(); if (avail >= 2048) { break; } System.Threading.Thread.Sleep(20); } if (avail <= 0) { break; } //Console.Write('.'); int toRead = (outlet.avail() / align) * align; Logger.pcm.a("reading pcm data " + buffer.Length + ", " + toRead); int i = wp16.Read(buffer, 0, toRead); //toclip.Add((DateTime.UtcNow.Ticks / 10000) + ", " + i); Logger.pcm.a("locking for write " + i); lock (locker) { int _soffMono = soffMono; int _soffStereo = soffStereo; for (int a = 0; a < encoders.Count; a++) { LSEncoder enc = encoders[a]; if (!enc.crashed && enc.stdin != null) { bool silence = false; if (enc.GetType() == typeof(LSVorbis)) { silence = true; for (int ofs = 1; ofs < i; ofs += 16) { int v = buffer[ofs]; if (v > 0x80) { v = 255 - v; } if (v > 1) { silence = false; break; } } if (silence) { Logger.pcm.a("SILENCE to " + enc.enc.ext + " " + i); soffMono = _soffMono; soffStereo = _soffStereo; bool stereo = enc.enc.channels == LSSettings.LSChannels.stereo; enc.enqueue(barf(i, stereo), i); } } if (!silence) { //Logger.pcm.a("writing to " + enc.enc.ext + " " + i); enc.enqueue(buffer, i); } } } } if (w != null) { //Logger.pcm.a("writing to dump " + i); w.Write(buffer, 0, i); } } } catch (Exception ex) { System.Windows.Forms.MessageBox.Show("pcm reader / enc prism just died\n\nthought you might want to know\n\n===========================\n" + ex.Message + "\n" + ex.StackTrace); } Console.WriteLine("shutting down encoder prism"); if (w != null) { w.Close(); } }
void medic() { Logger.med.a("active"); while (!qt("medic")) { for (int a = 0; a < encoders.Count; a++) { LSEncoder enc = encoders[a]; if (enc.crashed) { if (res_cd == 0) { Logger.pcm.a("pending resurrect " + enc.enc.ext); } if (++res_cd < 50) { continue; } res_cd = 0; Logger.pcm.a("resurrecting " + enc.enc.ext); enc.Dispose(); try { if (enc.enc.ext == "mp3") { enc = new LSLame(settings, this); } else if (enc.enc.ext == "ogg") { enc = new LSVorbis(settings, this); } else if (enc.enc.ext == "opus") { enc = new LSOpus(settings, this); } else { System.Windows.Forms.MessageBox.Show("this shouldn't happen"); Program.kill(); } lock (locker) { encoders[a] = enc; } Logger.pcm.a("resurrected " + enc.enc.ext); } catch { Logger.pcm.a("resurrect failure: " + enc.enc.ext); if (Program.BALLOONS) { Program.ni.ShowBalloonTip(1000, "Connection error", "Failed to restart " + enc.enc.ext, System.Windows.Forms.ToolTipIcon.Error); } } } else if (enc.aborted) { string msg = "Removing " + enc.enc.ext + " encoder"; Logger.pcm.a(msg); encoders.RemoveAt(a--); if (Program.BALLOONS) { Program.ni.ShowBalloonTip(1000, "Connection error", msg, System.Windows.Forms.ToolTipIcon.Error); } } } System.Threading.Thread.Sleep(10); } Logger.med.a("disposed"); }