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