xref: /aosp_15_r20/hardware/interfaces/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker  * Copyright 2020 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker  *
4*4d7e907cSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker  *
8*4d7e907cSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker  *
10*4d7e907cSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker  * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker  */
16*4d7e907cSAndroid Build Coastguard Worker 
17*4d7e907cSAndroid Build Coastguard Worker #include "EvsUltrasonicsArray.h"
18*4d7e907cSAndroid Build Coastguard Worker 
19*4d7e907cSAndroid Build Coastguard Worker #include <android-base/logging.h>
20*4d7e907cSAndroid Build Coastguard Worker #include <hidlmemory/mapping.h>
21*4d7e907cSAndroid Build Coastguard Worker #include <log/log.h>
22*4d7e907cSAndroid Build Coastguard Worker #include <time.h>
23*4d7e907cSAndroid Build Coastguard Worker #include <utils/SystemClock.h>
24*4d7e907cSAndroid Build Coastguard Worker #include <utils/Timers.h>
25*4d7e907cSAndroid Build Coastguard Worker 
26*4d7e907cSAndroid Build Coastguard Worker namespace android {
27*4d7e907cSAndroid Build Coastguard Worker namespace hardware {
28*4d7e907cSAndroid Build Coastguard Worker namespace automotive {
29*4d7e907cSAndroid Build Coastguard Worker namespace evs {
30*4d7e907cSAndroid Build Coastguard Worker namespace V1_1 {
31*4d7e907cSAndroid Build Coastguard Worker namespace implementation {
32*4d7e907cSAndroid Build Coastguard Worker 
33*4d7e907cSAndroid Build Coastguard Worker // Arbitrary limit on number of data frames allowed to be allocated
34*4d7e907cSAndroid Build Coastguard Worker // Safeguards against unreasonable resource consumption and provides a testable limit
35*4d7e907cSAndroid Build Coastguard Worker const unsigned int kMaximumDataFramesInFlight = 100;
36*4d7e907cSAndroid Build Coastguard Worker 
37*4d7e907cSAndroid Build Coastguard Worker const uint32_t kMaxReadingsPerSensor = 5;
38*4d7e907cSAndroid Build Coastguard Worker const uint32_t kMaxReceiversCount = 3;
39*4d7e907cSAndroid Build Coastguard Worker 
40*4d7e907cSAndroid Build Coastguard Worker const unsigned int kSharedMemoryMaxSize =
41*4d7e907cSAndroid Build Coastguard Worker         kMaxReadingsPerSensor * kMaxReceiversCount * 2 * sizeof(float);
42*4d7e907cSAndroid Build Coastguard Worker 
43*4d7e907cSAndroid Build Coastguard Worker // Target frame rate in frames per second.
44*4d7e907cSAndroid Build Coastguard Worker const int kTargetFrameRate = 10;
45*4d7e907cSAndroid Build Coastguard Worker 
46*4d7e907cSAndroid Build Coastguard Worker namespace {
47*4d7e907cSAndroid Build Coastguard Worker 
fillMockArrayDesc(UltrasonicsArrayDesc & arrayDesc)48*4d7e907cSAndroid Build Coastguard Worker void fillMockArrayDesc(UltrasonicsArrayDesc& arrayDesc) {
49*4d7e907cSAndroid Build Coastguard Worker     arrayDesc.maxReadingsPerSensorCount = kMaxReadingsPerSensor;
50*4d7e907cSAndroid Build Coastguard Worker     arrayDesc.maxReceiversCount = kMaxReceiversCount;
51*4d7e907cSAndroid Build Coastguard Worker 
52*4d7e907cSAndroid Build Coastguard Worker     const int kSensorCount = 3;
53*4d7e907cSAndroid Build Coastguard Worker     const float kMaxRange = 4000;                // 4 metres.
54*4d7e907cSAndroid Build Coastguard Worker     const float kAngleOfMeasurement = 0.261799;  // 15 degrees.
55*4d7e907cSAndroid Build Coastguard Worker 
56*4d7e907cSAndroid Build Coastguard Worker     std::vector<UltrasonicSensor> sensors(kSensorCount);
57*4d7e907cSAndroid Build Coastguard Worker 
58*4d7e907cSAndroid Build Coastguard Worker     // Sensor pointing forward on left side of front bumper.
59*4d7e907cSAndroid Build Coastguard Worker     sensors[0].maxRange = kMaxRange;
60*4d7e907cSAndroid Build Coastguard Worker     sensors[0].angleOfMeasurement = kAngleOfMeasurement;
61*4d7e907cSAndroid Build Coastguard Worker     sensors[0].pose = {{1, 0, 0, 0}, {-1000, 2000, 200}};
62*4d7e907cSAndroid Build Coastguard Worker 
63*4d7e907cSAndroid Build Coastguard Worker     // Sensor pointing forward on center of front bumper.
64*4d7e907cSAndroid Build Coastguard Worker     sensors[1].maxRange = kMaxRange;
65*4d7e907cSAndroid Build Coastguard Worker     sensors[1].angleOfMeasurement = kAngleOfMeasurement;
66*4d7e907cSAndroid Build Coastguard Worker     sensors[1].pose = {{1, 0, 0, 0}, {0, 2000, 200}};
67*4d7e907cSAndroid Build Coastguard Worker 
68*4d7e907cSAndroid Build Coastguard Worker     // Sensor pointing forward on right side of front bumper.
69*4d7e907cSAndroid Build Coastguard Worker     sensors[2].maxRange = kMaxRange;
70*4d7e907cSAndroid Build Coastguard Worker     sensors[2].angleOfMeasurement = kAngleOfMeasurement;
71*4d7e907cSAndroid Build Coastguard Worker     sensors[2].pose = {{1, 0, 0, 0}, {1000, 2000, 200}};
72*4d7e907cSAndroid Build Coastguard Worker 
73*4d7e907cSAndroid Build Coastguard Worker     arrayDesc.sensors = sensors;
74*4d7e907cSAndroid Build Coastguard Worker }
75*4d7e907cSAndroid Build Coastguard Worker 
76*4d7e907cSAndroid Build Coastguard Worker // Struct used by SerializeWaveformData().
77*4d7e907cSAndroid Build Coastguard Worker struct WaveformData {
78*4d7e907cSAndroid Build Coastguard Worker     uint8_t receiverId;
79*4d7e907cSAndroid Build Coastguard Worker     std::vector<std::pair<float, float>> readings;
80*4d7e907cSAndroid Build Coastguard Worker };
81*4d7e907cSAndroid Build Coastguard Worker 
82*4d7e907cSAndroid Build Coastguard Worker // Serializes data provided in waveformDataList to a shared memory data pointer.
83*4d7e907cSAndroid Build Coastguard Worker // TODO(b/149950362): Add a common library for serialiazing and deserializing waveform data.
SerializeWaveformData(const std::vector<WaveformData> & waveformDataList,uint8_t * pData)84*4d7e907cSAndroid Build Coastguard Worker void SerializeWaveformData(const std::vector<WaveformData>& waveformDataList, uint8_t* pData) {
85*4d7e907cSAndroid Build Coastguard Worker     for (auto& waveformData : waveformDataList) {
86*4d7e907cSAndroid Build Coastguard Worker         // Set Id
87*4d7e907cSAndroid Build Coastguard Worker         memcpy(pData, &waveformData.receiverId, sizeof(uint8_t));
88*4d7e907cSAndroid Build Coastguard Worker         pData += sizeof(uint8_t);
89*4d7e907cSAndroid Build Coastguard Worker 
90*4d7e907cSAndroid Build Coastguard Worker         for (auto& reading : waveformData.readings) {
91*4d7e907cSAndroid Build Coastguard Worker             // Set the time of flight.
92*4d7e907cSAndroid Build Coastguard Worker             memcpy(pData, &reading.first, sizeof(float));
93*4d7e907cSAndroid Build Coastguard Worker             pData += sizeof(float);
94*4d7e907cSAndroid Build Coastguard Worker 
95*4d7e907cSAndroid Build Coastguard Worker             // Set the resonance.
96*4d7e907cSAndroid Build Coastguard Worker             memcpy(pData, &reading.second, sizeof(float));
97*4d7e907cSAndroid Build Coastguard Worker             pData += sizeof(float);
98*4d7e907cSAndroid Build Coastguard Worker         }
99*4d7e907cSAndroid Build Coastguard Worker     }
100*4d7e907cSAndroid Build Coastguard Worker }
101*4d7e907cSAndroid Build Coastguard Worker 
102*4d7e907cSAndroid Build Coastguard Worker // Fills dataFrameDesc with mock data.
fillMockDataFrame(UltrasonicsDataFrameDesc & dataFrameDesc,sp<IMemory> pIMemory)103*4d7e907cSAndroid Build Coastguard Worker bool fillMockDataFrame(UltrasonicsDataFrameDesc& dataFrameDesc, sp<IMemory> pIMemory) {
104*4d7e907cSAndroid Build Coastguard Worker     dataFrameDesc.timestampNs = elapsedRealtimeNano();
105*4d7e907cSAndroid Build Coastguard Worker 
106*4d7e907cSAndroid Build Coastguard Worker     const std::vector<uint8_t> transmittersIdList = {0};
107*4d7e907cSAndroid Build Coastguard Worker     dataFrameDesc.transmittersIdList = transmittersIdList;
108*4d7e907cSAndroid Build Coastguard Worker 
109*4d7e907cSAndroid Build Coastguard Worker     const std::vector<uint8_t> recvIdList = {0, 1, 2};
110*4d7e907cSAndroid Build Coastguard Worker     dataFrameDesc.receiversIdList = recvIdList;
111*4d7e907cSAndroid Build Coastguard Worker 
112*4d7e907cSAndroid Build Coastguard Worker     const std::vector<uint32_t> receiversReadingsCountList = {2, 2, 4};
113*4d7e907cSAndroid Build Coastguard Worker     dataFrameDesc.receiversReadingsCountList = receiversReadingsCountList;
114*4d7e907cSAndroid Build Coastguard Worker 
115*4d7e907cSAndroid Build Coastguard Worker     const std::vector<WaveformData> waveformDataList = {
116*4d7e907cSAndroid Build Coastguard Worker             {recvIdList[0], {{1000, 0.1f}, {2000, 0.8f}}},
117*4d7e907cSAndroid Build Coastguard Worker             {recvIdList[1], {{1000, 0.1f}, {2000, 1.0f}}},
118*4d7e907cSAndroid Build Coastguard Worker             {recvIdList[2], {{1000, 0.1f}, {2000, 0.2f}, {4000, 0.2f}, {5000, 0.1f}}}};
119*4d7e907cSAndroid Build Coastguard Worker 
120*4d7e907cSAndroid Build Coastguard Worker     if (pIMemory.get() == nullptr) {
121*4d7e907cSAndroid Build Coastguard Worker         return false;
122*4d7e907cSAndroid Build Coastguard Worker     }
123*4d7e907cSAndroid Build Coastguard Worker 
124*4d7e907cSAndroid Build Coastguard Worker     uint8_t* pData = (uint8_t*)((void*)pIMemory->getPointer());
125*4d7e907cSAndroid Build Coastguard Worker 
126*4d7e907cSAndroid Build Coastguard Worker     pIMemory->update();
127*4d7e907cSAndroid Build Coastguard Worker     SerializeWaveformData(waveformDataList, pData);
128*4d7e907cSAndroid Build Coastguard Worker     pIMemory->commit();
129*4d7e907cSAndroid Build Coastguard Worker 
130*4d7e907cSAndroid Build Coastguard Worker     return true;
131*4d7e907cSAndroid Build Coastguard Worker }
132*4d7e907cSAndroid Build Coastguard Worker 
133*4d7e907cSAndroid Build Coastguard Worker }  // namespace
134*4d7e907cSAndroid Build Coastguard Worker 
EvsUltrasonicsArray(const char * deviceName)135*4d7e907cSAndroid Build Coastguard Worker EvsUltrasonicsArray::EvsUltrasonicsArray(const char* deviceName)
136*4d7e907cSAndroid Build Coastguard Worker     : mFramesAllowed(0), mFramesInUse(0), mStreamState(STOPPED) {
137*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "EvsUltrasonicsArray instantiated";
138*4d7e907cSAndroid Build Coastguard Worker 
139*4d7e907cSAndroid Build Coastguard Worker     // Set up mock data for description.
140*4d7e907cSAndroid Build Coastguard Worker     mArrayDesc.ultrasonicsArrayId = deviceName;
141*4d7e907cSAndroid Build Coastguard Worker     fillMockArrayDesc(mArrayDesc);
142*4d7e907cSAndroid Build Coastguard Worker 
143*4d7e907cSAndroid Build Coastguard Worker     // Assign allocator.
144*4d7e907cSAndroid Build Coastguard Worker     mShmemAllocator = IAllocator::getService("ashmem");
145*4d7e907cSAndroid Build Coastguard Worker     if (mShmemAllocator.get() == nullptr) {
146*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "SurroundViewHidlTest getService ashmem failed";
147*4d7e907cSAndroid Build Coastguard Worker     }
148*4d7e907cSAndroid Build Coastguard Worker }
149*4d7e907cSAndroid Build Coastguard Worker 
Create(const char * deviceName)150*4d7e907cSAndroid Build Coastguard Worker sp<EvsUltrasonicsArray> EvsUltrasonicsArray::Create(const char* deviceName) {
151*4d7e907cSAndroid Build Coastguard Worker     return sp<EvsUltrasonicsArray>(new EvsUltrasonicsArray(deviceName));
152*4d7e907cSAndroid Build Coastguard Worker }
153*4d7e907cSAndroid Build Coastguard Worker 
~EvsUltrasonicsArray()154*4d7e907cSAndroid Build Coastguard Worker EvsUltrasonicsArray::~EvsUltrasonicsArray() {
155*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "EvsUltrasonicsArray being destroyed";
156*4d7e907cSAndroid Build Coastguard Worker     forceShutdown();
157*4d7e907cSAndroid Build Coastguard Worker }
158*4d7e907cSAndroid Build Coastguard Worker 
159*4d7e907cSAndroid Build Coastguard Worker // This gets called if another caller "steals" ownership of the ultrasonic array.
forceShutdown()160*4d7e907cSAndroid Build Coastguard Worker void EvsUltrasonicsArray::forceShutdown() {
161*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "EvsUltrasonicsArray forceShutdown";
162*4d7e907cSAndroid Build Coastguard Worker 
163*4d7e907cSAndroid Build Coastguard Worker     // Make sure our output stream is cleaned up
164*4d7e907cSAndroid Build Coastguard Worker     // (It really should be already)
165*4d7e907cSAndroid Build Coastguard Worker     stopStream();
166*4d7e907cSAndroid Build Coastguard Worker 
167*4d7e907cSAndroid Build Coastguard Worker     // Claim the lock while we work on internal state
168*4d7e907cSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mAccessLock);
169*4d7e907cSAndroid Build Coastguard Worker 
170*4d7e907cSAndroid Build Coastguard Worker     // Drop all the data frames we've been using
171*4d7e907cSAndroid Build Coastguard Worker     for (auto&& dataFrame : mDataFrames) {
172*4d7e907cSAndroid Build Coastguard Worker         if (dataFrame.inUse) {
173*4d7e907cSAndroid Build Coastguard Worker             LOG(ERROR) << "Error - releasing data frame despite remote ownership";
174*4d7e907cSAndroid Build Coastguard Worker         }
175*4d7e907cSAndroid Build Coastguard Worker         dataFrame.sharedMemory.clear();
176*4d7e907cSAndroid Build Coastguard Worker     }
177*4d7e907cSAndroid Build Coastguard Worker     mDataFrames.clear();
178*4d7e907cSAndroid Build Coastguard Worker 
179*4d7e907cSAndroid Build Coastguard Worker     // Put this object into an unrecoverable error state since somebody else
180*4d7e907cSAndroid Build Coastguard Worker     // is going to own the underlying ultrasonic array now
181*4d7e907cSAndroid Build Coastguard Worker     mStreamState = DEAD;
182*4d7e907cSAndroid Build Coastguard Worker }
183*4d7e907cSAndroid Build Coastguard Worker 
GetMockArrayDesc(const char * deviceName)184*4d7e907cSAndroid Build Coastguard Worker UltrasonicsArrayDesc EvsUltrasonicsArray::GetMockArrayDesc(const char* deviceName) {
185*4d7e907cSAndroid Build Coastguard Worker     UltrasonicsArrayDesc ultrasonicsArrayDesc;
186*4d7e907cSAndroid Build Coastguard Worker     ultrasonicsArrayDesc.ultrasonicsArrayId = deviceName;
187*4d7e907cSAndroid Build Coastguard Worker     fillMockArrayDesc(ultrasonicsArrayDesc);
188*4d7e907cSAndroid Build Coastguard Worker     return ultrasonicsArrayDesc;
189*4d7e907cSAndroid Build Coastguard Worker }
190*4d7e907cSAndroid Build Coastguard Worker 
getUltrasonicArrayInfo(getUltrasonicArrayInfo_cb _get_info_cb)191*4d7e907cSAndroid Build Coastguard Worker Return<void> EvsUltrasonicsArray::getUltrasonicArrayInfo(getUltrasonicArrayInfo_cb _get_info_cb) {
192*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "EvsUltrasonicsArray getUltrasonicsArrayInfo";
193*4d7e907cSAndroid Build Coastguard Worker 
194*4d7e907cSAndroid Build Coastguard Worker     // Return the description for the get info callback.
195*4d7e907cSAndroid Build Coastguard Worker     _get_info_cb(mArrayDesc);
196*4d7e907cSAndroid Build Coastguard Worker 
197*4d7e907cSAndroid Build Coastguard Worker     return Void();
198*4d7e907cSAndroid Build Coastguard Worker }
199*4d7e907cSAndroid Build Coastguard Worker 
setMaxFramesInFlight(uint32_t bufferCount)200*4d7e907cSAndroid Build Coastguard Worker Return<EvsResult> EvsUltrasonicsArray::setMaxFramesInFlight(uint32_t bufferCount) {
201*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "EvsUltrasonicsArray setMaxFramesInFlight";
202*4d7e907cSAndroid Build Coastguard Worker 
203*4d7e907cSAndroid Build Coastguard Worker     // Lock mutex for performing changes to available frames.
204*4d7e907cSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mAccessLock);
205*4d7e907cSAndroid Build Coastguard Worker 
206*4d7e907cSAndroid Build Coastguard Worker     // We cannot function without at least one buffer to send data.
207*4d7e907cSAndroid Build Coastguard Worker     if (bufferCount < 1) {
208*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "Ignoring setMaxFramesInFlight with less than one buffer requested";
209*4d7e907cSAndroid Build Coastguard Worker         return EvsResult::INVALID_ARG;
210*4d7e907cSAndroid Build Coastguard Worker     }
211*4d7e907cSAndroid Build Coastguard Worker 
212*4d7e907cSAndroid Build Coastguard Worker     // Update our internal state of buffer count.
213*4d7e907cSAndroid Build Coastguard Worker     if (setAvailableFrames_Locked(bufferCount)) {
214*4d7e907cSAndroid Build Coastguard Worker         return EvsResult::OK;
215*4d7e907cSAndroid Build Coastguard Worker     } else {
216*4d7e907cSAndroid Build Coastguard Worker         return EvsResult::BUFFER_NOT_AVAILABLE;
217*4d7e907cSAndroid Build Coastguard Worker     }
218*4d7e907cSAndroid Build Coastguard Worker 
219*4d7e907cSAndroid Build Coastguard Worker     return EvsResult::OK;
220*4d7e907cSAndroid Build Coastguard Worker }
221*4d7e907cSAndroid Build Coastguard Worker 
doneWithDataFrame(const UltrasonicsDataFrameDesc & dataFrameDesc)222*4d7e907cSAndroid Build Coastguard Worker Return<void> EvsUltrasonicsArray::doneWithDataFrame(const UltrasonicsDataFrameDesc& dataFrameDesc) {
223*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "EvsUltrasonicsArray doneWithFrame";
224*4d7e907cSAndroid Build Coastguard Worker 
225*4d7e907cSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mAccessLock);
226*4d7e907cSAndroid Build Coastguard Worker 
227*4d7e907cSAndroid Build Coastguard Worker     if (dataFrameDesc.dataFrameId >= mDataFrames.size()) {
228*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "ignoring doneWithFrame called with invalid dataFrameId "
229*4d7e907cSAndroid Build Coastguard Worker                    << dataFrameDesc.dataFrameId << "(max is " << mDataFrames.size() - 1 << ")";
230*4d7e907cSAndroid Build Coastguard Worker         return Void();
231*4d7e907cSAndroid Build Coastguard Worker     }
232*4d7e907cSAndroid Build Coastguard Worker 
233*4d7e907cSAndroid Build Coastguard Worker     if (!mDataFrames[dataFrameDesc.dataFrameId].inUse) {
234*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "ignoring doneWithFrame called on frame " << dataFrameDesc.dataFrameId
235*4d7e907cSAndroid Build Coastguard Worker                    << "which is already free";
236*4d7e907cSAndroid Build Coastguard Worker         return Void();
237*4d7e907cSAndroid Build Coastguard Worker     }
238*4d7e907cSAndroid Build Coastguard Worker 
239*4d7e907cSAndroid Build Coastguard Worker     // Mark the frame as available
240*4d7e907cSAndroid Build Coastguard Worker     mDataFrames[dataFrameDesc.dataFrameId].inUse = false;
241*4d7e907cSAndroid Build Coastguard Worker     mFramesInUse--;
242*4d7e907cSAndroid Build Coastguard Worker 
243*4d7e907cSAndroid Build Coastguard Worker     // If this frame's index is high in the array, try to move it down
244*4d7e907cSAndroid Build Coastguard Worker     // to improve locality after mFramesAllowed has been reduced.
245*4d7e907cSAndroid Build Coastguard Worker     if (dataFrameDesc.dataFrameId >= mFramesAllowed) {
246*4d7e907cSAndroid Build Coastguard Worker         // Find an empty slot lower in the array (which should always exist in this case)
247*4d7e907cSAndroid Build Coastguard Worker         for (auto&& dataFrame : mDataFrames) {
248*4d7e907cSAndroid Build Coastguard Worker             if (!dataFrame.sharedMemory.IsValid()) {
249*4d7e907cSAndroid Build Coastguard Worker                 dataFrame.sharedMemory = mDataFrames[dataFrameDesc.dataFrameId].sharedMemory;
250*4d7e907cSAndroid Build Coastguard Worker                 mDataFrames[dataFrameDesc.dataFrameId].sharedMemory.clear();
251*4d7e907cSAndroid Build Coastguard Worker                 return Void();
252*4d7e907cSAndroid Build Coastguard Worker             }
253*4d7e907cSAndroid Build Coastguard Worker         }
254*4d7e907cSAndroid Build Coastguard Worker     }
255*4d7e907cSAndroid Build Coastguard Worker 
256*4d7e907cSAndroid Build Coastguard Worker     return Void();
257*4d7e907cSAndroid Build Coastguard Worker }
258*4d7e907cSAndroid Build Coastguard Worker 
startStream(const::android::sp<IEvsUltrasonicsArrayStream> & stream)259*4d7e907cSAndroid Build Coastguard Worker Return<EvsResult> EvsUltrasonicsArray::startStream(
260*4d7e907cSAndroid Build Coastguard Worker         const ::android::sp<IEvsUltrasonicsArrayStream>& stream) {
261*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "EvsUltrasonicsArray startStream";
262*4d7e907cSAndroid Build Coastguard Worker 
263*4d7e907cSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mAccessLock);
264*4d7e907cSAndroid Build Coastguard Worker 
265*4d7e907cSAndroid Build Coastguard Worker     if (mStreamState != STOPPED) {
266*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "ignoring startStream call when a stream is already running.";
267*4d7e907cSAndroid Build Coastguard Worker         return EvsResult::STREAM_ALREADY_RUNNING;
268*4d7e907cSAndroid Build Coastguard Worker     }
269*4d7e907cSAndroid Build Coastguard Worker 
270*4d7e907cSAndroid Build Coastguard Worker     // If the client never indicated otherwise, configure ourselves for a single streaming buffer
271*4d7e907cSAndroid Build Coastguard Worker     if (mFramesAllowed < 1) {
272*4d7e907cSAndroid Build Coastguard Worker         if (!setAvailableFrames_Locked(1)) {
273*4d7e907cSAndroid Build Coastguard Worker             LOG(ERROR)
274*4d7e907cSAndroid Build Coastguard Worker                     << "Failed to start stream because we couldn't get shared memory data buffer";
275*4d7e907cSAndroid Build Coastguard Worker             return EvsResult::BUFFER_NOT_AVAILABLE;
276*4d7e907cSAndroid Build Coastguard Worker         }
277*4d7e907cSAndroid Build Coastguard Worker     }
278*4d7e907cSAndroid Build Coastguard Worker 
279*4d7e907cSAndroid Build Coastguard Worker     // Record the user's callback for use when we have a frame ready
280*4d7e907cSAndroid Build Coastguard Worker     mStream = stream;
281*4d7e907cSAndroid Build Coastguard Worker 
282*4d7e907cSAndroid Build Coastguard Worker     // Start the frame generation thread
283*4d7e907cSAndroid Build Coastguard Worker     mStreamState = RUNNING;
284*4d7e907cSAndroid Build Coastguard Worker     mCaptureThread = std::thread([this]() { generateDataFrames(); });
285*4d7e907cSAndroid Build Coastguard Worker 
286*4d7e907cSAndroid Build Coastguard Worker     return EvsResult::OK;
287*4d7e907cSAndroid Build Coastguard Worker }
288*4d7e907cSAndroid Build Coastguard Worker 
stopStream()289*4d7e907cSAndroid Build Coastguard Worker Return<void> EvsUltrasonicsArray::stopStream() {
290*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "EvsUltrasonicsArray stopStream";
291*4d7e907cSAndroid Build Coastguard Worker 
292*4d7e907cSAndroid Build Coastguard Worker     bool streamStateStopping = false;
293*4d7e907cSAndroid Build Coastguard Worker     {
294*4d7e907cSAndroid Build Coastguard Worker         std::lock_guard<std::mutex> lock(mAccessLock);
295*4d7e907cSAndroid Build Coastguard Worker         if (mStreamState == RUNNING) {
296*4d7e907cSAndroid Build Coastguard Worker             // Tell the GenerateFrames loop we want it to stop
297*4d7e907cSAndroid Build Coastguard Worker             mStreamState = STOPPING;
298*4d7e907cSAndroid Build Coastguard Worker             streamStateStopping = true;
299*4d7e907cSAndroid Build Coastguard Worker         }
300*4d7e907cSAndroid Build Coastguard Worker     }
301*4d7e907cSAndroid Build Coastguard Worker 
302*4d7e907cSAndroid Build Coastguard Worker     if (streamStateStopping) {
303*4d7e907cSAndroid Build Coastguard Worker         // Block outside the mutex until the "stop" flag has been acknowledged
304*4d7e907cSAndroid Build Coastguard Worker         // We won't send any more frames, but the client might still get some already in flight
305*4d7e907cSAndroid Build Coastguard Worker         LOG(DEBUG) << "Waiting for stream thread to end...";
306*4d7e907cSAndroid Build Coastguard Worker         mCaptureThread.join();
307*4d7e907cSAndroid Build Coastguard Worker     }
308*4d7e907cSAndroid Build Coastguard Worker 
309*4d7e907cSAndroid Build Coastguard Worker     {
310*4d7e907cSAndroid Build Coastguard Worker         std::lock_guard<std::mutex> lock(mAccessLock);
311*4d7e907cSAndroid Build Coastguard Worker         mStreamState = STOPPED;
312*4d7e907cSAndroid Build Coastguard Worker         mStream = nullptr;
313*4d7e907cSAndroid Build Coastguard Worker         LOG(DEBUG) << "Stream marked STOPPED.";
314*4d7e907cSAndroid Build Coastguard Worker     }
315*4d7e907cSAndroid Build Coastguard Worker 
316*4d7e907cSAndroid Build Coastguard Worker     return Void();
317*4d7e907cSAndroid Build Coastguard Worker }
318*4d7e907cSAndroid Build Coastguard Worker 
setAvailableFrames_Locked(unsigned bufferCount)319*4d7e907cSAndroid Build Coastguard Worker bool EvsUltrasonicsArray::setAvailableFrames_Locked(unsigned bufferCount) {
320*4d7e907cSAndroid Build Coastguard Worker     if (bufferCount < 1) {
321*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "Ignoring request to set buffer count to zero";
322*4d7e907cSAndroid Build Coastguard Worker         return false;
323*4d7e907cSAndroid Build Coastguard Worker     }
324*4d7e907cSAndroid Build Coastguard Worker     if (bufferCount > kMaximumDataFramesInFlight) {
325*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "Rejecting buffer request in excess of internal limit";
326*4d7e907cSAndroid Build Coastguard Worker         return false;
327*4d7e907cSAndroid Build Coastguard Worker     }
328*4d7e907cSAndroid Build Coastguard Worker 
329*4d7e907cSAndroid Build Coastguard Worker     // Is an increase required?
330*4d7e907cSAndroid Build Coastguard Worker     if (mFramesAllowed < bufferCount) {
331*4d7e907cSAndroid Build Coastguard Worker         // An increase is required
332*4d7e907cSAndroid Build Coastguard Worker         unsigned needed = bufferCount - mFramesAllowed;
333*4d7e907cSAndroid Build Coastguard Worker         LOG(INFO) << "Number of data frame buffers to add: " << needed;
334*4d7e907cSAndroid Build Coastguard Worker 
335*4d7e907cSAndroid Build Coastguard Worker         unsigned added = increaseAvailableFrames_Locked(needed);
336*4d7e907cSAndroid Build Coastguard Worker         if (added != needed) {
337*4d7e907cSAndroid Build Coastguard Worker             // If we didn't add all the frames we needed, then roll back to the previous state
338*4d7e907cSAndroid Build Coastguard Worker             LOG(ERROR) << "Rolling back to previous frame queue size";
339*4d7e907cSAndroid Build Coastguard Worker             decreaseAvailableFrames_Locked(added);
340*4d7e907cSAndroid Build Coastguard Worker             return false;
341*4d7e907cSAndroid Build Coastguard Worker         }
342*4d7e907cSAndroid Build Coastguard Worker     } else if (mFramesAllowed > bufferCount) {
343*4d7e907cSAndroid Build Coastguard Worker         // A decrease is required
344*4d7e907cSAndroid Build Coastguard Worker         unsigned framesToRelease = mFramesAllowed - bufferCount;
345*4d7e907cSAndroid Build Coastguard Worker         LOG(INFO) << "Number of data frame buffers to reduce: " << framesToRelease;
346*4d7e907cSAndroid Build Coastguard Worker 
347*4d7e907cSAndroid Build Coastguard Worker         unsigned released = decreaseAvailableFrames_Locked(framesToRelease);
348*4d7e907cSAndroid Build Coastguard Worker         if (released != framesToRelease) {
349*4d7e907cSAndroid Build Coastguard Worker             // This shouldn't happen with a properly behaving client because the client
350*4d7e907cSAndroid Build Coastguard Worker             // should only make this call after returning sufficient outstanding buffers
351*4d7e907cSAndroid Build Coastguard Worker             // to allow a clean resize.
352*4d7e907cSAndroid Build Coastguard Worker             LOG(ERROR) << "Buffer queue shrink failed -- too many buffers currently in use?";
353*4d7e907cSAndroid Build Coastguard Worker         }
354*4d7e907cSAndroid Build Coastguard Worker     }
355*4d7e907cSAndroid Build Coastguard Worker 
356*4d7e907cSAndroid Build Coastguard Worker     return true;
357*4d7e907cSAndroid Build Coastguard Worker }
358*4d7e907cSAndroid Build Coastguard Worker 
allocateAndMapSharedMemory()359*4d7e907cSAndroid Build Coastguard Worker EvsUltrasonicsArray::SharedMemory EvsUltrasonicsArray::allocateAndMapSharedMemory() {
360*4d7e907cSAndroid Build Coastguard Worker     SharedMemory sharedMemory;
361*4d7e907cSAndroid Build Coastguard Worker 
362*4d7e907cSAndroid Build Coastguard Worker     // Check shared memory allocator is valid.
363*4d7e907cSAndroid Build Coastguard Worker     if (mShmemAllocator.get() == nullptr) {
364*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "Shared memory allocator not initialized.";
365*4d7e907cSAndroid Build Coastguard Worker         return SharedMemory();
366*4d7e907cSAndroid Build Coastguard Worker     }
367*4d7e907cSAndroid Build Coastguard Worker 
368*4d7e907cSAndroid Build Coastguard Worker     // Allocate memory.
369*4d7e907cSAndroid Build Coastguard Worker     bool allocateSuccess = false;
370*4d7e907cSAndroid Build Coastguard Worker     Return<void> result = mShmemAllocator->allocate(kSharedMemoryMaxSize,
371*4d7e907cSAndroid Build Coastguard Worker                                                     [&](bool success, const hidl_memory& hidlMem) {
372*4d7e907cSAndroid Build Coastguard Worker                                                         if (!success) {
373*4d7e907cSAndroid Build Coastguard Worker                                                             return;
374*4d7e907cSAndroid Build Coastguard Worker                                                         }
375*4d7e907cSAndroid Build Coastguard Worker                                                         allocateSuccess = success;
376*4d7e907cSAndroid Build Coastguard Worker                                                         sharedMemory.hidlMemory = hidlMem;
377*4d7e907cSAndroid Build Coastguard Worker                                                     });
378*4d7e907cSAndroid Build Coastguard Worker 
379*4d7e907cSAndroid Build Coastguard Worker     // Check result of allocated memory.
380*4d7e907cSAndroid Build Coastguard Worker     if (!result.isOk() || !allocateSuccess) {
381*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "Shared memory allocation failed.";
382*4d7e907cSAndroid Build Coastguard Worker         return SharedMemory();
383*4d7e907cSAndroid Build Coastguard Worker     }
384*4d7e907cSAndroid Build Coastguard Worker 
385*4d7e907cSAndroid Build Coastguard Worker     // Map shared memory.
386*4d7e907cSAndroid Build Coastguard Worker     sharedMemory.pIMemory = mapMemory(sharedMemory.hidlMemory);
387*4d7e907cSAndroid Build Coastguard Worker     if (sharedMemory.pIMemory.get() == nullptr) {
388*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "Shared memory mapping failed.";
389*4d7e907cSAndroid Build Coastguard Worker         return SharedMemory();
390*4d7e907cSAndroid Build Coastguard Worker     }
391*4d7e907cSAndroid Build Coastguard Worker 
392*4d7e907cSAndroid Build Coastguard Worker     // Return success.
393*4d7e907cSAndroid Build Coastguard Worker     return sharedMemory;
394*4d7e907cSAndroid Build Coastguard Worker }
395*4d7e907cSAndroid Build Coastguard Worker 
increaseAvailableFrames_Locked(unsigned numToAdd)396*4d7e907cSAndroid Build Coastguard Worker unsigned EvsUltrasonicsArray::increaseAvailableFrames_Locked(unsigned numToAdd) {
397*4d7e907cSAndroid Build Coastguard Worker     unsigned added = 0;
398*4d7e907cSAndroid Build Coastguard Worker 
399*4d7e907cSAndroid Build Coastguard Worker     while (added < numToAdd) {
400*4d7e907cSAndroid Build Coastguard Worker         SharedMemory sharedMemory = allocateAndMapSharedMemory();
401*4d7e907cSAndroid Build Coastguard Worker 
402*4d7e907cSAndroid Build Coastguard Worker         // If allocate and map fails, break.
403*4d7e907cSAndroid Build Coastguard Worker         if (!sharedMemory.IsValid()) {
404*4d7e907cSAndroid Build Coastguard Worker             break;
405*4d7e907cSAndroid Build Coastguard Worker         }
406*4d7e907cSAndroid Build Coastguard Worker 
407*4d7e907cSAndroid Build Coastguard Worker         // Find a place to store the new buffer
408*4d7e907cSAndroid Build Coastguard Worker         bool stored = false;
409*4d7e907cSAndroid Build Coastguard Worker         for (auto&& dataFrame : mDataFrames) {
410*4d7e907cSAndroid Build Coastguard Worker             if (!dataFrame.sharedMemory.IsValid()) {
411*4d7e907cSAndroid Build Coastguard Worker                 // Use this existing entry
412*4d7e907cSAndroid Build Coastguard Worker                 dataFrame.sharedMemory = sharedMemory;
413*4d7e907cSAndroid Build Coastguard Worker                 dataFrame.inUse = false;
414*4d7e907cSAndroid Build Coastguard Worker                 stored = true;
415*4d7e907cSAndroid Build Coastguard Worker                 break;
416*4d7e907cSAndroid Build Coastguard Worker             }
417*4d7e907cSAndroid Build Coastguard Worker         }
418*4d7e907cSAndroid Build Coastguard Worker 
419*4d7e907cSAndroid Build Coastguard Worker         if (!stored) {
420*4d7e907cSAndroid Build Coastguard Worker             // Add a BufferRecord wrapping this handle to our set of available buffers
421*4d7e907cSAndroid Build Coastguard Worker             mDataFrames.emplace_back(sharedMemory);
422*4d7e907cSAndroid Build Coastguard Worker         }
423*4d7e907cSAndroid Build Coastguard Worker 
424*4d7e907cSAndroid Build Coastguard Worker         mFramesAllowed++;
425*4d7e907cSAndroid Build Coastguard Worker         added++;
426*4d7e907cSAndroid Build Coastguard Worker     }
427*4d7e907cSAndroid Build Coastguard Worker 
428*4d7e907cSAndroid Build Coastguard Worker     return added;
429*4d7e907cSAndroid Build Coastguard Worker }
430*4d7e907cSAndroid Build Coastguard Worker 
decreaseAvailableFrames_Locked(unsigned numToRemove)431*4d7e907cSAndroid Build Coastguard Worker unsigned EvsUltrasonicsArray::decreaseAvailableFrames_Locked(unsigned numToRemove) {
432*4d7e907cSAndroid Build Coastguard Worker     unsigned removed = 0;
433*4d7e907cSAndroid Build Coastguard Worker 
434*4d7e907cSAndroid Build Coastguard Worker     for (auto&& dataFrame : mDataFrames) {
435*4d7e907cSAndroid Build Coastguard Worker         // Is this record not in use, but holding a buffer that we can free?
436*4d7e907cSAndroid Build Coastguard Worker         if (!dataFrame.inUse && dataFrame.sharedMemory.IsValid()) {
437*4d7e907cSAndroid Build Coastguard Worker             // Release buffer and update the record so we can recognize it as "empty"
438*4d7e907cSAndroid Build Coastguard Worker             dataFrame.sharedMemory.clear();
439*4d7e907cSAndroid Build Coastguard Worker 
440*4d7e907cSAndroid Build Coastguard Worker             mFramesAllowed--;
441*4d7e907cSAndroid Build Coastguard Worker             removed++;
442*4d7e907cSAndroid Build Coastguard Worker 
443*4d7e907cSAndroid Build Coastguard Worker             if (removed == numToRemove) {
444*4d7e907cSAndroid Build Coastguard Worker                 break;
445*4d7e907cSAndroid Build Coastguard Worker             }
446*4d7e907cSAndroid Build Coastguard Worker         }
447*4d7e907cSAndroid Build Coastguard Worker     }
448*4d7e907cSAndroid Build Coastguard Worker 
449*4d7e907cSAndroid Build Coastguard Worker     return removed;
450*4d7e907cSAndroid Build Coastguard Worker }
451*4d7e907cSAndroid Build Coastguard Worker 
452*4d7e907cSAndroid Build Coastguard Worker // This is the asynchronous data frame generation thread that runs in parallel with the
453*4d7e907cSAndroid Build Coastguard Worker // main serving thread. There is one for each active ultrasonic array instance.
generateDataFrames()454*4d7e907cSAndroid Build Coastguard Worker void EvsUltrasonicsArray::generateDataFrames() {
455*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "Data frame generation loop started";
456*4d7e907cSAndroid Build Coastguard Worker 
457*4d7e907cSAndroid Build Coastguard Worker     unsigned idx = 0;
458*4d7e907cSAndroid Build Coastguard Worker 
459*4d7e907cSAndroid Build Coastguard Worker     while (true) {
460*4d7e907cSAndroid Build Coastguard Worker         bool timeForFrame = false;
461*4d7e907cSAndroid Build Coastguard Worker 
462*4d7e907cSAndroid Build Coastguard Worker         nsecs_t startTime = elapsedRealtimeNano();
463*4d7e907cSAndroid Build Coastguard Worker 
464*4d7e907cSAndroid Build Coastguard Worker         // Lock scope for updating shared state
465*4d7e907cSAndroid Build Coastguard Worker         {
466*4d7e907cSAndroid Build Coastguard Worker             std::lock_guard<std::mutex> lock(mAccessLock);
467*4d7e907cSAndroid Build Coastguard Worker 
468*4d7e907cSAndroid Build Coastguard Worker             if (mStreamState != RUNNING) {
469*4d7e907cSAndroid Build Coastguard Worker                 // Break out of our main thread loop
470*4d7e907cSAndroid Build Coastguard Worker                 break;
471*4d7e907cSAndroid Build Coastguard Worker             }
472*4d7e907cSAndroid Build Coastguard Worker 
473*4d7e907cSAndroid Build Coastguard Worker             // Are we allowed to issue another buffer?
474*4d7e907cSAndroid Build Coastguard Worker             if (mFramesInUse >= mFramesAllowed) {
475*4d7e907cSAndroid Build Coastguard Worker                 // Can't do anything right now -- skip this frame
476*4d7e907cSAndroid Build Coastguard Worker                 LOG(WARNING) << "Skipped a frame because too many are in flight";
477*4d7e907cSAndroid Build Coastguard Worker             } else {
478*4d7e907cSAndroid Build Coastguard Worker                 // Identify an available buffer to fill
479*4d7e907cSAndroid Build Coastguard Worker                 for (idx = 0; idx < mDataFrames.size(); idx++) {
480*4d7e907cSAndroid Build Coastguard Worker                     if (!mDataFrames[idx].inUse && mDataFrames[idx].sharedMemory.IsValid()) {
481*4d7e907cSAndroid Build Coastguard Worker                         // Found an available record, so stop looking
482*4d7e907cSAndroid Build Coastguard Worker                         break;
483*4d7e907cSAndroid Build Coastguard Worker                     }
484*4d7e907cSAndroid Build Coastguard Worker                 }
485*4d7e907cSAndroid Build Coastguard Worker                 if (idx >= mDataFrames.size()) {
486*4d7e907cSAndroid Build Coastguard Worker                     // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed
487*4d7e907cSAndroid Build Coastguard Worker                     LOG(ERROR) << "Failed to find an available buffer slot";
488*4d7e907cSAndroid Build Coastguard Worker                 } else {
489*4d7e907cSAndroid Build Coastguard Worker                     // We're going to make the frame busy
490*4d7e907cSAndroid Build Coastguard Worker                     mDataFrames[idx].inUse = true;
491*4d7e907cSAndroid Build Coastguard Worker                     mFramesInUse++;
492*4d7e907cSAndroid Build Coastguard Worker                     timeForFrame = true;
493*4d7e907cSAndroid Build Coastguard Worker                 }
494*4d7e907cSAndroid Build Coastguard Worker             }
495*4d7e907cSAndroid Build Coastguard Worker         }
496*4d7e907cSAndroid Build Coastguard Worker 
497*4d7e907cSAndroid Build Coastguard Worker         if (timeForFrame) {
498*4d7e907cSAndroid Build Coastguard Worker             // Assemble the buffer description we'll transmit below
499*4d7e907cSAndroid Build Coastguard Worker             UltrasonicsDataFrameDesc mockDataFrameDesc;
500*4d7e907cSAndroid Build Coastguard Worker             mockDataFrameDesc.dataFrameId = idx;
501*4d7e907cSAndroid Build Coastguard Worker             mockDataFrameDesc.waveformsData = mDataFrames[idx].sharedMemory.hidlMemory;
502*4d7e907cSAndroid Build Coastguard Worker 
503*4d7e907cSAndroid Build Coastguard Worker             // Fill mock waveform data.
504*4d7e907cSAndroid Build Coastguard Worker             fillMockDataFrame(mockDataFrameDesc, mDataFrames[idx].sharedMemory.pIMemory);
505*4d7e907cSAndroid Build Coastguard Worker 
506*4d7e907cSAndroid Build Coastguard Worker             // Issue the (asynchronous) callback to the client -- can't be holding the lock
507*4d7e907cSAndroid Build Coastguard Worker             auto result = mStream->deliverDataFrame(mockDataFrameDesc);
508*4d7e907cSAndroid Build Coastguard Worker             if (result.isOk()) {
509*4d7e907cSAndroid Build Coastguard Worker                 LOG(DEBUG) << "Delivered data frame id: " << mockDataFrameDesc.dataFrameId;
510*4d7e907cSAndroid Build Coastguard Worker             } else {
511*4d7e907cSAndroid Build Coastguard Worker                 // This can happen if the client dies and is likely unrecoverable.
512*4d7e907cSAndroid Build Coastguard Worker                 // To avoid consuming resources generating failing calls, we stop sending
513*4d7e907cSAndroid Build Coastguard Worker                 // frames.  Note, however, that the stream remains in the "STREAMING" state
514*4d7e907cSAndroid Build Coastguard Worker                 // until cleaned up on the main thread.
515*4d7e907cSAndroid Build Coastguard Worker                 LOG(ERROR) << "Frame delivery call failed in the transport layer.";
516*4d7e907cSAndroid Build Coastguard Worker 
517*4d7e907cSAndroid Build Coastguard Worker                 // Since we didn't actually deliver it, mark the frame as available
518*4d7e907cSAndroid Build Coastguard Worker                 std::lock_guard<std::mutex> lock(mAccessLock);
519*4d7e907cSAndroid Build Coastguard Worker                 mDataFrames[idx].inUse = false;
520*4d7e907cSAndroid Build Coastguard Worker                 mFramesInUse--;
521*4d7e907cSAndroid Build Coastguard Worker 
522*4d7e907cSAndroid Build Coastguard Worker                 break;
523*4d7e907cSAndroid Build Coastguard Worker             }
524*4d7e907cSAndroid Build Coastguard Worker         }
525*4d7e907cSAndroid Build Coastguard Worker 
526*4d7e907cSAndroid Build Coastguard Worker         // Sleep to generate frames at kTargetFrameRate.
527*4d7e907cSAndroid Build Coastguard Worker         static const nsecs_t kTargetFrameTimeUs = 1000 * 1000 / kTargetFrameRate;
528*4d7e907cSAndroid Build Coastguard Worker         const nsecs_t now = elapsedRealtimeNano();
529*4d7e907cSAndroid Build Coastguard Worker         const nsecs_t workTimeUs = (now - startTime) / 1000;
530*4d7e907cSAndroid Build Coastguard Worker         const nsecs_t sleepDurationUs = kTargetFrameTimeUs - workTimeUs;
531*4d7e907cSAndroid Build Coastguard Worker         if (sleepDurationUs > 0) {
532*4d7e907cSAndroid Build Coastguard Worker             usleep(sleepDurationUs);
533*4d7e907cSAndroid Build Coastguard Worker         }
534*4d7e907cSAndroid Build Coastguard Worker     }
535*4d7e907cSAndroid Build Coastguard Worker 
536*4d7e907cSAndroid Build Coastguard Worker     // If we've been asked to stop, send an event to signal the actual end of stream
537*4d7e907cSAndroid Build Coastguard Worker     EvsEventDesc event;
538*4d7e907cSAndroid Build Coastguard Worker     event.aType = EvsEventType::STREAM_STOPPED;
539*4d7e907cSAndroid Build Coastguard Worker     auto result = mStream->notify(event);
540*4d7e907cSAndroid Build Coastguard Worker     if (!result.isOk()) {
541*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "Error delivering end of stream marker";
542*4d7e907cSAndroid Build Coastguard Worker     }
543*4d7e907cSAndroid Build Coastguard Worker }
544*4d7e907cSAndroid Build Coastguard Worker 
545*4d7e907cSAndroid Build Coastguard Worker }  // namespace implementation
546*4d7e907cSAndroid Build Coastguard Worker }  // namespace V1_1
547*4d7e907cSAndroid Build Coastguard Worker }  // namespace evs
548*4d7e907cSAndroid Build Coastguard Worker }  // namespace automotive
549*4d7e907cSAndroid Build Coastguard Worker }  // namespace hardware
550*4d7e907cSAndroid Build Coastguard Worker }  // namespace android
551