完善 OTG 相机有线传图:支持 Sony/Canon 自动识别,页面 detach 保持会话以便再次进入复连。
引入进程级 CameraTetheringSession 与共享 USB Browser;离开传图页仅取消 UI 回调,App 终止时再完整 shutdown 释放 PTP 与 Browser 资源。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -2,26 +2,73 @@
|
||||
|
||||
## 职责
|
||||
|
||||
提供 USB OTG 相机有线连接与 Sony PTP 边拍边传能力,不包含业务 API 或 OSS 上传。
|
||||
提供 USB OTG 相机有线连接与 Sony/Canon PTP 边拍边传能力,不包含业务 API 或 OSS 上传。
|
||||
|
||||
## 核心组件
|
||||
|
||||
| 组件 | 说明 |
|
||||
| --- | --- |
|
||||
| `CameraServiceProtocol` | 相机服务抽象,上层只依赖此协议 |
|
||||
| `SonyCameraService` | Sony 相机实现,封装 PTP 下载与连接状态 |
|
||||
| `ImageCaptureDeviceManager` | ImageCaptureCore 设备浏览、会话与 PTP 事件 |
|
||||
| `SonyPTPCommands` | Sony SDIO/PTP 命令封装 |
|
||||
| `CameraTetheringSession` | 进程级单例,持有共享 `AutoDetectCameraService` |
|
||||
| `AutoDetectCameraService` | 按 USB Vendor ID 自动识别品牌并委托 |
|
||||
| `SonyCameraService` | Sony 相机实现,封装 SDIO/PTP 下载 |
|
||||
| `CanonCameraService` | Canon EOS 相机实现,封装 GetEvent/PTP 下载 |
|
||||
| `ImageCaptureDeviceManager` | Sony ICC 设备管理 |
|
||||
| `CanonImageCaptureDeviceManager` | Canon ICC 设备管理 |
|
||||
| `PTPHelper` | 共享 PTP 编解码与命令发送 |
|
||||
| `CameraDownloadStorage` | 本地下载作用域、目录与文件名消毒 |
|
||||
|
||||
## 品牌识别
|
||||
|
||||
插入 USB 相机后,`AutoDetectCameraService` 读取 `ICCameraDevice.usbVendorID`:
|
||||
|
||||
- `0x054C` → Sony
|
||||
- `0x04A9` → Canon
|
||||
- 其他 → 提示不支持的相机品牌
|
||||
|
||||
## 业务流程
|
||||
|
||||
1. `SonyCameraService.connect()` 启动 USB 设备搜索。
|
||||
2. 授权通过后打开 ICC 会话并执行 Sony SDIO 握手。
|
||||
3. 拍摄事件触发 PTP 下载,底层先写入临时目录,再由传输管道按账号与相册移入业务目录。
|
||||
4. 通过 `onNewAsset` 回调通知上层有新照片。
|
||||
1. `AutoDetectCameraService.connect()` 启动 USB 设备搜索(或复用已有连接)。
|
||||
2. 发现相机并完成系统授权后,按 Vendor ID 创建品牌 Service 并 attach。
|
||||
3. 品牌 Service 打开 ICC 会话并执行品牌专有 PTP 握手(Sony SDIO / Canon SetRemoteMode)。
|
||||
4. 拍摄事件触发 PTP 下载或 catalog 回退,底层先写入临时目录。
|
||||
5. 通过 `onNewAsset` 回调通知上层有新照片。
|
||||
|
||||
## 相机端前置条件
|
||||
|
||||
- **Sony**:设为电脑遥控(PC Remote)模式
|
||||
- **Canon**:设为电脑遥控 / PC Remote / 照片传输(PTP)模式
|
||||
- 均需关闭「仅充电」模式
|
||||
|
||||
## 依赖
|
||||
|
||||
- ImageCaptureCore(系统框架)
|
||||
- 无第三方库依赖
|
||||
|
||||
## 页面生命周期与资源释放
|
||||
|
||||
OTG 相机连接由 `CameraTetheringSession.sharedService` 进程级持有;`CameraServiceFactory.makeAutoDetect()` 始终返回该单例。
|
||||
|
||||
**进入 OTG 页:**
|
||||
|
||||
1. `.task` 调用 `WiredCameraTransferViewModel.start()`。
|
||||
2. `pipeline.attachToUI(...)` 绑定 UI 回调。
|
||||
3. `connect()` 启动或复用 USB 搜索;若已连接则跳过 attach,同步状态并补发 detach 期间缓冲的新片。
|
||||
4. 发现相机后按 Vendor ID attach 品牌服务,打开 ICC 会话并执行 PTP 握手。
|
||||
|
||||
**离开 OTG 页(detach):**
|
||||
|
||||
1. `.task` 取消或 `onDisappear` 触发 `detachFromUI()`(幂等)。
|
||||
2. 仅清空 `onNewAsset` / `onConnectionStateChange` 等 UI 回调,取消 Pipeline 上传/通知任务。
|
||||
3. **不** PTP CloseSession、**不** stop Browser、**不** nil `activeService`。
|
||||
4. 底层 D215 轮询与 PTP 下载可继续,新片写入 `pendingAssetsWhileDetached`,再次进入时 flush。
|
||||
|
||||
**App 即将终止(shutdown):**
|
||||
|
||||
1. `AppDelegate.applicationWillTerminate` 调用 `CameraTetheringSession.shutdown()`。
|
||||
2. 品牌 Service 完整断开(Sony 先 `Position_Key_Setting=Local` 再 PTP CloseSession)。
|
||||
3. `usbBrowser.stop()` 停止 USB Browser 并释放授权状态。
|
||||
|
||||
进入后台**不**主动 shutdown;系统挂起 USB 时由 `deviceBrowserDidResumeOperations` 处理恢复。
|
||||
|
||||
若返回后再进入无法连接,优先检查日志中是否出现「会话关闭超时」或在非 terminate 场景误调用了 `shutdown()`。
|
||||
|
||||
Reference in New Issue
Block a user