diff options
Diffstat (limited to 'libs/audioflinger/AudioFlinger.cpp')
-rw-r--r-- | libs/audioflinger/AudioFlinger.cpp | 226 |
1 files changed, 208 insertions, 18 deletions
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index ecfe1e0..2414e8d 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -47,6 +47,10 @@ #include "A2dpAudioInterface.h" #endif +#ifdef LVMX +#include "lifevibes.h" +#endif + // ---------------------------------------------------------------------------- // the sim build doesn't have gettid @@ -68,6 +72,10 @@ static const float MAX_GAIN = 4096.0f; // 50 * ~20msecs = 1 second static const int8_t kMaxTrackRetries = 50; static const int8_t kMaxTrackStartupRetries = 50; +// allow less retry attempts on direct output thread. +// direct outputs can be a scarce resource in audio hardware and should +// be released as quickly as possible. +static const int8_t kMaxTrackRetriesDirect = 2; static const int kDumpLockRetries = 50; static const int kDumpLockSleep = 20000; @@ -132,6 +140,9 @@ AudioFlinger::AudioFlinger() } else { LOGE("Couldn't even initialize the stubbed audio hardware!"); } +#ifdef LVMX + LifeVibes::init(); +#endif } AudioFlinger::~AudioFlinger() @@ -411,6 +422,11 @@ status_t AudioFlinger::setMode(int mode) AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_SET_MODE; status_t ret = mAudioHardware->setMode(mode); +#ifdef LVMX + if (NO_ERROR == ret) { + LifeVibes::setMode(mode); + } +#endif mHardwareStatus = AUDIO_HW_IDLE; return ret; } @@ -544,11 +560,11 @@ bool AudioFlinger::streamMute(int stream) const return mStreamTypes[stream].mute; } -bool AudioFlinger::isMusicActive() const +bool AudioFlinger::isStreamActive(int stream) const { Mutex::Autolock _l(mLock); for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) { - if (mPlaybackThreads.valueAt(i)->isMusicActive()) { + if (mPlaybackThreads.valueAt(i)->isStreamActive(stream)) { return true; } } @@ -566,11 +582,37 @@ status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs) return PERMISSION_DENIED; } +#ifdef LVMX + AudioParameter param = AudioParameter(keyValuePairs); + LifeVibes::setParameters(ioHandle,keyValuePairs); + String8 key = String8(AudioParameter::keyRouting); + int device; + if (NO_ERROR != param.getInt(key, device)) { + device = -1; + } + + key = String8(LifevibesTag); + String8 value; + int musicEnabled = -1; + if (NO_ERROR == param.get(key, value)) { + if (value == LifevibesEnable) { + musicEnabled = 1; + } else if (value == LifevibesDisable) { + musicEnabled = 0; + } + } +#endif + // ioHandle == 0 means the parameters are global to the audio hardware interface if (ioHandle == 0) { AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_SET_PARAMETER; result = mAudioHardware->setParameters(keyValuePairs); +#ifdef LVMX + if ((NO_ERROR == result) && (musicEnabled != -1)) { + LifeVibes::enableMusic((bool) musicEnabled); + } +#endif mHardwareStatus = AUDIO_HW_IDLE; return result; } @@ -586,7 +628,13 @@ status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs) } } if (thread != NULL) { - return thread->setParameters(keyValuePairs); + result = thread->setParameters(keyValuePairs); +#ifdef LVMX + if ((NO_ERROR == result) && (device != -1)) { + LifeVibes::setDevice(LifeVibes::threadIdToAudioOutputType(thread->id()), device); + } +#endif + return result; } return BAD_VALUE; } @@ -618,6 +666,21 @@ size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int cha return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount); } +unsigned int AudioFlinger::getInputFramesLost(int ioHandle) +{ + if (ioHandle == 0) { + return 0; + } + + Mutex::Autolock _l(mLock); + + RecordThread *recordThread = checkRecordThread_l(ioHandle); + if (recordThread != NULL) { + return recordThread->getInputFramesLost(); + } + return 0; +} + status_t AudioFlinger::setVoiceVolume(float value) { // check calling permissions @@ -633,6 +696,20 @@ status_t AudioFlinger::setVoiceVolume(float value) return ret; } +status_t AudioFlinger::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output) +{ + status_t status; + + Mutex::Autolock _l(mLock); + + PlaybackThread *playbackThread = checkPlaybackThread_l(output); + if (playbackThread != NULL) { + return playbackThread->getRenderPosition(halFrames, dspFrames); + } + + return BAD_VALUE; +} + void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client) { @@ -1029,12 +1106,24 @@ uint32_t AudioFlinger::PlaybackThread::latency() const status_t AudioFlinger::PlaybackThread::setMasterVolume(float value) { +#ifdef LVMX + int audioOutputType = LifeVibes::getMixerType(mId, mType); + if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { + LifeVibes::setMasterVolume(audioOutputType, value); + } +#endif mMasterVolume = value; return NO_ERROR; } status_t AudioFlinger::PlaybackThread::setMasterMute(bool muted) { +#ifdef LVMX + int audioOutputType = LifeVibes::getMixerType(mId, mType); + if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { + LifeVibes::setMasterMute(audioOutputType, muted); + } +#endif mMasterMute = muted; return NO_ERROR; } @@ -1051,12 +1140,24 @@ bool AudioFlinger::PlaybackThread::masterMute() const status_t AudioFlinger::PlaybackThread::setStreamVolume(int stream, float value) { +#ifdef LVMX + int audioOutputType = LifeVibes::getMixerType(mId, mType); + if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { + LifeVibes::setStreamVolume(audioOutputType, stream, value); + } +#endif mStreamTypes[stream].volume = value; return NO_ERROR; } status_t AudioFlinger::PlaybackThread::setStreamMute(int stream, bool muted) { +#ifdef LVMX + int audioOutputType = LifeVibes::getMixerType(mId, mType); + if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { + LifeVibes::setStreamMute(audioOutputType, stream, muted); + } +#endif mStreamTypes[stream].mute = muted; return NO_ERROR; } @@ -1071,7 +1172,7 @@ bool AudioFlinger::PlaybackThread::streamMute(int stream) const return mStreamTypes[stream].mute; } -bool AudioFlinger::PlaybackThread::isMusicActive() const +bool AudioFlinger::PlaybackThread::isStreamActive(int stream) const { Mutex::Autolock _l(mLock); size_t count = mActiveTracks.size(); @@ -1079,7 +1180,7 @@ bool AudioFlinger::PlaybackThread::isMusicActive() const sp<Track> t = mActiveTracks[i].promote(); if (t == 0) continue; Track* const track = t.get(); - if (t->type() == AudioSystem::MUSIC) + if (t->type() == stream) return true; } return false; @@ -1166,6 +1267,19 @@ void AudioFlinger::PlaybackThread::readOutputParameters() memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t)); } +status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames) +{ + if (halFrames == 0 || dspFrames == 0) { + return BAD_VALUE; + } + if (mOutput == 0) { + return INVALID_OPERATION; + } + *halFrames = mBytesWritten/mOutput->frameSize(); + + return mOutput->getRenderPosition(dspFrames); +} + // ---------------------------------------------------------------------------- AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id) @@ -1290,8 +1404,15 @@ bool AudioFlinger::MixerThread::threadLoop() if (sleepTime == 0) { mLastWriteTime = systemTime(); mInWrite = true; + mBytesWritten += mixBufferSize; +#ifdef LVMX + int audioOutputType = LifeVibes::getMixerType(mId, mType); + if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { + LifeVibes::process(audioOutputType, curBuf, mixBufferSize); + } +#endif int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize); - if (bytesWritten > 0) mBytesWritten += bytesWritten; + if (bytesWritten < 0) mBytesWritten -= mixBufferSize; mNumWrites++; mInWrite = false; nsecs_t now = systemTime(); @@ -1333,6 +1454,29 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track uint32_t mixerStatus = MIXER_IDLE; // find out which tracks need to be processed size_t count = activeTracks.size(); + + float masterVolume = mMasterVolume; + bool masterMute = mMasterMute; + +#ifdef LVMX + bool tracksConnectedChanged = false; + bool stateChanged = false; + + int audioOutputType = LifeVibes::getMixerType(mId, mType); + if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) + { + int activeTypes = 0; + for (size_t i=0 ; i<count ; i++) { + sp<Track> t = activeTracks[i].promote(); + if (t == 0) continue; + Track* const track = t.get(); + int iTracktype=track->type(); + activeTypes |= 1<<track->type(); + } + LifeVibes::computeVolumes(audioOutputType, activeTypes, tracksConnectedChanged, stateChanged, masterVolume, masterMute); + } +#endif + for (size_t i=0 ; i<count ; i++) { sp<Track> t = activeTracks[i].promote(); if (t == 0) continue; @@ -1344,21 +1488,33 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track // for all its buffers to be filled before processing it mAudioMixer->setActiveTrack(track->name()); if (cblk->framesReady() && (track->isReady() || track->isStopped()) && - !track->isPaused()) + !track->isPaused() && !track->isTerminated()) { //LOGV("track %d u=%08x, s=%08x [OK] on thread %p", track->name(), cblk->user, cblk->server, this); // compute volume for this track int16_t left, right; - if (track->isMuted() || mMasterMute || track->isPausing() || + if (track->isMuted() || masterMute || track->isPausing() || mStreamTypes[track->type()].mute) { left = right = 0; if (track->isPausing()) { track->setPaused(); } } else { + // read original volumes with volume control float typeVolume = mStreamTypes[track->type()].volume; - float v = mMasterVolume * typeVolume; +#ifdef LVMX + bool streamMute=false; + // read the volume from the LivesVibes audio engine. + if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) + { + LifeVibes::getStreamVolumes(audioOutputType, track->type(), &typeVolume, &streamMute); + if (streamMute) { + typeVolume = 0; + } + } +#endif + float v = masterVolume * typeVolume; float v_clamped = v * cblk->volume[0]; if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; left = int16_t(v_clamped); @@ -1384,7 +1540,13 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track // do not apply ramp param = AudioMixer::RAMP_VOLUME; } - +#ifdef LVMX + if ( tracksConnectedChanged || stateChanged ) + { + // only do the ramp when the volume is changed by the user / application + param = AudioMixer::VOLUME; + } +#endif mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left); mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right); mAudioMixer->setParameter( @@ -1636,6 +1798,9 @@ bool AudioFlinger::DirectOutputThread::threadLoop() uint32_t activeSleepTime = activeSleepTimeUs(); uint32_t idleSleepTime = idleSleepTimeUs(); uint32_t sleepTime = idleSleepTime; + // use shorter standby delay as on normal output to release + // hardware resources as soon as possible + nsecs_t standbyDelay = microseconds(activeSleepTime*2); while (!exitPending()) @@ -1652,6 +1817,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() mixBufferSize = mFrameCount*mFrameSize; activeSleepTime = activeSleepTimeUs(); idleSleepTime = idleSleepTimeUs(); + standbyDelay = microseconds(activeSleepTime*2); } // put audio hardware into standby after short delay @@ -1684,7 +1850,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() } } - standbyTime = systemTime() + kStandbyTimeInNsecs; + standbyTime = systemTime() + standbyDelay; sleepTime = idleSleepTime; continue; } @@ -1701,7 +1867,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() // The first time a track is added we wait // for all its buffers to be filled before processing it if (cblk->framesReady() && (track->isReady() || track->isStopped()) && - !track->isPaused()) + !track->isPaused() && !track->isTerminated()) { //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server); @@ -1738,7 +1904,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() } // reset retry count - track->mRetryCount = kMaxTrackRetries; + track->mRetryCount = kMaxTrackRetriesDirect; activeTrack = t; mixerStatus = MIXER_TRACKS_READY; } else { @@ -1791,7 +1957,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() activeTrack->releaseBuffer(&buffer); } sleepTime = 0; - standbyTime = systemTime() + kStandbyTimeInNsecs; + standbyTime = systemTime() + standbyDelay; } else { if (sleepTime == 0) { if (mixerStatus == MIXER_TRACKS_ENABLED) { @@ -1812,8 +1978,9 @@ bool AudioFlinger::DirectOutputThread::threadLoop() if (sleepTime == 0) { mLastWriteTime = systemTime(); mInWrite = true; + mBytesWritten += mixBufferSize; int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize); - if (bytesWritten) mBytesWritten += bytesWritten; + if (bytesWritten < 0) mBytesWritten -= mixBufferSize; mNumWrites++; mInWrite = false; mStandby = false; @@ -2900,7 +3067,7 @@ void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue() AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid) : RefBase(), mAudioFlinger(audioFlinger), - mMemoryDealer(new MemoryDealer(1024*1024)), + mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client")), mPid(pid) { // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer @@ -3203,7 +3370,10 @@ bool AudioFlinger::RecordThread::threadLoop() if (mBytesRead < 0) { LOGE("Error reading audio input"); if (mActiveTrack->mState == TrackBase::ACTIVE) { - sleep(1); + // Force input into standby so that it tries to + // recover at next read attempt + mInput->standby(); + usleep(5000); } mRsmpInIndex = mFrameCount; framesOut = 0; @@ -3385,7 +3555,10 @@ status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* if (mBytesRead < 0) { LOGE("RecordThread::getNextBuffer() Error reading audio input"); if (mActiveTrack->mState == TrackBase::ACTIVE) { - sleep(1); + // Force input into standby so that it tries to + // recover at next read attempt + mInput->standby(); + usleep(5000); } buffer->raw = 0; buffer->frameCount = 0; @@ -3546,6 +3719,11 @@ void AudioFlinger::RecordThread::readInputParameters() mRsmpInIndex = mFrameCount; } +unsigned int AudioFlinger::RecordThread::getInputFramesLost() +{ + return mInput->getInputFramesLost(); +} + // ---------------------------------------------------------------------------- int AudioFlinger::openOutput(uint32_t *pDevices, @@ -3597,6 +3775,18 @@ int AudioFlinger::openOutput(uint32_t *pDevices, } else { thread = new MixerThread(this, output, ++mNextThreadId); LOGV("openOutput() created mixer output: ID %d thread %p", mNextThreadId, thread); + +#ifdef LVMX + unsigned bitsPerSample = + (format == AudioSystem::PCM_16_BIT) ? 16 : + ((format == AudioSystem::PCM_8_BIT) ? 8 : 0); + unsigned channelCount = (channels == AudioSystem::CHANNEL_OUT_STEREO) ? 2 : 1; + int audioOutputType = LifeVibes::threadIdToAudioOutputType(thread->id()); + + LifeVibes::init_aot(audioOutputType, samplingRate, bitsPerSample, channelCount); + LifeVibes::setDevice(audioOutputType, *pDevices); +#endif + } mPlaybackThreads.add(mNextThreadId, thread); |