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