有的项目客户要求speaker播放的时候四个喇叭播放的声音呈现在不同的方位,有的算法有这个能力,但Android输出限制最多只有两声道,遇到类似需求的应该知道我想表达的是什么。一般的做法是在hal层或者kernel某个地方write的时候直接将音频流双声道copy成四声道,这种做法简单,但达不到四个角度的喇叭环绕效果,对于某些高端产品,需要宣传卖点,所以需要另一套方案,在audioflinger做些修改解除Android最多只有两声道输出限制,并让音效按四声道参数做算法。
写这些东西的目的是因为后面这一套方案比较复杂,当时我在做的时候网上没有任何可供参考的东西,当时也是花了一个半月时间才做了初步方案,希望帮助到有类似需求的人。
首先需要配置音频策略,不懂的可以看看Android官方文档,配置音频政策,访问需要有一点技巧。简单说下,里面包含三类标签,mixports,devicePort,route,分别代表虚拟设备,物理设备和路由。我们修改devicePort,使其具备四声道输出能力,这里需要写的是最大输出能力,mixports随便写,也可不写。
diff --git a/audio_policy_config/audio_policy_configuration.xml b/audio_policy_config/audio_policy_configuration.xml
--- a/audio_policy_config/audio_policy_configuration.xml
+++ b/audio_policy_config/audio_policy_configuration.xml
@@ -136,9 +132,7 @@
<!-- Output devices declaration i.e. Sink DEVICE PORT -->
<devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER">
<profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
- samplingRates="44100 48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_QUAD"/>
</devicePort>
<devicePort tagName="Wired Headset" type="AUDIO_DEVICE_OUT_WIRED_HEADSET" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
需要注意一点,当时我们做这个的时候把mixports里的fast和deep_buffer删掉了,这么做一是项目需要,二是可以少解决一些问题。上面说的mixports不写,就需要在下面这个位置做些修改,这里做可以灵活一点。
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -534,8 +534,11 @@ status_t SwAudioOutputDescriptor::open(const audio_config_t *config,
mFlags = (audio_output_flags_t)(mFlags | flags);
- ALOGV("opening output for device %s profile %p name %s",
- mDevices.toString().c_str(), mProfile.get(), mProfile->getName().c_str());
+ if (device->type() == AUDIO_DEVICE_OUT_SPEAKER && mFlags == AUDIO_OUTPUT_FLAG_PRIMARY) {
+ lConfig.channel_mask = AUDIO_CHANNEL_OUT_QUAD;
+ }
+ ALOGD("opening output for device %s profile %p name %s channel mask %#x flags %#x",
+ mDevices.toString().c_str(), mProfile.get(), mProfile->getName().c_str(), lConfig.channel_mask, mFlags);
status_t status = mClientInterface->openOutput(mProfile->getModuleHandle(),
output,
补充一点知识,lConfig.channel_mask参数最后会通过AudioFlinger传到HAL层的open函数,并保存。每个物理设备都会对应一个Thread类,这个类在framework/av/services/audioflinger/Threads.cpp,每个Thread类创建时都会调用PlaybackThread::readOutputParameters_l函数,函数开头获取的几个音频参数就是从HAL层获取的,后面的修改都围绕channel mask值。
@@ -2998,6 +3019,9 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()
mChannelCount = audio_channel_count_from_out_mask(mChannelMask);
mBalance.setChannelMask(mChannelMask);
+ mMaxChannelCount = mChannelCount < audio_channel_count_from_out_mask(AUDIO_CHANNEL_OUT_QUAD)
+ ? mChannelCount : audio_channel_count_from_out_mask(AUDIO_CHANNEL_OUT_7POINT1);
+
// Get actual HAL format.
status_t result = mOutput->stream->getAudioProperties(nullptr, nullptr, &mHALFormat);
LOG_ALWAYS_FATAL_IF(result != OK, "Error when retrieving output stream format: %d", result);
@@ -3121,7 +3145,7 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()
mMixerBuffer = NULL;
if (mMixerBufferEnabled) {
mMixerBufferFormat = AUDIO_FORMAT_PCM_FLOAT; // no longer valid: AUDIO_FORMAT_PCM_16_BIT.
- mMixerBufferSize = mNormalFrameCount * mChannelCount
+ mMixerBufferSize = mNormalFrameCount * mMaxChannelCount
* audio_bytes_per_sample(mMixerBufferFormat);
(void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize);
}
@@ -3129,7 +3153,7 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()
mEffectBuffer = NULL;
if (mEffectBufferEnabled) {
mEffectBufferFormat = EFFECT_BUFFER_FORMAT;
- mEffectBufferSize = mNormalFrameCount * mChannelCount
+ mEffectBufferSize = mNormalFrameCount * mMaxChannelCount
* audio_bytes_per_sample(mEffectBufferFormat);
(void)posix_memalign(&mEffectBuffer, 32, mEffectBufferSize);
}
@@ -3970,7 +4023,7 @@ bool AudioFlinger::PlaybackThread::threadLoop()
}
memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat,
- mNormalFrameCount * (mChannelCount + mHapticChannelCount));
+ mNormalFrameCount * (mMaxChannelCount + mHapticChannelCount));
// If we're going directly to the sink and there are haptic channels,
// we should adjust channels as the sample data is partially interleaved
@@ -3538,7 +3591,7 @@ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& c
// Only one effect chain can be present in direct output thread and it uses
// the sink buffer as input
if (mType != DIRECT) {
- size_t numSamples = mNormalFrameCount * (mChannelCount + mHapticChannelCount);
+ size_t numSamples = mNormalFrameCount * (mMaxChannelCount + mHapticChannelCount);
status_t result = mAudioFlinger->mEffectsFactoryHal->allocateBuffer(
numSamples * sizeof(effect_buffer_t),
&halInBuffer);
这个位置是为了增大buffer,整个播放流程设计到mixer buffer, effect buffer,sink buffer,用作输入输出,每个buffer代表音频处理某个阶段,每个阶段处理完了拷贝到下一个buffer。前两个buffer搞这么大是因为输入的声道不确定,但我们限制最大只有8声道,sink buffer是最终写到HAL的buffer,effect buffer输入可能很大,输出不会超过四声道,所以sink buffer不用特别增大,但他会按照mChannelCount参数申请大小。
@@ -5106,6 +5163,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
// counts only _active_ fast tracks
size_t fastTracks = 0;
uint32_t resetMask = 0; // bit mask of fast tracks that need to be reset
+ uint32_t trackChannelMask = AUDIO_CHANNEL_NONE;
float masterVolume = mMasterVolume;
bool masterMute = mMasterMute;
@@ -5113,6 +5171,35 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
if (masterMute) {
masterVolume = 0;
}
+
+ auto getChannelMask = [this](audio_channel_mask_t channelMask)->audio_channel_mask_t {
+ if (channelMask == AUDIO_CHANNEL_OUT_MONO || audio_channel_count_from_out_mask(channelMask) > mMaxChannelCount) {
+ return AUDIO_CHANNEL_OUT_STEREO;
+ } else if (channelMask == AUDIO_CHANNEL_OUT_QUAD) {
+ return AUDIO_CHANNEL_OUT_7POINT1;
+ } else {
+ return channelMask;
+ }
+ };
+
+ if (count && (mChannelMask == AUDIO_CHANNEL_OUT_STEREO || !(mIsDapEnabled = checkDapEnabled(true)))) {
+ trackChannelMask = AUDIO_CHANNEL_OUT_STEREO;
+ } else {
+ for (auto track: mActiveTracks) {
+ audio_channel_mask_t channelMask = getChannelMask(track->channelMask());
+ trackChannelMask |= channelMask;
+
+ //ALOGD("%s, mActiveTrackCount %zu, activeTrack->channelMask %#x, trackChannelMask %#x, mChannelMask %#x, deviceType %#x, id %d, this %p, sessionid %d",
+ // __func__, count, track->channelMask(), trackChannelMask, mChannelMask, mOutputDevice, mId, this, track->sessionId());
+ }
+ }
+
+ if(trackChannelMask != AUDIO_CHANNEL_NONE){
+ for(size_t i = 0; i < mEffectChains.size(); i++){
+ mEffectChains[i]->updateChannelMask(static_cast<audio_channel_mask_t>(trackChannelMask));
+ }
+ }
// Delegate master volume control to effect in output mix effect chain if needed
sp<EffectChain> chain = getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
if (chain != 0) {
@@ -5585,7 +5672,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
trackId,
AudioMixer::TRACK,
AudioMixer::MIXER_CHANNEL_MASK,
- (void *)(uintptr_t)(mChannelMask | mHapticChannelMask));
+ (void *)(uintptr_t)(trackChannelMask | mHapticChannelMask));
// limit track sample rate to 2 x output sample rate, which changes at re-configuration
uint32_t maxSampleRate = mSampleRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX;
uint32_t reqSampleRate = proxy->getSampleRate();
这里修改的目的是为了得到一个正确的trackChannelMask,然后分别传到EffectModule和AudioMixer。
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -879,6 +879,16 @@ void AudioFlinger::EffectModule::reset_l()
mEffectInterface->command(EFFECT_CMD_RESET, 0, NULL, 0, NULL);
}
+void AudioFlinger::EffectChain::updateChannelMask(audio_channel_mask_t channelMask) {
+ if (mTrackChannelMask == channelMask) return;
+
+ mTrackChannelMask = channelMask;
+ for (auto effect: mEffects) {
+ ALOGD("%s update success! sessionId %d", __func__, effect->sessionId());
+ effect->configure();
+ }
+}
+
status_t AudioFlinger::EffectModule::configure()
{
ALOGVV("configure() started");
@@ -901,6 +911,11 @@ status_t AudioFlinger::EffectModule::configure()
mConfig.inputCfg.channels = channelMask;
mConfig.outputCfg.channels = channelMask;
+ mConfig.inputCfg.channels = callback->chain().promote()->mTrackChannelMask;
+ if (!audio_is_global_session(mSessionId)) {
+ mConfig.outputCfg.channels = callback->chain().promote()->mTrackChannelMask;
+ }
+
if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
if (mConfig.inputCfg.channels != AUDIO_CHANNEL_OUT_MONO) {
mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_MONO;
@@ -2088,6 +2103,8 @@ AudioFlinger::EffectChain::EffectChain(const wp<ThreadBase>& thread,
mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX),
mEffectCallback(new EffectCallback(wp<EffectChain>(this), thread))
{
+ mTrackChannelMask = AUDIO_CHANNEL_OUT_STEREO;
+
mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
sp<ThreadBase> p = thread.promote();
if (p == nullptr) {
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -434,6 +434,9 @@ public:
audio_session_t sessionId() const {
return mSessionId; }
void setSessionId(audio_session_t sessionId) {
mSessionId = sessionId; }
+ audio_channel_mask_t mTrackChannelMask;
+ void updateChannelMask(audio_channel_mask_t channelMask);
+
sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor);
sp<EffectModule> getEffectFromId_l(int id);
sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type);
下面是对音效开关的处理,音效关的时候需要手动将双声道转成四声道
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -137,6 +137,23 @@
// TODO: Move these macro/inlines to a header file.
#define max(a, b) ((a) > (b) ? (a) : (b))
+#define EFFECT_UUID_DAP {
0x9d4921da, 0x8225, 0x4f29, 0xaefa, {
0x39, 0x53, 0x7a, 0x04, 0xbc, 0xaa } };
+#define copy_frame_by_channel(dst_buffer, dst_type, src_buffer, src_type, num_frames, clamp) \
+{
\
+ dst_type *dst = (dst_type *)dst_buffer; \
+ src_type *src = (src_type *)src_buffer; \
+ int32_t dst_idx = (num_frames - 1) * 4; \
+ int32_t src_idx = (num_frames - 1) * 2; \
+ for (int32_t i = num_frames - 1; i >= 0; i--) {
\
+ dst[dst_idx + 3] = clamp(src[src_idx + 1]); \
+ dst[dst_idx + 2] = clamp(src[src_idx + 0]); \
+ dst[dst_idx + 1] = dst[dst_idx + 3]; \
+ dst[dst_idx + 0] = dst[dst_idx + 2]; \
+ dst_idx -= 4; \
+ src_idx -= 2; \
+ } \
+}
+bool AudioFlinger::PlaybackThread::checkDapEnabled(bool needLock)
+{
+ Vector< sp<EffectChain> > effectChains;
+ bool enabled = false;
+
+ effect_descriptor_t desc;
+ desc.uuid = EFFECT_UUID_DAP;
+
+ if (needLock) {
+ lockEffectChains_l(effectChains);
+ }
+ for (auto chain: mEffectChains) {
+ auto effect = chain->getEffectFromDesc_l(&desc);
+ if(effect != nullptr && effect->isProcessEnabled()) {
+ enabled = true;
+ break;
+ }
+ }
+ if (needLock) {
+ unlockEffectChains(effectChains);
+ }
+ return enabled;
+}
@@ -4044,8 +4097,12 @@ bool AudioFlinger::PlaybackThread::threadLoop()
mBalance.process((float *)mEffectBuffer, mNormalFrameCount);
}
- memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat,
- mNormalFrameCount * (mChannelCount + mHapticChannelCount));
+ if (mType != OFFLOAD && mType != DIRECT && mChannelCount == 4 && (!mIsDapEnabled /* || !checkDapEnabled(false) */)) {
+ copy_frame_by_channel(mSinkBuffer, int32_t, mEffectBuffer, float, mNormalFrameCount, clamp32_from_float);
+ } else {
+ memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat,
+ mNormalFrameCount * (mChannelCount + mHapticChannelCount));
+ }
// The sample data is partially interleaved when haptic channels exist,
// we need to adjust channels here.
if (mHapticChannelCount > 0) {
还有一些HAL的修改,不同平台实现不一样。需要在HAL层对除了扬声器以外的其它设备比如蓝牙耳机,有线耳机,DuplicatingThread播放,REMOTE_SUBMIX模式等等做一个统一操作,因为虽然除扬声器以外的设备都是双声道播放,但是因为修改了前面提到的AudioOutputDescriptor.cpp文件,参数不会跟着变化,所以要在HAL层write函数位置进行四转二操作。
代码修改基本就这些,真正困难的是调试,还需要大家对Audio有一定熟悉,当然遇到这类需要的人应该非常少。
未完待续