Preserve legacy timestamp waits and validate actual surface acknowledgements

This commit is contained in:
evgeny committed 2026-10-20 00:42:05 +02:00
1 parent 3eccf58c5e
commit dd5dee2767
2 files changed
+19 -7

No files matched your search

@@ -268,7 +268,8 @@ private class CallVideoTexture(context: Context, private val video: CallVideoEng
val now = System.nanoTime(); commits++
if (updateAt != 0L) { commitMaxUs = maxOf(commitMaxUs, (now - updateAt) / 1000); updateAt = 0 }
// Если timestamp ещё старый, новое TextureView update само назначит draw/commit.
video.presented(surface, texture.timestamp / 1000)
val matched = video.presented(surface, texture.timestamp / 1000)
if (!matched && (Build.VERSION.SDK_INT < 29 || !isHardwareAccelerated)) postOnAnimation { consumed(texture, surface) }
if (reportAt == 0L) reportAt = now
if (now - reportAt >= 1_000_000_000) {
LogManager.addLog("DEBUG", "call", "video surface intervalMs=${(now - reportAt) / 1_000_000} " +
@@ -38,7 +38,7 @@ public final class VideoSurfaceProbeActivity extends Activity implements Texture
private volatile boolean cancelled;
private volatile long expectedPts = -1, submittedAt;
private final AtomicInteger submitted = new AtomicInteger();
private int acknowledged, updates, mismatches, lastReported;
private int acknowledged, updates, staleChecks, lastReported;
private int fps;
private boolean legacy;
private long started, ackMaxUs;
@@ -50,10 +50,11 @@ public final class VideoSurfaceProbeActivity extends Activity implements Texture
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
producer.start(); render = new Handler(producer.getLooper());
view = new TextureView(this); view.setSurfaceTextureListener(this); setContentView(view);
Log.i(TAG, "start legacy=" + legacy + " fps=" + fps + " hardware=" + getWindow().getAttributes().flags);
Log.i(TAG, "start legacy=" + legacy + " fps=" + fps);
}
@Override public void onSurfaceTextureAvailable(SurfaceTexture next, int width, int height) {
Log.i(TAG, "surface available hardware=" + view.isHardwareAccelerated() + " view=" + width + "x" + height);
texture = next; next.setDefaultBufferSize(640, 360); surface = new Surface(next);
observer = view.getViewTreeObserver(); observer.addOnPreDrawListener(this);
render.post(() -> {
@@ -89,7 +90,12 @@ public final class VideoSurfaceProbeActivity extends Activity implements Texture
private void committed() {
if (cancelled || texture == null || expectedPts < 0) return;
long pts = texture.getTimestamp() / 1000;
if (pts != expectedPts) { mismatches++; Log.w(TAG, "timestamp actual=" + pts + " expected=" + expectedPts); return; }
// Посторонний UI draw может завершиться до прихода следующего буфера. Это не ACK:
// ожидаем TextureView update, который сам создаст следующий draw/commit.
if (pts != expectedPts) {
if (++staleChecks == 1) Log.d(TAG, "defer ACK timestamp=" + pts + " expected=" + expectedPts);
return;
}
expectedPts = -1; acknowledged++;
ackMaxUs = Math.max(ackMaxUs, (System.nanoTime() - submittedAt) / 1000);
long next = started + submitted.get() * 1_000_000_000L / fps;
@@ -125,14 +131,19 @@ public final class VideoSurfaceProbeActivity extends Activity implements Texture
+ " advanced=" + (acknowledged - lastReported) + " updates=" + updates + " ackMaxUs=" + ackMaxUs);
lastReported = acknowledged;
if (elapsed >= 8_000_000_000L) {
boolean valid = legacy ? acknowledged < 30 : acknowledged >= fps * 8 * 0.8 && mismatches == 0;
boolean valid = legacy ? acknowledged < 30 : acknowledged >= fps * 8 * 0.8
&& acknowledged <= submitted.get() && submitted.get() - acknowledged <= 1;
Log.i(TAG, "RESULT " + (valid ? "PASS" : "FAIL") + " legacy=" + legacy + " targetFps=" + fps + " submitted=" + submitted.get()
+ " acknowledged=" + acknowledged + " updates=" + updates + " mismatches=" + mismatches + " ackMaxUs=" + ackMaxUs);
+ " acknowledged=" + acknowledged + " updates=" + updates + " staleChecks=" + staleChecks + " ackMaxUs=" + ackMaxUs);
finish(); return;
}
view.invalidate(); main.postDelayed(this::tick, 500);
}
@Override protected void onStop() { cancelled = true; super.onStop(); }
@Override protected void onStop() {
cancelled = true;
if (texture == null) { Log.i(TAG, "stopped before surface became available"); producer.quitSafely(); }
super.onStop();
}
private static void check(boolean condition, String stage) {
if (!condition) throw new IllegalStateException(stage + " EGL error=" + EGL14.eglGetError());
}