Skip to content

Commit c23bf05

Browse files
authored
Handle macOS stream errors (#776)
Resolves #331 Handles stream errors in a way similar to iOS broadcast (by unpublishing the track so it won't get stuck).
1 parent 05b6ced commit c23bf05

3 files changed

Lines changed: 25 additions & 1 deletion

File tree

.changes/turn-off-display

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
patch type="fixed" "Screen sharing getting stuck on macOS when the display is turned off"

Sources/LiveKit/Track/Capturers/MacOSScreenCapturer.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public class MacOSScreenCapturer: VideoCapturer, @unchecked Sendable {
101101
}
102102

103103
// Why does SCStream hold strong reference to delegate?
104-
let stream = SCStream(filter: filter, configuration: configuration, delegate: nil)
104+
let stream = SCStream(filter: filter, configuration: configuration, delegate: self)
105105
try stream.addStreamOutput(self, type: .screen, sampleHandlerQueue: nil)
106106
if #available(macOS 13.0, *) {
107107
try stream.addStreamOutput(self, type: .audio, sampleHandlerQueue: nil)
@@ -200,6 +200,18 @@ extension MacOSScreenCapturer {
200200
}
201201
}
202202

203+
// MARK: - SCStreamDelegate
204+
205+
@available(macOS 12.3, *)
206+
extension MacOSScreenCapturer: SCStreamDelegate {
207+
public func stream(_: SCStream, didStopWithError error: Error) {
208+
log("Stream stopped with error: \(error)", .error)
209+
Task {
210+
try await stopCapture()
211+
}
212+
}
213+
}
214+
203215
// MARK: - SCStreamOutput
204216

205217
@available(macOS 12.3, *)

Sources/LiveKit/TrackPublications/LocalTrackPublication.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,17 @@ extension LocalTrackPublication: VideoCapturerDelegate {
119119
try await participant.unpublish(publication: self)
120120
}
121121
}
122+
// A similar check for macOS may be triggered e.g. when the display is powered off.
123+
#elseif os(macOS)
124+
if #available(macOS 12.3, *), state == .stopped, capturer is MacOSScreenCapturer {
125+
Task {
126+
guard let participant = try await self.requireParticipant() as? LocalParticipant else {
127+
return
128+
}
129+
130+
try await participant.unpublish(publication: self)
131+
}
132+
}
122133
#endif
123134
}
124135
}

0 commit comments

Comments
 (0)