fix: suspend OTG live transfer on exit
This commit is contained in:
@ -36,6 +36,7 @@ protocol WiredCameraConnectionManaging: AnyObject {
|
||||
func configureLiveTransfer(albumID: Int?)
|
||||
func start()
|
||||
func unbindDelegate()
|
||||
func suspendLiveTransfer()
|
||||
func disconnect()
|
||||
}
|
||||
|
||||
@ -86,6 +87,11 @@ final class ConnectionManager: NSObject, WiredCameraConnectionManaging {
|
||||
func configureLiveTransfer(albumID: Int?) {
|
||||
liveTransferAlbumID = albumID
|
||||
OTGLog.debug(.connection, "live transfer album=\(albumID.map(String.init) ?? "nil")")
|
||||
if albumID == nil {
|
||||
stopLiveTransferServices()
|
||||
return
|
||||
}
|
||||
resumeLiveTransferIfPossible()
|
||||
}
|
||||
|
||||
/// Entry point when OTG UI appears: reconnect cached device or start discovery.
|
||||
@ -115,6 +121,13 @@ final class ConnectionManager: NSObject, WiredCameraConnectionManaging {
|
||||
cancelSearchTimers()
|
||||
}
|
||||
|
||||
/// 页面离开时暂停边拍边传轮询,保留 USB Session 与设备缓存。
|
||||
func suspendLiveTransfer() {
|
||||
OTGLog.info(.connection, "suspend live transfer")
|
||||
liveTransferAlbumID = nil
|
||||
stopLiveTransferServices()
|
||||
}
|
||||
|
||||
/// 断开 Session 并释放 Driver;缓存设备保留至 USB 拔出。
|
||||
func disconnect() {
|
||||
guard let device = activeDevice else {
|
||||
@ -131,12 +144,7 @@ final class ConnectionManager: NSObject, WiredCameraConnectionManaging {
|
||||
isClosingSession = true
|
||||
isContentCatalogReady = false
|
||||
cancelSearchTimers()
|
||||
sonyRemoteCapture?.stop()
|
||||
sonyRemoteCapture = nil
|
||||
canonRemoteCapture?.stop()
|
||||
canonRemoteCapture = nil
|
||||
nikonLiveCapture?.stop()
|
||||
nikonLiveCapture = nil
|
||||
stopLiveTransferServices()
|
||||
liveTransferAlbumID = nil
|
||||
currentDriver?.disconnect()
|
||||
currentDriver = nil
|
||||
@ -305,12 +313,7 @@ final class ConnectionManager: NSObject, WiredCameraConnectionManaging {
|
||||
}
|
||||
|
||||
private func clearDeviceCache() {
|
||||
sonyRemoteCapture?.stop()
|
||||
sonyRemoteCapture = nil
|
||||
canonRemoteCapture?.stop()
|
||||
canonRemoteCapture = nil
|
||||
nikonLiveCapture?.stop()
|
||||
nikonLiveCapture = nil
|
||||
stopLiveTransferServices()
|
||||
cachedDevice = nil
|
||||
currentDriver?.disconnect()
|
||||
currentDriver = nil
|
||||
@ -428,24 +431,7 @@ private extension ConnectionManager {
|
||||
await runGetDeviceInfoProbe(on: camera)
|
||||
|
||||
case .sony:
|
||||
let transactionID: UInt32 = 1
|
||||
let result = await SonyPTPHelper.initializeRemoteSession(
|
||||
on: camera,
|
||||
startingTransactionID: transactionID
|
||||
)
|
||||
if result.success {
|
||||
let service = SonyRemoteCaptureService()
|
||||
service.onShotSaved = makeLiveShotSavedHandler()
|
||||
sonyRemoteCapture = service
|
||||
service.start(
|
||||
camera: camera,
|
||||
startingTransactionID: result.nextTransactionID,
|
||||
albumID: liveTransferAlbumID
|
||||
)
|
||||
OTGLog.info(.sony, "Sony remote session ready")
|
||||
} else {
|
||||
OTGLog.error(.sony, "Sony remote session setup failed")
|
||||
}
|
||||
await startSonyLiveTransferIfNeeded(for: camera)
|
||||
|
||||
default:
|
||||
await runGetDeviceInfoProbe(on: camera)
|
||||
@ -474,10 +460,12 @@ private extension ConnectionManager {
|
||||
/// catalog 就绪后再初始化 Canon 远程模式,避免 SetRemoteMode 打断 SD 卡枚举。
|
||||
private func startCanonLiveTransferIfNeeded(for camera: ICCameraDevice) {
|
||||
guard canonRemoteCapture == nil else { return }
|
||||
guard liveTransferAlbumID != nil else { return }
|
||||
guard PlatformDetector.detect(from: buildDeviceInfo(from: camera)) == .canon else { return }
|
||||
|
||||
Task { @MainActor in
|
||||
try? await Task.sleep(nanoseconds: 500_000_000)
|
||||
guard self.canonRemoteCapture == nil, self.liveTransferAlbumID != nil else { return }
|
||||
|
||||
let transactionID: UInt32 = 1
|
||||
let result = await CanonPTPHelper.initializeRemoteSession(
|
||||
@ -504,6 +492,7 @@ private extension ConnectionManager {
|
||||
/// catalog 就绪后启动尼康边拍边传(didAdd + catalog 轮询,无需 PTP 远程会话)。
|
||||
private func startNikonLiveTransferIfNeeded(for camera: ICCameraDevice) {
|
||||
guard nikonLiveCapture == nil else { return }
|
||||
guard liveTransferAlbumID != nil else { return }
|
||||
guard PlatformDetector.detect(from: buildDeviceInfo(from: camera)) == .nikon else { return }
|
||||
|
||||
let service = NikonCatalogLiveCaptureService()
|
||||
@ -513,6 +502,57 @@ private extension ConnectionManager {
|
||||
OTGLog.info(.nikon, "Nikon catalog live capture ready")
|
||||
}
|
||||
|
||||
private func startSonyLiveTransferIfNeeded(for camera: ICCameraDevice) async {
|
||||
guard sonyRemoteCapture == nil else { return }
|
||||
guard liveTransferAlbumID != nil else { return }
|
||||
guard PlatformDetector.detect(from: buildDeviceInfo(from: camera)) == .sony else { return }
|
||||
|
||||
let transactionID: UInt32 = 1
|
||||
let result = await SonyPTPHelper.initializeRemoteSession(
|
||||
on: camera,
|
||||
startingTransactionID: transactionID
|
||||
)
|
||||
guard liveTransferAlbumID != nil else { return }
|
||||
if result.success {
|
||||
let service = SonyRemoteCaptureService()
|
||||
service.onShotSaved = makeLiveShotSavedHandler()
|
||||
sonyRemoteCapture = service
|
||||
service.start(
|
||||
camera: camera,
|
||||
startingTransactionID: result.nextTransactionID,
|
||||
albumID: liveTransferAlbumID
|
||||
)
|
||||
OTGLog.info(.sony, "Sony remote session ready")
|
||||
} else {
|
||||
OTGLog.error(.sony, "Sony remote session setup failed")
|
||||
}
|
||||
}
|
||||
|
||||
private func resumeLiveTransferIfPossible() {
|
||||
guard let camera = cachedDevice, case .connected = state else { return }
|
||||
switch PlatformDetector.detect(from: buildDeviceInfo(from: camera)) {
|
||||
case .sony:
|
||||
Task { await startSonyLiveTransferIfNeeded(for: camera) }
|
||||
case .canon:
|
||||
guard isContentCatalogReady else { return }
|
||||
startCanonLiveTransferIfNeeded(for: camera)
|
||||
case .nikon:
|
||||
guard isContentCatalogReady else { return }
|
||||
startNikonLiveTransferIfNeeded(for: camera)
|
||||
case .unknown:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func stopLiveTransferServices() {
|
||||
sonyRemoteCapture?.stop()
|
||||
sonyRemoteCapture = nil
|
||||
canonRemoteCapture?.stop()
|
||||
canonRemoteCapture = nil
|
||||
nikonLiveCapture?.stop()
|
||||
nikonLiveCapture = nil
|
||||
}
|
||||
|
||||
private func makeLiveShotSavedHandler() -> (String) -> Void {
|
||||
{ [weak self] filename in
|
||||
guard let self, let albumID = self.liveTransferAlbumID else { return }
|
||||
@ -557,12 +597,7 @@ extension ConnectionManager: ICCameraDeviceDelegate {
|
||||
}
|
||||
|
||||
isClosingSession = false
|
||||
sonyRemoteCapture?.stop()
|
||||
sonyRemoteCapture = nil
|
||||
canonRemoteCapture?.stop()
|
||||
canonRemoteCapture = nil
|
||||
nikonLiveCapture?.stop()
|
||||
nikonLiveCapture = nil
|
||||
stopLiveTransferServices()
|
||||
currentDriver = nil
|
||||
isContentCatalogReady = false
|
||||
if let camera = device as? ICCameraDevice {
|
||||
|
||||
Reference in New Issue
Block a user