blob: af90f2cefe4f93506bd905a248c34622473abcc2 [file] [log] [blame]
Scott Randolphdcc35342017-01-19 13:33:42 -08001/*
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
Scott Randolphdcc35342017-01-19 13:33:42 -080017#include "VirtualCamera.h"
18#include "HalCamera.h"
Scott Randolphda289be2017-03-30 14:30:34 -070019#include "Enumerator.h"
Scott Randolphdcc35342017-01-19 13:33:42 -080020
21#include <ui/GraphicBufferAllocator.h>
22#include <ui/GraphicBufferMapper.h>
23
24
25namespace android {
26namespace automotive {
27namespace evs {
28namespace V1_0 {
29namespace implementation {
30
31
Scott Randolphda289be2017-03-30 14:30:34 -070032VirtualCamera::VirtualCamera(sp<HalCamera> halCamera) :
33 mHalCamera(halCamera) {
34}
35
36
Scott Randolph29803802017-01-25 13:11:51 -080037VirtualCamera::~VirtualCamera() {
Scott Randolphda289be2017-03-30 14:30:34 -070038 shutdown();
39}
40
41
42void 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");
Scott Randolph29803802017-01-25 13:11:51 -080048 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 }
Scott Randolph29803802017-01-25 13:11:51 -080060 }
Scott Randolphdcc35342017-01-19 13:33:42 -080061
Scott Randolphda289be2017-03-30 14:30:34 -070062 // Drop our reference to our associated hardware camera
63 mHalCamera = nullptr;
Scott Randolphdcc35342017-01-19 13:33:42 -080064}
65
66
67bool VirtualCamera::deliverFrame(const BufferDesc& buffer) {
68 if (buffer.memHandle == nullptr) {
Scott Randolph29803802017-01-25 13:11:51 -080069 // 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
Scott Randolphdcc35342017-01-19 13:33:42 -080075 // 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;
Scott Randolph29803802017-01-25 13:11:51 -080083 } else if (mFramesHeld.size() >= mFramesAllowed) {
Scott Randolphdcc35342017-01-19 13:33:42 -080084 // Indicate that we declined to send the frame to the client because they're at quota
Scott Randolphffd02f22017-02-10 18:07:22 -080085 ALOGI("Skipping new frame as we hold %zu of %u allowed.",
Scott Randolph29803802017-01-25 13:11:51 -080086 mFramesHeld.size(), mFramesAllowed);
Scott Randolphdcc35342017-01-19 13:33:42 -080087 return false;
88 } else {
Scott Randolph29803802017-01-25 13:11:51 -080089 // 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
Scott Randolphdcc35342017-01-19 13:33:42 -080093 mStream->deliverFrame(buffer);
94 return true;
95 }
96 }
97}
98
99
Scott Randolphf1b55e72017-03-01 20:35:44 -0800100// Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
Scott Randolphda289be2017-03-30 14:30:34 -0700101Return<void> VirtualCamera::getCameraInfo(getCameraInfo_cb info_cb) {
Scott Randolphdcc35342017-01-19 13:33:42 -0800102 // Straight pass through to hardware layer
Scott Randolphda289be2017-03-30 14:30:34 -0700103 return mHalCamera->getHwCamera()->getCameraInfo(info_cb);
Scott Randolphdcc35342017-01-19 13:33:42 -0800104}
105
Scott Randolph29803802017-01-25 13:11:51 -0800106
Scott Randolphdcc35342017-01-19 13:33:42 -0800107Return<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
Scott Randolph29803802017-01-25 13:11:51 -0800123
Scott Randolphdcc35342017-01-19 13:33:42 -0800124Return<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
Scott Randolph29803802017-01-25 13:11:51 -0800132 assert(mFramesHeld.size() == 0);
Scott Randolphdcc35342017-01-19 13:33:42 -0800133
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
Scott Randolph29803802017-01-25 13:11:51 -0800147 // TODO: Detect and exit if we encounter a stalled stream or unresponsive driver?
148 // Consider using a timer and watching for frame arrival?
149
Scott Randolphdcc35342017-01-19 13:33:42 -0800150 return EvsResult::OK;
151}
152
Scott Randolph29803802017-01-25 13:11:51 -0800153
Scott Randolphdcc35342017-01-19 13:33:42 -0800154Return<void> VirtualCamera::doneWithFrame(const BufferDesc& buffer) {
155 if (buffer.memHandle == nullptr) {
156 ALOGE("ignoring doneWithFrame called with invalid handle");
157 } else {
Scott Randolph29803802017-01-25 13:11:51 -0800158 // 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);
Scott Randolphdcc35342017-01-19 13:33:42 -0800173
Scott Randolph29803802017-01-25 13:11:51 -0800174 // Tell our parent that we're done with this buffer
175 mHalCamera->doneWithFrame(buffer);
176 }
Scott Randolphdcc35342017-01-19 13:33:42 -0800177 }
178
179 return Void();
180}
181
Scott Randolph29803802017-01-25 13:11:51 -0800182
Scott Randolphdcc35342017-01-19 13:33:42 -0800183Return<void> VirtualCamera::stopVideoStream() {
184 if (mStreamState == RUNNING) {
185 // Tell the frame delivery pipeline we don't want any more frames
186 mStreamState = STOPPING;
187
Scott Randolph29803802017-01-25 13:11:51 -0800188 // Deliver an empty frame to close out the frame stream
Scott Randolphdcc35342017-01-19 13:33:42 -0800189 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
Scott Randolph29803802017-01-25 13:11:51 -0800208
Scott Randolphdcc35342017-01-19 13:33:42 -0800209Return<int32_t> VirtualCamera::getExtendedInfo(uint32_t opaqueIdentifier) {
210 // Pass straight through to the hardware device
211 return mHalCamera->getHwCamera()->getExtendedInfo(opaqueIdentifier);
212}
213
Scott Randolph29803802017-01-25 13:11:51 -0800214
Scott Randolphdcc35342017-01-19 13:33:42 -0800215Return<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