fix: 修复 waitForProcess race condition,添加调试日志
This commit is contained in:
parent
acb232d38b
commit
ec88e9f530
@ -15,6 +15,21 @@ final class ProgressState: @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Thread-safe atomic boolean for one-shot guards
|
||||||
|
final class AtomicBool: @unchecked Sendable {
|
||||||
|
private var value = false
|
||||||
|
private let lock = NSLock()
|
||||||
|
|
||||||
|
/// Returns true if this call set it from false to true (first caller wins)
|
||||||
|
func setTrue() -> Bool {
|
||||||
|
lock.lock()
|
||||||
|
defer { lock.unlock() }
|
||||||
|
guard !value else { return false }
|
||||||
|
value = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final class FFmpegRecorder: StreamRecorderEngine {
|
public final class FFmpegRecorder: StreamRecorderEngine {
|
||||||
public weak var delegate: StreamRecorderDelegate?
|
public weak var delegate: StreamRecorderDelegate?
|
||||||
public private(set) var isRecording = false
|
public private(set) var isRecording = false
|
||||||
@ -108,6 +123,7 @@ public final class FFmpegRecorder: StreamRecorderEngine {
|
|||||||
|
|
||||||
// 异步等待进程完成(不阻塞 cooperative thread)
|
// 异步等待进程完成(不阻塞 cooperative thread)
|
||||||
await waitForProcess(proc)
|
await waitForProcess(proc)
|
||||||
|
NSLog("[Recorder] ffmpeg process exited, status: %d", proc.terminationStatus)
|
||||||
stderrPipe.fileHandleForReading.readabilityHandler = nil
|
stderrPipe.fileHandleForReading.readabilityHandler = nil
|
||||||
isRecording = false
|
isRecording = false
|
||||||
|
|
||||||
@ -119,9 +135,11 @@ public final class FFmpegRecorder: StreamRecorderEngine {
|
|||||||
throw RecordingError.outputNotFound
|
throw RecordingError.outputNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NSLog("[Recorder] Analyzing output file...")
|
||||||
// 分析输出文件
|
// 分析输出文件
|
||||||
let ffprobePath = ffmpegPath.replacingOccurrences(of: "ffmpeg", with: "ffprobe")
|
let ffprobePath = ffmpegPath.replacingOccurrences(of: "ffmpeg", with: "ffprobe")
|
||||||
let result = try await analyzeOutput(path: outputPath, ffprobePath: ffprobePath)
|
let result = try await analyzeOutput(path: outputPath, ffprobePath: ffprobePath)
|
||||||
|
NSLog("[Recorder] Analysis complete, notifying delegate")
|
||||||
delegate?.recorder(self, didFinishWithResult: result)
|
delegate?.recorder(self, didFinishWithResult: result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,13 +159,18 @@ public final class FFmpegRecorder: StreamRecorderEngine {
|
|||||||
private func waitForProcess(_ proc: Process) async {
|
private func waitForProcess(_ proc: Process) async {
|
||||||
guard proc.isRunning else { return }
|
guard proc.isRunning else { return }
|
||||||
await withCheckedContinuation { (continuation: CheckedContinuation<Void, Never>) in
|
await withCheckedContinuation { (continuation: CheckedContinuation<Void, Never>) in
|
||||||
|
let resumed = AtomicBool()
|
||||||
proc.terminationHandler = { _ in
|
proc.terminationHandler = { _ in
|
||||||
continuation.resume()
|
if resumed.setTrue() {
|
||||||
|
continuation.resume()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Race condition: process may have exited between isRunning check and setting handler
|
// Race condition: process may have exited between isRunning check and setting handler
|
||||||
if !proc.isRunning {
|
if !proc.isRunning {
|
||||||
proc.terminationHandler = nil
|
proc.terminationHandler = nil
|
||||||
continuation.resume()
|
if resumed.setTrue() {
|
||||||
|
continuation.resume()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user