import UIKit import Foundation let decoder = JSONDecoder() let encoder = JSONEncoder() struct ObsMessage { struct OpCodeOnly { let op: Int } struct Unknown: Codable { let op: Int let d: D? typealias D = Dictionary } struct Hello: Codable { /// op: 0 let op: Int let d: D struct D: Codable { let obsWebSocketVersion: String let rpcVersion: Int } } struct Identify: Codable { /// op: 1 let op: Int let d: D struct D: Codable { let rpcVersion: Int } } struct Identified: Codable { /// op: 2 let op: Int let d: D struct D: Codable { let negotiatedRpcVersion: Int } } struct Reidentify: Codable { /// op: 3 let op: Int let d: D struct D: Codable { let eventSubscriptions: EventSubscription? } struct EventSubscription: OptionSet, Codable { var rawValue: Int } } } extension ObsMessage { static func identify() -> Identify { .init(op: 1, d: .init(rpcVersion: 1)) } static func reidentify() -> Reidentify { .init(op: 3, d: .init(eventSubscriptions: nil)) } } extension ObsMessage.Hello { static func from(webSocketTaskMessage message: URLSessionWebSocketTask.Message) throws -> Self { guard case .string(let msg) = message else { print("Hello message is not String") let e = NSError() throw e } return try decoder.decode(Self.self, from: msg.data(using: .utf8)!) } } extension ObsMessage.Identified { static func from(webSocketTaskMessage message: URLSessionWebSocketTask.Message) throws -> Self { guard case .string(let msg) = message else { print("Hello message is not String") let e = NSError() throw e } return try decoder.decode(Self.self, from: msg.data(using: .utf8)!) } } class Handler: NSObject { } extension Handler: URLSessionDelegate{ } extension Handler: URLSessionTaskDelegate{ } extension Handler: URLSessionWebSocketDelegate { func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) { print("WebSocket did open. protocol:", `protocol` ?? "none") Task { let hello_msg = try await webSocketTask.receive() print("hello_msg:", hello_msg) let hello = try! ObsMessage.Hello.from(webSocketTaskMessage: hello_msg) print("decoded: ", hello) let identify = try! encoder.encode(ObsMessage.identify()) try await webSocketTask.send(.string(String(data: identify, encoding: .utf8)!)) let identified_msg = try await webSocketTask.receive() let identified = try! ObsMessage.Identified.from(webSocketTaskMessage: identified_msg) print("identified: ", identified) let reidentidy = try! encoder.encode(ObsMessage.reidentify()) try await webSocketTask.send(.string(String(data: reidentidy, encoding: .utf8)!)) let reidentified_msg = try await webSocketTask.receive() let reidentified = try! ObsMessage.Identified.from(webSocketTaskMessage: reidentified_msg) print("reidentified: ", reidentified) // event loop while(true) { let msg = try await webSocketTask.receive() print("msg:", msg) } } } func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) { print("WebSocket did close. closeCode:", closeCode) } } let host = "192.168.1.x" let port = "4455" // default of obs-websocket v5.0.0 let endpoint = URL(string: "ws://\(host):\(port)")! var req = URLRequest(url: endpoint) req.setValue("obswebsocket.json", forHTTPHeaderField: "Sec-WebSocket-Protocol") let s = URLSession.shared // let t = s.webSocketTask(with: endpoint) let t = s.webSocketTask(with: endpoint, protocols: ["obswebsocket.json"]) // let t = s.webSocketTask(with: req) let delegate = Handler() t.delegate = delegate t.resume()