1 /*
2  * Copyright 2020 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 #include <android-base/logging.h>
18 #include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
19 #include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
20 #include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
21 #include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
22 #include <hidl/HidlTransportSupport.h>
23 #include <stdio.h>
24 #include <utils/StrongPointer.h>
25 #include <utils/Log.h>
26 #include <thread>
27 
28 #include "SurroundViewServiceCallback.h"
29 
30 // libhidl:
31 using android::hardware::configureRpcThreadpool;
32 using android::hardware::joinRpcThreadpool;
33 
34 using android::sp;
35 using android::hardware::Return;
36 using android::hardware::automotive::evs::V1_0::EvsResult;
37 
38 using BufferDesc_1_0  = android::hardware::automotive::evs::V1_0::BufferDesc;
39 using DisplayState = android::hardware::automotive::evs::V1_0::DisplayState;
40 
41 using namespace android::hardware::automotive::sv::V1_0;
42 using namespace android::hardware::automotive::evs::V1_1;
43 
44 const int kLowResolutionWidth = 120;
45 const int kLowResolutionHeight = 90;
46 
47 enum DemoMode {
48     UNKNOWN,
49     DEMO_2D,
50     DEMO_3D,
51 };
52 
run2dSurroundView(sp<ISurroundViewService> pSurroundViewService,sp<IEvsDisplay> pDisplay)53 bool run2dSurroundView(sp<ISurroundViewService> pSurroundViewService,
54                        sp<IEvsDisplay> pDisplay) {
55     LOG(INFO) << "Run 2d Surround View demo";
56 
57     // Call HIDL API "start2dSession"
58     sp<ISurroundView2dSession> surroundView2dSession;
59 
60     SvResult svResult;
61     pSurroundViewService->start2dSession(
62         [&surroundView2dSession, &svResult](
63             const sp<ISurroundView2dSession>& session, SvResult result) {
64         surroundView2dSession = session;
65         svResult = result;
66     });
67 
68     if (surroundView2dSession == nullptr || svResult != SvResult::OK) {
69         LOG(ERROR) << "Failed to start2dSession";
70         return false;
71     } else {
72         LOG(INFO) << "start2dSession succeeded";
73     }
74 
75     sp<SurroundViewServiceCallback> sv2dCallback
76         = new SurroundViewServiceCallback(pDisplay, surroundView2dSession);
77 
78     // Start 2d stream with callback
79     if (surroundView2dSession->startStream(sv2dCallback) != SvResult::OK) {
80         LOG(ERROR) << "Failed to start 2d stream";
81         return false;
82     }
83 
84     // Let the SV algorithm run for 10 seconds for HIGH_QUALITY
85     std::this_thread::sleep_for(std::chrono::seconds(10));
86 
87     // Switch to low quality and lower resolution
88     Sv2dConfig config;
89     config.width = kLowResolutionWidth;
90     config.blending = SvQuality::LOW;
91     if (surroundView2dSession->set2dConfig(config) != SvResult::OK) {
92         LOG(ERROR) << "Failed to set2dConfig";
93         return false;
94     }
95 
96     // Let the SV algorithm run for 10 seconds for LOW_QUALITY
97     std::this_thread::sleep_for(std::chrono::seconds(10));
98 
99     // TODO(b/150412555): wait for the last frame
100     // Stop the 2d stream and session
101     surroundView2dSession->stopStream();
102 
103     pSurroundViewService->stop2dSession(surroundView2dSession);
104     surroundView2dSession = nullptr;
105 
106     LOG(INFO) << "SV 2D session finished.";
107 
108     return true;
109 };
110 
run3dSurroundView(sp<ISurroundViewService> pSurroundViewService,sp<IEvsDisplay> pDisplay)111 bool run3dSurroundView(sp<ISurroundViewService> pSurroundViewService,
112                        sp<IEvsDisplay> pDisplay) {
113     LOG(INFO) << "Run 3d Surround View demo";
114 
115     // Call HIDL API "start3dSession"
116     sp<ISurroundView3dSession> surroundView3dSession;
117 
118     SvResult svResult;
119     pSurroundViewService->start3dSession(
120         [&surroundView3dSession, &svResult](
121             const sp<ISurroundView3dSession>& session, SvResult result) {
122         surroundView3dSession = session;
123         svResult = result;
124     });
125 
126     if (surroundView3dSession == nullptr || svResult != SvResult::OK) {
127         LOG(ERROR) << "Failed to start3dSession";
128         return false;
129     } else {
130         LOG(INFO) << "start3dSession succeeded";
131     }
132 
133     // TODO(b/150412555): now we have the dummy view here since the views are
134     // set in service. This should be fixed.
135     std::vector<View3d> singleView(1);
136     surroundView3dSession->setViews(singleView);
137 
138     if (surroundView3dSession->setViews(singleView) != SvResult::OK) {
139         LOG(ERROR) << "Failed to setViews";
140         return false;
141     }
142 
143     sp<SurroundViewServiceCallback> sv3dCallback
144         = new SurroundViewServiceCallback(pDisplay, surroundView3dSession);
145 
146     // Start 3d stream with callback
147     if (surroundView3dSession->startStream(sv3dCallback) != SvResult::OK) {
148         LOG(ERROR) << "Failed to start 3d stream";
149         return false;
150     }
151 
152     // Let the SV algorithm run for 10 seconds for HIGH_QUALITY
153     std::this_thread::sleep_for(std::chrono::seconds(10));
154 
155     // Switch to low quality and lower resolution
156     Sv3dConfig config;
157     config.width = kLowResolutionWidth;
158     config.height = kLowResolutionHeight;
159     config.carDetails = SvQuality::LOW;
160     if (surroundView3dSession->set3dConfig(config) != SvResult::OK) {
161         LOG(ERROR) << "Failed to set3dConfig";
162         return false;
163     }
164 
165     // Let the SV algorithm run for 10 seconds for LOW_QUALITY
166     std::this_thread::sleep_for(std::chrono::seconds(10));
167 
168     // TODO(b/150412555): wait for the last frame
169     // Stop the 3d stream and session
170     surroundView3dSession->stopStream();
171 
172     pSurroundViewService->stop3dSession(surroundView3dSession);
173     surroundView3dSession = nullptr;
174 
175     LOG(DEBUG) << "SV 3D session finished.";
176 
177     return true;
178 };
179 
180 // Main entry point
main(int argc,char ** argv)181 int main(int argc, char** argv) {
182     // Start up
183     LOG(INFO) << "SV app starting";
184 
185     DemoMode mode = UNKNOWN;
186     for (int i=1; i< argc; i++) {
187         if (strcmp(argv[i], "--use2d") == 0) {
188             mode = DEMO_2D;
189         } else if (strcmp(argv[i], "--use3d") == 0) {
190             mode = DEMO_3D;
191         } else {
192             LOG(WARNING) << "Ignoring unrecognized command line arg: "
193                          << argv[i];
194         }
195     }
196 
197     if (mode == UNKNOWN) {
198         LOG(ERROR) << "No demo mode is specified. Exiting";
199         return EXIT_FAILURE;
200     }
201 
202     // Set thread pool size to one to avoid concurrent events from the HAL.
203     // This pool will handle the SurroundViewStream callbacks.
204     configureRpcThreadpool(1, false /* callerWillJoin */);
205 
206     // Try to connect to EVS service
207     LOG(INFO) << "Acquiring EVS Enumerator";
208     sp<IEvsEnumerator> evs = IEvsEnumerator::getService();
209     if (evs == nullptr) {
210         LOG(ERROR) << "getService(default) returned NULL.  Exiting.";
211         return EXIT_FAILURE;
212     }
213 
214     // Try to connect to SV service
215     LOG(INFO) << "Acquiring SV Service";
216     android::sp<ISurroundViewService> surroundViewService
217         = ISurroundViewService::getService("default");
218 
219     if (surroundViewService == nullptr) {
220         LOG(ERROR) << "getService(default) returned NULL.";
221         return EXIT_FAILURE;
222     } else {
223         LOG(INFO) << "Get ISurroundViewService default";
224     }
225 
226     // Connect to evs display
227     int displayId;
228     evs->getDisplayIdList([&displayId](auto idList) {
229         displayId = idList[0];
230     });
231 
232     LOG(INFO) << "Acquiring EVS Display with ID: "
233               << displayId;
234     sp<IEvsDisplay> display = evs->openDisplay_1_1(displayId);
235     if (display == nullptr) {
236         LOG(ERROR) << "EVS Display unavailable.  Exiting.";
237         return EXIT_FAILURE;
238     }
239 
240     if (mode == DEMO_2D) {
241         if (!run2dSurroundView(surroundViewService, display)) {
242             LOG(ERROR) << "Something went wrong in 2d surround view demo. "
243                        << "Exiting.";
244             return EXIT_FAILURE;
245         }
246     } else if (mode == DEMO_3D) {
247         if (!run3dSurroundView(surroundViewService, display)) {
248             LOG(ERROR) << "Something went wrong in 3d surround view demo. "
249                        << "Exiting.";
250             return EXIT_FAILURE;
251         }
252     }
253 
254     evs->closeDisplay(display);
255 
256     LOG(DEBUG) << "SV sample app finished running successfully";
257     return EXIT_SUCCESS;
258 }
259