Fix freeze YouTube al cambio punteggio: PNG atomica e relay stabile
rsvg scrive su .tmp poi rename; il feeder ignora PNG parziali. YouTube relay: no doppio avvio, reconnect RTMP; overlay restart solo dopo 3 miss. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -37,10 +37,12 @@ module Streams
|
||||
end
|
||||
|
||||
def render_png!(svg_path, png_path)
|
||||
unless system("rsvg-convert", "-w", "1280", "-h", "720", "-o", png_path.to_s, svg_path.to_s, out: File::NULL, err: File::NULL)
|
||||
tmp = "#{png_path}.tmp"
|
||||
unless system("rsvg-convert", "-w", "1280", "-h", "720", "-o", tmp, svg_path.to_s, out: File::NULL, err: File::NULL)
|
||||
raise Error, "rsvg-convert fallito per session #{@session.id}"
|
||||
end
|
||||
|
||||
File.rename(tmp, png_path)
|
||||
FileUtils.touch(png_path)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -86,8 +86,15 @@ module Streams
|
||||
end
|
||||
|
||||
if running?(session.id)
|
||||
Rails.logger.warn("[OverlayRelay] _air non attivo, restart session=#{session.id}")
|
||||
misses = redis.incr(overlay_air_miss_key(session.id)).to_i
|
||||
redis.expire(overlay_air_miss_key(session.id), 120)
|
||||
return if misses < 3
|
||||
|
||||
redis.del(overlay_air_miss_key(session.id))
|
||||
Rails.logger.warn("[OverlayRelay] _air non attivo dopo #{misses} tentativi, restart session=#{session.id}")
|
||||
stop(session)
|
||||
else
|
||||
redis.del(overlay_air_miss_key(session.id))
|
||||
end
|
||||
|
||||
start(session)
|
||||
@@ -181,6 +188,10 @@ module Streams
|
||||
redis.get(format(REDIS_KEY, session_id))
|
||||
end
|
||||
|
||||
def overlay_air_miss_key(session_id)
|
||||
format("overlay_relay:air_miss:%s", session_id)
|
||||
end
|
||||
|
||||
def process_alive?(pid)
|
||||
Process.kill(0, pid.to_i)
|
||||
true
|
||||
|
||||
@@ -12,6 +12,8 @@ module Streams
|
||||
return if session.stream_key.blank?
|
||||
return if session.terminal?
|
||||
|
||||
return pid_for(session.id).to_i if running?(session.id)
|
||||
|
||||
stop(session) if pid_for(session.id).present?
|
||||
|
||||
log_path = log_file(session)
|
||||
@@ -80,6 +82,7 @@ module Streams
|
||||
"-fflags", "+genpts+discardcorrupt", "-use_wallclock_as_timestamps", "1",
|
||||
"-analyzeduration", "10000000", "-probesize", "10000000",
|
||||
"-rw_timeout", "15000000",
|
||||
"-reconnect", "1", "-reconnect_at_eof", "1", "-reconnect_streamed", "1", "-reconnect_delay_max", "5",
|
||||
"-i", intake,
|
||||
"-f", "lavfi", "-i", "anullsrc=channel_layout=mono:sample_rate=48000",
|
||||
"-map", "0:v:0", "-map", "1:a:0",
|
||||
|
||||
@@ -16,13 +16,24 @@ trap("TERM") { stop = true }
|
||||
trap("INT") { stop = true }
|
||||
|
||||
# image2pipe richiede frame continui: inviamo la PNG a ritmo fisso ( anche se invariata ).
|
||||
last_bytes = nil
|
||||
File.open(pipe_path, "wb") do |pipe|
|
||||
loop do
|
||||
break if stop
|
||||
|
||||
if File.exist?(png_path)
|
||||
pipe.write(File.binread(png_path))
|
||||
bytes = File.binread(png_path)
|
||||
# Evita frame corrotti durante rsvg-convert (file parziale prima del rename atomico).
|
||||
next if bytes.bytesize < 512
|
||||
|
||||
if bytes != last_bytes
|
||||
pipe.write(bytes)
|
||||
pipe.flush
|
||||
last_bytes = bytes
|
||||
elsif last_bytes
|
||||
pipe.write(last_bytes)
|
||||
pipe.flush
|
||||
end
|
||||
end
|
||||
|
||||
sleep poll_sec
|
||||
|
||||
Reference in New Issue
Block a user