Fix YouTube waiting: transcode verso RTMP e sync stato live.
Il relay non usa più copy (stream inactive su YouTube); PublisherSync nel refresh overlay; activate solo quando lo stream YouTube è active. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -26,6 +26,7 @@ class OverlayRefreshJob < ApplicationJob
|
|||||||
return self.class.cancel_chain(session_id) unless Streams::OverlayRelay.running?(session_id)
|
return self.class.cancel_chain(session_id) unless Streams::OverlayRelay.running?(session_id)
|
||||||
|
|
||||||
Streams::Overlay::Refresh.call(session)
|
Streams::Overlay::Refresh.call(session)
|
||||||
|
Mediamtx::PublisherSync.new(session).call if session.status.in?(%w[connecting reconnecting live paused])
|
||||||
if session.platform == "youtube"
|
if session.platform == "youtube"
|
||||||
Streams::YoutubeRelay.ensure_publishing!(session)
|
Streams::YoutubeRelay.ensure_publishing!(session)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -19,14 +19,9 @@ module Streams
|
|||||||
intake = mediamtx_intake_url(session)
|
intake = mediamtx_intake_url(session)
|
||||||
output = "rtmp://a.rtmp.youtube.com/live2/#{session.stream_key}"
|
output = "rtmp://a.rtmp.youtube.com/live2/#{session.stream_key}"
|
||||||
|
|
||||||
|
# YouTube richiede FLV H.264/AAC stabili; -c copy lascia spesso streamStatus=inactive.
|
||||||
pid = Process.spawn(
|
pid = Process.spawn(
|
||||||
"ffmpeg", "-nostdin", "-hide_banner", "-loglevel", "warning",
|
*youtube_ffmpeg_args(intake, output, log_path),
|
||||||
"-rw_timeout", "15000000",
|
|
||||||
"-i", intake,
|
|
||||||
"-c", "copy",
|
|
||||||
"-f", "flv",
|
|
||||||
output,
|
|
||||||
%i[out err] => log_path,
|
|
||||||
pgroup: true
|
pgroup: true
|
||||||
)
|
)
|
||||||
Process.detach(pid)
|
Process.detach(pid)
|
||||||
@@ -62,13 +57,33 @@ module Streams
|
|||||||
|
|
||||||
return if running?(session.id)
|
return if running?(session.id)
|
||||||
|
|
||||||
|
last_restart = redis.get(restart_debounce_key(session.id)).to_i
|
||||||
|
return if last_restart.positive? && (Time.now.to_i - last_restart) < 20
|
||||||
|
|
||||||
start(session)
|
start(session)
|
||||||
|
redis.set(restart_debounce_key(session.id), Time.now.to_i, ex: 300)
|
||||||
rescue Error => e
|
rescue Error => e
|
||||||
Rails.logger.warn("[YoutubeRelay] ensure_publishing session=#{session.id}: #{e.message}")
|
Rails.logger.warn("[YoutubeRelay] ensure_publishing session=#{session.id}: #{e.message}")
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def youtube_ffmpeg_args(intake, output, log_path)
|
||||||
|
[
|
||||||
|
"ffmpeg", "-nostdin", "-hide_banner", "-loglevel", "warning",
|
||||||
|
"-fflags", "+genpts+discardcorrupt", "-use_wallclock_as_timestamps", "1",
|
||||||
|
"-rw_timeout", "15000000",
|
||||||
|
"-i", intake,
|
||||||
|
"-map", "0:v:0", "-map", "0:a:0",
|
||||||
|
"-c:v", "libx264", "-preset", "veryfast", "-tune", "zerolatency",
|
||||||
|
"-pix_fmt", "yuv420p", "-r", "30", "-g", "30", "-keyint_min", "30", "-sc_threshold", "0",
|
||||||
|
"-b:v", "4000k", "-maxrate", "4000k", "-bufsize", "8000k",
|
||||||
|
"-c:a", "aac", "-b:a", "128k", "-ar", "48000", "-ac", "1",
|
||||||
|
"-f", "flv", output,
|
||||||
|
%i[out err] => log_path
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
def schedule_youtube_activate(session)
|
def schedule_youtube_activate(session)
|
||||||
return if session.youtube_broadcast_id.blank?
|
return if session.youtube_broadcast_id.blank?
|
||||||
|
|
||||||
@@ -88,6 +103,10 @@ module Streams
|
|||||||
@redis ||= Redis.new(url: ENV.fetch("REDIS_URL", "redis://localhost:6379/0"))
|
@redis ||= Redis.new(url: ENV.fetch("REDIS_URL", "redis://localhost:6379/0"))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def restart_debounce_key(session_id)
|
||||||
|
format("youtube_relay:debounce:%s", session_id)
|
||||||
|
end
|
||||||
|
|
||||||
def store_pid(session_id, pid)
|
def store_pid(session_id, pid)
|
||||||
redis.set(format(REDIS_KEY, session_id), pid, ex: 48.hours.to_i)
|
redis.set(format(REDIS_KEY, session_id), pid, ex: 48.hours.to_i)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -56,12 +56,18 @@ module Youtube
|
|||||||
return if @credential.blank? || missing_oauth_config?
|
return if @credential.blank? || missing_oauth_config?
|
||||||
|
|
||||||
client = authorized_client
|
client = authorized_client
|
||||||
item = client.list_live_broadcasts("status", id: broadcast_id).items&.first
|
item = client.list_live_broadcasts("status", id: broadcast_id, mine: true).items&.first
|
||||||
return unless item
|
return unless item
|
||||||
|
|
||||||
status = item.status.life_cycle_status.to_s
|
status = item.status.life_cycle_status.to_s
|
||||||
return if status == "live"
|
return if status == "live"
|
||||||
|
|
||||||
|
stream_id = item.content_details&.bound_stream_id
|
||||||
|
if stream_id.present?
|
||||||
|
stream = client.list_live_streams("status", id: stream_id, mine: true).items&.first
|
||||||
|
return if stream&.status&.stream_status != "active"
|
||||||
|
end
|
||||||
|
|
||||||
if %w[ready created].include?(status)
|
if %w[ready created].include?(status)
|
||||||
client.transition_live_broadcast("testing", broadcast_id, "id,status")
|
client.transition_live_broadcast("testing", broadcast_id, "id,status")
|
||||||
status = "testing"
|
status = "testing"
|
||||||
|
|||||||
Reference in New Issue
Block a user