diff options
Diffstat (limited to 'services')
| -rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 522 | ||||
| -rw-r--r-- | services/audioflinger/AudioFlinger.h | 157 | ||||
| -rw-r--r-- | services/audioflinger/AudioPolicyService.cpp | 396 | ||||
| -rw-r--r-- | services/audioflinger/AudioPolicyService.h | 62 | 
4 files changed, 924 insertions, 213 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 86d4cc3..482336b 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -81,6 +81,8 @@ static const int kDumpLockSleep = 20000;  static const nsecs_t kWarningThrottle = seconds(5); +// RecordThread loop sleep time upon application overrun or audio HAL read error +static const int kRecordThreadSleepUs = 5000;  // ---------------------------------------------------------------------------- @@ -417,7 +419,7 @@ sp<IAudioTrack> AudioFlinger::createTrack(              lSessionId = *sessionId;          } else {              // if no audio session id is provided, create one here -            lSessionId = nextUniqueId_l(); +            lSessionId = nextUniqueId();              if (sessionId != NULL) {                  *sessionId = lSessionId;              } @@ -725,6 +727,15 @@ status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs)          thread = checkPlaybackThread_l(ioHandle);          if (thread == NULL) {              thread = checkRecordThread_l(ioHandle); +        } else if (thread.get() == primaryPlaybackThread_l()) { +            // indicate output device change to all input threads for pre processing +            AudioParameter param = AudioParameter(keyValuePairs); +            int value; +            if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) { +                for (size_t i = 0; i < mRecordThreads.size(); i++) { +                    mRecordThreads.valueAt(i)->setParameters(keyValuePairs); +                } +            }          }      }      if (thread != NULL) { @@ -873,10 +884,10 @@ void AudioFlinger::removeClient_l(pid_t pid)  // ---------------------------------------------------------------------------- -AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id) +AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id, uint32_t device)      :   Thread(false),          mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0), -        mFrameSize(1), mFormat(0), mStandby(false), mId(id), mExiting(false) +        mFrameSize(1), mFormat(0), mStandby(false), mId(id), mExiting(false), mDevice(device)  {  } @@ -1032,14 +1043,15 @@ status_t AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args      return NO_ERROR;  } -  // ---------------------------------------------------------------------------- -AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device) -    :   ThreadBase(audioFlinger, id), +AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, +                                             AudioStreamOut* output, +                                             int id, +                                             uint32_t device) +    :   ThreadBase(audioFlinger, id, device),          mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output), -        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false), -        mDevice(device) +        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)  {      readOutputParameters(); @@ -1199,9 +1211,9 @@ sp<AudioFlinger::PlaybackThread::Track>  AudioFlinger::PlaybackThread::createTra          }      } -    if (mOutput == 0) { +    lStatus = initCheck(); +    if (lStatus != NO_ERROR) {          LOGE("Audio driver not initialized."); -        lStatus = NO_INIT;          goto Exit;      } @@ -1423,7 +1435,7 @@ status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, ui      if (halFrames == 0 || dspFrames == 0) {          return BAD_VALUE;      } -    if (mOutput == 0) { +    if (initCheck() != NO_ERROR) {          return INVALID_OPERATION;      }      *halFrames = mBytesWritten / audio_stream_frame_size(&mOutput->stream->common); @@ -1468,34 +1480,6 @@ uint32_t AudioFlinger::PlaybackThread::getStrategyForSession_l(int sessionId)      return AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);  } -sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain(int sessionId) -{ -    Mutex::Autolock _l(mLock); -    return getEffectChain_l(sessionId); -} - -sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain_l(int sessionId) -{ -    sp<EffectChain> chain; - -    size_t size = mEffectChains.size(); -    for (size_t i = 0; i < size; i++) { -        if (mEffectChains[i]->sessionId() == sessionId) { -            chain = mEffectChains[i]; -            break; -        } -    } -    return chain; -} - -void AudioFlinger::PlaybackThread::setMode(uint32_t mode) -{ -    Mutex::Autolock _l(mLock); -    size_t size = mEffectChains.size(); -    for (size_t i = 0; i < size; i++) { -        mEffectChains[i]->setMode_l(mode); -    } -}  // ---------------------------------------------------------------------------- @@ -1503,7 +1487,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud      :   PlaybackThread(audioFlinger, output, id, device),          mAudioMixer(0)  { -    mType = PlaybackThread::MIXER; +    mType = ThreadBase::MIXER;      mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);      // FIXME - Current mixer implementation only supports stereo output @@ -2072,7 +2056,7 @@ uint32_t AudioFlinger::MixerThread::suspendSleepTimeUs()  AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)      :   PlaybackThread(audioFlinger, output, id, device)  { -    mType = PlaybackThread::DIRECT; +    mType = ThreadBase::DIRECT;  }  AudioFlinger::DirectOutputThread::~DirectOutputThread() @@ -2551,7 +2535,7 @@ uint32_t AudioFlinger::DirectOutputThread::suspendSleepTimeUs()  AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread, int id)      :   MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->device()), mWaitTimeMs(UINT_MAX)  { -    mType = PlaybackThread::DUPLICATING; +    mType = ThreadBase::DUPLICATING;      addOutputTrack(mainThread);  } @@ -3751,21 +3735,26 @@ sp<IAudioRecord> AudioFlinger::openRecord(          if (sessionId != NULL && *sessionId != AUDIO_SESSION_OUTPUT_MIX) {              lSessionId = *sessionId;          } else { -            lSessionId = nextUniqueId_l(); +            lSessionId = nextUniqueId();              if (sessionId != NULL) {                  *sessionId = lSessionId;              }          }          // create new record track. The record track uses one track in mHardwareMixerThread by convention. -        recordTrack = new RecordThread::RecordTrack(thread, client, sampleRate, -                                                   format, channelMask, frameCount, flags, lSessionId); -    } -    if (recordTrack->getCblk() == NULL) { +        recordTrack = thread->createRecordTrack_l(client, +                                                sampleRate, +                                                format, +                                                channelMask, +                                                frameCount, +                                                flags, +                                                lSessionId, +                                                &lStatus); +    } +    if (lStatus != NO_ERROR) {          // remove local strong reference to Client before deleting the RecordTrack so that the Client          // destructor is called by the TrackBase destructor with mLock held          client.clear();          recordTrack.clear(); -        lStatus = NO_MEMORY;          goto Exit;      } @@ -3814,10 +3803,16 @@ status_t AudioFlinger::RecordHandle::onTransact(  // ---------------------------------------------------------------------------- -AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, AudioStreamIn *input, uint32_t sampleRate, uint32_t channels, int id) : -    ThreadBase(audioFlinger, id), -    mInput(input), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0) +AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, +                                         AudioStreamIn *input, +                                         uint32_t sampleRate, +                                         uint32_t channels, +                                         int id, +                                         uint32_t device) : +    ThreadBase(audioFlinger, id, device), +    mInput(input), mTrack(NULL), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0)  { +    mType = ThreadBase::RECORD;      mReqChannelCount = popcount(channels);      mReqSampleRate = sampleRate;      readInputParameters(); @@ -3847,6 +3842,7 @@ bool AudioFlinger::RecordThread::threadLoop()  {      AudioBufferProvider::Buffer buffer;      sp<RecordTrack> activeTrack; +    Vector< sp<EffectChain> > effectChains;      nsecs_t lastWarning = 0; @@ -3897,14 +3893,22 @@ bool AudioFlinger::RecordThread::threadLoop()                      mStandby = false;                  }              } +            lockEffectChains_l(effectChains);          }          if (mActiveTrack != 0) {              if (mActiveTrack->mState != TrackBase::ACTIVE &&                  mActiveTrack->mState != TrackBase::RESUMING) { -                usleep(5000); +                unlockEffectChains(effectChains); +                usleep(kRecordThreadSleepUs);                  continue;              } +            for (size_t i = 0; i < effectChains.size(); i ++) { +                effectChains[i]->process_l(); +            } +            // enable changes in effect chain +            unlockEffectChains(effectChains); +              buffer.frameCount = mFrameCount;              if (LIKELY(mActiveTrack->getNextBuffer(&buffer) == NO_ERROR)) {                  size_t framesOut = buffer.frameCount; @@ -3953,7 +3957,7 @@ bool AudioFlinger::RecordThread::threadLoop()                                      // Force input into standby so that it tries to                                      // recover at next read attempt                                      mInput->stream->common.standby(&mInput->stream->common); -                                    usleep(5000); +                                    usleep(kRecordThreadSleepUs);                                  }                                  mRsmpInIndex = mFrameCount;                                  framesOut = 0; @@ -4001,9 +4005,12 @@ bool AudioFlinger::RecordThread::threadLoop()                  // Release the processor for a while before asking for a new buffer.                  // This will give the application more chance to read from the buffer and                  // clear the overflow. -                usleep(5000); +                usleep(kRecordThreadSleepUs);              } +        } else { +            unlockEffectChains(effectChains);          } +        effectChains.clear();      }      if (!mStandby) { @@ -4017,6 +4024,49 @@ bool AudioFlinger::RecordThread::threadLoop()      return false;  } + +sp<AudioFlinger::RecordThread::RecordTrack>  AudioFlinger::RecordThread::createRecordTrack_l( +        const sp<AudioFlinger::Client>& client, +        uint32_t sampleRate, +        int format, +        int channelMask, +        int frameCount, +        uint32_t flags, +        int sessionId, +        status_t *status) +{ +    sp<RecordTrack> track; +    status_t lStatus; + +    lStatus = initCheck(); +    if (lStatus != NO_ERROR) { +        LOGE("Audio driver not initialized."); +        goto Exit; +    } + +    { // scope for mLock +        Mutex::Autolock _l(mLock); + +        track = new RecordTrack(this, client, sampleRate, +                      format, channelMask, frameCount, flags, sessionId); + +        if (track->getCblk() == NULL) { +            lStatus = NO_MEMORY; +            goto Exit; +        } + +        mTrack = track.get(); + +    } +    lStatus = NO_ERROR; + +Exit: +    if (status) { +        *status = lStatus; +    } +    return track; +} +  status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack)  {      LOGV("RecordThread::start"); @@ -4146,7 +4196,7 @@ status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer*                  // Force input into standby so that it tries to                  // recover at next read attempt                  mInput->stream->common.standby(&mInput->stream->common); -                usleep(5000); +                usleep(kRecordThreadSleepUs);              }              buffer->raw = 0;              buffer->frameCount = 0; @@ -4211,6 +4261,23 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l()                  reconfig = true;              }          } +        if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) { +            // forward device change to effects that have requested to be +            // aware of attached audio device. +            for (size_t i = 0; i < mEffectChains.size(); i++) { +                mEffectChains[i]->setDevice_l(value); +            } +            // 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() +            if (value & AUDIO_DEVICE_OUT_ALL) { +                mDevice &= (uint32_t)~(value & AUDIO_DEVICE_OUT_ALL); +                status = BAD_VALUE; +            } else { +                mDevice &= (uint32_t)~(value & AUDIO_DEVICE_IN_ALL); +            } +            mDevice |= (uint32_t)value; +        }          if (status == NO_ERROR) {              status = mInput->stream->common.set_parameters(&mInput->stream->common, keyValuePair.string());              if (status == INVALID_OPERATION) { @@ -4320,6 +4387,21 @@ unsigned int AudioFlinger::RecordThread::getInputFramesLost()      return mInput->stream->get_input_frames_lost(mInput->stream);  } +uint32_t AudioFlinger::RecordThread::hasAudioSession(int sessionId) +{ +    Mutex::Autolock _l(mLock); +    uint32_t result = 0; +    if (getEffectChain_l(sessionId) != 0) { +        result = EFFECT_SESSION; +    } + +    if (mTrack != NULL && sessionId == mTrack->sessionId()) { +        result |= TRACK_SESSION; +    } + +    return result; +} +  // ----------------------------------------------------------------------------  int AudioFlinger::openOutput(uint32_t *pDevices, @@ -4368,7 +4450,7 @@ int AudioFlinger::openOutput(uint32_t *pDevices,      mHardwareStatus = AUDIO_HW_IDLE;      if (outStream != NULL) {          AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream); -        int id = nextUniqueId_l(); +        int id = nextUniqueId();          if ((flags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT) ||              (format != AUDIO_FORMAT_PCM_16_BIT) || @@ -4405,7 +4487,7 @@ int AudioFlinger::openDuplicateOutput(int output1, int output2)          return 0;      } -    int id = nextUniqueId_l(); +    int id = nextUniqueId();      DuplicatingThread *thread = new DuplicatingThread(this, thread1, id);      thread->addOutputTrack(thread2);      mPlaybackThreads.add(id, thread); @@ -4428,9 +4510,9 @@ status_t AudioFlinger::closeOutput(int output)          LOGV("closeOutput() %d", output); -        if (thread->type() == PlaybackThread::MIXER) { +        if (thread->type() == ThreadBase::MIXER) {              for (size_t i = 0; i < mPlaybackThreads.size(); i++) { -                if (mPlaybackThreads.valueAt(i)->type() == PlaybackThread::DUPLICATING) { +                if (mPlaybackThreads.valueAt(i)->type() == ThreadBase::DUPLICATING) {                      DuplicatingThread *dupThread = (DuplicatingThread *)mPlaybackThreads.valueAt(i).get();                      dupThread->removeOutputTrack((MixerThread *)thread.get());                  } @@ -4442,7 +4524,7 @@ status_t AudioFlinger::closeOutput(int output)      }      thread->exit(); -    if (thread->type() != PlaybackThread::DUPLICATING) { +    if (thread->type() != ThreadBase::DUPLICATING) {          AudioStreamOut *out = thread->getOutput();          out->hwDev->close_output_stream(out->hwDev, out->stream);          delete out; @@ -4537,9 +4619,17 @@ int AudioFlinger::openInput(uint32_t *pDevices,      if (inStream != NULL) {          AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream); -        int id = nextUniqueId_l(); -         // Start record thread -        thread = new RecordThread(this, input, reqSamplingRate, reqChannels, id); +        int id = nextUniqueId(); +        // Start record thread +        // RecorThread require both input and output device indication to forward to audio +        // pre processing modules +        uint32_t device = (*pDevices) | primaryOutputDevice_l(); +        thread = new RecordThread(this, +                                  input, +                                  reqSamplingRate, +                                  reqChannels, +                                  id, +                                  device);          mRecordThreads.add(id, thread);          LOGV("openInput() created record thread: ID %d thread %p", id, thread);          if (pSamplingRate) *pSamplingRate = reqSamplingRate; @@ -4597,7 +4687,7 @@ status_t AudioFlinger::setStreamOutput(uint32_t stream, int output)      for (size_t i = 0; i < mPlaybackThreads.size(); i++) {          PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();          if (thread != dstThread && -            thread->type() != PlaybackThread::DIRECT) { +            thread->type() != ThreadBase::DIRECT) {              MixerThread *srcThread = (MixerThread *)thread;              srcThread->invalidateTracks(stream);          } @@ -4609,8 +4699,7 @@ status_t AudioFlinger::setStreamOutput(uint32_t stream, int output)  int AudioFlinger::newAudioSessionId()  { -    AutoMutex _l(mLock); -    return nextUniqueId_l(); +    return nextUniqueId();  }  // checkPlaybackThread_l() must be called with AudioFlinger::mLock held @@ -4628,7 +4717,7 @@ AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(int output) const  {      PlaybackThread *thread = checkPlaybackThread_l(output);      if (thread != NULL) { -        if (thread->type() == PlaybackThread::DIRECT) { +        if (thread->type() == ThreadBase::DIRECT) {              thread = NULL;          }      } @@ -4645,12 +4734,34 @@ AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(int input) const      return thread;  } -// nextUniqueId_l() must be called with AudioFlinger::mLock held -int AudioFlinger::nextUniqueId_l() +uint32_t AudioFlinger::nextUniqueId() +{ +    return android_atomic_inc(&mNextUniqueId); +} + +AudioFlinger::PlaybackThread *AudioFlinger::primaryPlaybackThread_l()  { -    return mNextUniqueId++; +    for (size_t i = 0; i < mPlaybackThreads.size(); i++) { +        PlaybackThread *thread = mPlaybackThreads.valueAt(i).get(); +        if (thread->getOutput()->hwDev == mPrimaryHardwareDev) { +            return thread; +        } +    } +    return NULL; +} + +uint32_t AudioFlinger::primaryOutputDevice_l() +{ +    PlaybackThread *thread = primaryPlaybackThread_l(); + +    if (thread == NULL) { +        return 0; +    } + +    return thread->device();  } +  // ----------------------------------------------------------------------------  //  Effect management  // ---------------------------------------------------------------------------- @@ -4683,7 +4794,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,          effect_descriptor_t *pDesc,          const sp<IEffectClient>& effectClient,          int32_t priority, -        int output, +        int io,          int sessionId,          status_t *status,          int *id, @@ -4695,8 +4806,8 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,      sp<Client> client;      wp<Client> wclient; -    LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, output %d", -            pid, effectClient.get(), priority, sessionId, output); +    LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, io %d", +            pid, effectClient.get(), priority, sessionId, io);      if (pDesc == NULL) {          lStatus = BAD_VALUE; @@ -4724,7 +4835,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,          goto Exit;      } -    if (output == 0) { +    if (io == 0) {          if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) {              // output must be specified by AudioPolicyManager when using session              // AUDIO_SESSION_OUTPUT_STAGE @@ -4732,9 +4843,9 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,              goto Exit;          } else if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {              // if the output returned by getOutputForEffect() is removed before we lock the -            // mutex below, the call to checkPlaybackThread_l(output) below will detect it +            // mutex below, the call to checkPlaybackThread_l(io) below will detect it              // and we will exit safely -            output = AudioSystem::getOutputForEffect(&desc); +            io = AudioSystem::getOutputForEffect(&desc);          }      } @@ -4811,31 +4922,41 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,          // output threads.          // If output is 0 here, sessionId is neither SESSION_OUTPUT_STAGE nor SESSION_OUTPUT_MIX          // because of code checking output when entering the function. -        if (output == 0) { +        // Note: io is never 0 when creating an effect on an input +        if (io == 0) {               // look for the thread where the specified audio session is present              for (size_t i = 0; i < mPlaybackThreads.size(); i++) {                  if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) { -                    output = mPlaybackThreads.keyAt(i); +                    io = mPlaybackThreads.keyAt(i);                      break;                  }              } +            if (io == 0) { +               for (size_t i = 0; i < mRecordThreads.size(); i++) { +                   if (mRecordThreads.valueAt(i)->hasAudioSession(sessionId) != 0) { +                       io = mRecordThreads.keyAt(i); +                       break; +                   } +               } +            }              // If no output thread contains the requested session ID, default to              // first output. The effect chain will be moved to the correct output              // thread when a track with the same session ID is created -            if (output == 0 && mPlaybackThreads.size()) { -                output = mPlaybackThreads.keyAt(0); +            if (io == 0 && mPlaybackThreads.size()) { +                io = mPlaybackThreads.keyAt(0);              } +            LOGV("createEffect() got io %d for effect %s", io, desc.name);          } -        LOGV("createEffect() got output %d for effect %s", output, desc.name); -        PlaybackThread *thread = checkPlaybackThread_l(output); +        ThreadBase *thread = checkRecordThread_l(io);          if (thread == NULL) { -            LOGE("createEffect() unknown output thread"); -            lStatus = BAD_VALUE; -            goto Exit; +            thread = checkPlaybackThread_l(io); +            if (thread == NULL) { +                LOGE("createEffect() unknown output thread"); +                lStatus = BAD_VALUE; +                goto Exit; +            }          } -        // TODO: allow attachment of effect to inputs -          wclient = mClients.valueFor(pid);          if (wclient != NULL) { @@ -4943,8 +5064,9 @@ status_t AudioFlinger::moveEffectChain_l(int session,      return NO_ERROR;  } +  // PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held -sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( +sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(          const sp<AudioFlinger::Client>& client,          const sp<IEffectClient>& effectClient,          int32_t priority, @@ -4957,24 +5079,14 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(      sp<EffectModule> effect;      sp<EffectHandle> handle;      status_t lStatus; -    sp<Track> track;      sp<EffectChain> chain;      bool chainCreated = false;      bool effectCreated = false;      bool effectRegistered = false; -    if (mOutput == 0) { +    lStatus = initCheck(); +    if (lStatus != NO_ERROR) {          LOGW("createEffect_l() Audio driver not initialized."); -        lStatus = NO_INIT; -        goto Exit; -    } - -    // Do not allow auxiliary effect on session other than 0 -    if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY && -        sessionId != AUDIO_SESSION_OUTPUT_MIX) { -        LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", -                desc->name, sessionId); -        lStatus = BAD_VALUE;          goto Exit;      } @@ -4986,6 +5098,16 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(          lStatus = BAD_VALUE;          goto Exit;      } +    // Only Pre processor effects are allowed on input threads and only on input threads +    if ((mType == RECORD && +            (desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC) || +            (mType != RECORD && +                    (desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC)) { +        LOGW("createEffect_l() effect %s (flags %08x) created on wrong thread type %d", +                desc->name, desc->flags, mType); +        lStatus = BAD_VALUE; +        goto Exit; +    }      LOGV("createEffect_l() thread %p effect %s on session %d", this, desc->name, sessionId); @@ -5008,7 +5130,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(          LOGV("createEffect_l() got effect %p on chain %p", effect == 0 ? 0 : effect.get(), chain.get());          if (effect == 0) { -            int id = mAudioFlinger->nextUniqueId_l(); +            int id = mAudioFlinger->nextUniqueId();              // Check CPU and memory usage              lStatus = AudioSystem::registerEffect(desc, mId, chain->strategy(), sessionId, id);              if (lStatus != NO_ERROR) { @@ -5059,9 +5181,20 @@ Exit:      return handle;  } +sp<AudioFlinger::EffectModule> AudioFlinger::ThreadBase::getEffect_l(int sessionId, int effectId) +{ +    sp<EffectModule> effect; + +    sp<EffectChain> chain = getEffectChain_l(sessionId); +    if (chain != 0) { +        effect = chain->getEffectFromId_l(effectId); +    } +    return effect; +} +  // PlaybackThread::addEffect_l() must be called with AudioFlinger::mLock and  // PlaybackThread::mLock held -status_t AudioFlinger::PlaybackThread::addEffect_l(const sp<EffectModule>& effect) +status_t AudioFlinger::ThreadBase::addEffect_l(const sp<EffectModule>& effect)  {      // check for existing effect chain with the requested audio session      int sessionId = effect->sessionId(); @@ -5097,7 +5230,7 @@ status_t AudioFlinger::PlaybackThread::addEffect_l(const sp<EffectModule>& effec      return NO_ERROR;  } -void AudioFlinger::PlaybackThread::removeEffect_l(const sp<EffectModule>& effect) { +void AudioFlinger::ThreadBase::removeEffect_l(const sp<EffectModule>& effect) {      LOGV("removeEffect_l() %p effect %p", this, effect.get());      effect_descriptor_t desc = effect->desc(); @@ -5116,7 +5249,53 @@ void AudioFlinger::PlaybackThread::removeEffect_l(const sp<EffectModule>& effect      }  } -void AudioFlinger::PlaybackThread::disconnectEffect(const sp<EffectModule>& effect, +void AudioFlinger::ThreadBase::lockEffectChains_l( +        Vector<sp <AudioFlinger::EffectChain> >& effectChains) +{ +    effectChains = mEffectChains; +    for (size_t i = 0; i < mEffectChains.size(); i++) { +        mEffectChains[i]->lock(); +    } +} + +void AudioFlinger::ThreadBase::unlockEffectChains( +        Vector<sp <AudioFlinger::EffectChain> >& effectChains) +{ +    for (size_t i = 0; i < effectChains.size(); i++) { +        effectChains[i]->unlock(); +    } +} + +sp<AudioFlinger::EffectChain> AudioFlinger::ThreadBase::getEffectChain(int sessionId) +{ +    Mutex::Autolock _l(mLock); +    return getEffectChain_l(sessionId); +} + +sp<AudioFlinger::EffectChain> AudioFlinger::ThreadBase::getEffectChain_l(int sessionId) +{ +    sp<EffectChain> chain; + +    size_t size = mEffectChains.size(); +    for (size_t i = 0; i < size; i++) { +        if (mEffectChains[i]->sessionId() == sessionId) { +            chain = mEffectChains[i]; +            break; +        } +    } +    return chain; +} + +void AudioFlinger::ThreadBase::setMode(uint32_t mode) +{ +    Mutex::Autolock _l(mLock); +    size_t size = mEffectChains.size(); +    for (size_t i = 0; i < size; i++) { +        mEffectChains[i]->setMode_l(mode); +    } +} + +void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect,                                                      const wp<EffectHandle>& handle) {      Mutex::Autolock _l(mLock);      LOGV("disconnectEffect() %p effect %p", this, effect.get()); @@ -5222,35 +5401,6 @@ size_t AudioFlinger::PlaybackThread::removeEffectChain_l(const sp<EffectChain>&      return mEffectChains.size();  } -void AudioFlinger::PlaybackThread::lockEffectChains_l( -        Vector<sp <AudioFlinger::EffectChain> >& effectChains) -{ -    effectChains = mEffectChains; -    for (size_t i = 0; i < mEffectChains.size(); i++) { -        mEffectChains[i]->lock(); -    } -} - -void AudioFlinger::PlaybackThread::unlockEffectChains( -        Vector<sp <AudioFlinger::EffectChain> >& effectChains) -{ -    for (size_t i = 0; i < effectChains.size(); i++) { -        effectChains[i]->unlock(); -    } -} - - -sp<AudioFlinger::EffectModule> AudioFlinger::PlaybackThread::getEffect_l(int sessionId, int effectId) -{ -    sp<EffectModule> effect; - -    sp<EffectChain> chain = getEffectChain_l(sessionId); -    if (chain != 0) { -        effect = chain->getEffectFromId_l(effectId); -    } -    return effect; -} -  status_t AudioFlinger::PlaybackThread::attachAuxEffect(          const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)  { @@ -5291,6 +5441,34 @@ void AudioFlinger::PlaybackThread::detachAuxEffect_l(int effectId)      }  } +status_t AudioFlinger::RecordThread::addEffectChain_l(const sp<EffectChain>& chain) +{ +    // only one chain per input thread +    if (mEffectChains.size() != 0) { +        return INVALID_OPERATION; +    } +    LOGV("addEffectChain_l() %p on thread %p", chain.get(), this); + +    chain->setInBuffer(NULL); +    chain->setOutBuffer(NULL); + +    mEffectChains.add(chain); + +    return NO_ERROR; +} + +size_t AudioFlinger::RecordThread::removeEffectChain_l(const sp<EffectChain>& chain) +{ +    LOGV("removeEffectChain_l() %p from thread %p", chain.get(), this); +    LOGW_IF(mEffectChains.size() != 1, +            "removeEffectChain_l() %p invalid chain size %d on thread %p", +            chain.get(), mEffectChains.size(), this); +    if (mEffectChains.size() == 1) { +        mEffectChains.removeAt(0); +    } +    return 0; +} +  // ----------------------------------------------------------------------------  //  EffectModule implementation  // ---------------------------------------------------------------------------- @@ -5312,12 +5490,11 @@ AudioFlinger::EffectModule::EffectModule(const wp<ThreadBase>& wThread,      if (thread == 0) {          return;      } -    PlaybackThread *p = (PlaybackThread *)thread.get();      memcpy(&mDescriptor, desc, sizeof(effect_descriptor_t));      // create effect engine from effect factory -    mStatus = EffectCreate(&desc->uuid, sessionId, p->id(), &mEffectInterface); +    mStatus = EffectCreate(&desc->uuid, sessionId, thread->id(), &mEffectInterface);      if (mStatus != NO_ERROR) {          return; @@ -5340,6 +5517,13 @@ AudioFlinger::EffectModule::~EffectModule()  {      LOGV("Destructor %p", this);      if (mEffectInterface != NULL) { +        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC || +                (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) { +            sp<ThreadBase> thread = mThread.promote(); +            if (thread != 0) { +                thread->stream()->remove_audio_effect(thread->stream(), mEffectInterface); +            } +        }          // release effect engine          EffectRelease(mEffectInterface);      } @@ -5415,8 +5599,7 @@ void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle)      {          sp<ThreadBase> thread = mThread.promote();          if (thread != 0) { -            PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); -            playbackThread->disconnectEffect(keep, handle); +            thread->disconnectEffect(keep, handle);          }      }  } @@ -5626,6 +5809,14 @@ status_t AudioFlinger::EffectModule::start_l()      if (status == 0) {          status = cmdStatus;      } +    if (status == 0 && +            ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC || +             (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC)) { +        sp<ThreadBase> thread = mThread.promote(); +        if (thread != 0) { +            thread->stream()->add_audio_effect(thread->stream(), mEffectInterface); +        } +    }      return status;  } @@ -5645,6 +5836,14 @@ status_t AudioFlinger::EffectModule::stop_l()      if (status == 0) {          status = cmdStatus;      } +    if (status == 0 && +            ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC || +             (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC)) { +        sp<ThreadBase> thread = mThread.promote(); +        if (thread != 0) { +            thread->stream()->remove_audio_effect(thread->stream(), mEffectInterface); +        } +    }      return status;  } @@ -5784,17 +5983,41 @@ status_t AudioFlinger::EffectModule::setDevice(uint32_t device)  {      Mutex::Autolock _l(mLock);      status_t status = NO_ERROR; -    if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) { -        status_t cmdStatus; -        uint32_t size = sizeof(status_t); -        status = (*mEffectInterface)->command(mEffectInterface, -                                              EFFECT_CMD_SET_DEVICE, -                                              sizeof(uint32_t), -                                              &device, -                                              &size, -                                              &cmdStatus); -        if (status == NO_ERROR) { -            status = cmdStatus; +    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; +        if (dev) { +            status_t cmdStatus; +            uint32_t size = sizeof(status_t); + +            status = (*mEffectInterface)->command(mEffectInterface, +                                                  EFFECT_CMD_SET_DEVICE, +                                                  sizeof(uint32_t), +                                                  &dev, +                                                  &size, +                                                  &cmdStatus); +            if (status == NO_ERROR) { +                status = cmdStatus; +            } +        } +        dev = device & AUDIO_DEVICE_IN_ALL; +        if (dev) { +            status_t cmdStatus; +            uint32_t size = sizeof(status_t); + +            status_t status2 = (*mEffectInterface)->command(mEffectInterface, +                                                  EFFECT_CMD_SET_INPUT_DEVICE, +                                                  sizeof(uint32_t), +                                                  &dev, +                                                  &size, +                                                  &cmdStatus); +            if (status2 == NO_ERROR) { +                status2 = cmdStatus; +            } +            if (status == NO_ERROR) { +                status = status2; +            }          }      }      return status; @@ -6168,7 +6391,6 @@ void AudioFlinger::EffectChain::process_l()          LOGW("process_l(): cannot promote mixer thread");          return;      } -    PlaybackThread *playbackThread = (PlaybackThread *)thread.get();      bool isGlobalSession = (mSessionId == AUDIO_SESSION_OUTPUT_MIX) ||              (mSessionId == AUDIO_SESSION_OUTPUT_STAGE);      bool tracksOnSession = false; @@ -6180,7 +6402,7 @@ void AudioFlinger::EffectChain::process_l()      // will not do it      if (tracksOnSession &&              activeTrackCnt() == 0) { -        size_t numSamples = playbackThread->frameCount() * playbackThread->channelCount(); +        size_t numSamples = thread->frameCount() * thread->channelCount();          memset(mInBuffer, 0, numSamples * sizeof(int16_t));      } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 1fad987..fff4f06 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -157,7 +157,7 @@ public:                          effect_descriptor_t *pDesc,                          const sp<IEffectClient>& effectClient,                          int32_t priority, -                        int output, +                        int io,                          int sessionId,                          status_t *status,                          int *id, @@ -273,9 +273,17 @@ private:      class ThreadBase : public Thread {      public: -        ThreadBase (const sp<AudioFlinger>& audioFlinger, int id); +        ThreadBase (const sp<AudioFlinger>& audioFlinger, int id, uint32_t device);          virtual             ~ThreadBase(); + +        enum type { +            MIXER,              // Thread class is MixerThread +            DIRECT,             // Thread class is DirectOutputThread +            DUPLICATING,        // Thread class is DuplicatingThread +            RECORD              // Thread class is RecordThread +        }; +          status_t dumpBase(int fd, const Vector<String16>& args);          // base for record and playback @@ -377,6 +385,8 @@ private:              int mParam;          }; +        virtual     status_t    initCheck() const = 0; +                    int         type() const { return mType; }                      uint32_t    sampleRate() const;                      int         channelCount() const;                      uint32_t    format() const; @@ -392,6 +402,60 @@ private:                      void        processConfigEvents();                      int         id() const { return mId;}                      bool        standby() { return mStandby; } +                    uint32_t    device() { return mDevice; } +        virtual     audio_stream_t* stream() = 0; + +                    sp<EffectHandle> createEffect_l( +                                        const sp<AudioFlinger::Client>& client, +                                        const sp<IEffectClient>& effectClient, +                                        int32_t priority, +                                        int sessionId, +                                        effect_descriptor_t *desc, +                                        int *enabled, +                                        status_t *status); +                    void disconnectEffect(const sp< EffectModule>& effect, +                                          const wp<EffectHandle>& handle); + +                    // return values for hasAudioSession (bit field) +                    enum effect_state { +                        EFFECT_SESSION = 0x1,   // the audio session corresponds to at least one +                                                // effect +                        TRACK_SESSION = 0x2     // the audio session corresponds to at least one +                                                // track +                    }; + +                    // get effect chain corresponding to session Id. +                    sp<EffectChain> getEffectChain(int sessionId); +                    // same as getEffectChain() but must be called with ThreadBase mutex locked +                    sp<EffectChain> getEffectChain_l(int sessionId); +                    // add an effect chain to the chain list (mEffectChains) +        virtual     status_t addEffectChain_l(const sp<EffectChain>& chain) = 0; +                    // remove an effect chain from the chain list (mEffectChains) +        virtual     size_t removeEffectChain_l(const sp<EffectChain>& chain) = 0; +                    // lock mall effect chains Mutexes. Must be called before releasing the +                    // ThreadBase mutex before processing the mixer and effects. This guarantees the +                    // integrity of the chains during the process. +                    void lockEffectChains_l(Vector<sp <EffectChain> >& effectChains); +                    // unlock effect chains after process +                    void unlockEffectChains(Vector<sp <EffectChain> >& effectChains); +                    // set audio mode to all effect chains +                    void setMode(uint32_t mode); +                    // get effect module with corresponding ID on specified audio session +                    sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId); +                    // add and effect module. Also creates the effect chain is none exists for +                    // the effects audio session +                    status_t addEffect_l(const sp< EffectModule>& effect); +                    // remove and effect module. Also removes the effect chain is this was the last +                    // effect +                    void removeEffect_l(const sp< EffectModule>& effect); +                    // detach all tracks connected to an auxiliary effect +        virtual     void detachAuxEffect_l(int effectId) {} +                    // returns either EFFECT_SESSION if effects on this audio session exist in one +                    // chain, or TRACK_SESSION if tracks on this audio session exist, or both +                    virtual uint32_t hasAudioSession(int sessionId) = 0; +                    // the value returned by default implementation is not important as the +                    // strategy is only meaningful for PlaybackThread which implements this method +                    virtual uint32_t getStrategyForSession_l(int sessionId) { return 0; }          mutable     Mutex                   mLock; @@ -406,6 +470,7 @@ private:          friend class RecordThread;          friend class RecordTrack; +                    int                     mType;                      Condition               mWaitWorkCV;                      sp<AudioFlinger>        mAudioFlinger;                      uint32_t                mSampleRate; @@ -421,18 +486,15 @@ private:                      bool                    mStandby;                      int                     mId;                      bool                    mExiting; +                    Vector< sp<EffectChain> > mEffectChains; +                    uint32_t                mDevice;    // output device for PlaybackThread +                                                        // input + output devices for RecordThread      };      // --- PlaybackThread ---      class PlaybackThread : public ThreadBase {      public: -        enum type { -            MIXER, -            DIRECT, -            DUPLICATING -        }; -          enum mixer_state {              MIXER_IDLE,              MIXER_TRACKS_ENABLED, @@ -569,6 +631,8 @@ private:          virtual     status_t    readyToRun();          virtual     void        onFirstRef(); +        virtual     status_t    initCheck() const { return (mOutput == 0) ? NO_INIT : NO_ERROR; } +          virtual     uint32_t    latency() const;          virtual     status_t    setMasterVolume(float value); @@ -595,8 +659,8 @@ private:                                      status_t *status);                      AudioStreamOut* getOutput() { return mOutput; } +                    virtual audio_stream_t* stream() { return &mOutput->stream->common; } -        virtual     int         type() const { return mType; }                      void        suspend() { mSuspended++; }                      void        restore() { if (mSuspended) mSuspended--; }                      bool        isSuspended() { return (mSuspended != 0); } @@ -605,45 +669,16 @@ private:          virtual     status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);                      int16_t     *mixBuffer() { return mMixBuffer; }; -                    sp<EffectHandle> createEffect_l( -                                        const sp<AudioFlinger::Client>& client, -                                        const sp<IEffectClient>& effectClient, -                                        int32_t priority, -                                        int sessionId, -                                        effect_descriptor_t *desc, -                                        int *enabled, -                                        status_t *status); -                    void disconnectEffect(const sp< EffectModule>& effect, -                                          const wp<EffectHandle>& handle); - -                    // return values for hasAudioSession (bit field) -                    enum effect_state { -                        EFFECT_SESSION = 0x1,   // the audio session corresponds to at least one -                                                // effect -                        TRACK_SESSION = 0x2     // the audio session corresponds to at least one -                                                // track -                    }; - -                    uint32_t hasAudioSession(int sessionId); -                    sp<EffectChain> getEffectChain(int sessionId); -                    sp<EffectChain> getEffectChain_l(int sessionId); -                    status_t addEffectChain_l(const sp<EffectChain>& chain); -                    size_t removeEffectChain_l(const sp<EffectChain>& chain); -                    void lockEffectChains_l(Vector<sp <EffectChain> >& effectChains); -                    void unlockEffectChains(Vector<sp <EffectChain> >& effectChains); - -                    sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId); -                    void detachAuxEffect_l(int effectId); +        virtual     void detachAuxEffect_l(int effectId);                      status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track,                              int EffectId);                      status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track,                              int EffectId); -                    void setMode(uint32_t mode); -                    status_t addEffect_l(const sp< EffectModule>& effect); -                    void removeEffect_l(const sp< EffectModule>& effect); - -                    uint32_t getStrategyForSession_l(int sessionId); +                    virtual status_t addEffectChain_l(const sp<EffectChain>& chain); +                    virtual size_t removeEffectChain_l(const sp<EffectChain>& chain); +                    virtual uint32_t hasAudioSession(int sessionId); +                    virtual uint32_t getStrategyForSession_l(int sessionId);          struct  stream_type_t {              stream_type_t() @@ -656,7 +691,6 @@ private:          };      protected: -        int                             mType;          int16_t*                        mMixBuffer;          int                             mSuspended;          int                             mBytesWritten; @@ -688,8 +722,6 @@ private:          void        readOutputParameters(); -        uint32_t    device() { return mDevice; } -          virtual status_t    dumpInternals(int fd, const Vector<String16>& args);          status_t    dumpTracks(int fd, const Vector<String16>& args);          status_t    dumpEffectChains(int fd, const Vector<String16>& args); @@ -703,8 +735,6 @@ private:          int                             mNumWrites;          int                             mNumDelayedWrites;          bool                            mInWrite; -        Vector< sp<EffectChain> >       mEffectChains; -        uint32_t                        mDevice;      };      class MixerThread : public PlaybackThread { @@ -788,11 +818,13 @@ private:                float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }                void audioConfigChanged_l(int event, int ioHandle, void *param2); -              int  nextUniqueId_l(); +              uint32_t nextUniqueId();                status_t moveEffectChain_l(int session,                                       AudioFlinger::PlaybackThread *srcThread,                                       AudioFlinger::PlaybackThread *dstThread,                                       bool reRegister); +              PlaybackThread *primaryPlaybackThread_l(); +              uint32_t primaryOutputDevice_l();      friend class AudioBuffer; @@ -864,18 +896,33 @@ private:                          AudioStreamIn *input,                          uint32_t sampleRate,                          uint32_t channels, -                        int id); +                        int id, +                        uint32_t device);                  ~RecordThread();          virtual bool        threadLoop();          virtual status_t    readyToRun() { return NO_ERROR; }          virtual void        onFirstRef(); +        virtual status_t    initCheck() const { return (mInput == 0) ? NO_INIT : NO_ERROR; } +                sp<AudioFlinger::RecordThread::RecordTrack>  createRecordTrack_l( +                        const sp<AudioFlinger::Client>& client, +                        uint32_t sampleRate, +                        int format, +                        int channelMask, +                        int frameCount, +                        uint32_t flags, +                        int sessionId, +                        status_t *status); +                  status_t    start(RecordTrack* recordTrack);                  void        stop(RecordTrack* recordTrack);                  status_t    dump(int fd, const Vector<String16>& args);                  AudioStreamIn* getInput() { return mInput; } +                virtual audio_stream_t* stream() { return &mInput->stream->common; } + +                void        setTrack(RecordTrack *recordTrack) { mTrack = recordTrack; }          virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer);          virtual void        releaseBuffer(AudioBufferProvider::Buffer* buffer);          virtual bool        checkForNewParameters_l(); @@ -884,9 +931,14 @@ private:                  void        readInputParameters();          virtual unsigned int  getInputFramesLost(); +        virtual status_t addEffectChain_l(const sp<EffectChain>& chain); +        virtual size_t removeEffectChain_l(const sp<EffectChain>& chain); +        virtual uint32_t hasAudioSession(int sessionId); +      private:                  RecordThread();                  AudioStreamIn                       *mInput; +                RecordTrack*                        mTrack;                  sp<RecordTrack>                     mActiveTrack;                  Condition                           mStartStopCond;                  AudioResampler                      *mResampler; @@ -1103,9 +1155,8 @@ private:          status_t addEffect_l(const sp<EffectModule>& handle);          size_t removeEffect_l(const sp<EffectModule>& handle); -        int sessionId() { -            return mSessionId; -        } +        int sessionId() { return mSessionId; } +        void setSessionId(int sessionId) { mSessionId = sessionId; }          sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor);          sp<EffectModule> getEffectFromId_l(int id); diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp index 8e16d94..dd1e153 100644 --- a/services/audioflinger/AudioPolicyService.cpp +++ b/services/audioflinger/AudioPolicyService.cpp @@ -33,11 +33,14 @@  #include <cutils/properties.h>  #include <dlfcn.h>  #include <hardware_legacy/power.h> +#include <media/AudioEffect.h> +#include <media/EffectsFactoryApi.h>  #include <hardware/hardware.h>  #include <system/audio.h>  #include <system/audio_policy.h>  #include <hardware/audio_policy.h> +#include <audio_effects/audio_effects_conf.h>  namespace android { @@ -101,6 +104,13 @@ AudioPolicyService::AudioPolicyService()      mpAudioPolicy->set_can_mute_enforced_audible(mpAudioPolicy, !forced_val);      LOGI("Loaded audio policy from %s (%s)", module->name, module->id); + +    // load audio pre processing modules +    if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) { +        loadPreProcessorConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE); +    } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) { +        loadPreProcessorConfig(AUDIO_EFFECT_DEFAULT_CONFIG_FILE); +    }  }  AudioPolicyService::~AudioPolicyService() @@ -110,6 +120,31 @@ AudioPolicyService::~AudioPolicyService()      mAudioCommandThread->exit();      mAudioCommandThread.clear(); + +    // release audio pre processing resources +    for (size_t i = 0; i < mInputSources.size(); i++) { +        InputSourceDesc *source = mInputSources.valueAt(i); +        Vector <EffectDesc *> effects = source->mEffects; +        for (size_t j = 0; j < effects.size(); j++) { +            delete effects[j]->mName; +            Vector <effect_param_t *> params = effects[j]->mParams; +            for (size_t k = 0; k < params.size(); k++) { +                delete params[k]; +            } +            params.clear(); +            delete effects[j]; +        } +        effects.clear(); +        delete source; +    } +    mInputSources.clear(); + +    for (size_t i = 0; i < mInputs.size(); i++) { +        mInputs.valueAt(i)->mEffects.clear(); +        delete mInputs.valueAt(i); +    } +    mInputs.clear(); +      if (mpAudioPolicy && mpAudioPolicyDev)          mpAudioPolicyDev->destroy_audio_policy(mpAudioPolicyDev, mpAudioPolicy);      if (mpAudioPolicyDev) @@ -276,13 +311,51 @@ audio_io_handle_t AudioPolicyService::getInput(int inputSource,                                      uint32_t samplingRate,                                      uint32_t format,                                      uint32_t channels, -                                    audio_in_acoustics_t acoustics) +                                    audio_in_acoustics_t acoustics, +                                    int audioSession)  {      if (mpAudioPolicy == NULL) {          return 0;      }      Mutex::Autolock _l(mLock); -    return mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate, format, channels, acoustics); +    audio_io_handle_t input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate, +                                                       format, channels, acoustics); + +    if (input == 0) { +        return input; +    } +    // create audio pre processors according to input source +    ssize_t index = mInputSources.indexOfKey((audio_source_t)inputSource); +    if (index < 0) { +        return input; +    } +    ssize_t idx = mInputs.indexOfKey(input); +    InputDesc *inputDesc; +    if (idx < 0) { +        inputDesc = new InputDesc(); +        inputDesc->mSessionId = audioSession; +        mInputs.add(input, inputDesc); +    } else { +        inputDesc = mInputs.valueAt(idx); +    } + +    Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects; +    for (size_t i = 0; i < effects.size(); i++) { +        EffectDesc *effect = effects[i]; +        sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0, audioSession, input); +        status_t status = fx->initCheck(); +        if (status != NO_ERROR && status != ALREADY_EXISTS) { +            LOGW("Failed to create Fx %s on input %d", effect->mName, input); +            // fx goes out of scope and strong ref on AudioEffect is released +            continue; +        } +        for (size_t j = 0; j < effect->mParams.size(); j++) { +            fx->setParameter(effect->mParams[j]); +        } +        inputDesc->mEffects.add(fx); +    } +    setPreProcessorEnabled(inputDesc, true); +    return input;  }  status_t AudioPolicyService::startInput(audio_io_handle_t input) @@ -291,6 +364,7 @@ status_t AudioPolicyService::startInput(audio_io_handle_t input)          return NO_INIT;      }      Mutex::Autolock _l(mLock); +      return mpAudioPolicy->start_input(mpAudioPolicy, input);  } @@ -300,6 +374,7 @@ status_t AudioPolicyService::stopInput(audio_io_handle_t input)          return NO_INIT;      }      Mutex::Autolock _l(mLock); +      return mpAudioPolicy->stop_input(mpAudioPolicy, input);  } @@ -310,6 +385,16 @@ void AudioPolicyService::releaseInput(audio_io_handle_t input)      }      Mutex::Autolock _l(mLock);      mpAudioPolicy->release_input(mpAudioPolicy, input); + +    ssize_t index = mInputs.indexOfKey(input); +    if (index < 0) { +        return; +    } +    InputDesc *inputDesc = mInputs.valueAt(index); +    setPreProcessorEnabled(inputDesc, false); +    inputDesc->mEffects.clear(); +    delete inputDesc; +    mInputs.removeItemsAt(index);  }  status_t AudioPolicyService::initStreamVolume(audio_stream_type_t stream, @@ -384,7 +469,7 @@ audio_io_handle_t AudioPolicyService::getOutputForEffect(effect_descriptor_t *de  }  status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc, -                                audio_io_handle_t output, +                                audio_io_handle_t io,                                  uint32_t strategy,                                  int session,                                  int id) @@ -392,7 +477,7 @@ status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc,      if (mpAudioPolicy == NULL) {          return NO_INIT;      } -    return mpAudioPolicy->register_effect(mpAudioPolicy, desc, output, strategy, session, id); +    return mpAudioPolicy->register_effect(mpAudioPolicy, desc, io, strategy, session, id);  }  status_t AudioPolicyService::unregisterEffect(int id) @@ -489,6 +574,15 @@ status_t AudioPolicyService::dumpPermissionDenial(int fd)      return NO_ERROR;  } +void AudioPolicyService::setPreProcessorEnabled(InputDesc *inputDesc, bool enabled) +{ +    Vector<sp<AudioEffect> > fxVector = inputDesc->mEffects; +    for (size_t i = 0; i < fxVector.size(); i++) { +        sp<AudioEffect> fx = fxVector.itemAt(i); +        fx->setEnabled(enabled); +    } +} +  status_t AudioPolicyService::onTransact(          uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  { @@ -918,6 +1012,300 @@ int AudioPolicyService::setVoiceVolume(float volume, int delayMs)      return (int)mAudioCommandThread->voiceVolumeCommand(volume, delayMs);  } +// ---------------------------------------------------------------------------- +// Audio pre-processing configuration +// ---------------------------------------------------------------------------- + +const char *AudioPolicyService::kInputSourceNames[AUDIO_SOURCE_CNT -1] = { +    MIC_SRC_TAG, +    VOICE_UL_SRC_TAG, +    VOICE_DL_SRC_TAG, +    VOICE_CALL_SRC_TAG, +    CAMCORDER_SRC_TAG, +    VOICE_REC_SRC_TAG, +    VOICE_COMM_SRC_TAG +}; + +// returns the audio_source_t enum corresponding to the input source name or +// AUDIO_SOURCE_CNT is no match found +audio_source_t AudioPolicyService::inputSourceNameToEnum(const char *name) +{ +    int i; +    for (i = AUDIO_SOURCE_MIC; i < AUDIO_SOURCE_CNT; i++) { +        if (strcmp(name, kInputSourceNames[i - AUDIO_SOURCE_MIC]) == 0) { +            LOGV("inputSourceNameToEnum found source %s %d", name, i); +            break; +        } +    } +    return (audio_source_t)i; +} + +size_t AudioPolicyService::growParamSize(char *param, +                                         size_t size, +                                         size_t *curSize, +                                         size_t *totSize) +{ +    // *curSize is at least sizeof(effect_param_t) + 2 * sizeof(int) +    size_t pos = ((*curSize - 1 ) / size + 1) * size; + +    if (pos + size > *totSize) { +        while (pos + size > *totSize) { +            *totSize += ((*totSize + 7) / 8) * 4; +        } +        param = (char *)realloc(param, *totSize); +    } +    *curSize = pos + size; +    return pos; +} + +size_t AudioPolicyService::readParamValue(cnode *node, +                                          char *param, +                                          size_t *curSize, +                                          size_t *totSize) +{ +    if (strncmp(node->name, SHORT_TAG, sizeof(SHORT_TAG) + 1) == 0) { +        size_t pos = growParamSize(param, sizeof(short), curSize, totSize); +        *(short *)((char *)param + pos) = (short)atoi(node->value); +        LOGV("readParamValue() reading short %d", *(short *)((char *)param + pos)); +        return sizeof(short); +    } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) { +        size_t pos = growParamSize(param, sizeof(int), curSize, totSize); +        *(int *)((char *)param + pos) = atoi(node->value); +        LOGV("readParamValue() reading int %d", *(int *)((char *)param + pos)); +        return sizeof(int); +    } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) { +        size_t pos = growParamSize(param, sizeof(float), curSize, totSize); +        *(float *)((char *)param + pos) = (float)atof(node->value); +        LOGV("readParamValue() reading float %f",*(float *)((char *)param + pos)); +        return sizeof(float); +    } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) { +        size_t pos = growParamSize(param, sizeof(bool), curSize, totSize); +        if (strncmp(node->value, "false", strlen("false") + 1) == 0) { +            *(bool *)((char *)param + pos) = false; +        } else { +            *(bool *)((char *)param + pos) = true; +        } +        LOGV("readParamValue() reading bool %s",*(bool *)((char *)param + pos) ? "true" : "false"); +        return sizeof(bool); +    } else if (strncmp(node->name, STRING_TAG, sizeof(STRING_TAG) + 1) == 0) { +        size_t len = strnlen(node->value, EFFECT_STRING_LEN_MAX); +        if (*curSize + len + 1 > *totSize) { +            *totSize = *curSize + len + 1; +            param = (char *)realloc(param, *totSize); +        } +        strncpy(param + *curSize, node->value, len); +        *curSize += len; +        param[*curSize] = '\0'; +        LOGV("readParamValue() reading string %s", param + *curSize - len); +        return len; +    } +    LOGW("readParamValue() unknown param type %s", node->name); +    return 0; +} + +effect_param_t *AudioPolicyService::loadEffectParameter(cnode *root) +{ +    cnode *param; +    cnode *value; +    size_t curSize = sizeof(effect_param_t); +    size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int); +    effect_param_t *fx_param = (effect_param_t *)malloc(totSize); + +    param = config_find(root, PARAM_TAG); +    value = config_find(root, VALUE_TAG); +    if (param == NULL && value == NULL) { +        // try to parse simple parameter form {int int} +        param = root->first_child; +        if (param) { +            // Note: that a pair of random strings is read as 0 0 +            int *ptr = (int *)fx_param->data; +            int *ptr2 = (int *)((char *)param + sizeof(effect_param_t)); +            LOGW("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2); +            *ptr++ = atoi(param->name); +            *ptr = atoi(param->value); +            fx_param->psize = sizeof(int); +            fx_param->vsize = sizeof(int); +            return fx_param; +        } +    } +    if (param == NULL || value == NULL) { +        LOGW("loadEffectParameter() invalid parameter description %s", root->name); +        goto error; +    } + +    fx_param->psize = 0; +    param = param->first_child; +    while (param) { +        LOGV("loadEffectParameter() reading param of type %s", param->name); +        size_t size = readParamValue(param, (char *)fx_param, &curSize, &totSize); +        if (size == 0) { +            goto error; +        } +        fx_param->psize += size; +        param = param->next; +    } + +    // align start of value field on 32 bit boundary +    curSize = ((curSize - 1 ) / sizeof(int) + 1) * sizeof(int); + +    fx_param->vsize = 0; +    value = value->first_child; +    while (value) { +        LOGV("loadEffectParameter() reading value of type %s", value->name); +        size_t size = readParamValue(value, (char *)fx_param, &curSize, &totSize); +        if (size == 0) { +            goto error; +        } +        fx_param->vsize += size; +        value = value->next; +    } + +    return fx_param; + +error: +    delete fx_param; +    return NULL; +} + +void AudioPolicyService::loadEffectParameters(cnode *root, Vector <effect_param_t *>& params) +{ +    cnode *node = root->first_child; +    while (node) { +        LOGV("loadEffectParameters() loading param %s", node->name); +        effect_param_t *param = loadEffectParameter(node); +        if (param == NULL) { +            node = node->next; +            continue; +        } +        params.add(param); +        node = node->next; +    } +} + +AudioPolicyService::InputSourceDesc *AudioPolicyService::loadInputSource( +                                                            cnode *root, +                                                            const Vector <EffectDesc *>& effects) +{ +    cnode *node = root->first_child; +    if (node == NULL) { +        LOGW("loadInputSource() empty element %s", root->name); +        return NULL; +    } +    InputSourceDesc *source = new InputSourceDesc(); +    while (node) { +        size_t i; +        for (i = 0; i < effects.size(); i++) { +            if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) { +                LOGV("loadInputSource() found effect %s in list", node->name); +                break; +            } +        } +        if (i == effects.size()) { +            LOGV("loadInputSource() effect %s not in list", node->name); +            node = node->next; +            continue; +        } +        EffectDesc *effect = new EffectDesc(*effects[i]); +        loadEffectParameters(node, effect->mParams); +        LOGV("loadInputSource() adding effect %s uuid %08x", effect->mName, effect->mUuid.timeLow); +        source->mEffects.add(effect); +        node = node->next; +    } +    if (source->mEffects.size() == 0) { +        LOGW("loadInputSource() no valid effects found in source %s", root->name); +        delete source; +        return NULL; +    } +    return source; +} + +status_t AudioPolicyService::loadInputSources(cnode *root, const Vector <EffectDesc *>& effects) +{ +    cnode *node = config_find(root, PREPROCESSING_TAG); +    if (node == NULL) { +        return -ENOENT; +    } +    node = node->first_child; +    while (node) { +        audio_source_t source = inputSourceNameToEnum(node->name); +        if (source == AUDIO_SOURCE_CNT) { +            LOGW("loadInputSources() invalid input source %s", node->name); +            node = node->next; +            continue; +        } +        LOGV("loadInputSources() loading input source %s", node->name); +        InputSourceDesc *desc = loadInputSource(node, effects); +        if (desc == NULL) { +            node = node->next; +            continue; +        } +        mInputSources.add(source, desc); +        node = node->next; +    } +    return NO_ERROR; +} + +AudioPolicyService::EffectDesc *AudioPolicyService::loadEffect(cnode *root) +{ +    cnode *node = config_find(root, UUID_TAG); +    if (node == NULL) { +        return NULL; +    } +    effect_uuid_t uuid; +    if (AudioEffect::stringToGuid(node->value, &uuid) != NO_ERROR) { +        LOGW("loadEffect() invalid uuid %s", node->value); +        return NULL; +    } +    EffectDesc *effect = new EffectDesc(); +    effect->mName = strdup(root->name); +    memcpy(&effect->mUuid, &uuid, sizeof(effect_uuid_t)); + +    return effect; +} + +status_t AudioPolicyService::loadEffects(cnode *root, Vector <EffectDesc *>& effects) +{ +    cnode *node = config_find(root, EFFECTS_TAG); +    if (node == NULL) { +        return -ENOENT; +    } +    node = node->first_child; +    while (node) { +        LOGV("loadEffects() loading effect %s", node->name); +        EffectDesc *effect = loadEffect(node); +        if (effect == NULL) { +            node = node->next; +            continue; +        } +        effects.add(effect); +        node = node->next; +    } +    return NO_ERROR; +} + +status_t AudioPolicyService::loadPreProcessorConfig(const char *path) +{ +    cnode *root; +    char *data; + +    data = (char *)load_file(path, NULL); +    if (data == NULL) { +        return -ENODEV; +    } +    root = config_node("", ""); +    config_load(root, data); + +    Vector <EffectDesc *> effects; +    loadEffects(root, effects); +    loadInputSources(root, effects); + +    config_free(root); +    free(root); +    free(data); + +    return NO_ERROR; +} +  /* implementation of the interface to the policy manager */  extern "C" { diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h index b830120..62ad29e 100644 --- a/services/audioflinger/AudioPolicyService.h +++ b/services/audioflinger/AudioPolicyService.h @@ -17,14 +17,17 @@  #ifndef ANDROID_AUDIOPOLICYSERVICE_H  #define ANDROID_AUDIOPOLICYSERVICE_H -#include <media/IAudioPolicyService.h> -#include <media/ToneGenerator.h> +#include <cutils/misc.h> +#include <cutils/config_utils.h>  #include <utils/Vector.h> +#include <utils/SortedVector.h>  #include <binder/BinderService.h> -  #include <system/audio.h>  #include <system/audio_policy.h>  #include <hardware/audio_policy.h> +#include <media/IAudioPolicyService.h> +#include <media/ToneGenerator.h> +#include <media/AudioEffect.h>  namespace android { @@ -78,7 +81,8 @@ public:                                      uint32_t format = AUDIO_FORMAT_DEFAULT,                                      uint32_t channels = 0,                                      audio_in_acoustics_t acoustics = -                                            (audio_in_acoustics_t)0); +                                            (audio_in_acoustics_t)0, +                                    int audioSession = 0);      virtual status_t startInput(audio_io_handle_t input);      virtual status_t stopInput(audio_io_handle_t input);      virtual void releaseInput(audio_io_handle_t input); @@ -93,7 +97,7 @@ public:      virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc);      virtual status_t registerEffect(effect_descriptor_t *desc, -                                    audio_io_handle_t output, +                                    audio_io_handle_t io,                                      uint32_t strategy,                                      int session,                                      int id); @@ -218,6 +222,51 @@ private:          String8 mName;                      // string used by wake lock fo delayed commands      }; +    class EffectDesc { +    public: +        EffectDesc() {} +        virtual ~EffectDesc() {} +        char *mName; +        effect_uuid_t mUuid; +        Vector <effect_param_t *> mParams; +    }; + +    class InputSourceDesc { +    public: +        InputSourceDesc() {} +        virtual ~InputSourceDesc() {} +        Vector <EffectDesc *> mEffects; +    }; + + +    class InputDesc { +    public: +        InputDesc() {} +        virtual ~InputDesc() {} +        int mSessionId; +        Vector< sp<AudioEffect> >mEffects; +    }; + +    static const char *kInputSourceNames[AUDIO_SOURCE_CNT -1]; + +    void setPreProcessorEnabled(InputDesc *inputDesc, bool enabled); +    status_t loadPreProcessorConfig(const char *path); +    status_t loadEffects(cnode *root, Vector <EffectDesc *>& effects); +    EffectDesc *loadEffect(cnode *root); +    status_t loadInputSources(cnode *root, const Vector <EffectDesc *>& effects); +    audio_source_t inputSourceNameToEnum(const char *name); +    InputSourceDesc *loadInputSource(cnode *root, const Vector <EffectDesc *>& effects); +    void loadEffectParameters(cnode *root, Vector <effect_param_t *>& params); +    effect_param_t *loadEffectParameter(cnode *root); +    size_t readParamValue(cnode *node, +                          char *param, +                          size_t *curSize, +                          size_t *totSize); +    size_t growParamSize(char *param, +                         size_t size, +                         size_t *curSize, +                         size_t *totSize); +      // Internal dump utilities.      status_t dumpPermissionDenial(int fd); @@ -226,9 +275,10 @@ private:                              // device connection state  or routing      sp <AudioCommandThread> mAudioCommandThread;    // audio commands thread      sp <AudioCommandThread> mTonePlaybackThread;     // tone playback thread -      struct audio_policy_device *mpAudioPolicyDev;      struct audio_policy *mpAudioPolicy; +    KeyedVector< audio_source_t, InputSourceDesc* > mInputSources; +    KeyedVector< audio_io_handle_t, InputDesc* > mInputs;  };  }; // namespace android  | 
