blob: 6f6416060b17e7dc1d5cb7d8c9f692c9cd2f8caa [file] [log] [blame]
Changyeon Joc882f7a2021-03-09 08:41:41 -08001/*
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
25using namespace ::android::hardware::automotive::evs::V1_1;
26
27using ::android::sp;
28using ::android::hardware::hidl_handle;
29using ::android::hardware::hidl_vec;
30using ::android::hardware::Return;
31using ::android::hardware::Void;
32using ::android::hardware::automotive::evs::V1_0::EvsResult;
33using ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
34
35using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
36using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
37using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
38
39namespace android {
40namespace automotive {
41namespace evs {
42
Changyeon Jo527158e2021-03-28 20:29:46 -070043StreamHandler::StreamHandler(sp<IEvsCamera>& camera, EvsServiceCallback* callback,
Changyeon Joc882f7a2021-03-09 08:41:41 -080044 int maxNumFramesInFlight) :
Changyeon Jo527158e2021-03-28 20:29:46 -070045 mEvsCamera(camera), mCallback(callback), mMaxNumFramesInFlight(maxNumFramesInFlight) {
Changyeon Joc882f7a2021-03-09 08:41:41 -080046 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 */
61StreamHandler::~StreamHandler() {
62 shutdown();
63}
64
65/*
66 * Stops an active stream and releases the camera device in use
67 */
68void 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 */
80bool 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 */
99bool 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 */
135void 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;
Changyeon Jo527158e2021-03-28 20:29:46 -0700140 return;
Changyeon Joc882f7a2021-03-09 08:41:41 -0800141 }
142
143 // Waits until the stream has actually stopped
144 std::unique_lock<std::mutex> lock(mLock);
Changyeon Jo527158e2021-03-28 20:29:46 -0700145 while (mRunning) {
146 if (!mCondition.wait_for(lock, 1s, [this]() { return !mRunning; })) {
Changyeon Joc882f7a2021-03-09 08:41:41 -0800147 LOG(WARNING) << "STREAM_STOPPED event timer expired. EVS service may die.";
Changyeon Jo527158e2021-03-28 20:29:46 -0700148 break;
Changyeon Joc882f7a2021-03-09 08:41:41 -0800149 }
150 }
151}
152
153bool StreamHandler::isRunning() {
Changyeon Jo527158e2021-03-28 20:29:46 -0700154 std::lock_guard<std::mutex> lock(mLock);
Changyeon Joc882f7a2021-03-09 08:41:41 -0800155 return mRunning;
156}
157
158void 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 mReceivedBuffers.erase(it);
165 break;
166 }
167 }
168 }
169
170 // Packages a returned buffer and sends it back to the camera
171 hidl_vec<BufferDesc_1_1> frames;
172 frames.resize(1);
173 frames[0] = buffer;
174 auto status = mEvsCamera->doneWithFrame_1_1(frames);
175 if (!status.isOk()) {
176 LOG(ERROR) << "Failed to return a frame to EVS service; this may leak the memory.";
177 }
178}
179
180Return<void> StreamHandler::deliverFrame(const BufferDesc_1_0& buffer) {
181 LOG(WARNING) << "Ignores a frame delivered from v1.0 EVS service.";
182 auto status = mEvsCamera->doneWithFrame(buffer);
183 if (!status.isOk()) {
184 LOG(ERROR) << "Failed to return a frame to EVS service; this may leak the memory.";
185 }
186 return {};
187}
188
189Return<void> StreamHandler::deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers) {
190 LOG(DEBUG) << "Received frames from the camera, bufferId = " << buffers[0].bufferId;
191
192 // Takes the lock to protect our frameDesc slots and running state variable
193 BufferDesc_1_1 frameDesc = buffers[0];
194 if (frameDesc.buffer.nativeHandle.getNativeHandle() == nullptr) {
195 // Signals that the last frameDesc has been received and the stream is stopped
196 LOG(WARNING) << "Invalid null frameDesc (id: 0x" << std::hex << frameDesc.bufferId
197 << ") is ignored";
198
199 return {};
200 }
201
202 size_t numBuffersInUse;
203 {
204 std::lock_guard<std::mutex> lock(mLock);
205 numBuffersInUse = mReceivedBuffers.size();
206 }
207
208 if (numBuffersInUse > mMaxNumFramesInFlight) {
209 // We're holding more than what allowed; returns this buffer
210 // immediately.
211 doneWithFrame(frameDesc);
212 } else {
213 {
214 std::lock_guard<std::mutex> lock(mLock);
215 // Records a new frameDesc and forwards to clients
216 mReceivedBuffers.emplace_back(frameDesc);
217 LOG(DEBUG) << "Got buffer " << frameDesc.bufferId
218 << ", total = " << mReceivedBuffers.size();
219
220 // Notify anybody who cares that things have changed
Changyeon Jo527158e2021-03-28 20:29:46 -0700221 mCondition.notify_all();
Changyeon Joc882f7a2021-03-09 08:41:41 -0800222 }
223
224 // Forwards a new frame
Changyeon Jo527158e2021-03-28 20:29:46 -0700225 mCallback->onNewFrame(frameDesc);
Changyeon Joc882f7a2021-03-09 08:41:41 -0800226 }
227
228 return {};
229}
230
231Return<void> StreamHandler::notify(const EvsEventDesc& event) {
232 switch (event.aType) {
233 case EvsEventType::STREAM_STOPPED: {
234 {
235 std::lock_guard<std::mutex> lock(mLock);
236 // Signal that the last frame has been received and the stream is stopped
237 mRunning = false;
238 }
239 LOG(DEBUG) << "Received a STREAM_STOPPED event";
240 break;
241 }
242 case EvsEventType::PARAMETER_CHANGED:
243 LOG(DEBUG) << "Camera parameter 0x" << std::hex << event.payload[0] << " is set to 0x"
244 << std::hex << event.payload[1];
245 break;
246 // Below events are ignored in reference implementation.
247 case EvsEventType::STREAM_STARTED:
248 [[fallthrough]];
249 case EvsEventType::FRAME_DROPPED:
250 [[fallthrough]];
251 case EvsEventType::TIMEOUT:
252 LOG(INFO) << "Event 0x" << std::hex << static_cast<int32_t>(event.aType)
253 << " is received but ignored";
254 break;
255 default:
256 LOG(ERROR) << "Unknown event id 0x" << std::hex << static_cast<int32_t>(event.aType);
257 break;
258 }
259
Changyeon Jo527158e2021-03-28 20:29:46 -0700260 mCallback->onNewEvent(event);
Changyeon Joc882f7a2021-03-09 08:41:41 -0800261
262 return {};
263}
264
265} // namespace evs
266} // namespace automotive
267} // namespace android