Bug: b/307672498 Change-Id: Ia50f514ff9ecbd273953fc1eab55340b75728a4f Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/325185 Commit-Queue: Linus Nilsson <lnilsson@webrtc.org> Reviewed-by: Zoé Lepaul <xalep@webrtc.org> Cr-Commit-Position: refs/heads/main@{#41094}
124 lines
3.7 KiB
Java
124 lines
3.7 KiB
Java
/*
|
|
* Copyright 2023 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
package org.webrtc;
|
|
|
|
import static java.lang.Math.ceil;
|
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
|
import static org.mockito.Mockito.inOrder;
|
|
import static org.mockito.Mockito.times;
|
|
import static org.mockito.Mockito.verify;
|
|
|
|
import androidx.test.runner.AndroidJUnit4;
|
|
import java.time.Duration;
|
|
import org.junit.Before;
|
|
import org.junit.Test;
|
|
import org.junit.runner.RunWith;
|
|
import org.mockito.InOrder;
|
|
import org.mockito.Mock;
|
|
import org.mockito.MockitoAnnotations;
|
|
import org.robolectric.annotation.Config;
|
|
import org.robolectric.shadows.ShadowLooper;
|
|
import org.robolectric.shadows.ShadowChoreographer;
|
|
|
|
@RunWith(AndroidJUnit4.class)
|
|
@Config(manifest = Config.NONE)
|
|
public class RenderSynchronizerTest {
|
|
|
|
private static final Duration FRAME_DELAY = Duration.ofMillis(16);
|
|
private static final float DEFAULT_FRAME_RATE = 30f;
|
|
|
|
@Mock private RenderSynchronizer.Listener mockListener;
|
|
private RenderSynchronizer renderSynchronizer;
|
|
private Duration refreshDelay;
|
|
private float frameRate;
|
|
|
|
@Before
|
|
public void setUp() {
|
|
MockitoAnnotations.initMocks(this);
|
|
ShadowChoreographer.setPaused(true);
|
|
}
|
|
|
|
private void init(float displayRefreshRate, float renderFrameRate) {
|
|
refreshDelay = Duration.ofMillis((long)ceil(1000 / displayRefreshRate));
|
|
frameRate = renderFrameRate;
|
|
|
|
ShadowChoreographer.setFrameDelay(refreshDelay);
|
|
renderSynchronizer = new RenderSynchronizer(renderFrameRate);
|
|
renderSynchronizer.registerListener(mockListener);
|
|
}
|
|
|
|
@Test
|
|
public void renderWindowOpensOnFirstFrame() {
|
|
init(/* displayRefreshRate= */60f, /* renderFrameRate= */30f);
|
|
|
|
advanceOneRefreshCycle();
|
|
verify(mockListener).onRenderWindowOpen();
|
|
}
|
|
|
|
@Test
|
|
public void doubleDisplayRefreshRate() {
|
|
init(/* displayRefreshRate= */60f, /* renderFrameRate= */30f);
|
|
|
|
InOrder inOrder = inOrder(mockListener);
|
|
for (int i = 0; i < 10; ++i) {
|
|
advanceOneRefreshCycle();
|
|
inOrder.verify(mockListener).onRenderWindowOpen();
|
|
|
|
advanceOneRefreshCycle();
|
|
inOrder.verify(mockListener).onRenderWindowClose();
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void trippleRefreshRate() {
|
|
init(/* displayRefreshRate= */90f, /* renderFrameRate= */30f);
|
|
InOrder inOrder = inOrder(mockListener);
|
|
for (int i = 0; i < 10; ++i) {
|
|
advanceOneRefreshCycle();
|
|
inOrder.verify(mockListener).onRenderWindowOpen();
|
|
|
|
advanceOneRefreshCycle();
|
|
inOrder.verify(mockListener).onRenderWindowClose();
|
|
|
|
advanceOneRefreshCycle();
|
|
// No action expected, window stays closed/
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void equalRefreshRate() {
|
|
init(/* displayRefreshRate= */30f, /* renderFrameRate= */30f);
|
|
for (int i = 0; i < 10; ++i) {
|
|
advanceOneRefreshCycle();
|
|
}
|
|
verify(mockListener, times(10)).onRenderWindowOpen();
|
|
verify(mockListener, times(0)).onRenderWindowClose();
|
|
}
|
|
|
|
@Test
|
|
public void halfRefreshRate() {
|
|
init(/* displayRefreshRate= */30f, /* renderFrameRate= */60f);
|
|
for (int i = 0; i < 10; ++i) {
|
|
advanceOneRefreshCycle();
|
|
}
|
|
verify(mockListener, times(10)).onRenderWindowOpen();
|
|
verify(mockListener, times(0)).onRenderWindowClose();
|
|
}
|
|
|
|
private void advanceOneRefreshCycle() {
|
|
advanceBy(refreshDelay);
|
|
}
|
|
|
|
private void advanceBy(Duration duration) {
|
|
ShadowLooper.idleMainLooper(duration.toMillis(), MILLISECONDS);
|
|
}
|
|
}
|