diff options
Diffstat (limited to 'services/audioflinger')
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 839 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 214 |
2 files changed, 1014 insertions, 39 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 1ce47a3..c7fbb09 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1,6 +1,11 @@ /* ** ** Copyright 2007, The Android Open Source Project +** Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. +** +** Copyright (c) 2012, The Linux Foundation. All rights reserved. +** Not a Contribution, Apache license notifications and license are retained +** for attribution purposes only. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -100,6 +105,11 @@ #define ALOGVV(a...) do { } while(0) #endif +#ifdef QCOM_HARDWARE +#define DIRECT_TRACK_EOS 1 +static const char lockName[] = "DirectTrack"; +#endif + namespace android { static const char kDeadlockedString[] = "AudioFlinger may be deadlocked\n"; @@ -220,6 +230,14 @@ out: return rc; } +static uint32_t getInputChannelCount(uint32_t channels) { +#ifdef QCOM_HARDWARE + // only mono or stereo and 5.1 are supported for input sources + return popcount((channels) & (AUDIO_CHANNEL_IN_STEREO | AUDIO_CHANNEL_IN_MONO | AUDIO_CHANNEL_IN_5POINT1)); +#else + return popcount(channels); +#endif +} // ---------------------------------------------------------------------------- AudioFlinger::AudioFlinger() @@ -241,6 +259,11 @@ void AudioFlinger::onFirstRef() Mutex::Autolock _l(mLock); /* TODO: move all this work into an Init() function */ +#ifdef QCOM_HARDWARE + mLPASessionId = -2; // -2 is invalid session ID + mIsEffectConfigChanged = false; + mLPAEffectChain = NULL; +#endif char val_str[PROPERTY_VALUE_MAX] = { 0 }; if (property_get("ro.audio.flinger_standbytime_ms", val_str, NULL) >= 0) { uint32_t int_val; @@ -546,9 +569,218 @@ Exit: return trackHandle; } +#ifdef QCOM_HARDWARE +sp<IDirectTrack> AudioFlinger::createDirectTrack( + pid_t pid, + uint32_t sampleRate, + audio_channel_mask_t channelMask, + audio_io_handle_t output, + int *sessionId, + IDirectTrackClient *client, + audio_stream_type_t streamType, + status_t *status) +{ + *status = NO_ERROR; + status_t lStatus = NO_ERROR; + sp<IDirectTrack> track = NULL; + DirectAudioTrack* directTrack = NULL; + Mutex::Autolock _l(mLock); + + ALOGV("createDirectTrack() sessionId: %d sampleRate %d channelMask %d", + *sessionId, sampleRate, channelMask); + AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(output); + if(desc == NULL) { + ALOGE("Error: Invalid output (%d) to create direct audio track", output); + lStatus = BAD_VALUE; + goto Exit; + } + desc->mStreamType = streamType; + if (desc->flag & AUDIO_OUTPUT_FLAG_LPA) { + if (sessionId != NULL && *sessionId != AUDIO_SESSION_OUTPUT_MIX) { + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { + sp<PlaybackThread> t = mPlaybackThreads.valueAt(i); + // Check if the session ID is already associated with a track + uint32_t sessions = t->hasAudioSession(*sessionId); + + // check if an effect with same session ID is waiting for a ssession to be created + ALOGV("check if an effect with same session ID is waiting for a ssession to be created"); + if ((mLPAEffectChain == NULL) && (sessions & PlaybackThread::EFFECT_SESSION)) { + // Clear reference to previous effect chain if any + t->mLock.lock(); + ALOGV("getting the LPA effect chain and setting LPA flag to true."); + mLPAEffectChain = t->getEffectChain_l(*sessionId); + t->mLock.unlock(); + } + } + mLPASessionId = *sessionId; + if (mLPAEffectChain != NULL) { + mLPAEffectChain->setLPAFlag(true); + // For LPA, the volume will be applied in DSP. No need for volume + // control in the Effect chain, so setting it to unity. + uint32_t volume = 0x1000000; // Equals to 1.0 in 8.24 format + mLPAEffectChain->setVolume_l(&volume,&volume); + } else { + ALOGW("There was no effectChain created for the sessionId(%d)", mLPASessionId); + } + mLPASampleRate = sampleRate; + mLPANumChannels = popcount(channelMask); + } else { + if(sessionId != NULL) { + ALOGE("Error: Invalid sessionID (%d) for direct audio track", *sessionId); + } + } + } + mLock.unlock(); + directTrack = new DirectAudioTrack(this, output, desc, client, desc->flag); + desc->trackRefPtr = dynamic_cast<void *>(directTrack); + mLock.lock(); + if (directTrack != 0) { + track = dynamic_cast<IDirectTrack *>(directTrack); + AudioEventObserver* obv = dynamic_cast<AudioEventObserver *>(directTrack); + ALOGE("setting observer mOutputDesc track %p, obv %p", track.get(), obv); + desc->stream->set_observer(desc->stream, reinterpret_cast<void *>(obv)); + } else { + lStatus = BAD_VALUE; + } +Exit: + if(lStatus) { + if (track != NULL) { + track.clear(); + } + *status = lStatus; + } + return track; +} + +void AudioFlinger::deleteEffectSession() +{ + Mutex::Autolock _l(mLock); + ALOGV("deleteSession"); + // -2 is invalid session ID + mLPASessionId = -2; + if (mLPAEffectChain != NULL) { + mLPAEffectChain->setLPAFlag(false); + size_t i, numEffects = mLPAEffectChain->getNumEffects(); + for(i = 0; i < numEffects; i++) { + sp<EffectModule> effect = mLPAEffectChain->getEffectFromIndex_l(i); + effect->setInBuffer(mLPAEffectChain->inBuffer()); + if (i == numEffects-1) { + effect->setOutBuffer(mLPAEffectChain->outBuffer()); + } else { + effect->setOutBuffer(mLPAEffectChain->inBuffer()); + } + effect->configure(); + } + mLPAEffectChain.clear(); + mLPAEffectChain = NULL; + } +} + +// ToDo: Should we go ahead with this frameCount? +#define DEAFULT_FRAME_COUNT 1200 +void AudioFlinger::applyEffectsOn(void *token, int16_t *inBuffer, int16_t *outBuffer, int size) +{ + ALOGV("applyEffectsOn: inBuf %p outBuf %p size %d token %p", inBuffer, outBuffer, size, token); + // This might be the first buffer to apply effects after effect config change + // should not skip effects processing + mIsEffectConfigChanged = false; + + volatile size_t numEffects = 0; + if(mLPAEffectChain != NULL) { + numEffects = mLPAEffectChain->getNumEffects(); + } + + if( numEffects > 0) { + size_t i = 0; + int16_t *pIn = inBuffer; + int16_t *pOut = outBuffer; + + int frameCount = size / (sizeof(int16_t) * mLPANumChannels); + + while(frameCount > 0) { + if(mLPAEffectChain == NULL) { + ALOGV("LPA Effect Chain is removed - No effects processing !!"); + numEffects = 0; + break; + } + mLPAEffectChain->lock(); + + numEffects = mLPAEffectChain->getNumEffects(); + if(!numEffects) { + ALOGV("applyEffectsOn: All the effects are removed - nothing to process"); + mLPAEffectChain->unlock(); + break; + } + + int outFrameCount = (frameCount > DEAFULT_FRAME_COUNT ? DEAFULT_FRAME_COUNT: frameCount); + bool isEffectEnabled = false; + for(i = 0; i < numEffects; i++) { + // If effect configuration is changed while applying effects do not process further + if(mIsEffectConfigChanged) { + mLPAEffectChain->unlock(); + ALOGV("applyEffectsOn: mIsEffectConfigChanged is set - no further processing"); + return; + } + sp<EffectModule> effect = mLPAEffectChain->getEffectFromIndex_l(i); + if(effect == NULL) { + ALOGE("getEffectFromIndex_l(%d) returned NULL ptr", i); + mLPAEffectChain->unlock(); + return; + } + if(i == 0) { + // For the first set input and output buffers different + isEffectEnabled = effect->isProcessEnabled(); + effect->setInBuffer(pIn); + effect->setOutBuffer(pOut); + } else { + // For the remaining use previous effect's output buffer as input buffer + effect->setInBuffer(pOut); + effect->setOutBuffer(pOut); + } + // true indicates that it is being applied on LPA output + effect->configure(true, mLPASampleRate, mLPANumChannels, outFrameCount); + } + + if(isEffectEnabled) { + // Clear the output buffer + memset(pOut, 0, (outFrameCount * mLPANumChannels * sizeof(int16_t))); + } else { + // Copy input buffer content to the output buffer + memcpy(pOut, pIn, (outFrameCount * mLPANumChannels * sizeof(int16_t))); + } + + mLPAEffectChain->process_l(); + + mLPAEffectChain->unlock(); + + // Update input and output buffer pointers + pIn += (outFrameCount * mLPANumChannels); + pOut += (outFrameCount * mLPANumChannels); + frameCount -= outFrameCount; + } + } + + if (!numEffects) { + ALOGV("applyEffectsOn: There are no effects to be applied"); + if(inBuffer != outBuffer) { + // No effect applied so just copy input buffer to output buffer + memcpy(outBuffer, inBuffer, size); + } + } +} +#endif + uint32_t AudioFlinger::sampleRate(audio_io_handle_t output) const { Mutex::Autolock _l(mLock); +#ifdef QCOM_HARDWARE + if (!mDirectAudioTracks.isEmpty()) { + AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(output); + if(desc != NULL) { + return desc->stream->common.get_sample_rate(&desc->stream->common); + } + } +#endif PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { ALOGW("sampleRate() unknown thread %d", output); @@ -560,6 +792,12 @@ uint32_t AudioFlinger::sampleRate(audio_io_handle_t output) const int AudioFlinger::channelCount(audio_io_handle_t output) const { Mutex::Autolock _l(mLock); +#ifdef QCOM_HARDWARE + AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(output); + if(desc != NULL) { + return desc->stream->common.get_channels(&desc->stream->common); + } +#endif PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { ALOGW("channelCount() unknown thread %d", output); @@ -582,6 +820,12 @@ audio_format_t AudioFlinger::format(audio_io_handle_t output) const size_t AudioFlinger::frameCount(audio_io_handle_t output) const { Mutex::Autolock _l(mLock); +#ifdef QCOM_HARDWARE + AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(output); + if(desc != NULL) { + return desc->stream->common.get_buffer_size(&desc->stream->common); + } +#endif PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { ALOGW("frameCount() unknown thread %d", output); @@ -785,12 +1029,35 @@ status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value, } AutoMutex lock(mLock); +#ifdef QCOM_HARDWARE + ALOGV("setStreamVolume stream %d, output %d, value %f",stream, output, value); + AudioSessionDescriptor *desc = NULL; + if (!mDirectAudioTracks.isEmpty()) { + desc = mDirectAudioTracks.valueFor(output); + if (desc != NULL) { + ALOGV("setStreamVolume for mAudioTracks size %d desc %p",mDirectAudioTracks.size(),desc); + if (desc->mStreamType == stream) { + mStreamTypes[stream].volume = value; + desc->stream->set_volume(desc->stream, + desc->mVolumeLeft * mStreamTypes[stream].volume, + desc->mVolumeRight* mStreamTypes[stream].volume); + return NO_ERROR; + } + } + } +#endif PlaybackThread *thread = NULL; if (output) { thread = checkPlaybackThread_l(output); if (thread == NULL) { +#ifdef QCOM_HARDWARE + if (desc != NULL) { + return NO_ERROR; + } +#endif return BAD_VALUE; } + } mStreamTypes[stream].volume = value; @@ -917,6 +1184,18 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& return final_result; } +#ifdef QCOM_HARDWARE + AudioSessionDescriptor *desc = NULL; + if (!mDirectAudioTracks.isEmpty()) { + desc = mDirectAudioTracks.valueFor(ioHandle); + if (desc != NULL) { + ALOGV("setParameters for mAudioTracks size %d desc %p",mDirectAudioTracks.size(),desc); + desc->stream->common.set_parameters(&desc->stream->common, keyValuePairs.string()); + return NO_ERROR; + } + } +#endif + // hold a strong ref on thread in case closeOutput() or closeInput() is called // and the thread is exited once the lock is released sp<ThreadBase> thread; @@ -929,13 +1208,17 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& // indicate output device change to all input threads for pre processing AudioParameter param = AudioParameter(keyValuePairs); int value; + DefaultKeyedVector< int, sp<RecordThread> > recordThreads = mRecordThreads; + mLock.unlock(); if ((param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) && (value != 0)) { - for (size_t i = 0; i < mRecordThreads.size(); i++) { - mRecordThreads.valueAt(i)->setParameters(keyValuePairs); + for (size_t i = 0; i < recordThreads.size(); i++) { + recordThreads.valueAt(i)->setParameters(keyValuePairs); } } + mLock.lock(); } + mLock.unlock(); } if (thread != 0) { return thread->setParameters(keyValuePairs); @@ -1056,14 +1339,14 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client) Mutex::Autolock _l(mLock); - pid_t pid = IPCThreadState::self()->getCallingPid(); - if (mNotificationClients.indexOfKey(pid) < 0) { + sp<IBinder> binder = client->asBinder(); + if (mNotificationClients.indexOfKey(binder) < 0) { sp<NotificationClient> notificationClient = new NotificationClient(this, client, - pid); - ALOGV("registerClient() client %p, pid %d", notificationClient.get(), pid); + binder); + ALOGV("registerClient() client %p, binder %d", notificationClient.get(), binder.get); - mNotificationClients.add(pid, notificationClient); + mNotificationClients.add(binder, notificationClient); sp<IBinder> binder = client->asBinder(); binder->linkToDeath(notificationClient); @@ -1080,12 +1363,30 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client) } } -void AudioFlinger::removeNotificationClient(pid_t pid) +#ifdef QCOM_HARDWARE +status_t AudioFlinger::deregisterClient(const sp<IAudioFlingerClient>& client) { + ALOGV("deregisterClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid()); Mutex::Autolock _l(mLock); - mNotificationClients.removeItem(pid); + sp<IBinder> binder = client->asBinder(); + int index = mNotificationClients.indexOfKey(binder); + if (index >= 0) { + mNotificationClients.removeItemsAt(index); + return true; + } + return false; +} +#endif + +void AudioFlinger::removeNotificationClient(sp<IBinder> binder) +{ + Mutex::Autolock _l(mLock); + + mNotificationClients.removeItem(binder); + + int pid = IPCThreadState::self()->getCallingPid(); ALOGV("%d died, releasing its sessions", pid); size_t num = mAudioSessionRefs.size(); bool removed = false; @@ -1110,6 +1411,12 @@ void AudioFlinger::removeNotificationClient(pid_t pid) // audioConfigChanged_l() must be called with AudioFlinger::mLock held void AudioFlinger::audioConfigChanged_l(int event, audio_io_handle_t ioHandle, const void *param2) { +#ifdef QCOM_HARDWARE + ALOGV("AudioFlinger::audioConfigChanged_l: event %d", event); + if (event == AudioSystem::EFFECT_CONFIG_CHANGED) { + mIsEffectConfigChanged = true; + } +#endif size_t size = mNotificationClients.size(); for (size_t i = 0; i < size; i++) { mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioHandle, @@ -1212,6 +1519,15 @@ status_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs) return status; } +#ifdef QCOM_HARDWARE +void AudioFlinger::ThreadBase::effectConfigChanged() { + mAudioFlinger->mLock.lock(); + ALOGV("New effect is being added to LPA chain, Notifying LPA Direct Track"); + mAudioFlinger->audioConfigChanged_l(AudioSystem::EFFECT_CONFIG_CHANGED, 0, NULL); + mAudioFlinger->mLock.unlock(); +} +#endif + void AudioFlinger::ThreadBase::sendIoConfigEvent(int event, int param) { Mutex::Autolock _l(mLock); @@ -2660,7 +2976,10 @@ bool AudioFlinger::PlaybackThread::threadLoop() // only process effects if we're going to write if (sleepTime == 0) { for (size_t i = 0; i < effectChains.size(); i ++) { - effectChains[i]->process_l(); +#ifdef QCOM_HARDWARE + if (effectChains[i] != mAudioFlinger->mLPAEffectChain) +#endif + effectChains[i]->process_l(); } } @@ -5785,8 +6104,8 @@ void AudioFlinger::Client::releaseTimedTrack() AudioFlinger::NotificationClient::NotificationClient(const sp<AudioFlinger>& audioFlinger, const sp<IAudioFlingerClient>& client, - pid_t pid) - : mAudioFlinger(audioFlinger), mPid(pid), mAudioFlingerClient(client) + sp<IBinder> binder) + : mAudioFlinger(audioFlinger), mBinder(binder), mAudioFlingerClient(client) { } @@ -5797,9 +6116,309 @@ AudioFlinger::NotificationClient::~NotificationClient() void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who) { sp<NotificationClient> keep(this); - mAudioFlinger->removeNotificationClient(mPid); + mAudioFlinger->removeNotificationClient(mBinder); +} + +// ---------------------------------------------------------------------------- +#ifdef QCOM_HARDWARE +AudioFlinger::DirectAudioTrack::DirectAudioTrack(const sp<AudioFlinger>& audioFlinger, + int output, AudioSessionDescriptor *outputDesc, + IDirectTrackClient* client, audio_output_flags_t outflag) + : BnDirectTrack(), mIsPaused(false), mAudioFlinger(audioFlinger), mOutput(output), mOutputDesc(outputDesc), + mClient(client), mEffectConfigChanged(false), mKillEffectsThread(false), mFlag(outflag) +{ + if (mFlag & AUDIO_OUTPUT_FLAG_LPA) { + createEffectThread(); + + mAudioFlingerClient = new AudioFlingerDirectTrackClient(this); + mAudioFlinger->registerClient(mAudioFlingerClient); + + allocateBufPool(); + } + mDeathRecipient = new PMDeathRecipient(this); + acquireWakeLock(); +} + +AudioFlinger::DirectAudioTrack::~DirectAudioTrack() { + if (mFlag & AUDIO_OUTPUT_FLAG_LPA) { + requestAndWaitForEffectsThreadExit(); + mAudioFlinger->deregisterClient(mAudioFlingerClient); + mAudioFlinger->deleteEffectSession(); + deallocateBufPool(); + } + releaseWakeLock(); + if (mPowerManager != 0) { + sp<IBinder> binder = mPowerManager->asBinder(); + binder->unlinkToDeath(mDeathRecipient); + } + AudioSystem::releaseOutput(mOutput); +} + +status_t AudioFlinger::DirectAudioTrack::start() { + if(mIsPaused) { + mIsPaused = false; + mOutputDesc->stream->start(mOutputDesc->stream); + } + mOutputDesc->mActive = true; + AudioSystem::startOutput(mOutput, (audio_stream_type_t)mOutputDesc->mStreamType); + return NO_ERROR; +} + +void AudioFlinger::DirectAudioTrack::stop() { + mOutputDesc->mActive = false; + mOutputDesc->stream->stop(mOutputDesc->stream); + AudioSystem::stopOutput(mOutput, (audio_stream_type_t)mOutputDesc->mStreamType); +} + +void AudioFlinger::DirectAudioTrack::pause() { + if(!mIsPaused) { + mIsPaused = true; + mOutputDesc->stream->pause(mOutputDesc->stream); + mOutputDesc->mActive = false; + AudioSystem::stopOutput(mOutput, (audio_stream_type_t)mOutputDesc->mStreamType); + } +} + +ssize_t AudioFlinger::DirectAudioTrack::write(const void *buffer, size_t size) { + ALOGV("Writing to AudioSessionOut"); + int isAvail = 0; + mOutputDesc->stream->is_buffer_available(mOutputDesc->stream, &isAvail); + if (!isAvail) { + return 0; + } + + if (mFlag & AUDIO_OUTPUT_FLAG_LPA) { + mEffectLock.lock(); + List<BufferInfo>::iterator it = mEffectsPool.begin(); + BufferInfo buf = *it; + mEffectsPool.erase(it); + memcpy((char *) buf.localBuf, (char *)buffer, size); + buf.bytesToWrite = size; + mEffectsPool.push_back(buf); + mAudioFlinger->applyEffectsOn(static_cast<void *>(this), (int16_t*)buf.localBuf,(int16_t*)buffer,(int)size); + mEffectLock.unlock(); + } + return mOutputDesc->stream->write(mOutputDesc->stream, buffer, size); +} + +void AudioFlinger::DirectAudioTrack::flush() { + if (mFlag & AUDIO_OUTPUT_FLAG_LPA) { + mEffectsPool.clear(); + mEffectsPool = mBufPool; + } + mOutputDesc->stream->flush(mOutputDesc->stream); +} + +void AudioFlinger::DirectAudioTrack::mute(bool muted) { +} + +void AudioFlinger::DirectAudioTrack::setVolume(float left, float right) { + mOutputDesc->mVolumeLeft = 1.0; + mOutputDesc->mVolumeRight = 1.0; +} + +int64_t AudioFlinger::DirectAudioTrack::getTimeStamp() { + int64_t time; + mOutputDesc->stream->get_next_write_timestamp(mOutputDesc->stream, &time); + ALOGV("Timestamp %lld",time); + return time; +} + +void AudioFlinger::DirectAudioTrack::postEOS(int64_t delayUs) { + ALOGV("Notify Audio Track of EOS event"); + mClient->notify(DIRECT_TRACK_EOS); +} + +void AudioFlinger::DirectAudioTrack::allocateBufPool() { + void *dsp_buf = NULL; + void *local_buf = NULL; + + //1. get the ion buffer information + struct buf_info* buf = NULL; + mOutputDesc->stream->get_buffer_info(mOutputDesc->stream, &buf); + ALOGV("get buffer info %p",buf); + if (!buf) { + ALOGV("buffer is NULL"); + return; + } + int nSize = buf->bufsize; + int bufferCount = buf->nBufs; + + //2. allocate the buffer pool, allocate local buffers + for (int i = 0; i < bufferCount; i++) { + dsp_buf = (void *)buf->buffers[i]; + local_buf = malloc(nSize); + memset(local_buf, 0, nSize); + // Store this information for internal mapping / maintanence + BufferInfo buf(local_buf, dsp_buf, nSize); + buf.bytesToWrite = 0; + mBufPool.push_back(buf); + mEffectsPool.push_back(buf); + + ALOGV("The MEM that is allocated buffer is %x, size %d",(unsigned int)dsp_buf,nSize); + } + free(buf); +} + +void AudioFlinger::DirectAudioTrack::deallocateBufPool() { + + //1. Deallocate the local memory + //2. Remove all the buffers from bufpool + while (!mBufPool.empty()) { + List<BufferInfo>::iterator it = mBufPool.begin(); + BufferInfo &memBuffer = *it; + // free the local buffer corresponding to mem buffer + if (memBuffer.localBuf) { + free(memBuffer.localBuf); + memBuffer.localBuf = NULL; + } + ALOGV("Removing from bufpool"); + mBufPool.erase(it); + } +} + +status_t AudioFlinger::DirectAudioTrack::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + return BnDirectTrack::onTransact(code, data, reply, flags); +} + +void *AudioFlinger::DirectAudioTrack::EffectsThreadWrapper(void *me) { + static_cast<DirectAudioTrack *>(me)->EffectsThreadEntry(); + return NULL; +} + +void AudioFlinger::DirectAudioTrack::EffectsThreadEntry() { + while(1) { + mEffectLock.lock(); + if (!mEffectConfigChanged && !mKillEffectsThread) { + mEffectCv.wait(mEffectLock); + } + + if(mKillEffectsThread) { + mEffectLock.unlock(); + break; + } + + if (mEffectConfigChanged) { + mEffectConfigChanged = false; + for ( List<BufferInfo>::iterator it = mEffectsPool.begin(); + it != mEffectsPool.end(); it++) { + ALOGV("Apply effects on the buffer dspbuf %p, mEffectsPool.size() %d",it->dspBuf,mEffectsPool.size()); + mAudioFlinger->applyEffectsOn(static_cast<void *>(this), + (int16_t *)it->localBuf, + (int16_t *)it->dspBuf, + it->bytesToWrite); + if (mEffectConfigChanged) { + break; + } + } + + } + mEffectLock.unlock(); + } + ALOGV("Effects thread is dead"); + mEffectsThreadAlive = false; +} + +void AudioFlinger::DirectAudioTrack::requestAndWaitForEffectsThreadExit() { + if (!mEffectsThreadAlive) + return; + mKillEffectsThread = true; + mEffectCv.signal(); + pthread_join(mEffectsThread,NULL); + ALOGV("effects thread killed"); +} + +void AudioFlinger::DirectAudioTrack::createEffectThread() { + //Create the effects thread + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + mEffectsThreadAlive = true; + ALOGV("Creating Effects Thread"); + pthread_create(&mEffectsThread, &attr, EffectsThreadWrapper, this); +} +AudioFlinger::DirectAudioTrack::AudioFlingerDirectTrackClient::AudioFlingerDirectTrackClient(void *obj) +{ + ALOGV("AudioFlinger::DirectAudioTrack::AudioFlingerDirectTrackClient"); + pBaseClass = (DirectAudioTrack*)obj; +} + +void AudioFlinger::DirectAudioTrack::AudioFlingerDirectTrackClient::binderDied(const wp<IBinder>& who) { + pBaseClass->mAudioFlinger.clear(); + ALOGW("AudioFlinger server died!"); +} + +void AudioFlinger::DirectAudioTrack::AudioFlingerDirectTrackClient + ::ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2) { + ALOGV("ioConfigChanged() event %d", event); + if (event == AudioSystem::EFFECT_CONFIG_CHANGED) { + ALOGV("Received notification for change in effect module"); + // Seek to current media time - flush the decoded buffers with the driver + pBaseClass->mEffectConfigChanged = true; + // Signal effects thread to re-apply effects + ALOGV("Signalling Effects Thread"); + pBaseClass->mEffectCv.signal(); + + } + ALOGV("ioConfigChanged Out"); +} + +void AudioFlinger::DirectAudioTrack::acquireWakeLock() +{ + Mutex::Autolock _l(pmLock); + + if (mPowerManager == 0) { + // use checkService() to avoid blocking if power service is not up yet + sp<IBinder> binder = + defaultServiceManager()->checkService(String16("power")); + if (binder == 0) { + ALOGW("Thread %s cannot connect to the power manager service", lockName); + } else { + mPowerManager = interface_cast<IPowerManager>(binder); + binder->linkToDeath(mDeathRecipient); + } + } + if (mPowerManager != 0 && mWakeLockToken == 0) { + sp<IBinder> binder = new BBinder(); + status_t status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK, + binder, + String16(lockName)); + if (status == NO_ERROR) { + mWakeLockToken = binder; + } + ALOGV("acquireWakeLock() status %d", status); + } } +void AudioFlinger::DirectAudioTrack::releaseWakeLock() +{ + Mutex::Autolock _l(pmLock); + + if (mWakeLockToken != 0) { + ALOGV("releaseWakeLock()"); + if (mPowerManager != 0) { + mPowerManager->releaseWakeLock(mWakeLockToken, 0); + } + mWakeLockToken.clear(); + } +} + +void AudioFlinger::DirectAudioTrack::clearPowerManager() +{ + Mutex::Autolock _l(pmLock); + releaseWakeLock(); + mPowerManager.clear(); +} + +void AudioFlinger::DirectAudioTrack::PMDeathRecipient::binderDied(const wp<IBinder>& who) +{ + parentClass->clearPowerManager(); + ALOGW("power manager service died !!!"); +} +#endif + // ---------------------------------------------------------------------------- AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::PlaybackThread::Track>& track) @@ -6002,7 +6621,7 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, ThreadBase(audioFlinger, id, AUDIO_DEVICE_NONE, device, RECORD), mInput(input), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL), // mRsmpInIndex and mInputBytes set by readInputParameters() - mReqChannelCount(popcount(channelMask)), + mReqChannelCount(getInputChannelCount(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?) @@ -6617,7 +7236,7 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l() reconfig = true; } if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) { - reqChannelCount = popcount(value); + reqChannelCount = getInputChannelCount(value); reconfig = true; } if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) { @@ -6678,7 +7297,7 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l() reqFormat == mInput->stream->common.get_format(&mInput->stream->common) && reqFormat == AUDIO_FORMAT_PCM_16_BIT && ((int)mInput->stream->common.get_sample_rate(&mInput->stream->common) <= (2 * reqSamplingRate)) && - popcount(mInput->stream->common.get_channels(&mInput->stream->common)) <= FCC_2 && + getInputChannelCount(mInput->stream->common.get_channels(&mInput->stream->common)) <= FCC_2 && (reqChannelCount <= FCC_2)) { status = NO_ERROR; } @@ -6749,7 +7368,7 @@ void AudioFlinger::RecordThread::readInputParameters() mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common); mChannelMask = mInput->stream->common.get_channels(&mInput->stream->common); - mChannelCount = (uint16_t)popcount(mChannelMask); + mChannelCount = (uint16_t)getInputChannelCount(mChannelMask); mFormat = mInput->stream->common.get_format(&mInput->stream->common); mFrameSize = audio_stream_frame_size(&mInput->stream->common); mInputBytes = mInput->stream->common.get_buffer_size(&mInput->stream->common); @@ -7023,7 +7642,18 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module, if (status == NO_ERROR && outStream != NULL) { AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream); - +#ifdef QCOM_HARDWARE + if (flags & AUDIO_OUTPUT_FLAG_LPA || flags & AUDIO_OUTPUT_FLAG_TUNNEL ) { + AudioSessionDescriptor *desc = new AudioSessionDescriptor(hwDevHal, outStream, flags); + desc->mActive = true; + //TODO: no stream type + //desc->mStreamType = streamType; + desc->mVolumeLeft = 1.0; + desc->mVolumeRight = 1.0; + desc->device = *pDevices; + mDirectAudioTracks.add(id, desc); + } else +#endif if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) || (config.format != AUDIO_FORMAT_PCM_16_BIT) || (config.channel_mask != AUDIO_CHANNEL_OUT_STEREO)) { @@ -7033,16 +7663,30 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module, thread = new MixerThread(this, output, id, *pDevices); ALOGV("openOutput() created mixer output: ID %d thread %p", id, thread); } - mPlaybackThreads.add(id, thread); +#ifdef QCOM_HARDWARE + if (thread != NULL) +#endif + mPlaybackThreads.add(id, thread); if (pSamplingRate != NULL) *pSamplingRate = config.sample_rate; if (pFormat != NULL) *pFormat = config.format; if (pChannelMask != NULL) *pChannelMask = config.channel_mask; - if (pLatencyMs != NULL) *pLatencyMs = thread->latency(); - - // notify client processes of the new output creation - thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED); - +#ifdef QCOM_HARDWARE + if (thread != NULL) { +#endif + if (pLatencyMs != NULL) *pLatencyMs = thread->latency(); + // notify client processes of the new output creation + thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED); +#ifdef QCOM_HARDWARE + } + else { + *pLatencyMs = 0; + if ((flags & AUDIO_OUTPUT_FLAG_LPA) || (flags & AUDIO_OUTPUT_FLAG_TUNNEL)) { + AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(id); + *pLatencyMs = desc->stream->get_latency(desc->stream); + } + } +#endif // the first primary output opened designates the primary hw device if ((mPrimaryHardwareDev == NULL) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) { ALOGI("Using module %d has the primary audio interface", module); @@ -7089,6 +7733,21 @@ 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 +#ifdef QCOM_HARDWARE + AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(output); + if (desc) { + ALOGV("Closing DirectTrack output %d", output); + desc->mActive = false; + desc->stream->common.standby(&desc->stream->common); + desc->hwDev->close_output_stream(desc->hwDev, desc->stream); + desc->trackRefPtr = NULL; + mDirectAudioTracks.removeItem(output); + audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, NULL); + delete desc; + return NO_ERROR; + } +#endif + sp<PlaybackThread> thread; { Mutex::Autolock _l(mLock); @@ -7210,7 +7869,7 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, if (status == BAD_VALUE && 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)) { + (getInputChannelCount(config.channel_mask) <= FCC_2) && (getInputChannelCount(reqChannels) <= FCC_2)) { ALOGV("openInput() reopening with proposed sampling rate and channel mask"); inStream = NULL; #ifndef ICS_AUDIO_BLOB @@ -7833,6 +8492,21 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l( addEffectChain_l(chain); chain->setStrategy(getStrategyForSession_l(sessionId)); chainCreated = true; +#ifdef QCOM_HARDWARE + if(sessionId == mAudioFlinger->mLPASessionId) { + // Clear reference to previous effect chain if any + if(mAudioFlinger->mLPAEffectChain.get()) { + mAudioFlinger->mLPAEffectChain.clear(); + } + ALOGV("New EffectChain is created for LPA session ID %d", sessionId); + mAudioFlinger->mLPAEffectChain = chain; + chain->setLPAFlag(true); + // For LPA, the volume will be applied in DSP. No need for volume + // control in the Effect chain, so setting it to unity. + uint32_t volume = 0x1000000; // Equals to 1.0 in 8.24 format + chain->setVolume_l(&volume,&volume); + } +#endif } else { effect = chain->getEffectFromDesc_l(desc); } @@ -7863,6 +8537,11 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l( effect->setDevice(mInDevice); effect->setMode(mAudioFlinger->getMode()); effect->setAudioSource(mAudioSource); +#ifdef QCOM_HARDWARE + if(chain == mAudioFlinger->mLPAEffectChain) { + effect->setLPAFlag(true); + } +#endif } // create effect handle and connect it to effect module handle = new EffectHandle(effect, client, effectClient, priority); @@ -7969,7 +8648,10 @@ void AudioFlinger::ThreadBase::lockEffectChains_l( { effectChains = mEffectChains; for (size_t i = 0; i < mEffectChains.size(); i++) { - mEffectChains[i]->lock(); +#ifdef QCOM_HARDWARE + if (mEffectChains[i] != mAudioFlinger->mLPAEffectChain) +#endif + mEffectChains[i]->lock(); } } @@ -7977,7 +8659,10 @@ void AudioFlinger::ThreadBase::unlockEffectChains( const Vector< sp<AudioFlinger::EffectChain> >& effectChains) { for (size_t i = 0; i < effectChains.size(); i++) { - effectChains[i]->unlock(); +#ifdef QCOM_HARDWARE + if (mEffectChains[i] != mAudioFlinger->mLPAEffectChain) +#endif + effectChains[i]->unlock(); } } @@ -8209,6 +8894,9 @@ AudioFlinger::EffectModule::EffectModule(ThreadBase *thread, // mMaxDisableWaitCnt is set by configure() and not used before then // mDisableWaitCnt is set by process() and updateState() and not used before then mSuspended(false) +#ifdef QCOM_HARDWARE + ,mIsForLPA(false) +#endif { ALOGV("Constructor %p", this); int lStatus; @@ -8334,6 +9022,9 @@ AudioFlinger::EffectHandle *AudioFlinger::EffectModule::controlHandle_l() size_t AudioFlinger::EffectModule::disconnect(EffectHandle *handle, bool unpinIfLast) { +#ifdef QCOM_HARDWARE + setEnabled(false); +#endif ALOGV("disconnect() %p handle %p", this, handle); // keep a strong reference on this EffectModule to avoid calling the // destructor before we exit @@ -8440,8 +9131,19 @@ void AudioFlinger::EffectModule::reset_l() (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_RESET, 0, NULL, 0, NULL); } +#ifndef QCOM_HARDWARE status_t AudioFlinger::EffectModule::configure() { +#else +status_t AudioFlinger::EffectModule::configure(bool isForLPA, int sampleRate, int channelCount, int frameCount) +{ + uint32_t channels; + + // Acquire lock here to make sure that any other thread does not delete + // the effect handle and release the effect module. + Mutex::Autolock _l(mLock); +#endif + if (mEffectInterface == NULL) { return NO_INIT; } @@ -8453,6 +9155,23 @@ status_t AudioFlinger::EffectModule::configure() // TODO: handle configuration of effects replacing track process audio_channel_mask_t channelMask = thread->channelMask(); +#ifdef QCOM_HARDWARE + mIsForLPA = isForLPA; + if(isForLPA) { + if (channelCount == 1) { + channels = AUDIO_CHANNEL_OUT_MONO; + } else { + channels = AUDIO_CHANNEL_OUT_STEREO; + } + ALOGV("%s: LPA ON - channels %d", __func__, channels); + } else { + if (thread->channelCount() == 1) { + channels = AUDIO_CHANNEL_OUT_MONO; + } else { + channels = AUDIO_CHANNEL_OUT_STEREO; + } + } +#endif if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_MONO; @@ -8462,7 +9181,13 @@ status_t AudioFlinger::EffectModule::configure() 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(); +#ifdef QCOM_HARDWARE + if(isForLPA){ + mConfig.inputCfg.samplingRate = sampleRate; + ALOGV("%s: LPA ON - sampleRate %d", __func__, sampleRate); + } else +#endif + mConfig.inputCfg.samplingRate = thread->sampleRate(); mConfig.outputCfg.samplingRate = mConfig.inputCfg.samplingRate; mConfig.inputCfg.bufferProvider.cookie = NULL; mConfig.inputCfg.bufferProvider.getBuffer = NULL; @@ -8487,7 +9212,13 @@ status_t AudioFlinger::EffectModule::configure() } mConfig.inputCfg.mask = EFFECT_CONFIG_ALL; mConfig.outputCfg.mask = EFFECT_CONFIG_ALL; - mConfig.inputCfg.buffer.frameCount = thread->frameCount(); +#ifdef QCOM_HARDWARE + if(isForLPA) { + mConfig.inputCfg.buffer.frameCount = frameCount; + ALOGV("%s: LPA ON - frameCount %d", __func__, frameCount); + } else +#endif + mConfig.inputCfg.buffer.frameCount = thread->frameCount(); mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount; ALOGV("configure() %p thread %p buffer %p framecount %d", @@ -8667,10 +9398,15 @@ status_t AudioFlinger::EffectModule::setEnabled(bool enabled) // must be called with EffectModule::mLock held status_t AudioFlinger::EffectModule::setEnabled_l(bool enabled) { - +#ifdef QCOM_HARDWARE + bool effectStateChanged = false; +#endif ALOGV("setEnabled %p enabled %d", this, enabled); if (enabled != isEnabled()) { +#ifdef QCOM_HARDWARE + effectStateChanged = true; +#endif status_t status = AudioSystem::setEffectEnabled(mId, enabled); if (enabled && status != NO_ERROR) { return status; @@ -8708,6 +9444,16 @@ status_t AudioFlinger::EffectModule::setEnabled_l(bool enabled) } } } +#ifdef QCOM_HARDWARE + /* + Send notification event to LPA Player when an effect for + LPA output is enabled or disabled. + */ + if (effectStateChanged && mIsForLPA) { + sp<ThreadBase> thread = mThread.promote(); + thread->effectConfigChanged(); + } +#endif return NO_ERROR; } @@ -9157,6 +9903,18 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode, return disable(); } +#ifdef QCOM_HARDWARE + ALOGV("EffectHandle::command: isOnLPA %d", mEffect->isOnLPA()); + if(mEffect->isOnLPA() && + ((cmdCode == EFFECT_CMD_SET_PARAM) || (cmdCode == EFFECT_CMD_SET_PARAM_DEFERRED) || + (cmdCode == EFFECT_CMD_SET_PARAM_COMMIT) || (cmdCode == EFFECT_CMD_SET_DEVICE) || + (cmdCode == EFFECT_CMD_SET_VOLUME) || (cmdCode == EFFECT_CMD_SET_AUDIO_MODE)) ) { + // Notify Direct track for the change in Effect module + // TODO: check if it is required to send mLPAHandle + ALOGV("Notifying Direct Track for the change in effect config"); + mClient->audioFlinger()->audioConfigChanged_l(AudioSystem::EFFECT_CONFIG_CHANGED, 0, NULL); + } +#endif return mEffect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData); } @@ -9225,6 +9983,9 @@ AudioFlinger::EffectChain::EffectChain(ThreadBase *thread, : mThread(thread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0), mOwnInBuffer(false), mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX), mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX) +#ifdef QCOM_HARDWARE + ,mIsForLPATrack(false) +#endif { mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC); if (thread == NULL) { @@ -9269,6 +10030,20 @@ sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId_l(int return 0; } +#ifdef QCOM_HARDWARE +sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromIndex_l(int idx) +{ + sp<EffectModule> effect = NULL; + if(idx < 0 || idx >= mEffects.size()) { + ALOGE("EffectChain::getEffectFromIndex_l: invalid index %d", idx); + } + if(mEffects.size() > 0){ + effect = mEffects[idx]; + } + return effect; +} +#endif + // getEffectFromType_l() must be called with ThreadBase::mLock held sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromType_l( const effect_uuid_t *type) @@ -9335,7 +10110,11 @@ void AudioFlinger::EffectChain::process_l() } size_t size = mEffects.size(); +#ifdef QCOM_HARDWARE + if (doProcess || isForLPATrack()) { +#else if (doProcess) { +#endif for (size_t i = 0; i < size; i++) { mEffects[i]->process(); } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 49e2b2c..d2daae7 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -1,6 +1,9 @@ /* ** ** Copyright 2007, The Android Open Source Project +** Copyright (c) 2012, The Linux Foundation. All rights reserved. +** Not a Contribution, Apache license notifications and license are retained +** for attribution purposes only. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -26,6 +29,10 @@ #include <media/IAudioFlinger.h> #include <media/IAudioFlingerClient.h> +#ifdef QCOM_HARDWARE +#include <media/IDirectTrack.h> +#include <media/IDirectTrackClient.h> +#endif #include <media/IAudioTrack.h> #include <media/IAudioRecord.h> #include <media/AudioSystem.h> @@ -52,6 +59,7 @@ #include "AudioWatchdog.h" #include <powermanager/IPowerManager.h> +#include <utils/List.h> namespace android { @@ -99,6 +107,19 @@ public: pid_t tid, int *sessionId, status_t *status); +#ifdef QCOM_HARDWARE + virtual sp<IDirectTrack> createDirectTrack( + pid_t pid, + uint32_t sampleRate, + audio_channel_mask_t channelMask, + audio_io_handle_t output, + int *sessionId, + IDirectTrackClient* client, + audio_stream_type_t streamType, + status_t *status); + + virtual void deleteEffectSession(); +#endif virtual sp<IAudioRecord> openRecord( pid_t pid, @@ -141,7 +162,9 @@ public: virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) const; virtual void registerClient(const sp<IAudioFlingerClient>& client); - +#ifdef QCOM_HARDWARE + virtual status_t deregisterClient(const sp<IAudioFlingerClient>& client); +#endif virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask) const; @@ -216,6 +239,13 @@ public: Parcel* reply, uint32_t flags); +#ifdef QCOM_HARDWARE + void applyEffectsOn(void *token, + int16_t *buffer1, + int16_t *buffer2, + int size); +#endif + // end of IAudioFlinger interface class SyncEvent; @@ -314,7 +344,7 @@ private: public: NotificationClient(const sp<AudioFlinger>& audioFlinger, const sp<IAudioFlingerClient>& client, - pid_t pid); + sp<IBinder> binder); virtual ~NotificationClient(); sp<IAudioFlingerClient> audioFlingerClient() const { return mAudioFlingerClient; } @@ -327,7 +357,7 @@ private: NotificationClient& operator = (const NotificationClient&); const sp<AudioFlinger> mAudioFlinger; - const pid_t mPid; + sp<IBinder> mBinder; const sp<IAudioFlingerClient> mAudioFlingerClient; }; @@ -343,6 +373,9 @@ private: class EffectModule; class EffectHandle; class EffectChain; +#ifdef QCOM_HARDWARE + struct AudioSessionDescriptor; +#endif struct AudioStreamOut; struct AudioStreamIn; @@ -570,6 +603,9 @@ private: virtual status_t setParameters(const String8& keyValuePairs); virtual String8 getParameters(const String8& keys) = 0; virtual void audioConfigChanged_l(int event, int param = 0) = 0; +#ifdef QCOM_HARDWARE + void effectConfigChanged(); +#endif void sendIoConfigEvent(int event, int param = 0); void sendIoConfigEvent_l(int event, int param = 0); void sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio); @@ -1400,6 +1436,115 @@ private: sp<PlaybackThread> getEffectThread_l(int sessionId, int EffectId); // server side of the client's IAudioTrack +#ifdef QCOM_HARDWARE + class DirectAudioTrack : public android::BnDirectTrack, + public AudioEventObserver + { + public: + DirectAudioTrack(const sp<AudioFlinger>& audioFlinger, + int output, AudioSessionDescriptor *outputDesc, + IDirectTrackClient* client, audio_output_flags_t outflag); + virtual ~DirectAudioTrack(); + virtual status_t start(); + virtual void stop(); + virtual void flush(); + virtual void mute(bool); + virtual void pause(); + virtual ssize_t write(const void *buffer, size_t bytes); + virtual void setVolume(float left, float right); + virtual int64_t getTimeStamp(); + virtual void postEOS(int64_t delayUs); + + virtual status_t onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); + private: + + IDirectTrackClient* mClient; + AudioSessionDescriptor *mOutputDesc; + int mOutput; + bool mIsPaused; + audio_output_flags_t mFlag; + + class BufferInfo { + public: + BufferInfo(void *buf1, void *buf2, int32_t nSize) : + localBuf(buf1), dspBuf(buf2), memBufsize(nSize) + {} + + void *localBuf; + void *dspBuf; + uint32_t memBufsize; + uint32_t bytesToWrite; + }; + List<BufferInfo> mBufPool; + List<BufferInfo> mEffectsPool; + + void allocateBufPool(); + void deallocateBufPool(); + + //******Effects************* + static void *EffectsThreadWrapper(void *me); + void EffectsThreadEntry(); + // make sure the Effects thread also exited + void requestAndWaitForEffectsThreadExit(); + void createEffectThread(); + Condition mEffectCv; + Mutex mEffectLock; + pthread_t mEffectsThread; + bool mKillEffectsThread; + bool mEffectsThreadAlive; + bool mEffectConfigChanged; + + //Structure to recieve the Effect notification from the flinger. + class AudioFlingerDirectTrackClient: public IBinder::DeathRecipient, public BnAudioFlingerClient { + public: + AudioFlingerDirectTrackClient(void *obj); + + DirectAudioTrack *pBaseClass; + // DeathRecipient + virtual void binderDied(const wp<IBinder>& who); + + // IAudioFlingerClient + + // indicate a change in the configuration of an output or input: keeps the cached + // values for output/input parameters upto date in client process + virtual void ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2); + + friend class DirectAudioTrack; + }; + // helper function to obtain AudioFlinger service handle + sp<AudioFlinger> mAudioFlinger; + sp<AudioFlingerDirectTrackClient> mAudioFlingerClient; + + void clearPowerManager(); + class PMDeathRecipient : public IBinder::DeathRecipient { + public: + PMDeathRecipient(void *obj){parentClass = (DirectAudioTrack *)obj;} + virtual ~PMDeathRecipient() {} + + // IBinder::DeathRecipient + virtual void binderDied(const wp<IBinder>& who); + + private: + DirectAudioTrack *parentClass; + PMDeathRecipient(const PMDeathRecipient&); + PMDeathRecipient& operator = (const PMDeathRecipient&); + + friend class DirectAudioTrack; + }; + + friend class PMDeathRecipient; + + Mutex pmLock; + void acquireWakeLock(); + void releaseWakeLock(); + + sp<IPowerManager> mPowerManager; + sp<IBinder> mWakeLockToken; + sp<PMDeathRecipient> mDeathRecipient; + }; +#endif + class TrackHandle : public android::BnAudioTrack { public: TrackHandle(const sp<PlaybackThread::Track>& track); @@ -1424,7 +1569,7 @@ private: }; void removeClient_l(pid_t pid); - void removeNotificationClient(pid_t pid); + void removeNotificationClient(sp<IBinder> binder); // record thread @@ -1636,7 +1781,14 @@ private: void *pReplyData); void reset_l(); +#ifdef QCOM_HARDWARE + status_t configure(bool isForLPA = false, + int sampleRate = 0, + int channelCount = 0, + int frameCount = 0); +#else status_t configure(); +#endif status_t init(); effect_state state() const { return mState; @@ -1683,7 +1835,10 @@ private: bool purgeHandles(); void lock() { mLock.lock(); } void unlock() { mLock.unlock(); } - +#ifdef QCOM_HARDWARE + bool isOnLPA() { return mIsForLPA;} + void setLPAFlag(bool isForLPA) {mIsForLPA = isForLPA; } +#endif void dump(int fd, const Vector<String16>& args); protected: @@ -1715,6 +1870,9 @@ mutable Mutex mLock; // mutex for process, commands and handl // sending disable command. uint32_t mDisableWaitCnt; // current process() calls count during disable period. bool mSuspended; // effect is suspended: temporarily disabled by framework +#ifdef QCOM_HARDWARE + bool mIsForLPA; +#endif }; // The EffectHandle class implements the IEffect interface. It provides resources @@ -1823,12 +1981,18 @@ mutable Mutex mLock; // mutex for process, commands and handl status_t addEffect_l(const sp<EffectModule>& handle); size_t removeEffect_l(const sp<EffectModule>& handle); +#ifdef QCOM_HARDWARE + size_t getNumEffects() { return mEffects.size(); } +#endif int sessionId() const { return mSessionId; } void setSessionId(int sessionId) { mSessionId = sessionId; } sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor); sp<EffectModule> getEffectFromId_l(int id); +#ifdef QCOM_HARDWARE + sp<EffectModule> getEffectFromIndex_l(int idx); +#endif sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type); bool setVolume_l(uint32_t *left, uint32_t *right); void setDevice_l(audio_devices_t device); @@ -1874,6 +2038,10 @@ mutable Mutex mLock; // mutex for process, commands and handl void clearInputBuffer(); void dump(int fd, const Vector<String16>& args); +#ifdef QCOM_HARDWARE + bool isForLPATrack() {return mIsForLPATrack; } + void setLPAFlag(bool flag) {mIsForLPATrack = flag;} +#endif protected: friend class AudioFlinger; // for mThread, mEffects @@ -1922,6 +2090,9 @@ mutable Mutex mLock; // mutex for process, commands and handl uint32_t mNewLeftVolume; // new volume on left channel uint32_t mNewRightVolume; // new volume on right channel uint32_t mStrategy; // strategy for this effect chain +#ifdef QCOM_HARDWARE + bool mIsForLPATrack; +#endif // mSuspendedEffects lists all effects currently suspended in the chain. // Use effect type UUID timelow field as key. There is no real risk of identical // timeLow fields among effect type UUIDs. @@ -1983,7 +2154,21 @@ mutable Mutex mLock; // mutex for process, commands and handl AudioStreamIn(AudioHwDevice *dev, audio_stream_in_t *in) : audioHwDev(dev), stream(in) {} }; - +#ifdef QCOM_HARDWARE + struct AudioSessionDescriptor { + bool mActive; + int mStreamType; + float mVolumeLeft; + float mVolumeRight; + audio_hw_device_t *hwDev; + audio_stream_out_t *stream; + audio_output_flags_t flag; + void *trackRefPtr; + audio_devices_t device; + AudioSessionDescriptor(audio_hw_device_t *dev, audio_stream_out_t *out, audio_output_flags_t outflag) : + hwDev(dev), stream(out), flag(outflag) {} + }; +#endif // for mAudioSessionRefs only struct AudioSessionRef { AudioSessionRef(int sessionid, pid_t pid) : @@ -2043,14 +2228,25 @@ mutable Mutex mLock; // mutex for process, commands and handl DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> > mRecordThreads; - DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients; + DefaultKeyedVector< sp<IBinder>, sp<NotificationClient> > mNotificationClients; volatile int32_t mNextUniqueId; // updated by android_atomic_inc audio_mode_t mMode; bool mBtNrecIsOff; - +#ifdef QCOM_HARDWARE + DefaultKeyedVector<audio_io_handle_t, AudioSessionDescriptor *> mDirectAudioTracks; +#endif // protected by mLock +#ifdef QCOM_HARDWARE + volatile bool mIsEffectConfigChanged; +#endif Vector<AudioSessionRef*> mAudioSessionRefs; - +#ifdef QCOM_HARDWARE + sp<EffectChain> mLPAEffectChain; + int mLPASessionId; + int mLPASampleRate; + int mLPANumChannels; + volatile bool mAllChainsLocked; +#endif float masterVolume_l() const; bool masterMute_l() const; audio_module_handle_t loadHwModule_l(const char *name); |