Merge "ToneGenerator: fix stop/destroy concurrency" into 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/media/libstagefright/wifi-display/source/Converter.cpp b/media/libstagefright/wifi-display/source/Converter.cpp
index d41e1e6..0a8462c 100644
--- a/media/libstagefright/wifi-display/source/Converter.cpp
+++ b/media/libstagefright/wifi-display/source/Converter.cpp
@@ -135,7 +135,9 @@
return mNeedToManuallyPrependSPSPPS;
}
-static int32_t getBitrate(const char *propName, int32_t defaultValue) {
+// static
+int32_t Converter::GetInt32Property(
+ const char *propName, int32_t defaultValue) {
char val[PROPERTY_VALUE_MAX];
if (property_get(propName, val, NULL)) {
char *end;
@@ -185,8 +187,8 @@
mOutputFormat->setString("mime", outputMIME.c_str());
- int32_t audioBitrate = getBitrate("media.wfd.audio-bitrate", 128000);
- int32_t videoBitrate = getBitrate("media.wfd.video-bitrate", 5000000);
+ int32_t audioBitrate = GetInt32Property("media.wfd.audio-bitrate", 128000);
+ int32_t videoBitrate = GetInt32Property("media.wfd.video-bitrate", 5000000);
mPrevVideoBitrate = videoBitrate;
ALOGI("using audio bitrate of %d bps, video bitrate of %d bps",
@@ -622,20 +624,6 @@
}
status_t Converter::doMoreWork() {
-#if 0
- if (mIsVideo) {
- int32_t videoBitrate = getBitrate("media.wfd.video-bitrate", 5000000);
- if (videoBitrate != mPrevVideoBitrate) {
- sp<AMessage> params = new AMessage;
-
- params->setInt32("videoBitrate", videoBitrate);
- mEncoder->setParameters(params);
-
- mPrevVideoBitrate = videoBitrate;
- }
- }
-#endif
-
status_t err;
for (;;) {
diff --git a/media/libstagefright/wifi-display/source/Converter.h b/media/libstagefright/wifi-display/source/Converter.h
index 538f10a..ba297c4 100644
--- a/media/libstagefright/wifi-display/source/Converter.h
+++ b/media/libstagefright/wifi-display/source/Converter.h
@@ -73,6 +73,8 @@
int32_t getVideoBitrate() const;
void setVideoBitrate(int32_t bitrate);
+ static int32_t GetInt32Property(const char *propName, int32_t defaultValue);
+
protected:
virtual ~Converter();
virtual void onMessageReceived(const sp<AMessage> &msg);
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index 68aa9cb..715d0b5 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -27,6 +27,7 @@
#include "WifiDisplaySource.h"
#include <binder/IServiceManager.h>
+#include <cutils/properties.h>
#include <media/IHDCP.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -66,6 +67,7 @@
bool isAudio() const;
const sp<Converter> &converter() const;
+ const sp<RepeaterSource> &repeaterSource() const;
ssize_t mediaSenderTrackIndex() const;
void setMediaSenderTrackIndex(size_t index);
@@ -171,6 +173,11 @@
return mConverter;
}
+const sp<RepeaterSource> &
+WifiDisplaySource::PlaybackSession::Track::repeaterSource() const {
+ return mRepeaterSource;
+}
+
ssize_t WifiDisplaySource::PlaybackSession::Track::mediaSenderTrackIndex() const {
CHECK_GE(mMediaSenderTrackIndex, 0);
return mMediaSenderTrackIndex;
@@ -663,27 +670,67 @@
if (mVideoTrackIndex >= 0) {
const sp<Track> &videoTrack = mTracks.valueFor(mVideoTrackIndex);
sp<Converter> converter = videoTrack->converter();
+
if (converter != NULL) {
- int32_t videoBitrate = converter->getVideoBitrate();
+ int32_t videoBitrate =
+ Converter::GetInt32Property("media.wfd.video-bitrate", -1);
- if (avgLatencyUs > 300000ll) {
- videoBitrate *= 0.6;
+ char val[PROPERTY_VALUE_MAX];
+ if (videoBitrate < 0
+ && property_get("media.wfd.video-bitrate", val, NULL)
+ && !strcasecmp("adaptive", val)) {
+ videoBitrate = converter->getVideoBitrate();
- if (videoBitrate < 500000) {
- videoBitrate = 500000; // cap at 500kbit/sec
- }
- } else if (avgLatencyUs < 100000ll) {
- videoBitrate *= 1.1;
-
- if (videoBitrate > 10000000) {
- videoBitrate = 10000000; // cap at 10Mbit/sec
+ if (avgLatencyUs > 300000ll) {
+ videoBitrate *= 0.6;
+ } else if (avgLatencyUs < 100000ll) {
+ videoBitrate *= 1.1;
}
}
- if (videoBitrate != converter->getVideoBitrate()) {
- ALOGI("setting video bitrate to %d bps", videoBitrate);
+ if (videoBitrate > 0) {
+ if (videoBitrate < 500000) {
+ videoBitrate = 500000;
+ } else if (videoBitrate > 10000000) {
+ videoBitrate = 10000000;
+ }
- converter->setVideoBitrate(videoBitrate);
+ if (videoBitrate != converter->getVideoBitrate()) {
+ ALOGI("setting video bitrate to %d bps", videoBitrate);
+
+ converter->setVideoBitrate(videoBitrate);
+ }
+ }
+ }
+
+ sp<RepeaterSource> repeaterSource = videoTrack->repeaterSource();
+ if (repeaterSource != NULL) {
+ double rateHz =
+ Converter::GetInt32Property(
+ "media.wfd.video-framerate", -1);
+
+ if (rateHz < 0.0) {
+ rateHz = repeaterSource->getFrameRate();
+
+ if (avgLatencyUs > 300000ll) {
+ rateHz *= 0.9;
+ } else if (avgLatencyUs < 200000ll) {
+ rateHz *= 1.1;
+ }
+ }
+
+ if (rateHz > 0) {
+ if (rateHz < 5.0) {
+ rateHz = 5.0;
+ } else if (rateHz > 30.0) {
+ rateHz = 30.0;
+ }
+
+ if (rateHz != repeaterSource->getFrameRate()) {
+ ALOGI("setting frame rate to %.2f Hz", rateHz);
+
+ repeaterSource->setFrameRate(rateHz);
+ }
}
}
}
diff --git a/media/libstagefright/wifi-display/source/RepeaterSource.cpp b/media/libstagefright/wifi-display/source/RepeaterSource.cpp
index 72be927..cc8dee3 100644
--- a/media/libstagefright/wifi-display/source/RepeaterSource.cpp
+++ b/media/libstagefright/wifi-display/source/RepeaterSource.cpp
@@ -27,6 +27,25 @@
CHECK(!mStarted);
}
+double RepeaterSource::getFrameRate() const {
+ return mRateHz;
+}
+
+void RepeaterSource::setFrameRate(double rateHz) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (rateHz == mRateHz) {
+ return;
+ }
+
+ if (mStartTimeUs >= 0ll) {
+ int64_t nextTimeUs = mStartTimeUs + (mFrameCount * 1000000ll) / mRateHz;
+ mStartTimeUs = nextTimeUs;
+ mFrameCount = 0;
+ }
+ mRateHz = rateHz;
+}
+
status_t RepeaterSource::start(MetaData *params) {
CHECK(!mStarted);
diff --git a/media/libstagefright/wifi-display/source/RepeaterSource.h b/media/libstagefright/wifi-display/source/RepeaterSource.h
index 146af32..8d414fd 100644
--- a/media/libstagefright/wifi-display/source/RepeaterSource.h
+++ b/media/libstagefright/wifi-display/source/RepeaterSource.h
@@ -28,6 +28,9 @@
// send updates in a while, this is its wakeup call.
void wakeUp();
+ double getFrameRate() const;
+ void setFrameRate(double rateHz);
+
protected:
virtual ~RepeaterSource();
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,
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index 2332b3e..f60749d 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -19,6 +19,7 @@
#include <sys/mman.h>
#include <utils/Log.h>
+#include <binder/PermissionCache.h>
#include <media/nbaio/NBLog.h>
#include <private/android_filesystem_config.h>
#include "MediaLogService.h"
@@ -55,6 +56,14 @@
status_t MediaLogService::dump(int fd, const Vector<String16>& args)
{
+ // FIXME merge with similar but not identical code at services/audioflinger/ServiceUtilities.cpp
+ static const String16 sDump("android.permission.DUMP");
+ if (!(IPCThreadState::self()->getCallingUid() == AID_MEDIA ||
+ PermissionCache::checkCallingPermission(sDump))) {
+ fdprintf(fd, "Permission denied.\n");
+ return NO_ERROR;
+ }
+
Vector<NamedReader> namedReaders;
{
Mutex::Autolock _l(mLock);