1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.car; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.junit.Assume.assumeTrue; 22 23 import android.car.Car; 24 import android.car.evs.CarEvsBufferDescriptor; 25 import android.car.evs.CarEvsManager; 26 import android.car.evs.CarEvsManager.CarEvsStreamEvent; 27 import android.car.evs.CarEvsStatus; 28 import android.os.SystemClock; 29 import android.util.Log; 30 31 import androidx.test.core.app.ApplicationProvider; 32 import androidx.test.filters.MediumTest; 33 import androidx.test.runner.AndroidJUnit4; 34 35 import org.junit.After; 36 import org.junit.Before; 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 40 import java.util.ArrayList; 41 import java.util.concurrent.ExecutorService; 42 import java.util.concurrent.Executors; 43 import java.util.concurrent.Semaphore; 44 import java.util.concurrent.TimeUnit; 45 46 /* 47 * IMPORTANT NOTE: 48 * This test assumes that EVS HAL is running at the time of test. Depending on the test target, the 49 * reference EVS HAL ($ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver) may be needed. 50 * Please add below line to the target's build script to add the reference EVS HAL to the build: 51 * ENABLE_EVS_SAMPLE := true 52 * 53 * The test will likely fail if no EVS HAL is running on the target device. 54 */ 55 @RunWith(AndroidJUnit4.class) 56 @MediumTest 57 public final class CarEvsManagerTest extends MockedCarTestBase { 58 private static final String TAG = CarEvsManagerTest.class.getSimpleName(); 59 60 // We'd expect that underlying stream runs @10fps at least. 61 private static final int NUMBER_OF_FRAMES_TO_WAIT = 10; 62 private static final int FRAME_TIMEOUT_MS = 1000; 63 private static final int SMALL_NAP_MS = 500; 64 private static final int STREAM_EVENT_TIMEOUT_SEC = 2; 65 66 // Will return frame buffers in the order they arrived. 67 private static final int INDEX_TO_FIRST_ELEM = 0; 68 69 private final ArrayList<CarEvsBufferDescriptor> mReceivedBuffers = new ArrayList<>(); 70 private final ExecutorService mCallbackExecutor = Executors.newFixedThreadPool(1); 71 private final Semaphore mFrameReceivedSignal = new Semaphore(0); 72 private final Semaphore mStreamEventOccurred = new Semaphore(0); 73 74 private final Car mCar = Car.createCar(ApplicationProvider.getApplicationContext()); 75 private final CarEvsManager mEvsManager = 76 (CarEvsManager) mCar.getCarManager(Car.CAR_EVS_SERVICE); 77 private final EvsStreamCallbackImpl mStreamCallback = new EvsStreamCallbackImpl(); 78 private final EvsStatusListenerImpl mStatusListener = new EvsStatusListenerImpl(); 79 80 private @CarEvsStreamEvent int mLastStreamEvent; 81 82 @Before setUp()83 public void setUp() { 84 assumeTrue(mCar.isFeatureEnabled(Car.CAR_EVS_SERVICE)); 85 assertThat(mEvsManager).isNotNull(); 86 assumeTrue(mEvsManager.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW)); 87 assertThat(mStreamCallback).isNotNull(); 88 assertThat(mStatusListener).isNotNull(); 89 90 // Drains all permits 91 mFrameReceivedSignal.drainPermits(); 92 mStreamEventOccurred.drainPermits(); 93 94 // Ensures no stream is active 95 mEvsManager.stopVideoStream(); 96 } 97 98 @After tearDown()99 public void tearDown() throws Exception { 100 if (mEvsManager != null) { 101 mEvsManager.stopVideoStream(); 102 } 103 } 104 105 @Test testSessionTokenGeneration()106 public void testSessionTokenGeneration() throws Exception { 107 assertThat(mEvsManager.generateSessionToken()).isNotNull(); 108 } 109 110 @Test testStartAndStopVideoStream()111 public void testStartAndStopVideoStream() throws Exception { 112 // Registers a status listener and start monitoring the CarEvsService's state changes. 113 mEvsManager.setStatusListener(mCallbackExecutor, mStatusListener); 114 115 // Requests to start a video stream. 116 assertThat( 117 mEvsManager.startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW, 118 /* token = */ null, mCallbackExecutor, mStreamCallback) 119 ).isEqualTo(CarEvsManager.ERROR_NONE); 120 121 // Waits for a few frame buffers 122 for (int i = 0; i < NUMBER_OF_FRAMES_TO_WAIT; ++i) { 123 assertThat( 124 mFrameReceivedSignal.tryAcquire(FRAME_TIMEOUT_MS, TimeUnit.MILLISECONDS) 125 ).isTrue(); 126 127 // Nothing to do; returns a buffer immediately 128 CarEvsBufferDescriptor toBeReturned = mReceivedBuffers.get(INDEX_TO_FIRST_ELEM); 129 mReceivedBuffers.remove(INDEX_TO_FIRST_ELEM); 130 mEvsManager.returnFrameBuffer(toBeReturned); 131 } 132 133 // Checks a current status 134 CarEvsStatus status = mEvsManager.getCurrentStatus(); 135 assertThat(status).isNotNull(); 136 assertThat(status.getState()).isEqualTo(CarEvsManager.SERVICE_STATE_ACTIVE); 137 assertThat(status.getServiceType()).isEqualTo(CarEvsManager.SERVICE_TYPE_REARVIEW); 138 139 // Then, requests to stop a video stream 140 mEvsManager.stopVideoStream(); 141 142 // Checks a current status a few hundreds milliseconds after. CarEvsService will move into 143 // the inactive state when it gets a stream-stopped event from the EVS manager. 144 SystemClock.sleep(SMALL_NAP_MS); 145 assertThat(mStreamCallback.waitForStreamEvent(CarEvsManager.STREAM_EVENT_STREAM_STOPPED)) 146 .isTrue(); 147 148 // Unregister a listener 149 mEvsManager.clearStatusListener(); 150 } 151 152 @Test testIsSupported()153 public void testIsSupported() throws Exception { 154 assertThat(mEvsManager.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW)).isTrue(); 155 // TODO(b/179029031): Fix below test when the Surround View service is integrated into 156 // CarEvsService. 157 assertThat(mEvsManager.isSupported(CarEvsManager.SERVICE_TYPE_SURROUNDVIEW)).isFalse(); 158 } 159 160 /** 161 * Class that implements the listener interface and gets called back from 162 * {@link android.car.evs.CarEvsManager.CarEvsStatusListener}. 163 */ 164 private static final class EvsStatusListenerImpl implements CarEvsManager.CarEvsStatusListener { 165 @Override onStatusChanged(CarEvsStatus status)166 public void onStatusChanged(CarEvsStatus status) { 167 Log.i(TAG, "Received a notification of status changed to " + status.getState()); 168 } 169 } 170 171 /** 172 * Class that implements the listener interface and gets called back from 173 * {@link android.hardware.automotive.evs.IEvsCameraStream}. 174 */ 175 private final class EvsStreamCallbackImpl implements CarEvsManager.CarEvsStreamCallback { 176 @Override onStreamEvent(@arEvsStreamEvent int event)177 public void onStreamEvent(@CarEvsStreamEvent int event) { 178 mLastStreamEvent = event; 179 mStreamEventOccurred.release(); 180 } 181 182 @Override onNewFrame(CarEvsBufferDescriptor buffer)183 public void onNewFrame(CarEvsBufferDescriptor buffer) { 184 // Enqueues a new frame 185 mReceivedBuffers.add(buffer); 186 187 // Notifies a new frame's arrival 188 mFrameReceivedSignal.release(); 189 } 190 waitForStreamEvent(@arEvsStreamEvent int expected)191 public boolean waitForStreamEvent(@CarEvsStreamEvent int expected) { 192 while (mLastStreamEvent != expected) { 193 try { 194 if (!mStreamEventOccurred.tryAcquire(STREAM_EVENT_TIMEOUT_SEC, 195 TimeUnit.SECONDS)) { 196 Log.e(TAG, "No stream event is received before the timer expired."); 197 return false; 198 } 199 } catch (InterruptedException e) { 200 Log.e(TAG, "Current waiting thread is interrupted. ", e); 201 return false; 202 } 203 } 204 205 return true; 206 } 207 } 208 } 209