1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "AidlCameraStream.h"
18 
19 #include "utils/include/Utils.h"
20 
21 #include <aidl/android/hardware/automotive/evs/BufferDesc.h>
22 #include <aidl/android/hardware/automotive/evs/EvsEventDesc.h>
23 #include <aidl/android/hardware/automotive/evs/EvsEventType.h>
24 #include <android-base/logging.h>
25 
26 namespace aidl::android::automotive::evs::implementation {
27 
28 namespace hidlevs = ::android::hardware::automotive::evs;
29 
30 using ::aidl::android::hardware::automotive::evs::BufferDesc;
31 using ::aidl::android::hardware::automotive::evs::EvsEventDesc;
32 using ::aidl::android::hardware::automotive::evs::EvsEventType;
33 using ::aidl::android::hardware::automotive::evs::EvsResult;
34 using ::ndk::ScopedAStatus;
35 
AidlCameraStream(const::android::sp<hidlevs::V1_0::IEvsCameraStream> & hidlStream)36 AidlCameraStream::AidlCameraStream(
37         const ::android::sp<hidlevs::V1_0::IEvsCameraStream>& hidlStream) {
38     auto hidlStreamV1 = hidlevs::V1_1::IEvsCameraStream::castFrom(hidlStream).withDefault(nullptr);
39     if (!hidlStreamV1) {
40         mImpl = std::make_shared<ImplV0>(hidlStream);
41     } else {
42         mImpl = std::make_shared<ImplV1>(hidlStreamV1);
43     }
44 }
45 
deliverFrame(const std::vector<BufferDesc> & buffers)46 ScopedAStatus AidlCameraStream::deliverFrame(const std::vector<BufferDesc>& buffers) {
47     return mImpl->deliverFrame(buffers);
48 }
49 
notify(const EvsEventDesc & event)50 ScopedAStatus AidlCameraStream::notify(const EvsEventDesc& event) {
51     return mImpl->notify(event);
52 }
53 
getBuffer(int id,BufferDesc * _return)54 bool AidlCameraStream::getBuffer(int id, BufferDesc* _return) {
55     return mImpl->getBuffer(id, _return);
56 }
57 
getBuffer(int id,BufferDesc * _return)58 bool AidlCameraStream::IHidlCameraStream::getBuffer(int id, BufferDesc* _return) {
59     auto it = std::find_if(mBuffers.begin(), mBuffers.end(),
60                            [id](const BufferDesc& buffer) { return id == buffer.bufferId; });
61     if (it == mBuffers.end()) {
62         return false;
63     }
64 
65     *_return = std::move(*it);
66     mBuffers.erase(it);
67     return true;
68 }
69 
ImplV0(const::android::sp<hidlevs::V1_0::IEvsCameraStream> & stream)70 AidlCameraStream::ImplV0::ImplV0(const ::android::sp<hidlevs::V1_0::IEvsCameraStream>& stream) :
71       IHidlCameraStream(stream) {}
72 
deliverFrame(const std::vector<BufferDesc> & buffers)73 ScopedAStatus AidlCameraStream::ImplV0::deliverFrame(const std::vector<BufferDesc>& buffers) {
74     if (!mStream) {
75         return ScopedAStatus::fromServiceSpecificError(
76                 static_cast<int>(EvsResult::RESOURCE_NOT_AVAILABLE));
77     }
78 
79     auto hidlBuffer = Utils::makeToHidlV1_0(buffers[0], /* doDup= */ false);
80     mBuffers.push_back(std::move(Utils::dupBufferDesc(buffers[0], /* doDup= */ true)));
81     if (auto status = mStream->deliverFrame(std::move(hidlBuffer)); !status.isOk()) {
82         LOG(ERROR) << "Failed to forward a frame to HIDL v1.0 client";
83         return ScopedAStatus::fromStatus(STATUS_FAILED_TRANSACTION);
84     }
85 
86     return ScopedAStatus::ok();
87 }
88 
notify(const EvsEventDesc & event)89 ScopedAStatus AidlCameraStream::ImplV0::notify(const EvsEventDesc& event) {
90     if (!mStream) {
91         return ScopedAStatus::fromServiceSpecificError(
92                 static_cast<int>(EvsResult::RESOURCE_NOT_AVAILABLE));
93     }
94 
95     switch (event.aType) {
96         case EvsEventType::STREAM_STOPPED:
97             if (auto status = mStream->deliverFrame({}); !status.isOk()) {
98                 LOG(ERROR) << "Error delivering the end of stream marker";
99                 return ScopedAStatus::fromStatus(STATUS_FAILED_TRANSACTION);
100             }
101             break;
102 
103         default:
104             // HIDL v1.0 interface does not support events
105             LOG(INFO) << "Event " << toString(event.aType)
106                       << " is received but ignored for HIDL v1.0 client";
107             break;
108     }
109 
110     return ScopedAStatus::ok();
111 }
112 
ImplV1(const::android::sp<hidlevs::V1_1::IEvsCameraStream> & stream)113 AidlCameraStream::ImplV1::ImplV1(const ::android::sp<hidlevs::V1_1::IEvsCameraStream>& stream) :
114       IHidlCameraStream(stream), mStream(stream) {}
115 
deliverFrame(const std::vector<BufferDesc> & buffers)116 ScopedAStatus AidlCameraStream::ImplV1::deliverFrame(const std::vector<BufferDesc>& buffers) {
117     const auto n = buffers.size();
118     ::android::hardware::hidl_vec<hidlevs::V1_1::BufferDesc> hidlBuffers(n);
119     for (auto i = 0; i < n; ++i) {
120         BufferDesc buffer = std::move(Utils::dupBufferDesc(buffers[i], /* doDup= */ true));
121         hidlBuffers[i] = std::move(Utils::makeToHidlV1_1(buffer, /* doDup= */ false));
122         mBuffers.push_back(std::move(buffer));
123     }
124 
125     if (auto status = mStream->deliverFrame_1_1(hidlBuffers); !status.isOk()) {
126         LOG(ERROR) << "Failed to forward a frame to HIDL v1.1 client";
127         return ScopedAStatus::fromStatus(STATUS_FAILED_TRANSACTION);
128     }
129 
130     return ScopedAStatus::ok();
131 }
132 
notify(const EvsEventDesc & event)133 ScopedAStatus AidlCameraStream::ImplV1::notify(const EvsEventDesc& event) {
134     if (!mStream) {
135         return ScopedAStatus::fromServiceSpecificError(
136                 static_cast<int>(EvsResult::RESOURCE_NOT_AVAILABLE));
137     }
138 
139     hidlevs::V1_1::EvsEventDesc hidlEvent;
140     if (!Utils::makeToHidl(event, &hidlEvent)) {
141         return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::INVALID_ARG));
142     }
143 
144     if (auto status = mStream->notify(hidlEvent); !status.isOk()) {
145         LOG(ERROR) << "Failed to forward an event, " << toString(event.aType);
146         return ScopedAStatus::fromStatus(STATUS_FAILED_TRANSACTION);
147     }
148 
149     return ScopedAStatus::ok();
150 }
151 
152 }  // namespace aidl::android::automotive::evs::implementation
153