summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/AudioFlinger.cpp20
-rw-r--r--services/audioflinger/Threads.cpp59
-rw-r--r--services/audioflinger/Threads.h4
-rw-r--r--services/audioflinger/Tracks.cpp4
-rw-r--r--services/camera/libcameraservice/api2/CameraDeviceClient.cpp80
-rw-r--r--services/camera/libcameraservice/api2/CameraDeviceClient.h3
6 files changed, 139 insertions, 31 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 8fbac42..f6e4c6a 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -264,6 +264,12 @@ void AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
}
}
+ result.append("Notification Clients:\n");
+ for (size_t i = 0; i < mNotificationClients.size(); ++i) {
+ snprintf(buffer, SIZE, " pid: %d\n", mNotificationClients.keyAt(i));
+ result.append(buffer);
+ }
+
result.append("Global session refs:\n");
result.append(" session pid count\n");
for (size_t i = 0; i < mAudioSessionRefs.size(); i++) {
@@ -1850,6 +1856,16 @@ void AudioFlinger::acquireAudioSessionId(int audioSession)
Mutex::Autolock _l(mLock);
pid_t caller = IPCThreadState::self()->getCallingPid();
ALOGV("acquiring %d from %d", audioSession, caller);
+
+ // Ignore requests received from processes not known as notification client. The request
+ // is likely proxied by mediaserver (e.g CameraService) and releaseAudioSessionId() can be
+ // called from a different pid leaving a stale session reference. Also we don't know how
+ // to clear this reference if the client process dies.
+ if (mNotificationClients.indexOfKey(caller) < 0) {
+ ALOGV("acquireAudioSessionId() unknown client %d for session %d", caller, audioSession);
+ return;
+ }
+
size_t num = mAudioSessionRefs.size();
for (size_t i = 0; i< num; i++) {
AudioSessionRef *ref = mAudioSessionRefs.editItemAt(i);
@@ -1882,7 +1898,9 @@ void AudioFlinger::releaseAudioSessionId(int audioSession)
return;
}
}
- ALOGW("session id %d not found for pid %d", audioSession, caller);
+ // If the caller is mediaserver it is likely that the session being released was acquired
+ // on behalf of a process not in notification clients and we ignore the warning.
+ ALOGW_IF(caller != getpid_cached, "session id %d not found for pid %d", audioSession, caller);
}
void AudioFlinger::purgeStaleEffects_l() {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 242e020..5f36cab 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -960,6 +960,7 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge
mUseAsyncWrite(false),
mWriteAckSequence(0),
mDrainSequence(0),
+ mSignalPending(false),
mScreenState(AudioFlinger::mScreenState),
// index 0 is reserved for normal mixer's submix
mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1),
@@ -1348,14 +1349,14 @@ void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, f
{
Mutex::Autolock _l(mLock);
mStreamTypes[stream].volume = value;
- signal_l();
+ broadcast_l();
}
void AudioFlinger::PlaybackThread::setStreamMute(audio_stream_type_t stream, bool muted)
{
Mutex::Autolock _l(mLock);
mStreamTypes[stream].mute = muted;
- signal_l();
+ broadcast_l();
}
float AudioFlinger::PlaybackThread::streamVolume(audio_stream_type_t stream) const
@@ -1413,8 +1414,8 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
status = NO_ERROR;
}
- ALOGV("mWaitWorkCV.broadcast");
- mWaitWorkCV.broadcast();
+ ALOGV("signal playback thread");
+ broadcast_l();
return status;
}
@@ -1455,14 +1456,14 @@ void AudioFlinger::PlaybackThread::removeTrack_l(const sp<Track>& track)
}
}
-void AudioFlinger::PlaybackThread::signal_l()
+void AudioFlinger::PlaybackThread::broadcast_l()
{
// Thread could be blocked waiting for async
// so signal it to handle state changes immediately
// If threadLoop is currently unlocked a signal of mWaitWorkCV will
// be lost so we also flag to prevent it blocking on mWaitWorkCV
mSignalPending = true;
- mWaitWorkCV.signal();
+ mWaitWorkCV.broadcast();
}
String8 AudioFlinger::PlaybackThread::getParameters(const String8& keys)
@@ -2143,7 +2144,6 @@ bool AudioFlinger::PlaybackThread::threadLoop()
}
saveOutputTracks();
-
if (mSignalPending) {
// A signal was raised while we were unlocked
mSignalPending = false;
@@ -2158,10 +2158,10 @@ bool AudioFlinger::PlaybackThread::threadLoop()
acquireWakeLock_l();
standbyTime = systemTime() + standbyDelay;
sleepTime = 0;
- if (exitPending()) {
- break;
- }
- } else if ((!mActiveTracks.size() && systemTime() > standbyTime) ||
+
+ continue;
+ }
+ if ((!mActiveTracks.size() && systemTime() > standbyTime) ||
isSuspended()) {
// put audio hardware into standby after short delay
if (shouldStandby_l()) {
@@ -2203,7 +2203,6 @@ bool AudioFlinger::PlaybackThread::threadLoop()
continue;
}
}
-
// mMixerStatusIgnoringFastTracks is also updated internally
mMixerStatus = prepareTracks_l(&tracksToRemove);
@@ -3871,13 +3870,14 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr
Vector< sp<Track> > *tracksToRemove
)
{
- ALOGV("OffloadThread::prepareTracks_l");
size_t count = mActiveTracks.size();
mixer_state mixerStatus = MIXER_IDLE;
bool doHwPause = false;
bool doHwResume = false;
+ ALOGV("OffloadThread::prepareTracks_l active tracks %d", count);
+
// find out which tracks need to be processed
for (size_t i = 0; i < count; i++) {
sp<Track> t = mActiveTracks[i].promote();
@@ -3931,23 +3931,27 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr
// make sure processVolume_l() will apply new volume even if 0
mLeftVolFloat = mRightVolFloat = -1.0;
if (track->mState == TrackBase::RESUMING) {
- if (mPausedBytesRemaining) {
- // Need to continue write that was interrupted
- mCurrentWriteLength = mPausedWriteLength;
- mBytesRemaining = mPausedBytesRemaining;
- mPausedBytesRemaining = 0;
- }
track->mState = TrackBase::ACTIVE;
+ if (last) {
+ if (mPausedBytesRemaining) {
+ // Need to continue write that was interrupted
+ mCurrentWriteLength = mPausedWriteLength;
+ mBytesRemaining = mPausedBytesRemaining;
+ mPausedBytesRemaining = 0;
+ }
+ if (mHwPaused) {
+ doHwResume = true;
+ mHwPaused = false;
+ // threadLoop_mix() will handle the case that we need to
+ // resume an interrupted write
+ }
+ // enable write to audio HAL
+ sleepTime = 0;
+ }
}
}
if (last) {
- if (mHwPaused) {
- doHwResume = true;
- mHwPaused = false;
- // threadLoop_mix() will handle the case that we need to
- // resume an interrupted write
- }
// reset retry count
track->mRetryCount = kMaxTrackRetriesOffload;
mActiveTrack = t;
@@ -3964,9 +3968,9 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr
// has been written
ALOGV("OffloadThread: underrun and STOPPING_1 -> draining, STOPPING_2");
track->mState = TrackBase::STOPPING_2; // so presentation completes after drain
- sleepTime = 0;
- standbyTime = systemTime() + standbyDelay;
if (last) {
+ sleepTime = 0;
+ standbyTime = systemTime() + standbyDelay;
mixerStatus = MIXER_DRAIN_TRACK;
mDrainSequence += 2;
if (mHwPaused) {
@@ -4353,6 +4357,7 @@ bool AudioFlinger::RecordThread::threadLoop()
mStandby = false;
}
}
+
lockEffectChains_l(effectChains);
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index f13cb54..443b8d7 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -528,7 +528,7 @@ private:
status_t addTrack_l(const sp<Track>& track);
bool destroyTrack_l(const sp<Track>& track);
void removeTrack_l(const sp<Track>& track);
- void signal_l();
+ void broadcast_l();
void readOutputParameters();
@@ -592,6 +592,8 @@ private:
// Bit 0 is reset by the async callback thread calling resetDraining(). Out of sequence
// callbacks are ignored.
uint32_t mDrainSequence;
+ // A condition that must be evaluated by prepareTrack_l() has changed and we must not wait
+ // for async write callback in the thread loop before evaluating it
bool mSignalPending;
sp<AsyncCallbackThread> mCallbackThread;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index ccba014..d8d325d 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -651,7 +651,7 @@ void AudioFlinger::PlaybackThread::Track::pause()
case RESUMING:
mState = PAUSING;
ALOGV("ACTIVE/RESUMING => PAUSING (%d) on thread %p", mName, thread.get());
- playbackThread->signal_l();
+ playbackThread->broadcast_l();
break;
default:
@@ -711,7 +711,7 @@ void AudioFlinger::PlaybackThread::Track::flush()
// before mixer thread can run. This is important when offloading
// because the hardware buffer could hold a large amount of audio
playbackThread->flushOutput_l();
- playbackThread->signal_l();
+ playbackThread->broadcast_l();
}
}
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 055ea12..83466cb 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -360,6 +360,26 @@ status_t CameraDeviceClient::createStream(int width, int height, int format,
ALOGV("%s: Camera %d: Successfully created a new stream ID %d",
__FUNCTION__, mCameraId, streamId);
+
+ /**
+ * Set the stream transform flags to automatically
+ * rotate the camera stream for preview use cases.
+ */
+ int32_t transform = 0;
+ res = getRotationTransformLocked(&transform);
+
+ if (res != OK) {
+ // Error logged by getRotationTransformLocked.
+ return res;
+ }
+
+ res = mDevice->setStreamTransform(streamId, transform);
+ if (res != OK) {
+ ALOGE("%s: Failed to set stream transform (stream id %d)",
+ __FUNCTION__, streamId);
+ return res;
+ }
+
return streamId;
}
@@ -560,4 +580,64 @@ bool CameraDeviceClient::enforceRequestPermissions(CameraMetadata& metadata) {
return true;
}
+status_t CameraDeviceClient::getRotationTransformLocked(int32_t* transform) {
+ ALOGV("%s: begin", __FUNCTION__);
+
+ if (transform == NULL) {
+ ALOGW("%s: null transform", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ *transform = 0;
+
+ const CameraMetadata& staticInfo = mDevice->info();
+ camera_metadata_ro_entry_t entry = staticInfo.find(ANDROID_SENSOR_ORIENTATION);
+ if (entry.count == 0) {
+ ALOGE("%s: Camera %d: Can't find android.sensor.orientation in "
+ "static metadata!", __FUNCTION__, mCameraId);
+ return INVALID_OPERATION;
+ }
+
+ int32_t& flags = *transform;
+
+ int orientation = entry.data.i32[0];
+ switch (orientation) {
+ case 0:
+ flags = 0;
+ break;
+ case 90:
+ flags = NATIVE_WINDOW_TRANSFORM_ROT_90;
+ break;
+ case 180:
+ flags = NATIVE_WINDOW_TRANSFORM_ROT_180;
+ break;
+ case 270:
+ flags = NATIVE_WINDOW_TRANSFORM_ROT_270;
+ break;
+ default:
+ ALOGE("%s: Invalid HAL android.sensor.orientation value: %d",
+ __FUNCTION__, orientation);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * This magic flag makes surfaceflinger un-rotate the buffers
+ * to counter the extra global device UI rotation whenever the user
+ * physically rotates the device.
+ *
+ * By doing this, the camera buffer always ends up aligned
+ * with the physical camera for a "see through" effect.
+ *
+ * In essence, the buffer only gets rotated during preview use-cases.
+ * The user is still responsible to re-create streams of the proper
+ * aspect ratio, or the preview will end up looking non-uniformly
+ * stretched.
+ */
+ flags |= NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
+
+ ALOGV("%s: final transform = 0x%x", __FUNCTION__, flags);
+
+ return OK;
+}
+
} // namespace android
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index c6b6336..b490924 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -120,6 +120,9 @@ protected:
const CameraMetadata& frame);
virtual void detachDevice();
+ // Calculate the ANativeWindow transform from android.sensor.orientation
+ status_t getRotationTransformLocked(/*out*/int32_t* transform);
+
private:
/** ICameraDeviceUser interface-related private members */