1 /*
2  * Copyright (C) 2016 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 "VirtualCamera.h"
18 #include "HalCamera.h"
19 #include "Enumerator.h"
20 
21 #include <ui/GraphicBufferAllocator.h>
22 #include <ui/GraphicBufferMapper.h>
23 
24 
25 namespace android {
26 namespace automotive {
27 namespace evs {
28 namespace V1_0 {
29 namespace implementation {
30 
31 
VirtualCamera(sp<HalCamera> halCamera)32 VirtualCamera::VirtualCamera(sp<HalCamera> halCamera) :
33     mHalCamera(halCamera) {
34 }
35 
36 
~VirtualCamera()37 VirtualCamera::~VirtualCamera() {
38     shutdown();
39 }
40 
41 
shutdown()42 void VirtualCamera::shutdown() {
43     // In normal operation, the stream should already be stopped by the time we get here
44     if (mStreamState != STOPPED) {
45         // Note that if we hit this case, no terminating frame will be sent to the client,
46         // but they're probably already dead anyway.
47         ALOGW("Virtual camera being shutdown while stream is running");
48 
49         // Tell the frame delivery pipeline we don't want any more frames
50         mStreamState = STOPPING;
51 
52         if (mFramesHeld.size() > 0) {
53             ALOGW("VirtualCamera destructing with frames in flight.");
54 
55             // Return to the underlying hardware camera any buffers the client was holding
56             for (auto&& heldBuffer : mFramesHeld) {
57                 // Tell our parent that we're done with this buffer
58                 mHalCamera->doneWithFrame(heldBuffer);
59             }
60             mFramesHeld.clear();
61         }
62 
63         // Give the underlying hardware camera the heads up that it might be time to stop
64         mHalCamera->clientStreamEnding();
65     }
66 
67     // Drop our reference to our associated hardware camera
68     mHalCamera = nullptr;
69 }
70 
71 
deliverFrame(const BufferDesc & buffer)72 bool VirtualCamera::deliverFrame(const BufferDesc& buffer) {
73     if (buffer.memHandle == nullptr) {
74         // Warn if we got an unexpected stream termination
75         if (mStreamState != STOPPING) {
76             // TODO:  Should we suicide in this case to trigger a restart of the stack?
77             ALOGW("Stream unexpectedly stopped");
78         }
79 
80         // This is the stream end marker, so send it along, then mark the stream as stopped
81         mStream->deliverFrame(buffer);
82         mStreamState = STOPPED;
83         return true;
84     } else {
85         if (mStreamState == STOPPED) {
86             // A stopped stream gets no frames
87             return false;
88         } else if (mFramesHeld.size() >= mFramesAllowed) {
89             // Indicate that we declined to send the frame to the client because they're at quota
90             ALOGI("Skipping new frame as we hold %zu of %u allowed.",
91                   mFramesHeld.size(), mFramesAllowed);
92             return false;
93         } else {
94             // Keep a record of this frame so we can clean up if we have to in case of client death
95             mFramesHeld.push_back(buffer);
96 
97             // Pass this buffer through to our client
98             mStream->deliverFrame(buffer);
99             return true;
100         }
101     }
102 }
103 
104 
105 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
getCameraInfo(getCameraInfo_cb info_cb)106 Return<void> VirtualCamera::getCameraInfo(getCameraInfo_cb info_cb) {
107     // Straight pass through to hardware layer
108     return mHalCamera->getHwCamera()->getCameraInfo(info_cb);
109 }
110 
111 
setMaxFramesInFlight(uint32_t bufferCount)112 Return<EvsResult> VirtualCamera::setMaxFramesInFlight(uint32_t bufferCount) {
113     // How many buffers are we trying to add (or remove if negative)
114     int bufferCountChange = bufferCount - mFramesAllowed;
115 
116     // Ask our parent for more buffers
117     bool result = mHalCamera->changeFramesInFlight(bufferCountChange);
118     if (!result) {
119         ALOGE("Failed to change buffer count by %d to %d", bufferCountChange, bufferCount);
120         return EvsResult::BUFFER_NOT_AVAILABLE;
121     }
122 
123     // Update our notion of how many frames we're allowed
124     mFramesAllowed = bufferCount;
125     return EvsResult::OK;
126 }
127 
128 
startVideoStream(const::android::sp<IEvsCameraStream> & stream)129 Return<EvsResult> VirtualCamera::startVideoStream(const ::android::sp<IEvsCameraStream>& stream)  {
130     // We only support a single stream at a time
131     if (mStreamState != STOPPED) {
132         ALOGE("ignoring startVideoStream call when a stream is already running.");
133         return EvsResult::STREAM_ALREADY_RUNNING;
134     }
135 
136     // Validate our held frame count is starting out at zero as we expect
137     assert(mFramesHeld.size() == 0);
138 
139     // Record the user's callback for use when we have a frame ready
140     mStream = stream;
141     mStreamState = RUNNING;
142 
143     // Tell the underlying camera hardware that we want to stream
144     Return<EvsResult> result = mHalCamera->clientStreamStarting();
145     if ((!result.isOk()) || (result != EvsResult::OK)) {
146         // If we failed to start the underlying stream, then we're not actually running
147         mStream = nullptr;
148         mStreamState = STOPPED;
149         return EvsResult::UNDERLYING_SERVICE_ERROR;
150     }
151 
152     // TODO:  Detect and exit if we encounter a stalled stream or unresponsive driver?
153     // Consider using a timer and watching for frame arrival?
154 
155     return EvsResult::OK;
156 }
157 
158 
doneWithFrame(const BufferDesc & buffer)159 Return<void> VirtualCamera::doneWithFrame(const BufferDesc& buffer) {
160     if (buffer.memHandle == nullptr) {
161         ALOGE("ignoring doneWithFrame called with invalid handle");
162     } else {
163         // Find this buffer in our "held" list
164         auto it = mFramesHeld.begin();
165         while (it != mFramesHeld.end()) {
166             if (it->bufferId == buffer.bufferId) {
167                 // found it!
168                 break;
169             }
170             ++it;
171         }
172         if (it == mFramesHeld.end()) {
173             // We should always find the frame in our "held" list
174             ALOGE("Ignoring doneWithFrame called with unrecognized frameID %d", buffer.bufferId);
175         } else {
176             // Take this frame out of our "held" list
177             mFramesHeld.erase(it);
178 
179             // Tell our parent that we're done with this buffer
180             mHalCamera->doneWithFrame(buffer);
181         }
182     }
183 
184     return Void();
185 }
186 
187 
stopVideoStream()188 Return<void> VirtualCamera::stopVideoStream()  {
189     if (mStreamState == RUNNING) {
190         // Tell the frame delivery pipeline we don't want any more frames
191         mStreamState = STOPPING;
192 
193         // Deliver an empty frame to close out the frame stream
194         BufferDesc nullBuff = {};
195         auto result = mStream->deliverFrame(nullBuff);
196         if (!result.isOk()) {
197             ALOGE("Error delivering end of stream marker");
198         }
199 
200         // Since we are single threaded, no frame can be delivered while this function is running,
201         // so we can go directly to the STOPPED state here on the server.
202         // Note, however, that there still might be frames already queued that client will see
203         // after returning from the client side of this call.
204         mStreamState = STOPPED;
205 
206         // Give the underlying hardware camera the heads up that it might be time to stop
207         mHalCamera->clientStreamEnding();
208     }
209 
210     return Void();
211 }
212 
213 
getExtendedInfo(uint32_t opaqueIdentifier)214 Return<int32_t> VirtualCamera::getExtendedInfo(uint32_t opaqueIdentifier)  {
215     // Pass straight through to the hardware device
216     return mHalCamera->getHwCamera()->getExtendedInfo(opaqueIdentifier);
217 }
218 
219 
setExtendedInfo(uint32_t opaqueIdentifier,int32_t opaqueValue)220 Return<EvsResult> VirtualCamera::setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue)  {
221     // Pass straight through to the hardware device
222     // TODO: Should we restrict access to this entry point somehow?
223     return mHalCamera->getHwCamera()->setExtendedInfo(opaqueIdentifier, opaqueValue);
224 }
225 
226 } // namespace implementation
227 } // namespace V1_0
228 } // namespace evs
229 } // namespace automotive
230 } // namespace android
231