aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/invalid/lena/scrcpy/Session.java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/invalid/lena/scrcpy/Session.java')
-rw-r--r--app/src/main/java/invalid/lena/scrcpy/Session.java52
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;