[SV HIDL] Default implementation for Surround View
Bug: 148618804
Test: atest -c VtsHalSurroundViewV1_0TargetTest (tested together with Change-id I1c6bfa77adb699ab80337497aac4582861315bcd)
Change-Id: Ibc9e32d9cc6c93ca71f34bc54e3bdecdf2c4dba2
diff --git a/automotive/sv/1.0/default/Android.bp b/automotive/sv/1.0/default/Android.bp
new file mode 100644
index 0000000..8417949
--- /dev/null
+++ b/automotive/sv/1.0/default/Android.bp
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+ name: "android.hardware.automotive.sv@1.0-service",
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "service.cpp",
+ "SurroundViewService.cpp",
+ "SurroundView2dSession.cpp",
+ "SurroundView3dSession.cpp",
+ ],
+ init_rc: ["android.hardware.automotive.sv@1.0-service.rc"],
+ vintf_fragments: ["android.hardware.automotive.sv@1.0-service.xml"],
+ shared_libs: [
+ "android.hardware.automotive.sv@1.0",
+ "android.hidl.memory@1.0",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libui",
+ "libutils",
+ "libhidlmemory",
+ ],
+
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/automotive/sv/1.0/default/SurroundView2dSession.cpp b/automotive/sv/1.0/default/SurroundView2dSession.cpp
new file mode 100644
index 0000000..4f97598
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView2dSession.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SurroundView2dSession.h"
+
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+SurroundView2dSession::SurroundView2dSession() :
+ mStreamState(STOPPED) {
+ mEvsCameraIds = {"0" , "1", "2", "3"};
+
+ mConfig.width = 640;
+ mConfig.blending = SvQuality::HIGH;
+
+ framesRecord.frames.svBuffers.resize(1);
+ framesRecord.frames.svBuffers[0].viewId = 0;
+ framesRecord.frames.svBuffers[0].hardwareBuffer.nativeHandle =
+ new native_handle_t();
+ framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] =
+ mConfig.width;
+ framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] =
+ mConfig.width * 3 / 4;
+}
+
+// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession
+Return<SvResult> SurroundView2dSession::startStream(
+ const sp<ISurroundViewStream>& stream) {
+ ALOGD("SurroundView2dSession::startStream");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (mStreamState != STOPPED) {
+ ALOGE("ignoring startVideoStream call"
+ "when a stream is already running.");
+ return SvResult::INTERNAL_ERROR;
+ }
+
+ mStream = stream;
+
+ ALOGD("Notify SvEvent::STREAM_STARTED");
+ mStream->notify(SvEvent::STREAM_STARTED);
+
+ // Start the frame generation thread
+ mStreamState = RUNNING;
+ mCaptureThread = std::thread([this](){ generateFrames(); });
+
+ return SvResult::OK;
+}
+
+Return<void> SurroundView2dSession::stopStream() {
+ ALOGD("SurroundView2dSession::stopStream");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ if (mStreamState == RUNNING) {
+ // Tell the GenerateFrames loop we want it to stop
+ mStreamState = STOPPING;
+
+ // Block outside the mutex until the "stop" flag has been acknowledged
+ // We won't send any more frames, but the client might still get some
+ // already in flight
+ ALOGD("Waiting for stream thread to end...");
+ lock.unlock();
+ mCaptureThread.join();
+ lock.lock();
+
+ mStreamState = STOPPED;
+ mStream = nullptr;
+ ALOGD("Stream marked STOPPED.");
+ }
+
+ return android::hardware::Void();
+}
+
+Return<void> SurroundView2dSession::doneWithFrames(
+ const SvFramesDesc& svFramesDesc){
+ ALOGD("SurroundView2dSession::doneWithFrames");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ framesRecord.inUse = false;
+
+ (void)svFramesDesc;
+ return android::hardware::Void();
+}
+
+// Methods from ISurroundView2dSession follow.
+Return<void> SurroundView2dSession::get2dMappingInfo(
+ get2dMappingInfo_cb _hidl_cb) {
+ ALOGD("SurroundView2dSession::get2dMappingInfo");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ Sv2dMappingInfo info;
+ info.width = 8; // keeps ratio to 4:3
+ info.height = 6;
+ info.center.isValid = true;
+ info.center.x = 0;
+ info.center.y = 0;
+ _hidl_cb(info);
+ return android::hardware::Void();
+}
+
+Return<SvResult> SurroundView2dSession::set2dConfig(
+ const Sv2dConfig& sv2dConfig) {
+ ALOGD("SurroundView2dSession::setConfig");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ mConfig.width = sv2dConfig.width;
+ mConfig.blending = sv2dConfig.blending;
+ ALOGD("Notify SvEvent::CONFIG_UPDATED");
+ mStream->notify(SvEvent::CONFIG_UPDATED);
+
+ return SvResult::OK;
+}
+
+Return<void> SurroundView2dSession::get2dConfig(get2dConfig_cb _hidl_cb) {
+ ALOGD("SurroundView2dSession::getConfig");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ _hidl_cb(mConfig);
+ return android::hardware::Void();
+}
+
+Return<void> SurroundView2dSession::projectCameraPoints(
+ const hidl_vec<Point2dInt>& points2dCamera,
+ const hidl_string& cameraId,
+ projectCameraPoints_cb _hidl_cb) {
+ ALOGD("SurroundView2dSession::projectCameraPoints");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ bool cameraIdFound = false;
+ for (auto evsCameraId : mEvsCameraIds) {
+ if (cameraId == evsCameraId) {
+ cameraIdFound = true;
+ ALOGI("Camera id found.");
+ break;
+ }
+ }
+
+ if (!cameraIdFound) {
+ ALOGE("Camera id not found.");
+ _hidl_cb(hidl_vec<Point2dFloat>());
+ return android::hardware::Void();
+ }
+
+ hidl_vec<Point2dFloat> outPoints;
+ outPoints.resize(points2dCamera.size());
+
+ int width = mConfig.width;
+ int height = mConfig.width * 3 / 4;
+ for (int i=0; i<points2dCamera.size(); i++) {
+ // Assuming all the points in the image frame can be projected into 2d
+ // Surround View space. Otherwise cannot.
+ if (points2dCamera[i].x < 0 || points2dCamera[i].y > width-1 ||
+ points2dCamera[i].x < 0 || points2dCamera[i].y > height-1) {
+ ALOGW("SurroundView2dSession::projectCameraPoints "
+ "gets invalid 2d camera points. Ignored");
+ outPoints[i].isValid = false;
+ outPoints[i].x = 10000;
+ outPoints[i].y = 10000;
+ } else {
+ outPoints[i].isValid = true;
+ outPoints[i].x = 0;
+ outPoints[i].y = 0;
+ }
+ }
+
+ _hidl_cb(outPoints);
+ return android::hardware::Void();
+}
+
+void SurroundView2dSession::generateFrames() {
+ ALOGD("SurroundView2dSession::generateFrames");
+
+ int sequenceId = 0;
+
+ while(true) {
+ {
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (mStreamState != RUNNING) {
+ // Break out of our main thread loop
+ break;
+ }
+
+ framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] =
+ mConfig.width;
+ framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] =
+ mConfig.width * 3 / 4;
+ }
+
+ usleep(100 * 1000);
+
+ framesRecord.frames.timestampNs = elapsedRealtimeNano();
+ framesRecord.frames.sequenceId = sequenceId++;
+
+ {
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (framesRecord.inUse) {
+ ALOGD("Notify SvEvent::FRAME_DROPPED");
+ mStream->notify(SvEvent::FRAME_DROPPED);
+ } else {
+ framesRecord.inUse = true;
+ mStream->receiveFrames(framesRecord.frames);
+ }
+ }
+ }
+
+ // If we've been asked to stop, send an event to signal the actual
+ // end of stream
+ ALOGD("Notify SvEvent::STREAM_STOPPED");
+ mStream->notify(SvEvent::STREAM_STOPPED);
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundView2dSession.h b/automotive/sv/1.0/default/SurroundView2dSession.h
new file mode 100644
index 0000000..ee751e7
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView2dSession.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <thread>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+using ::std::mutex;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundView2dSession : public ISurroundView2dSession {
+public:
+ SurroundView2dSession();
+
+ // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+ Return<SvResult> startStream(
+ const sp<ISurroundViewStream>& stream) override;
+ Return<void> stopStream() override;
+ Return<void> doneWithFrames(const SvFramesDesc& svFramesDesc) override;
+
+ // Methods from ISurroundView2dSession follow.
+ Return<void> get2dMappingInfo(get2dMappingInfo_cb _hidl_cb) override;
+ Return<SvResult> set2dConfig(const Sv2dConfig& sv2dConfig) override;
+ Return<void> get2dConfig(get2dConfig_cb _hidl_cb) override;
+ Return<void> projectCameraPoints(
+ const hidl_vec<Point2dInt>& points2dCamera,
+ const hidl_string& cameraId,
+ projectCameraPoints_cb _hidl_cb) override;
+
+ // TODO(tanmayp): Make private and add set/get method.
+ // Stream subscribed for the session.
+ sp<ISurroundViewStream> mStream;
+
+private:
+ void generateFrames();
+
+ enum StreamStateValues {
+ STOPPED,
+ RUNNING,
+ STOPPING,
+ DEAD,
+ };
+ StreamStateValues mStreamState;
+
+ Sv2dConfig mConfig;
+
+ std::thread mCaptureThread; // The thread we'll use to synthesize frames
+
+ struct FramesRecord {
+ SvFramesDesc frames;
+ bool inUse = false;
+ };
+
+ FramesRecord framesRecord;
+
+ // Synchronization necessary to deconflict mCaptureThread from the main service thread
+ std::mutex mAccessLock;
+
+ std::vector<std::string> mEvsCameraIds;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundView3dSession.cpp b/automotive/sv/1.0/default/SurroundView3dSession.cpp
new file mode 100644
index 0000000..da36f32
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView3dSession.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SurroundView3dSession.h"
+
+#include <set>
+
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hardware::hidl_memory;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+SurroundView3dSession::SurroundView3dSession() :
+ mStreamState(STOPPED){
+
+ mEvsCameraIds = {"0" , "1", "2", "3"};
+
+ mConfig.width = 640;
+ mConfig.height = 480;
+ mConfig.carDetails = SvQuality::HIGH;
+
+ framesRecord.frames.svBuffers.resize(1);
+ framesRecord.frames.svBuffers[0].viewId = 0;
+ framesRecord.frames.svBuffers[0].hardwareBuffer.nativeHandle = new native_handle_t();
+ framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] = mConfig.width;
+ framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] = mConfig.height;
+}
+
+// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+Return<SvResult> SurroundView3dSession::startStream(
+ const sp<ISurroundViewStream>& stream) {
+ ALOGD("SurroundView3dSession::startStream");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (mStreamState != STOPPED) {
+ ALOGE("ignoring startVideoStream call when a stream is already running.");
+ return SvResult::INTERNAL_ERROR;
+ }
+
+ if (mViews.empty()) {
+ ALOGE("No views have been set for current Surround View 3d Session. "
+ "Please call setViews before starting the stream.");
+ return SvResult::VIEW_NOT_SET;
+ }
+
+ mStream = stream;
+
+ ALOGD("Notify SvEvent::STREAM_STARTED");
+ mStream->notify(SvEvent::STREAM_STARTED);
+
+ // Start the frame generation thread
+ mStreamState = RUNNING;
+ mCaptureThread = std::thread([this](){ generateFrames(); });
+
+ return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::stopStream() {
+ ALOGD("SurroundView3dSession::stopStream");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ if (mStreamState == RUNNING) {
+ // Tell the GenerateFrames loop we want it to stop
+ mStreamState = STOPPING;
+
+ // Block outside the mutex until the "stop" flag has been acknowledged
+ // We won't send any more frames, but the client might still get some already in flight
+ ALOGD("Waiting for stream thread to end...");
+ lock.unlock();
+ mCaptureThread.join();
+ lock.lock();
+
+ mStreamState = STOPPED;
+ mStream = nullptr;
+ ALOGD("Stream marked STOPPED.");
+ }
+
+ return android::hardware::Void();
+}
+
+Return<void> SurroundView3dSession::doneWithFrames(
+ const SvFramesDesc& svFramesDesc){
+ ALOGD("SurroundView3dSession::doneWithFrames");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ framesRecord.inUse = false;
+
+ (void)svFramesDesc;
+ return android::hardware::Void();
+}
+
+// Methods from ISurroundView3dSession follow.
+Return<SvResult> SurroundView3dSession::setViews(const hidl_vec<View3d>& views) {
+ ALOGD("SurroundView3dSession::stopStream");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ mViews.resize(views.size());
+ for (int i=0; i<views.size(); i++) {
+ mViews[i] = views[i];
+ }
+
+ return SvResult::OK;
+}
+
+Return<SvResult> SurroundView3dSession::set3dConfig(const Sv3dConfig& sv3dConfig) {
+ ALOGD("SurroundView3dSession::set3dConfig");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ mConfig.width = sv3dConfig.width;
+ mConfig.height = sv3dConfig.height;
+ mConfig.carDetails = sv3dConfig.carDetails;
+ ALOGD("Notify SvEvent::CONFIG_UPDATED");
+ mStream->notify(SvEvent::CONFIG_UPDATED);
+
+ return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::get3dConfig(get3dConfig_cb _hidl_cb) {
+ ALOGD("SurroundView3dSession::get3dConfig");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ _hidl_cb(mConfig);
+ return android::hardware::Void();
+}
+
+bool VerifyOverlayData(const OverlaysData& overlaysData) {
+ // Check size of shared memory matches overlaysMemoryDesc.
+ const int kVertexSize = 16;
+ const int kIdSize = 2;
+ int memDescSize = 0;
+ for (auto overlayMemDesc : overlaysData.overlaysMemoryDesc) {
+ memDescSize += kIdSize + kVertexSize * overlayMemDesc.verticesCount;
+ }
+ if (memDescSize != overlaysData.overlaysMemory.size()) {
+ ALOGE("shared memory and overlaysMemoryDesc size mismatch.");
+ return false;
+ }
+
+ // Map memory.
+ sp<IMemory> pSharedMemory = mapMemory(overlaysData.overlaysMemory);
+ if(pSharedMemory.get() == nullptr) {
+ ALOGE("mapMemory failed.");
+ return false;
+ }
+
+ // Get Data pointer.
+ uint8_t* pData = (uint8_t*)((void*)pSharedMemory->getPointer());
+ if (pData == nullptr) {
+ ALOGE("Shared memory getPointer() failed.");
+ return false;
+ }
+
+ int idOffset = 0;
+ std::set<uint16_t> overlayIdSet;
+ for (auto overlayMemDesc : overlaysData.overlaysMemoryDesc) {
+
+ if (overlayIdSet.find(overlayMemDesc.id) != overlayIdSet.end()) {
+ ALOGE("Duplicate id within memory descriptor.");
+ return false;
+ }
+ overlayIdSet.insert(overlayMemDesc.id);
+
+ if(overlayMemDesc.verticesCount < 3) {
+ ALOGE("Less than 3 vertices.");
+ return false;
+ }
+
+ if (overlayMemDesc.overlayPrimitive == OverlayPrimitive::TRIANGLES &&
+ overlayMemDesc.verticesCount % 3 != 0) {
+ ALOGE("Triangles primitive does not have vertices multiple of 3.");
+ return false;
+ }
+
+ uint16_t overlayId = *((uint16_t*)(pData + idOffset));
+
+ if (overlayId != overlayMemDesc.id) {
+ ALOGE("Overlay id mismatch %d , %d", overlayId, overlayMemDesc.id);
+ return false;
+ }
+
+ idOffset += kIdSize + (kVertexSize * overlayMemDesc.verticesCount);
+ }
+
+ return true;
+}
+
+Return<SvResult> SurroundView3dSession::updateOverlays(
+ const OverlaysData& overlaysData) {
+
+ if(!VerifyOverlayData(overlaysData)) {
+ ALOGE("VerifyOverlayData failed.");
+ return SvResult::INVALID_ARG;
+ }
+
+ return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::projectCameraPointsTo3dSurface(
+ const hidl_vec<Point2dInt>& cameraPoints,
+ const hidl_string& cameraId,
+ projectCameraPointsTo3dSurface_cb _hidl_cb) {
+
+ std::vector<Point3dFloat> points3d;
+ bool cameraIdFound = false;
+ for (auto evsCameraId : mEvsCameraIds) {
+ if (cameraId == evsCameraId) {
+ cameraIdFound = true;
+ ALOGI("Camera id found.");
+ break;
+ }
+ }
+
+ if (!cameraIdFound) {
+ ALOGE("Camera id not found.");
+ _hidl_cb(points3d);
+ return android::hardware::Void();
+ }
+
+ for (const auto cameraPoint : cameraPoints) {
+ Point3dFloat point3d;
+ point3d.isValid = true;
+
+ if (cameraPoint.x < 0 || cameraPoint.x >= mConfig.width-1 ||
+ cameraPoint.y < 0 || cameraPoint.y >= mConfig.height-1) {
+ ALOGE("Camera point out of bounds.");
+ point3d.isValid = false;
+ }
+ points3d.push_back(point3d);
+ }
+ _hidl_cb(points3d);
+ return android::hardware::Void();
+}
+
+void SurroundView3dSession::generateFrames() {
+ ALOGD("SurroundView3dSession::generateFrames");
+
+ int sequenceId = 0;
+
+ while(true) {
+ {
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (mStreamState != RUNNING) {
+ // Break out of our main thread loop
+ break;
+ }
+ }
+
+ usleep(100 * 1000);
+
+ framesRecord.frames.timestampNs = elapsedRealtimeNano();
+ framesRecord.frames.sequenceId = sequenceId++;
+
+ framesRecord.frames.svBuffers.resize(mViews.size());
+ for (int i=0; i<mViews.size(); i++) {
+ framesRecord.frames.svBuffers[i].viewId = mViews[i].viewId;
+ framesRecord.frames.svBuffers[i].hardwareBuffer.nativeHandle = new native_handle_t();
+ framesRecord.frames.svBuffers[i].hardwareBuffer.description[0] = mConfig.width; // width
+ framesRecord.frames.svBuffers[i].hardwareBuffer.description[1] = mConfig.height; // height
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (framesRecord.inUse) {
+ ALOGD("Notify SvEvent::FRAME_DROPPED");
+ mStream->notify(SvEvent::FRAME_DROPPED);
+ } else {
+ framesRecord.inUse = true;
+ mStream->receiveFrames(framesRecord.frames);
+ }
+ }
+ }
+
+ // If we've been asked to stop, send an event to signal the actual end of stream
+ ALOGD("Notify SvEvent::STREAM_STOPPED");
+ mStream->notify(SvEvent::STREAM_STOPPED);
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundView3dSession.h b/automotive/sv/1.0/default/SurroundView3dSession.h
new file mode 100644
index 0000000..5c638db
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView3dSession.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <thread>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+using ::std::mutex;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundView3dSession : public ISurroundView3dSession {
+public:
+ SurroundView3dSession();
+
+ // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+ Return<SvResult> startStream(
+ const sp<ISurroundViewStream>& stream) override;
+ Return<void> stopStream() override;
+ Return<void> doneWithFrames(const SvFramesDesc& svFramesDesc) override;
+
+ // Methods from ISurroundView3dSession follow.
+ Return<SvResult> setViews(const hidl_vec<View3d>& views) override;
+ Return<SvResult> set3dConfig(const Sv3dConfig& sv3dConfig) override;
+ Return<void> get3dConfig(get3dConfig_cb _hidl_cb) override;
+ Return<SvResult> updateOverlays(const OverlaysData& overlaysData);
+ Return<void> projectCameraPointsTo3dSurface(
+ const hidl_vec<Point2dInt>& cameraPoints,
+ const hidl_string& cameraId,
+ projectCameraPointsTo3dSurface_cb _hidl_cb);
+
+ // Stream subscribed for the session.
+ // TODO(tanmayp): Make private and add set/get method.
+ sp<ISurroundViewStream> mStream;
+
+private:
+ void generateFrames();
+
+ enum StreamStateValues {
+ STOPPED,
+ RUNNING,
+ STOPPING,
+ DEAD,
+ };
+ StreamStateValues mStreamState;
+
+ std::thread mCaptureThread; // The thread we'll use to synthesize frames
+
+ struct FramesRecord {
+ SvFramesDesc frames;
+ bool inUse = false;
+ };
+
+ FramesRecord framesRecord;
+
+ // Synchronization necessary to deconflict mCaptureThread from the main service thread
+ std::mutex mAccessLock;
+
+ std::vector<View3d> mViews;
+
+ Sv3dConfig mConfig;
+
+ std::vector<std::string> mEvsCameraIds;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/sv/1.0/default/SurroundViewService.cpp b/automotive/sv/1.0/default/SurroundViewService.cpp
new file mode 100644
index 0000000..fe89dd5
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundViewService.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SurroundViewService.h"
+
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+const std::string kCameraIds[] = {"0", "1", "2", "3"};
+
+Return<void> SurroundViewService::getCameraIds(getCameraIds_cb _hidl_cb) {
+ std::vector<hidl_string> cameraIds = {kCameraIds[0], kCameraIds[1],
+ kCameraIds[2], kCameraIds[3]};
+ _hidl_cb(cameraIds);
+ return android::hardware::Void();
+}
+
+Return<void> SurroundViewService::start2dSession(start2dSession_cb _hidl_cb) {
+ ALOGD("SurroundViewService::start2dSession");
+ if (mSurroundView2dSession != nullptr) {
+ ALOGW("Only one 2d session is supported at the same time");
+ _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
+ } else {
+ mSurroundView2dSession = new SurroundView2dSession();
+ _hidl_cb(mSurroundView2dSession, SvResult::OK);
+ }
+ return android::hardware::Void();
+}
+
+Return<SvResult> SurroundViewService::stop2dSession(
+ const sp<ISurroundView2dSession>& sv2dSession) {
+ ALOGD("SurroundViewService::stop2dSession");
+ if (sv2dSession != nullptr && sv2dSession == mSurroundView2dSession) {
+ mSurroundView2dSession = nullptr;
+ return SvResult::OK;
+ } else {
+ ALOGE("Invalid arg for stop2dSession");
+ return SvResult::INVALID_ARG;
+ }
+}
+
+Return<void> SurroundViewService::start3dSession(start3dSession_cb _hidl_cb) {
+ ALOGD("SurroundViewService::start3dSession");
+ if (mSurroundView3dSession != nullptr) {
+ ALOGW("Only one 3d session is supported at the same time");
+ _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
+ } else {
+ mSurroundView3dSession = new SurroundView3dSession();
+ _hidl_cb(mSurroundView3dSession, SvResult::OK);
+ }
+ return android::hardware::Void();
+}
+
+Return<SvResult> SurroundViewService::stop3dSession(
+ const sp<ISurroundView3dSession>& sv3dSession) {
+ ALOGD("SurroundViewService::stop3dSession");
+ if (sv3dSession != nullptr && sv3dSession == mSurroundView3dSession) {
+ mSurroundView3dSession = nullptr;
+ return SvResult::OK;
+ } else {
+ ALOGE("Invalid arg for stop3dSession");
+ return SvResult::INVALID_ARG;
+ }
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundViewService.h b/automotive/sv/1.0/default/SurroundViewService.h
new file mode 100644
index 0000000..9e0e151
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundViewService.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "SurroundView2dSession.h"
+#include "SurroundView3dSession.h"
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundViewService : public ISurroundViewService {
+public:
+ // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewService follow.
+ Return<void> getCameraIds(getCameraIds_cb _hidl_cb) override;
+ Return<void> start2dSession(start2dSession_cb _hidl_cb) override;
+ Return<SvResult> stop2dSession(
+ const sp<ISurroundView2dSession>& sv2dSession) override;
+
+ Return<void> start3dSession(start3dSession_cb _hidl_cb) override;
+ Return<SvResult> stop3dSession(
+ const sp<ISurroundView3dSession>& sv3dSession) override;
+
+private:
+ sp<SurroundView2dSession> mSurroundView2dSession;
+ sp<SurroundView3dSession> mSurroundView3dSession;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc
new file mode 100644
index 0000000..e822017
--- /dev/null
+++ b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc
@@ -0,0 +1,5 @@
+service sv_service /vendor/bin/hw/android.hardware.automotive.sv@1.0-service
+ class hal
+ user automotive_evs
+ group automotive_evs
+ disabled
diff --git a/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml
new file mode 100644
index 0000000..ba8e5ac
--- /dev/null
+++ b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.automotive.sv</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>ISurroundViewService</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/automotive/sv/1.0/default/service.cpp b/automotive/sv/1.0/default/service.cpp
new file mode 100644
index 0000000..fae7425
--- /dev/null
+++ b/automotive/sv/1.0/default/service.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.automotive.sv@1.0-service"
+
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware_buffer.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <thread>
+#include <ui/GraphicBuffer.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/SystemClock.h>
+
+#include "SurroundViewService.h"
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// implementation:
+using android::hardware::automotive::sv::V1_0::implementation::SurroundViewService;
+
+int main() {
+ ALOGI("ISurroundViewService default implementation is starting");
+ android::sp<ISurroundViewService> service = new SurroundViewService();
+
+ configureRpcThreadpool(1, true /* callerWillJoin */);
+
+ // Register our service -- if somebody is already registered by our name,
+ // they will be killed (their thread pool will throw an exception).
+ android::status_t status = service->registerAsService();
+
+ LOG_ALWAYS_FATAL_IF(status != android::OK,
+ "Could not register default Surround View Service (%d)",
+ status);
+
+ joinRpcThreadpool();
+
+ // In normal operation, we don't expect the thread pool to exit
+ ALOGE("Surround View Service is shutting down");
+ return 1;
+}