summaryrefslogtreecommitdiffstats
path: root/services/audioflinger/Threads.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/audioflinger/Threads.cpp')
-rw-r--r--services/audioflinger/Threads.cpp126
1 files changed, 97 insertions, 29 deletions
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index e0b664b..c3aafd9 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -910,6 +910,15 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
goto Exit;
}
+ // Reject any effect on multichannel sinks.
+ // TODO: fix both format and multichannel issues with effects.
+ if (mChannelCount != FCC_2) {
+ ALOGW("createEffect_l() Cannot add effect %s for multichannel(%d) thread",
+ desc->name, mChannelCount);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+
// Allow global effects only on offloaded and mixer threads
if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
switch (mType) {
@@ -1146,6 +1155,18 @@ void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect,
}
}
+void AudioFlinger::ThreadBase::getAudioPortConfig(struct audio_port_config *config)
+{
+ config->type = AUDIO_PORT_TYPE_MIX;
+ config->ext.mix.handle = mId;
+ config->sample_rate = mSampleRate;
+ config->format = mFormat;
+ config->channel_mask = mChannelMask;
+ config->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
+ AUDIO_PORT_CONFIG_FORMAT;
+}
+
+
// ----------------------------------------------------------------------------
// Playback
// ----------------------------------------------------------------------------
@@ -1376,9 +1397,10 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
) &&
// PCM data
audio_is_linear_pcm(format) &&
- // mono or stereo
- ( (channelMask == AUDIO_CHANNEL_OUT_MONO) ||
- (channelMask == AUDIO_CHANNEL_OUT_STEREO) ) &&
+ // identical channel mask to sink, or mono in and stereo sink
+ (channelMask == mChannelMask ||
+ (channelMask == AUDIO_CHANNEL_OUT_MONO &&
+ mChannelMask == AUDIO_CHANNEL_OUT_STEREO)) &&
// hardware sample rate
(sampleRate == mSampleRate) &&
// normal mixer has an associated fast mixer
@@ -1482,7 +1504,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
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()) {
+ if (t != 0 && t->isExternalTrack()) {
uint32_t actual = AudioSystem::getStrategyForStream(t->streamType());
if (sessionId == t->sessionId() && strategy != actual) {
ALOGE("createTrack_l() mismatched strategy; expected %u but found %u",
@@ -1495,7 +1517,8 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
if (!isTimed) {
track = new Track(this, client, streamType, sampleRate, format,
- channelMask, frameCount, sharedBuffer, sessionId, uid, *flags);
+ channelMask, frameCount, NULL, sharedBuffer,
+ sessionId, uid, *flags, TrackBase::TYPE_DEFAULT);
} else {
track = TimedTrack::create(this, client, streamType, sampleRate, format,
channelMask, frameCount, sharedBuffer, sessionId, uid);
@@ -1608,7 +1631,7 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
// 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()) {
+ if (track->isExternalTrack()) {
TrackBase::track_state state = track->mState;
mLock.unlock();
status = AudioSystem::startOutput(mId, track->streamType(), track->sessionId());
@@ -1801,9 +1824,10 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()
if (!audio_is_output_channel(mChannelMask)) {
LOG_ALWAYS_FATAL("HAL channel mask %#x not valid for output", mChannelMask);
}
- if ((mType == MIXER || mType == DUPLICATING) && mChannelMask != AUDIO_CHANNEL_OUT_STEREO) {
- LOG_ALWAYS_FATAL("HAL channel mask %#x not supported for mixed output; "
- "must be AUDIO_CHANNEL_OUT_STEREO", mChannelMask);
+ if ((mType == MIXER || mType == DUPLICATING)
+ && !isValidPcmSinkChannelMask(mChannelMask)) {
+ LOG_ALWAYS_FATAL("HAL channel mask %#x not supported for mixed output",
+ mChannelMask);
}
mChannelCount = audio_channel_count_from_out_mask(mChannelMask);
mHALFormat = mOutput->stream->common.get_format(&mOutput->stream->common);
@@ -2044,7 +2068,7 @@ void AudioFlinger::PlaybackThread::threadLoop_removeTracks(
if (count > 0) {
for (size_t i = 0 ; i < count ; i++) {
const sp<Track>& track = tracksToRemove.itemAt(i);
- if (!track->isOutputTrack()) {
+ if (track->isExternalTrack()) {
AudioSystem::stopOutput(mId, track->streamType(), track->sessionId());
#ifdef ADD_BATTERY_DATA
// to track the speaker usage
@@ -2713,6 +2737,26 @@ status_t AudioFlinger::PlaybackThread::releaseAudioPatch_l(const audio_patch_han
return status;
}
+void AudioFlinger::PlaybackThread::addPatchTrack(const sp<PatchTrack>& track)
+{
+ Mutex::Autolock _l(mLock);
+ mTracks.add(track);
+}
+
+void AudioFlinger::PlaybackThread::deletePatchTrack(const sp<PatchTrack>& track)
+{
+ Mutex::Autolock _l(mLock);
+ destroyTrack_l(track);
+}
+
+void AudioFlinger::PlaybackThread::getAudioPortConfig(struct audio_port_config *config)
+{
+ ThreadBase::getAudioPortConfig(config);
+ config->role = AUDIO_PORT_ROLE_SOURCE;
+ config->ext.mix.hw_module = mOutput->audioHwDev->handle();
+ config->ext.mix.usecase.stream = AUDIO_STREAM_DEFAULT;
+}
+
// ----------------------------------------------------------------------------
AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
@@ -2732,11 +2776,6 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
mNormalFrameCount);
mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
- // FIXME - Current mixer implementation only supports stereo output
- if (mChannelCount != FCC_2) {
- ALOGE("Invalid audio hardware channel count %d", mChannelCount);
- }
-
// create an NBAIO sink for the HAL output stream, and negotiate
mOutputSink = new AudioStreamOutSink(output->stream);
size_t numCounterOffers = 0;
@@ -3459,6 +3498,10 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
name,
AudioMixer::TRACK,
AudioMixer::CHANNEL_MASK, (void *)(uintptr_t)track->channelMask());
+ mAudioMixer->setParameter(
+ name,
+ AudioMixer::TRACK,
+ AudioMixer::MIXER_CHANNEL_MASK, (void *)(uintptr_t)mChannelMask);
// limit track sample rate to 2 x output sample rate, which changes at re-configuration
uint32_t maxSampleRate = mSampleRate * 2;
uint32_t reqSampleRate = track->mAudioTrackServerProxy->getSampleRate();
@@ -3697,7 +3740,7 @@ bool AudioFlinger::MixerThread::checkForNewParameter_l(const String8& keyValuePa
reconfig = true;
}
if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
- if ((audio_format_t) value != AUDIO_FORMAT_PCM_16_BIT) {
+ if (!isValidPcmSinkFormat((audio_format_t) value)) {
status = BAD_VALUE;
} else {
// no need to save value, since it's constant
@@ -3705,7 +3748,7 @@ bool AudioFlinger::MixerThread::checkForNewParameter_l(const String8& keyValuePa
}
}
if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
- if ((audio_channel_mask_t) value != AUDIO_CHANNEL_OUT_STEREO) {
+ if (!isValidPcmSinkChannelMask((audio_channel_mask_t) value)) {
status = BAD_VALUE;
} else {
// no need to save value, since it's constant
@@ -5523,8 +5566,8 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe
Mutex::Autolock _l(mLock);
track = new RecordTrack(this, client, sampleRate,
- format, channelMask, frameCount, sessionId, uid,
- *flags);
+ format, channelMask, frameCount, NULL, sessionId, uid,
+ *flags, TrackBase::TYPE_DEFAULT);
lStatus = track->initCheck();
if (lStatus != NO_ERROR) {
@@ -5601,15 +5644,19 @@ status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac
recordTrack->mState = TrackBase::STARTING_1;
mActiveTracks.add(recordTrack);
mActiveTracksGen++;
- mLock.unlock();
- status_t status = AudioSystem::startInput(mId);
- mLock.lock();
- // FIXME should verify that recordTrack is still in mActiveTracks
- if (status != NO_ERROR) {
- mActiveTracks.remove(recordTrack);
- mActiveTracksGen++;
- recordTrack->clearSyncStartEvent();
- return status;
+ status_t status = NO_ERROR;
+ if (recordTrack->isExternalTrack()) {
+ mLock.unlock();
+ status = AudioSystem::startInput(mId);
+ mLock.lock();
+ // FIXME should verify that recordTrack is still in mActiveTracks
+ if (status != NO_ERROR) {
+ mActiveTracks.remove(recordTrack);
+ mActiveTracksGen++;
+ recordTrack->clearSyncStartEvent();
+ ALOGV("RecordThread::start error %d", status);
+ return status;
+ }
}
// Catch up with current buffer indices if thread is already running.
// This is what makes a new client discard all buffered data. If the track's mRsmpInFront
@@ -5634,7 +5681,9 @@ status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac
}
startError:
- AudioSystem::stopInput(mId);
+ if (recordTrack->isExternalTrack()) {
+ AudioSystem::stopInput(mId);
+ }
recordTrack->clearSyncStartEvent();
// FIXME I wonder why we do not reset the state here?
return status;
@@ -6177,5 +6226,24 @@ status_t AudioFlinger::RecordThread::releaseAudioPatch_l(const audio_patch_handl
return status;
}
+void AudioFlinger::RecordThread::addPatchRecord(const sp<PatchRecord>& record)
+{
+ Mutex::Autolock _l(mLock);
+ mTracks.add(record);
+}
+
+void AudioFlinger::RecordThread::deletePatchRecord(const sp<PatchRecord>& record)
+{
+ Mutex::Autolock _l(mLock);
+ destroyTrack_l(record);
+}
+
+void AudioFlinger::RecordThread::getAudioPortConfig(struct audio_port_config *config)
+{
+ ThreadBase::getAudioPortConfig(config);
+ config->role = AUDIO_PORT_ROLE_SINK;
+ config->ext.mix.hw_module = mInput->audioHwDev->handle();
+ config->ext.mix.usecase.source = mAudioSource;
+}
}; // namespace android