merge in jb-mr2-release history after reset to jb-mr2-dev
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index 396b009..fec5461 100644
--- a/camera/ProCamera.cpp
+++ b/camera/ProCamera.cpp
@@ -103,7 +103,7 @@
{
Mutex::Autolock al(mWaitMutex);
mMetadataReady = true;
- mLatestMetadata = tmp;
+ mLatestMetadata = tmp; // make copy
mWaitCondition.broadcast();
}
@@ -312,8 +312,6 @@
sp<ProCameraListener> listener = mListener;
StreamInfo& stream = getStreamInfo(streamId);
- CpuConsumer::LockedBuffer buf;
-
if (listener.get() != NULL) {
listener->onFrameAvailable(streamId, stream.cpuConsumer);
}
@@ -421,7 +419,7 @@
// Destructive: Subsequent calls return empty metadatas
CameraMetadata tmp = mLatestMetadata;
- mLatestMetadata.release();
+ mLatestMetadata.clear();
return tmp;
}
diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp
index ecc0854..2b5f3ad 100644
--- a/camera/tests/ProCameraTests.cpp
+++ b/camera/tests/ProCameraTests.cpp
@@ -587,14 +587,19 @@
sp<ServiceListener> listener = new ServiceListener();
EXPECT_OK(ProCamera::addServiceListener(listener));
- ServiceListener::Status currentStatus = ServiceListener::STATUS_AVAILABLE;
+ ServiceListener::Status currentStatus;
+
+ // when subscribing a new listener,
+ // we immediately get a callback to the current status
+ while (listener->waitForStatusChange(/*out*/currentStatus) != OK);
+ EXPECT_EQ(ServiceListener::STATUS_PRESENT, currentStatus);
dout << "Will now stream and resume infinitely..." << std::endl;
while (true) {
- if (currentStatus == ServiceListener::STATUS_AVAILABLE) {
+ if (currentStatus == ServiceListener::STATUS_PRESENT) {
- EXPECT_OK(mCamera->createStream(mDisplayW, mDisplayH, mDisplayFmt,
+ ASSERT_OK(mCamera->createStream(mDisplayW, mDisplayH, mDisplayFmt,
surface,
&depthStreamId));
EXPECT_NE(-1, depthStreamId);
@@ -613,12 +618,15 @@
while (listener->waitForStatusChange(/*out*/stat) != OK);
if (currentStatus != stat) {
- if (stat == ServiceListener::STATUS_AVAILABLE) {
+ if (stat == ServiceListener::STATUS_PRESENT) {
dout << "Reconnecting to camera" << std::endl;
mCamera = ProCamera::connect(CAMERA_ID);
} else if (stat == ServiceListener::STATUS_NOT_AVAILABLE) {
dout << "Disconnecting from camera" << std::endl;
mCamera->disconnect();
+ } else if (stat == ServiceListener::STATUS_NOT_PRESENT) {
+ dout << "Camera unplugged" << std::endl;
+ mCamera = NULL;
} else {
dout << "Unknown status change "
<< std::hex << stat << std::endl;
@@ -1021,6 +1029,9 @@
// Consume two frames simultaneously. Unsynchronized by timestamps.
for (int i = 0; i < REQUEST_COUNT; ++i) {
+ // Exhaust event queue so it doesn't keep growing
+ while (mListener->ReadEvent() != UNKNOWN);
+
// Get the metadata
EXPECT_OK(mCamera->waitForFrameMetadata());
CameraMetadata meta = mCamera->consumeFrameMetadata();
@@ -1216,7 +1227,7 @@
}
EXPECT_OK(listener->waitForStatusChange(/*out*/stat));
- EXPECT_EQ(ServiceListener::STATUS_AVAILABLE, stat);
+ EXPECT_EQ(ServiceListener::STATUS_PRESENT, stat);
EXPECT_OK(ProCamera::removeServiceListener(listener));
}
diff --git a/include/camera/ICameraServiceListener.h b/include/camera/ICameraServiceListener.h
index 88860dd..f2a11c2 100644
--- a/include/camera/ICameraServiceListener.h
+++ b/include/camera/ICameraServiceListener.h
@@ -38,9 +38,8 @@
* NOT_PRESENT -> PRESENT
* NOT_PRESENT -> ENUMERATING
* ENUMERATING -> PRESENT
- * PRESENT -> AVAILABLE
- * AVAILABLE -> NOT_AVAILABLE
- * NOT_AVAILABLE -> AVAILABLE
+ * PRESENT -> NOT_AVAILABLE
+ * NOT_AVAILABLE -> PRESENT
*
* A state will never immediately transition back to itself.
*/
@@ -48,15 +47,17 @@
// Device physically unplugged
STATUS_NOT_PRESENT = CAMERA_DEVICE_STATUS_NOT_PRESENT,
// Device physically has been plugged in
+ // and the camera can be used exlusively
STATUS_PRESENT = CAMERA_DEVICE_STATUS_PRESENT,
// Device physically has been plugged in
// but it will not be connect-able until enumeration is complete
STATUS_ENUMERATING = CAMERA_DEVICE_STATUS_ENUMERATING,
// Camera can be used exclusively
- STATUS_AVAILABLE = 0x80000000,
+ STATUS_AVAILABLE = STATUS_PRESENT, // deprecated, will be removed
+
// Camera is in use by another app and cannot be used exclusively
- STATUS_NOT_AVAILABLE,
+ STATUS_NOT_AVAILABLE = 0x80000000,
// Use to initialize variables only
STATUS_UNKNOWN = 0xFFFFFFFF,
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index 0529bcd..2183fbe 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -271,6 +271,7 @@
float mVolume; // Volume applied to audio track
audio_stream_type_t mStreamType; // Audio stream used for output
unsigned int mProcessSize; // Size of audio blocks generated at a time by audioCallback() (in PCM frames).
+ struct timespec mStartTime; // tone start time: needed to guaranty actual tone duration
bool initAudioTrack();
static void audioCallback(int event, void* user, void *info);
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 58d495e..9ea3ea7 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -922,6 +922,9 @@
ALOGV("Immediate start, time %d", (unsigned int)(systemTime()/1000000));
lResult = true;
mState = TONE_STARTING;
+ if (clock_gettime(CLOCK_MONOTONIC, &mStartTime) != 0) {
+ mStartTime.tv_sec = 0;
+ }
mLock.unlock();
mpAudioTrack->start();
mLock.lock();
@@ -940,6 +943,7 @@
} else {
ALOGV("Delayed start");
mState = TONE_RESTARTING;
+ mStartTime.tv_sec = 0;
lStatus = mWaitCbkCond.waitRelative(mLock, seconds(3));
if (lStatus == NO_ERROR) {
if (mState != TONE_IDLE) {
@@ -976,21 +980,49 @@
ALOGV("stopTone");
mLock.lock();
- if (mState == TONE_PLAYING || mState == TONE_STARTING || mState == TONE_RESTARTING) {
- mState = TONE_STOPPING;
+ if (mState != TONE_IDLE && mState != TONE_INIT) {
+ if (mState == TONE_PLAYING || mState == TONE_STARTING || mState == TONE_RESTARTING) {
+ struct timespec stopTime;
+ // If the start time is valid, make sure that the number of audio samples produced
+ // corresponds at least to the time between the start and stop commands.
+ // This is needed in case of cold start of the output stream.
+ if ((mStartTime. tv_sec != 0) && (clock_gettime(CLOCK_MONOTONIC, &stopTime) == 0)) {
+ time_t sec = stopTime.tv_sec - mStartTime.tv_sec;
+ long nsec = stopTime.tv_nsec - mStartTime.tv_nsec;
+ long durationMs;
+ if (nsec < 0) {
+ --sec;
+ nsec += 1000000000;
+ }
+
+ if ((sec + 1) > ((long)(INT_MAX / mSamplingRate))) {
+ mMaxSmp = sec * mSamplingRate;
+ } else {
+ // mSamplingRate is always > 1000
+ sec = sec * 1000 + nsec / 1000000; // duration in milliseconds
+ mMaxSmp = (sec * mSamplingRate) / 1000;
+ }
+ ALOGV("stopTone() forcing mMaxSmp to %d, total for far %d", mMaxSmp, mTotalSmp);
+ } else {
+ mState = TONE_STOPPING;
+ }
+ }
ALOGV("waiting cond");
status_t lStatus = mWaitCbkCond.waitRelative(mLock, seconds(3));
if (lStatus == NO_ERROR) {
+ // If the tone was restarted exit now before calling clearWaveGens();
+ if (mState != TONE_INIT) {
+ return;
+ }
ALOGV("track stop complete, time %d", (unsigned int)(systemTime()/1000000));
} else {
ALOGE("--- Stop timed out");
mState = TONE_IDLE;
mpAudioTrack->stop();
}
+ clearWaveGens();
}
- clearWaveGens();
-
mLock.unlock();
}
@@ -1258,6 +1290,9 @@
ALOGV("Cbk restarting track");
if (lpToneGen->prepareWave()) {
lpToneGen->mState = TONE_STARTING;
+ if (clock_gettime(CLOCK_MONOTONIC, &lpToneGen->mStartTime) != 0) {
+ lpToneGen->mStartTime.tv_sec = 0;
+ }
// must reload lpToneDesc as prepareWave() may change mpToneDesc
lpToneDesc = lpToneGen->mpToneDesc;
} else {
@@ -1299,7 +1334,7 @@
}
if (lSignal)
- lpToneGen->mWaitCbkCond.signal();
+ lpToneGen->mWaitCbkCond.broadcast();
lpToneGen->mLock.unlock();
}
}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 5a6a3c8..2db5224 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -66,6 +66,20 @@
return IPCThreadState::self()->getCallingUid();
}
+extern "C" {
+static void camera_device_status_change(
+ const struct camera_module_callbacks* callbacks,
+ int camera_id,
+ int new_status) {
+ sp<CameraService> cs = const_cast<CameraService*>(
+ static_cast<const CameraService*>(callbacks));
+
+ cs->onDeviceStatusChanged(
+ camera_id,
+ new_status);
+}
+} // extern "C"
+
// ----------------------------------------------------------------------------
// This is ugly and only safe if we never re-create the CameraService, but
@@ -79,8 +93,10 @@
gCameraService = this;
for (size_t i = 0; i < MAX_CAMERAS; ++i) {
- mStatusList[i] = ICameraServiceListener::STATUS_AVAILABLE;
+ mStatusList[i] = ICameraServiceListener::STATUS_PRESENT;
}
+
+ this->camera_device_status_change = android::camera_device_status_change;
}
void CameraService::onFirstRef()
@@ -105,6 +121,11 @@
for (int i = 0; i < mNumberOfCameras; i++) {
setCameraFree(i);
}
+
+ if (mModule->common.module_api_version >=
+ CAMERA_MODULE_API_VERSION_2_1) {
+ mModule->set_callbacks(this);
+ }
}
}
@@ -118,6 +139,67 @@
gCameraService = NULL;
}
+void CameraService::onDeviceStatusChanged(int cameraId,
+ int newStatus)
+{
+ ALOGI("%s: Status changed for cameraId=%d, newStatus=%d", __FUNCTION__,
+ cameraId, newStatus);
+
+ if (cameraId < 0 || cameraId >= MAX_CAMERAS) {
+ ALOGE("%s: Bad camera ID %d", __FUNCTION__, cameraId);
+ return;
+ }
+
+ if ((int)getStatus(cameraId) == newStatus) {
+ ALOGE("%s: State transition to the same status 0x%x not allowed",
+ __FUNCTION__, (uint32_t)newStatus);
+ return;
+ }
+
+ /* don't do this in updateStatus
+ since it is also called from connect and we could get into a deadlock */
+ if (newStatus == CAMERA_DEVICE_STATUS_NOT_PRESENT) {
+ Vector<sp<BasicClient> > clientsToDisconnect;
+ {
+ Mutex::Autolock al(mServiceLock);
+
+ /* Find all clients that we need to disconnect */
+ sp<Client> client = mClient[cameraId].promote();
+ if (client.get() != NULL) {
+ clientsToDisconnect.push_back(client);
+ }
+
+ int i = cameraId;
+ for (size_t j = 0; j < mProClientList[i].size(); ++j) {
+ sp<ProClient> cl = mProClientList[i][j].promote();
+ if (cl != NULL) {
+ clientsToDisconnect.push_back(cl);
+ }
+ }
+ }
+
+ /* now disconnect them. don't hold the lock
+ or we can get into a deadlock */
+
+ for (size_t i = 0; i < clientsToDisconnect.size(); ++i) {
+ sp<BasicClient> client = clientsToDisconnect[i];
+
+ client->disconnect();
+ /**
+ * The remote app will no longer be able to call methods on the
+ * client since the client PID will be reset to 0
+ */
+ }
+
+ ALOGV("%s: After unplug, disconnected %d clients",
+ __FUNCTION__, clientsToDisconnect.size());
+ }
+
+ updateStatus(
+ static_cast<ICameraServiceListener::Status>(newStatus), cameraId);
+
+}
+
int32_t CameraService::getNumberOfCameras() {
return mNumberOfCameras;
}
@@ -212,6 +294,19 @@
return false;
}
+ ICameraServiceListener::Status currentStatus = getStatus(cameraId);
+ if (currentStatus == ICameraServiceListener::STATUS_NOT_PRESENT) {
+ ALOGI("Camera is not plugged in,"
+ " connect X (pid %d) rejected", callingPid);
+ return false;
+ } else if (currentStatus == ICameraServiceListener::STATUS_ENUMERATING) {
+ ALOGI("Camera is enumerating,"
+ " connect X (pid %d) rejected", callingPid);
+ return false;
+ }
+ // Else don't check for STATUS_NOT_AVAILABLE.
+ // -- It's done implicitly in canConnectUnsafe /w the mBusy array
+
return true;
}
@@ -293,6 +388,7 @@
// If there are other non-exclusive users of the camera,
// this will tear them down before we can reuse the camera
if (isValidCameraId(cameraId)) {
+ // transition from PRESENT -> NOT_AVAILABLE
updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,
cameraId);
}
@@ -321,7 +417,8 @@
if (!connectFinishUnsafe(client, client->asBinder())) {
// this is probably not recoverable.. maybe the client can try again
- updateStatus(ICameraServiceListener::STATUS_AVAILABLE, cameraId);
+ // OK: we can only get here if we were originally in PRESENT state
+ updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);
return NULL;
}
@@ -429,6 +526,15 @@
mListenerList.push_back(listener);
+ /* Immediately signal current status to this listener only */
+ {
+ Mutex::Autolock m(mStatusMutex) ;
+ int numCams = getNumberOfCameras();
+ for (int i = 0; i < numCams; ++i) {
+ listener->onStatusChanged(mStatusList[i], i);
+ }
+ }
+
return OK;
}
status_t CameraService::removeListener(
@@ -719,6 +825,8 @@
void CameraService::BasicClient::disconnect() {
mCameraService->removeClientByRemote(mRemoteBinder);
+ // client shouldn't be able to call into us anymore
+ mClientPid = 0;
}
status_t CameraService::BasicClient::startCameraOps() {
@@ -816,7 +924,7 @@
void CameraService::Client::disconnect() {
BasicClient::disconnect();
mCameraService->setCameraFree(mCameraId);
- mCameraService->updateStatus(ICameraServiceListener::STATUS_AVAILABLE,
+ mCameraService->updateStatus(ICameraServiceListener::STATUS_PRESENT,
mCameraId);
}
@@ -1017,6 +1125,16 @@
ALOGV("%s: Status has changed for camera ID %d from 0x%x to 0x%x",
__FUNCTION__, cameraId, (uint32_t)oldStatus, (uint32_t)status);
+ if (oldStatus == ICameraServiceListener::STATUS_NOT_PRESENT &&
+ (status != ICameraServiceListener::STATUS_PRESENT &&
+ status != ICameraServiceListener::STATUS_ENUMERATING)) {
+
+ ALOGW("%s: From NOT_PRESENT can only transition into PRESENT"
+ " or ENUMERATING", __FUNCTION__);
+ mStatusList[cameraId] = oldStatus;
+ return;
+ }
+
/**
* ProClients lose their exclusive lock.
* - Done before the CameraClient can initialize the HAL device,
@@ -1041,4 +1159,14 @@
}
}
+ICameraServiceListener::Status CameraService::getStatus(int cameraId) const {
+ if (cameraId < 0 || cameraId >= MAX_CAMERAS) {
+ ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId);
+ return ICameraServiceListener::STATUS_UNKNOWN;
+ }
+
+ Mutex::Autolock al(mStatusMutex);
+ return mStatusList[cameraId];
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index c5e495f..8cb1691 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -45,7 +45,8 @@
class CameraService :
public BinderService<CameraService>,
public BnCameraService,
- public IBinder::DeathRecipient
+ public IBinder::DeathRecipient,
+ public camera_module_callbacks_t
{
friend class BinderService<CameraService>;
public:
@@ -59,6 +60,11 @@
virtual ~CameraService();
/////////////////////////////////////////////////////////////////////
+ // HAL Callbacks
+ virtual void onDeviceStatusChanged(int cameraId,
+ int newStatus);
+
+ /////////////////////////////////////////////////////////////////////
// ICameraService
virtual int32_t getNumberOfCameras();
virtual status_t getCameraInfo(int cameraId,
@@ -327,10 +333,14 @@
mListenerList;
// guard only mStatusList and the broadcasting of ICameraServiceListener
- Mutex mStatusMutex;
+ mutable Mutex mStatusMutex;
ICameraServiceListener::Status
mStatusList[MAX_CAMERAS];
+ // Read the current status (locks mStatusMutex)
+ ICameraServiceListener::Status
+ getStatus(int cameraId) const;
+
// Broadcast the new status if it changed (locks the service mutex)
void updateStatus(
ICameraServiceListener::Status status,