summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--services/audioflinger/AudioFlinger.cpp44
-rw-r--r--services/audioflinger/AudioFlinger.h27
-rw-r--r--services/audioflinger/AudioMixer.cpp5
-rw-r--r--services/audioflinger/AudioMixer.h2
-rw-r--r--services/audioflinger/FastMixer.cpp29
-rw-r--r--services/audioflinger/FastMixer.h2
-rw-r--r--services/audioflinger/Threads.cpp36
7 files changed, 111 insertions, 34 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 8bf709e..f10a561 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1594,15 +1594,24 @@ sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_
audio_stream_out_t *outStream = NULL;
// FOR TESTING ONLY:
- // Enable increased sink precision for mixing mode if kEnableExtendedPrecision is true.
- if (kEnableExtendedPrecision && // Check only for Normal Mixing mode
- !(flags & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT))) {
- // Update format
- //config.format = AUDIO_FORMAT_PCM_FLOAT;
- //config.format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
- //config.format = AUDIO_FORMAT_PCM_32_BIT;
- //config.format = AUDIO_FORMAT_PCM_8_24_BIT;
- // ALOGV("openOutput() upgrading format to %#08x", config.format);
+ // This if statement allows overriding the audio policy settings
+ // and forcing a specific format or channel mask to the HAL/Sink device for testing.
+ if (!(flags & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT))) {
+ // Check only for Normal Mixing mode
+ if (kEnableExtendedPrecision) {
+ // Specify format (uncomment one below to choose)
+ //config->format = AUDIO_FORMAT_PCM_FLOAT;
+ //config->format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+ //config->format = AUDIO_FORMAT_PCM_32_BIT;
+ //config->format = AUDIO_FORMAT_PCM_8_24_BIT;
+ // ALOGV("openOutput() upgrading format to %#08x", config.format);
+ }
+ if (kEnableExtendedChannels) {
+ // Specify channel mask (uncomment one below to choose)
+ //config->channel_mask = audio_channel_out_mask_from_count(4); // for USB 4ch
+ //config->channel_mask = audio_channel_mask_from_representation_and_bits(
+ // AUDIO_CHANNEL_REPRESENTATION_INDEX, (1 << 4) - 1); // another 4ch example
+ }
}
status_t status = hwDevHal->open_output_stream(hwDevHal,
@@ -1613,8 +1622,8 @@ sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_
&outStream);
mHardwareStatus = AUDIO_HW_IDLE;
- ALOGV("openOutput_l() openOutputStream returned output %p, SamplingRate %d, Format %#08x, "
- "Channels %x, status %d",
+ ALOGV("openOutput() openOutputStream returned output %p, sampleRate %d, Format %#x, "
+ "channelMask %#x, status %d",
outStream,
config->sample_rate,
config->format,
@@ -1630,7 +1639,7 @@ sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_
ALOGV("openOutput() created offload output: ID %d thread %p", id, thread);
} else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
|| !isValidPcmSinkFormat(config->format)
- || (config->channel_mask != AUDIO_CHANNEL_OUT_STEREO)) {
+ || !isValidPcmSinkChannelMask(config->channel_mask)) {
thread = new DirectOutputThread(this, output, id, device);
ALOGV("openOutput() created direct output: ID %d thread %p", id, thread);
} else {
@@ -1792,7 +1801,6 @@ status_t AudioFlinger::closeOutput_nonvirtual(audio_io_handle_t output)
closeOutputFinish(thread);
}
- thread.clear();
return NO_ERROR;
}
@@ -2515,6 +2523,16 @@ status_t AudioFlinger::moveEffectChain_l(int sessionId,
return INVALID_OPERATION;
}
+ // Check whether the destination thread has a channel count of FCC_2, which is
+ // currently required for (most) effects. Prevent moving the effect chain here rather
+ // than disabling the addEffect_l() call in dstThread below.
+ if (dstThread->mChannelCount != FCC_2) {
+ ALOGW("moveEffectChain_l() effect chain failed because"
+ " destination thread %p channel count(%u) != %u",
+ dstThread, dstThread->mChannelCount, FCC_2);
+ 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
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 2830e6d..ab4c567 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -55,6 +55,7 @@
#include "FastMixer.h"
#include <media/nbaio/NBAIO.h>
#include "AudioWatchdog.h"
+#include "AudioMixer.h"
#include <powermanager/IPowerManager.h>
@@ -327,6 +328,30 @@ private:
audio_devices_t devices);
void purgeStaleEffects_l();
+ // Set kEnableExtendedChannels to true to enable greater than stereo output
+ // for the MixerThread and device sink. Number of channels allowed is
+ // FCC_2 <= channels <= AudioMixer::MAX_NUM_CHANNELS.
+ static const bool kEnableExtendedChannels = false;
+
+ // Returns true if channel mask is permitted for the PCM sink in the MixerThread
+ static inline bool isValidPcmSinkChannelMask(audio_channel_mask_t channelMask) {
+ switch (audio_channel_mask_get_representation(channelMask)) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION: {
+ uint32_t channelCount = FCC_2; // stereo is default
+ if (kEnableExtendedChannels) {
+ channelCount = audio_channel_count_from_out_mask(channelMask);
+ if (channelCount > AudioMixer::MAX_NUM_CHANNELS) {
+ return false;
+ }
+ }
+ // check that channelMask is the "canonical" one we expect for the channelCount.
+ return channelMask == audio_channel_out_mask_from_count(channelCount);
+ }
+ default:
+ return false;
+ }
+ }
+
// Set kEnableExtendedPrecision to true to use extended precision in MixerThread
static const bool kEnableExtendedPrecision = true;
@@ -565,7 +590,7 @@ private:
uint32_t version() const { return mHwDevice->common.version; }
private:
- audio_module_handle_t mHandle;
+ const audio_module_handle_t mHandle;
const char * const mModuleName;
audio_hw_device_t * const mHwDevice;
const Flags mFlags;
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index e777de5..6edca1b 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -40,6 +40,7 @@
#include <common_time/cc_helper.h>
#include <media/EffectsFactoryApi.h>
+#include <audio_effects/effect_downmix.h>
#include "AudioMixerOps.h"
#include "AudioMixer.h"
@@ -941,7 +942,9 @@ bool AudioMixer::track_t::setResampler(uint32_t trackSampleRate, uint32_t devSam
// but if none exists, it is the channel count (1 for mono).
const int resamplerChannelCount = downmixerBufferProvider != NULL
? mMixerChannelCount : channelCount;
- ALOGVV("Creating resampler with %#x format\n", mMixerInFormat);
+ ALOGVV("Creating resampler:"
+ " format(%#x) channels(%d) devSampleRate(%u) quality(%d)\n",
+ mMixerInFormat, resamplerChannelCount, devSampleRate, quality);
resampler = AudioResampler::create(
mMixerInFormat,
resamplerChannelCount,
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 86f72e4..5ba377b 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -26,7 +26,7 @@
#include <media/AudioBufferProvider.h>
#include "AudioResampler.h"
-#include <audio_effects/effect_downmix.h>
+#include <hardware/audio_effect.h>
#include <system/audio.h>
#include <media/nbaio/NBLog.h>
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index c486630..9e15293 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -55,6 +55,7 @@ FastMixer::FastMixer() : FastThread(),
mixer(NULL),
mSinkBuffer(NULL),
mSinkBufferSize(0),
+ mSinkChannelCount(FCC_2),
mMixerBuffer(NULL),
mMixerBufferSize(0),
mMixerBufferFormat(AUDIO_FORMAT_PCM_16_BIT),
@@ -71,6 +72,9 @@ FastMixer::FastMixer() : FastThread(),
current = &initial;
mDummyDumpState = &dummyDumpState;
+ // TODO: Add channel mask to NBAIO_Format.
+ // We assume that the channel mask must be a valid positional channel mask.
+ mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount);
unsigned i;
for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
@@ -148,10 +152,17 @@ void FastMixer::onStateChange()
if (outputSink == NULL) {
format = Format_Invalid;
sampleRate = 0;
+ mSinkChannelCount = 0;
+ mSinkChannelMask = AUDIO_CHANNEL_NONE;
} else {
format = outputSink->format();
sampleRate = Format_sampleRate(format);
- ALOG_ASSERT(Format_channelCount(format) == FCC_2);
+ mSinkChannelCount = Format_channelCount(format);
+ LOG_ALWAYS_FATAL_IF(mSinkChannelCount > AudioMixer::MAX_NUM_CHANNELS);
+
+ // TODO: Add channel mask to NBAIO_Format
+ // We assume that the channel mask must be a valid positional channel mask.
+ mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount);
}
dumpState->mSampleRate = sampleRate;
}
@@ -169,10 +180,12 @@ void FastMixer::onStateChange()
// implementation; it would be better to have normal mixer allocate for us
// to avoid blocking here and to prevent possible priority inversion
mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks);
- const size_t mixerFrameSize = FCC_2 * audio_bytes_per_sample(mMixerBufferFormat);
+ const size_t mixerFrameSize = mSinkChannelCount
+ * audio_bytes_per_sample(mMixerBufferFormat);
mMixerBufferSize = mixerFrameSize * frameCount;
(void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize);
- const size_t sinkFrameSize = FCC_2 * audio_bytes_per_sample(format.mFormat);
+ const size_t sinkFrameSize = mSinkChannelCount
+ * audio_bytes_per_sample(format.mFormat);
if (sinkFrameSize > mixerFrameSize) { // need a sink buffer
mSinkBufferSize = sinkFrameSize * frameCount;
(void)posix_memalign(&mSinkBuffer, 32, mSinkBufferSize);
@@ -244,7 +257,7 @@ void FastMixer::onStateChange()
fastTrackNames[i] = name;
mixer->setBufferProvider(name, bufferProvider);
mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
- (void *) mMixerBuffer);
+ (void *)mMixerBuffer);
// newly allocated track names default to full scale volume
mixer->setParameter(
name,
@@ -252,6 +265,10 @@ void FastMixer::onStateChange()
AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat);
mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
(void *)(uintptr_t)fastTrack->mFormat);
+ mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
+ (void *)(uintptr_t)fastTrack->mChannelMask);
+ mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK,
+ (void *)(uintptr_t)mSinkChannelMask);
mixer->enable(name);
}
generations[i] = fastTrack->mGeneration;
@@ -286,7 +303,9 @@ void FastMixer::onStateChange()
mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
(void *)(uintptr_t)fastTrack->mFormat);
mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
- (void *)(uintptr_t) fastTrack->mChannelMask);
+ (void *)(uintptr_t)fastTrack->mChannelMask);
+ mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK,
+ (void *)(uintptr_t)mSinkChannelMask);
// already enabled
}
generations[i] = fastTrack->mGeneration;
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 4671670..fde8c2b 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -66,6 +66,8 @@ private:
void* mSinkBuffer; // used for mixer output format translation
// if sink format is different than mixer output.
size_t mSinkBufferSize;
+ uint32_t mSinkChannelCount;
+ audio_channel_mask_t mSinkChannelMask;
void* mMixerBuffer; // mixer output buffer.
size_t mMixerBufferSize;
audio_format_t mMixerBufferFormat; // mixer output format: AUDIO_FORMAT_PCM_(16_BIT|FLOAT).
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 651c6ea..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) {
@@ -1388,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
@@ -1814,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);
@@ -2765,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;
@@ -3492,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();
@@ -3730,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
@@ -3738,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