1/*
2**
3** Copyright (C) 2013, The Android Open Source Project
4**
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
18//#define LOG_NDEBUG 0
19#define LOG_TAG "ProCamera"
20#include <utils/Log.h>
21#include <utils/threads.h>
22#include <utils/Mutex.h>
23
24#include <binder/IPCThreadState.h>
25#include <binder/IServiceManager.h>
26#include <binder/IMemory.h>
27
28#include <camera/ProCamera.h>
29#include <camera/IProCameraUser.h>
30#include <camera/IProCameraCallbacks.h>
31
32#include <gui/IGraphicBufferProducer.h>
33
34#include <system/camera_metadata.h>
35
36namespace android {
37
38sp<ProCamera> ProCamera::connect(int cameraId)
39{
40    return CameraBaseT::connect(cameraId, String16(),
41                                 ICameraService::USE_CALLING_UID);
42}
43
44ProCamera::ProCamera(int cameraId)
45    : CameraBase(cameraId)
46{
47}
48
49CameraTraits<ProCamera>::TCamConnectService CameraTraits<ProCamera>::fnConnectService =
50        &ICameraService::connectPro;
51
52ProCamera::~ProCamera()
53{
54
55}
56
57/* IProCameraUser's implementation */
58
59// callback from camera service
60void ProCamera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
61{
62    return CameraBaseT::notifyCallback(msgType, ext1, ext2);
63}
64
65void ProCamera::onLockStatusChanged(
66                                 IProCameraCallbacks::LockStatus newLockStatus)
67{
68    ALOGV("%s: newLockStatus = %d", __FUNCTION__, newLockStatus);
69
70    sp<ProCameraListener> listener;
71    {
72        Mutex::Autolock _l(mLock);
73        listener = mListener;
74    }
75    if (listener != NULL) {
76        switch (newLockStatus) {
77            case IProCameraCallbacks::LOCK_ACQUIRED:
78                listener->onLockAcquired();
79                break;
80            case IProCameraCallbacks::LOCK_RELEASED:
81                listener->onLockReleased();
82                break;
83            case IProCameraCallbacks::LOCK_STOLEN:
84                listener->onLockStolen();
85                break;
86            default:
87                ALOGE("%s: Unknown lock status: %d",
88                      __FUNCTION__, newLockStatus);
89        }
90    }
91}
92
93void ProCamera::onResultReceived(int32_t requestId, camera_metadata* result) {
94    ALOGV("%s: requestId = %d, result = %p", __FUNCTION__, requestId, result);
95
96    sp<ProCameraListener> listener;
97    {
98        Mutex::Autolock _l(mLock);
99        listener = mListener;
100    }
101
102    CameraMetadata tmp(result);
103
104    // Unblock waitForFrame(id) callers
105    {
106        Mutex::Autolock al(mWaitMutex);
107        mMetadataReady = true;
108        mLatestMetadata = tmp; // make copy
109        mWaitCondition.broadcast();
110    }
111
112    result = tmp.release();
113
114    if (listener != NULL) {
115        listener->onResultReceived(requestId, result);
116    } else {
117        free_camera_metadata(result);
118    }
119
120}
121
122status_t ProCamera::exclusiveTryLock()
123{
124    sp <IProCameraUser> c = mCamera;
125    if (c == 0) return NO_INIT;
126
127    return c->exclusiveTryLock();
128}
129status_t ProCamera::exclusiveLock()
130{
131    sp <IProCameraUser> c = mCamera;
132    if (c == 0) return NO_INIT;
133
134    return c->exclusiveLock();
135}
136status_t ProCamera::exclusiveUnlock()
137{
138    sp <IProCameraUser> c = mCamera;
139    if (c == 0) return NO_INIT;
140
141    return c->exclusiveUnlock();
142}
143bool ProCamera::hasExclusiveLock()
144{
145    sp <IProCameraUser> c = mCamera;
146    if (c == 0) return NO_INIT;
147
148    return c->hasExclusiveLock();
149}
150
151// Note that the callee gets a copy of the metadata.
152int ProCamera::submitRequest(const struct camera_metadata* metadata,
153                             bool streaming)
154{
155    sp <IProCameraUser> c = mCamera;
156    if (c == 0) return NO_INIT;
157
158    return c->submitRequest(const_cast<struct camera_metadata*>(metadata),
159                            streaming);
160}
161
162status_t ProCamera::cancelRequest(int requestId)
163{
164    sp <IProCameraUser> c = mCamera;
165    if (c == 0) return NO_INIT;
166
167    return c->cancelRequest(requestId);
168}
169
170status_t ProCamera::deleteStream(int streamId)
171{
172    sp <IProCameraUser> c = mCamera;
173    if (c == 0) return NO_INIT;
174
175    status_t s = c->deleteStream(streamId);
176
177    mStreams.removeItem(streamId);
178
179    return s;
180}
181
182status_t ProCamera::createStream(int width, int height, int format,
183                                 const sp<Surface>& surface,
184                                 /*out*/
185                                 int* streamId)
186{
187    *streamId = -1;
188
189    ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
190                                                                       format);
191
192    if (surface == 0) {
193        return BAD_VALUE;
194    }
195
196    return createStream(width, height, format,
197                        surface->getIGraphicBufferProducer(),
198                        streamId);
199}
200
201status_t ProCamera::createStream(int width, int height, int format,
202                                 const sp<IGraphicBufferProducer>& bufferProducer,
203                                 /*out*/
204                                 int* streamId) {
205    *streamId = -1;
206
207    ALOGV("%s: createStreamT %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
208                                                                       format);
209
210    if (bufferProducer == 0) {
211        return BAD_VALUE;
212    }
213
214    sp <IProCameraUser> c = mCamera;
215    status_t stat = c->createStream(width, height, format, bufferProducer,
216                                    streamId);
217
218    if (stat == OK) {
219        StreamInfo s(*streamId);
220
221        mStreams.add(*streamId, s);
222    }
223
224    return stat;
225}
226
227status_t ProCamera::createStreamCpu(int width, int height, int format,
228                                    int heapCount,
229                                    /*out*/
230                                    sp<CpuConsumer>* cpuConsumer,
231                                    int* streamId) {
232    return createStreamCpu(width, height, format, heapCount,
233                           /*synchronousMode*/true,
234                           cpuConsumer, streamId);
235}
236
237status_t ProCamera::createStreamCpu(int width, int height, int format,
238                                    int heapCount,
239                                    bool synchronousMode,
240                                    /*out*/
241                                    sp<CpuConsumer>* cpuConsumer,
242                                    int* streamId)
243{
244    ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
245                                                                        format);
246
247    *cpuConsumer = NULL;
248
249    sp <IProCameraUser> c = mCamera;
250    if (c == 0) return NO_INIT;
251
252    sp<IGraphicBufferProducer> producer;
253    sp<IGraphicBufferConsumer> consumer;
254    BufferQueue::createBufferQueue(&producer, &consumer);
255    sp<CpuConsumer> cc = new CpuConsumer(consumer, heapCount
256            /*, synchronousMode*/);
257    cc->setName(String8("ProCamera::mCpuConsumer"));
258
259    sp<Surface> stc = new Surface(producer);
260
261    status_t s = createStream(width, height, format,
262                              stc->getIGraphicBufferProducer(),
263                              streamId);
264
265    if (s != OK) {
266        ALOGE("%s: Failure to create stream %dx%d (fmt=0x%x)", __FUNCTION__,
267                    width, height, format);
268        return s;
269    }
270
271    sp<ProFrameListener> frameAvailableListener =
272        new ProFrameListener(this, *streamId);
273
274    getStreamInfo(*streamId).cpuStream = true;
275    getStreamInfo(*streamId).cpuConsumer = cc;
276    getStreamInfo(*streamId).synchronousMode = synchronousMode;
277    getStreamInfo(*streamId).stc = stc;
278    // for lifetime management
279    getStreamInfo(*streamId).frameAvailableListener = frameAvailableListener;
280
281    cc->setFrameAvailableListener(frameAvailableListener);
282
283    *cpuConsumer = cc;
284
285    return s;
286}
287
288camera_metadata* ProCamera::getCameraInfo(int cameraId) {
289    ALOGV("%s: cameraId = %d", __FUNCTION__, cameraId);
290
291    sp <IProCameraUser> c = mCamera;
292    if (c == 0) return NULL;
293
294    camera_metadata* ptr = NULL;
295    status_t status = c->getCameraInfo(cameraId, &ptr);
296
297    if (status != OK) {
298        ALOGE("%s: Failed to get camera info, error = %d", __FUNCTION__, status);
299    }
300
301    return ptr;
302}
303
304status_t ProCamera::createDefaultRequest(int templateId,
305                                             camera_metadata** request) const {
306    ALOGV("%s: templateId = %d", __FUNCTION__, templateId);
307
308    sp <IProCameraUser> c = mCamera;
309    if (c == 0) return NO_INIT;
310
311    return c->createDefaultRequest(templateId, request);
312}
313
314void ProCamera::onFrameAvailable(int streamId) {
315    ALOGV("%s: streamId = %d", __FUNCTION__, streamId);
316
317    sp<ProCameraListener> listener = mListener;
318    StreamInfo& stream = getStreamInfo(streamId);
319
320    if (listener.get() != NULL) {
321        listener->onFrameAvailable(streamId, stream.cpuConsumer);
322    }
323
324    // Unblock waitForFrame(id) callers
325    {
326        Mutex::Autolock al(mWaitMutex);
327        getStreamInfo(streamId).frameReady++;
328        mWaitCondition.broadcast();
329    }
330}
331
332int ProCamera::waitForFrameBuffer(int streamId) {
333    status_t stat = BAD_VALUE;
334    Mutex::Autolock al(mWaitMutex);
335
336    StreamInfo& si = getStreamInfo(streamId);
337
338    if (si.frameReady > 0) {
339        int numFrames = si.frameReady;
340        si.frameReady = 0;
341        return numFrames;
342    } else {
343        while (true) {
344            stat = mWaitCondition.waitRelative(mWaitMutex,
345                                                mWaitTimeout);
346            if (stat != OK) {
347                ALOGE("%s: Error while waiting for frame buffer: %d",
348                    __FUNCTION__, stat);
349                return stat;
350            }
351
352            if (si.frameReady > 0) {
353                int numFrames = si.frameReady;
354                si.frameReady = 0;
355                return numFrames;
356            }
357            // else it was some other stream that got unblocked
358        }
359    }
360
361    return stat;
362}
363
364int ProCamera::dropFrameBuffer(int streamId, int count) {
365    StreamInfo& si = getStreamInfo(streamId);
366
367    if (!si.cpuStream) {
368        return BAD_VALUE;
369    } else if (count < 0) {
370        return BAD_VALUE;
371    }
372
373    if (!si.synchronousMode) {
374        ALOGW("%s: No need to drop frames on asynchronous streams,"
375              " as asynchronous mode only keeps 1 latest frame around.",
376              __FUNCTION__);
377        return BAD_VALUE;
378    }
379
380    int numDropped = 0;
381    for (int i = 0; i < count; ++i) {
382        CpuConsumer::LockedBuffer buffer;
383        if (si.cpuConsumer->lockNextBuffer(&buffer) != OK) {
384            break;
385        }
386
387        si.cpuConsumer->unlockBuffer(buffer);
388        numDropped++;
389    }
390
391    return numDropped;
392}
393
394status_t ProCamera::waitForFrameMetadata() {
395    status_t stat = BAD_VALUE;
396    Mutex::Autolock al(mWaitMutex);
397
398    if (mMetadataReady) {
399        return OK;
400    } else {
401        while (true) {
402            stat = mWaitCondition.waitRelative(mWaitMutex,
403                                               mWaitTimeout);
404
405            if (stat != OK) {
406                ALOGE("%s: Error while waiting for metadata: %d",
407                        __FUNCTION__, stat);
408                return stat;
409            }
410
411            if (mMetadataReady) {
412                mMetadataReady = false;
413                return OK;
414            }
415            // else it was some other stream or metadata
416        }
417    }
418
419    return stat;
420}
421
422CameraMetadata ProCamera::consumeFrameMetadata() {
423    Mutex::Autolock al(mWaitMutex);
424
425    // Destructive: Subsequent calls return empty metadatas
426    CameraMetadata tmp = mLatestMetadata;
427    mLatestMetadata.clear();
428
429    return tmp;
430}
431
432ProCamera::StreamInfo& ProCamera::getStreamInfo(int streamId) {
433    return mStreams.editValueFor(streamId);
434}
435
436}; // namespace android
437