1 /*
2 * Copyright 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 #include "StreamHandler.h"
18
19 #include <android-base/chrono_utils.h>
20 #include <android-base/logging.h>
21 #include <cutils/native_handle.h>
22
23 #include <cstring>
24
25 using namespace ::android::hardware::automotive::evs::V1_1;
26
27 using ::android::sp;
28 using ::android::hardware::hidl_handle;
29 using ::android::hardware::hidl_vec;
30 using ::android::hardware::Return;
31 using ::android::hardware::Void;
32 using ::android::hardware::automotive::evs::V1_0::EvsResult;
33 using ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
34
35 using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
36 using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
37 using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
38
39 namespace android {
40 namespace automotive {
41 namespace evs {
42
StreamHandler(sp<IEvsCamera> & camera,EvsServiceCallback * callback,int maxNumFramesInFlight)43 StreamHandler::StreamHandler(sp<IEvsCamera>& camera, EvsServiceCallback* callback,
44 int maxNumFramesInFlight) :
45 mEvsCamera(camera), mCallback(callback), mMaxNumFramesInFlight(maxNumFramesInFlight) {
46 if (camera == nullptr) {
47 LOG(ERROR) << "IEvsCamera is invalid.";
48 } else {
49 // We rely on the camera having at least two buffers available since we'll hold one and
50 // expect the camera to be able to capture a new image in the background.
51 auto status = camera->setMaxFramesInFlight(maxNumFramesInFlight);
52 if (!status.isOk()) {
53 LOG(WARNING) << "Failed to adjust the maximum number of frames in flight.";
54 }
55 }
56 }
57
58 /*
59 * Shuts down a stream handler
60 */
~StreamHandler()61 StreamHandler::~StreamHandler() {
62 shutdown();
63 }
64
65 /*
66 * Stops an active stream and releases the camera device in use
67 */
shutdown()68 void StreamHandler::shutdown() {
69 // Make sure we're not still streaming
70 blockingStopStream();
71
72 // At this point, the receiver thread is no longer running, so we can safely drop
73 // our remote object references so they can be freed
74 mEvsCamera = nullptr;
75 }
76
77 /*
78 * Requests EVS to start a video stream
79 */
startStream()80 bool StreamHandler::startStream() {
81 std::lock_guard<std::mutex> lock(mLock);
82 if (!mRunning) {
83 auto result = mEvsCamera->startVideoStream(this);
84 if (!result.isOk() or result != EvsResult::OK) {
85 LOG(ERROR) << "StreamHandler failed to start a video stream.";
86 return false;
87 }
88
89 // Marks ourselves as running
90 mRunning = true;
91 }
92
93 return true;
94 }
95
96 /*
97 * Requests to stop a video stream
98 */
asyncStopStream()99 bool StreamHandler::asyncStopStream() {
100 bool success = true;
101
102 // This will result in STREAM_STOPPED event; the client may want to wait
103 // this event to confirm the closure.
104 {
105 std::lock_guard<std::mutex> lock(mLock);
106 auto it = mReceivedBuffers.begin();
107 while (it != mReceivedBuffers.end()) {
108 // Packages a returned buffer and sends it back to the camera
109 hidl_vec<BufferDesc_1_1> frames;
110 frames.resize(1);
111 frames[0] = *it;
112 auto status = mEvsCamera->doneWithFrame_1_1(frames);
113 if (!status.isOk()) {
114 LOG(WARNING) << "Failed to return a frame to EVS service; "
115 << "this may leak the memory.";
116 success = false;
117 }
118
119 it = mReceivedBuffers.erase(it);
120 }
121 }
122
123 auto status = mEvsCamera->stopVideoStream();
124 if (!status.isOk()) {
125 LOG(WARNING) << "stopVideoStream() failed but ignored.";
126 success = false;
127 }
128
129 return success;
130 }
131
132 /*
133 * Requests to stop a video stream and waits for a confirmation
134 */
blockingStopStream()135 void StreamHandler::blockingStopStream() {
136 if (!asyncStopStream()) {
137 // EVS service may die so no stream-stop event occurs.
138 std::lock_guard<std::mutex> lock(mLock);
139 mRunning = false;
140 return;
141 }
142
143 // Waits until the stream has actually stopped
144 std::unique_lock<std::mutex> lock(mLock);
145 while (mRunning) {
146 if (!mCondition.wait_for(lock, 1s, [this]() { return !mRunning; })) {
147 LOG(WARNING) << "STREAM_STOPPED event timer expired. EVS service may die.";
148 break;
149 }
150 }
151 }
152
isRunning()153 bool StreamHandler::isRunning() {
154 std::lock_guard<std::mutex> lock(mLock);
155 return mRunning;
156 }
157
doneWithFrame(const BufferDesc_1_1 & buffer)158 void StreamHandler::doneWithFrame(const BufferDesc_1_1& buffer) {
159 {
160 std::lock_guard<std::mutex> lock(mLock);
161 auto it = mReceivedBuffers.begin();
162 while (it != mReceivedBuffers.end()) {
163 if (it->bufferId == buffer.bufferId) {
164 // We intentionally do not update the iterator to detect a
165 // request to return an unknown buffer.
166 mReceivedBuffers.erase(it);
167 break;
168 }
169 ++it;
170 }
171
172 if (it == mReceivedBuffers.end()) {
173 LOG(DEBUG) << "Ignores a request to return unknown buffer";
174 return;
175 }
176 }
177
178 // Packages a returned buffer and sends it back to the camera
179 hidl_vec<BufferDesc_1_1> frames;
180 frames.resize(1);
181 frames[0] = buffer;
182 auto status = mEvsCamera->doneWithFrame_1_1(frames);
183 if (!status.isOk()) {
184 LOG(ERROR) << "Failed to return a frame to EVS service; this may leak the memory.";
185 }
186 }
187
deliverFrame(const BufferDesc_1_0 & buffer)188 Return<void> StreamHandler::deliverFrame(const BufferDesc_1_0& buffer) {
189 LOG(WARNING) << "Ignores a frame delivered from v1.0 EVS service.";
190 auto status = mEvsCamera->doneWithFrame(buffer);
191 if (!status.isOk()) {
192 LOG(ERROR) << "Failed to return a frame to EVS service; this may leak the memory.";
193 }
194 return {};
195 }
196
deliverFrame_1_1(const hidl_vec<BufferDesc_1_1> & buffers)197 Return<void> StreamHandler::deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers) {
198 LOG(DEBUG) << "Received frames from the camera, bufferId = " << buffers[0].bufferId;
199
200 // Takes the lock to protect our frameDesc slots and running state variable
201 BufferDesc_1_1 frameDesc = buffers[0];
202 if (frameDesc.buffer.nativeHandle.getNativeHandle() == nullptr) {
203 // Signals that the last frameDesc has been received and the stream is stopped
204 LOG(WARNING) << "Invalid null frameDesc (id: 0x" << std::hex << frameDesc.bufferId
205 << ") is ignored";
206
207 return {};
208 }
209
210 size_t numBuffersInUse;
211 {
212 std::lock_guard<std::mutex> lock(mLock);
213 numBuffersInUse = mReceivedBuffers.size();
214 }
215
216 if (numBuffersInUse > mMaxNumFramesInFlight) {
217 // We're holding more than what allowed; returns this buffer
218 // immediately.
219 doneWithFrame(frameDesc);
220 } else {
221 {
222 std::lock_guard<std::mutex> lock(mLock);
223 // Records a new frameDesc and forwards to clients
224 mReceivedBuffers.emplace_back(frameDesc);
225 LOG(DEBUG) << "Got buffer " << frameDesc.bufferId
226 << ", total = " << mReceivedBuffers.size();
227
228 // Notify anybody who cares that things have changed
229 mCondition.notify_all();
230 }
231
232 // Forwards a new frame
233 mCallback->onNewFrame(frameDesc);
234 }
235
236 return {};
237 }
238
notify(const EvsEventDesc & event)239 Return<void> StreamHandler::notify(const EvsEventDesc& event) {
240 switch (event.aType) {
241 case EvsEventType::STREAM_STOPPED: {
242 {
243 std::lock_guard<std::mutex> lock(mLock);
244 // Signal that the last frame has been received and the stream is stopped
245 mRunning = false;
246 }
247 LOG(DEBUG) << "Received a STREAM_STOPPED event";
248 break;
249 }
250 case EvsEventType::PARAMETER_CHANGED:
251 LOG(DEBUG) << "Camera parameter 0x" << std::hex << event.payload[0] << " is set to 0x"
252 << std::hex << event.payload[1];
253 break;
254 // Below events are ignored in reference implementation.
255 case EvsEventType::STREAM_STARTED:
256 [[fallthrough]];
257 case EvsEventType::FRAME_DROPPED:
258 [[fallthrough]];
259 case EvsEventType::TIMEOUT:
260 LOG(INFO) << "Event 0x" << std::hex << static_cast<int32_t>(event.aType)
261 << " is received but ignored";
262 break;
263 default:
264 LOG(ERROR) << "Unknown event id 0x" << std::hex << static_cast<int32_t>(event.aType);
265 break;
266 }
267
268 mCallback->onNewEvent(event);
269
270 return {};
271 }
272
273 } // namespace evs
274 } // namespace automotive
275 } // namespace android
276