From 9a59276fb465e492138e0576523b54079671e8f4 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Mon, 21 Jul 2014 21:56:01 -0700 Subject: Add multichannel capability to AudioFlinger But not enabled (kEnableExtendedChannels == false). Change-Id: I62f7e31fbd29ad703a9a02f5d1a280b6972dd423 --- services/audioflinger/AudioFlinger.cpp | 44 ++++++++++++++++++++++++---------- services/audioflinger/AudioFlinger.h | 27 ++++++++++++++++++++- services/audioflinger/AudioMixer.cpp | 5 +++- services/audioflinger/AudioMixer.h | 2 +- services/audioflinger/FastMixer.cpp | 29 ++++++++++++++++++---- services/audioflinger/FastMixer.h | 2 ++ services/audioflinger/Threads.cpp | 36 ++++++++++++++++++---------- 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::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::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::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 #include "AudioWatchdog.h" +#include "AudioMixer.h" #include @@ -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 #include +#include #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 #include "AudioResampler.h" -#include +#include #include #include 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::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::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, 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 -- cgit v1.1