1 /*
2  * Copyright (C) 2011 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 /*
18  * Contains implementation of a class EmulatedQemuCameraDevice that encapsulates
19  * an emulated camera device connected to the host.
20  */
21 
22 #define LOG_NDEBUG 0
23 #define LOG_TAG "EmulatedCamera_QemuDevice"
24 #include <cutils/log.h>
25 #include "EmulatedQemuCamera.h"
26 #include "EmulatedQemuCameraDevice.h"
27 
28 namespace android {
29 
EmulatedQemuCameraDevice(EmulatedQemuCamera * camera_hal)30 EmulatedQemuCameraDevice::EmulatedQemuCameraDevice(EmulatedQemuCamera* camera_hal)
31     : EmulatedCameraDevice(camera_hal),
32       mQemuClient(),
33       mPreviewFrame(NULL)
34 {
35 }
36 
~EmulatedQemuCameraDevice()37 EmulatedQemuCameraDevice::~EmulatedQemuCameraDevice()
38 {
39     if (mPreviewFrame != NULL) {
40         delete[] mPreviewFrame;
41     }
42 }
43 
44 /****************************************************************************
45  * Public API
46  ***************************************************************************/
47 
Initialize(const char * device_name)48 status_t EmulatedQemuCameraDevice::Initialize(const char* device_name)
49 {
50     /* Connect to the service. */
51     char connect_str[256];
52     snprintf(connect_str, sizeof(connect_str), "name=%s", device_name);
53     status_t res = mQemuClient.connectClient(connect_str);
54     if (res != NO_ERROR) {
55         return res;
56     }
57 
58     /* Initialize base class. */
59     res = EmulatedCameraDevice::Initialize();
60     if (res == NO_ERROR) {
61         ALOGV("%s: Connected to the emulated camera service '%s'",
62              __FUNCTION__, device_name);
63         mDeviceName = device_name;
64     } else {
65         mQemuClient.queryDisconnect();
66     }
67 
68     return res;
69 }
70 
71 /****************************************************************************
72  * Emulated camera device abstract interface implementation.
73  ***************************************************************************/
74 
connectDevice()75 status_t EmulatedQemuCameraDevice::connectDevice()
76 {
77     ALOGV("%s", __FUNCTION__);
78 
79     Mutex::Autolock locker(&mObjectLock);
80     if (!isInitialized()) {
81         ALOGE("%s: Qemu camera device is not initialized.", __FUNCTION__);
82         return EINVAL;
83     }
84     if (isConnected()) {
85         ALOGW("%s: Qemu camera device '%s' is already connected.",
86              __FUNCTION__, (const char*)mDeviceName);
87         return NO_ERROR;
88     }
89 
90     /* Connect to the camera device via emulator. */
91     const status_t res = mQemuClient.queryConnect();
92     if (res == NO_ERROR) {
93         ALOGV("%s: Connected to device '%s'",
94              __FUNCTION__, (const char*)mDeviceName);
95         mState = ECDS_CONNECTED;
96     } else {
97         ALOGE("%s: Connection to device '%s' failed",
98              __FUNCTION__, (const char*)mDeviceName);
99     }
100 
101     return res;
102 }
103 
disconnectDevice()104 status_t EmulatedQemuCameraDevice::disconnectDevice()
105 {
106     ALOGV("%s", __FUNCTION__);
107 
108     Mutex::Autolock locker(&mObjectLock);
109     if (!isConnected()) {
110         ALOGW("%s: Qemu camera device '%s' is already disconnected.",
111              __FUNCTION__, (const char*)mDeviceName);
112         return NO_ERROR;
113     }
114     if (isStarted()) {
115         ALOGE("%s: Cannot disconnect from the started device '%s.",
116              __FUNCTION__, (const char*)mDeviceName);
117         return EINVAL;
118     }
119 
120     /* Disconnect from the camera device via emulator. */
121     const status_t res = mQemuClient.queryDisconnect();
122     if (res == NO_ERROR) {
123         ALOGV("%s: Disonnected from device '%s'",
124              __FUNCTION__, (const char*)mDeviceName);
125         mState = ECDS_INITIALIZED;
126     } else {
127         ALOGE("%s: Disconnection from device '%s' failed",
128              __FUNCTION__, (const char*)mDeviceName);
129     }
130 
131     return res;
132 }
133 
startDevice(int width,int height,uint32_t pix_fmt)134 status_t EmulatedQemuCameraDevice::startDevice(int width,
135                                                int height,
136                                                uint32_t pix_fmt)
137 {
138     ALOGV("%s", __FUNCTION__);
139 
140     Mutex::Autolock locker(&mObjectLock);
141     if (!isConnected()) {
142         ALOGE("%s: Qemu camera device '%s' is not connected.",
143              __FUNCTION__, (const char*)mDeviceName);
144         return EINVAL;
145     }
146     if (isStarted()) {
147         ALOGW("%s: Qemu camera device '%s' is already started.",
148              __FUNCTION__, (const char*)mDeviceName);
149         return NO_ERROR;
150     }
151 
152     status_t res = EmulatedCameraDevice::commonStartDevice(width, height, pix_fmt);
153     if (res != NO_ERROR) {
154         ALOGE("%s: commonStartDevice failed", __FUNCTION__);
155         return res;
156     }
157 
158     /* Allocate preview frame buffer. */
159     /* TODO: Watch out for preview format changes! At this point we implement
160      * RGB32 only.*/
161     mPreviewFrame = new uint32_t[mTotalPixels];
162     if (mPreviewFrame == NULL) {
163         ALOGE("%s: Unable to allocate %d bytes for preview frame",
164              __FUNCTION__, mTotalPixels);
165         return ENOMEM;
166     }
167 
168     /* Start the actual camera device. */
169     res = mQemuClient.queryStart(mPixelFormat, mFrameWidth, mFrameHeight);
170     if (res == NO_ERROR) {
171         ALOGV("%s: Qemu camera device '%s' is started for %.4s[%dx%d] frames",
172              __FUNCTION__, (const char*)mDeviceName,
173              reinterpret_cast<const char*>(&mPixelFormat),
174              mFrameWidth, mFrameHeight);
175         mState = ECDS_STARTED;
176     } else {
177         ALOGE("%s: Unable to start device '%s' for %.4s[%dx%d] frames",
178              __FUNCTION__, (const char*)mDeviceName,
179              reinterpret_cast<const char*>(&pix_fmt), width, height);
180     }
181 
182     return res;
183 }
184 
stopDevice()185 status_t EmulatedQemuCameraDevice::stopDevice()
186 {
187     ALOGV("%s", __FUNCTION__);
188 
189     Mutex::Autolock locker(&mObjectLock);
190     if (!isStarted()) {
191         ALOGW("%s: Qemu camera device '%s' is not started.",
192              __FUNCTION__, (const char*)mDeviceName);
193         return NO_ERROR;
194     }
195 
196     /* Stop the actual camera device. */
197     status_t res = mQemuClient.queryStop();
198     if (res == NO_ERROR) {
199         if (mPreviewFrame == NULL) {
200             delete[] mPreviewFrame;
201             mPreviewFrame = NULL;
202         }
203         EmulatedCameraDevice::commonStopDevice();
204         mState = ECDS_CONNECTED;
205         ALOGV("%s: Qemu camera device '%s' is stopped",
206              __FUNCTION__, (const char*)mDeviceName);
207     } else {
208         ALOGE("%s: Unable to stop device '%s'",
209              __FUNCTION__, (const char*)mDeviceName);
210     }
211 
212     return res;
213 }
214 
215 /****************************************************************************
216  * EmulatedCameraDevice virtual overrides
217  ***************************************************************************/
218 
getCurrentPreviewFrame(void * buffer)219 status_t EmulatedQemuCameraDevice::getCurrentPreviewFrame(void* buffer)
220 {
221     ALOGW_IF(mPreviewFrame == NULL, "%s: No preview frame", __FUNCTION__);
222     if (mPreviewFrame != NULL) {
223         memcpy(buffer, mPreviewFrame, mTotalPixels * 4);
224         return 0;
225     } else {
226         return EmulatedCameraDevice::getCurrentPreviewFrame(buffer);
227     }
228 }
229 
230 /****************************************************************************
231  * Worker thread management overrides.
232  ***************************************************************************/
233 
inWorkerThread()234 bool EmulatedQemuCameraDevice::inWorkerThread()
235 {
236     /* Wait till FPS timeout expires, or thread exit message is received. */
237     WorkerThread::SelectRes res =
238         getWorkerThread()->Select(-1, 1000000 / mEmulatedFPS);
239     if (res == WorkerThread::EXIT_THREAD) {
240         ALOGV("%s: Worker thread has been terminated.", __FUNCTION__);
241         return false;
242     }
243 
244     /* Query frames from the service. */
245     status_t query_res = mQemuClient.queryFrame(mCurrentFrame, mPreviewFrame,
246                                                  mFrameBufferSize,
247                                                  mTotalPixels * 4,
248                                                  mWhiteBalanceScale[0],
249                                                  mWhiteBalanceScale[1],
250                                                  mWhiteBalanceScale[2],
251                                                  mExposureCompensation);
252     if (query_res == NO_ERROR) {
253         /* Timestamp the current frame, and notify the camera HAL. */
254         mCurFrameTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
255         mCameraHAL->onNextFrameAvailable(mCurrentFrame, mCurFrameTimestamp, this);
256         return true;
257     } else {
258         ALOGE("%s: Unable to get current video frame: %s",
259              __FUNCTION__, strerror(query_res));
260         mCameraHAL->onCameraDeviceError(CAMERA_ERROR_SERVER_DIED);
261         return false;
262     }
263 }
264 
265 }; /* namespace android */
266