• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.evs;
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 com.android.car.MockedCarTestBase;
36 
37 import org.junit.After;
38 import org.junit.Before;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 
42 import java.util.ArrayList;
43 import java.util.concurrent.ExecutorService;
44 import java.util.concurrent.Executors;
45 import java.util.concurrent.Semaphore;
46 import java.util.concurrent.TimeUnit;
47 
48 /*
49  * IMPORTANT NOTE:
50  * This test assumes that EVS HAL is running at the time of test.  Depending on the test target, the
51  * reference EVS HAL ($ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver) may be needed.
52  * Please add below line to the target's build script to add the reference EVS HAL to the build:
53  * ENABLE_EVS_SAMPLE := true
54  *
55  * The test will likely fail if no EVS HAL is running on the target device.
56  */
57 @RunWith(AndroidJUnit4.class)
58 @MediumTest
59 public final class CarEvsManagerTest extends MockedCarTestBase {
60     private static final String TAG = CarEvsManagerTest.class.getSimpleName();
61 
62     // We'd expect that underlying stream runs @10fps at least.
63     private static final int NUMBER_OF_FRAMES_TO_WAIT = 10;
64     private static final int FRAME_TIMEOUT_MS = 1000;
65     private static final int SMALL_NAP_MS = 500;
66     private static final int STREAM_EVENT_TIMEOUT_SEC = 2;
67 
68     // Will return frame buffers in the order they arrived.
69     private static final int INDEX_TO_FIRST_ELEM = 0;
70 
71     private final ArrayList<CarEvsBufferDescriptor> mReceivedBuffers = new ArrayList<>();
72     private final ExecutorService mCallbackExecutor = Executors.newFixedThreadPool(1);
73     private final Semaphore mFrameReceivedSignal = new Semaphore(0);
74     private final Semaphore mStreamEventOccurred = new Semaphore(0);
75 
76     private final Car mCar = Car.createCar(ApplicationProvider.getApplicationContext());
77     private final CarEvsManager mEvsManager =
78             (CarEvsManager) mCar.getCarManager(Car.CAR_EVS_SERVICE);
79     private final EvsStreamCallbackImpl mStreamCallback = new EvsStreamCallbackImpl();
80     private final EvsStatusListenerImpl mStatusListener = new EvsStatusListenerImpl();
81 
82     private @CarEvsStreamEvent int mLastStreamEvent;
83 
84     @Before
setUp()85     public void setUp() {
86         assumeTrue(mCar.isFeatureEnabled(Car.CAR_EVS_SERVICE));
87         assertThat(mEvsManager).isNotNull();
88         assumeTrue(mEvsManager.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW));
89         assertThat(mStreamCallback).isNotNull();
90         assertThat(mStatusListener).isNotNull();
91 
92         // Drains all permits
93         mFrameReceivedSignal.drainPermits();
94         mStreamEventOccurred.drainPermits();
95 
96         // Ensures no stream is active
97         mEvsManager.stopVideoStream();
98     }
99 
100     @After
tearDown()101     public void tearDown() throws Exception {
102         if (mEvsManager != null) {
103             mEvsManager.stopVideoStream();
104         }
105     }
106 
107     @Test
testSessionTokenGeneration()108     public void testSessionTokenGeneration() throws Exception {
109         assertThat(mEvsManager.generateSessionToken()).isNotNull();
110     }
111 
112     @Test
testStartAndStopVideoStream()113     public void testStartAndStopVideoStream() throws Exception {
114         // Registers a status listener and start monitoring the CarEvsService's state changes.
115         mEvsManager.setStatusListener(mCallbackExecutor, mStatusListener);
116 
117         // Requests to start a video stream.
118         assertThat(
119                 mEvsManager.startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW,
120                         /* token = */ null, mCallbackExecutor, mStreamCallback)
121         ).isEqualTo(CarEvsManager.ERROR_NONE);
122 
123         // Waits for a few frame buffers
124         for (int i = 0; i < NUMBER_OF_FRAMES_TO_WAIT; ++i) {
125             assertThat(
126                     mFrameReceivedSignal.tryAcquire(FRAME_TIMEOUT_MS, TimeUnit.MILLISECONDS)
127             ).isTrue();
128 
129             // Nothing to do; returns a buffer immediately
130             CarEvsBufferDescriptor toBeReturned = mReceivedBuffers.get(INDEX_TO_FIRST_ELEM);
131             mReceivedBuffers.remove(INDEX_TO_FIRST_ELEM);
132             mEvsManager.returnFrameBuffer(toBeReturned);
133         }
134 
135         // Checks a current status
136         CarEvsStatus status = mEvsManager.getCurrentStatus();
137         assertThat(status).isNotNull();
138         assertThat(status.getState()).isEqualTo(CarEvsManager.SERVICE_STATE_ACTIVE);
139         assertThat(status.getServiceType()).isEqualTo(CarEvsManager.SERVICE_TYPE_REARVIEW);
140 
141         // Then, requests to stop a video stream
142         mEvsManager.stopVideoStream();
143 
144         // Checks a current status a few hundreds milliseconds after.  CarEvsService will move into
145         // the inactive state when it gets a stream-stopped event from the EVS manager.
146         SystemClock.sleep(SMALL_NAP_MS);
147         assertThat(mStreamCallback.waitForStreamEvent(CarEvsManager.STREAM_EVENT_STREAM_STOPPED))
148                 .isTrue();
149 
150         // Unregister a listener
151         mEvsManager.clearStatusListener();
152     }
153 
154     @Test
testIsSupported()155     public void testIsSupported() throws Exception {
156         assertThat(mEvsManager.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW)).isTrue();
157         // TODO(b/179029031): Fix below test when the Surround View service is integrated into
158         // CarEvsService.
159         assertThat(mEvsManager.isSupported(CarEvsManager.SERVICE_TYPE_SURROUNDVIEW)).isFalse();
160     }
161 
162     /**
163      * Class that implements the listener interface and gets called back from
164      * {@link android.car.evs.CarEvsManager.CarEvsStatusListener}.
165      */
166     private static final class EvsStatusListenerImpl implements CarEvsManager.CarEvsStatusListener {
167         @Override
onStatusChanged(CarEvsStatus status)168         public void onStatusChanged(CarEvsStatus status) {
169             Log.i(TAG, "Received a notification of status changed to " + status.getState());
170         }
171     }
172 
173     /**
174      * Class that implements the listener interface and gets called back from
175      * {@link android.hardware.automotive.evs.IEvsCameraStream}.
176      */
177     private final class EvsStreamCallbackImpl implements CarEvsManager.CarEvsStreamCallback {
178         @Override
onStreamEvent(@arEvsStreamEvent int event)179         public void onStreamEvent(@CarEvsStreamEvent int event) {
180             mLastStreamEvent = event;
181             mStreamEventOccurred.release();
182         }
183 
184         @Override
onNewFrame(CarEvsBufferDescriptor buffer)185         public void onNewFrame(CarEvsBufferDescriptor buffer) {
186             // Enqueues a new frame
187             mReceivedBuffers.add(buffer);
188 
189             // Notifies a new frame's arrival
190             mFrameReceivedSignal.release();
191         }
192 
waitForStreamEvent(@arEvsStreamEvent int expected)193         public boolean waitForStreamEvent(@CarEvsStreamEvent int expected) {
194             while (mLastStreamEvent != expected) {
195                 try {
196                     if (!mStreamEventOccurred.tryAcquire(STREAM_EVENT_TIMEOUT_SEC,
197                             TimeUnit.SECONDS)) {
198                         Log.e(TAG, "No stream event is received before the timer expired.");
199                         return false;
200                     }
201                 } catch (InterruptedException e) {
202                     Log.e(TAG, "Current waiting thread is interrupted. ", e);
203                     return false;
204                 }
205             }
206 
207             return true;
208         }
209     }
210 }
211