diff options
Diffstat (limited to 'app/src/main/java/invalid/lena/scrcpy/Session.java')
| -rw-r--r-- | app/src/main/java/invalid/lena/scrcpy/Session.java | 52 |
1 files changed, 7 insertions, 45 deletions
diff --git a/app/src/main/java/invalid/lena/scrcpy/Session.java b/app/src/main/java/invalid/lena/scrcpy/Session.java index 294b27d..39ef38a 100644 --- a/app/src/main/java/invalid/lena/scrcpy/Session.java +++ b/app/src/main/java/invalid/lena/scrcpy/Session.java @@ -67,22 +67,8 @@ public final class Session { // deterministic failure walks the ladder and then gives up. private static final long[] RECONNECT_BACKOFF_MS = {1_000L, 2_000L, 5_000L, 10_000L, 15_000L}; - // Comfortably longer than STALL_MS + STALL_POLL_MS. If it were not, - // a stall-detected drop would always look "healthy" (a stall is only - // declared after STALL_MS of silence, so the connection is at least - // that old by then), the budget would reset on every stall and the - // ladder would never be reached for the one failure it exists for. private static final long HEALTHY_MS = 120_000L; - // Stall watchdog. adb streams have no read timeout - AdbStream.read() - // waits on its queue until data arrives or the stream is closed - so a - // target that disappears without closing the socket (Wi-Fi dropping - // mid-frame, NAT rebinding, a carrier idle timeout on a VPN link) - // leaves the readers parked and the session frozen forever with no - // reconnect. Poll for silence on the audio socket instead; see - // AudioStream.isStarted() for why audio and not video. - private static final long STALL_MS = 30_000L; - private static final long STALL_POLL_MS = 5_000L; private static final long BRING_UP_DEADLINE_MS = 90_000L; private static final long STOP_JOIN_MS = 10_000L; @@ -118,9 +104,8 @@ public final class Session { } } - // Counted down by the video reader when its loop exits; the session - // thread parks on it for the live duration of a connection. Swapped - // for a fresh latch on each reconnect cycle. + // Counted down when video or control ends; audio is optional and never + // ends a session. Swapped for a fresh latch on each reconnect cycle. private volatile CountDownLatch endSignal = new CountDownLatch(1); public Session(Context ctx, Adb adb, Devices.Device target, Surface surface, Listener listener) { @@ -242,14 +227,12 @@ public final class Session { if (!connect()) return; // gave up: onError + onStopped fired long upAt = monotonicMs(); CountDownLatch latch; - AudioStream as; synchronized (this) { if (stopped) return; latch = endSignal; - as = audioStream; } try { - awaitEndOrStall(latch, as); + latch.await(); } catch (InterruptedException ie) { return; } @@ -286,29 +269,6 @@ public final class Session { } } - // Park until the pipeline dies, stop() fires, or the audio socket has - // been silent long enough that the link must be gone. Returning - // without the latch firing leaves the readers parked; the caller's - // tearDownInstalled() closes their streams, which unblocks them. - // - // The watchdog only arms once audio is actually flowing. If the - // target cannot capture audio the server reports the stream disabled, - // AudioStream returns immediately, and there is no reliable idle - // signal left - in that case fall back to waiting indefinitely rather - // than inventing one from the video socket, which is legitimately - // silent whenever the target's screen is static. - private void awaitEndOrStall(CountDownLatch latch, AudioStream as) - throws InterruptedException { - while (!latch.await(STALL_POLL_MS, TimeUnit.MILLISECONDS)) { - if (stopped || as == null || !as.isStarted()) continue; - long idle = monotonicMs() - as.lastPacketAtMs(); - if (idle >= STALL_MS) { - Log.w("session: no audio for %d ms - link presumed dead", idle); - return; - } - } - } - // Run the bring-up retry ladder once. Returns true when a session is // live (read threads started); false if the budget was exhausted, in // which case onError() + onStopped() have already fired. @@ -429,8 +389,10 @@ public final class Session { ctrl = new Controller(ctx, cs::send); cs.setInboundSink(ctrl); - ak = new AudioSink(ended); - as = new AudioStream(s.audioIn, ak, ended); + // Audio is optional. Failure to capture or play it must not tear + // down video and control. + ak = new AudioSink(); + as = new AudioStream(s.audioIn, ak); vk = new VideoSink(surface, ended); Controller ctrlRef = ctrl; |