fix: pre-install audioMix in playIndex to prevent video freeze on record start

Setting playerItem.audioMix while AVPlayer is actively playing causes
the audio/video pipeline to reconfigure, stalling video playback.

Fix: install the MTAudioProcessingTap audioMix at item creation time
(in playIndex, before replaceCurrentItem), so the pipeline is already
configured when playback begins. startRecording now only flips the
isRecording flag and skips re-installation if audioMix exists.

Also removed the guard that blocked tap installation when tracks
weren't available yet (HLS streams) — the wildcard trackID
(kCMPersistentTrackID_Invalid) handles this case.
This commit is contained in:
yumoqing 2026-06-28 10:30:20 +08:00
parent cff2bd2793
commit 9160b3ce2b
2 changed files with 13 additions and 7 deletions

View File

@ -186,6 +186,9 @@ final class PlayerBridge: ObservableObject {
let output = AVPlayerItemVideoOutput(pixelBufferAttributes: pixelBufferAttributes) let output = AVPlayerItemVideoOutput(pixelBufferAttributes: pixelBufferAttributes)
playerItem.add(output) playerItem.add(output)
videoOutput = output videoOutput = output
// 预装音频 Tap(在播放前设置 audioMix,避免播放中设置导致视频卡顿)
screenRecorder.installAudioTap(on: playerItem)
#endif #endif
player.replaceCurrentItem(with: playerItem) player.replaceCurrentItem(with: playerItem)

View File

@ -319,7 +319,8 @@ final class PlayerRecorder: NSObject {
// MARK: - Audio Tap Setup // MARK: - Audio Tap Setup
/// 安装音频 Tap(使用 playerItem.tracks 获取轨道,支持 HLS 虚拟 asset) /// 安装音频 Tap(使用 playerItem.tracks 获取轨道,支持 HLS 虚拟 asset)
private func installAudioTap(on playerItem: AVPlayerItem) { /// 应在 playerItem 开始播放前调用(playIndex 中),避免播放中设置 audioMix 导致视频卡顿
func installAudioTap(on playerItem: AVPlayerItem) {
// 确保全局上下文存在 // 确保全局上下文存在
if gTapContext == nil { if gTapContext == nil {
gTapContext = AudioTapContext() gTapContext = AudioTapContext()
@ -344,10 +345,8 @@ final class PlayerRecorder: NSObject {
} }
} }
guard audioTrackID != kCMPersistentTrackID_Invalid else { if audioTrackID == kCMPersistentTrackID_Invalid {
print("[Recorder:DIAG] ⚠️ No enabled audio track in playerItem.tracks!") print("[Recorder:DIAG] ⚠️ No enabled audio track found yet (tracks=\(itemTracks.count)), using wildcard")
writeDiagLog("No audio track in playerItem.tracks (count=\(itemTracks.count))")
return
} }
print("[Recorder:DIAG] Using audio trackID=\(audioTrackID)") print("[Recorder:DIAG] Using audio trackID=\(audioTrackID)")
@ -431,8 +430,12 @@ final class PlayerRecorder: NSObject {
isRunning = false isRunning = false
recordStartTime = startTime recordStartTime = startTime
// 安装音频 Tap(录制时 asset 已加载,同步获取 track) // 安装音频 Tap(如果 playIndex 中已预装,则跳过)
if playerItem.audioMix == nil {
installAudioTap(on: playerItem) installAudioTap(on: playerItem)
} else {
print("[Recorder:DIAG] audioMix already installed, skipping")
}
let tempFilename = "temp_recording_\(Int(Date().timeIntervalSince1970)).mp4" let tempFilename = "temp_recording_\(Int(Date().timeIntervalSince1970)).mp4"
let url = saveDirectory.appendingPathComponent(tempFilename) let url = saveDirectory.appendingPathComponent(tempFilename)