sp<IAudioTrack> AudioFlinger::createTrack( audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t frameCount, IAudioFlinger::track_flags_t *flags, const sp<IMemory>& sharedBuffer, audio_io_handle_t output, pid_t tid, int *sessionId, status_t *status) { sp<PlaybackThread::Track> track; sp<TrackHandle> trackHandle; sp<Client> client; status_t lStatus; int lSessionId; // client AudioTrack::set already implements AUDIO_STREAM_DEFAULT => AUDIO_STREAM_MUSIC, // but if someone uses binder directly they could bypass that and cause us to crash if (uint32_t(streamType) >= AUDIO_STREAM_CNT) { ALOGE("createTrack() invalid stream type %d", streamType); lStatus = BAD_VALUE; goto Exit; } // client is responsible for conversion of 8-bit PCM to 16-bit PCM, // and we don't yet support 8.24 or 32-bit PCM if (audio_is_linear_pcm(format) && format != AUDIO_FORMAT_PCM_16_BIT) { ALOGE("createTrack() invalid format %d", format); lStatus = BAD_VALUE; goto Exit; } { Mutex::Autolock _l(mLock); PlaybackThread *thread = checkPlaybackThread_l(output); PlaybackThread *effectThread = NULL; if (thread == NULL) { ALOGE("no playback thread found for output handle %d", output); lStatus = BAD_VALUE; goto Exit; } pid_t pid = IPCThreadState::self()->getCallingPid(); client = registerPid_l(pid); ALOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId); //当sessionId==0时,重新生成ID,由此区分MixChain和NoramChain //即不会出现sessionId为0的track,由此可以保留sessionId为0的MixChain保存 //auxiliary类型的effect if (sessionId != NULL && *sessionId != AUDIO_SESSION_OUTPUT_MIX) { // check if an effect chain with the same session ID is present on another // output thread and move it here. // 查找其它线程中中是否有相同的sessionId的Chain,将其移到本线程中 for (size_t i = 0; i < mPlaybackThreads.size(); i++) { sp<PlaybackThread> t = mPlaybackThreads.valueAt(i); if (mPlaybackThreads.keyAt(i) != output) { uint32_t sessions = t->hasAudioSession(*sessionId); if (sessions & PlaybackThread::EFFECT_SESSION) { effectThread = t.get(); break; } } } lSessionId = *sessionId; } else { // if no audio session id is provided, create one here lSessionId = nextUniqueId(); if (sessionId != NULL) { *sessionId = lSessionId; } } ALOGV("createTrack() lSessionId: %d", lSessionId); track = thread->createTrack_l(client, streamType, sampleRate, format, channelMask, frameCount, sharedBuffer, lSessionId, flags, tid, &lStatus); // move effect chain to this output thread if an effect on same session was waiting // for a track to be created // 将Chain切换到本线程中 if (lStatus == NO_ERROR && effectThread != NULL) { Mutex::Autolock _dl(thread->mLock); Mutex::Autolock _sl(effectThread->mLock); moveEffectChain_l(lSessionId, effectThread, thread, true); } // Look for sync events awaiting for a session to be used. for (int i = 0; i < (int)mPendingSyncEvents.size(); i++) { if (mPendingSyncEvents[i]->triggerSession() == lSessionId) { if (thread->isValidSyncEvent(mPendingSyncEvents[i])) { if (lStatus == NO_ERROR) { (void) track->setSyncEvent(mPendingSyncEvents[i]); } else { mPendingSyncEvents[i]->cancel(); } mPendingSyncEvents.removeAt(i); i--; } } } } if (lStatus == NO_ERROR) { trackHandle = new TrackHandle(track); } else { // remove local strong reference to Client before deleting the Track so that the Client // destructor is called by the TrackBase destructor with mLock held client.clear(); track.clear(); } Exit: if (status != NULL) { *status = lStatus; } return trackHandle; } //0、判断是否是fast track模式,来设置输入缓冲区的大小 //1、根据该thread的类型判断输入参数的合法性, // 具体有MIXER、DIRECT、DUPLICATING、RECORD、OFFLOAD五种类型 //2、构造track,根据是否限时,分为track和timetrack,将其添加到mTracks //3、如果获得该会话对应EffectChain的input buffer,作为track的main buffer // 后续由track处理之后的数据交由EffectChain继续处理 //4、根据seesionId关联track与对应的EffectChain,设置track的mMainBuff //5、如果是Fast track,发送配置event消息 sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l( const sp<AudioFlinger::Client>& client, audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t frameCount, const sp<IMemory>& sharedBuffer, int sessionId, IAudioFlinger::track_flags_t *flags, pid_t tid, int uid, status_t *status) { sp<Track> track; status_t lStatus; bool isTimed = (*flags & IAudioFlinger::TRACK_TIMED) != 0; // client expresses a preference for FAST, but we get the final say if (*flags & IAudioFlinger::TRACK_FAST) { // 需要满足以下条件才会创建fast track,否则创建norm track,并将TRACK_FASTD对应的为位设置为0 //1、不限时 //2、属于static类型的track,或者使用输入缓冲区大于等于物理缓冲区的两倍,或者输入缓冲区为0 //3、属于PCM类型 //4、属于单声道或者立体声道 //5、已经构造FastMixer对象,可以对track进行fast mix //6、有足够的Fast track使用(总计8个),初始为1111 1110,最大为0000 0000, // 当mFastTrackAvailMask=0时,表示没有空闲的Fast track if ( // not timed (!isTimed) && // either of these use cases: ( // use case 1: shared buffer with any frame count ( (sharedBuffer != 0) ) || // use case 2: callback handler and frame count is default or at least as large as HAL ( (tid != -1) && ((frameCount == 0) || (frameCount >= mFrameCount)) ) ) && // PCM data audio_is_linear_pcm(format) && // mono or stereo ( (channelMask == AUDIO_CHANNEL_OUT_MONO) || (channelMask == AUDIO_CHANNEL_OUT_STEREO) ) && // hardware sample rate (sampleRate == mSampleRate) && // normal mixer has an associated fast mixer hasFastMixer() && // there are sufficient fast track slots available (mFastTrackAvailMask != 0) // FIXME test that MixerThread for this fast track has a capable output HAL // FIXME add a permission test also? ) { // if frameCount not specified, then it defaults to fast mixer (HAL) frame count // 如果对缓冲区的大小没有特殊要求,则将track的缓冲区大小设置为物理缓冲区的两倍 if (frameCount == 0) { frameCount = mFrameCount * kFastTrackMultiplier; } ALOGV("AUDIO_OUTPUT_FLAG_FAST accepted: frameCount=%d mFrameCount=%d", frameCount, mFrameCount); } else { ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: isTimed=%d sharedBuffer=%p frameCount=%d " "mFrameCount=%d format=%d isLinear=%d channelMask=%#x sampleRate=%u mSampleRate=%u " "hasFastMixer=%d tid=%d fastTrackAvailMask=%#x", isTimed, sharedBuffer.get(), frameCount, mFrameCount, format, audio_is_linear_pcm(format), channelMask, sampleRate, mSampleRate, hasFastMixer(), tid, mFastTrackAvailMask); *flags &= ~IAudioFlinger::TRACK_FAST; // For compatibility with AudioTrack calculation, buffer depth is forced // to be at least 2 x the normal mixer frame count and cover audio hardware latency. // This is probably too conservative, but legacy application code may depend on it. // If you change this calculation, also review the start threshold which is related. // 如果对缓冲区大小有要求,则根据物理缓冲区的延时来计算物理缓冲区对应的最小track缓冲区, // 要求的缓冲区比最小缓冲区小,则将track的缓冲区设置为最小缓冲区, // 其中mNormalFrameCount为norm mixer需要的缓冲区,大于物理缓冲区mFrameCount uint32_t latencyMs = mOutput->stream->get_latency(mOutput->stream); uint32_t minBufCount = latencyMs / ((1000 * mNormalFrameCount) / mSampleRate); if (minBufCount < 2) { minBufCount = 2; } size_t minFrameCount = mNormalFrameCount * minBufCount; if (frameCount < minFrameCount) { frameCount = minFrameCount; } } } //1、如果是直接输出或者进行硬件解码,则输入的采样率、采样精度、声道数需要和物理输出一致 //2、否则输入的采样率必须小于物理采样率,否则会造成重采样失真 if (mType == DIRECT) { if ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM) { if (sampleRate != mSampleRate || format != mFormat || channelMask != mChannelMask) { ALOGE("createTrack_l() Bad parameter: sampleRate %u format %d, channelMask 0x%08x " "for output %p with format %d", sampleRate, format, channelMask, mOutput, mFormat); lStatus = BAD_VALUE; goto Exit; } } } else if (mType == OFFLOAD) { if (sampleRate != mSampleRate || format != mFormat || channelMask != mChannelMask) { ALOGE("createTrack_l() Bad parameter: sampleRate %d format %d, channelMask 0x%08x \"" "for output %p with format %d", sampleRate, format, channelMask, mOutput, mFormat); lStatus = BAD_VALUE; goto Exit; } } else { if ((format & AUDIO_FORMAT_MAIN_MASK) != AUDIO_FORMAT_PCM) { ALOGE("createTrack_l() Bad parameter: format %d \"" "for output %p with format %d", format, mOutput, mFormat); lStatus = BAD_VALUE; goto Exit; } // Resampler implementation limits input sampling rate to 2 x output sampling rate. if (sampleRate > mSampleRate*2) { ALOGE("Sample rate out of range: %u mSampleRate %u", sampleRate, mSampleRate); lStatus = BAD_VALUE; goto Exit; } } lStatus = initCheck(); if (lStatus != NO_ERROR) { ALOGE("Audio driver not initialized."); goto Exit; } { // scope for mLock Mutex::Autolock _l(mLock); // all tracks in same audio session must share the same routing strategy otherwise // conflicts will happen when tracks are moved from one output to another by audio policy // manager // 同一会话sessionID中的track必须设置相同的strategy,否则会导致track切换失败 uint32_t strategy = AudioSystem::getStrategyForStream(streamType); for (size_t i = 0; i < mTracks.size(); ++i) { sp<Track> t = mTracks[i]; if (t != 0 && !t->isOutputTrack()) { uint32_t actual = AudioSystem::getStrategyForStream(t->streamType()); if (sessionId == t->sessionId() && strategy != actual) { ALOGE("createTrack_l() mismatched strategy; expected %u but found %u", strategy, actual); lStatus = BAD_VALUE; goto Exit; } } } // 根据是否限时构造track对象 if (!isTimed) { track = new Track(this, client, streamType, sampleRate, format, channelMask, frameCount, sharedBuffer, sessionId, uid, *flags); } else { track = TimedTrack::create(this, client, streamType, sampleRate, format, channelMask, frameCount, sharedBuffer, sessionId, uid); } if (track == 0 || track->getCblk() == NULL || track->name() < 0) { lStatus = NO_MEMORY; // track must be cleared from the caller as the caller has the AF lock goto Exit; } mTracks.add(track); //根据sessionId关联track和effectChain //数据流:track->mMainBuff(InBuff)->Chain->OutBuff sp<EffectChain> chain = getEffectChain_l(sessionId); if (chain != 0) { ALOGV("createTrack_l() setting main buffer %p", chain->inBuffer()); track->setMainBuffer(chain->inBuffer()); chain->setStrategy(AudioSystem::getStrategyForStream(track->streamType())); chain->incTrackCnt(); } if ((*flags & IAudioFlinger::TRACK_FAST) && (tid != -1)) { pid_t callingPid = IPCThreadState::self()->getCallingPid(); // we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful, // so ask activity manager to do this on our behalf sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp); } } lStatus = NO_ERROR; Exit: if (status) { *status = lStatus; } return track; } // 1、调用Client对象为track分配内存空间,使用客户端已申请sharebuff // 或根据输入的framecount来申请buff // 2、构造track的服务代理对象ServerProxy AudioFlinger::ThreadBase::TrackBase::TrackBase( ThreadBase *thread, const sp<Client>& client, uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t frameCount, const sp<IMemory>& sharedBuffer, int sessionId, int clientUid, bool isOut) : RefBase(), mThread(thread), mClient(client), mCblk(NULL), // mBuffer mState(IDLE), mSampleRate(sampleRate), mFormat(format), mChannelMask(channelMask), mChannelCount(popcount(channelMask)), mFrameSize(audio_is_linear_pcm(format) ? mChannelCount * audio_bytes_per_sample(format) : sizeof(int8_t)), mFrameCount(frameCount), mSessionId(sessionId), mIsOut(isOut), mServerProxy(NULL), mId(android_atomic_inc(&nextTrackId)), mTerminated(false) { // if the caller is us, trust the specified uid if (IPCThreadState::self()->getCallingPid() != getpid_cached || clientUid == -1) { int newclientUid = IPCThreadState::self()->getCallingUid(); if (clientUid != -1 && clientUid != newclientUid) { ALOGW("uid %d tried to pass itself off as %d", newclientUid, clientUid); } clientUid = newclientUid; } // clientUid contains the uid of the app that is responsible for this track, so we can blame // battery usage on it. mUid = clientUid; // client == 0 implies sharedBuffer == 0 ALOG_ASSERT(!(client == 0 && sharedBuffer != 0)); ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size()); // ALOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize); // 计算audio_track_cblk_t和需要传输数据的缓冲区大小, // STREAM模式和STATIC都有audio_track_cblk_t结构,但是STATIC模式没有真正使用 /** * 特别是stream模式下,需要audio_track_cblk_t来协调生成者和消费者,计算共享内存大小 * -------------------------------------------------------- * | audio_track_cblk_t | buffer | * -------------------------------------------------------- */ size_t size = sizeof(audio_track_cblk_t); size_t bufferSize = (sharedBuffer == 0 ? roundup(frameCount) : frameCount) * mFrameSize; if (sharedBuffer == 0) { size += bufferSize; } if (client != 0) { //请求Client中的MemoryDealer工具类来分配buffer //1、如果是STREAM类型,则包含了audio_track_cblk_t结构和数据缓冲区, //2、如果是STATIC,则只有audio_track_cblk_t结构 mCblkMemory = client->heap()->allocate(size); if (mCblkMemory != 0) { mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer()); // can't assume mCblk != NULL } else { ALOGE("not enough memory for AudioTrack size=%u", size); client->heap()->dump("AudioTrack"); return; } } else { // this syntax avoids calling the audio_track_cblk_t constructor twice mCblk = (audio_track_cblk_t *) new uint8_t[size]; // assume mCblk != NULL } // construct the shared structure in-place. // 如果申请内存成功,则在内存中构造audio_track_cblk_t对象来协调生产者和消费者 if (mCblk != NULL) { new(mCblk) audio_track_cblk_t(); // clear all buffers mCblk->frameCount_ = frameCount; if (sharedBuffer == 0) { mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); memset(mBuffer, 0, bufferSize); } else { mBuffer = sharedBuffer->pointer(); #if 0 mCblk->mFlags = CBLK_FORCEREADY; // FIXME hack, need to fix the track ready logic #endif } #ifdef TEE_SINK if (mTeeSinkTrackEnabled) { NBAIO_Format pipeFormat = Format_from_SR_C(mSampleRate, mChannelCount); if (pipeFormat != Format_Invalid) { Pipe *pipe = new Pipe(mTeeSinkTrackFrames, pipeFormat); size_t numCounterOffers = 0; const NBAIO_Format offers[1] = {pipeFormat}; ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers); ALOG_ASSERT(index == 0); PipeReader *pipeReader = new PipeReader(*pipe); numCounterOffers = 0; index = pipeReader->negotiate(offers, 1, NULL, numCounterOffers); ALOG_ASSERT(index == 0); mTeeSink = pipe; mTeeSource = pipeReader; } } #endif } } // 1、调用基类TrackBase的构造函数,为track分配内存空间 // 2、判断是否已经为该normal track分配了内存 // 3、为该track分配AudioMixer中对应的normal track,将索引保存在mName // 4、如果该track也属于fast track类型,查询是否有空闲的fast track, // 为该track分配一个fast track,将索引保存在mFastIndex和mName,最多分配8个 // 5、所以由上可见,normal track和fast track可能同时存在于Track中 AudioFlinger::PlaybackThread::Track::Track( PlaybackThread *thread, const sp<Client>& client, audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t frameCount, const sp<IMemory>& sharedBuffer, int sessionId, int uid, IAudioFlinger::track_flags_t flags) : TrackBase(thread, client, sampleRate, format, channelMask, frameCount, sharedBuffer, sessionId, uid, true /*isOut*/), mFillingUpStatus(FS_INVALID), // mRetryCount initialized later when needed mSharedBuffer(sharedBuffer), mStreamType(streamType), mName(-1), // see note below mMainBuffer(thread->mixBuffer()), mAuxBuffer(NULL), mAuxEffectId(0), mHasVolumeController(false), mPresentationCompleteFrames(0), mFlags(flags), mFastIndex(-1), mCachedVolume(1.0), mIsInvalid(false), mAudioTrackServerProxy(NULL), mResumeToStopping(false) { if (mCblk != NULL) { if (sharedBuffer == 0) { mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount, mFrameSize); } else { mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount, mFrameSize); } mServerProxy = mAudioTrackServerProxy; // to avoid leaking a track name, do not allocate one unless there is an mCblk // 从AudioMixer中分配一个normal track,返回该normal track的index mName = thread->getTrackName_l(channelMask, sessionId); if (mName < 0) { ALOGE("no more track names available"); return; } // only allocate a fast track index if we were able to allocate a normal track name if (flags & IAudioFlinger::TRACK_FAST) { mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads(); ALOG_ASSERT(thread->mFastTrackAvailMask != 0); int i = __builtin_ctz(thread->mFastTrackAvailMask); ALOG_ASSERT(0 < i && i < (int)FastMixerState::kMaxFastTracks); // FIXME This is too eager. We allocate a fast track index before the // fast track becomes active. Since fast tracks are a scarce resource, // this means we are potentially denying other more important fast tracks from // being created. It would be better to allocate the index dynamically. //保存该normal track对应的fast track mFastIndex = i; // Read the initial underruns because this field is never cleared by the fast mixer mObservedUnderruns = thread->getFastTrackUnderruns(i); //初始值mFastTrackAvailMask = 1111 1110,终止值为0000 0000, //初始值i = 1,i的取值范围(0,7) thread->mFastTrackAvailMask &= ~(1 << i); } } ALOGV("Track constructor name %d, calling pid %d", mName, IPCThreadState::self()->getCallingPid()); } //1、将track添加到active tracks中,表示该track处于活动状态 //2、使能track与对应的EffectChain的连接 //3、发送广播 status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track) { status_t status = ALREADY_EXISTS; // set retry count for buffer fill track->mRetryCount = kMaxTrackStartupRetries; if (mActiveTracks.indexOf(track) < 0) { // the track is newly added, make sure it fills up all its // buffers before playing. This is to ensure the client will // effectively get the latency it requested. if (!track->isOutputTrack()) { TrackBase::track_state state = track->mState; mLock.unlock(); status = AudioSystem::startOutput(mId, track->streamType(), track->sessionId()); mLock.lock(); // abort track was stopped/paused while we released the lock if (state != track->mState) { if (status == NO_ERROR) { mLock.unlock(); AudioSystem::stopOutput(mId, track->streamType(), track->sessionId()); mLock.lock(); } return INVALID_OPERATION; } // abort if start is rejected by audio policy manager if (status != NO_ERROR) { return PERMISSION_DENIED; } #ifdef ADD_BATTERY_DATA // to track the speaker usage addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStart); #endif } track->mFillingUpStatus = track->sharedBuffer() != 0 ? Track::FS_FILLED : Track::FS_FILLING; track->mResetDone = false; track->mPresentationCompleteFrames = 0; mActiveTracks.add(track); mWakeLockUids.add(track->uid()); mActiveTracksGeneration++; mLatestActiveTrack = track; sp<EffectChain> chain = getEffectChain_l(track->sessionId()); if (chain != 0) { ALOGV("addTrack_l() starting track on chain %p for session %d", chain.get(), track->sessionId()); chain->incActiveTrackCnt(); } status = NO_ERROR; } ALOGV("signal playback thread"); broadcast_l(); return status; } //0、触发event事件 //1、将track从mTracks中移除,重置mName = -1 //2、修改AudioMixer中的mTrackNames对应位为0,设置mState.tracks[name].enabled = false //3、如果该track为FastTrack,将变量mFastTrackAvailMask相对的位置为1,重置mFastIndex = -1 //4、断开track与对应的EffectChain的连接 void AudioFlinger::PlaybackThread::removeTrack_l(const sp<Track>& track) { track->triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE); mTracks.remove(track); deleteTrackName_l(track->name()); // redundant as track is about to be destroyed, for dumpsys only track->mName = -1; if (track->isFastTrack()) { int index = track->mFastIndex; ALOG_ASSERT(0 < index && index < (int)FastMixerState::kMaxFastTracks); ALOG_ASSERT(!(mFastTrackAvailMask & (1 << index))); mFastTrackAvailMask |= 1 << index; // redundant as track is about to be destroyed, for dumpsys only track->mFastIndex = -1; } sp<EffectChain> chain = getEffectChain_l(track->sessionId()); if (chain != 0) { chain->decTrackCnt(); } } int AudioFlinger::MixerThread::getTrackName_l(audio_channel_mask_t channelMask, int sessionId) { return mAudioMixer->getTrackName(channelMask, sessionId); } //获得AudioMixer端的normal track,并将mTrackNames对应bit置为1,获得该位的indexint int AudioMixer::getTrackName(audio_channel_mask_t channelMask, int sessionId) { uint32_t names = (~mTrackNames) & mConfiguredNames; if (names != 0) { int n = __builtin_ctz(names); ALOGV("add track (%d)", n); mTrackNames |= 1 << n; // assume default parameters for the track, except where noted below track_t* t = &mState.tracks[n]; t->needs = 0; t->volume[0] = UNITY_GAIN; t->volume[1] = UNITY_GAIN; // no initialization needed // t->prevVolume[0] // t->prevVolume[1] t->volumeInc[0] = 0; t->volumeInc[1] = 0; t->auxLevel = 0; t->auxInc = 0; // no initialization needed // t->prevAuxLevel // t->frameCount t->channelCount = 2; t->enabled = false; t->format = 16; t->channelMask = AUDIO_CHANNEL_OUT_STEREO; t->sessionId = sessionId; // setBufferProvider(name, AudioBufferProvider *) is required before enable(name) t->bufferProvider = NULL; t->buffer.raw = NULL; // no initialization needed // t->buffer.frameCount t->hook = NULL; t->in = NULL; t->resampler = NULL; t->sampleRate = mSampleRate; // setParameter(name, TRACK, MAIN_BUFFER, mixBuffer) is required before enable(name) t->mainBuffer = NULL; t->auxBuffer = NULL; t->downmixerBufferProvider = NULL; status_t status = initTrackDownmix(&mState.tracks[n], n, channelMask); if (status == OK) { return TRACK0 + n; } ALOGE("AudioMixer::getTrackName(0x%x) failed, error preparing track for downmix", channelMask); } return -1; } void AudioFlinger::MixerThread::deleteTrackName_l(int name) { ALOGV("remove track (%d) and delete from mixer", name); mAudioMixer->deleteTrackName(name); } status_t AudioFlinger::moveEffectChain_l(int sessionId, AudioFlinger::PlaybackThread *srcThread, AudioFlinger::PlaybackThread *dstThread, bool reRegister) { ALOGV("moveEffectChain_l() session %d from thread %p to thread %p", sessionId, srcThread, dstThread); sp<EffectChain> chain = srcThread->getEffectChain_l(sessionId); if (chain == 0) { ALOGW("moveEffectChain_l() effect chain for session %d not on source thread %p", sessionId, srcThread); return INVALID_OPERATION; } // remove chain first. This is useful only if reconfiguring effect chain on same output thread, // so that a new chain is created with correct parameters when first effect is added. This is // otherwise unnecessary as removeEffect_l() will remove the chain when last effect is // removed. srcThread->removeEffectChain_l(chain); // transfer all effects one by one so that new effect chain is created on new thread with // correct buffer sizes and audio parameters and effect engines reconfigured accordingly audio_io_handle_t dstOutput = dstThread->id(); sp<EffectChain> dstChain; uint32_t strategy = 0; // prevent compiler warning sp<EffectModule> effect = chain->getEffectFromId_l(0); while (effect != 0) { srcThread->removeEffect_l(effect); dstThread->addEffect_l(effect); // removeEffect_l() has stopped the effect if it was active so it must be restarted if (effect->state() == EffectModule::ACTIVE || effect->state() == EffectModule::STOPPING) { effect->start(); } // if the move request is not received from audio policy manager, the effect must be // re-registered with the new strategy and output if (dstChain == 0) { dstChain = effect->chain().promote(); if (dstChain == 0) { ALOGW("moveEffectChain_l() cannot get chain from effect %p", effect.get()); srcThread->addEffect_l(effect); return NO_INIT; } strategy = dstChain->strategy(); } if (reRegister) { AudioSystem::unregisterEffect(effect->id()); AudioSystem::registerEffect(&effect->desc(), dstOutput, strategy, sessionId, effect->id()); } effect = chain->getEffectFromId_l(0); } return NO_ERROR; }