diff --git a/Sources/ForgeCameraSony/SonyDriver.swift b/Sources/ForgeCameraSony/SonyDriver.swift index f17756f..95447a0 100644 --- a/Sources/ForgeCameraSony/SonyDriver.swift +++ b/Sources/ForgeCameraSony/SonyDriver.swift @@ -14,13 +14,18 @@ enum SonyPaths { static let userLut = "/cna/v1/monitoring/lut" } -/// Venice 2 driver: REST over IP. Capability-narrow — user 3D LUT push only, -/// no native CDL (grade pipeline must full-bake for this camera). +/// Venice 2 driver — POSTURE PER RESEARCH (docs/research/arri-cap-protocol.md, Sony +/// section): Venice IP protocol is CLOSED (partner products speak it natively; public +/// path is only the authenticated web remote at /rmt.html). This driver keeps our +/// provisional REST shape for the simulator and future backend-capture correction, +/// but capabilities are downgraded: NO look push claimed (lut3dSizes empty, +/// no native CDL) until verified on hardware/partner docs. On-set Venice grading +/// path today = SDI-chain LUT box / DeckLink output, not camera-internal. public actor SonyDriver: CameraDriver { public nonisolated let capabilities = CameraCapabilities( vendor: .sony, supportsNativeCDL: false, - lut3dSizes: [17, 33], + lut3dSizes: [], metadataFields: [.clipName, .exposureIndex, .whiteBalance, .tint, .fps, .timecode]) private let host: String @@ -118,26 +123,11 @@ public actor SonyDriver: CameraDriver { } public func push(look: FlattenedLook) async throws { - guard look.cdl == nil else { - throw CameraError.unsupportedLook("Venice has no native CDL — re-flatten with splitLeadingCDL=false") - } - guard let lut = look.lut else { - throw CameraError.unsupportedLook("nothing to push") - } - guard capabilities.lut3dSizes.contains(lut.size) else { - throw CameraError.unsupportedLook("LUT size \(lut.size) not in \(capabilities.lut3dSizes)") - } - let payload = try JSONSerialization.data( - withJSONObject: ["size": lut.size, "table": lut.table], - options: [.sortedKeys]) - var req = URLRequest(url: url(SonyPaths.userLut)) - req.httpMethod = "PUT" - req.httpBody = payload - req.setValue("application/json", forHTTPHeaderField: "Content-Type") - let (_, http) = try await perform(req) - guard http.statusCode == 200 else { - throw CameraError.pushFailed("LUT upload -> \(http.statusCode)") - } + // Venice IP look control is closed/unverified (see research doc). + // Grade Venice via SDI-chain LUT box or DeckLink output. Re-enable + // once a real wire path is proven (partner SDK or backend capture). + throw CameraError.unsupportedLook( + "Venice look push over IP unverified — use SDI-chain LUT box; monitoring-only driver") } // MARK: Polling diff --git a/Tests/ForgeCameraSonyTests/SonyDriverTests.swift b/Tests/ForgeCameraSonyTests/SonyDriverTests.swift index 4dc395e..828cfd1 100644 --- a/Tests/ForgeCameraSonyTests/SonyDriverTests.swift +++ b/Tests/ForgeCameraSonyTests/SonyDriverTests.swift @@ -28,12 +28,12 @@ final class SonyDriverTests: XCTestCase { return SonyDriver(host: "127.0.0.1", port: port, pollInterval: .milliseconds(20)) } - // Venice 2: NO native CDL — capability-narrow. + // Venice 2: protocol closed (research) — no look-push capability claimed. func testCapabilities() async { let driver = await makeDriver() XCTAssertEqual(driver.capabilities.vendor, .sony) XCTAssertFalse(driver.capabilities.supportsNativeCDL) - XCTAssertTrue(driver.capabilities.lut3dSizes.contains(33)) + XCTAssertTrue(driver.capabilities.lut3dSizes.isEmpty) } func testConnectEmitsConnected() async throws { @@ -70,26 +70,24 @@ final class SonyDriverTests: XCTestCase { await driver.disconnect() } - // LUT-only push accepted. - func testPushLutOnly() async throws { + // Any look push rejected: Venice look control unverified/closed (research). + // Metadata/rec-state monitoring is the only claimed capability. + func testAnyPushRejected() async throws { let driver = await makeDriver() try await driver.connect() - let look = FlattenedLook(cdl: nil, lut: Lut3D.identity(size: 33), latticeSize: 33) - try await driver.push(look: look) - let count = await sim.uploadedLutCount - XCTAssertEqual(count, 1) - await driver.disconnect() - } - // Push with split CDL to a no-native-CDL camera must throw unsupportedLook — - // caller (gang layer) is responsible for re-flattening full-bake. - func testPushSplitCDLRejected() async throws { - let driver = await makeDriver() - try await driver.connect() - let cdl = CDL(slope: SIMD3(1.2, 1, 1), offset: .zero, power: .one, saturation: 1) - let look = FlattenedLook(cdl: cdl, lut: Lut3D.identity(size: 33), latticeSize: 33) + let lutOnly = FlattenedLook(cdl: nil, lut: Lut3D.identity(size: 33), latticeSize: 33) do { - try await driver.push(look: look) + try await driver.push(look: lutOnly) + XCTFail("expected unsupportedLook") + } catch let e as CameraError { + guard case .unsupportedLook = e else { return XCTFail("wrong error") } + } + + let cdl = CDL(slope: SIMD3(1.2, 1, 1), offset: .zero, power: .one, saturation: 1) + let withCDL = FlattenedLook(cdl: cdl, lut: nil, latticeSize: 33) + do { + try await driver.push(look: withCDL) XCTFail("expected unsupportedLook") } catch let e as CameraError { guard case .unsupportedLook = e else { return XCTFail("wrong error") }