blob: 121819ae1b62e58778d597f654c1976b89740e04 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2**
3** Copyright (C) 2008, The Android Open Source Project
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018#define LOG_TAG "CameraService"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019
Chih-Chung Change25cc652010-05-06 16:36:58 +080020#include <stdio.h>
21#include <sys/types.h>
22#include <pthread.h>
23
Mathias Agopian07952722009-05-19 19:08:10 -070024#include <binder/IPCThreadState.h>
Chih-Chung Change25cc652010-05-06 16:36:58 +080025#include <binder/IServiceManager.h>
Mathias Agopian07952722009-05-19 19:08:10 -070026#include <binder/MemoryBase.h>
27#include <binder/MemoryHeapBase.h>
Chih-Chung Change25cc652010-05-06 16:36:58 +080028#include <cutils/atomic.h>
29#include <hardware/hardware.h>
30#include <media/AudioSystem.h>
31#include <media/mediaplayer.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080032#include <surfaceflinger/ISurface.h>
33#include <ui/Overlay.h>
Chih-Chung Change25cc652010-05-06 16:36:58 +080034#include <utils/Errors.h>
35#include <utils/Log.h>
36#include <utils/String16.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037
38#include "CameraService.h"
Eric Laurenta7f1e5c2009-03-27 16:27:16 -070039
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040namespace android {
41
Chih-Chung Change25cc652010-05-06 16:36:58 +080042// ----------------------------------------------------------------------------
43// Logging support -- this is for debugging only
44// Use "adb shell dumpsys media.camera -v 1" to change it.
45static volatile int32_t gLogLevel = 0;
46
47#define LOG1(...) LOGD_IF(gLogLevel >= 1, __VA_ARGS__);
48#define LOG2(...) LOGD_IF(gLogLevel >= 2, __VA_ARGS__);
49
50static void setLogLevel(int level) {
51 android_atomic_write(level, &gLogLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052}
53
Chih-Chung Change25cc652010-05-06 16:36:58 +080054// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055
Chih-Chung Chang1f25ec82009-06-22 16:03:41 +080056static int getCallingPid() {
57 return IPCThreadState::self()->getCallingPid();
58}
59
Chih-Chung Change25cc652010-05-06 16:36:58 +080060static int getCallingUid() {
61 return IPCThreadState::self()->getCallingUid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062}
63
64// ----------------------------------------------------------------------------
65
Chih-Chung Change25cc652010-05-06 16:36:58 +080066// This is ugly and only safe if we never re-create the CameraService, but
67// should be ok for now.
68static CameraService *gCameraService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069
Chih-Chung Change25cc652010-05-06 16:36:58 +080070CameraService::CameraService()
71:mSoundRef(0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072{
Chih-Chung Change25cc652010-05-06 16:36:58 +080073 LOGI("CameraService started (pid=%d)", getpid());
74
Chih-Chung Changb8bb78f2010-06-10 13:32:16 +080075 mNumberOfCameras = HAL_getNumberOfCameras();
76 if (mNumberOfCameras > MAX_CAMERAS) {
77 LOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
78 mNumberOfCameras, MAX_CAMERAS);
79 mNumberOfCameras = MAX_CAMERAS;
80 }
81
82 for (int i = 0; i < mNumberOfCameras; i++) {
Chih-Chung Change25cc652010-05-06 16:36:58 +080083 setCameraFree(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 }
Chih-Chung Change25cc652010-05-06 16:36:58 +080085
86 gCameraService = this;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087}
88
Chih-Chung Change25cc652010-05-06 16:36:58 +080089CameraService::~CameraService() {
Chih-Chung Changb8bb78f2010-06-10 13:32:16 +080090 for (int i = 0; i < mNumberOfCameras; i++) {
Chih-Chung Change25cc652010-05-06 16:36:58 +080091 if (mBusy[i]) {
92 LOGE("camera %d is still in use in destructor!", i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 }
94 }
95
Chih-Chung Change25cc652010-05-06 16:36:58 +080096 gCameraService = NULL;
97}
98
99int32_t CameraService::getNumberOfCameras() {
Chih-Chung Changb8bb78f2010-06-10 13:32:16 +0800100 return mNumberOfCameras;
101}
102
103status_t CameraService::getCameraInfo(int cameraId,
104 struct CameraInfo* cameraInfo) {
105 if (cameraId < 0 || cameraId >= mNumberOfCameras) {
106 return BAD_VALUE;
107 }
108
109 HAL_getCameraInfo(cameraId, cameraInfo);
110 return OK;
Chih-Chung Change25cc652010-05-06 16:36:58 +0800111}
112
113sp<ICamera> CameraService::connect(
114 const sp<ICameraClient>& cameraClient, int cameraId) {
115 int callingPid = getCallingPid();
116 LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);
117
118 sp<Client> client;
Chih-Chung Changb8bb78f2010-06-10 13:32:16 +0800119 if (cameraId < 0 || cameraId >= mNumberOfCameras) {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800120 LOGE("CameraService::connect X (pid %d) rejected (invalid cameraId %d).",
121 callingPid, cameraId);
122 return NULL;
Chih-Chung Changd5d1ebd2009-06-24 19:59:31 +0800123 }
124
Chih-Chung Change25cc652010-05-06 16:36:58 +0800125 Mutex::Autolock lock(mServiceLock);
126 if (mClient[cameraId] != 0) {
127 client = mClient[cameraId].promote();
128 if (client != 0) {
129 if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) {
130 LOG1("CameraService::connect X (pid %d) (the same client)",
131 callingPid);
132 return client;
133 } else {
134 LOGW("CameraService::connect X (pid %d) rejected (existing client).",
135 callingPid);
136 return NULL;
137 }
138 }
139 mClient[cameraId].clear();
140 }
141
142 if (mBusy[cameraId]) {
143 LOGW("CameraService::connect X (pid %d) rejected"
144 " (camera %d is still busy).", callingPid, cameraId);
145 return NULL;
146 }
147
Wu-cheng Lie7044382010-08-17 15:45:37 -0700148 sp<CameraHardwareInterface> hardware = HAL_openCameraHardware(cameraId);
149 if (hardware == NULL) {
150 LOGE("Fail to open camera hardware (id=%d)", cameraId);
151 return NULL;
152 }
Wu-cheng Lib982fb42010-10-19 17:19:09 +0800153 CameraInfo info;
154 HAL_getCameraInfo(cameraId, &info);
155 client = new Client(this, cameraClient, hardware, cameraId, info.facing,
156 info.orientation, callingPid);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800157 mClient[cameraId] = client;
158 LOG1("CameraService::connect X");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 return client;
160}
161
Chih-Chung Change25cc652010-05-06 16:36:58 +0800162void CameraService::removeClient(const sp<ICameraClient>& cameraClient) {
Chih-Chung Chang1f25ec82009-06-22 16:03:41 +0800163 int callingPid = getCallingPid();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800164 LOG1("CameraService::removeClient E (pid %d)", callingPid);
Chih-Chung Chang1f25ec82009-06-22 16:03:41 +0800165
Chih-Chung Changb8bb78f2010-06-10 13:32:16 +0800166 for (int i = 0; i < mNumberOfCameras; i++) {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800167 // Declare this before the lock to make absolutely sure the
168 // destructor won't be called with the lock held.
169 sp<Client> client;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170
Chih-Chung Change25cc652010-05-06 16:36:58 +0800171 Mutex::Autolock lock(mServiceLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172
Chih-Chung Change25cc652010-05-06 16:36:58 +0800173 // This happens when we have already disconnected (or this is
174 // just another unused camera).
175 if (mClient[i] == 0) continue;
176
177 // Promote mClient. It can fail if we are called from this path:
178 // Client::~Client() -> disconnect() -> removeClient().
179 client = mClient[i].promote();
180
181 if (client == 0) {
182 mClient[i].clear();
183 continue;
184 }
185
186 if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) {
187 // Found our camera, clear and leave.
188 LOG1("removeClient: clear camera %d", i);
189 mClient[i].clear();
190 break;
191 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 }
193
Chih-Chung Change25cc652010-05-06 16:36:58 +0800194 LOG1("CameraService::removeClient X (pid %d)", callingPid);
195}
196
197sp<CameraService::Client> CameraService::getClientById(int cameraId) {
Chih-Chung Changb8bb78f2010-06-10 13:32:16 +0800198 if (cameraId < 0 || cameraId >= mNumberOfCameras) return NULL;
Chih-Chung Change25cc652010-05-06 16:36:58 +0800199 return mClient[cameraId].promote();
200}
201
Chih-Chung Change25cc652010-05-06 16:36:58 +0800202status_t CameraService::onTransact(
203 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
204 // Permission checks
205 switch (code) {
206 case BnCameraService::CONNECT:
207 const int pid = getCallingPid();
208 const int self_pid = getpid();
209 if (pid != self_pid) {
210 // we're called from a different process, do the real check
211 if (!checkCallingPermission(
212 String16("android.permission.CAMERA"))) {
213 const int uid = getCallingUid();
214 LOGE("Permission Denial: "
215 "can't use the camera pid=%d, uid=%d", pid, uid);
216 return PERMISSION_DENIED;
217 }
218 }
219 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 }
221
Chih-Chung Change25cc652010-05-06 16:36:58 +0800222 return BnCameraService::onTransact(code, data, reply, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223}
224
Chih-Chung Change25cc652010-05-06 16:36:58 +0800225// The reason we need this busy bit is a new CameraService::connect() request
226// may come in while the previous Client's destructor has not been run or is
227// still running. If the last strong reference of the previous Client is gone
228// but the destructor has not been finished, we should not allow the new Client
229// to be created because we need to wait for the previous Client to tear down
230// the hardware first.
231void CameraService::setCameraBusy(int cameraId) {
232 android_atomic_write(1, &mBusy[cameraId]);
Chih-Chung Chang6fcba312009-06-24 13:44:37 +0800233}
234
Chih-Chung Change25cc652010-05-06 16:36:58 +0800235void CameraService::setCameraFree(int cameraId) {
236 android_atomic_write(0, &mBusy[cameraId]);
Chih-Chung Chang6fcba312009-06-24 13:44:37 +0800237}
238
Chih-Chung Change25cc652010-05-06 16:36:58 +0800239// We share the media players for shutter and recording sound for all clients.
240// A reference count is kept to determine when we will actually release the
241// media players.
242
243static MediaPlayer* newMediaPlayer(const char *file) {
244 MediaPlayer* mp = new MediaPlayer();
245 if (mp->setDataSource(file, NULL) == NO_ERROR) {
Eric Laurenta553c252009-07-17 12:17:14 -0700246 mp->setAudioStreamType(AudioSystem::ENFORCED_AUDIBLE);
Jason Samsb18b6912009-03-24 20:21:36 -0700247 mp->prepare();
248 } else {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800249 LOGE("Failed to load CameraService sounds: %s", file);
250 return NULL;
Jason Samsb18b6912009-03-24 20:21:36 -0700251 }
252 return mp;
253}
254
Chih-Chung Change25cc652010-05-06 16:36:58 +0800255void CameraService::loadSound() {
256 Mutex::Autolock lock(mSoundLock);
257 LOG1("CameraService::loadSound ref=%d", mSoundRef);
258 if (mSoundRef++) return;
259
260 mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/system/media/audio/ui/camera_click.ogg");
261 mSoundPlayer[SOUND_RECORDING] = newMediaPlayer("/system/media/audio/ui/VideoRecord.ogg");
262}
263
264void CameraService::releaseSound() {
265 Mutex::Autolock lock(mSoundLock);
266 LOG1("CameraService::releaseSound ref=%d", mSoundRef);
267 if (--mSoundRef) return;
268
269 for (int i = 0; i < NUM_SOUNDS; i++) {
270 if (mSoundPlayer[i] != 0) {
271 mSoundPlayer[i]->disconnect();
272 mSoundPlayer[i].clear();
273 }
274 }
275}
276
277void CameraService::playSound(sound_kind kind) {
278 LOG1("playSound(%d)", kind);
279 Mutex::Autolock lock(mSoundLock);
280 sp<MediaPlayer> player = mSoundPlayer[kind];
281 if (player != 0) {
282 // do not play the sound if stream volume is 0
283 // (typically because ringer mode is silent).
284 int index;
285 AudioSystem::getStreamVolumeIndex(AudioSystem::ENFORCED_AUDIBLE, &index);
286 if (index != 0) {
287 player->seekTo(0);
288 player->start();
289 }
290 }
291}
292
293// ----------------------------------------------------------------------------
294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295CameraService::Client::Client(const sp<CameraService>& cameraService,
Wu-cheng Lie7044382010-08-17 15:45:37 -0700296 const sp<ICameraClient>& cameraClient,
297 const sp<CameraHardwareInterface>& hardware,
Wu-cheng Lib982fb42010-10-19 17:19:09 +0800298 int cameraId, int cameraFacing, int cameraOrientation, int clientPid) {
Chih-Chung Chang1f25ec82009-06-22 16:03:41 +0800299 int callingPid = getCallingPid();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800300 LOG1("Client::Client E (pid %d)", callingPid);
301
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 mCameraService = cameraService;
303 mCameraClient = cameraClient;
Wu-cheng Lie7044382010-08-17 15:45:37 -0700304 mHardware = hardware;
Chih-Chung Change25cc652010-05-06 16:36:58 +0800305 mCameraId = cameraId;
Wu-cheng Lib982fb42010-10-19 17:19:09 +0800306 mCameraFacing = cameraFacing;
307 mCameraOrientation = cameraOrientation;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 mClientPid = clientPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 mUseOverlay = mHardware->useOverlay();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800310 mMsgEnabled = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311
Benny Wongda83f462009-08-12 12:01:27 -0500312 mHardware->setCallbacks(notifyCallback,
313 dataCallback,
314 dataCallbackTimestamp,
Chih-Chung Change25cc652010-05-06 16:36:58 +0800315 (void *)cameraId);
Benny Wongda83f462009-08-12 12:01:27 -0500316
317 // Enable zoom, error, and focus messages by default
Chih-Chung Change25cc652010-05-06 16:36:58 +0800318 enableMsgType(CAMERA_MSG_ERROR |
319 CAMERA_MSG_ZOOM |
320 CAMERA_MSG_FOCUS);
Benny Wong6d2090e2009-07-15 18:44:27 -0500321 mOverlayW = 0;
322 mOverlayH = 0;
Jason Samsb18b6912009-03-24 20:21:36 -0700323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 // Callback is disabled by default
325 mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
Wu-cheng Lib982fb42010-10-19 17:19:09 +0800326 mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT);
Wu-cheng Lib3347bc2010-09-23 17:17:43 -0700327 mOrientationChanged = false;
Chih-Chung Change25cc652010-05-06 16:36:58 +0800328 cameraService->setCameraBusy(cameraId);
329 cameraService->loadSound();
330 LOG1("Client::Client X (pid %d)", callingPid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331}
332
Chih-Chung Change25cc652010-05-06 16:36:58 +0800333static void *unregister_surface(void *arg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 ISurface *surface = (ISurface *)arg;
335 surface->unregisterBuffers();
336 IPCThreadState::self()->flushCommands();
337 return NULL;
338}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339
Chih-Chung Change25cc652010-05-06 16:36:58 +0800340// tear down the client
341CameraService::Client::~Client() {
Chih-Chung Chang1f25ec82009-06-22 16:03:41 +0800342 int callingPid = getCallingPid();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800343 LOG1("Client::~Client E (pid %d, this %p)", callingPid, this);
Chih-Chung Chang1f25ec82009-06-22 16:03:41 +0800344
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 if (mSurface != 0 && !mUseOverlay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 pthread_t thr;
347 // We unregister the buffers in a different thread because binder does
348 // not let us make sychronous transactions in a binder destructor (that
349 // is, upon our reaching a refcount of zero.)
Chih-Chung Change25cc652010-05-06 16:36:58 +0800350 pthread_create(&thr,
351 NULL, // attr
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 unregister_surface,
353 mSurface.get());
354 pthread_join(thr, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 }
356
Chih-Chung Change25cc652010-05-06 16:36:58 +0800357 // set mClientPid to let disconnet() tear down the hardware
Chih-Chung Chang1f25ec82009-06-22 16:03:41 +0800358 mClientPid = callingPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 disconnect();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800360 mCameraService->releaseSound();
361 LOG1("Client::~Client X (pid %d, this %p)", callingPid, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362}
363
Chih-Chung Change25cc652010-05-06 16:36:58 +0800364// ----------------------------------------------------------------------------
365
366status_t CameraService::Client::checkPid() const {
Chih-Chung Chang6fcba312009-06-24 13:44:37 +0800367 int callingPid = getCallingPid();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800368 if (callingPid == mClientPid) return NO_ERROR;
James Dong71d714c2010-06-09 15:57:48 -0700369
Chih-Chung Change25cc652010-05-06 16:36:58 +0800370 LOGW("attempt to use a locked camera from a different process"
371 " (old pid %d, new pid %d)", mClientPid, callingPid);
372 return EBUSY;
373}
Chih-Chung Chang1f25ec82009-06-22 16:03:41 +0800374
Chih-Chung Change25cc652010-05-06 16:36:58 +0800375status_t CameraService::Client::checkPidAndHardware() const {
376 status_t result = checkPid();
377 if (result != NO_ERROR) return result;
378 if (mHardware == 0) {
379 LOGE("attempt to use a camera after disconnect() (pid %d)", getCallingPid());
380 return INVALID_OPERATION;
381 }
382 return NO_ERROR;
383}
Chih-Chung Chang1f25ec82009-06-22 16:03:41 +0800384
Chih-Chung Change25cc652010-05-06 16:36:58 +0800385status_t CameraService::Client::lock() {
386 int callingPid = getCallingPid();
387 LOG1("lock (pid %d)", callingPid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 Mutex::Autolock lock(mLock);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800389
390 // lock camera to this client if the the camera is unlocked
391 if (mClientPid == 0) {
392 mClientPid = callingPid;
393 return NO_ERROR;
394 }
395
396 // returns NO_ERROR if the client already owns the camera, EBUSY otherwise
397 return checkPid();
398}
399
400status_t CameraService::Client::unlock() {
401 int callingPid = getCallingPid();
402 LOG1("unlock (pid %d)", callingPid);
403 Mutex::Autolock lock(mLock);
404
405 // allow anyone to use camera (after they lock the camera)
406 status_t result = checkPid();
407 if (result == NO_ERROR) {
408 mClientPid = 0;
409 LOG1("clear mCameraClient (pid %d)", callingPid);
410 // we need to remove the reference to ICameraClient so that when the app
411 // goes away, the reference count goes to 0.
412 mCameraClient.clear();
413 }
414 return result;
415}
416
417// connect a new client to the camera
418status_t CameraService::Client::connect(const sp<ICameraClient>& client) {
419 int callingPid = getCallingPid();
420 LOG1("connect E (pid %d)", callingPid);
421 Mutex::Autolock lock(mLock);
422
423 if (mClientPid != 0 && checkPid() != NO_ERROR) {
424 LOGW("Tried to connect to a locked camera (old pid %d, new pid %d)",
425 mClientPid, callingPid);
426 return EBUSY;
427 }
428
429 if (mCameraClient != 0 && (client->asBinder() == mCameraClient->asBinder())) {
430 LOG1("Connect to the same client");
431 return NO_ERROR;
432 }
433
434 mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
435 mClientPid = callingPid;
436 mCameraClient = client;
437
438 LOG1("connect X (pid %d)", callingPid);
439 return NO_ERROR;
440}
441
442void CameraService::Client::disconnect() {
443 int callingPid = getCallingPid();
444 LOG1("disconnect E (pid %d)", callingPid);
445 Mutex::Autolock lock(mLock);
446
447 if (checkPid() != NO_ERROR) {
448 LOGW("different client - don't disconnect");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 return;
450 }
Chih-Chung Change25cc652010-05-06 16:36:58 +0800451
452 if (mClientPid <= 0) {
453 LOG1("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 return;
455 }
456
Chih-Chung Chang6fcba312009-06-24 13:44:37 +0800457 // Make sure disconnect() is done once and once only, whether it is called
458 // from the user directly, or called by the destructor.
459 if (mHardware == 0) return;
460
Chih-Chung Change25cc652010-05-06 16:36:58 +0800461 LOG1("hardware teardown");
Chih-Chung Chang6fcba312009-06-24 13:44:37 +0800462 // Before destroying mHardware, we must make sure it's in the
463 // idle state.
Chih-Chung Change25cc652010-05-06 16:36:58 +0800464 // Turn off all messages.
465 disableMsgType(CAMERA_MSG_ALL_MSGS);
Chih-Chung Chang6fcba312009-06-24 13:44:37 +0800466 mHardware->stopPreview();
Benny Wongda83f462009-08-12 12:01:27 -0500467 mHardware->cancelPicture();
Chih-Chung Chang6fcba312009-06-24 13:44:37 +0800468 // Release the hardware resources.
469 mHardware->release();
Benny Wong6d2090e2009-07-15 18:44:27 -0500470 // Release the held overlay resources.
Chih-Chung Change25cc652010-05-06 16:36:58 +0800471 if (mUseOverlay) {
Benny Wong6d2090e2009-07-15 18:44:27 -0500472 mOverlayRef = 0;
473 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 mHardware.clear();
Chih-Chung Chang6fcba312009-06-24 13:44:37 +0800475
Chih-Chung Changd5d1ebd2009-06-24 19:59:31 +0800476 mCameraService->removeClient(mCameraClient);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800477 mCameraService->setCameraFree(mCameraId);
Chih-Chung Chang6fcba312009-06-24 13:44:37 +0800478
Chih-Chung Change25cc652010-05-06 16:36:58 +0800479 LOG1("disconnect X (pid %d)", callingPid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480}
481
Chih-Chung Change25cc652010-05-06 16:36:58 +0800482// ----------------------------------------------------------------------------
483
484// set the ISurface that the preview will use
485status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface) {
486 LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 Mutex::Autolock lock(mLock);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800488 status_t result = checkPidAndHardware();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 if (result != NO_ERROR) return result;
Wu-cheng Lib8a10fe2009-06-23 23:37:36 +0800490
Wu-cheng Lib8a10fe2009-06-23 23:37:36 +0800491 result = NO_ERROR;
Chih-Chung Change25cc652010-05-06 16:36:58 +0800492
493 // return if no change in surface.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 // asBinder() is safe on NULL (returns NULL)
Chih-Chung Change25cc652010-05-06 16:36:58 +0800495 if (surface->asBinder() == mSurface->asBinder()) {
496 return result;
497 }
498
499 if (mSurface != 0) {
500 LOG1("clearing old preview surface %p", mSurface.get());
501 if (mUseOverlay) {
502 // Force the destruction of any previous overlay
503 sp<Overlay> dummy;
504 mHardware->setOverlay(dummy);
Wu-cheng Lib3347bc2010-09-23 17:17:43 -0700505 mOverlayRef = 0;
Chih-Chung Change25cc652010-05-06 16:36:58 +0800506 } else {
507 mSurface->unregisterBuffers();
Wu-cheng Lib8a10fe2009-06-23 23:37:36 +0800508 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 }
Chih-Chung Change25cc652010-05-06 16:36:58 +0800510 mSurface = surface;
511 mOverlayRef = 0;
512 // If preview has been already started, set overlay or register preview
513 // buffers now.
514 if (mHardware->previewEnabled()) {
515 if (mUseOverlay) {
516 result = setOverlay();
517 } else if (mSurface != 0) {
518 result = registerPreviewBuffers();
519 }
520 }
521
Wu-cheng Lib8a10fe2009-06-23 23:37:36 +0800522 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523}
524
Chih-Chung Change25cc652010-05-06 16:36:58 +0800525status_t CameraService::Client::registerPreviewBuffers() {
Wu-cheng Lib8a10fe2009-06-23 23:37:36 +0800526 int w, h;
527 CameraParameters params(mHardware->getParameters());
528 params.getPreviewSize(&w, &h);
529
Chih-Chung Change25cc652010-05-06 16:36:58 +0800530 // FIXME: don't use a hardcoded format here.
Wu-cheng Lib8a10fe2009-06-23 23:37:36 +0800531 ISurface::BufferHeap buffers(w, h, w, h,
Mathias Agopian5a487122010-02-16 19:42:32 -0800532 HAL_PIXEL_FORMAT_YCrCb_420_SP,
Chih-Chung Change1ceec22010-01-21 17:31:06 -0800533 mOrientation,
Wu-cheng Lib8a10fe2009-06-23 23:37:36 +0800534 0,
535 mHardware->getPreviewHeap());
536
Chih-Chung Change25cc652010-05-06 16:36:58 +0800537 status_t result = mSurface->registerBuffers(buffers);
538 if (result != NO_ERROR) {
539 LOGE("registerBuffers failed with status %d", result);
Wu-cheng Lib8a10fe2009-06-23 23:37:36 +0800540 }
Chih-Chung Change25cc652010-05-06 16:36:58 +0800541 return result;
Wu-cheng Lib8a10fe2009-06-23 23:37:36 +0800542}
543
Chih-Chung Change25cc652010-05-06 16:36:58 +0800544status_t CameraService::Client::setOverlay() {
545 int w, h;
546 CameraParameters params(mHardware->getParameters());
547 params.getPreviewSize(&w, &h);
548
Wu-cheng Lib3347bc2010-09-23 17:17:43 -0700549 if (w != mOverlayW || h != mOverlayH || mOrientationChanged) {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800550 // Force the destruction of any previous overlay
551 sp<Overlay> dummy;
552 mHardware->setOverlay(dummy);
553 mOverlayRef = 0;
Wu-cheng Lib3347bc2010-09-23 17:17:43 -0700554 mOrientationChanged = false;
Chih-Chung Change25cc652010-05-06 16:36:58 +0800555 }
556
557 status_t result = NO_ERROR;
558 if (mSurface == 0) {
559 result = mHardware->setOverlay(NULL);
560 } else {
561 if (mOverlayRef == 0) {
562 // FIXME:
563 // Surfaceflinger may hold onto the previous overlay reference for some
564 // time after we try to destroy it. retry a few times. In the future, we
565 // should make the destroy call block, or possibly specify that we can
566 // wait in the createOverlay call if the previous overlay is in the
567 // process of being destroyed.
568 for (int retry = 0; retry < 50; ++retry) {
569 mOverlayRef = mSurface->createOverlay(w, h, OVERLAY_FORMAT_DEFAULT,
570 mOrientation);
571 if (mOverlayRef != 0) break;
572 LOGW("Overlay create failed - retrying");
573 usleep(20000);
574 }
575 if (mOverlayRef == 0) {
576 LOGE("Overlay Creation Failed!");
577 return -EINVAL;
578 }
579 result = mHardware->setOverlay(new Overlay(mOverlayRef));
580 }
581 }
582 if (result != NO_ERROR) {
583 LOGE("mHardware->setOverlay() failed with status %d\n", result);
584 return result;
585 }
586
587 mOverlayW = w;
588 mOverlayH = h;
589
590 return result;
591}
592
593// set the preview callback flag to affect how the received frames from
594// preview are handled.
595void CameraService::Client::setPreviewCallbackFlag(int callback_flag) {
596 LOG1("setPreviewCallbackFlag(%d) (pid %d)", callback_flag, getCallingPid());
597 Mutex::Autolock lock(mLock);
598 if (checkPidAndHardware() != NO_ERROR) return;
599
600 mPreviewCallbackFlag = callback_flag;
601
602 // If we don't use overlay, we always need the preview frame for display.
603 // If we do use overlay, we only need the preview frame if the user
604 // wants the data.
605 if (mUseOverlay) {
606 if(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK) {
607 enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
608 } else {
609 disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
610 }
611 }
612}
613
614// start preview mode
615status_t CameraService::Client::startPreview() {
616 LOG1("startPreview (pid %d)", getCallingPid());
617 return startCameraMode(CAMERA_PREVIEW_MODE);
618}
619
620// start recording mode
621status_t CameraService::Client::startRecording() {
622 LOG1("startRecording (pid %d)", getCallingPid());
623 return startCameraMode(CAMERA_RECORDING_MODE);
624}
625
626// start preview or recording
627status_t CameraService::Client::startCameraMode(camera_mode mode) {
628 LOG1("startCameraMode(%d)", mode);
629 Mutex::Autolock lock(mLock);
630 status_t result = checkPidAndHardware();
631 if (result != NO_ERROR) return result;
632
633 switch(mode) {
634 case CAMERA_PREVIEW_MODE:
635 if (mSurface == 0) {
636 LOG1("mSurface is not set yet.");
637 // still able to start preview in this case.
638 }
639 return startPreviewMode();
640 case CAMERA_RECORDING_MODE:
641 if (mSurface == 0) {
642 LOGE("mSurface must be set before startRecordingMode.");
643 return INVALID_OPERATION;
644 }
645 return startRecordingMode();
646 default:
647 return UNKNOWN_ERROR;
648 }
649}
650
651status_t CameraService::Client::startPreviewMode() {
652 LOG1("startPreviewMode");
653 status_t result = NO_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654
655 // if preview has been enabled, nothing needs to be done
656 if (mHardware->previewEnabled()) {
657 return NO_ERROR;
658 }
659
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 if (mUseOverlay) {
Wu-cheng Lib8a10fe2009-06-23 23:37:36 +0800661 // If preview display has been set, set overlay now.
662 if (mSurface != 0) {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800663 result = setOverlay();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 }
Chih-Chung Change25cc652010-05-06 16:36:58 +0800665 if (result != NO_ERROR) return result;
666 result = mHardware->startPreview();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 } else {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800668 enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
669 result = mHardware->startPreview();
670 if (result != NO_ERROR) return result;
Wu-cheng Lib8a10fe2009-06-23 23:37:36 +0800671 // If preview display has been set, register preview buffers now.
672 if (mSurface != 0) {
Chih-Chung Change25cc652010-05-06 16:36:58 +0800673 // Unregister here because the surface may be previously registered
674 // with the raw (snapshot) heap.
Wu-cheng Lib8a10fe2009-06-23 23:37:36 +0800675 mSurface->unregisterBuffers();
Chih-Chung Change25cc652010-05-06 16:36:58 +0800676 result = registerPreviewBuffers();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 }
678 }
Chih-Chung Change25cc652010-05-06 16:36:58 +0800679 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680}
681
Chih-Chung Change25cc652010-05-06 16:36:58 +0800682status_t CameraService::Client::startRecordingMode() {
683 LOG1("startRecordingMode");
684 status_t result = NO_ERROR;
Wu-cheng Li36f68b82009-09-28 16:14:58 -0700685
Chih-Chung Change25cc652010-05-06 16:36:58 +0800686 // if recording has been enabled, nothing needs to be done
687 if (mHardware->recordingEnabled()) {
688 return NO_ERROR;
689 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690
Chih-Chung Change25cc652010-05-06 16:36:58 +0800691 // if preview has not been started, start preview first
692 if (!mHardware->previewEnabled()) {
693 result = startPreviewMode();
694 if (result != NO_ERROR) {
695 return result;
Eric Laurent524dc042009-11-27 05:07:55 -0800696 }
Jason Samsb18b6912009-03-24 20:21:36 -0700697 }
Benny Wongda83f462009-08-12 12:01:27 -0500698
Chih-Chung Change25cc652010-05-06 16:36:58 +0800699 // start recording mode
700 enableMsgType(CAMERA_MSG_VIDEO_FRAME);
701 mCameraService->playSound(SOUND_RECORDING);
702 result = mHardware->startRecording();
703 if (result != NO_ERROR) {
704 LOGE("mHardware->startRecording() failed with status %d", result);
705 }
706 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707}
708
709// stop preview mode
Chih-Chung Change25cc652010-05-06 16:36:58 +0800710void CameraService::Client::stopPreview() {
711 LOG1("stopPreview (pid %d)", getCallingPid());
712 Mutex::Autolock lock(mLock);
713 if (checkPidAndHardware() != NO_ERROR) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714
Chih-Chung Change25cc652010-05-06 16:36:58 +0800715 disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
716 mHardware->stopPreview();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717
Chih-Chung Change25cc652010-05-06 16:36:58 +0800718 if (mSurface != 0 && !mUseOverlay) {
719 mSurface->unregisterBuffers();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 }
721
Chih-Chung Change25cc652010-05-06 16:36:58 +0800722 mPreviewBuffer.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723}
724
725// stop recording mode
Chih-Chung Change25cc652010-05-06 16:36:58 +0800726void CameraService::Client::stopRecording() {
727 LOG1("stopRecording (pid %d)", getCallingPid());
728 Mutex::Autolock lock(mLock);
729 if (checkPidAndHardware() != NO_ERROR) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730
Chih-Chung Change25cc652010-05-06 16:36:58 +0800731 mCameraService->playSound(SOUND_RECORDING);
732 disableMsgType(CAMERA_MSG_VIDEO_FRAME);
733 mHardware->stopRecording();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734
Chih-Chung Change25cc652010-05-06 16:36:58 +0800735 mPreviewBuffer.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736}
737
738// release a recording frame
Chih-Chung Change25cc652010-05-06 16:36:58 +0800739void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 Mutex::Autolock lock(mLock);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800741 if (checkPidAndHardware() != NO_ERROR) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 mHardware->releaseRecordingFrame(mem);
743}
744
Chih-Chung Change25cc652010-05-06 16:36:58 +0800745bool CameraService::Client::previewEnabled() {
746 LOG1("previewEnabled (pid %d)", getCallingPid());
747
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 Mutex::Autolock lock(mLock);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800749 if (checkPidAndHardware() != NO_ERROR) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 return mHardware->previewEnabled();
751}
752
Chih-Chung Change25cc652010-05-06 16:36:58 +0800753bool CameraService::Client::recordingEnabled() {
754 LOG1("recordingEnabled (pid %d)", getCallingPid());
755
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 Mutex::Autolock lock(mLock);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800757 if (checkPidAndHardware() != NO_ERROR) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 return mHardware->recordingEnabled();
759}
760
Chih-Chung Change25cc652010-05-06 16:36:58 +0800761status_t CameraService::Client::autoFocus() {
762 LOG1("autoFocus (pid %d)", getCallingPid());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763
764 Mutex::Autolock lock(mLock);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800765 status_t result = checkPidAndHardware();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 if (result != NO_ERROR) return result;
767
Benny Wongda83f462009-08-12 12:01:27 -0500768 return mHardware->autoFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769}
770
Chih-Chung Change25cc652010-05-06 16:36:58 +0800771status_t CameraService::Client::cancelAutoFocus() {
772 LOG1("cancelAutoFocus (pid %d)", getCallingPid());
Chih-Chung Chang244f8c22009-09-15 14:51:56 +0800773
774 Mutex::Autolock lock(mLock);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800775 status_t result = checkPidAndHardware();
Chih-Chung Chang244f8c22009-09-15 14:51:56 +0800776 if (result != NO_ERROR) return result;
777
Chih-Chung Chang244f8c22009-09-15 14:51:56 +0800778 return mHardware->cancelAutoFocus();
779}
780
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800781// take a picture - image is returned in callback
Chih-Chung Change25cc652010-05-06 16:36:58 +0800782status_t CameraService::Client::takePicture() {
783 LOG1("takePicture (pid %d)", getCallingPid());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784
785 Mutex::Autolock lock(mLock);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800786 status_t result = checkPidAndHardware();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 if (result != NO_ERROR) return result;
788
Chih-Chung Change25cc652010-05-06 16:36:58 +0800789 enableMsgType(CAMERA_MSG_SHUTTER |
790 CAMERA_MSG_POSTVIEW_FRAME |
791 CAMERA_MSG_RAW_IMAGE |
792 CAMERA_MSG_COMPRESSED_IMAGE);
Benny Wongda83f462009-08-12 12:01:27 -0500793
794 return mHardware->takePicture();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795}
796
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797// set preview/capture parameters - key/value pairs
Chih-Chung Change25cc652010-05-06 16:36:58 +0800798status_t CameraService::Client::setParameters(const String8& params) {
799 LOG1("setParameters (pid %d) (%s)", getCallingPid(), params.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800
801 Mutex::Autolock lock(mLock);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800802 status_t result = checkPidAndHardware();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 if (result != NO_ERROR) return result;
804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 CameraParameters p(params);
James Dong6085b4e2009-09-13 17:10:24 -0700806 return mHardware->setParameters(p);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807}
808
809// get preview/capture parameters - key/value pairs
Chih-Chung Change25cc652010-05-06 16:36:58 +0800810String8 CameraService::Client::getParameters() const {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 Mutex::Autolock lock(mLock);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800812 if (checkPidAndHardware() != NO_ERROR) return String8();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813
Wu-cheng Liab5b4242009-04-22 16:21:26 +0800814 String8 params(mHardware->getParameters().flatten());
Chih-Chung Change25cc652010-05-06 16:36:58 +0800815 LOG1("getParameters (pid %d) (%s)", getCallingPid(), params.string());
Wu-cheng Liab5b4242009-04-22 16:21:26 +0800816 return params;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817}
818
Chih-Chung Change25cc652010-05-06 16:36:58 +0800819status_t CameraService::Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
820 LOG1("sendCommand (pid %d)", getCallingPid());
Wu-cheng Lib3347bc2010-09-23 17:17:43 -0700821 int orientation;
Wu-cheng Li36f68b82009-09-28 16:14:58 -0700822 Mutex::Autolock lock(mLock);
Chih-Chung Change25cc652010-05-06 16:36:58 +0800823 status_t result = checkPidAndHardware();
Wu-cheng Li36f68b82009-09-28 16:14:58 -0700824 if (result != NO_ERROR) return result;
825
Chih-Chung Changd1d77062010-01-22 17:49:48 -0800826 if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) {
827 // The orientation cannot be set during preview.
828 if (mHardware->previewEnabled()) {
829 return INVALID_OPERATION;
830 }
Wu-cheng Lib982fb42010-10-19 17:19:09 +0800831 // Mirror the preview if the camera is front-facing.
832 orientation = getOrientation(arg1, mCameraFacing == CAMERA_FACING_FRONT);
833 if (orientation == -1) return BAD_VALUE;
834
Wu-cheng Lib3347bc2010-09-23 17:17:43 -0700835 if (mOrientation != orientation) {
836 mOrientation = orientation;
837 if (mOverlayRef != 0) mOrientationChanged = true;
838 }
Chih-Chung Changd1d77062010-01-22 17:49:48 -0800839 return OK;
840 }
841
Wu-cheng Li36f68b82009-09-28 16:14:58 -0700842 return mHardware->sendCommand(cmd, arg1, arg2);
843}
844
Chih-Chung Change25cc652010-05-06 16:36:58 +0800845// ----------------------------------------------------------------------------
846
847void CameraService::Client::enableMsgType(int32_t msgType) {
848 android_atomic_or(msgType, &mMsgEnabled);
849 mHardware->enableMsgType(msgType);
850}
851
852void CameraService::Client::disableMsgType(int32_t msgType) {
853 android_atomic_and(~msgType, &mMsgEnabled);
854 mHardware->disableMsgType(msgType);
855}
856
857#define CHECK_MESSAGE_INTERVAL 10 // 10ms
858bool CameraService::Client::lockIfMessageWanted(int32_t msgType) {
859 int sleepCount = 0;
860 while (mMsgEnabled & msgType) {
861 if (mLock.tryLock() == NO_ERROR) {
862 if (sleepCount > 0) {
863 LOG1("lockIfMessageWanted(%d): waited for %d ms",
864 msgType, sleepCount * CHECK_MESSAGE_INTERVAL);
865 }
866 return true;
867 }
868 if (sleepCount++ == 0) {
869 LOG1("lockIfMessageWanted(%d): enter sleep", msgType);
870 }
871 usleep(CHECK_MESSAGE_INTERVAL * 1000);
872 }
873 LOGW("lockIfMessageWanted(%d): dropped unwanted message", msgType);
874 return false;
875}
876
877// ----------------------------------------------------------------------------
878
879// Converts from a raw pointer to the client to a strong pointer during a
880// hardware callback. This requires the callbacks only happen when the client
881// is still alive.
882sp<CameraService::Client> CameraService::Client::getClientFromCookie(void* user) {
883 sp<Client> client = gCameraService->getClientById((int) user);
884
885 // This could happen if the Client is in the process of shutting down (the
886 // last strong reference is gone, but the destructor hasn't finished
887 // stopping the hardware).
888 if (client == 0) return NULL;
889
890 // The checks below are not necessary and are for debugging only.
891 if (client->mCameraService.get() != gCameraService) {
892 LOGE("mismatch service!");
893 return NULL;
894 }
895
896 if (client->mHardware == 0) {
897 LOGE("mHardware == 0: callback after disconnect()?");
898 return NULL;
899 }
900
901 return client;
902}
903
904// Callback messages can be dispatched to internal handlers or pass to our
905// client's callback functions, depending on the message type.
906//
907// notifyCallback:
908// CAMERA_MSG_SHUTTER handleShutter
909// (others) c->notifyCallback
910// dataCallback:
911// CAMERA_MSG_PREVIEW_FRAME handlePreviewData
912// CAMERA_MSG_POSTVIEW_FRAME handlePostview
913// CAMERA_MSG_RAW_IMAGE handleRawPicture
914// CAMERA_MSG_COMPRESSED_IMAGE handleCompressedPicture
915// (others) c->dataCallback
916// dataCallbackTimestamp
917// (others) c->dataCallbackTimestamp
918//
919// NOTE: the *Callback functions grab mLock of the client before passing
920// control to handle* functions. So the handle* functions must release the
921// lock before calling the ICameraClient's callbacks, so those callbacks can
922// invoke methods in the Client class again (For example, the preview frame
923// callback may want to releaseRecordingFrame). The handle* functions must
924// release the lock after all accesses to member variables, so it must be
925// handled very carefully.
926
927void CameraService::Client::notifyCallback(int32_t msgType, int32_t ext1,
928 int32_t ext2, void* user) {
929 LOG2("notifyCallback(%d)", msgType);
930
931 sp<Client> client = getClientFromCookie(user);
932 if (client == 0) return;
933 if (!client->lockIfMessageWanted(msgType)) return;
934
935 switch (msgType) {
936 case CAMERA_MSG_SHUTTER:
937 // ext1 is the dimension of the yuv picture.
938 client->handleShutter((image_rect_type *)ext1);
939 break;
940 default:
941 client->handleGenericNotify(msgType, ext1, ext2);
942 break;
943 }
944}
945
946void CameraService::Client::dataCallback(int32_t msgType,
947 const sp<IMemory>& dataPtr, void* user) {
948 LOG2("dataCallback(%d)", msgType);
949
950 sp<Client> client = getClientFromCookie(user);
951 if (client == 0) return;
952 if (!client->lockIfMessageWanted(msgType)) return;
953
954 if (dataPtr == 0) {
955 LOGE("Null data returned in data callback");
956 client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
957 return;
958 }
959
960 switch (msgType) {
961 case CAMERA_MSG_PREVIEW_FRAME:
962 client->handlePreviewData(dataPtr);
963 break;
964 case CAMERA_MSG_POSTVIEW_FRAME:
965 client->handlePostview(dataPtr);
966 break;
967 case CAMERA_MSG_RAW_IMAGE:
968 client->handleRawPicture(dataPtr);
969 break;
970 case CAMERA_MSG_COMPRESSED_IMAGE:
971 client->handleCompressedPicture(dataPtr);
972 break;
973 default:
974 client->handleGenericData(msgType, dataPtr);
975 break;
976 }
977}
978
979void CameraService::Client::dataCallbackTimestamp(nsecs_t timestamp,
980 int32_t msgType, const sp<IMemory>& dataPtr, void* user) {
981 LOG2("dataCallbackTimestamp(%d)", msgType);
982
983 sp<Client> client = getClientFromCookie(user);
984 if (client == 0) return;
985 if (!client->lockIfMessageWanted(msgType)) return;
986
987 if (dataPtr == 0) {
988 LOGE("Null data returned in data with timestamp callback");
989 client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
990 return;
991 }
992
993 client->handleGenericDataTimestamp(timestamp, msgType, dataPtr);
994}
995
996// snapshot taken callback
997// "size" is the width and height of yuv picture for registerBuffer.
998// If it is NULL, use the picture size from parameters.
999void CameraService::Client::handleShutter(image_rect_type *size) {
1000 mCameraService->playSound(SOUND_SHUTTER);
1001
1002 // Screen goes black after the buffer is unregistered.
1003 if (mSurface != 0 && !mUseOverlay) {
1004 mSurface->unregisterBuffers();
1005 }
1006
1007 sp<ICameraClient> c = mCameraClient;
1008 if (c != 0) {
1009 mLock.unlock();
1010 c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
1011 if (!lockIfMessageWanted(CAMERA_MSG_SHUTTER)) return;
1012 }
1013 disableMsgType(CAMERA_MSG_SHUTTER);
1014
1015 // It takes some time before yuvPicture callback to be called.
1016 // Register the buffer for raw image here to reduce latency.
1017 if (mSurface != 0 && !mUseOverlay) {
1018 int w, h;
1019 CameraParameters params(mHardware->getParameters());
1020 if (size == NULL) {
1021 params.getPictureSize(&w, &h);
1022 } else {
1023 w = size->width;
1024 h = size->height;
1025 w &= ~1;
1026 h &= ~1;
1027 LOG1("Snapshot image width=%d, height=%d", w, h);
1028 }
1029 // FIXME: don't use hardcoded format constants here
1030 ISurface::BufferHeap buffers(w, h, w, h,
1031 HAL_PIXEL_FORMAT_YCrCb_420_SP, mOrientation, 0,
1032 mHardware->getRawHeap());
1033
1034 mSurface->registerBuffers(buffers);
Chih-Chung Chang3ef6ebe2010-07-02 07:48:03 -07001035 IPCThreadState::self()->flushCommands();
Chih-Chung Change25cc652010-05-06 16:36:58 +08001036 }
1037
1038 mLock.unlock();
1039}
1040
1041// preview callback - frame buffer update
1042void CameraService::Client::handlePreviewData(const sp<IMemory>& mem) {
1043 ssize_t offset;
1044 size_t size;
1045 sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
1046
1047 if (!mUseOverlay) {
1048 if (mSurface != 0) {
1049 mSurface->postBuffer(offset);
1050 }
1051 }
1052
1053 // local copy of the callback flags
1054 int flags = mPreviewCallbackFlag;
1055
1056 // is callback enabled?
1057 if (!(flags & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
1058 // If the enable bit is off, the copy-out and one-shot bits are ignored
1059 LOG2("frame callback is disabled");
1060 mLock.unlock();
1061 return;
1062 }
1063
1064 // hold a strong pointer to the client
1065 sp<ICameraClient> c = mCameraClient;
1066
1067 // clear callback flags if no client or one-shot mode
1068 if (c == 0 || (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
1069 LOG2("Disable preview callback");
1070 mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
1071 FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
1072 FRAME_CALLBACK_FLAG_ENABLE_MASK);
1073 if (mUseOverlay) {
1074 disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
1075 }
1076 }
1077
1078 if (c != 0) {
1079 // Is the received frame copied out or not?
1080 if (flags & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
1081 LOG2("frame is copied");
1082 copyFrameAndPostCopiedFrame(c, heap, offset, size);
1083 } else {
1084 LOG2("frame is forwarded");
1085 mLock.unlock();
1086 c->dataCallback(CAMERA_MSG_PREVIEW_FRAME, mem);
1087 }
1088 } else {
1089 mLock.unlock();
1090 }
1091}
1092
1093// picture callback - postview image ready
1094void CameraService::Client::handlePostview(const sp<IMemory>& mem) {
1095 disableMsgType(CAMERA_MSG_POSTVIEW_FRAME);
1096
1097 sp<ICameraClient> c = mCameraClient;
1098 mLock.unlock();
1099 if (c != 0) {
1100 c->dataCallback(CAMERA_MSG_POSTVIEW_FRAME, mem);
1101 }
1102}
1103
1104// picture callback - raw image ready
1105void CameraService::Client::handleRawPicture(const sp<IMemory>& mem) {
1106 disableMsgType(CAMERA_MSG_RAW_IMAGE);
1107
1108 ssize_t offset;
1109 size_t size;
1110 sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
1111
1112 // Put the YUV version of the snapshot in the preview display.
1113 if (mSurface != 0 && !mUseOverlay) {
1114 mSurface->postBuffer(offset);
1115 }
1116
1117 sp<ICameraClient> c = mCameraClient;
1118 mLock.unlock();
1119 if (c != 0) {
1120 c->dataCallback(CAMERA_MSG_RAW_IMAGE, mem);
1121 }
1122}
1123
1124// picture callback - compressed picture ready
1125void CameraService::Client::handleCompressedPicture(const sp<IMemory>& mem) {
1126 disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
1127
1128 sp<ICameraClient> c = mCameraClient;
1129 mLock.unlock();
1130 if (c != 0) {
1131 c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem);
1132 }
1133}
1134
1135
1136void CameraService::Client::handleGenericNotify(int32_t msgType,
1137 int32_t ext1, int32_t ext2) {
1138 sp<ICameraClient> c = mCameraClient;
1139 mLock.unlock();
1140 if (c != 0) {
1141 c->notifyCallback(msgType, ext1, ext2);
1142 }
1143}
1144
1145void CameraService::Client::handleGenericData(int32_t msgType,
1146 const sp<IMemory>& dataPtr) {
1147 sp<ICameraClient> c = mCameraClient;
1148 mLock.unlock();
1149 if (c != 0) {
1150 c->dataCallback(msgType, dataPtr);
1151 }
1152}
1153
1154void CameraService::Client::handleGenericDataTimestamp(nsecs_t timestamp,
1155 int32_t msgType, const sp<IMemory>& dataPtr) {
1156 sp<ICameraClient> c = mCameraClient;
1157 mLock.unlock();
1158 if (c != 0) {
1159 c->dataCallbackTimestamp(timestamp, msgType, dataPtr);
1160 }
1161}
1162
1163void CameraService::Client::copyFrameAndPostCopiedFrame(
1164 const sp<ICameraClient>& client, const sp<IMemoryHeap>& heap,
1165 size_t offset, size_t size) {
1166 LOG2("copyFrameAndPostCopiedFrame");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 // It is necessary to copy out of pmem before sending this to
1168 // the callback. For efficiency, reuse the same MemoryHeapBase
1169 // provided it's big enough. Don't allocate the memory or
1170 // perform the copy if there's no callback.
Dave Sparks05fd0df2009-11-10 17:08:08 -08001171 // hold the preview lock while we grab a reference to the preview buffer
Dave Sparksc8093c12009-11-06 11:47:13 -08001172 sp<MemoryHeapBase> previewBuffer;
Chih-Chung Change25cc652010-05-06 16:36:58 +08001173
1174 if (mPreviewBuffer == 0) {
1175 mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
1176 } else if (size > mPreviewBuffer->virtualSize()) {
1177 mPreviewBuffer.clear();
1178 mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001179 }
Chih-Chung Change25cc652010-05-06 16:36:58 +08001180 if (mPreviewBuffer == 0) {
1181 LOGE("failed to allocate space for preview buffer");
1182 mLock.unlock();
1183 return;
1184 }
1185 previewBuffer = mPreviewBuffer;
1186
1187 memcpy(previewBuffer->base(), (uint8_t *)heap->base() + offset, size);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188
Dave Sparksc8093c12009-11-06 11:47:13 -08001189 sp<MemoryBase> frame = new MemoryBase(previewBuffer, 0, size);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001190 if (frame == 0) {
1191 LOGE("failed to allocate space for frame callback");
Chih-Chung Change25cc652010-05-06 16:36:58 +08001192 mLock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 return;
1194 }
Chih-Chung Change25cc652010-05-06 16:36:58 +08001195
1196 mLock.unlock();
Dave Sparksdd158c92009-10-15 10:02:22 -07001197 client->dataCallback(CAMERA_MSG_PREVIEW_FRAME, frame);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198}
1199
Wu-cheng Lib982fb42010-10-19 17:19:09 +08001200int CameraService::Client::getOrientation(int degrees, bool mirror) {
1201 if (!mirror) {
1202 if (degrees == 0) return 0;
1203 else if (degrees == 90) return HAL_TRANSFORM_ROT_90;
1204 else if (degrees == 180) return HAL_TRANSFORM_ROT_180;
1205 else if (degrees == 270) return HAL_TRANSFORM_ROT_270;
1206 } else { // mirror (horizontal flip)
1207 // Now overlay does ROT_90 before FLIP_V or FLIP_H. It should be FLIP_V
1208 // or FLIP_H first.
1209 // TODO: change this after overlay is fixed.
1210 if (degrees == 0) { // FLIP_H and ROT_0
1211 return HAL_TRANSFORM_FLIP_H;
1212 } else if (degrees == 90) { // FLIP_H and ROT_90
1213 return HAL_TRANSFORM_ROT_90 | HAL_TRANSFORM_FLIP_V;
1214 } else if (degrees == 180) { // FLIP_H and ROT_180
1215 return HAL_TRANSFORM_FLIP_V;
1216 } else if (degrees == 270) { // FLIP_H and ROT_270
1217 return HAL_TRANSFORM_ROT_90 | HAL_TRANSFORM_FLIP_H;
1218 }
1219 }
1220 LOGE("Invalid setDisplayOrientation degrees=%d", degrees);
1221 return -1;
1222}
1223
1224
Chih-Chung Change25cc652010-05-06 16:36:58 +08001225// ----------------------------------------------------------------------------
1226
Chih-Chung Change86ae1b2010-03-05 11:33:03 -08001227static const int kDumpLockRetries = 50;
1228static const int kDumpLockSleep = 60000;
1229
1230static bool tryLock(Mutex& mutex)
1231{
1232 bool locked = false;
1233 for (int i = 0; i < kDumpLockRetries; ++i) {
1234 if (mutex.tryLock() == NO_ERROR) {
1235 locked = true;
1236 break;
1237 }
1238 usleep(kDumpLockSleep);
1239 }
1240 return locked;
1241}
1242
Chih-Chung Change25cc652010-05-06 16:36:58 +08001243status_t CameraService::dump(int fd, const Vector<String16>& args) {
Chih-Chung Change86ae1b2010-03-05 11:33:03 -08001244 static const char* kDeadlockedString = "CameraService may be deadlocked\n";
1245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001246 const size_t SIZE = 256;
1247 char buffer[SIZE];
1248 String8 result;
1249 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
1250 snprintf(buffer, SIZE, "Permission Denial: "
1251 "can't dump CameraService from pid=%d, uid=%d\n",
Chih-Chung Chang1f25ec82009-06-22 16:03:41 +08001252 getCallingPid(),
Chih-Chung Change25cc652010-05-06 16:36:58 +08001253 getCallingUid());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001254 result.append(buffer);
1255 write(fd, result.string(), result.size());
1256 } else {
Chih-Chung Change86ae1b2010-03-05 11:33:03 -08001257 bool locked = tryLock(mServiceLock);
1258 // failed to lock - CameraService is probably deadlocked
1259 if (!locked) {
1260 String8 result(kDeadlockedString);
1261 write(fd, result.string(), result.size());
1262 }
1263
Chih-Chung Change25cc652010-05-06 16:36:58 +08001264 bool hasClient = false;
Chih-Chung Changb8bb78f2010-06-10 13:32:16 +08001265 for (int i = 0; i < mNumberOfCameras; i++) {
Chih-Chung Change25cc652010-05-06 16:36:58 +08001266 sp<Client> client = mClient[i].promote();
1267 if (client == 0) continue;
1268 hasClient = true;
1269 sprintf(buffer, "Client[%d] (%p) PID: %d\n",
1270 i,
1271 client->getCameraClient()->asBinder().get(),
1272 client->mClientPid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 result.append(buffer);
1274 write(fd, result.string(), result.size());
Chih-Chung Change25cc652010-05-06 16:36:58 +08001275 client->mHardware->dump(fd, args);
1276 }
1277 if (!hasClient) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 result.append("No camera client yet.\n");
1279 write(fd, result.string(), result.size());
1280 }
Chih-Chung Change86ae1b2010-03-05 11:33:03 -08001281
1282 if (locked) mServiceLock.unlock();
Chih-Chung Change25cc652010-05-06 16:36:58 +08001283
1284 // change logging level
1285 int n = args.size();
1286 for (int i = 0; i + 1 < n; i++) {
1287 if (args[i] == String16("-v")) {
1288 String8 levelStr(args[i+1]);
1289 int level = atoi(levelStr.string());
1290 sprintf(buffer, "Set Log Level to %d", level);
1291 result.append(buffer);
1292 setLogLevel(level);
1293 }
1294 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 }
1296 return NO_ERROR;
1297}
1298
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001299}; // namespace android