diff options
Diffstat (limited to 'services/audioflinger')
-rw-r--r-- | services/audioflinger/Android.mk | 2 | ||||
-rw-r--r-- | services/audioflinger/AudioBufferProviderSource.cpp | 14 | ||||
-rw-r--r-- | services/audioflinger/AudioBufferProviderSource.h | 5 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 1033 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 351 | ||||
-rw-r--r-- | services/audioflinger/AudioMixer.cpp | 2 | ||||
-rw-r--r-- | services/audioflinger/AudioPolicyService.cpp | 53 | ||||
-rw-r--r-- | services/audioflinger/AudioPolicyService.h | 10 | ||||
-rw-r--r-- | services/audioflinger/AudioStreamOutSink.cpp | 12 | ||||
-rw-r--r-- | services/audioflinger/AudioStreamOutSink.h | 5 | ||||
-rw-r--r-- | services/audioflinger/FastMixer.cpp | 11 | ||||
-rw-r--r-- | services/audioflinger/MonoPipe.cpp | 134 | ||||
-rw-r--r-- | services/audioflinger/MonoPipe.h | 41 | ||||
-rw-r--r-- | services/audioflinger/MonoPipeReader.cpp | 18 | ||||
-rw-r--r-- | services/audioflinger/MonoPipeReader.h | 2 | ||||
-rw-r--r-- | services/audioflinger/NBAIO.cpp | 7 | ||||
-rw-r--r-- | services/audioflinger/NBAIO.h | 28 | ||||
-rw-r--r-- | services/audioflinger/Soaker.h | 45 | ||||
-rw-r--r-- | services/audioflinger/SourceAudioBufferProvider.cpp | 2 |
19 files changed, 1067 insertions, 708 deletions
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index 8473fab..c2d2790 100644 --- a/services/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk @@ -89,7 +89,7 @@ LOCAL_CFLAGS += -DFAST_MIXER_STATISTICS LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"' -LOCAL_CFLAGS += -DHAVE_REQUEST_PRIORITY -UFAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE -USOAKER +LOCAL_CFLAGS += -UFAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE # uncomment for systrace # LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_AUDIO diff --git a/services/audioflinger/AudioBufferProviderSource.cpp b/services/audioflinger/AudioBufferProviderSource.cpp index 4342171..613e924 100644 --- a/services/audioflinger/AudioBufferProviderSource.cpp +++ b/services/audioflinger/AudioBufferProviderSource.cpp @@ -46,14 +46,16 @@ ssize_t AudioBufferProviderSource::availableToRead() return mBuffer.raw != NULL ? mBuffer.frameCount - mConsumed : 0; } -ssize_t AudioBufferProviderSource::read(void *buffer, size_t count) +ssize_t AudioBufferProviderSource::read(void *buffer, + size_t count, + int64_t readPTS) { if (CC_UNLIKELY(!mNegotiated)) { return NEGOTIATE; } if (CC_UNLIKELY(mBuffer.raw == NULL)) { mBuffer.frameCount = count; - status_t status = mProvider->getNextBuffer(&mBuffer, AudioBufferProvider::kInvalidPTS); + status_t status = mProvider->getNextBuffer(&mBuffer, readPTS); if (status != OK) { return status == NOT_ENOUGH_DATA ? (ssize_t) WOULD_BLOCK : (ssize_t) status; } @@ -79,7 +81,8 @@ ssize_t AudioBufferProviderSource::read(void *buffer, size_t count) return count; } -ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *user, size_t block) +ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *user, + int64_t readPTS, size_t block) { if (CC_UNLIKELY(!mNegotiated)) { return NEGOTIATE; @@ -99,7 +102,7 @@ ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *us // 1 <= count <= block if (CC_UNLIKELY(mBuffer.raw == NULL)) { mBuffer.frameCount = count; - status_t status = mProvider->getNextBuffer(&mBuffer, AudioBufferProvider::kInvalidPTS); + status_t status = mProvider->getNextBuffer(&mBuffer, readPTS); if (CC_LIKELY(status == OK)) { ALOG_ASSERT(mBuffer.raw != NULL && mBuffer.frameCount <= count); // mConsumed is 0 either from constructor or after releaseBuffer() @@ -117,7 +120,8 @@ ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *us count = available; } if (CC_LIKELY(count > 0)) { - ssize_t ret = via(user, (char *) mBuffer.raw + (mConsumed << mBitShift), count); + char* readTgt = (char *) mBuffer.raw + (mConsumed << mBitShift); + ssize_t ret = via(user, readTgt, count, readPTS); if (CC_UNLIKELY(ret <= 0)) { if (CC_LIKELY(accumulator > 0)) { return accumulator; diff --git a/services/audioflinger/AudioBufferProviderSource.h b/services/audioflinger/AudioBufferProviderSource.h index 2b39937..1435a84 100644 --- a/services/audioflinger/AudioBufferProviderSource.h +++ b/services/audioflinger/AudioBufferProviderSource.h @@ -42,8 +42,9 @@ public: //virtual size_t framesOverrun(); //virtual size_t overruns(); virtual ssize_t availableToRead(); - virtual ssize_t read(void *buffer, size_t count); - virtual ssize_t readVia(readVia_t via, size_t total, void *user, size_t block); + virtual ssize_t read(void *buffer, size_t count, int64_t readPTS); + virtual ssize_t readVia(readVia_t via, size_t total, void *user, + int64_t readPTS, size_t block); private: AudioBufferProvider * const mProvider; diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index aab9984..7e5f102 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -83,13 +83,7 @@ #include "PipeReader.h" #include "SourceAudioBufferProvider.h" -#ifdef HAVE_REQUEST_PRIORITY #include "SchedulingPolicyService.h" -#endif - -#ifdef SOAKER -#include "Soaker.h" -#endif // ---------------------------------------------------------------------------- @@ -167,6 +161,10 @@ static const enum { static uint32_t gScreenState; // incremented by 2 when screen state changes, bit 0 == 1 means "off" // AudioFlinger::setParameters() updates, other threads read w/o lock +// Priorities for requestPriority +static const int kPriorityAudioApp = 2; +static const int kPriorityFastMixer = 3; + // ---------------------------------------------------------------------------- #ifdef ADD_BATTERY_DATA @@ -216,9 +214,8 @@ out: AudioFlinger::AudioFlinger() : BnAudioFlinger(), mPrimaryHardwareDev(NULL), - mHardwareStatus(AUDIO_HW_IDLE), // see also onFirstRef() + mHardwareStatus(AUDIO_HW_IDLE), mMasterVolume(1.0f), - mMasterVolumeSupportLvl(MVS_NONE), mMasterMute(false), mNextUniqueId(1), mMode(AUDIO_MODE_INVALID), @@ -247,21 +244,17 @@ void AudioFlinger::onFirstRef() } mMode = AUDIO_MODE_NORMAL; - mMasterVolumeSW = 1.0; - mMasterVolume = 1.0; - mHardwareStatus = AUDIO_HW_IDLE; } AudioFlinger::~AudioFlinger() { - while (!mRecordThreads.isEmpty()) { // closeInput() will remove first entry from mRecordThreads - closeInput(mRecordThreads.keyAt(0)); + closeInput_nonvirtual(mRecordThreads.keyAt(0)); } while (!mPlaybackThreads.isEmpty()) { // closeOutput() will remove first entry from mPlaybackThreads - closeOutput(mPlaybackThreads.keyAt(0)); + closeOutput_nonvirtual(mPlaybackThreads.keyAt(0)); } for (size_t i = 0; i < mAudioHwDevs.size(); i++) { @@ -278,7 +271,9 @@ static const char * const audio_interfaces[] = { }; #define ARRAY_SIZE(x) (sizeof((x))/sizeof(((x)[0]))) -audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(audio_module_handle_t module, uint32_t devices) +AudioFlinger::AudioHwDevice* AudioFlinger::findSuitableHwDev_l( + audio_module_handle_t module, + audio_devices_t devices) { // if module is 0, the request comes from an old policy manager and we should load // well known modules @@ -289,22 +284,23 @@ audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(audio_module_handle_t modul } } else { // check a match for the requested module handle - AudioHwDevice *audioHwdevice = mAudioHwDevs.valueFor(module); - if (audioHwdevice != NULL) { - return audioHwdevice->hwDevice(); + AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(module); + if (audioHwDevice != NULL) { + return audioHwDevice; } } // then try to find a module supporting the requested device. for (size_t i = 0; i < mAudioHwDevs.size(); i++) { - audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice(); + AudioHwDevice *audioHwDevice = mAudioHwDevs.valueAt(i); + audio_hw_device_t *dev = audioHwDevice->hwDevice(); if ((dev->get_supported_devices(dev) & devices) == devices) - return dev; + return audioHwDevice; } return NULL; } -status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args) +void AudioFlinger::dumpClients(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; @@ -327,11 +323,10 @@ status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args) result.append(buffer); } write(fd, result.string(), result.size()); - return NO_ERROR; } -status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args) +void AudioFlinger::dumpInternals(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; @@ -344,10 +339,9 @@ status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args) (uint32_t)(mStandbyTimeInNsecs / 1000000)); result.append(buffer); write(fd, result.string(), result.size()); - return NO_ERROR; } -status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args) +void AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; @@ -358,7 +352,6 @@ status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args IPCThreadState::self()->getCallingUid()); result.append(buffer); write(fd, result.string(), result.size()); - return NO_ERROR; } static bool tryLock(Mutex& mutex) @@ -440,7 +433,7 @@ sp<IAudioTrack> AudioFlinger::createTrack( audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount, IAudioFlinger::track_flags_t flags, const sp<IMemory>& sharedBuffer, @@ -610,30 +603,27 @@ status_t AudioFlinger::setMasterVolume(float value) return PERMISSION_DENIED; } - float swmv = value; - Mutex::Autolock _l(mLock); + mMasterVolume = value; - // when hw supports master volume, don't scale in sw mixer - if (MVS_NONE != mMasterVolumeSupportLvl) { - for (size_t i = 0; i < mAudioHwDevs.size(); i++) { - AutoMutex lock(mHardwareLock); - audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice(); + // Set master volume in the HALs which support it. + for (size_t i = 0; i < mAudioHwDevs.size(); i++) { + AutoMutex lock(mHardwareLock); + AudioHwDevice *dev = mAudioHwDevs.valueAt(i); - mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; - if (NULL != dev->set_master_volume) { - dev->set_master_volume(dev, value); - } - mHardwareStatus = AUDIO_HW_IDLE; + mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; + if (dev->canSetMasterVolume()) { + dev->hwDevice()->set_master_volume(dev->hwDevice(), value); } - - swmv = 1.0; + mHardwareStatus = AUDIO_HW_IDLE; } - mMasterVolume = value; - mMasterVolumeSW = swmv; + // Now set the master volume in each playback thread. Playback threads + // assigned to HALs which do not have master volume support will apply + // master volume during the mix operation. Threads with HALs which do + // support master volume will simply ignore the setting. for (size_t i = 0; i < mPlaybackThreads.size(); i++) - mPlaybackThreads.valueAt(i)->setMasterVolume(swmv); + mPlaybackThreads.valueAt(i)->setMasterVolume(value); return NO_ERROR; } @@ -656,8 +646,9 @@ status_t AudioFlinger::setMode(audio_mode_t mode) { // scope for the lock AutoMutex lock(mHardwareLock); + audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice(); mHardwareStatus = AUDIO_HW_SET_MODE; - ret = mPrimaryHardwareDev->set_mode(mPrimaryHardwareDev, mode); + ret = dev->set_mode(dev, mode); mHardwareStatus = AUDIO_HW_IDLE; } @@ -684,8 +675,9 @@ status_t AudioFlinger::setMicMute(bool state) } AutoMutex lock(mHardwareLock); + audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice(); mHardwareStatus = AUDIO_HW_SET_MIC_MUTE; - ret = mPrimaryHardwareDev->set_mic_mute(mPrimaryHardwareDev, state); + ret = dev->set_mic_mute(dev, state); mHardwareStatus = AUDIO_HW_IDLE; return ret; } @@ -699,22 +691,44 @@ bool AudioFlinger::getMicMute() const bool state = AUDIO_MODE_INVALID; AutoMutex lock(mHardwareLock); + audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice(); mHardwareStatus = AUDIO_HW_GET_MIC_MUTE; - mPrimaryHardwareDev->get_mic_mute(mPrimaryHardwareDev, &state); + dev->get_mic_mute(dev, &state); mHardwareStatus = AUDIO_HW_IDLE; return state; } status_t AudioFlinger::setMasterMute(bool muted) { + status_t ret = initCheck(); + if (ret != NO_ERROR) { + return ret; + } + // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } Mutex::Autolock _l(mLock); - // This is an optimization, so PlaybackThread doesn't have to look at the one from AudioFlinger mMasterMute = muted; + + // Set master mute in the HALs which support it. + for (size_t i = 0; i < mAudioHwDevs.size(); i++) { + AutoMutex lock(mHardwareLock); + AudioHwDevice *dev = mAudioHwDevs.valueAt(i); + + mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE; + if (dev->canSetMasterMute()) { + dev->hwDevice()->set_master_mute(dev->hwDevice(), muted); + } + mHardwareStatus = AUDIO_HW_IDLE; + } + + // Now set the master mute in each playback thread. Playback threads + // assigned to HALs which do not have master mute support will apply master + // mute during the mix operation. Threads with HALs which do support master + // mute will simply ignore the setting. for (size_t i = 0; i < mPlaybackThreads.size(); i++) mPlaybackThreads.valueAt(i)->setMasterMute(muted); @@ -727,12 +741,6 @@ float AudioFlinger::masterVolume() const return masterVolume_l(); } -float AudioFlinger::masterVolumeSW() const -{ - Mutex::Autolock _l(mLock); - return masterVolumeSW_l(); -} - bool AudioFlinger::masterMute() const { Mutex::Autolock _l(mLock); @@ -741,23 +749,14 @@ bool AudioFlinger::masterMute() const float AudioFlinger::masterVolume_l() const { - if (MVS_FULL == mMasterVolumeSupportLvl) { - float ret_val; - AutoMutex lock(mHardwareLock); - - mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME; - ALOG_ASSERT((NULL != mPrimaryHardwareDev) && - (NULL != mPrimaryHardwareDev->get_master_volume), - "can't get master volume"); - - mPrimaryHardwareDev->get_master_volume(mPrimaryHardwareDev, &ret_val); - mHardwareStatus = AUDIO_HW_IDLE; - return ret_val; - } - return mMasterVolume; } +bool AudioFlinger::masterMute_l() const +{ + return mMasterMute; +} + status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value, audio_io_handle_t output) { @@ -876,17 +875,19 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& if (mBtNrecIsOff != btNrecIsOff) { for (size_t i = 0; i < mRecordThreads.size(); i++) { sp<RecordThread> thread = mRecordThreads.valueAt(i); - RecordThread::RecordTrack *track = thread->track(); - if (track != NULL) { - audio_devices_t device = (audio_devices_t)( - thread->device() & AUDIO_DEVICE_IN_ALL); - bool suspend = audio_is_bluetooth_sco_device(device) && btNrecIsOff; + audio_devices_t device = thread->device() & AUDIO_DEVICE_IN_ALL; + bool suspend = audio_is_bluetooth_sco_device(device) && btNrecIsOff; + // collect all of the thread's session IDs + KeyedVector<int, bool> ids = thread->sessionIds(); + // suspend effects associated with those session IDs + for (size_t j = 0; j < ids.size(); ++j) { + int sessionId = ids.keyAt(j); thread->setEffectSuspended(FX_IID_AEC, suspend, - track->sessionId()); + sessionId); thread->setEffectSuspended(FX_IID_NS, suspend, - track->sessionId()); + sessionId); } } mBtNrecIsOff = btNrecIsOff; @@ -908,7 +909,7 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& { Mutex::Autolock _l(mLock); thread = checkPlaybackThread_l(ioHandle); - if (thread == NULL) { + if (thread == 0) { thread = checkRecordThread_l(ioHandle); } else if (thread == primaryPlaybackThread_l()) { // indicate output device change to all input threads for pre processing @@ -964,7 +965,8 @@ String8 AudioFlinger::getParameters(audio_io_handle_t ioHandle, const String8& k return String8(""); } -size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const +size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t format, + audio_channel_mask_t channelMask) const { status_t ret = initCheck(); if (ret != NO_ERROR) { @@ -975,20 +977,17 @@ size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t form mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE; struct audio_config config = { sample_rate: sampleRate, - channel_mask: audio_channel_in_mask_from_count(channelCount), + channel_mask: channelMask, format: format, }; - size_t size = mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, &config); + audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice(); + size_t size = dev->get_input_buffer_size(dev, &config); mHardwareStatus = AUDIO_HW_IDLE; return size; } unsigned int AudioFlinger::getInputFramesLost(audio_io_handle_t ioHandle) const { - if (ioHandle == 0) { - return 0; - } - Mutex::Autolock _l(mLock); RecordThread *recordThread = checkRecordThread_l(ioHandle); @@ -1011,8 +1010,9 @@ status_t AudioFlinger::setVoiceVolume(float value) } AutoMutex lock(mHardwareLock); + audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice(); mHardwareStatus = AUDIO_HW_SET_VOICE_VOLUME; - ret = mPrimaryHardwareDev->set_voice_volume(mPrimaryHardwareDev, value); + ret = dev->set_voice_volume(dev, value); mHardwareStatus = AUDIO_HW_IDLE; return ret; @@ -1124,7 +1124,7 @@ sp<AudioFlinger::PlaybackThread> AudioFlinger::getEffectThread_l(int sessionId, // ---------------------------------------------------------------------------- AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id, - uint32_t device, type_t type) + audio_devices_t device, type_t type) : Thread(false), mType(type), mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mNormalFrameCount(0), @@ -1132,8 +1132,7 @@ AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio mChannelCount(0), mFrameSize(1), mFormat(AUDIO_FORMAT_INVALID), mParamStatus(NO_ERROR), - mStandby(false), mId(id), - mDevice(device), + mStandby(false), mDevice(device), mId(id), mDeathRecipient(new PMDeathRecipient(this)) { } @@ -1226,7 +1225,7 @@ void AudioFlinger::ThreadBase::processConfigEvents() mLock.unlock(); } -status_t AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args) +void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; @@ -1283,10 +1282,9 @@ status_t AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args if (locked) { mLock.unlock(); } - return NO_ERROR; } -status_t AudioFlinger::ThreadBase::dumpEffectChains(int fd, const Vector<String16>& args) +void AudioFlinger::ThreadBase::dumpEffectChains(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; @@ -1301,7 +1299,6 @@ status_t AudioFlinger::ThreadBase::dumpEffectChains(int fd, const Vector<String1 chain->dump(fd, args); } } - return NO_ERROR; } void AudioFlinger::ThreadBase::acquireWakeLock() @@ -1397,8 +1394,8 @@ void AudioFlinger::ThreadBase::checkSuspendOnAddEffectChain_l(const sp<EffectCha return; } - KeyedVector <int, sp<SuspendedSessionDesc> > sessionEffects = - mSuspendedSessions.editValueAt(index); + const KeyedVector <int, sp<SuspendedSessionDesc> >& sessionEffects = + mSuspendedSessions.valueAt(index); for (size_t i = 0; i < sessionEffects.size(); i++) { sp<SuspendedSessionDesc> desc = sessionEffects.valueAt(i); @@ -1424,7 +1421,7 @@ void AudioFlinger::ThreadBase::updateSuspendedSessions_l(const effect_uuid_t *ty if (suspend) { if (index >= 0) { - sessionEffects = mSuspendedSessions.editValueAt(index); + sessionEffects = mSuspendedSessions.valueAt(index); } else { mSuspendedSessions.add(sessionId, sessionEffects); } @@ -1432,7 +1429,7 @@ void AudioFlinger::ThreadBase::updateSuspendedSessions_l(const effect_uuid_t *ty if (index < 0) { return; } - sessionEffects = mSuspendedSessions.editValueAt(index); + sessionEffects = mSuspendedSessions.valueAt(index); } @@ -1449,7 +1446,7 @@ void AudioFlinger::ThreadBase::updateSuspendedSessions_l(const effect_uuid_t *ty } else { desc = new SuspendedSessionDesc(); if (type != NULL) { - memcpy(&desc->mType, type, sizeof(effect_uuid_t)); + desc->mType = *type; } sessionEffects.add(key, desc); ALOGV("updateSuspendedSessions_l() suspend adding effect %08x", key); @@ -1509,18 +1506,12 @@ void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled_l(const sp<EffectModu AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, audio_io_handle_t id, - uint32_t device, + audio_devices_t device, type_t type) : ThreadBase(audioFlinger, id, device, type), mMixBuffer(NULL), mSuspended(0), mBytesWritten(0), - // Assumes constructor is called by AudioFlinger with it's mLock held, - // but it would be safer to explicitly pass initial masterMute as parameter - mMasterMute(audioFlinger->masterMute_l()), // mStreamTypes[] initialized in constructor body mOutput(output), - // Assumes constructor is called by AudioFlinger with it's mLock held, - // but it would be safer to explicitly pass initial masterVolume as parameter - mMasterVolume(audioFlinger->masterVolumeSW_l()), mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false), mMixerStatus(MIXER_IDLE), mMixerStatusIgnoringFastTracks(MIXER_IDLE), @@ -1531,6 +1522,25 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge { snprintf(mName, kNameLength, "AudioOut_%X", id); + // Assumes constructor is called by AudioFlinger with it's mLock held, but + // it would be safer to explicitly pass initial masterVolume/masterMute as + // parameter. + // + // If the HAL we are using has support for master volume or master mute, + // then do not attenuate or mute during mixing (just leave the volume at 1.0 + // and the mute set to false). + mMasterVolume = audioFlinger->masterVolume_l(); + mMasterMute = audioFlinger->masterMute_l(); + if (mOutput && mOutput->audioHwDev) { + if (mOutput->audioHwDev->canSetMasterVolume()) { + mMasterVolume = 1.0; + } + + if (mOutput->audioHwDev->canSetMasterMute()) { + mMasterMute = false; + } + } + readOutputParameters(); // mStreamTypes[AUDIO_STREAM_CNT] is initialized by stream_type_t default constructor @@ -1549,15 +1559,14 @@ AudioFlinger::PlaybackThread::~PlaybackThread() delete [] mMixBuffer; } -status_t AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args) +void AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args) { dumpInternals(fd, args); dumpTracks(fd, args); dumpEffectChains(fd, args); - return NO_ERROR; } -status_t AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args) +void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; @@ -1605,11 +1614,9 @@ status_t AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16> FastTrackUnderruns underruns = getFastTrackUnderruns(0); fdprintf(fd, "Normal mixer raw underrun counters: partial=%u empty=%u\n", underruns.mBitFields.mPartial, underruns.mBitFields.mEmpty); - - return NO_ERROR; } -status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args) +void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; @@ -1633,8 +1640,6 @@ status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String fdprintf(fd, "Fast track availMask=%#x\n", mFastTrackAvailMask); dumpBase(fd, args); - - return NO_ERROR; } // Thread virtuals @@ -1660,7 +1665,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount, const sp<IMemory>& sharedBuffer, int sessionId, @@ -1715,7 +1720,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac frameCount, mFrameCount); } else { ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: isTimed=%d sharedBuffer=%p frameCount=%d " - "mFrameCount=%d format=%d isLinear=%d channelMask=%d sampleRate=%d mSampleRate=%d " + "mFrameCount=%d format=%d isLinear=%d channelMask=%#x sampleRate=%d mSampleRate=%d " "hasFastMixer=%d tid=%d fastTrackAvailMask=%#x", isTimed, sharedBuffer.get(), frameCount, mFrameCount, format, audio_is_linear_pcm(format), @@ -1789,7 +1794,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac track = TimedTrack::create(this, client, streamType, sampleRate, format, channelMask, frameCount, sharedBuffer, sessionId); } - if (track == NULL || track->getCblk() == NULL || track->name() < 0) { + if (track == 0 || track->getCblk() == NULL || track->name() < 0) { lStatus = NO_MEMORY; goto Exit; } @@ -1804,18 +1809,16 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac } } -#ifdef HAVE_REQUEST_PRIORITY if ((flags & IAudioFlinger::TRACK_FAST) && (tid != -1)) { pid_t callingPid = IPCThreadState::self()->getCallingPid(); // we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful, // so ask activity manager to do this on our behalf - int err = requestPriority(callingPid, tid, 1); + int err = requestPriority(callingPid, tid, kPriorityAudioApp); if (err != 0) { ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d", - 1, callingPid, tid, err); + kPriorityAudioApp, callingPid, tid, err); } } -#endif lStatus = NO_ERROR; @@ -1857,13 +1860,25 @@ uint32_t AudioFlinger::PlaybackThread::latency_l() const void AudioFlinger::PlaybackThread::setMasterVolume(float value) { Mutex::Autolock _l(mLock); - mMasterVolume = value; + // Don't apply master volume in SW if our HAL can do it for us. + if (mOutput && mOutput->audioHwDev && + mOutput->audioHwDev->canSetMasterVolume()) { + mMasterVolume = 1.0; + } else { + mMasterVolume = value; + } } void AudioFlinger::PlaybackThread::setMasterMute(bool muted) { Mutex::Autolock _l(mLock); - setMasterMute_l(muted); + // Don't apply master mute in SW if our HAL can do it for us. + if (mOutput && mOutput->audioHwDev && + mOutput->audioHwDev->canSetMasterMute()) { + mMasterMute = false; + } else { + mMasterMute = muted; + } } void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value) @@ -2192,28 +2207,25 @@ void AudioFlinger::PlaybackThread::threadLoop_removeTracks(const Vector< sp<Trac // ---------------------------------------------------------------------------- AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, - audio_io_handle_t id, uint32_t device, type_t type) + audio_io_handle_t id, audio_devices_t device, type_t type) : PlaybackThread(audioFlinger, output, id, device, type), // mAudioMixer below -#ifdef SOAKER - mSoaker(NULL), -#endif // mFastMixer below mFastMixerFutex(0) // mOutputSink below // mPipeSink below // mNormalSink below { - ALOGV("MixerThread() id=%d device=%d type=%d", id, device, type); - ALOGV("mSampleRate=%d, mChannelMask=%d, mChannelCount=%d, mFormat=%d, mFrameSize=%d, " + ALOGV("MixerThread() id=%d device=%#x type=%d", id, device, type); + ALOGV("mSampleRate=%d, mChannelMask=%#x, mChannelCount=%d, mFormat=%d, mFrameSize=%d, " "mFrameCount=%d, mNormalFrameCount=%d", mSampleRate, mChannelMask, mChannelCount, mFormat, mFrameSize, mFrameCount, mNormalFrameCount); mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate); // FIXME - Current mixer implementation only supports stereo output - if (mChannelCount == 1) { - ALOGE("Invalid audio hardware channel count"); + if (mChannelCount != FCC_2) { + ALOGE("Invalid audio hardware channel count %d", mChannelCount); } // create an NBAIO sink for the HAL output stream, and negotiate @@ -2267,13 +2279,6 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud mTeeSource = teeSource; #endif -#ifdef SOAKER - // create a soaker as workaround for governor issues - mSoaker = new Soaker(); - // FIXME Soaker should only run when needed, i.e. when FastMixer is not in COLD_IDLE - mSoaker->run("Soaker", PRIORITY_LOWEST); -#endif - // create fast mixer and configure it initially with just one fast track for our submix mFastMixer = new FastMixer(); FastMixerStateQueue *sq = mFastMixer->sq(); @@ -2305,14 +2310,12 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud // start the fast mixer mFastMixer->run("FastMixer", PRIORITY_URGENT_AUDIO); -#ifdef HAVE_REQUEST_PRIORITY pid_t tid = mFastMixer->getTid(); - int err = requestPriority(getpid_cached, tid, 2); + int err = requestPriority(getpid_cached, tid, kPriorityFastMixer); if (err != 0) { ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d", - 2, getpid_cached, tid, err); + kPriorityFastMixer, getpid_cached, tid, err); } -#endif #ifdef AUDIO_WATCHDOG // create and start the watchdog @@ -2320,10 +2323,10 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud mAudioWatchdog->setDump(&mAudioWatchdogDump); mAudioWatchdog->run("AudioWatchdog", PRIORITY_URGENT_AUDIO); tid = mAudioWatchdog->getTid(); - err = requestPriority(getpid_cached, tid, 1); + err = requestPriority(getpid_cached, tid, kPriorityFastMixer); if (err != 0) { ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d", - 1, getpid_cached, tid, err); + kPriorityFastMixer, getpid_cached, tid, err); } #endif @@ -2370,12 +2373,6 @@ AudioFlinger::MixerThread::~MixerThread() delete fastTrack->mBufferProvider; sq->end(false /*didModify*/); delete mFastMixer; -#ifdef SOAKER - if (mSoaker != NULL) { - mSoaker->requestExitAndWait(); - } - delete mSoaker; -#endif if (mAudioWatchdog != 0) { mAudioWatchdog->requestExit(); mAudioWatchdog->requestExitAndWait(); @@ -2508,9 +2505,6 @@ bool AudioFlinger::PlaybackThread::threadLoop() // MIXER nsecs_t lastWarning = 0; -if (mType == MIXER) { - longStandbyExit = false; -} // DUPLICATING // FIXME could this be made local to while loop? @@ -2519,9 +2513,9 @@ if (mType == MIXER) { cacheParameters_l(); sleepTime = idleSleepTime; -if (mType == MIXER) { - sleepTimeShift = 0; -} + if (mType == MIXER) { + sleepTimeShift = 0; + } CpuStats cpuStats; const String8 myName(String8::format("thread %p type %d TID %d", this, mType, gettid())); @@ -2548,7 +2542,7 @@ if (mType == MIXER) { // put audio hardware into standby after short delay if (CC_UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) || - mSuspended > 0)) { + isSuspended())) { if (!mStandby) { threadLoop_standby(); @@ -2602,7 +2596,7 @@ if (mType == MIXER) { threadLoop_sleepTime(); } - if (mSuspended > 0) { + if (isSuspended()) { sleepTime = suspendSleepTimeUs(); } @@ -2635,11 +2629,6 @@ if (mType == MIXER) { ns2ms(delta), mNumDelayedWrites, this); lastWarning = now; } - // FIXME this is broken: longStandbyExit should be handled out of the if() and with - // a different threshold. Or completely removed for what it is worth anyway... - if (mStandby) { - longStandbyExit = true; - } } } @@ -2667,15 +2656,13 @@ if (mType == MIXER) { // is now local to this block, but will keep it for now (at least until merge done). } -if (mType == MIXER || mType == DIRECT) { - // put output stream into standby mode - if (!mStandby) { - mOutput->stream->common.standby(&mOutput->stream->common); + // for DuplicatingThread, standby mode is handled by the outputTracks, otherwise ... + if (mType == MIXER || mType == DIRECT) { + // put output stream into standby mode + if (!mStandby) { + mOutput->stream->common.standby(&mOutput->stream->common); + } } -} -if (mType == DUPLICATING) { - // for DuplicatingThread, standby mode is handled by the outputTracks -} releaseWakeLock(); @@ -2794,7 +2781,7 @@ void AudioFlinger::MixerThread::threadLoop_standby() // shared by MIXER and DIRECT, overridden by DUPLICATING void AudioFlinger::PlaybackThread::threadLoop_standby() { - ALOGV("Audio hardware entering standby, mixer %p, suspend count %u", this, mSuspended); + ALOGV("Audio hardware entering standby, mixer %p, suspend count %d", this, mSuspended); mOutput->stream->common.standby(&mOutput->stream->common); } @@ -2804,9 +2791,10 @@ void AudioFlinger::MixerThread::threadLoop_mix() int64_t pts; status_t status = INVALID_OPERATION; - if (NULL != mOutput->stream->get_next_write_timestamp) { - status = mOutput->stream->get_next_write_timestamp( - mOutput->stream, &pts); + if (mNormalSink != 0) { + status = mNormalSink->getNextWriteTimestamp(&pts); + } else { + status = mOutputSink->getNextWriteTimestamp(&pts); } if (status != NO_ERROR) { @@ -2847,11 +2835,10 @@ void AudioFlinger::MixerThread::threadLoop_sleepTime() } else { sleepTime = idleSleepTime; } - } else if (mBytesWritten != 0 || - (mMixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) { + } else if (mBytesWritten != 0 || (mMixerStatus == MIXER_TRACKS_ENABLED)) { memset (mMixBuffer, 0, mixBufferSize); sleepTime = 0; - ALOGV_IF((mBytesWritten == 0 && (mMixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start"); + ALOGV_IF((mBytesWritten == 0 && (mMixerStatus == MIXER_TRACKS_ENABLED)), "anticipated start"); } // TODO add standby time extension fct of effect tail } @@ -3229,7 +3216,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac } //ALOGV("track %d u=%08x, s=%08x [NOT READY] on thread %p", name, cblk->user, cblk->server, this); - if ((track->sharedBuffer() != 0) || track->isTerminated() || + if ((track->sharedBuffer() != 0) || track->isStopped() || track->isPaused()) { // We have consumed all the buffers of this track. // Remove it from the list of active tracks. @@ -3249,8 +3236,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac track->mUnderrunCount++; // No buffers for this track. Give it a few chances to // fill a buffer, then remove it from active list. - if (--(track->mRetryCount) <= 0) { - ALOGV("BUFFER TIMEOUT: remove(%d) from active list on thread %p", name, this); + if (--(track->mRetryCount) <= 0 || track->isTerminated()) { + ALOGV_IF(track->mRetryCount <= 0, "BUFFER TIMEOUT: remove(%d) from active list on thread %p", name, this); tracksToRemove->add(track); // indicate to client process that the track was disabled because of underrun; // it will then automatically call start() when data is available @@ -3373,7 +3360,7 @@ void AudioFlinger::PlaybackThread::cacheParameters_l() idleSleepTime = idleSleepTimeUs(); } -void AudioFlinger::MixerThread::invalidateTracks(audio_stream_type_t streamType) +void AudioFlinger::PlaybackThread::invalidateTracks(audio_stream_type_t streamType) { ALOGV ("MixerThread::invalidateTracks() mixer %p, streamType %d, mTracks.size %d", this, streamType, mTracks.size()); @@ -3460,14 +3447,14 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l() #ifdef ADD_BATTERY_DATA // when changing the audio output device, call addBatteryData to notify // the change - if ((int)mDevice != value) { + if (mDevice != value) { uint32_t params = 0; // check whether speaker is on if (value & AUDIO_DEVICE_OUT_SPEAKER) { params |= IMediaPlayerService::kBatteryDataSpeakerOn; } - int deviceWithoutSpeaker + audio_devices_t deviceWithoutSpeaker = AUDIO_DEVICE_OUT_ALL & ~AUDIO_DEVICE_OUT_SPEAKER; // check if any other device (except speaker) is on if (value & deviceWithoutSpeaker ) { @@ -3482,7 +3469,7 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l() // forward device change to effects that have requested to be // aware of attached audio device. - mDevice = (uint32_t)value; + mDevice = value; for (size_t i = 0; i < mEffectChains.size(); i++) { mEffectChains[i]->setDevice_l(mDevice); } @@ -3505,7 +3492,7 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l() readOutputParameters(); mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate); for (size_t i = 0; i < mTracks.size() ; i++) { - int name = getTrackName_l((audio_channel_mask_t)mTracks[i]->mChannelMask); + int name = getTrackName_l(mTracks[i]->mChannelMask); if (name < 0) break; mTracks[i]->mName = name; // limit track sample rate to 2 x new output sample rate @@ -3539,7 +3526,7 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l() return reconfig; } -status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args) +void AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; @@ -3593,7 +3580,8 @@ status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16> #define TEE_SINK_READ 1024 short buffer[TEE_SINK_READ * FCC_2]; size_t count = TEE_SINK_READ; - ssize_t actual = teeSource->read(buffer, count); + ssize_t actual = teeSource->read(buffer, count, + AudioBufferProvider::kInvalidPTS); bool wasFirstRead = firstRead; firstRead = false; if (actual <= 0) { @@ -3602,7 +3590,7 @@ status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16> } break; } - ALOG_ASSERT(actual <= count); + ALOG_ASSERT(actual <= (ssize_t)count); write(teeFd, buffer, actual * channelCount * sizeof(short)); total += actual; } @@ -3624,8 +3612,6 @@ status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16> AudioWatchdogDump wdCopy = mAudioWatchdogDump; wdCopy.dump(fd); } - - return NO_ERROR; } uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() const @@ -3651,7 +3637,7 @@ void AudioFlinger::MixerThread::cacheParameters_l() // ---------------------------------------------------------------------------- AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, - AudioStreamOut* output, audio_io_handle_t id, uint32_t device) + AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device) : PlaybackThread(audioFlinger, output, id, device, DIRECT) // mLeftVolFloat, mRightVolFloat { @@ -3751,7 +3737,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep } //ALOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server); - if ((track->sharedBuffer() != 0) || track->isTerminated() || + if ((track->sharedBuffer() != 0) || track->isStopped() || track->isPaused()) { // We have consumed all the buffers of this track. // Remove it from the list of active tracks. @@ -3769,8 +3755,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep } else { // No buffers for this track. Give it a few chances to // fill a buffer, then remove it from active list. - if (--(track->mRetryCount) <= 0) { - ALOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name()); + if (--(track->mRetryCount) <= 0 || track->isTerminated()) { + ALOGV_IF(track->mRetryCount <= 0, "BUFFER TIMEOUT: remove(%d) from active list", track->name()); trackToRemove = track; } else { mixerStatus = MIXER_TRACKS_ENABLED; @@ -4070,6 +4056,7 @@ bool AudioFlinger::DuplicatingThread::outputsReady(const SortedVector< sp<Output return false; } PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); + // see note at standby() declaration if (playbackThread->standby() && !playbackThread->isSuspended()) { ALOGV("DuplicatingThread output track %p on thread %p Not Ready", outputTracks[i].get(), thread.get()); return false; @@ -4099,7 +4086,7 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( const sp<Client>& client, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount, const sp<IMemory>& sharedBuffer, int sessionId) @@ -4274,7 +4261,7 @@ AudioFlinger::PlaybackThread::Track::Track( audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount, const sp<IMemory>& sharedBuffer, int sessionId, @@ -4300,7 +4287,7 @@ AudioFlinger::PlaybackThread::Track::Track( // 16 bit because data is converted to 16 bit before being stored in buffer by AudioTrack mCblk->frameSize = audio_is_linear_pcm(format) ? mChannelCount * sizeof(int16_t) : sizeof(uint8_t); // to avoid leaking a track name, do not allocate one unless there is an mCblk - mName = thread->getTrackName_l((audio_channel_mask_t)channelMask); + mName = thread->getTrackName_l(channelMask); mCblk->mName = mName; if (mName < 0) { ALOGE("no more track names available"); @@ -4329,11 +4316,6 @@ AudioFlinger::PlaybackThread::Track::Track( AudioFlinger::PlaybackThread::Track::~Track() { ALOGV("PlaybackThread::Track destructor"); - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - Mutex::Autolock _l(thread->mLock); - mState = TERMINATED; - } } void AudioFlinger::PlaybackThread::Track::destroy() @@ -4496,8 +4478,6 @@ status_t AudioFlinger::PlaybackThread::Track::getNextBuffer( } buffer->raw = getBuffer(s, framesReq); - if (buffer->raw == NULL) goto getNextBuffer_exit; - buffer->frameCount = framesReq; return NO_ERROR; } @@ -4821,12 +4801,12 @@ AudioFlinger::PlaybackThread::TimedTrack::create( audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount, const sp<IMemory>& sharedBuffer, int sessionId) { if (!client->reserveTimedTrack()) - return NULL; + return 0; return new TimedTrack( thread, client, streamType, sampleRate, format, channelMask, frameCount, @@ -4839,7 +4819,7 @@ AudioFlinger::PlaybackThread::TimedTrack::TimedTrack( audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount, const sp<IMemory>& sharedBuffer, int sessionId) @@ -5061,7 +5041,7 @@ status_t AudioFlinger::PlaybackThread::TimedTrack::getNextBuffer( AudioBufferProvider::Buffer* buffer, int64_t pts) { if (pts == AudioBufferProvider::kInvalidPTS) { - buffer->raw = 0; + buffer->raw = NULL; buffer->frameCount = 0; mTimedAudioOutputOnTime = false; return INVALID_OPERATION; @@ -5076,7 +5056,7 @@ status_t AudioFlinger::PlaybackThread::TimedTrack::getNextBuffer( // if we have no timed buffers, then fail if (mTimedBufferQueue.isEmpty()) { - buffer->raw = 0; + buffer->raw = NULL; buffer->frameCount = 0; return NOT_ENOUGH_DATA; } @@ -5103,7 +5083,7 @@ status_t AudioFlinger::PlaybackThread::TimedTrack::getNextBuffer( // the transform failed. this shouldn't happen, but if it does // then just drop this buffer ALOGW("timedGetNextBuffer transform failed"); - buffer->raw = 0; + buffer->raw = NULL; buffer->frameCount = 0; trimTimedBufferQueueHead_l("getNextBuffer; no transform"); return NO_ERROR; @@ -5112,7 +5092,7 @@ status_t AudioFlinger::PlaybackThread::TimedTrack::getNextBuffer( if (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME) { if (OK != mCCHelper.commonTimeToLocalTime(transformedPTS, &headLocalPTS)) { - buffer->raw = 0; + buffer->raw = NULL; buffer->frameCount = 0; return INVALID_OPERATION; } @@ -5334,7 +5314,7 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack( const sp<Client>& client, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount, int sessionId) : TrackBase(thread, client, sampleRate, format, @@ -5355,10 +5335,7 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack( AudioFlinger::RecordThread::RecordTrack::~RecordTrack() { - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - AudioSystem::releaseInput(thread->id()); - } + ALOGV("%s", __func__); } // AudioBufferProvider interface @@ -5389,8 +5366,6 @@ status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvi } buffer->raw = getBuffer(s, framesReq); - if (buffer->raw == NULL) goto getNextBuffer_exit; - buffer->frameCount = framesReq; return NO_ERROR; } @@ -5418,14 +5393,26 @@ void AudioFlinger::RecordThread::RecordTrack::stop() sp<ThreadBase> thread = mThread.promote(); if (thread != 0) { RecordThread *recordThread = (RecordThread *)thread.get(); - recordThread->stop(this); - TrackBase::reset(); - // Force overrun condition to avoid false overrun callback until first data is - // read from buffer - android_atomic_or(CBLK_UNDERRUN_ON, &mCblk->flags); + recordThread->mLock.lock(); + bool doStop = recordThread->stop_l(this); + if (doStop) { + TrackBase::reset(); + // Force overrun condition to avoid false overrun callback until first data is + // read from buffer + android_atomic_or(CBLK_UNDERRUN_ON, &mCblk->flags); + } + recordThread->mLock.unlock(); + if (doStop) { + AudioSystem::stopInput(recordThread->id()); + } } } +/*static*/ void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result) +{ + result.append(" Clien Fmt Chn mask Session Buf S SRate Serv User\n"); +} + void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size) { snprintf(buffer, size, " %05d %03u 0x%08x %05d %04u %01d %05u %08x %08x\n", @@ -5448,7 +5435,7 @@ AudioFlinger::PlaybackThread::OutputTrack::OutputTrack( DuplicatingThread *sourceThread, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount) : Track(playbackThread, NULL, AUDIO_STREAM_CNT, sampleRate, format, channelMask, frameCount, NULL, 0, IAudioFlinger::TRACK_DEFAULT), @@ -5836,9 +5823,10 @@ sp<IAudioRecord> AudioFlinger::openRecord( audio_io_handle_t input, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount, IAudioFlinger::track_flags_t flags, + pid_t tid, int *sessionId, status_t *status) { @@ -5877,13 +5865,8 @@ sp<IAudioRecord> AudioFlinger::openRecord( } } // create new record track. The record track uses one track in mHardwareMixerThread by convention. - recordTrack = thread->createRecordTrack_l(client, - sampleRate, - format, - channelMask, - frameCount, - lSessionId, - &lStatus); + recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask, + frameCount, lSessionId, flags, tid, &lStatus); } if (lStatus != NO_ERROR) { // remove local strong reference to Client before deleting the RecordTrack so that the Client @@ -5913,19 +5896,24 @@ AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordThread::Re } AudioFlinger::RecordHandle::~RecordHandle() { - stop(); + stop_nonvirtual(); + mRecordTrack->destroy(); } sp<IMemory> AudioFlinger::RecordHandle::getCblk() const { return mRecordTrack->getCblk(); } -status_t AudioFlinger::RecordHandle::start(int event, int triggerSession) { +status_t AudioFlinger::RecordHandle::start(int /*AudioSystem::sync_event_t*/ event, int triggerSession) { ALOGV("RecordHandle::start()"); return mRecordTrack->start((AudioSystem::sync_event_t)event, triggerSession); } void AudioFlinger::RecordHandle::stop() { + stop_nonvirtual(); +} + +void AudioFlinger::RecordHandle::stop_nonvirtual() { ALOGV("RecordHandle::stop()"); mRecordTrack->stop(); } @@ -5941,13 +5929,13 @@ status_t AudioFlinger::RecordHandle::onTransact( AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, AudioStreamIn *input, uint32_t sampleRate, - uint32_t channels, + audio_channel_mask_t channelMask, audio_io_handle_t id, - uint32_t device) : + audio_devices_t device) : ThreadBase(audioFlinger, id, device, RECORD), - mInput(input), mTrack(NULL), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL), + mInput(input), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL), // mRsmpInIndex and mInputBytes set by readInputParameters() - mReqChannelCount(popcount(channels)), + mReqChannelCount(popcount(channelMask)), mReqSampleRate(sampleRate) // mBytesRead is only meaningful while active, and so is cleared in start() // (but might be better to also clear here for dump?) @@ -5985,6 +5973,7 @@ bool AudioFlinger::RecordThread::threadLoop() nsecs_t lastWarning = 0; + inputStandBy(); acquireWakeLock(); // start recording @@ -5996,10 +5985,7 @@ bool AudioFlinger::RecordThread::threadLoop() Mutex::Autolock _l(mLock); checkForNewParameters_l(); if (mActiveTrack == 0 && mConfigEvents.isEmpty()) { - if (!mStandby) { - mInput->stream->common.standby(&mInput->stream->common); - mStandby = true; - } + standby(); if (exitPending()) break; @@ -6013,10 +5999,7 @@ bool AudioFlinger::RecordThread::threadLoop() } if (mActiveTrack != 0) { if (mActiveTrack->mState == TrackBase::PAUSING) { - if (!mStandby) { - mInput->stream->common.standby(&mInput->stream->common); - mStandby = true; - } + standby(); mActiveTrack.clear(); mStartStopCond.broadcast(); } else if (mActiveTrack->mState == TrackBase::RESUMING) { @@ -6034,6 +6017,9 @@ bool AudioFlinger::RecordThread::threadLoop() mStartStopCond.broadcast(); } mStandby = false; + } else if (mActiveTrack->mState == TrackBase::TERMINATED) { + removeTrack_l(mActiveTrack); + mActiveTrack.clear(); } } lockEffectChains_l(effectChains); @@ -6068,18 +6054,12 @@ bool AudioFlinger::RecordThread::threadLoop() mFormat != AUDIO_FORMAT_PCM_16_BIT) { memcpy(dst, src, framesIn * mFrameSize); } else { - int16_t *src16 = (int16_t *)src; - int16_t *dst16 = (int16_t *)dst; if (mChannelCount == 1) { - while (framesIn--) { - *dst16++ = *src16; - *dst16++ = *src16++; - } + upmix_to_stereo_i16_from_mono_i16((int16_t *)dst, + (int16_t *)src, framesIn); } else { - while (framesIn--) { - *dst16++ = (int16_t)(((int32_t)*src16 + (int32_t)*(src16 + 1)) >> 1); - src16 += 2; - } + downmix_to_mono_i16_from_stereo_i16((int16_t *)dst, + (int16_t *)src, framesIn); } } } @@ -6097,7 +6077,7 @@ bool AudioFlinger::RecordThread::threadLoop() if (mActiveTrack->mState == TrackBase::ACTIVE) { // Force input into standby so that it tries to // recover at next read attempt - mInput->stream->common.standby(&mInput->stream->common); + inputStandBy(); usleep(kRecordThreadSleepUs); } mRsmpInIndex = mFrameCount; @@ -6120,12 +6100,8 @@ bool AudioFlinger::RecordThread::threadLoop() if (mChannelCount == 2 && mReqChannelCount == 1) { ditherAndClamp(mRsmpOutBuffer, mRsmpOutBuffer, framesOut); // the resampler always outputs stereo samples: do post stereo to mono conversion - int16_t *src = (int16_t *)mRsmpOutBuffer; - int16_t *dst = buffer.i16; - while (framesOut--) { - *dst++ = (int16_t)(((int32_t)*src + (int32_t)*(src + 1)) >> 1); - src += 2; - } + downmix_to_mono_i16_from_stereo_i16(buffer.i16, (int16_t *)mRsmpOutBuffer, + framesOut); } else { ditherAndClamp((int32_t *)buffer.raw, mRsmpOutBuffer, framesOut); } @@ -6151,7 +6127,7 @@ bool AudioFlinger::RecordThread::threadLoop() } } } - mActiveTrack->overflow(); + mActiveTrack->clearOverflow(); } // client isn't retrieving buffers fast enough else { @@ -6173,12 +6149,13 @@ bool AudioFlinger::RecordThread::threadLoop() effectChains.clear(); } - if (!mStandby) { - mInput->stream->common.standby(&mInput->stream->common); - } - mActiveTrack.clear(); + standby(); - mStartStopCond.broadcast(); + { + Mutex::Autolock _l(mLock); + mActiveTrack.clear(); + mStartStopCond.broadcast(); + } releaseWakeLock(); @@ -6186,14 +6163,28 @@ bool AudioFlinger::RecordThread::threadLoop() return false; } +void AudioFlinger::RecordThread::standby() +{ + if (!mStandby) { + inputStandBy(); + mStandby = true; + } +} + +void AudioFlinger::RecordThread::inputStandBy() +{ + mInput->stream->common.standby(&mInput->stream->common); +} sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRecordTrack_l( const sp<AudioFlinger::Client>& client, uint32_t sampleRate, audio_format_t format, - int channelMask, + audio_channel_mask_t channelMask, int frameCount, int sessionId, + IAudioFlinger::track_flags_t flags, + pid_t tid, status_t *status) { sp<RecordTrack> track; @@ -6205,6 +6196,8 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createR goto Exit; } + // FIXME use flags and tid similar to createTrack_l() + { // scope for mLock Mutex::Autolock _l(mLock); @@ -6215,11 +6208,11 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createR lStatus = NO_MEMORY; goto Exit; } + mTracks.add(track); - mTrack = track.get(); // disable AEC and NS if the device is a BT SCO headset supporting those pre processings - bool suspend = audio_is_bluetooth_sco_device( - (audio_devices_t)(mDevice & AUDIO_DEVICE_IN_ALL)) && mAudioFlinger->btNrecIsOff(); + bool suspend = audio_is_bluetooth_sco_device(mDevice & AUDIO_DEVICE_IN_ALL) && + mAudioFlinger->btNrecIsOff(); setEffectSuspended_l(FX_IID_AEC, suspend, sessionId); setEffectSuspended_l(FX_IID_NS, suspend, sessionId); } @@ -6337,27 +6330,23 @@ void AudioFlinger::RecordThread::handleSyncStartEvent(const sp<SyncEvent>& event } } -void AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) { +bool AudioFlinger::RecordThread::stop_l(RecordThread::RecordTrack* recordTrack) { ALOGV("RecordThread::stop"); - sp<ThreadBase> strongMe = this; - { - AutoMutex lock(mLock); - if (mActiveTrack != 0 && recordTrack == mActiveTrack.get()) { - mActiveTrack->mState = TrackBase::PAUSING; - // do not wait for mStartStopCond if exiting - if (exitPending()) { - return; - } - mStartStopCond.wait(mLock); - // if we have been restarted, recordTrack == mActiveTrack.get() here - if (mActiveTrack == 0 || recordTrack != mActiveTrack.get()) { - mLock.unlock(); - AudioSystem::stopInput(mId); - mLock.lock(); - ALOGV("Record stopped OK"); - } - } + if (recordTrack != mActiveTrack.get() || recordTrack->mState == TrackBase::PAUSING) { + return false; + } + recordTrack->mState = TrackBase::PAUSING; + // do not wait for mStartStopCond if exiting + if (exitPending()) { + return true; + } + mStartStopCond.wait(mLock); + // if we have been restarted, recordTrack == mActiveTrack.get() here + if (exitPending() || recordTrack != mActiveTrack.get()) { + ALOGV("Record stopped OK"); + return true; } + return false; } bool AudioFlinger::RecordThread::isValidSyncEvent(const sp<SyncEvent>& event) @@ -6371,16 +6360,63 @@ status_t AudioFlinger::RecordThread::setSyncEvent(const sp<SyncEvent>& event) return BAD_VALUE; } + int eventSession = event->triggerSession(); + status_t ret = NAME_NOT_FOUND; + Mutex::Autolock _l(mLock); - if (mTrack != NULL && event->triggerSession() == mTrack->sessionId()) { - mTrack->setSyncEvent(event); - return NO_ERROR; + for (size_t i = 0; i < mTracks.size(); i++) { + sp<RecordTrack> track = mTracks[i]; + if (eventSession == track->sessionId()) { + track->setSyncEvent(event); + ret = NO_ERROR; + } } - return NAME_NOT_FOUND; + return ret; +} + +void AudioFlinger::RecordThread::RecordTrack::destroy() +{ + // see comments at AudioFlinger::PlaybackThread::Track::destroy() + sp<RecordTrack> keep(this); + { + sp<ThreadBase> thread = mThread.promote(); + if (thread != 0) { + if (mState == ACTIVE || mState == RESUMING) { + AudioSystem::stopInput(thread->id()); + } + AudioSystem::releaseInput(thread->id()); + Mutex::Autolock _l(thread->mLock); + RecordThread *recordThread = (RecordThread *) thread.get(); + recordThread->destroyTrack_l(this); + } + } +} + +// destroyTrack_l() must be called with ThreadBase::mLock held +void AudioFlinger::RecordThread::destroyTrack_l(const sp<RecordTrack>& track) +{ + track->mState = TrackBase::TERMINATED; + // active tracks are removed by threadLoop() + if (mActiveTrack != track) { + removeTrack_l(track); + } +} + +void AudioFlinger::RecordThread::removeTrack_l(const sp<RecordTrack>& track) +{ + mTracks.remove(track); + // need anything related to effects here? } -status_t AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args) +void AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args) +{ + dumpInternals(fd, args); + dumpTracks(fd, args); + dumpEffectChains(fd, args); +} + +void AudioFlinger::RecordThread::dumpInternals(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; @@ -6390,11 +6426,6 @@ status_t AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args) result.append(buffer); if (mActiveTrack != 0) { - result.append("Active Track:\n"); - result.append(" Clien Fmt Chn mask Session Buf S SRate Serv User\n"); - mActiveTrack->dump(buffer, SIZE); - result.append(buffer); - snprintf(buffer, SIZE, "In index: %d\n", mRsmpInIndex); result.append(buffer); snprintf(buffer, SIZE, "In size: %d\n", mInputBytes); @@ -6405,17 +6436,41 @@ status_t AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args) result.append(buffer); snprintf(buffer, SIZE, "Out sample rate: %d\n", mReqSampleRate); result.append(buffer); - - } else { - result.append("No record client\n"); + result.append("No active record client\n"); } + write(fd, result.string(), result.size()); dumpBase(fd, args); - dumpEffectChains(fd, args); +} - return NO_ERROR; +void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + snprintf(buffer, SIZE, "Input thread %p tracks\n", this); + result.append(buffer); + RecordTrack::appendDumpHeader(result); + for (size_t i = 0; i < mTracks.size(); ++i) { + sp<RecordTrack> track = mTracks[i]; + if (track != 0) { + track->dump(buffer, SIZE); + result.append(buffer); + } + } + + if (mActiveTrack != 0) { + snprintf(buffer, SIZE, "\nInput thread %p active tracks\n", this); + result.append(buffer); + RecordTrack::appendDumpHeader(result); + mActiveTrack->dump(buffer, SIZE); + result.append(buffer); + + } + write(fd, result.string(), result.size()); } // AudioBufferProvider interface @@ -6432,7 +6487,7 @@ status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* if (mActiveTrack->mState == TrackBase::ACTIVE) { // Force input into standby so that it tries to // recover at next read attempt - mInput->stream->common.standby(&mInput->stream->common); + inputStandBy(); usleep(kRecordThreadSleepUs); } buffer->raw = NULL; @@ -6508,25 +6563,30 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l() // store input device and output device but do not forward output device to audio HAL. // Note that status is ignored by the caller for output device // (see AudioFlinger::setParameters() + audio_devices_t newDevice = mDevice; if (value & AUDIO_DEVICE_OUT_ALL) { - mDevice &= (uint32_t)~(value & AUDIO_DEVICE_OUT_ALL); + newDevice &= ~(value & AUDIO_DEVICE_OUT_ALL); status = BAD_VALUE; } else { - mDevice &= (uint32_t)~(value & AUDIO_DEVICE_IN_ALL); + newDevice &= ~(value & AUDIO_DEVICE_IN_ALL); // disable AEC and NS if the device is a BT SCO headset supporting those pre processings - if (mTrack != NULL) { + if (mTracks.size() > 0) { bool suspend = audio_is_bluetooth_sco_device( (audio_devices_t)value) && mAudioFlinger->btNrecIsOff(); - setEffectSuspended_l(FX_IID_AEC, suspend, mTrack->sessionId()); - setEffectSuspended_l(FX_IID_NS, suspend, mTrack->sessionId()); + for (size_t i = 0; i < mTracks.size(); i++) { + sp<RecordTrack> track = mTracks[i]; + setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId()); + setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId()); + } } } - mDevice |= (uint32_t)value; + newDevice |= value; + mDevice = newDevice; // since mDevice is read by other threads, only write to it once } if (status == NO_ERROR) { status = mInput->stream->common.set_parameters(&mInput->stream->common, keyValuePair.string()); if (status == INVALID_OPERATION) { - mInput->stream->common.standby(&mInput->stream->common); + inputStandBy(); status = mInput->stream->common.set_parameters(&mInput->stream->common, keyValuePair.string()); } @@ -6656,23 +6716,28 @@ uint32_t AudioFlinger::RecordThread::hasAudioSession(int sessionId) result = EFFECT_SESSION; } - if (mTrack != NULL && sessionId == mTrack->sessionId()) { - result |= TRACK_SESSION; + for (size_t i = 0; i < mTracks.size(); ++i) { + if (sessionId == mTracks[i]->sessionId()) { + result |= TRACK_SESSION; + break; + } } return result; } -AudioFlinger::RecordThread::RecordTrack* AudioFlinger::RecordThread::track() +KeyedVector<int, bool> AudioFlinger::RecordThread::sessionIds() { + KeyedVector<int, bool> ids; Mutex::Autolock _l(mLock); - return mTrack; -} - -AudioFlinger::AudioStreamIn* AudioFlinger::RecordThread::getInput() const -{ - Mutex::Autolock _l(mLock); - return mInput; + for (size_t j = 0; j < mTracks.size(); ++j) { + sp<RecordThread::RecordTrack> track = mTracks[j]; + int sessionId = track->sessionId(); + if (ids.indexOfKey(sessionId) < 0) { + ids.add(sessionId, true); + } + } + return ids; } AudioFlinger::AudioStreamIn* AudioFlinger::RecordThread::clearInput() @@ -6730,16 +6795,52 @@ audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name) return 0; } - if ((mMasterVolumeSupportLvl != MVS_NONE) && - (NULL != dev->set_master_volume)) { + // Check and cache this HAL's level of support for master mute and master + // volume. If this is the first HAL opened, and it supports the get + // methods, use the initial values provided by the HAL as the current + // master mute and volume settings. + + AudioHwDevice::Flags flags = static_cast<AudioHwDevice::Flags>(0); + { // scope for auto-lock pattern AutoMutex lock(mHardwareLock); + + if (0 == mAudioHwDevs.size()) { + mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME; + if (NULL != dev->get_master_volume) { + float mv; + if (OK == dev->get_master_volume(dev, &mv)) { + mMasterVolume = mv; + } + } + + mHardwareStatus = AUDIO_HW_GET_MASTER_MUTE; + if (NULL != dev->get_master_mute) { + bool mm; + if (OK == dev->get_master_mute(dev, &mm)) { + mMasterMute = mm; + } + } + } + mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; - dev->set_master_volume(dev, mMasterVolume); + if ((NULL != dev->set_master_volume) && + (OK == dev->set_master_volume(dev, mMasterVolume))) { + flags = static_cast<AudioHwDevice::Flags>(flags | + AudioHwDevice::AHWD_CAN_SET_MASTER_VOLUME); + } + + mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE; + if ((NULL != dev->set_master_mute) && + (OK == dev->set_master_mute(dev, mMasterMute))) { + flags = static_cast<AudioHwDevice::Flags>(flags | + AudioHwDevice::AHWD_CAN_SET_MASTER_MUTE); + } + mHardwareStatus = AUDIO_HW_IDLE; } audio_module_handle_t handle = nextUniqueId(); - mAudioHwDevs.add(handle, new AudioHwDevice(name, dev)); + mAudioHwDevs.add(handle, new AudioHwDevice(name, dev, flags)); ALOGI("loadHwModule() Loaded %s audio interface from %s (%s) handle %d", name, dev->common.module->name, dev->common.module->id, handle); @@ -6764,11 +6865,11 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module, format: pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT, }; audio_stream_out_t *outStream = NULL; - audio_hw_device_t *outHwDev; + AudioHwDevice *outHwDev; ALOGV("openOutput(), module %d Device %x, SamplingRate %d, Format %d, Channels %x, flags %x", module, - (pDevices != NULL) ? (int)*pDevices : 0, + (pDevices != NULL) ? *pDevices : 0, config.sample_rate, config.format, config.channel_mask, @@ -6784,11 +6885,12 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module, if (outHwDev == NULL) return 0; + audio_hw_device_t *hwDevHal = outHwDev->hwDevice(); audio_io_handle_t id = nextUniqueId(); mHardwareStatus = AUDIO_HW_OUTPUT_OPEN; - status = outHwDev->open_output_stream(outHwDev, + status = hwDevHal->open_output_stream(hwDevHal, id, *pDevices, (audio_output_flags_t)flags, @@ -6832,41 +6934,8 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module, AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_SET_MODE; - outHwDev->set_mode(outHwDev, mMode); - - // Determine the level of master volume support the primary audio HAL has, - // and set the initial master volume at the same time. - float initialVolume = 1.0; - mMasterVolumeSupportLvl = MVS_NONE; - - mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME; - if ((NULL != outHwDev->get_master_volume) && - (NO_ERROR == outHwDev->get_master_volume(outHwDev, &initialVolume))) { - mMasterVolumeSupportLvl = MVS_FULL; - } else { - mMasterVolumeSupportLvl = MVS_SETONLY; - initialVolume = 1.0; - } - - mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; - if ((NULL == outHwDev->set_master_volume) || - (NO_ERROR != outHwDev->set_master_volume(outHwDev, initialVolume))) { - mMasterVolumeSupportLvl = MVS_NONE; - } - // now that we have a primary device, initialize master volume on other devices - for (size_t i = 0; i < mAudioHwDevs.size(); i++) { - audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice(); - - if ((dev != mPrimaryHardwareDev) && - (NULL != dev->set_master_volume)) { - dev->set_master_volume(dev, initialVolume); - } - } + hwDevHal->set_mode(hwDevHal, mMode); mHardwareStatus = AUDIO_HW_IDLE; - mMasterVolumeSW = (MVS_NONE == mMasterVolumeSupportLvl) - ? initialVolume - : 1.0; - mMasterVolume = initialVolume; } return id; } @@ -6897,6 +6966,11 @@ audio_io_handle_t AudioFlinger::openDuplicateOutput(audio_io_handle_t output1, status_t AudioFlinger::closeOutput(audio_io_handle_t output) { + return closeOutput_nonvirtual(output); +} + +status_t AudioFlinger::closeOutput_nonvirtual(audio_io_handle_t output) +{ // keep strong reference on the playback thread so that // it is not destroyed while exit() is executed sp<PlaybackThread> thread; @@ -6928,7 +7002,7 @@ status_t AudioFlinger::closeOutput(audio_io_handle_t output) AudioStreamOut *out = thread->clearOutput(); ALOG_ASSERT(out != NULL, "out shouldn't be NULL"); // from now on thread->mOutput is NULL - out->hwDev->close_output_stream(out->hwDev, out->stream); + out->hwDev()->close_output_stream(out->hwDev(), out->stream); delete out; } return NO_ERROR; @@ -6969,7 +7043,7 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, audio_devices_t *pDevices, uint32_t *pSamplingRate, audio_format_t *pFormat, - uint32_t *pChannelMask) + audio_channel_mask_t *pChannelMask) { status_t status; RecordThread *thread = NULL; @@ -6982,7 +7056,7 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, audio_format_t reqFormat = config.format; audio_channel_mask_t reqChannels = config.channel_mask; audio_stream_in_t *inStream = NULL; - audio_hw_device_t *inHwDev; + AudioHwDevice *inHwDev; if (pDevices == NULL || *pDevices == 0) { return 0; @@ -6994,9 +7068,10 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, if (inHwDev == NULL) return 0; + audio_hw_device_t *inHwHal = inHwDev->hwDevice(); audio_io_handle_t id = nextUniqueId(); - status = inHwDev->open_input_stream(inHwDev, id, *pDevices, &config, + status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config, &inStream); ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, status %d", inStream, @@ -7012,9 +7087,9 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, reqFormat == config.format && config.format == AUDIO_FORMAT_PCM_16_BIT && (config.sample_rate <= 2 * reqSamplingRate) && (popcount(config.channel_mask) <= FCC_2) && (popcount(reqChannels) <= FCC_2)) { - ALOGV("openInput() reopening with proposed sampling rate and channels"); + ALOGV("openInput() reopening with proposed sampling rate and channel mask"); inStream = NULL; - status = inHwDev->open_input_stream(inHwDev, id, *pDevices, &config, &inStream); + status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config, &inStream); } if (status == NO_ERROR && inStream != NULL) { @@ -7023,7 +7098,7 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, // Start record thread // RecorThread require both input and output device indication to forward to audio // pre processing modules - uint32_t device = (*pDevices) | primaryOutputDevice_l(); + audio_devices_t device = (*pDevices) | primaryOutputDevice_l(); thread = new RecordThread(this, input, reqSamplingRate, @@ -7036,8 +7111,6 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, if (pFormat != NULL) *pFormat = config.format; if (pChannelMask != NULL) *pChannelMask = reqChannels; - input->stream->common.standby(&input->stream->common); - // notify client processes of the new input creation thread->audioConfigChanged_l(AudioSystem::INPUT_OPENED); return id; @@ -7048,13 +7121,18 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, status_t AudioFlinger::closeInput(audio_io_handle_t input) { + return closeInput_nonvirtual(input); +} + +status_t AudioFlinger::closeInput_nonvirtual(audio_io_handle_t input) +{ // keep strong reference on the record thread so that // it is not destroyed while exit() is executed sp<RecordThread> thread; { Mutex::Autolock _l(mLock); thread = checkRecordThread_l(input); - if (thread == NULL) { + if (thread == 0) { return BAD_VALUE; } @@ -7069,7 +7147,7 @@ status_t AudioFlinger::closeInput(audio_io_handle_t input) AudioStreamIn *in = thread->clearInput(); ALOG_ASSERT(in != NULL, "in shouldn't be NULL"); // from now on thread->mInput is NULL - in->hwDev->close_input_stream(in->hwDev, in->stream); + in->hwDev()->close_input_stream(in->hwDev(), in->stream); delete in; return NO_ERROR; @@ -7078,21 +7156,11 @@ status_t AudioFlinger::closeInput(audio_io_handle_t input) status_t AudioFlinger::setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output) { Mutex::Autolock _l(mLock); - MixerThread *dstThread = checkMixerThread_l(output); - if (dstThread == NULL) { - ALOGW("setStreamOutput() bad output id %d", output); - return BAD_VALUE; - } - ALOGV("setStreamOutput() stream %d to output %d", stream, output); - audioConfigChanged_l(AudioSystem::STREAM_CONFIG_CHANGED, output, &stream); for (size_t i = 0; i < mPlaybackThreads.size(); i++) { PlaybackThread *thread = mPlaybackThreads.valueAt(i).get(); - if (thread != dstThread && thread->type() != ThreadBase::DIRECT) { - MixerThread *srcThread = (MixerThread *)thread; - srcThread->invalidateTracks(stream); - } + thread->invalidateTracks(stream); } return NO_ERROR; @@ -7186,20 +7254,14 @@ void AudioFlinger::purgeStaleEffects_l() { } } if (!found) { + Mutex::Autolock _l (t->mLock); // remove all effects from the chain while (ec->mEffects.size()) { sp<EffectModule> effect = ec->mEffects[0]; effect->unPin(); - Mutex::Autolock _l (t->mLock); t->removeEffect_l(effect); - for (size_t j = 0; j < effect->mHandles.size(); j++) { - sp<EffectHandle> handle = effect->mHandles[j].promote(); - if (handle != 0) { - handle->mEffect.clear(); - if (handle->mHasControl && handle->mEnabled) { - t->checkSuspendOnEffectEnabled_l(effect, false, effect->sessionId()); - } - } + if (effect->purgeHandles()) { + t->checkSuspendOnEffectEnabled_l(effect, false, effect->sessionId()); } AudioSystem::unregisterEffect(effect->id()); } @@ -7237,14 +7299,14 @@ AudioFlinger::PlaybackThread *AudioFlinger::primaryPlaybackThread_l() const for (size_t i = 0; i < mPlaybackThreads.size(); i++) { PlaybackThread *thread = mPlaybackThreads.valueAt(i).get(); AudioStreamOut *output = thread->getOutput(); - if (output != NULL && output->hwDev == mPrimaryHardwareDev) { + if (output != NULL && output->audioHwDev == mPrimaryHardwareDev) { return thread; } } return NULL; } -uint32_t AudioFlinger::primaryOutputDevice_l() const +audio_devices_t AudioFlinger::primaryOutputDevice_l() const { PlaybackThread *thread = primaryPlaybackThread_l(); @@ -7401,7 +7463,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, // 0 and the effect is not auxiliary, continue enumeration in case // an auxiliary version of this effect type is available found = true; - memcpy(&d, &desc, sizeof(effect_descriptor_t)); + d = desc; if (sessionId != AUDIO_SESSION_OUTPUT_MIX || (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { break; @@ -7417,7 +7479,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, // connect to output mix (Compliance to OpenSL ES) if (sessionId == AUDIO_SESSION_OUTPUT_MIX && (d.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) { - memcpy(&desc, &d, sizeof(effect_descriptor_t)); + desc = d; } } @@ -7436,7 +7498,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, } // return effect descriptor - memcpy(pDesc, &desc, sizeof(effect_descriptor_t)); + *pDesc = desc; // If output is not specified try to find a matching audio session ID in one of the // output threads. @@ -7670,7 +7732,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l( } // create effect handle and connect it to effect module handle = new EffectHandle(effect, client, effectClient, priority); - lStatus = effect->addHandle(handle); + lStatus = effect->addHandle(handle.get()); if (enabled != NULL) { *enabled = (int)effect->isEnabled(); } @@ -7810,7 +7872,7 @@ void AudioFlinger::ThreadBase::setMode(audio_mode_t mode) } void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect, - const wp<EffectHandle>& handle, + EffectHandle *handle, bool unpinIfLast) { Mutex::Autolock _l(mLock); @@ -8002,16 +8064,18 @@ AudioFlinger::EffectModule::EffectModule(ThreadBase *thread, effect_descriptor_t *desc, int id, int sessionId) - : mThread(thread), mChain(chain), mId(id), mSessionId(sessionId), mEffectInterface(NULL), - mStatus(NO_INIT), mState(IDLE), mSuspended(false) + : mPinned(sessionId > AUDIO_SESSION_OUTPUT_MIX), + mThread(thread), mChain(chain), mId(id), mSessionId(sessionId), + mDescriptor(*desc), + // mConfig is set by configure() and not used before then + mEffectInterface(NULL), + mStatus(NO_INIT), mState(IDLE), + // mMaxDisableWaitCnt is set by configure() and not used before then + // mDisableWaitCnt is set by process() and updateState() and not used before then + mSuspended(false) { ALOGV("Constructor %p", this); int lStatus; - if (thread == NULL) { - return; - } - - memcpy(&mDescriptor, desc, sizeof(effect_descriptor_t)); // create effect engine from effect factory mStatus = EffectCreate(&desc->uuid, sessionId, thread->id(), &mEffectInterface); @@ -8025,9 +8089,6 @@ AudioFlinger::EffectModule::EffectModule(ThreadBase *thread, goto Error; } - if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) { - mPinned = true; - } ALOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface); return; Error: @@ -8055,38 +8116,41 @@ AudioFlinger::EffectModule::~EffectModule() } } -status_t AudioFlinger::EffectModule::addHandle(const sp<EffectHandle>& handle) +status_t AudioFlinger::EffectModule::addHandle(EffectHandle *handle) { status_t status; Mutex::Autolock _l(mLock); int priority = handle->priority(); size_t size = mHandles.size(); - sp<EffectHandle> h; + EffectHandle *controlHandle = NULL; size_t i; for (i = 0; i < size; i++) { - h = mHandles[i].promote(); - if (h == 0) continue; + EffectHandle *h = mHandles[i]; + if (h == NULL || h->destroyed_l()) continue; + // first non destroyed handle is considered in control + if (controlHandle == NULL) + controlHandle = h; if (h->priority() <= priority) break; } // if inserted in first place, move effect control from previous owner to this handle if (i == 0) { bool enabled = false; - if (h != 0) { - enabled = h->enabled(); - h->setControl(false/*hasControl*/, true /*signal*/, enabled /*enabled*/); + if (controlHandle != NULL) { + enabled = controlHandle->enabled(); + controlHandle->setControl(false/*hasControl*/, true /*signal*/, enabled /*enabled*/); } handle->setControl(true /*hasControl*/, false /*signal*/, enabled /*enabled*/); status = NO_ERROR; } else { status = ALREADY_EXISTS; } - ALOGV("addHandle() %p added handle %p in position %d", this, handle.get(), i); + ALOGV("addHandle() %p added handle %p in position %d", this, handle, i); mHandles.insertAt(handle, i); return status; } -size_t AudioFlinger::EffectModule::removeHandle(const wp<EffectHandle>& handle) +size_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle) { Mutex::Autolock _l(mLock); size_t size = mHandles.size(); @@ -8097,43 +8161,44 @@ size_t AudioFlinger::EffectModule::removeHandle(const wp<EffectHandle>& handle) if (i == size) { return size; } - ALOGV("removeHandle() %p removed handle %p in position %d", this, handle.unsafe_get(), i); + ALOGV("removeHandle() %p removed handle %p in position %d", this, handle, i); - bool enabled = false; - EffectHandle *hdl = handle.unsafe_get(); - if (hdl != NULL) { - ALOGV("removeHandle() unsafe_get OK"); - enabled = hdl->enabled(); - } mHandles.removeAt(i); - size = mHandles.size(); // if removed from first place, move effect control from this handle to next in line - if (i == 0 && size != 0) { - sp<EffectHandle> h = mHandles[0].promote(); - if (h != 0) { - h->setControl(true /*hasControl*/, true /*signal*/ , enabled /*enabled*/); + if (i == 0) { + EffectHandle *h = controlHandle_l(); + if (h != NULL) { + h->setControl(true /*hasControl*/, true /*signal*/ , handle->enabled() /*enabled*/); } } // Prevent calls to process() and other functions on effect interface from now on. // The effect engine will be released by the destructor when the last strong reference on // this object is released which can happen after next process is called. - if (size == 0 && !mPinned) { + if (mHandles.size() == 0 && !mPinned) { mState = DESTROYED; } - return size; + return mHandles.size(); } -sp<AudioFlinger::EffectHandle> AudioFlinger::EffectModule::controlHandle() +// must be called with EffectModule::mLock held +AudioFlinger::EffectHandle *AudioFlinger::EffectModule::controlHandle_l() { - Mutex::Autolock _l(mLock); - return mHandles.size() != 0 ? mHandles[0].promote() : 0; + // the first valid handle in the list has control over the module + for (size_t i = 0; i < mHandles.size(); i++) { + EffectHandle *h = mHandles[i]; + if (h != NULL && !h->destroyed_l()) { + return h; + } + } + + return NULL; } -void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool unpinIfLast) +size_t AudioFlinger::EffectModule::disconnect(EffectHandle *handle, bool unpinIfLast) { - ALOGV("disconnect() %p handle %p", this, handle.unsafe_get()); + ALOGV("disconnect() %p handle %p", this, handle); // keep a strong reference on this EffectModule to avoid calling the // destructor before we exit sp<EffectModule> keep(this); @@ -8143,6 +8208,7 @@ void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool thread->disconnectEffect(keep, handle, unpinIfLast); } } + return mHandles.size(); } void AudioFlinger::EffectModule::updateState() { @@ -8240,7 +8306,6 @@ void AudioFlinger::EffectModule::reset_l() status_t AudioFlinger::EffectModule::configure() { - uint32_t channels; if (mEffectInterface == NULL) { return NO_INIT; } @@ -8251,18 +8316,14 @@ status_t AudioFlinger::EffectModule::configure() } // TODO: handle configuration of effects replacing track process - if (thread->channelCount() == 1) { - channels = AUDIO_CHANNEL_OUT_MONO; - } else { - channels = AUDIO_CHANNEL_OUT_STEREO; - } + audio_channel_mask_t channelMask = thread->channelMask(); if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_MONO; } else { - mConfig.inputCfg.channels = channels; + mConfig.inputCfg.channels = channelMask; } - mConfig.outputCfg.channels = channels; + mConfig.outputCfg.channels = channelMask; mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; mConfig.inputCfg.samplingRate = thread->sampleRate(); @@ -8452,8 +8513,8 @@ status_t AudioFlinger::EffectModule::command(uint32_t cmdCode, if (cmdCode != EFFECT_CMD_GET_PARAM && status == NO_ERROR) { uint32_t size = (replySize == NULL) ? 0 : *replySize; for (size_t i = 1; i < mHandles.size(); i++) { - sp<EffectHandle> h = mHandles[i].promote(); - if (h != 0) { + EffectHandle *h = mHandles[i]; + if (h != NULL && !h->destroyed_l()) { h->commandExecuted(cmdCode, cmdSize, pCmdData, size, pReplyData); } } @@ -8463,8 +8524,14 @@ status_t AudioFlinger::EffectModule::command(uint32_t cmdCode, status_t AudioFlinger::EffectModule::setEnabled(bool enabled) { - Mutex::Autolock _l(mLock); + return setEnabled_l(enabled); +} + +// must be called with EffectModule::mLock held +status_t AudioFlinger::EffectModule::setEnabled_l(bool enabled) +{ + ALOGV("setEnabled %p enabled %d", this, enabled); if (enabled != isEnabled()) { @@ -8499,8 +8566,8 @@ status_t AudioFlinger::EffectModule::setEnabled(bool enabled) return NO_ERROR; // simply ignore as we are being destroyed } for (size_t i = 1; i < mHandles.size(); i++) { - sp<EffectHandle> h = mHandles[i].promote(); - if (h != 0) { + EffectHandle *h = mHandles[i]; + if (h != NULL && !h->destroyed_l()) { h->setEnabled(enabled); } } @@ -8573,14 +8640,14 @@ status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, return status; } -status_t AudioFlinger::EffectModule::setDevice(uint32_t device) +status_t AudioFlinger::EffectModule::setDevice(audio_devices_t device) { Mutex::Autolock _l(mLock); status_t status = NO_ERROR; if (device && (mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) { // audio pre processing modules on RecordThread can receive both output and // input device indication in the same call - uint32_t dev = device & AUDIO_DEVICE_OUT_ALL; + audio_devices_t dev = device & AUDIO_DEVICE_OUT_ALL; if (dev) { status_t cmdStatus; uint32_t size = sizeof(status_t); @@ -8649,7 +8716,23 @@ bool AudioFlinger::EffectModule::suspended() const return mSuspended; } -status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args) +bool AudioFlinger::EffectModule::purgeHandles() +{ + bool enabled = false; + Mutex::Autolock _l(mLock); + for (size_t i = 0; i < mHandles.size(); i++) { + EffectHandle *handle = mHandles[i]; + if (handle != NULL && !handle->destroyed_l()) { + handle->effect().clear(); + if (handle->hasControl()) { + enabled = handle->enabled(); + } + } + } + return enabled; +} + +void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; @@ -8715,8 +8798,8 @@ status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args) result.append(buffer); result.append("\t\t\tPid Priority Ctrl Locked client server\n"); for (size_t i = 0; i < mHandles.size(); ++i) { - sp<EffectHandle> handle = mHandles[i].promote(); - if (handle != 0) { + EffectHandle *handle = mHandles[i]; + if (handle != NULL && !handle->destroyed_l()) { handle->dump(buffer, SIZE); result.append(buffer); } @@ -8729,8 +8812,6 @@ status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args) if (locked) { mLock.unlock(); } - - return NO_ERROR; } // ---------------------------------------------------------------------------- @@ -8746,7 +8827,7 @@ AudioFlinger::EffectHandle::EffectHandle(const sp<EffectModule>& effect, int32_t priority) : BnEffect(), mEffect(effect), mEffectClient(effectClient), mClient(client), mCblk(NULL), - mPriority(priority), mHasControl(false), mEnabled(false) + mPriority(priority), mHasControl(false), mEnabled(false), mDestroyed(false) { ALOGV("constructor %p", this); @@ -8771,8 +8852,15 @@ AudioFlinger::EffectHandle::EffectHandle(const sp<EffectModule>& effect, AudioFlinger::EffectHandle::~EffectHandle() { ALOGV("Destructor %p", this); + + if (mEffect == 0) { + mDestroyed = true; + return; + } + mEffect->lock(); + mDestroyed = true; + mEffect->unlock(); disconnect(false); - ALOGV("Destructor DONE %p", this); } status_t AudioFlinger::EffectHandle::enable() @@ -8843,9 +8931,8 @@ void AudioFlinger::EffectHandle::disconnect(bool unpinIfLast) if (mEffect == 0) { return; } - mEffect->disconnect(this, unpinIfLast); - - if (mHasControl && mEnabled) { + // restore suspended effects if the disconnected handle was enabled and the last one. + if ((mEffect->disconnect(this, unpinIfLast) == 0) && mEnabled) { sp<ThreadBase> thread = mEffect->thread().promote(); if (thread != 0) { thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId()); @@ -9275,7 +9362,7 @@ size_t AudioFlinger::EffectChain::removeEffect_l(const sp<EffectModule>& effect) } // setDevice_l() must be called with PlaybackThread::mLock held -void AudioFlinger::EffectChain::setDevice_l(uint32_t device) +void AudioFlinger::EffectChain::setDevice_l(audio_devices_t device) { size_t size = mEffects.size(); for (size_t i = 0; i < size; i++) { @@ -9350,7 +9437,7 @@ bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right) return hasControl; } -status_t AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args) +void AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; @@ -9384,8 +9471,6 @@ status_t AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args) if (locked) { mLock.unlock(); } - - return NO_ERROR; } // must be called with ThreadBase::mLock held @@ -9401,7 +9486,7 @@ void AudioFlinger::EffectChain::setEffectSuspended_l( desc = mSuspendedEffects.valueAt(index); } else { desc = new SuspendedEffectDesc(); - memcpy(&desc->mType, type, sizeof(effect_uuid_t)); + desc->mType = *type; mSuspendedEffects.add(type->timeLow, desc); ALOGV("setEffectSuspended_l() add entry for %08x", type->timeLow); } @@ -9428,10 +9513,12 @@ void AudioFlinger::EffectChain::setEffectSuspended_l( sp<EffectModule> effect = desc->mEffect.promote(); if (effect != 0) { effect->setSuspended(false); - sp<EffectHandle> handle = effect->controlHandle(); - if (handle != 0) { - effect->setEnabled(handle->enabled()); + effect->lock(); + EffectHandle *handle = effect->controlHandle_l(); + if (handle != NULL && !handle->destroyed_l()) { + effect->setEnabled_l(handle->enabled()); } + effect->unlock(); } desc->mEffect.clear(); } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index cfd718f..e5176a9 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -91,7 +91,7 @@ public: audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount, IAudioFlinger::track_flags_t flags, const sp<IMemory>& sharedBuffer, @@ -105,9 +105,10 @@ public: audio_io_handle_t input, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount, IAudioFlinger::track_flags_t flags, + pid_t tid, int *sessionId, status_t *status); @@ -121,7 +122,6 @@ public: virtual status_t setMasterMute(bool muted); virtual float masterVolume() const; - virtual float masterVolumeSW() const; virtual bool masterMute() const; virtual status_t setStreamVolume(audio_stream_type_t stream, float value, @@ -142,7 +142,8 @@ public: virtual void registerClient(const sp<IAudioFlingerClient>& client); - virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const; + virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, + audio_channel_mask_t channelMask) const; virtual audio_io_handle_t openOutput(audio_module_handle_t module, audio_devices_t *pDevices, @@ -255,6 +256,8 @@ public: void *cookie); private: + class AudioHwDevice; // fwd declaration for findSuitableHwDev_l + audio_mode_t getMode() const { return mMode; } bool btNrecIsOff() const { return mBtNrecIsOff; } @@ -268,17 +271,17 @@ private: // RefBase virtual void onFirstRef(); - audio_hw_device_t* findSuitableHwDev_l(audio_module_handle_t module, uint32_t devices); + AudioHwDevice* findSuitableHwDev_l(audio_module_handle_t module, audio_devices_t devices); void purgeStaleEffects_l(); // standby delay for MIXER and DUPLICATING playback threads is read from property // ro.audio.flinger_standbytime_ms or defaults to kDefaultStandbyTimeInNsecs static nsecs_t mStandbyTimeInNsecs; - // Internal dump utilites. - status_t dumpPermissionDenial(int fd, const Vector<String16>& args); - status_t dumpClients(int fd, const Vector<String16>& args); - status_t dumpInternals(int fd, const Vector<String16>& args); + // Internal dump utilities. + void dumpPermissionDenial(int fd, const Vector<String16>& args); + void dumpClients(int fd, const Vector<String16>& args); + void dumpInternals(int fd, const Vector<String16>& args); // --- Client --- class Client : public RefBase { @@ -350,11 +353,11 @@ private: RECORD // Thread class is RecordThread }; - ThreadBase (const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id, uint32_t device, type_t type); + ThreadBase (const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id, audio_devices_t device, type_t type); virtual ~ThreadBase(); - status_t dumpBase(int fd, const Vector<String16>& args); - status_t dumpEffectChains(int fd, const Vector<String16>& args); + void dumpBase(int fd, const Vector<String16>& args); + void dumpEffectChains(int fd, const Vector<String16>& args); void clearPowerManager(); @@ -380,14 +383,14 @@ private: const sp<Client>& client, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount, const sp<IMemory>& sharedBuffer, int sessionId); virtual ~TrackBase(); - virtual status_t start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE, - int triggerSession = 0) = 0; + virtual status_t start(AudioSystem::sync_event_t event, + int triggerSession) = 0; virtual void stop() = 0; sp<IMemory> getCblk() const { return mCblkMemory; } audio_track_cblk_t* cblk() const { return mCblk; } @@ -412,10 +415,17 @@ private: int channelCount() const { return mChannelCount; } - uint32_t channelMask() const { return mChannelMask; } + audio_channel_mask_t channelMask() const { return mChannelMask; } int sampleRate() const; // FIXME inline after cblk sr moved + // Return a pointer to the start of a contiguous slice of the track buffer. + // Parameter 'offset' is the requested start position, expressed in + // monotonically increasing frame units relative to the track epoch. + // Parameter 'frames' is the requested length, also in frame units. + // Always returns non-NULL. It is the caller's responsibility to + // verify that this will be successful; the result of calling this + // function with invalid 'offset' or 'frames' is undefined. void* getBuffer(uint32_t offset, uint32_t frames) const; bool isStopped() const { @@ -455,7 +465,7 @@ private: bool mStepServerFailed; const int mSessionId; uint8_t mChannelCount; - uint32_t mChannelMask; + audio_channel_mask_t mChannelMask; Vector < sp<SyncEvent> >mSyncEvents; }; @@ -483,14 +493,20 @@ private: }; virtual status_t initCheck() const = 0; + + // static externally-visible type_t type() const { return mType; } + audio_io_handle_t id() const { return mId;} + + // dynamic externally-visible uint32_t sampleRate() const { return mSampleRate; } int channelCount() const { return mChannelCount; } + audio_channel_mask_t channelMask() const { return mChannelMask; } audio_format_t format() const { return mFormat; } // Called by AudioFlinger::frameCount(audio_io_handle_t output) and effects, // and returns the normal mix buffer's frame count. No API for HAL frame count. size_t frameCount() const { return mNormalFrameCount; } - void wakeUp() { mWaitWorkCV.broadcast(); } + // Should be "virtual status_t requestExitAndWait()" and override same // method in Thread, but Thread::requestExitAndWait() is not yet virtual. void exit(); @@ -501,9 +517,11 @@ private: void sendConfigEvent(int event, int param = 0); void sendConfigEvent_l(int event, int param = 0); void processConfigEvents(); - audio_io_handle_t id() const { return mId;} + + // see note at declaration of mStandby and mDevice bool standby() const { return mStandby; } - uint32_t device() const { return mDevice; } + audio_devices_t device() const { return mDevice; } + virtual audio_stream_t* stream() const = 0; sp<EffectHandle> createEffect_l( @@ -515,7 +533,7 @@ private: int *enabled, status_t *status); void disconnectEffect(const sp< EffectModule>& effect, - const wp<EffectHandle>& handle, + EffectHandle *handle, bool unpinIfLast); // return values for hasAudioSession (bit field) @@ -598,7 +616,7 @@ private: void releaseWakeLock_l(); void setEffectSuspended_l(const effect_uuid_t *type, bool suspend, - int sessionId = AUDIO_SESSION_OUTPUT_MIX); + int sessionId); // updated mSuspendedSessions when an effect suspended or restored void updateSuspendedSessions_l(const effect_uuid_t *type, bool suspend, @@ -617,7 +635,7 @@ private: uint32_t mSampleRate; size_t mFrameCount; // output HAL, direct output, record size_t mNormalFrameCount; // normal mixer and effects - uint32_t mChannelMask; + audio_channel_mask_t mChannelMask; uint16_t mChannelCount; size_t mFrameSize; audio_format_t mFormat; @@ -646,11 +664,19 @@ private: status_t mParamStatus; Vector<ConfigEvent> mConfigEvents; - bool mStandby; + + // These fields are written and read by thread itself without lock or barrier, + // and read by other threads without lock or barrier via standby() and device(). + // Because of the absence of a lock or barrier, any other thread that reads + // these fields must use the information in isolation, or be prepared to deal + // with possibility that it might be inconsistent with other information. + bool mStandby; // Whether thread is currently in standby. + audio_devices_t mDevice; // output device for PlaybackThread + // input + output devices for RecordThread + const audio_io_handle_t mId; Vector< sp<EffectChain> > mEffectChains; - uint32_t mDevice; // output device for PlaybackThread - // input + output devices for RecordThread + static const int kNameLength = 16; // prctl(PR_SET_NAME) limit char mName[kNameLength]; sp<IPowerManager> mPowerManager; @@ -691,7 +717,7 @@ private: audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount, const sp<IMemory>& sharedBuffer, int sessionId, @@ -708,9 +734,7 @@ private: void flush(); void destroy(); void mute(bool); - int name() const { - return mName; - } + int name() const { return mName; } audio_stream_type_t streamType() const { return mStreamType; @@ -767,10 +791,14 @@ private: void triggerEvents(AudioSystem::sync_event_t type); virtual bool isTimedTrack() const { return false; } bool isFastTrack() const { return (mFlags & IAudioFlinger::TRACK_FAST) != 0; } + protected: - // we don't really need a lock for these - volatile bool mMute; + // written by Track::mute() called by binder thread(s), without a mutex or barrier. + // read by Track::isMuted() called by playback thread, also without a mutex or barrier. + // The lack of mutex or barrier is safe because the mute status is only used by itself. + bool mMute; + // FILLED state is used for suppressing volume ramp at begin of playing enum {FS_INVALID, FS_FILLING, FS_FILLED, FS_ACTIVE}; mutable uint8_t mFillingUpStatus; @@ -813,11 +841,11 @@ private: audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount, const sp<IMemory>& sharedBuffer, int sessionId); - ~TimedTrack(); + virtual ~TimedTrack(); class TimedBuffer { public: @@ -856,7 +884,7 @@ private: audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount, const sp<IMemory>& sharedBuffer, int sessionId); @@ -905,7 +933,7 @@ private: DuplicatingThread *sourceThread, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount); virtual ~OutputTrack(); @@ -936,10 +964,10 @@ private: }; // end of OutputTrack PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, - audio_io_handle_t id, uint32_t device, type_t type); + audio_io_handle_t id, audio_devices_t device, type_t type); virtual ~PlaybackThread(); - status_t dump(int fd, const Vector<String16>& args); + void dump(int fd, const Vector<String16>& args); // Thread virtuals virtual status_t readyToRun(); @@ -984,7 +1012,7 @@ public: audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount, const sp<IMemory>& sharedBuffer, int sessionId, @@ -996,9 +1024,19 @@ public: AudioStreamOut* clearOutput(); virtual audio_stream_t* stream() const; - void suspend() { mSuspended++; } - void restore() { if (mSuspended > 0) mSuspended--; } - bool isSuspended() const { return (mSuspended > 0); } + // a very large number of suspend() will eventually wraparound, but unlikely + void suspend() { (void) android_atomic_inc(&mSuspended); } + void restore() + { + // if restore() is done without suspend(), get back into + // range so that the next suspend() will operate correctly + if (android_atomic_dec(&mSuspended) <= 0) { + android_atomic_release_store(0, &mSuspended); + } + } + bool isSuspended() const + { return android_atomic_acquire_load(&mSuspended) > 0; } + virtual String8 getParameters(const String8& keys); virtual void audioConfigChanged_l(int event, int param = 0); status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames); @@ -1018,10 +1056,19 @@ public: virtual status_t setSyncEvent(const sp<SyncEvent>& event); virtual bool isValidSyncEvent(const sp<SyncEvent>& event); + void invalidateTracks(audio_stream_type_t streamType); + protected: int16_t* mMixBuffer; - uint32_t mSuspended; // suspend count, > 0 means suspended + + // suspend count, > 0 means suspended. While suspended, the thread continues to pull from + // tracks and mix, but doesn't write to HAL. A2DP and SCO HAL implementations can't handle + // concurrent use of both of them, so Audio Policy Service suspends one of the threads to + // workaround that restriction. + // 'volatile' means accessed via atomic operations and no lock. + volatile int32_t mSuspended; + int mBytesWritten; private: // mMasterMute is in both PlaybackThread and in AudioFlinger. When a @@ -1069,13 +1116,14 @@ public: void readOutputParameters(); - virtual status_t dumpInternals(int fd, const Vector<String16>& args); - status_t dumpTracks(int fd, const Vector<String16>& args); + virtual void dumpInternals(int fd, const Vector<String16>& args); + 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]; AudioStreamOut *mOutput; + float mMasterVolume; nsecs_t mLastWriteTime; int mNumWrites; @@ -1100,7 +1148,6 @@ public: // FIXME move these declarations into the specific sub-class that needs them // MIXER only - bool longStandbyExit; uint32_t sleepTimeShift; // same as AudioFlinger::mStandbyTimeInNsecs except for DIRECT which uses a shorter value @@ -1139,15 +1186,14 @@ public: MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, audio_io_handle_t id, - uint32_t device, + audio_devices_t device, type_t type = MIXER); virtual ~MixerThread(); // Thread virtuals - void invalidateTracks(audio_stream_type_t streamType); virtual bool checkForNewParameters_l(); - virtual status_t dumpInternals(int fd, const Vector<String16>& args); + virtual void dumpInternals(int fd, const Vector<String16>& args); protected: virtual mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove); @@ -1167,9 +1213,6 @@ public: AudioMixer* mAudioMixer; // normal mixer private: -#ifdef SOAKER - Thread* mSoaker; -#endif // one-time initialization, no locks required FastMixer* mFastMixer; // non-NULL if there is also a fast mixer sp<AudioWatchdog> mAudioWatchdog; // non-0 if there is an audio watchdog thread @@ -1198,7 +1241,7 @@ public: public: DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, - audio_io_handle_t id, uint32_t device); + audio_io_handle_t id, audio_devices_t device); virtual ~DirectOutputThread(); // Thread virtuals @@ -1287,7 +1330,7 @@ private: bool reRegister); // return thread associated with primary hardware device, or NULL PlaybackThread *primaryPlaybackThread_l() const; - uint32_t primaryOutputDevice_l() const; + audio_devices_t primaryOutputDevice_l() const; sp<PlaybackThread> getEffectThread_l(int sessionId, int EffectId); @@ -1331,18 +1374,22 @@ private: const sp<Client>& client, uint32_t sampleRate, audio_format_t format, - uint32_t channelMask, + audio_channel_mask_t channelMask, int frameCount, int sessionId); virtual ~RecordTrack(); - virtual status_t start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE, - int triggerSession = 0); + virtual status_t start(AudioSystem::sync_event_t event, int triggerSession); virtual void stop(); - bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; } + void destroy(); + + // clear the buffer overflow flag + void clearOverflow() { mOverflow = false; } + // set the buffer overflow flag and return previous value bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; } + static void appendDumpHeader(String8& result); void dump(char* buffer, size_t size); private: @@ -1355,18 +1402,24 @@ private: virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts = kInvalidPTS); // releaseBuffer() not overridden - bool mOverflow; + bool mOverflow; // overflow on most recent attempt to fill client buffer }; - RecordThread(const sp<AudioFlinger>& audioFlinger, AudioStreamIn *input, uint32_t sampleRate, - uint32_t channels, + audio_channel_mask_t channelMask, audio_io_handle_t id, - uint32_t device); + audio_devices_t device); virtual ~RecordThread(); + // no addTrack_l ? + void destroyTrack_l(const sp<RecordTrack>& track); + void removeTrack_l(const sp<RecordTrack>& track); + + void dumpInternals(int fd, const Vector<String16>& args); + void dumpTracks(int fd, const Vector<String16>& args); + // Thread virtual bool threadLoop(); virtual status_t readyToRun(); @@ -1379,17 +1432,22 @@ private: const sp<AudioFlinger::Client>& client, uint32_t sampleRate, audio_format_t format, - int channelMask, + audio_channel_mask_t channelMask, int frameCount, int sessionId, + IAudioFlinger::track_flags_t flags, + pid_t tid, status_t *status); status_t start(RecordTrack* recordTrack, AudioSystem::sync_event_t event, int triggerSession); - void stop(RecordTrack* recordTrack); - status_t dump(int fd, const Vector<String16>& args); - AudioStreamIn* getInput() const; + + // ask the thread to stop the specified track, and + // return true if the caller should then do it's part of the stopping process + bool stop_l(RecordTrack* recordTrack); + + void dump(int fd, const Vector<String16>& args); AudioStreamIn* clearInput(); virtual audio_stream_t* stream() const; @@ -1406,7 +1464,11 @@ private: virtual status_t addEffectChain_l(const sp<EffectChain>& chain); virtual size_t removeEffectChain_l(const sp<EffectChain>& chain); virtual uint32_t hasAudioSession(int sessionId); - RecordTrack* track(); + + // Return the set of unique session IDs across all tracks. + // The keys are the session IDs, and the associated values are meaningless. + // FIXME replace by Set [and implement Bag/Multiset for other uses]. + KeyedVector<int, bool> sessionIds(); virtual status_t setSyncEvent(const sp<SyncEvent>& event); virtual bool isValidSyncEvent(const sp<SyncEvent>& event); @@ -1417,9 +1479,16 @@ private: private: void clearSyncStartEvent(); - RecordThread(); + // Enter standby if not already in standby, and set mStandby flag + void standby(); + + // Call the HAL standby method unconditionally, and don't change mStandby flag + void inputStandBy(); + AudioStreamIn *mInput; - RecordTrack* mTrack; + SortedVector < sp<RecordTrack> > mTracks; + // mActiveTrack has dual roles: it indicates the current active track, and + // is used together with mStartStopCond to indicate start()/stop() progress sp<RecordTrack> mActiveTrack; Condition mStartStopCond; AudioResampler *mResampler; @@ -1445,12 +1514,15 @@ private: RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack); virtual ~RecordHandle(); virtual sp<IMemory> getCblk() const; - virtual status_t start(int event, int triggerSession); + virtual status_t start(int /*AudioSystem::sync_event_t*/ event, int triggerSession); virtual void stop(); virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); private: const sp<RecordThread::RecordTrack> mRecordTrack; + + // for use from destructor + void stop_nonvirtual(); }; //--- Audio Effect Management @@ -1510,6 +1582,7 @@ private: return mSessionId; } status_t setEnabled(bool enabled); + status_t setEnabled_l(bool enabled); bool isEnabled() const; bool isProcessEnabled() const; @@ -1521,14 +1594,14 @@ private: void setThread(const wp<ThreadBase>& thread) { mThread = thread; } const wp<ThreadBase>& thread() { return mThread; } - status_t addHandle(const sp<EffectHandle>& handle); - void disconnect(const wp<EffectHandle>& handle, bool unpinIfLast); - size_t removeHandle (const wp<EffectHandle>& handle); + status_t addHandle(EffectHandle *handle); + size_t disconnect(EffectHandle *handle, bool unpinIfLast); + size_t removeHandle(EffectHandle *handle); - effect_descriptor_t& desc() { return mDescriptor; } + const effect_descriptor_t& desc() const { return mDescriptor; } wp<EffectChain>& chain() { return mChain; } - status_t setDevice(uint32_t device); + status_t setDevice(audio_devices_t device); status_t setVolume(uint32_t *left, uint32_t *right, bool controller); status_t setMode(audio_mode_t mode); status_t start(); @@ -1536,12 +1609,15 @@ private: void setSuspended(bool suspended); bool suspended() const; - sp<EffectHandle> controlHandle(); + EffectHandle* controlHandle_l(); bool isPinned() const { return mPinned; } void unPin() { mPinned = false; } + bool purgeHandles(); + void lock() { mLock.lock(); } + void unlock() { mLock.unlock(); } - status_t dump(int fd, const Vector<String16>& args); + void dump(int fd, const Vector<String16>& args); protected: friend class AudioFlinger; // for mHandles @@ -1559,14 +1635,14 @@ private: mutable Mutex mLock; // mutex for process, commands and handles list protection wp<ThreadBase> mThread; // parent thread wp<EffectChain> mChain; // parent effect chain - int mId; // this instance unique ID - int mSessionId; // audio session ID - effect_descriptor_t mDescriptor;// effect descriptor received from effect engine + const int mId; // this instance unique ID + const int mSessionId; // audio session ID + const effect_descriptor_t mDescriptor;// effect descriptor received from effect engine effect_config_t mConfig; // input and output audio configuration effect_handle_t mEffectInterface; // Effect module C API status_t mStatus; // initialization status effect_state mState; // current activation state - Vector< wp<EffectHandle> > mHandles; // list of client handles + Vector<EffectHandle *> mHandles; // list of client handles // First handle in mHandles has highest priority and controls the effect module uint32_t mMaxDisableWaitCnt; // maximum grace period before forcing an effect off after // sending disable command. @@ -1624,6 +1700,8 @@ mutable Mutex mLock; // mutex for process, commands and handl int priority() const { return mPriority; } bool hasControl() const { return mHasControl; } sp<EffectModule> effect() const { return mEffect; } + // destroyed_l() must be called with the associated EffectModule mLock held + bool destroyed_l() const { return mDestroyed; } void dump(char* buffer, size_t size); @@ -1642,6 +1720,8 @@ mutable Mutex mLock; // mutex for process, commands and handl bool mHasControl; // true if this handle is controlling the effect bool mEnabled; // cached enable state: needed when the effect is // restored after being suspended + bool mDestroyed; // Set to true by destructor. Access with EffectModule + // mLock held }; // the EffectChain class represents a group of effects associated to one audio session. @@ -1684,7 +1764,7 @@ mutable Mutex mLock; // mutex for process, commands and handl sp<EffectModule> getEffectFromId_l(int id); sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type); bool setVolume_l(uint32_t *left, uint32_t *right); - void setDevice_l(uint32_t device); + void setDevice_l(audio_devices_t device); void setMode_l(audio_mode_t mode); void setInBuffer(int16_t *buffer, bool ownsBuffer = false) { @@ -1703,12 +1783,12 @@ mutable Mutex mLock; // mutex for process, commands and handl void incTrackCnt() { android_atomic_inc(&mTrackCnt); } void decTrackCnt() { android_atomic_dec(&mTrackCnt); } - int32_t trackCnt() const { return mTrackCnt;} + int32_t trackCnt() const { return android_atomic_acquire_load(&mTrackCnt); } void incActiveTrackCnt() { android_atomic_inc(&mActiveTrackCnt); mTailBufferCount = mMaxTailBuffers; } void decActiveTrackCnt() { android_atomic_dec(&mActiveTrackCnt); } - int32_t activeTrackCnt() const { return mActiveTrackCnt;} + int32_t activeTrackCnt() const { return android_atomic_acquire_load(&mActiveTrackCnt); } uint32_t strategy() const { return mStrategy; } void setStrategy(uint32_t strategy) @@ -1725,7 +1805,7 @@ mutable Mutex mLock; // mutex for process, commands and handl void clearInputBuffer(); - status_t dump(int fd, const Vector<String16>& args); + void dump(int fd, const Vector<String16>& args); protected: friend class AudioFlinger; // for mThread, mEffects @@ -1760,8 +1840,11 @@ mutable Mutex mLock; // mutex for process, commands and handl int mSessionId; // audio session ID int16_t *mInBuffer; // chain input buffer int16_t *mOutBuffer; // chain output buffer - volatile int32_t mActiveTrackCnt; // number of active tracks connected - volatile int32_t mTrackCnt; // number of tracks connected + + // 'volatile' here means these are accessed with atomic operations instead of mutex + volatile int32_t mActiveTrackCnt; // number of active tracks connected + volatile int32_t mTrackCnt; // number of tracks connected + int32_t mTailBufferCount; // current effect tail buffer count int32_t mMaxTailBuffers; // maximum effect tail buffers bool mOwnInBuffer; // true if the chain owns its input buffer @@ -1778,24 +1861,59 @@ mutable Mutex mLock; // mutex for process, commands and handl KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects; }; + class AudioHwDevice { + public: + enum Flags { + AHWD_CAN_SET_MASTER_VOLUME = 0x1, + AHWD_CAN_SET_MASTER_MUTE = 0x2, + }; + + AudioHwDevice(const char *moduleName, + audio_hw_device_t *hwDevice, + Flags flags) + : mModuleName(strdup(moduleName)) + , mHwDevice(hwDevice) + , mFlags(flags) { } + /*virtual*/ ~AudioHwDevice() { free((void *)mModuleName); } + + bool canSetMasterVolume() const { + return (0 != (mFlags & AHWD_CAN_SET_MASTER_VOLUME)); + } + + bool canSetMasterMute() const { + return (0 != (mFlags & AHWD_CAN_SET_MASTER_MUTE)); + } + + const char *moduleName() const { return mModuleName; } + audio_hw_device_t *hwDevice() const { return mHwDevice; } + private: + const char * const mModuleName; + audio_hw_device_t * const mHwDevice; + Flags mFlags; + }; + // AudioStreamOut and AudioStreamIn are immutable, so their fields are const. // For emphasis, we could also make all pointers to them be "const *", // but that would clutter the code unnecessarily. struct AudioStreamOut { - audio_hw_device_t* const hwDev; + AudioHwDevice* const audioHwDev; audio_stream_out_t* const stream; - AudioStreamOut(audio_hw_device_t *dev, audio_stream_out_t *out) : - hwDev(dev), stream(out) {} + audio_hw_device_t* hwDev() const { return audioHwDev->hwDevice(); } + + AudioStreamOut(AudioHwDevice *dev, audio_stream_out_t *out) : + audioHwDev(dev), stream(out) {} }; struct AudioStreamIn { - audio_hw_device_t* const hwDev; + AudioHwDevice* const audioHwDev; audio_stream_in_t* const stream; - AudioStreamIn(audio_hw_device_t *dev, audio_stream_in_t *in) : - hwDev(dev), stream(in) {} + audio_hw_device_t* hwDev() const { return audioHwDev->hwDevice(); } + + AudioStreamIn(AudioHwDevice *dev, audio_stream_in_t *in) : + audioHwDev(dev), stream(in) {} }; // for mAudioSessionRefs only @@ -1807,41 +1925,6 @@ mutable Mutex mLock; // mutex for process, commands and handl int mCnt; }; - enum master_volume_support { - // MVS_NONE: - // Audio HAL has no support for master volume, either setting or - // getting. All master volume control must be implemented in SW by the - // AudioFlinger mixing core. - MVS_NONE, - - // MVS_SETONLY: - // Audio HAL has support for setting master volume, but not for getting - // master volume (original HAL design did not include a getter). - // AudioFlinger needs to keep track of the last set master volume in - // addition to needing to set an initial, default, master volume at HAL - // load time. - MVS_SETONLY, - - // MVS_FULL: - // Audio HAL has support both for setting and getting master volume. - // AudioFlinger should send all set and get master volume requests - // directly to the HAL. - MVS_FULL, - }; - - class AudioHwDevice { - public: - AudioHwDevice(const char *moduleName, audio_hw_device_t *hwDevice) : - mModuleName(strdup(moduleName)), mHwDevice(hwDevice){} - ~AudioHwDevice() { free((void *)mModuleName); } - - const char *moduleName() const { return mModuleName; } - audio_hw_device_t *hwDevice() const { return mHwDevice; } - private: - const char * const mModuleName; - audio_hw_device_t * const mHwDevice; - }; - mutable Mutex mLock; DefaultKeyedVector< pid_t, wp<Client> > mClients; // see ~Client() @@ -1851,7 +1934,7 @@ mutable Mutex mLock; // mutex for process, commands and handl // always take mLock before mHardwareLock // These two fields are immutable after onFirstRef(), so no lock needed to access - audio_hw_device_t* mPrimaryHardwareDev; // mAudioHwDevs[0] or NULL + AudioHwDevice* mPrimaryHardwareDev; // mAudioHwDevs[0] or NULL DefaultKeyedVector<audio_module_handle_t, AudioHwDevice*> mAudioHwDevs; // for dump, indicates which hardware operation is currently in progress (but not stream ops) @@ -1875,6 +1958,8 @@ mutable Mutex mLock; // mutex for process, commands and handl AUDIO_HW_GET_INPUT_BUFFER_SIZE, // get_input_buffer_size AUDIO_HW_GET_MASTER_VOLUME, // get_master_volume AUDIO_HW_GET_PARAMETER, // get_parameters + AUDIO_HW_SET_MASTER_MUTE, // set_master_mute + AUDIO_HW_GET_MASTER_MUTE, // get_master_mute }; mutable hardware_call_state mHardwareStatus; // for dump only @@ -1885,8 +1970,6 @@ mutable Mutex mLock; // mutex for process, commands and handl // both are protected by mLock float mMasterVolume; - float mMasterVolumeSW; - master_volume_support mMasterVolumeSupportLvl; bool mMasterMute; DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> > mRecordThreads; @@ -1900,8 +1983,7 @@ mutable Mutex mLock; // mutex for process, commands and handl Vector<AudioSessionRef*> mAudioSessionRefs; float masterVolume_l() const; - float masterVolumeSW_l() const { return mMasterVolumeSW; } - bool masterMute_l() const { return mMasterMute; } + bool masterMute_l() const; audio_module_handle_t loadHwModule_l(const char *name); Vector < sp<SyncEvent> > mPendingSyncEvents; // sync events awaiting for a session @@ -1910,6 +1992,9 @@ mutable Mutex mLock; // mutex for process, commands and handl private: sp<Client> registerPid_l(pid_t pid); // always returns non-0 + // for use from destructor + status_t closeOutput_nonvirtual(audio_io_handle_t output); + status_t closeInput_nonvirtual(audio_io_handle_t input); }; diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp index 3e4c55e..a9814a1 100644 --- a/services/audioflinger/AudioMixer.cpp +++ b/services/audioflinger/AudioMixer.cpp @@ -416,7 +416,7 @@ void AudioMixer::setParameter(int name, int target, int param, void *value) case TRACK: switch (param) { case CHANNEL_MASK: { - uint32_t mask = (uint32_t)value; + audio_channel_mask_t mask = (audio_channel_mask_t) value; if (track.channelMask != mask) { uint32_t channelCount = popcount(mask); ALOG_ASSERT((channelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && channelCount); diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp index 0d13970..3a2dbe2 100644 --- a/services/audioflinger/AudioPolicyService.cpp +++ b/services/audioflinger/AudioPolicyService.cpp @@ -223,7 +223,7 @@ audio_policy_forced_cfg_t AudioPolicyService::getForceUse(audio_policy_force_use audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream, uint32_t samplingRate, audio_format_t format, - uint32_t channels, + audio_channel_mask_t channelMask, audio_output_flags_t flags) { if (mpAudioPolicy == NULL) { @@ -231,7 +231,7 @@ audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream, } ALOGV("getOutput() tid %d", gettid()); Mutex::Autolock _l(mLock); - return mpAudioPolicy->get_output(mpAudioPolicy, stream, samplingRate, format, channels, flags); + return mpAudioPolicy->get_output(mpAudioPolicy, stream, samplingRate, format, channelMask, flags); } status_t AudioPolicyService::startOutput(audio_io_handle_t output, @@ -271,8 +271,7 @@ void AudioPolicyService::releaseOutput(audio_io_handle_t output) audio_io_handle_t AudioPolicyService::getInput(audio_source_t inputSource, uint32_t samplingRate, audio_format_t format, - uint32_t channels, - audio_in_acoustics_t acoustics, + audio_channel_mask_t channelMask, int audioSession) { if (mpAudioPolicy == NULL) { @@ -283,8 +282,9 @@ audio_io_handle_t AudioPolicyService::getInput(audio_source_t inputSource, return 0; } Mutex::Autolock _l(mLock); + // the audio_in_acoustics_t parameter is ignored by get_input() audio_io_handle_t input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate, - format, channels, acoustics); + format, channelMask, (audio_in_acoustics_t) 0); if (input == 0) { return input; @@ -373,6 +373,7 @@ status_t AudioPolicyService::initStreamVolume(audio_stream_type_t stream, if (uint32_t(stream) >= AUDIO_STREAM_CNT) { return BAD_VALUE; } + Mutex::Autolock _l(mLock); mpAudioPolicy->init_stream_volume(mpAudioPolicy, stream, indexMin, indexMax); return NO_ERROR; } @@ -390,7 +391,7 @@ status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream, if (uint32_t(stream) >= AUDIO_STREAM_CNT) { return BAD_VALUE; } - + Mutex::Autolock _l(mLock); if (mpAudioPolicy->set_stream_volume_index_for_device) { return mpAudioPolicy->set_stream_volume_index_for_device(mpAudioPolicy, stream, @@ -411,6 +412,7 @@ status_t AudioPolicyService::getStreamVolumeIndex(audio_stream_type_t stream, if (uint32_t(stream) >= AUDIO_STREAM_CNT) { return BAD_VALUE; } + Mutex::Autolock _l(mLock); if (mpAudioPolicy->get_stream_volume_index_for_device) { return mpAudioPolicy->get_stream_volume_index_for_device(mpAudioPolicy, stream, @@ -439,7 +441,7 @@ audio_devices_t AudioPolicyService::getDevicesForStream(audio_stream_type_t stre return mpAudioPolicy->get_devices_for_stream(mpAudioPolicy, stream); } -audio_io_handle_t AudioPolicyService::getOutputForEffect(effect_descriptor_t *desc) +audio_io_handle_t AudioPolicyService::getOutputForEffect(const effect_descriptor_t *desc) { if (mpAudioPolicy == NULL) { return NO_INIT; @@ -448,7 +450,7 @@ audio_io_handle_t AudioPolicyService::getOutputForEffect(effect_descriptor_t *de return mpAudioPolicy->get_output_for_effect(mpAudioPolicy, desc); } -status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc, +status_t AudioPolicyService::registerEffect(const effect_descriptor_t *desc, audio_io_handle_t io, uint32_t strategy, int session, @@ -512,7 +514,7 @@ status_t AudioPolicyService::queryDefaultPreProcessing(int audioSession, for (size_t i = 0; i < effects.size(); i++) { effect_descriptor_t desc = effects[i]->descriptor(); if (i < *count) { - memcpy(descriptors + i, &desc, sizeof(effect_descriptor_t)); + descriptors[i] = desc; } } if (effects.size() > *count) { @@ -778,7 +780,6 @@ void AudioPolicyService::AudioCommandThread::startToneCommand(ToneGenerator::ton data->mType = type; data->mStream = stream; command->mParam = (void *)data; - command->mWaitStatus = false; Mutex::Autolock _l(mLock); insertCommand_l(command); ALOGV("AudioCommandThread() adding tone start type %d, stream %d", type, stream); @@ -790,7 +791,6 @@ void AudioPolicyService::AudioCommandThread::stopToneCommand() AudioCommand *command = new AudioCommand(); command->mCommand = STOP_TONE; command->mParam = NULL; - command->mWaitStatus = false; Mutex::Autolock _l(mLock); insertCommand_l(command); ALOGV("AudioCommandThread() adding tone stop"); @@ -811,11 +811,6 @@ status_t AudioPolicyService::AudioCommandThread::volumeCommand(audio_stream_type data->mVolume = volume; data->mIO = output; command->mParam = data; - if (delayMs == 0) { - command->mWaitStatus = true; - } else { - command->mWaitStatus = false; - } Mutex::Autolock _l(mLock); insertCommand_l(command, delayMs); ALOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d", @@ -841,11 +836,6 @@ status_t AudioPolicyService::AudioCommandThread::parametersCommand(audio_io_hand data->mIO = ioHandle; data->mKeyValuePairs = String8(keyValuePairs); command->mParam = data; - if (delayMs == 0) { - command->mWaitStatus = true; - } else { - command->mWaitStatus = false; - } Mutex::Autolock _l(mLock); insertCommand_l(command, delayMs); ALOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d", @@ -868,11 +858,6 @@ status_t AudioPolicyService::AudioCommandThread::voiceVolumeCommand(float volume VoiceVolumeData *data = new VoiceVolumeData(); data->mVolume = volume; command->mParam = data; - if (delayMs == 0) { - command->mWaitStatus = true; - } else { - command->mWaitStatus = false; - } Mutex::Autolock _l(mLock); insertCommand_l(command, delayMs); ALOGV("AudioCommandThread() adding set voice volume volume %f", volume); @@ -891,6 +876,7 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma ssize_t i; // not size_t because i will count down to -1 Vector <AudioCommand *> removedCommands; + nsecs_t time = 0; command->mTime = systemTime() + milliseconds(delayMs); // acquire wake lock to make sure delayed commands are processed @@ -936,6 +922,7 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma } else { data2->mKeyValuePairs = param2.toString(); } + time = command2->mTime; } break; case SET_VOLUME: { @@ -946,6 +933,7 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma ALOGV("Filtering out volume command on output %d for stream %d", data->mIO, data->mStream); removedCommands.add(command2); + time = command2->mTime; } break; case START_TONE: case STOP_TONE: @@ -967,6 +955,17 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma } removedCommands.clear(); + // wait for status only if delay is 0 and command time was not modified above + if (delayMs == 0 && time == 0) { + command->mWaitStatus = true; + } else { + command->mWaitStatus = false; + } + // update command time if modified above + if (time != 0) { + command->mTime = time; + } + // insert command at the right place according to its time stamp ALOGV("inserting command: %d at index %d, num commands %d", command->mCommand, (int)i+1, mAudioCommands.size()); @@ -1422,7 +1421,7 @@ static int aps_restore_output(void *service, audio_io_handle_t output) return af->restoreOutput(output); } -// deprecated: replaced by aps_open_input_on_module() +// deprecated: replaced by aps_open_input_on_module(), and acoustics parameter is ignored static audio_io_handle_t aps_open_input(void *service, audio_devices_t *pDevices, uint32_t *pSamplingRate, diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h index fbca000..a086734 100644 --- a/services/audioflinger/AudioPolicyService.h +++ b/services/audioflinger/AudioPolicyService.h @@ -64,7 +64,7 @@ public: virtual audio_io_handle_t getOutput(audio_stream_type_t stream, uint32_t samplingRate = 0, audio_format_t format = AUDIO_FORMAT_DEFAULT, - uint32_t channels = 0, + audio_channel_mask_t channelMask = 0, audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE); virtual status_t startOutput(audio_io_handle_t output, @@ -77,9 +77,7 @@ public: virtual audio_io_handle_t getInput(audio_source_t inputSource, uint32_t samplingRate = 0, audio_format_t format = AUDIO_FORMAT_DEFAULT, - uint32_t channels = 0, - audio_in_acoustics_t acoustics = - (audio_in_acoustics_t)0 /*AUDIO_IN_ACOUSTICS_NONE*/, + audio_channel_mask_t channelMask = 0, int audioSession = 0); virtual status_t startInput(audio_io_handle_t input); virtual status_t stopInput(audio_io_handle_t input); @@ -97,8 +95,8 @@ public: virtual uint32_t getStrategyForStream(audio_stream_type_t stream); virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream); - virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc); - virtual status_t registerEffect(effect_descriptor_t *desc, + virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc); + virtual status_t registerEffect(const effect_descriptor_t *desc, audio_io_handle_t io, uint32_t strategy, int session, diff --git a/services/audioflinger/AudioStreamOutSink.cpp b/services/audioflinger/AudioStreamOutSink.cpp index 8a5aa0c..bc2d15b 100644 --- a/services/audioflinger/AudioStreamOutSink.cpp +++ b/services/audioflinger/AudioStreamOutSink.cpp @@ -67,4 +67,16 @@ ssize_t AudioStreamOutSink::write(const void *buffer, size_t count) return ret; } +status_t AudioStreamOutSink::getNextWriteTimestamp(int64_t *timestamp) { + ALOG_ASSERT(timestamp != NULL); + + if (NULL == mStream) + return INVALID_OPERATION; + + if (NULL == mStream->get_next_write_timestamp) + return INVALID_OPERATION; + + return mStream->get_next_write_timestamp(mStream, timestamp); +} + } // namespace android diff --git a/services/audioflinger/AudioStreamOutSink.h b/services/audioflinger/AudioStreamOutSink.h index 1eff3f6..5976b18 100644 --- a/services/audioflinger/AudioStreamOutSink.h +++ b/services/audioflinger/AudioStreamOutSink.h @@ -47,6 +47,11 @@ public: virtual ssize_t write(const void *buffer, size_t count); + // AudioStreamOutSink wraps a HAL's output stream. Its + // getNextWriteTimestamp method is simply a passthru to the HAL's underlying + // implementation of GNWT (if any) + virtual status_t getNextWriteTimestamp(int64_t *timestamp); + // NBAIO_Sink end #if 0 // until necessary diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp index 7652132..fbcc11a 100644 --- a/services/audioflinger/FastMixer.cpp +++ b/services/audioflinger/FastMixer.cpp @@ -222,8 +222,8 @@ bool FastMixer::threadLoop() mixBuffer = new short[frameCount * 2]; periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00 underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75 - overrunNs = (frameCount * 250000000LL) / sampleRate; // 0.25 - forceNs = (frameCount * 750000000LL) / sampleRate; // 0.75 + overrunNs = (frameCount * 500000000LL) / sampleRate; // 0.50 + forceNs = (frameCount * 950000000LL) / sampleRate; // 0.95 warmupNs = (frameCount * 500000000LL) / sampleRate; // 0.50 } else { periodNs = 0; @@ -399,8 +399,13 @@ bool FastMixer::threadLoop() ftDump->mUnderruns = underruns; ftDump->mFramesReady = framesReady; } + + int64_t pts; + if (outputSink == NULL || (OK != outputSink->getNextWriteTimestamp(&pts))) + pts = AudioBufferProvider::kInvalidPTS; + // process() is CPU-bound - mixer->process(AudioBufferProvider::kInvalidPTS); + mixer->process(pts); mixBufferState = MIXED; } else if (mixBufferState == MIXED) { mixBufferState = UNDEFINED; diff --git a/services/audioflinger/MonoPipe.cpp b/services/audioflinger/MonoPipe.cpp index f3fc19a..bd876b4 100644 --- a/services/audioflinger/MonoPipe.cpp +++ b/services/audioflinger/MonoPipe.cpp @@ -17,17 +17,22 @@ #define LOG_TAG "MonoPipe" //#define LOG_NDEBUG 0 +#include <common_time/cc_helper.h> #include <cutils/atomic.h> #include <cutils/compiler.h> +#include <utils/LinearTransform.h> #include <utils/Log.h> #include <utils/Trace.h> +#include "AudioBufferProvider.h" #include "MonoPipe.h" #include "roundup.h" + namespace android { MonoPipe::MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock) : NBAIO_Sink(format), + mUpdateSeq(0), mReqFrames(reqFrames), mMaxFrames(roundup(reqFrames)), mBuffer(malloc(mMaxFrames * Format_frameSize(format))), @@ -38,6 +43,37 @@ MonoPipe::MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock) : mSetpoint((reqFrames * 11) / 16), mWriteCanBlock(writeCanBlock) { + CCHelper tmpHelper; + status_t res; + uint64_t N, D; + + mNextRdPTS = AudioBufferProvider::kInvalidPTS; + + mSamplesToLocalTime.a_zero = 0; + mSamplesToLocalTime.b_zero = 0; + mSamplesToLocalTime.a_to_b_numer = 0; + mSamplesToLocalTime.a_to_b_denom = 0; + + D = Format_sampleRate(format); + if (OK != (res = tmpHelper.getLocalFreq(&N))) { + ALOGE("Failed to fetch local time frequency when constructing a" + " MonoPipe (res = %d). getNextWriteTimestamp calls will be" + " non-functional", res); + return; + } + + LinearTransform::reduce(&N, &D); + static const uint64_t kSignedHiBitsMask = ~(0x7FFFFFFFull); + static const uint64_t kUnsignedHiBitsMask = ~(0xFFFFFFFFull); + if ((N & kSignedHiBitsMask) || (D & kUnsignedHiBitsMask)) { + ALOGE("Cannot reduce sample rate to local clock frequency ratio to fit" + " in a 32/32 bit rational. (max reduction is 0x%016llx/0x%016llx" + "). getNextWriteTimestamp calls will be non-functional", N, D); + return; + } + + mSamplesToLocalTime.a_to_b_numer = static_cast<int32_t>(N); + mSamplesToLocalTime.a_to_b_denom = static_cast<uint32_t>(D); } MonoPipe::~MonoPipe() @@ -162,4 +198,102 @@ void MonoPipe::setAvgFrames(size_t setpoint) mSetpoint = setpoint; } +status_t MonoPipe::getNextWriteTimestamp(int64_t *timestamp) +{ + int32_t front; + + ALOG_ASSERT(NULL != timestamp); + + if (0 == mSamplesToLocalTime.a_to_b_denom) + return UNKNOWN_ERROR; + + observeFrontAndNRPTS(&front, timestamp); + + if (AudioBufferProvider::kInvalidPTS != *timestamp) { + // If we have a valid read-pointer and next read timestamp pair, then + // use the current value of the write pointer to figure out how many + // frames are in the buffer, and offset the timestamp by that amt. Then + // next time we write to the MonoPipe, the data will hit the speakers at + // the next read timestamp plus the current amount of data in the + // MonoPipe. + size_t pendingFrames = (mRear - front) & (mMaxFrames - 1); + *timestamp = offsetTimestampByAudioFrames(*timestamp, pendingFrames); + } + + return OK; +} + +void MonoPipe::updateFrontAndNRPTS(int32_t newFront, int64_t newNextRdPTS) +{ + // Set the MSB of the update sequence number to indicate that there is a + // multi-variable update in progress. Use an atomic store with an "acquire" + // barrier to make sure that the next operations cannot be re-ordered and + // take place before the change to mUpdateSeq is commited.. + int32_t tmp = mUpdateSeq | 0x80000000; + android_atomic_acquire_store(tmp, &mUpdateSeq); + + // Update mFront and mNextRdPTS + mFront = newFront; + mNextRdPTS = newNextRdPTS; + + // We are finished with the update. Compute the next sequnce number (which + // should be the old sequence number, plus one, and with the MSB cleared) + // and then store it in mUpdateSeq using an atomic store with a "release" + // barrier so our update operations cannot be re-ordered past the update of + // the sequence number. + tmp = (tmp + 1) & 0x7FFFFFFF; + android_atomic_release_store(tmp, &mUpdateSeq); +} + +void MonoPipe::observeFrontAndNRPTS(int32_t *outFront, int64_t *outNextRdPTS) +{ + // Perform an atomic observation of mFront and mNextRdPTS. Basically, + // atomically observe the sequence number, then observer the variables, then + // atomically observe the sequence number again. If the two observations of + // the sequence number match, and the update-in-progress bit was not set, + // then we know we have a successful atomic observation. Otherwise, we loop + // around and try again. + // + // Note, it is very important that the observer be a lower priority thread + // than the updater. If the updater is lower than the observer, or they are + // the same priority and running with SCHED_FIFO (implying that quantum + // based premption is disabled) then we run the risk of deadlock. + int32_t seqOne, seqTwo; + + do { + seqOne = android_atomic_acquire_load(&mUpdateSeq); + *outFront = mFront; + *outNextRdPTS = mNextRdPTS; + seqTwo = android_atomic_release_load(&mUpdateSeq); + } while ((seqOne != seqTwo) || (seqOne & 0x80000000)); +} + +int64_t MonoPipe::offsetTimestampByAudioFrames(int64_t ts, size_t audFrames) +{ + if (0 == mSamplesToLocalTime.a_to_b_denom) + return AudioBufferProvider::kInvalidPTS; + + if (ts == AudioBufferProvider::kInvalidPTS) + return AudioBufferProvider::kInvalidPTS; + + int64_t frame_lt_duration; + if (!mSamplesToLocalTime.doForwardTransform(audFrames, + &frame_lt_duration)) { + // This should never fail, but if there is a bug which is causing it + // to fail, this message would probably end up flooding the logs + // because the conversion would probably fail forever. Log the + // error, but then zero out the ratio in the linear transform so + // that we don't try to do any conversions from now on. This + // MonoPipe's getNextWriteTimestamp is now broken for good. + ALOGE("Overflow when attempting to convert %d audio frames to" + " duration in local time. getNextWriteTimestamp will fail from" + " now on.", audFrames); + mSamplesToLocalTime.a_to_b_numer = 0; + mSamplesToLocalTime.a_to_b_denom = 0; + return AudioBufferProvider::kInvalidPTS; + } + + return ts + frame_lt_duration; +} + } // namespace android diff --git a/services/audioflinger/MonoPipe.h b/services/audioflinger/MonoPipe.h index f6e2cb3..c47bf6c 100644 --- a/services/audioflinger/MonoPipe.h +++ b/services/audioflinger/MonoPipe.h @@ -18,6 +18,7 @@ #define ANDROID_AUDIO_MONO_PIPE_H #include <time.h> +#include <utils/LinearTransform.h> #include "NBAIO.h" namespace android { @@ -56,6 +57,20 @@ public: virtual ssize_t write(const void *buffer, size_t count); //virtual ssize_t writeVia(writeVia_t via, size_t total, void *user, size_t block); + // MonoPipe's implementation of getNextWriteTimestamp works in conjunction + // with MonoPipeReader. Every time a MonoPipeReader reads from the pipe, it + // receives a "readPTS" indicating the point in time for which the reader + // would like to read data. This "last read PTS" is offset by the amt of + // data the reader is currently mixing and then cached cached along with the + // updated read pointer. This cached value is the local time for which the + // reader is going to request data next time it reads data (assuming we are + // in steady state and operating with no underflows). Writers to the + // MonoPipe who would like to know when their next write operation will hit + // the speakers can call getNextWriteTimestamp which will return the value + // of the last read PTS plus the duration of the amt of data waiting to be + // read in the MonoPipe. + virtual status_t getNextWriteTimestamp(int64_t *timestamp); + // average number of frames present in the pipe under normal conditions. // See throttling mechanism in MonoPipe::write() size_t getAvgFrames() const { return mSetpoint; } @@ -63,20 +78,42 @@ public: size_t maxFrames() const { return mMaxFrames; } private: + // A pair of methods and a helper variable which allows the reader and the + // writer to update and observe the values of mFront and mNextRdPTS in an + // atomic lock-less fashion. + // + // :: Important :: + // Two assumptions must be true in order for this lock-less approach to + // function properly on all systems. First, there may only be one updater + // thread in the system. Second, the updater thread must be running at a + // strictly higher priority than the observer threads. Currently, both of + // these assumptions are true. The only updater is always a single + // FastMixer thread (which runs with SCHED_FIFO/RT priority while the only + // observer is always an AudioFlinger::PlaybackThread running with + // traditional (non-RT) audio priority. + void updateFrontAndNRPTS(int32_t newFront, int64_t newNextRdPTS); + void observeFrontAndNRPTS(int32_t *outFront, int64_t *outNextRdPTS); + volatile int32_t mUpdateSeq; + const size_t mReqFrames; // as requested in constructor, unrounded const size_t mMaxFrames; // always a power of 2 void * const mBuffer; // mFront and mRear will never be separated by more than mMaxFrames. // 32-bit overflow is possible if the pipe is active for a long time, but if that happens it's // safe because we "&" with (mMaxFrames-1) at end of computations to calculate a buffer index. - volatile int32_t mFront; // written by reader with android_atomic_release_store, - // read by writer with android_atomic_acquire_load + volatile int32_t mFront; // written by the reader with updateFrontAndNRPTS, observed by + // the writer with observeFrontAndNRPTS volatile int32_t mRear; // written by writer with android_atomic_release_store, // read by reader with android_atomic_acquire_load + volatile int64_t mNextRdPTS; // written by the reader with updateFrontAndNRPTS, observed by + // the writer with observeFrontAndNRPTS bool mWriteTsValid; // whether mWriteTs is valid struct timespec mWriteTs; // time that the previous write() completed size_t mSetpoint; // target value for pipe fill depth const bool mWriteCanBlock; // whether write() should block if the pipe is full + + int64_t offsetTimestampByAudioFrames(int64_t ts, size_t audFrames); + LinearTransform mSamplesToLocalTime; }; } // namespace android diff --git a/services/audioflinger/MonoPipeReader.cpp b/services/audioflinger/MonoPipeReader.cpp index b80d0c0..39a07de 100644 --- a/services/audioflinger/MonoPipeReader.cpp +++ b/services/audioflinger/MonoPipeReader.cpp @@ -43,11 +43,25 @@ ssize_t MonoPipeReader::availableToRead() return ret; } -ssize_t MonoPipeReader::read(void *buffer, size_t count) +ssize_t MonoPipeReader::read(void *buffer, size_t count, int64_t readPTS) { + // Compute the "next read PTS" and cache it. Callers of read pass a read + // PTS indicating the local time for which they are requesting data along + // with a count (which is the number of audio frames they are going to + // ultimately pass to the next stage of the pipeline). Offsetting readPTS + // by the duration of count will give us the readPTS which will be passed to + // us next time, assuming they system continues to operate in steady state + // with no discontinuities. We stash this value so it can be used by the + // MonoPipe writer to imlement getNextWriteTimestamp. + int64_t nextReadPTS; + nextReadPTS = mPipe->offsetTimestampByAudioFrames(readPTS, count); + // count == 0 is unlikely and not worth checking for explicitly; will be handled automatically ssize_t red = availableToRead(); if (CC_UNLIKELY(red <= 0)) { + // Uh-oh, looks like we are underflowing. Update the next read PTS and + // get out. + mPipe->updateFrontAndNRPTS(mPipe->mFront, nextReadPTS); return red; } if (CC_LIKELY((size_t) red > count)) { @@ -66,7 +80,7 @@ ssize_t MonoPipeReader::read(void *buffer, size_t count) memcpy((char *) buffer + (part1 << mBitShift), mPipe->mBuffer, part2 << mBitShift); } } - android_atomic_release_store(red + mPipe->mFront, &mPipe->mFront); + mPipe->updateFrontAndNRPTS(red + mPipe->mFront, nextReadPTS); mFramesRead += red; } return red; diff --git a/services/audioflinger/MonoPipeReader.h b/services/audioflinger/MonoPipeReader.h index 9bb0a94..0e1c992 100644 --- a/services/audioflinger/MonoPipeReader.h +++ b/services/audioflinger/MonoPipeReader.h @@ -47,7 +47,7 @@ public: virtual ssize_t availableToRead(); - virtual ssize_t read(void *buffer, size_t count); + virtual ssize_t read(void *buffer, size_t count, int64_t readPTS); // NBAIO_Source end diff --git a/services/audioflinger/NBAIO.cpp b/services/audioflinger/NBAIO.cpp index 9d71eae..2c07ebf 100644 --- a/services/audioflinger/NBAIO.cpp +++ b/services/audioflinger/NBAIO.cpp @@ -128,7 +128,8 @@ ssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t bl } // This is a default implementation; it is expected that subclasses will optimize this. -ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, size_t block) +ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, + int64_t readPTS, size_t block) { if (!mNegotiated) { return (ssize_t) NEGOTIATE; @@ -147,11 +148,11 @@ ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, size_t bl if (count > block) { count = block; } - ssize_t ret = read(buffer, count); + ssize_t ret = read(buffer, count, readPTS); if (ret > 0) { ALOG_ASSERT((size_t) ret <= count); size_t maxRet = ret; - ret = via(user, buffer, maxRet); + ret = via(user, buffer, maxRet, readPTS); if (ret > 0) { ALOG_ASSERT((size_t) ret <= maxRet); accumulator += ret; diff --git a/services/audioflinger/NBAIO.h b/services/audioflinger/NBAIO.h index b5ae0f1..81f42ed 100644 --- a/services/audioflinger/NBAIO.h +++ b/services/audioflinger/NBAIO.h @@ -26,6 +26,7 @@ #include <limits.h> #include <stdlib.h> +#include <utils/Errors.h> #include <utils/RefBase.h> namespace android { @@ -74,7 +75,8 @@ unsigned Format_channelCount(NBAIO_Format format); // Callbacks used by NBAIO_Sink::writeVia() and NBAIO_Source::readVia() below. typedef ssize_t (*writeVia_t)(void *user, void *buffer, size_t count); -typedef ssize_t (*readVia_t)(void *user, const void *buffer, size_t count); +typedef ssize_t (*readVia_t)(void *user, const void *buffer, + size_t count, int64_t readPTS); // Abstract class (interface) representing a data port. class NBAIO_Port : public RefBase { @@ -198,6 +200,21 @@ public: // < 0 status_t error occurred prior to the first frame transfer during this callback. virtual ssize_t writeVia(writeVia_t via, size_t total, void *user, size_t block = 0); + // Get the time (on the LocalTime timeline) at which the first frame of audio of the next write + // operation to this sink will be eventually rendered by the HAL. + // Inputs: + // ts A pointer pointing to the int64_t which will hold the result. + // Return value: + // OK Everything went well, *ts holds the time at which the first audio frame of the next + // write operation will be rendered, or AudioBufferProvider::kInvalidPTS if this sink + // does not know the answer for some reason. Sinks which eventually lead to a HAL + // which implements get_next_write_timestamp may return Invalid temporarily if the DMA + // output of the audio driver has not started yet. Sinks which lead to a HAL which + // does not implement get_next_write_timestamp, or which don't lead to a HAL at all, + // will always return kInvalidPTS. + // <other> Something unexpected happened internally. Check the logs and start debugging. + virtual status_t getNextWriteTimestamp(int64_t *ts) { return INVALID_OPERATION; } + protected: NBAIO_Sink(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0) { } virtual ~NBAIO_Sink() { } @@ -238,6 +255,8 @@ public: // Inputs: // buffer Non-NULL destination buffer owned by consumer. // count Maximum number of frames to transfer. + // readPTS The presentation time (on the LocalTime timeline) for which data + // is being requested, or kInvalidPTS if not known. // Return value: // > 0 Number of frames successfully transferred prior to first error. // = 0 Count was zero. @@ -247,7 +266,7 @@ public: // WOULD_BLOCK No frames can be transferred without blocking. // OVERRUN read() has not been called frequently enough, or with enough frames to keep up. // One or more frames were lost due to overrun, try again to read more recent data. - virtual ssize_t read(void *buffer, size_t count) = 0; + virtual ssize_t read(void *buffer, size_t count, int64_t readPTS) = 0; // Transfer data from source using a series of callbacks. More suitable for zero-fill, // synthesis, and non-contiguous transfers (e.g. circular buffer or readv). @@ -256,6 +275,8 @@ public: // total Estimate of the number of frames the consumer desires. This is an estimate, // and it can consume a different number of frames during the series of callbacks. // user Arbitrary void * reserved for data consumer. + // readPTS The presentation time (on the LocalTime timeline) for which data + // is being requested, or kInvalidPTS if not known. // block Number of frames per block, that is a suggested value for 'count' in each callback. // Zero means no preference. This parameter is a hint only, and may be ignored. // Return value: @@ -278,7 +299,8 @@ public: // > 0 Number of frames successfully transferred during this callback prior to first error. // = 0 Count was zero. // < 0 status_t error occurred prior to the first frame transfer during this callback. - virtual ssize_t readVia(readVia_t via, size_t total, void *user, size_t block = 0); + virtual ssize_t readVia(readVia_t via, size_t total, void *user, + int64_t readPTS, size_t block = 0); protected: NBAIO_Source(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0) { } diff --git a/services/audioflinger/Soaker.h b/services/audioflinger/Soaker.h deleted file mode 100644 index 43d9d2f..0000000 --- a/services/audioflinger/Soaker.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _ANDROID_AUDIO_SOAKER_H -#define _ANDROID_AUDIO_SOAKER_H - -#include <utils/Thread.h> - -namespace android { - -class Soaker : public Thread { -public: - Soaker() : Thread() { } - virtual ~Soaker() { } -protected: - virtual bool threadLoop() { - int j = 0; - for (;;) { - for (int i = 0; i < 10000; ++i) { - j += i * i; - } - if (exitPending()) { - return false; - } - } - return j < 555555; - } -}; - -} // namespace android - -#endif // _ANDROID_AUDIO_SOAKER_H diff --git a/services/audioflinger/SourceAudioBufferProvider.cpp b/services/audioflinger/SourceAudioBufferProvider.cpp index e9d6d2c..3343b53 100644 --- a/services/audioflinger/SourceAudioBufferProvider.cpp +++ b/services/audioflinger/SourceAudioBufferProvider.cpp @@ -65,7 +65,7 @@ status_t SourceAudioBufferProvider::getNextBuffer(Buffer *buffer, int64_t pts) mSize = buffer->frameCount; } // read from source - ssize_t actual = mSource->read(mAllocated, buffer->frameCount); + ssize_t actual = mSource->read(mAllocated, buffer->frameCount, pts); if (actual > 0) { ALOG_ASSERT((size_t) actual <= buffer->frameCount); mOffset = 0; |