diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 20 | ||||
-rw-r--r-- | services/audioflinger/Threads.cpp | 59 | ||||
-rw-r--r-- | services/audioflinger/Threads.h | 4 | ||||
-rw-r--r-- | services/audioflinger/Tracks.cpp | 4 | ||||
-rw-r--r-- | services/camera/libcameraservice/api2/CameraDeviceClient.cpp | 80 | ||||
-rw-r--r-- | services/camera/libcameraservice/api2/CameraDeviceClient.h | 3 |
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 */ |