Aggiunge il mute del microfono in diretta per evitare claim YouTube sulla musica in palestra.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -47,6 +47,7 @@ final class LiveBroadcastEngine: ObservableObject {
|
||||
private var lastAppliedCaptureOrientation: AVCaptureVideoOrientation?
|
||||
private var orientationDebounceTask: Task<Void, Never>?
|
||||
private var rtmpSession: (any Session)?
|
||||
private var audioMuted = false
|
||||
private static var rtmpFactoryRegistered = false
|
||||
|
||||
private static func ensureRTMPFactoryRegistered() async {
|
||||
@@ -173,12 +174,21 @@ final class LiveBroadcastEngine: ObservableObject {
|
||||
overlayRenderer.detach()
|
||||
try? await mixer.stopRunning()
|
||||
pipelineConfigured = false
|
||||
audioMuted = false
|
||||
}
|
||||
|
||||
func release() async {
|
||||
await stopBroadcast()
|
||||
}
|
||||
|
||||
/// Silenzia il microfono senza togliere la traccia AAC (YouTube/MediaMTX richiedono audio continuo).
|
||||
func setAudioMuted(_ muted: Bool) async {
|
||||
audioMuted = muted
|
||||
await applyAudioMute()
|
||||
metrics.audioMuted = muted
|
||||
emitMetrics()
|
||||
}
|
||||
|
||||
/// Adattamento termico: aggiorna profilo video senza interrompere la sessione RTMP attiva.
|
||||
func applyThermalProfile(videoBitrate: Int, fps: Int) async {
|
||||
guard var current = config else { return }
|
||||
@@ -219,7 +229,8 @@ final class LiveBroadcastEngine: ObservableObject {
|
||||
AudioMixerSettings(
|
||||
sampleRate: BroadcastConfig.audioSampleRateHz,
|
||||
channels: BroadcastConfig.audioChannels,
|
||||
tracks: [0: AudioMixerTrackSettings(downmix: true, channelMap: [0])]
|
||||
isMuted: audioMuted,
|
||||
tracks: [0: AudioMixerTrackSettings(isMuted: audioMuted, downmix: true, channelMap: [0])]
|
||||
)
|
||||
)
|
||||
if let camera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) {
|
||||
@@ -324,7 +335,8 @@ final class LiveBroadcastEngine: ObservableObject {
|
||||
bitrateKbps: kbps,
|
||||
fps: self.config?.fps ?? self.metrics.fps,
|
||||
connected: self.phase == .live,
|
||||
lastError: self.metrics.lastError
|
||||
lastError: self.metrics.lastError,
|
||||
audioMuted: self.audioMuted
|
||||
)
|
||||
self.metricsListener?(self.metrics)
|
||||
}
|
||||
@@ -496,6 +508,16 @@ final class LiveBroadcastEngine: ObservableObject {
|
||||
UIDevice.current.endGeneratingDeviceOrientationNotifications()
|
||||
}
|
||||
|
||||
private func applyAudioMute() async {
|
||||
guard pipelineConfigured else { return }
|
||||
var settings = await mixer.audioMixerSettings
|
||||
settings.isMuted = audioMuted
|
||||
var track = settings.tracks[0] ?? AudioMixerTrackSettings(downmix: true, channelMap: [0])
|
||||
track.isMuted = audioMuted
|
||||
settings.tracks[0] = track
|
||||
try? await mixer.setAudioMixerSettings(settings)
|
||||
}
|
||||
|
||||
private func setPhase(_ newPhase: BroadcastPhase, error: String? = nil) {
|
||||
phase = newPhase
|
||||
metrics = BroadcastMetrics(
|
||||
@@ -503,7 +525,8 @@ final class LiveBroadcastEngine: ObservableObject {
|
||||
bitrateKbps: metrics.bitrateKbps,
|
||||
fps: config?.fps ?? metrics.fps,
|
||||
connected: newPhase == .live,
|
||||
lastError: error
|
||||
lastError: error,
|
||||
audioMuted: audioMuted
|
||||
)
|
||||
metricsListener?(metrics)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user