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