am 493941b8: Allow creation of an audio effect on a session with no audio tracks.
Merge commit '493941b8d8a12ee843d9823c0177f8005a7be54f' into gingerbread-plus-aosp * commit '493941b8d8a12ee843d9823c0177f8005a7be54f': Allow creation of an audio effect on a session with no audio tracks.
This commit is contained in:
@@ -307,6 +307,7 @@ sp<IAudioTrack> AudioFlinger::createTrack(
|
|||||||
{
|
{
|
||||||
Mutex::Autolock _l(mLock);
|
Mutex::Autolock _l(mLock);
|
||||||
PlaybackThread *thread = checkPlaybackThread_l(output);
|
PlaybackThread *thread = checkPlaybackThread_l(output);
|
||||||
|
PlaybackThread *effectThread = NULL;
|
||||||
if (thread == NULL) {
|
if (thread == NULL) {
|
||||||
LOGE("unknown output thread");
|
LOGE("unknown output thread");
|
||||||
lStatus = BAD_VALUE;
|
lStatus = BAD_VALUE;
|
||||||
@@ -324,12 +325,19 @@ sp<IAudioTrack> AudioFlinger::createTrack(
|
|||||||
|
|
||||||
LOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId);
|
LOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId);
|
||||||
if (sessionId != NULL && *sessionId != AudioSystem::SESSION_OUTPUT_MIX) {
|
if (sessionId != NULL && *sessionId != AudioSystem::SESSION_OUTPUT_MIX) {
|
||||||
// prevent same audio session on different output threads
|
|
||||||
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
|
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
|
||||||
if (mPlaybackThreads.keyAt(i) != output &&
|
sp<PlaybackThread> t = mPlaybackThreads.valueAt(i);
|
||||||
mPlaybackThreads.valueAt(i)->hasAudioSession(*sessionId)) {
|
if (mPlaybackThreads.keyAt(i) != output) {
|
||||||
lStatus = BAD_VALUE;
|
// prevent same audio session on different output threads
|
||||||
goto Exit;
|
uint32_t sessions = t->hasAudioSession(*sessionId);
|
||||||
|
if (sessions & PlaybackThread::TRACK_SESSION) {
|
||||||
|
lStatus = BAD_VALUE;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
// check if an effect with same session ID is waiting for a track to be created
|
||||||
|
if (sessions & PlaybackThread::EFFECT_SESSION) {
|
||||||
|
effectThread = t.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lSessionId = *sessionId;
|
lSessionId = *sessionId;
|
||||||
@@ -344,6 +352,14 @@ sp<IAudioTrack> AudioFlinger::createTrack(
|
|||||||
|
|
||||||
track = thread->createTrack_l(client, streamType, sampleRate, format,
|
track = thread->createTrack_l(client, streamType, sampleRate, format,
|
||||||
channelCount, frameCount, sharedBuffer, lSessionId, &lStatus);
|
channelCount, frameCount, sharedBuffer, lSessionId, &lStatus);
|
||||||
|
|
||||||
|
// move effect chain to this output thread if an effect on same session was waiting
|
||||||
|
// for a track to be created
|
||||||
|
if (lStatus == NO_ERROR && effectThread != NULL) {
|
||||||
|
Mutex::Autolock _dl(thread->mLock);
|
||||||
|
Mutex::Autolock _sl(effectThread->mLock);
|
||||||
|
moveEffectChain_l(lSessionId, effectThread, thread, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (lStatus == NO_ERROR) {
|
if (lStatus == NO_ERROR) {
|
||||||
trackHandle = new TrackHandle(track);
|
trackHandle = new TrackHandle(track);
|
||||||
@@ -1377,7 +1393,7 @@ void AudioFlinger::PlaybackThread::readOutputParameters()
|
|||||||
// create a copy of mEffectChains as calling moveEffectChain_l() can reorder some effect chains
|
// create a copy of mEffectChains as calling moveEffectChain_l() can reorder some effect chains
|
||||||
Vector< sp<EffectChain> > effectChains = mEffectChains;
|
Vector< sp<EffectChain> > effectChains = mEffectChains;
|
||||||
for (size_t i = 0; i < effectChains.size(); i ++) {
|
for (size_t i = 0; i < effectChains.size(); i ++) {
|
||||||
mAudioFlinger->moveEffectChain_l(effectChains[i]->sessionId(), this, this);
|
mAudioFlinger->moveEffectChain_l(effectChains[i]->sessionId(), this, this, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1394,22 +1410,24 @@ status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, ui
|
|||||||
return mOutput->getRenderPosition(dspFrames);
|
return mOutput->getRenderPosition(dspFrames);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioFlinger::PlaybackThread::hasAudioSession(int sessionId)
|
uint32_t AudioFlinger::PlaybackThread::hasAudioSession(int sessionId)
|
||||||
{
|
{
|
||||||
Mutex::Autolock _l(mLock);
|
Mutex::Autolock _l(mLock);
|
||||||
|
uint32_t result = 0;
|
||||||
if (getEffectChain_l(sessionId) != 0) {
|
if (getEffectChain_l(sessionId) != 0) {
|
||||||
return true;
|
result = EFFECT_SESSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < mTracks.size(); ++i) {
|
for (size_t i = 0; i < mTracks.size(); ++i) {
|
||||||
sp<Track> track = mTracks[i];
|
sp<Track> track = mTracks[i];
|
||||||
if (sessionId == track->sessionId() &&
|
if (sessionId == track->sessionId() &&
|
||||||
!(track->mCblk->flags & CBLK_INVALID_MSK)) {
|
!(track->mCblk->flags & CBLK_INVALID_MSK)) {
|
||||||
return true;
|
result |= TRACK_SESSION;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t AudioFlinger::PlaybackThread::getStrategyForSession_l(int sessionId)
|
uint32_t AudioFlinger::PlaybackThread::getStrategyForSession_l(int sessionId)
|
||||||
@@ -4704,11 +4722,17 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
|
|||||||
} else {
|
} else {
|
||||||
// look for the thread where the specified audio session is present
|
// look for the thread where the specified audio session is present
|
||||||
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
|
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
|
||||||
if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId)) {
|
if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
|
||||||
output = mPlaybackThreads.keyAt(i);
|
output = mPlaybackThreads.keyAt(i);
|
||||||
break;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PlaybackThread *thread = checkPlaybackThread_l(output);
|
PlaybackThread *thread = checkPlaybackThread_l(output);
|
||||||
@@ -4764,7 +4788,7 @@ status_t AudioFlinger::moveEffects(int session, int srcOutput, int dstOutput)
|
|||||||
|
|
||||||
Mutex::Autolock _dl(dstThread->mLock);
|
Mutex::Autolock _dl(dstThread->mLock);
|
||||||
Mutex::Autolock _sl(srcThread->mLock);
|
Mutex::Autolock _sl(srcThread->mLock);
|
||||||
moveEffectChain_l(session, srcThread, dstThread);
|
moveEffectChain_l(session, srcThread, dstThread, false);
|
||||||
|
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
@@ -4772,7 +4796,8 @@ status_t AudioFlinger::moveEffects(int session, int srcOutput, int dstOutput)
|
|||||||
// moveEffectChain_l mustbe called with both srcThread and dstThread mLocks held
|
// moveEffectChain_l mustbe called with both srcThread and dstThread mLocks held
|
||||||
status_t AudioFlinger::moveEffectChain_l(int session,
|
status_t AudioFlinger::moveEffectChain_l(int session,
|
||||||
AudioFlinger::PlaybackThread *srcThread,
|
AudioFlinger::PlaybackThread *srcThread,
|
||||||
AudioFlinger::PlaybackThread *dstThread)
|
AudioFlinger::PlaybackThread *dstThread,
|
||||||
|
bool reRegister)
|
||||||
{
|
{
|
||||||
LOGV("moveEffectChain_l() session %d from thread %p to thread %p",
|
LOGV("moveEffectChain_l() session %d from thread %p to thread %p",
|
||||||
session, srcThread, dstThread);
|
session, srcThread, dstThread);
|
||||||
@@ -4784,7 +4809,7 @@ status_t AudioFlinger::moveEffectChain_l(int session,
|
|||||||
return INVALID_OPERATION;
|
return INVALID_OPERATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove chain first. This is usefull only if reconfiguring effect chain on same output thread,
|
// 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
|
// so that a new chain is created with correct parameters when first effect is added. This is
|
||||||
// otherwise unecessary as removeEffect_l() will remove the chain when last effect is
|
// otherwise unecessary as removeEffect_l() will remove the chain when last effect is
|
||||||
// removed.
|
// removed.
|
||||||
@@ -4792,10 +4817,32 @@ status_t AudioFlinger::moveEffectChain_l(int session,
|
|||||||
|
|
||||||
// transfer all effects one by one so that new effect chain is created on new thread with
|
// 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
|
// correct buffer sizes and audio parameters and effect engines reconfigured accordingly
|
||||||
|
int dstOutput = dstThread->id();
|
||||||
|
sp<EffectChain> dstChain;
|
||||||
|
uint32_t strategy;
|
||||||
sp<EffectModule> effect = chain->getEffectFromId_l(0);
|
sp<EffectModule> effect = chain->getEffectFromId_l(0);
|
||||||
while (effect != 0) {
|
while (effect != 0) {
|
||||||
srcThread->removeEffect_l(effect);
|
srcThread->removeEffect_l(effect);
|
||||||
dstThread->addEffect_l(effect);
|
dstThread->addEffect_l(effect);
|
||||||
|
// 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) {
|
||||||
|
LOGW("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,
|
||||||
|
session,
|
||||||
|
effect->id());
|
||||||
|
}
|
||||||
effect = chain->getEffectFromId_l(0);
|
effect = chain->getEffectFromId_l(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -613,7 +613,15 @@ private:
|
|||||||
void disconnectEffect(const sp< EffectModule>& effect,
|
void disconnectEffect(const sp< EffectModule>& effect,
|
||||||
const wp<EffectHandle>& handle);
|
const wp<EffectHandle>& handle);
|
||||||
|
|
||||||
bool hasAudioSession(int sessionId);
|
// 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(int sessionId);
|
||||||
sp<EffectChain> getEffectChain_l(int sessionId);
|
sp<EffectChain> getEffectChain_l(int sessionId);
|
||||||
status_t addEffectChain_l(const sp<EffectChain>& chain);
|
status_t addEffectChain_l(const sp<EffectChain>& chain);
|
||||||
@@ -776,7 +784,8 @@ private:
|
|||||||
int nextUniqueId();
|
int nextUniqueId();
|
||||||
status_t moveEffectChain_l(int session,
|
status_t moveEffectChain_l(int session,
|
||||||
AudioFlinger::PlaybackThread *srcThread,
|
AudioFlinger::PlaybackThread *srcThread,
|
||||||
AudioFlinger::PlaybackThread *dstThread);
|
AudioFlinger::PlaybackThread *dstThread,
|
||||||
|
bool reRegister);
|
||||||
|
|
||||||
friend class AudioBuffer;
|
friend class AudioBuffer;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user