Skip to content

Commit 45e4339

Browse files
ensure that we can't put the remote or camera on a bad state
1 parent e703b54 commit 45e4339

7 files changed

Lines changed: 125 additions & 86 deletions

File tree

Pods/Pods.xcodeproj/project.pbxproj

Lines changed: 40 additions & 37 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

RemoteCam/CamStates.swift

Lines changed: 30 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,28 @@ import Photos
1313

1414
extension RemoteCamSession {
1515

16+
// MARK: - Camera Capabilities Retry Helper
17+
private func attemptToSendCapabilities(ctrl: CameraViewController, peer: MCPeerID, attempt: Int, maxAttempts: Int) {
18+
print("🔍 DEBUG: Attempt \(attempt)/\(maxAttempts) to gather camera capabilities")
19+
20+
ctrl.gatherAllCameraCapabilities()
21+
if let capabilities = ctrl.gatherCurrentCameraCapabilities() {
22+
print("✅ DEBUG: Successfully gathered capabilities on attempt \(attempt)")
23+
print("🔍 DEBUG: Sending camera capabilities - Available lenses: \(capabilities.getCurrentCameraInfo()?.availableLenses ?? [])")
24+
self.mailbox.addOperation(BlockOperation {
25+
self.sendCommandOrGoToScanning(peer: [peer], msg: capabilities)
26+
})
27+
} else if attempt < maxAttempts {
28+
let delay = Double(attempt) * 0.2 // 0.2s, 0.4s, 0.6s, 0.8s delays
29+
print("⏳ DEBUG: Attempt \(attempt) failed, retrying in \(delay)s")
30+
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
31+
self?.attemptToSendCapabilities(ctrl: ctrl, peer: peer, attempt: attempt + 1, maxAttempts: maxAttempts)
32+
}
33+
} else {
34+
print("❌ DEBUG: Failed to gather camera capabilities after \(maxAttempts) attempts")
35+
}
36+
}
37+
1638
func savePicture(_ imageData: Data) {
1739
PHPhotoLibrary.requestAuthorization { status in
1840
guard status == .authorized else {
@@ -90,69 +112,32 @@ extension RemoteCamSession {
90112
func camera(peer: MCPeerID,
91113
ctrl: CameraViewController,
92114
lobbyWrapper: Weak<DeviceScannerViewController>) -> Receive {
93-
var capabilitiesSent = false
94115

95116
return { [unowned self] (msg: Actor.Message) in
96117
guard lobbyWrapper.value != nil else {
97118
popAndStartScanning()
98119
return
99120
}
100121

101-
// Helper function to send capabilities if not already sent
102-
func sendCapabilitiesIfNeeded() {
103-
if !capabilitiesSent {
104-
print("🔍 DEBUG: First command received - gathering camera capabilities")
105-
ctrl.gatherAllCameraCapabilities()
106-
if let capabilities = ctrl.gatherCurrentCameraCapabilities() {
107-
print("🔍 DEBUG: Sending camera capabilities to monitor")
108-
print("🔍 DEBUG: Available lenses: \(capabilities.getCurrentCameraInfo()?.availableLenses ?? [])")
109-
self.sendCommandOrGoToScanning(peer: [peer], msg: capabilities)
110-
capabilitiesSent = true
111-
}
112-
}
113-
}
114-
115122
switch msg {
116123
case is OnEnter:
117124
print("🔍 DEBUG: Camera starting up")
118125
getFrameSender()?.tell(msg: SetSession(peer: peer, session: self))
119-
// Send capabilities after a brief delay to ensure camera is fully initialized
120-
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
121-
print("🔍 DEBUG: Camera entered - gathering and sending capabilities (delayed)")
122-
ctrl.gatherAllCameraCapabilities()
123-
if let capabilities = ctrl.gatherCurrentCameraCapabilities() {
124-
print("🔍 DEBUG: Sending camera capabilities to monitor")
125-
print("🔍 DEBUG: Available lenses: \(capabilities.getCurrentCameraInfo()?.availableLenses ?? [])")
126-
self.mailbox.addOperation(BlockOperation {
127-
self.sendCommandOrGoToScanning(peer: [peer], msg: capabilities)
128-
capabilitiesSent = true
129-
})
130-
} else {
131-
print("❌ DEBUG: Failed to gather current camera capabilities in OnEnter")
132-
}
133-
}
134126

135-
// MARK: - Monitor Join Handling
136127
case is RemoteCmd.PeerBecameMonitor:
137128
// When a new monitor joins, immediately send camera capabilities
138-
print("🔍 DEBUG: Camera received PeerBecameMonitor - sending capabilities immediately")
139-
ctrl.gatherAllCameraCapabilities()
140-
if let capabilities = ctrl.gatherCurrentCameraCapabilities() {
141-
print("🔍 DEBUG: Sending camera capabilities to new monitor")
142-
print("🔍 DEBUG: Available lenses: \(capabilities.getCurrentCameraInfo()?.availableLenses ?? [])")
143-
self.sendCommandOrGoToScanning(peer: [peer], msg: capabilities)
144-
} else {
145-
print("❌ DEBUG: Failed to gather current camera capabilities for new monitor")
146-
}
129+
print("🔍 DEBUG: Camera received PeerBecameMonitor - attempting to send capabilities")
130+
self.attemptToSendCapabilities(ctrl: ctrl, peer: peer, attempt: 1, maxAttempts: 5)
131+
132+
case is RemoteCmd.RequestCameraCapabilities:
133+
// When monitor explicitly requests capabilities
134+
print("🔍 DEBUG: Camera received RequestCameraCapabilities - attempting to gather capabilities")
135+
self.attemptToSendCapabilities(ctrl: ctrl, peer: peer, attempt: 1, maxAttempts: 5)
147136

148137
case is RemoteCmd.RequestFrame:
149-
// Send capabilities on first frame request, then handle normally
150-
sendCapabilitiesIfNeeded()
151138
self.receive(msg: msg)
152139

153140
case is RemoteCmd.SendFrame:
154-
// Send capabilities on first frame send, then handle normally
155-
sendCapabilitiesIfNeeded()
156141
self.receive(msg: msg)
157142

158143
case let m as UICmd.ToggleCameraResp:
@@ -179,7 +164,7 @@ extension RemoteCamSession {
179164
print("🔍 DEBUG: Camera received ToggleCamera command")
180165
let result = ctrl.toggleCamera()
181166
var resp: Message?
182-
if let (flashMode, position) = result.toOptional() {
167+
if let (_, position) = result.toOptional() {
183168
print("✅ DEBUG: Camera toggle success - new position: \(position)")
184169
// Send camera capabilities as part of the response
185170
let capabilities = ctrl.gatherCurrentCameraCapabilities()
@@ -191,7 +176,6 @@ extension RemoteCamSession {
191176
self.sendCommandOrGoToScanning(peer: [peer], msg: resp!)
192177

193178
case is RemoteCmd.ToggleFlash:
194-
sendCapabilitiesIfNeeded() // Ensure capabilities are sent
195179
let result = ctrl.toggleFlash()
196180
var resp: Message?
197181
if let flashMode = result.toOptional() {
@@ -203,7 +187,6 @@ extension RemoteCamSession {
203187

204188
// MARK: - Zoom Command Handling
205189
case let zoomCmd as RemoteCmd.SetZoom:
206-
sendCapabilitiesIfNeeded() // Ensure capabilities are sent
207190
print("🔍 DEBUG: Camera received SetZoom: \(zoomCmd.zoomFactor)")
208191
let result = ctrl.setZoom(zoomFactor: zoomCmd.zoomFactor)
209192
var resp: Message?
@@ -217,7 +200,6 @@ extension RemoteCamSession {
217200

218201
// MARK: - Lens Switching Command Handling
219202
case let lensCmd as RemoteCmd.SwitchLens:
220-
sendCapabilitiesIfNeeded() // Ensure capabilities are sent
221203
print("🔍 DEBUG: Camera received SwitchLens command to \(lensCmd.lensType.displayName)")
222204
let result = ctrl.switchLens(to: lensCmd.lensType)
223205
var resp: Message?

RemoteCam/MonitorPhotoStates.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,15 @@ extension RemoteCamSession {
7777
state: self.monitorSwitchingLens(monitor: monitor, peer: peer, lobby: lobby)
7878
)
7979
self.this ! msg
80+
81+
case is UICmd.RequestCameraCapabilities:
82+
// Request capabilities from camera
83+
self.sendCommandOrGoToScanning(peer: [peer], msg: RemoteCmd.RequestCameraCapabilities())
84+
85+
case is RemoteCmd.PeerBecameCamera:
86+
// When peer becomes camera, request fresh capabilities
87+
print("🔍 DEBUG: Monitor detected peer became camera - requesting fresh capabilities")
88+
self.sendCommandOrGoToScanning(peer: [peer], msg: RemoteCmd.RequestCameraCapabilities())
8089

8190
case let mode as UICmd.BecomeMonitor:
8291
if mode.mode == RecordingMode.Video {

RemoteCam/MonitorVideoStates.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,15 @@ extension MonitorVideoStates {
7878
state: self.monitorSwitchingLens(monitor: monitor, peer: peer, lobby: lobby)
7979
)
8080
self.this ! msg
81+
82+
case is UICmd.RequestCameraCapabilities:
83+
// Request capabilities from camera
84+
self.sendCommandOrGoToScanning(peer: [peer], msg: RemoteCmd.RequestCameraCapabilities())
85+
86+
case is RemoteCmd.PeerBecameCamera:
87+
// When peer becomes camera, request fresh capabilities
88+
print("🔍 DEBUG: Monitor detected peer became camera - requesting fresh capabilities")
89+
self.sendCommandOrGoToScanning(peer: [peer], msg: RemoteCmd.RequestCameraCapabilities())
8190

8291
case let c as DisconnectPeer:
8392
if c.peer.displayName == peer.displayName && self.session.connectedPeers.count == 0 {

RemoteCam/MonitorViewController.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,11 +246,13 @@ public class MonitorViewController: iAdViewController, UIImagePickerControllerDe
246246

247247
override public func viewWillAppear(_ animated: Bool) {
248248
super.viewWillAppear(animated)
249+
print("🔍 DEBUG: MonitorViewController viewWillAppear - \(ObjectIdentifier(self))")
249250
self.navigationController?.isNavigationBarHidden = true
250251
}
251252

252253
override public func viewDidLoad() {
253254
super.viewDidLoad()
255+
print("🔍 DEBUG: MonitorViewController viewDidLoad - \(ObjectIdentifier(self))")
254256
monitor ! SetViewCtrl(ctrl: self)
255257
self.configureTimerUI()
256258
self.setupProgrammaticZoomAndLensControls()
@@ -264,15 +266,30 @@ public class MonitorViewController: iAdViewController, UIImagePickerControllerDe
264266
self.imageView.contentMode = .scaleAspectFit
265267
recordingView.image = UIImage.gifImageWithName("recording")
266268
configurePhotoMode()
269+
270+
// Request camera capabilities after MonitorActor is fully set up
271+
// This handles the race condition where capabilities arrive before viewDidLoad
272+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
273+
print("🔍 DEBUG: Requesting camera capabilities after MonitorActor setup")
274+
if let session = self?.session {
275+
session ! UICmd.RequestCameraCapabilities()
276+
}
277+
278+
}
267279
}
268280

269281
deinit {
282+
print("🔍 DEBUG: MonitorViewController deinit - \(ObjectIdentifier(self))")
270283
print("stop monitor")
271284
self.timer.cancel()
272285
self.zoomLabelTimer?.invalidate()
273286
self.soundManager.stopPlayer()
274287
session ! UICmd.UnbecomeMonitor(sender: nil)
275-
monitor ! Actor.Harakiri(sender: nil)
288+
289+
// Delay actor destruction to allow pending messages to arrive
290+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [monitor] in
291+
monitor ! Actor.Harakiri(sender: nil)
292+
}
276293
}
277294

278295
let buttonPromptPhotoMode = NSLocalizedString("Taking picture", comment: "")

RemoteCam/RemoteCmds.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,4 +675,17 @@ public class RemoteCmd: Actor.Message {
675675
super.init(sender: nil)
676676
}
677677
}
678+
679+
@objc(_TtCC10ActorsDemo9RemoteCmd23RequestCameraCapabilities)public class RequestCameraCapabilities: Actor.Message, NSCoding {
680+
public init() {
681+
super.init(sender: nil)
682+
}
683+
684+
public func encode(with aCoder: NSCoder) {
685+
}
686+
687+
public required init?(coder aDecoder: NSCoder) {
688+
super.init(sender: nil)
689+
}
690+
}
678691
}

RemoteCam/UICmds.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ public class UICmd {
112112
}
113113
}
114114

115+
public class RequestCameraCapabilities: Actor.Message {
116+
public init() {
117+
super.init(sender: nil)
118+
}
119+
}
120+
115121
// MARK: - Zoom Commands
116122
@objc(_TtCC10ActorsDemo5UICmd8SetZoom)public class SetZoom: Actor.Message, NSCoding {
117123
public let zoomFactor: CGFloat

0 commit comments

Comments
 (0)