diff options
Diffstat (limited to 'services/audioflinger')
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 110 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 5 | ||||
-rw-r--r-- | services/audioflinger/ServiceUtilities.cpp | 7 | ||||
-rw-r--r-- | services/audioflinger/ServiceUtilities.h | 1 | ||||
-rw-r--r-- | services/audioflinger/Threads.cpp | 61 | ||||
-rw-r--r-- | services/audioflinger/Threads.h | 4 | ||||
-rw-r--r-- | services/audioflinger/Tracks.cpp | 27 |
7 files changed, 159 insertions, 56 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index c571cf5..71e6f83 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -650,6 +650,7 @@ sp<IAudioTrack> AudioFlinger::createTrack( } } + setAudioHwSyncForSession_l(thread, (audio_session_t)lSessionId); } if (lStatus != NO_ERROR) { @@ -890,6 +891,21 @@ bool AudioFlinger::masterMute_l() const return mMasterMute; } +status_t AudioFlinger::checkStreamType(audio_stream_type_t stream) const +{ + if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + ALOGW("setStreamVolume() invalid stream %d", stream); + return BAD_VALUE; + } + pid_t caller = IPCThreadState::self()->getCallingPid(); + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT && caller != getpid_cached) { + ALOGW("setStreamVolume() pid %d cannot use internal stream type %d", caller, stream); + return PERMISSION_DENIED; + } + + return NO_ERROR; +} + status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value, audio_io_handle_t output) { @@ -898,10 +914,11 @@ status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value, return PERMISSION_DENIED; } - if (uint32_t(stream) >= AUDIO_STREAM_CNT) { - ALOGE("setStreamVolume() invalid stream %d", stream); - return BAD_VALUE; + status_t status = checkStreamType(stream); + if (status != NO_ERROR) { + return status; } + ALOG_ASSERT(stream != AUDIO_STREAM_PATCH, "attempt to change AUDIO_STREAM_PATCH volume"); AutoMutex lock(mLock); PlaybackThread *thread = NULL; @@ -932,8 +949,13 @@ status_t AudioFlinger::setStreamMute(audio_stream_type_t stream, bool muted) return PERMISSION_DENIED; } - if (uint32_t(stream) >= AUDIO_STREAM_CNT || - uint32_t(stream) == AUDIO_STREAM_ENFORCED_AUDIBLE) { + status_t status = checkStreamType(stream); + if (status != NO_ERROR) { + return status; + } + ALOG_ASSERT(stream != AUDIO_STREAM_PATCH, "attempt to mute AUDIO_STREAM_PATCH"); + + if (uint32_t(stream) == AUDIO_STREAM_ENFORCED_AUDIBLE) { ALOGE("setStreamMute() invalid stream %d", stream); return BAD_VALUE; } @@ -948,7 +970,8 @@ status_t AudioFlinger::setStreamMute(audio_stream_type_t stream, bool muted) float AudioFlinger::streamVolume(audio_stream_type_t stream, audio_io_handle_t output) const { - if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + status_t status = checkStreamType(stream); + if (status != NO_ERROR) { return 0.0f; } @@ -969,7 +992,8 @@ float AudioFlinger::streamVolume(audio_stream_type_t stream, audio_io_handle_t o bool AudioFlinger::streamMute(audio_stream_type_t stream) const { - if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + status_t status = checkStreamType(stream); + if (status != NO_ERROR) { return true; } @@ -1604,22 +1628,69 @@ status_t AudioFlinger::setLowRamDevice(bool isLowRamDevice) audio_hw_sync_t AudioFlinger::getAudioHwSyncForSession(audio_session_t sessionId) { Mutex::Autolock _l(mLock); + + ssize_t index = mHwAvSyncIds.indexOfKey(sessionId); + if (index >= 0) { + ALOGV("getAudioHwSyncForSession found ID %d for session %d", + mHwAvSyncIds.valueAt(index), sessionId); + return mHwAvSyncIds.valueAt(index); + } + + audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice(); + if (dev == NULL) { + return AUDIO_HW_SYNC_INVALID; + } + char *reply = dev->get_parameters(dev, AUDIO_PARAMETER_HW_AV_SYNC); + AudioParameter param = AudioParameter(String8(reply)); + free(reply); + + int value; + if (param.getInt(String8(AUDIO_PARAMETER_HW_AV_SYNC), value) != NO_ERROR) { + ALOGW("getAudioHwSyncForSession error getting sync for session %d", sessionId); + return AUDIO_HW_SYNC_INVALID; + } + + // allow only one session for a given HW A/V sync ID. + for (size_t i = 0; i < mHwAvSyncIds.size(); i++) { + if (mHwAvSyncIds.valueAt(i) == (audio_hw_sync_t)value) { + ALOGV("getAudioHwSyncForSession removing ID %d for session %d", + value, mHwAvSyncIds.keyAt(i)); + mHwAvSyncIds.removeItemsAt(i); + break; + } + } + + mHwAvSyncIds.add(sessionId, value); + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { sp<PlaybackThread> thread = mPlaybackThreads.valueAt(i); - if ((thread->hasAudioSession(sessionId) & ThreadBase::TRACK_SESSION) != 0) { - // A session can only be on one thread, so exit after first match - String8 reply = thread->getParameters(String8(AUDIO_PARAMETER_STREAM_HW_AV_SYNC)); - AudioParameter param = AudioParameter(reply); - int value; - if (param.getInt(String8(AUDIO_PARAMETER_STREAM_HW_AV_SYNC), value) == NO_ERROR) { - return value; - } + uint32_t sessions = thread->hasAudioSession(sessionId); + if (sessions & PlaybackThread::TRACK_SESSION) { + AudioParameter param = AudioParameter(); + param.addInt(String8(AUDIO_PARAMETER_STREAM_HW_AV_SYNC), value); + thread->setParameters(param.toString()); break; } } - return AUDIO_HW_SYNC_INVALID; + + ALOGV("getAudioHwSyncForSession adding ID %d for session %d", value, sessionId); + return (audio_hw_sync_t)value; } +// setAudioHwSyncForSession_l() must be called with AudioFlinger::mLock held +void AudioFlinger::setAudioHwSyncForSession_l(PlaybackThread *thread, audio_session_t sessionId) +{ + ssize_t index = mHwAvSyncIds.indexOfKey(sessionId); + if (index >= 0) { + audio_hw_sync_t syncId = mHwAvSyncIds.valueAt(index); + ALOGV("setAudioHwSyncForSession_l found ID %d for session %d", syncId, sessionId); + AudioParameter param = AudioParameter(); + param.addInt(String8(AUDIO_PARAMETER_STREAM_HW_AV_SYNC), syncId); + thread->setParameters(param.toString()); + } +} + + // ---------------------------------------------------------------------------- @@ -1928,13 +1999,13 @@ sp<AudioFlinger::RecordThread> AudioFlinger::openInput_l(audio_module_handle_t m status_t status = inHwHal->open_input_stream(inHwHal, *input, device, &halconfig, &inStream, flags, address.string(), source); ALOGV("openInput_l() openInputStream returned input %p, SamplingRate %d" - ", Format %#x, Channels %x, flags %#x, status %d", + ", Format %#x, Channels %x, flags %#x, status %d addr %s", inStream, halconfig.sample_rate, halconfig.format, halconfig.channel_mask, flags, - status); + status, address.string()); // If the input could not be opened with the requested parameters and we can handle the // conversion internally, try to open again with the proposed parameters. The AudioFlinger can @@ -2585,7 +2656,8 @@ status_t AudioFlinger::moveEffectChain_l(int sessionId, // Check whether the destination thread has a channel count of FCC_2, which is // currently required for (most) effects. Prevent moving the effect chain here rather // than disabling the addEffect_l() call in dstThread below. - if (dstThread->mChannelCount != FCC_2) { + if ((dstThread->type() == ThreadBase::MIXER || dstThread->type() == ThreadBase::DUPLICATING) && + dstThread->mChannelCount != FCC_2) { ALOGW("moveEffectChain_l() effect chain failed because" " destination thread %p channel count(%u) != %u", dstThread, dstThread->mChannelCount, FCC_2); diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 1003017..aa0af1f 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -733,6 +733,8 @@ private: // Effect chains without a valid thread DefaultKeyedVector< audio_session_t , sp<EffectChain> > mOrphanEffectChains; + // list of sessions for which a valid HW A/V sync ID was retrieved from the HAL + DefaultKeyedVector< audio_session_t , audio_hw_sync_t >mHwAvSyncIds; private: sp<Client> registerPid(pid_t pid); // always returns non-0 @@ -741,6 +743,9 @@ private: void closeOutputInternal_l(sp<PlaybackThread> thread); status_t closeInput_nonvirtual(audio_io_handle_t input); void closeInputInternal_l(sp<RecordThread> thread); + void setAudioHwSyncForSession_l(PlaybackThread *thread, audio_session_t sessionId); + + status_t checkStreamType(audio_stream_type_t stream) const; #ifdef TEE_SINK // all record threads serially share a common tee sink, which is re-created on format change diff --git a/services/audioflinger/ServiceUtilities.cpp b/services/audioflinger/ServiceUtilities.cpp index 8246fef..fae19a1 100644 --- a/services/audioflinger/ServiceUtilities.cpp +++ b/services/audioflinger/ServiceUtilities.cpp @@ -50,6 +50,13 @@ bool captureHotwordAllowed() { return ok; } +bool captureFmTunerAllowed() { + static const String16 sCaptureFmTunerAllowed("android.permission.ACCESS_FM_RADIO"); + bool ok = checkCallingPermission(sCaptureFmTunerAllowed); + if (!ok) ALOGE("android.permission.ACCESS_FM_RADIO"); + return ok; +} + bool settingsAllowed() { if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true; static const String16 sAudioSettings("android.permission.MODIFY_AUDIO_SETTINGS"); diff --git a/services/audioflinger/ServiceUtilities.h b/services/audioflinger/ServiceUtilities.h index df6f6f4..ce18a90 100644 --- a/services/audioflinger/ServiceUtilities.h +++ b/services/audioflinger/ServiceUtilities.h @@ -23,6 +23,7 @@ extern pid_t getpid_cached; bool recordingAllowed(); bool captureAudioOutputAllowed(); bool captureHotwordAllowed(); +bool captureFmTunerAllowed(); bool settingsAllowed(); bool modifyAudioRoutingAllowed(); bool dumpAllowed(); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index ed8293d..b20b238 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -1224,15 +1224,12 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge readOutputParameters_l(); - // mStreamTypes[AUDIO_STREAM_CNT] is initialized by stream_type_t default constructor - // There is no AUDIO_STREAM_MIN, and ++ operator does not compile + // ++ operator does not compile for (audio_stream_type_t stream = AUDIO_STREAM_MIN; stream < AUDIO_STREAM_CNT; stream = (audio_stream_type_t) (stream + 1)) { mStreamTypes[stream].volume = mAudioFlinger->streamVolume_l(stream); mStreamTypes[stream].mute = mAudioFlinger->streamMute_l(stream); } - // mStreamTypes[AUDIO_STREAM_CNT] exists but isn't explicitly initialized here, - // because mAudioFlinger doesn't have one to copy from } AudioFlinger::PlaybackThread::~PlaybackThread() @@ -1625,13 +1622,15 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track) if (track->isExternalTrack()) { TrackBase::track_state state = track->mState; mLock.unlock(); - status = AudioSystem::startOutput(mId, track->streamType(), track->sessionId()); + status = AudioSystem::startOutput(mId, track->streamType(), + (audio_session_t)track->sessionId()); mLock.lock(); // abort track was stopped/paused while we released the lock if (state != track->mState) { if (status == NO_ERROR) { mLock.unlock(); - AudioSystem::stopOutput(mId, track->streamType(), track->sessionId()); + AudioSystem::stopOutput(mId, track->streamType(), + (audio_session_t)track->sessionId()); mLock.lock(); } return INVALID_OPERATION; @@ -2060,13 +2059,15 @@ void AudioFlinger::PlaybackThread::threadLoop_removeTracks( for (size_t i = 0 ; i < count ; i++) { const sp<Track>& track = tracksToRemove.itemAt(i); if (track->isExternalTrack()) { - AudioSystem::stopOutput(mId, track->streamType(), track->sessionId()); + AudioSystem::stopOutput(mId, track->streamType(), + (audio_session_t)track->sessionId()); #ifdef ADD_BATTERY_DATA // to track the speaker usage addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStop); #endif if (track->isTerminated()) { - AudioSystem::releaseOutput(mId); + AudioSystem::releaseOutput(mId, track->streamType(), + (audio_session_t)track->sessionId()); } } } @@ -2179,7 +2180,13 @@ void AudioFlinger::PlaybackThread::threadLoop_drain() void AudioFlinger::PlaybackThread::threadLoop_exit() { - // Default implementation has nothing to do + { + Mutex::Autolock _l(mLock); + for (size_t i = 0; i < mTracks.size(); i++) { + sp<Track> track = mTracks[i]; + track->invalidate(); + } + } } /* @@ -2687,7 +2694,8 @@ status_t AudioFlinger::PlaybackThread::getTimestamp_l(AudioTimestamp& timestamp) if (mNormalSink != 0) { return mNormalSink->getTimestamp(timestamp); } - if ((mType == OFFLOAD || mType == DIRECT) && mOutput->stream->get_presentation_position) { + if ((mType == OFFLOAD || mType == DIRECT) + && mOutput != NULL && mOutput->stream->get_presentation_position) { uint64_t position64; int ret = mOutput->stream->get_presentation_position( mOutput->stream, &position64, ×tamp.mTime); @@ -4001,9 +4009,14 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep bool last = l.get() == track; // The first time a track is added we wait - // for all its buffers to be filled before processing it + // for all its buffers to be filled before processing it. + // Allow draining the buffer in case the client + // app does not call stop() and relies on underrun to stop: + // hence the test on (track->mRetryCount > 1). + // If retryCount<=1 then track is about to underrun and be removed. uint32_t minFrames; - if ((track->sharedBuffer() == 0) && !track->isStopping_1() && !track->isPausing()) { + if ((track->sharedBuffer() == 0) && !track->isStopping_1() && !track->isPausing() + && (track->mRetryCount > 1)) { minFrames = mNormalFrameCount; } else { minFrames = 1; @@ -4660,7 +4673,11 @@ void AudioFlinger::DuplicatingThread::threadLoop_mix() if (outputsReady(outputTracks)) { mAudioMixer->process(AudioBufferProvider::kInvalidPTS); } else { - memset(mSinkBuffer, 0, mSinkBufferSize); + if (mMixerBufferValid) { + memset(mMixerBuffer, 0, mMixerBufferSize); + } else { + memset(mSinkBuffer, 0, mSinkBufferSize); + } } sleepTime = 0; writeFrames = mNormalFrameCount; @@ -4690,15 +4707,15 @@ void AudioFlinger::DuplicatingThread::threadLoop_sleepTime() ssize_t AudioFlinger::DuplicatingThread::threadLoop_write() { + // We convert the duplicating thread format to AUDIO_FORMAT_PCM_16_BIT + // for delivery downstream as needed. This in-place conversion is safe as + // AUDIO_FORMAT_PCM_16_BIT is smaller than any other supported format + // (AUDIO_FORMAT_PCM_8_BIT is not allowed here). + if (mFormat != AUDIO_FORMAT_PCM_16_BIT) { + memcpy_by_audio_format(mSinkBuffer, AUDIO_FORMAT_PCM_16_BIT, + mSinkBuffer, mFormat, writeFrames * mChannelCount); + } for (size_t i = 0; i < outputTracks.size(); i++) { - // We convert the duplicating thread format to AUDIO_FORMAT_PCM_16_BIT - // for delivery downstream as needed. This in-place conversion is safe as - // AUDIO_FORMAT_PCM_16_BIT is smaller than any other supported format - // (AUDIO_FORMAT_PCM_8_BIT is not allowed here). - if (mFormat != AUDIO_FORMAT_PCM_16_BIT) { - memcpy_by_audio_format(mSinkBuffer, AUDIO_FORMAT_PCM_16_BIT, - mSinkBuffer, mFormat, writeFrames * mChannelCount); - } outputTracks[i]->write(reinterpret_cast<int16_t*>(mSinkBuffer), writeFrames); } mStandby = false; @@ -4742,7 +4759,7 @@ void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread) frameCount, IPCThreadState::self()->getCallingUid()); if (outputTrack->cblk() != NULL) { - thread->setStreamVolume(AUDIO_STREAM_CNT, 1.0f); + thread->setStreamVolume(AUDIO_STREAM_PATCH, 1.0f); mOutputTracks.add(outputTrack); ALOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread); updateWaitTime_l(); diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index bb9aa18..119e495 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -727,9 +727,7 @@ private: void dumpTracks(int fd, const Vector<String16>& args); SortedVector< sp<Track> > mTracks; - // mStreamTypes[] uses 1 additional stream type internally for the OutputTrack used by - // DuplicatingThread - stream_type_t mStreamTypes[AUDIO_STREAM_CNT + 1]; + stream_type_t mStreamTypes[AUDIO_STREAM_CNT]; AudioStreamOut *mOutput; float mMasterVolume; diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index b9308fa..fcbf8f8 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -491,7 +491,7 @@ void AudioFlinger::PlaybackThread::Track::destroy() wasActive = playbackThread->destroyTrack_l(this); } if (isExternalTrack() && !wasActive) { - AudioSystem::releaseOutput(mThreadIoHandle); + AudioSystem::releaseOutput(mThreadIoHandle, mStreamType, (audio_session_t)mSessionId); } } } @@ -611,15 +611,16 @@ status_t AudioFlinger::PlaybackThread::Track::getNextBuffer( // ExtendedAudioBufferProvider interface -// Note that framesReady() takes a mutex on the control block using tryLock(). -// This could result in priority inversion if framesReady() is called by the normal mixer, -// as the normal mixer thread runs at lower -// priority than the client's callback thread: there is a short window within framesReady() -// during which the normal mixer could be preempted, and the client callback would block. -// Another problem can occur if framesReady() is called by the fast mixer: -// the tryLock() could block for up to 1 ms, and a sequence of these could delay fast mixer. -// FIXME Replace AudioTrackShared control block implementation by a non-blocking FIFO queue. +// framesReady() may return an approximation of the number of frames if called +// from a different thread than the one calling Proxy->obtainBuffer() and +// Proxy->releaseBuffer(). Also note there is no mutual exclusion in the +// AudioTrackServerProxy so be especially careful calling with FastTracks. size_t AudioFlinger::PlaybackThread::Track::framesReady() const { + if (mSharedBuffer != 0 && (isStopped() || isStopping())) { + // Static tracks return zero frames immediately upon stopping (for FastTracks). + // The remainder of the buffer is not drained. + return 0; + } return mAudioTrackServerProxy->framesReady(); } @@ -1656,8 +1657,9 @@ AudioFlinger::PlaybackThread::OutputTrack::OutputTrack( audio_channel_mask_t channelMask, size_t frameCount, int uid) - : Track(playbackThread, NULL, AUDIO_STREAM_CNT, sampleRate, format, channelMask, frameCount, - NULL, 0, 0, uid, IAudioFlinger::TRACK_DEFAULT, TYPE_OUTPUT), + : Track(playbackThread, NULL, AUDIO_STREAM_PATCH, + sampleRate, format, channelMask, frameCount, + NULL, 0, 0, uid, IAudioFlinger::TRACK_DEFAULT, TYPE_OUTPUT), mActive(false), mSourceThread(sourceThread), mClientProxy(NULL) { @@ -1872,7 +1874,8 @@ AudioFlinger::PlaybackThread::PatchTrack::PatchTrack(PlaybackThread *playbackThr size_t frameCount, void *buffer, IAudioFlinger::track_flags_t flags) - : Track(playbackThread, NULL, AUDIO_STREAM_CNT, sampleRate, format, channelMask, frameCount, + : Track(playbackThread, NULL, AUDIO_STREAM_PATCH, + sampleRate, format, channelMask, frameCount, buffer, 0, 0, getuid(), flags, TYPE_PATCH), mProxy(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true)) { |