Loading services/audioflinger/PlaybackTracks.h +4 −0 Original line number Diff line number Diff line Loading @@ -195,6 +195,10 @@ public: audio_output_flags_t getOutputFlags() const { return mFlags; } float getSpeed() const { return mSpeed; } bool canBeSpatialized() const { return (mAttr.flags & (AUDIO_FLAG_CONTENT_SPATIALIZED | AUDIO_FLAG_NEVER_SPATIALIZE)) == 0; } protected: // for numerous friend class PlaybackThread; Loading services/audioflinger/Threads.cpp +76 −23 Original line number Diff line number Diff line Loading @@ -2039,6 +2039,7 @@ AudioFlinger::PlaybackThread::~PlaybackThread() free(mSinkBuffer); free(mMixerBuffer); free(mEffectBuffer); free(mEffectToSinkBuffer); } // Thread virtuals Loading Loading @@ -3001,11 +3002,18 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l() // Originally this was int16_t[] array, need to remove legacy implications. free(mSinkBuffer); mSinkBuffer = NULL; free(mEffectToSinkBuffer); mEffectToSinkBuffer = nullptr; // For sink buffer size, we use the frame size from the downstream sink to avoid problems // with non PCM formats for compressed music, e.g. AAC, and Offload threads. const size_t sinkBufferSize = mNormalFrameCount * mFrameSize; (void)posix_memalign(&mSinkBuffer, 32, sinkBufferSize); if (mType == SPATIALIZER) { (void)posix_memalign(&mEffectToSinkBuffer, 32, sinkBufferSize); } // We resize the mMixerBuffer according to the requirements of the sink buffer which // drives the output. free(mMixerBuffer); Loading Loading @@ -3836,11 +3844,11 @@ bool AudioFlinger::PlaybackThread::threadLoop() // // mMixerBufferValid is only set true by MixerThread::prepareTracks_l(). // TODO use mSleepTimeUs == 0 as an additional condition. uint32_t mixerChannelCount = mEffectBufferValid ? audio_channel_count_from_out_mask(mMixerChannelMask) : mChannelCount; if (mMixerBufferValid) { void *buffer = mEffectBufferValid ? mEffectBuffer : mSinkBuffer; audio_format_t format = mEffectBufferValid ? mEffectBufferFormat : mFormat; uint32_t channelCount = mEffectBufferValid ? audio_channel_count_from_out_mask(mMixerChannelMask) : mChannelCount; // mono blend occurs for mixer threads only (not direct or offloaded) // and is handled here if we're going directly to the sink. Loading @@ -3858,7 +3866,7 @@ bool AudioFlinger::PlaybackThread::threadLoop() } memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat, mNormalFrameCount * (channelCount + mHapticChannelCount)); mNormalFrameCount * (mixerChannelCount + 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 Loading Loading @@ -3891,8 +3899,11 @@ bool AudioFlinger::PlaybackThread::threadLoop() && activeHapticSessionId == effectChains[i]->sessionId()) { // Haptic data is active in this case, copy it directly from // in buffer to out buffer. uint32_t channelCount = effectChains[i]->sessionId() == AUDIO_SESSION_OUTPUT_STAGE ? mixerChannelCount : mChannelCount; const size_t audioBufferSize = mNormalFrameCount * audio_bytes_per_frame(mChannelCount, EFFECT_BUFFER_FORMAT); * audio_bytes_per_frame(channelCount, EFFECT_BUFFER_FORMAT); memcpy_by_audio_format( (uint8_t*)effectChains[i]->outBuffer() + audioBufferSize, EFFECT_BUFFER_FORMAT, Loading Loading @@ -3932,8 +3943,23 @@ bool AudioFlinger::PlaybackThread::threadLoop() mBalance.process((float *)mEffectBuffer, mNormalFrameCount); } if (mType == SPATIALIZER) { memcpy_by_audio_format(mEffectToSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat, mNormalFrameCount * (mChannelCount + mHapticChannelCount)); accumulate_by_audio_format(mSinkBuffer, mEffectToSinkBuffer, mFormat, mNormalFrameCount * mChannelCount); const size_t audioBufferSize = mNormalFrameCount * audio_bytes_per_frame(mChannelCount, mFormat); memcpy_by_audio_format( (uint8_t*)mSinkBuffer + audioBufferSize, mFormat, (uint8_t*)mEffectToSinkBuffer + audioBufferSize, mFormat, mNormalFrameCount * mHapticChannelCount); } 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) { Loading Loading @@ -4588,6 +4614,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud && Intersection(outDeviceTypes(), getAudioDeviceOutAllA2dpSet()).empty(); break; } ALOG_ASSERT(initFastMixer && mType == SPATIALIZER); ALOGW_IF(initFastMixer == false && mFrameCount < mNormalFrameCount, "FastMixer is preferred for this sink as frameCount %zu is less than threshold %zu", mFrameCount, mNormalFrameCount); Loading Loading @@ -4946,6 +4973,9 @@ void AudioFlinger::MixerThread::threadLoop_sleepTime() // before effects processing or output. if (mMixerBufferValid) { memset(mMixerBuffer, 0, mMixerBufferSize); if (mType == SPATIALIZER) { memset(mSinkBuffer, 0, mSinkBufferSize); } } else { memset(mSinkBuffer, 0, mSinkBufferSize); } Loading Loading @@ -5438,11 +5468,21 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac trackId, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, (void *)(uintptr_t)track->channelMask()); if (mType == SPATIALIZER && !track->canBeSpatialized()) { mAudioMixer->setParameter( trackId, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, (void *)(uintptr_t)(mChannelMask | mHapticChannelMask)); } else { mAudioMixer->setParameter( trackId, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, (void *)(uintptr_t)(mMixerChannelMask | 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(); Loading Loading @@ -5479,6 +5519,16 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac if (mMixerBufferEnabled && (track->mainBuffer() == mSinkBuffer || track->mainBuffer() == mMixerBuffer)) { if (mType == SPATIALIZER && !track->canBeSpatialized()) { mAudioMixer->setParameter( trackId, AudioMixer::TRACK, AudioMixer::MIXER_FORMAT, (void *)mFormat); mAudioMixer->setParameter( trackId, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER, (void *)mSinkBuffer); } else { mAudioMixer->setParameter( trackId, AudioMixer::TRACK, Loading @@ -5489,6 +5539,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac AudioMixer::MAIN_BUFFER, (void *)mMixerBuffer); // TODO: override track->mainBuffer()? mMixerBufferValid = true; } } else { mAudioMixer->setParameter( trackId, Loading Loading @@ -5678,8 +5729,10 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac // sink or mix buffer must be cleared if all tracks are connected to an // effect chain as in this case the mixer will not write to the sink or mix buffer // and track effects will accumulate into it if ((mBytesRemaining == 0) && ((mixedTracks != 0 && mixedTracks == tracksWithEffect) || (mixedTracks == 0 && fastTracks > 0))) { // always clear sink buffer for spatializer output as the output of the spatializer // effect will be accumulated into it if ((mBytesRemaining == 0) && (((mixedTracks != 0 && mixedTracks == tracksWithEffect) || (mixedTracks == 0 && fastTracks > 0)) || (mType == SPATIALIZER))) { // FIXME as a performance optimization, should remember previous zero status if (mMixerBufferValid) { memset(mMixerBuffer, 0, mMixerBufferSize); Loading services/audioflinger/Threads.h +5 −0 Original line number Diff line number Diff line Loading @@ -1122,6 +1122,11 @@ protected: // for any processing (including output processing). bool mEffectBufferValid; // Frame size aligned buffer used to convert mEffectBuffer samples to mSinkBuffer format prior // to accumulate into mSinkBuffer on SPATIALIZER threads void* mEffectToSinkBuffer = nullptr; // suspend count, > 0 means suspended. While suspended, the thread continues to pull from // tracks and mix, but doesn't write to HAL. A2DP and SCO HAL implementations can't handle // concurrent use of both of them, so Audio Policy Service suspends one of the threads to Loading services/audiopolicy/managerdefault/AudioPolicyManager.cpp +104 −42 Original line number Diff line number Diff line Loading @@ -248,9 +248,7 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescript // been opened by checkOutputsForDevice() to query dynamic parameters if ((state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) || (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) && (desc->mDirectOpenCount == 0)) || (((desc->mFlags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0) && (desc != mSpatializerOutput))) { (desc->mDirectOpenCount == 0))) { clearAudioSourcesForOutput(output); closeOutput(output); } Loading Loading @@ -928,8 +926,7 @@ sp<IOProfile> AudioPolicyManager::getProfileForOutput( } sp<IOProfile> AudioPolicyManager::getSpatializerOutputProfile( const audio_config_t *config __unused, const AudioDeviceTypeAddrVector &devices, bool forOpening) const const audio_config_t *config __unused, const AudioDeviceTypeAddrVector &devices) const { for (const auto& hwModule : mHwModules) { for (const auto& curProfile : hwModule->getOutputProfiles()) { Loading @@ -947,9 +944,6 @@ sp<IOProfile> AudioPolicyManager::getSpatializerOutputProfile( continue; } } if (forOpening && !curProfile->canOpenNewIo()) { continue; } ALOGV("%s found profile %s", __func__, curProfile->getName().c_str()); return curProfile; } Loading Loading @@ -4843,6 +4837,21 @@ sp<SourceClientDescriptor> AudioPolicyManager::getSourceForAttributesOnOutput( return source; } /* static */ bool AudioPolicyManager::isChannelMaskSpatialized(audio_channel_mask_t channels) { switch (channels) { case AUDIO_CHANNEL_OUT_5POINT1: case AUDIO_CHANNEL_OUT_5POINT1POINT2: case AUDIO_CHANNEL_OUT_5POINT1POINT4: case AUDIO_CHANNEL_OUT_7POINT1: case AUDIO_CHANNEL_OUT_7POINT1POINT2: case AUDIO_CHANNEL_OUT_7POINT1POINT4: return true; default: return false; } } bool AudioPolicyManager::canBeSpatialized(const audio_attributes_t *attr, const audio_config_t *config, const AudioDeviceTypeAddrVector &devices) const Loading @@ -4851,17 +4860,21 @@ bool AudioPolicyManager::canBeSpatialized(const audio_attributes_t *attr, // the AUDIO_ATTRIBUTES_INITIALIZER value. // If attributes are specified, current policy is to only allow spatialization for media // and game usages. if (attr != nullptr && *attr != AUDIO_ATTRIBUTES_INITIALIZER && attr->usage != AUDIO_USAGE_MEDIA && attr->usage != AUDIO_USAGE_GAME) { if (attr != nullptr && *attr != AUDIO_ATTRIBUTES_INITIALIZER) { if (attr->usage != AUDIO_USAGE_MEDIA && attr->usage != AUDIO_USAGE_GAME) { return false; } if ((attr->flags & (AUDIO_FLAG_CONTENT_SPATIALIZED | AUDIO_FLAG_NEVER_SPATIALIZE)) != 0) { return false; } } // The caller can have the devices criteria ignored by passing and empty vector, and // getSpatializerOutputProfile() will ignore the devices when looking for a match. // Otherwise an output profile supporting a spatializer effect that can be routed // to the specified devices must exist. sp<IOProfile> profile = getSpatializerOutputProfile(config, devices, false /*forOpening*/); getSpatializerOutputProfile(config, devices); if (profile == nullptr) { return false; } Loading @@ -4869,37 +4882,36 @@ bool AudioPolicyManager::canBeSpatialized(const audio_attributes_t *attr, // The caller can have the audio config criteria ignored by either passing a null ptr or // the AUDIO_CONFIG_INITIALIZER value. // If an audio config is specified, current policy is to only allow spatialization for // 5.1, 7.1and 7.1.4 audio. // some positional channel masks. // If the spatializer output is already opened, only channel masks included in the // spatializer output mixer channel mask are allowed. if (config != nullptr && *config != AUDIO_CONFIG_INITIALIZER) { if (config->channel_mask != AUDIO_CHANNEL_OUT_5POINT1 && config->channel_mask != AUDIO_CHANNEL_OUT_7POINT1 && config->channel_mask != AUDIO_CHANNEL_OUT_7POINT1POINT4) { if (!isChannelMaskSpatialized(config->channel_mask)) { return false; } if (mSpatializerOutput != nullptr) { if (mSpatializerOutput != nullptr && mSpatializerOutput->mProfile == profile) { if ((config->channel_mask & mSpatializerOutput->mMixerChannelMask) != config->channel_mask) { return false; } } } return true; } void AudioPolicyManager::checkVirtualizerClientRoutes() { std::set<audio_stream_type_t> streamsToInvalidate; for (size_t i = 0; i < mOutputs.size(); i++) { const sp<SwAudioOutputDescriptor>& outputDescriptor = mOutputs[i]; for (const sp<TrackClientDescriptor>& client : outputDescriptor->getClientIterable()) { const sp<SwAudioOutputDescriptor>& desc = mOutputs[i]; for (const sp<TrackClientDescriptor>& client : desc->getClientIterable()) { audio_attributes_t attr = client->attributes(); DeviceVector devices = mEngine->getOutputDevicesForAttributes(attr, nullptr, false); AudioDeviceTypeAddrVector devicesTypeAddress = devices.toTypeAddrVector(); audio_config_base_t clientConfig = client->config(); audio_config_t config = audio_config_initializer(&clientConfig); if (canBeSpatialized(&attr, &config, devicesTypeAddress)) { if (desc != mSpatializerOutput && canBeSpatialized(&attr, &config, devicesTypeAddress)) { streamsToInvalidate.insert(client->stream()); } } Loading @@ -4915,10 +4927,6 @@ status_t AudioPolicyManager::getSpatializerOutput(const audio_config_base_t *mix audio_io_handle_t *output) { *output = AUDIO_IO_HANDLE_NONE; if (mSpatializerOutput != nullptr) { return INVALID_OPERATION; } DeviceVector devices = mEngine->getOutputDevicesForAttributes(*attr, nullptr, false); AudioDeviceTypeAddrVector devicesTypeAddress = devices.toTypeAddrVector(); audio_config_t *configPtr = nullptr; Loading @@ -4928,35 +4936,87 @@ status_t AudioPolicyManager::getSpatializerOutput(const audio_config_base_t *mix configPtr = &config; } if (!canBeSpatialized(attr, configPtr, devicesTypeAddress)) { ALOGW("%s provided attributes or mixer config cannot be spatialized", __func__); return BAD_VALUE; } sp<IOProfile> profile = getSpatializerOutputProfile(configPtr, devicesTypeAddress, true /*forOpening*/); getSpatializerOutputProfile(configPtr, devicesTypeAddress); if (profile == nullptr) { ALOGW("%s no suitable output profile for provided attributes or mixer config", __func__); return BAD_VALUE; } mSpatializerOutput = new SwAudioOutputDescriptor(profile, mpClientInterface); status_t status = mSpatializerOutput->open(nullptr, mixerConfig, devices, if (mSpatializerOutput != nullptr && mSpatializerOutput->mProfile == profile && configPtr != nullptr && configPtr->channel_mask == mSpatializerOutput->mMixerChannelMask) { *output = mSpatializerOutput->mIoHandle; ALOGV("%s returns current spatializer output %d", __func__, *output); return NO_ERROR; } mSpatializerOutput.clear(); for (size_t i = 0; i < mOutputs.size(); i++) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); if (!desc->isDuplicated() && desc->mProfile == profile) { mSpatializerOutput = desc; break; } } if (mSpatializerOutput == nullptr) { ALOGW("%s no opened spatializer output for profile %s", __func__, profile->getName().c_str()); return BAD_VALUE; } if (configPtr != nullptr && configPtr->channel_mask != mSpatializerOutput->mMixerChannelMask) { audio_config_base_t savedMixerConfig = { .sample_rate = mSpatializerOutput->getSamplingRate(), .format = mSpatializerOutput->getFormat(), .channel_mask = mSpatializerOutput->mMixerChannelMask, }; DeviceVector savedDevices = mSpatializerOutput->devices(); closeOutput(mSpatializerOutput->mIoHandle); mSpatializerOutput.clear(); const sp<SwAudioOutputDescriptor> desc = new SwAudioOutputDescriptor(profile, mpClientInterface); status_t status = desc->open(nullptr, mixerConfig, devices, mEngine->getStreamTypeForAttributes(*attr), AUDIO_OUTPUT_FLAG_SPATIALIZER, output); if (status != NO_ERROR) { ALOGV("%s failed opening output: status %d, output %d", __func__, status, *output); ALOGW("%s failed opening output: status %d, output %d", __func__, status, *output); if (*output != AUDIO_IO_HANDLE_NONE) { mSpatializerOutput->close(); desc->close(); } mSpatializerOutput.clear(); // re open the spatializer output with previous channel mask status_t newStatus = desc->open(nullptr, &savedMixerConfig, savedDevices, mEngine->getStreamTypeForAttributes(*attr), AUDIO_OUTPUT_FLAG_SPATIALIZER, output); if (newStatus != NO_ERROR) { if (*output != AUDIO_IO_HANDLE_NONE) { desc->close(); } ALOGE("%s failed to re-open mSpatializerOutput, status %d", __func__, newStatus); } else { mSpatializerOutput = desc; addOutput(*output, desc); } mPreviousOutputs = mOutputs; mpClientInterface->onAudioPortListUpdate(); *output = AUDIO_IO_HANDLE_NONE; return status; } checkVirtualizerClientRoutes(); addOutput(*output, mSpatializerOutput); mSpatializerOutput = desc; addOutput(*output, desc); mPreviousOutputs = mOutputs; mpClientInterface->onAudioPortListUpdate(); } checkVirtualizerClientRoutes(); *output = mSpatializerOutput->mIoHandle; ALOGV("%s returns new spatializer output %d", __func__, *output); return NO_ERROR; } Loading @@ -4968,8 +5028,11 @@ status_t AudioPolicyManager::releaseSpatializerOutput(audio_io_handle_t output) if (mSpatializerOutput->mIoHandle != output) { return BAD_VALUE; } closeOutput(output); mSpatializerOutput.clear(); checkVirtualizerClientRoutes(); return NO_ERROR; } Loading Loading @@ -5186,8 +5249,7 @@ void AudioPolicyManager::onNewAudioModulesAvailableInt(DeviceVector *newDevices) outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) { mPrimaryOutput = outputDesc; } if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0 || (outProfile->getFlags() & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0 ) { if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) { outputDesc->close(); } else { addOutput(output, outputDesc); Loading services/audiopolicy/managerdefault/AudioPolicyManager.h +3 −2 Original line number Diff line number Diff line Loading @@ -962,8 +962,9 @@ private: audio_io_handle_t *output); sp<IOProfile> getSpatializerOutputProfile(const audio_config_t *config, const AudioDeviceTypeAddrVector &devices, bool forOpening) const; const AudioDeviceTypeAddrVector &devices) const; static bool isChannelMaskSpatialized(audio_channel_mask_t channels); void checkVirtualizerClientRoutes(); Loading Loading
services/audioflinger/PlaybackTracks.h +4 −0 Original line number Diff line number Diff line Loading @@ -195,6 +195,10 @@ public: audio_output_flags_t getOutputFlags() const { return mFlags; } float getSpeed() const { return mSpeed; } bool canBeSpatialized() const { return (mAttr.flags & (AUDIO_FLAG_CONTENT_SPATIALIZED | AUDIO_FLAG_NEVER_SPATIALIZE)) == 0; } protected: // for numerous friend class PlaybackThread; Loading
services/audioflinger/Threads.cpp +76 −23 Original line number Diff line number Diff line Loading @@ -2039,6 +2039,7 @@ AudioFlinger::PlaybackThread::~PlaybackThread() free(mSinkBuffer); free(mMixerBuffer); free(mEffectBuffer); free(mEffectToSinkBuffer); } // Thread virtuals Loading Loading @@ -3001,11 +3002,18 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l() // Originally this was int16_t[] array, need to remove legacy implications. free(mSinkBuffer); mSinkBuffer = NULL; free(mEffectToSinkBuffer); mEffectToSinkBuffer = nullptr; // For sink buffer size, we use the frame size from the downstream sink to avoid problems // with non PCM formats for compressed music, e.g. AAC, and Offload threads. const size_t sinkBufferSize = mNormalFrameCount * mFrameSize; (void)posix_memalign(&mSinkBuffer, 32, sinkBufferSize); if (mType == SPATIALIZER) { (void)posix_memalign(&mEffectToSinkBuffer, 32, sinkBufferSize); } // We resize the mMixerBuffer according to the requirements of the sink buffer which // drives the output. free(mMixerBuffer); Loading Loading @@ -3836,11 +3844,11 @@ bool AudioFlinger::PlaybackThread::threadLoop() // // mMixerBufferValid is only set true by MixerThread::prepareTracks_l(). // TODO use mSleepTimeUs == 0 as an additional condition. uint32_t mixerChannelCount = mEffectBufferValid ? audio_channel_count_from_out_mask(mMixerChannelMask) : mChannelCount; if (mMixerBufferValid) { void *buffer = mEffectBufferValid ? mEffectBuffer : mSinkBuffer; audio_format_t format = mEffectBufferValid ? mEffectBufferFormat : mFormat; uint32_t channelCount = mEffectBufferValid ? audio_channel_count_from_out_mask(mMixerChannelMask) : mChannelCount; // mono blend occurs for mixer threads only (not direct or offloaded) // and is handled here if we're going directly to the sink. Loading @@ -3858,7 +3866,7 @@ bool AudioFlinger::PlaybackThread::threadLoop() } memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat, mNormalFrameCount * (channelCount + mHapticChannelCount)); mNormalFrameCount * (mixerChannelCount + 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 Loading Loading @@ -3891,8 +3899,11 @@ bool AudioFlinger::PlaybackThread::threadLoop() && activeHapticSessionId == effectChains[i]->sessionId()) { // Haptic data is active in this case, copy it directly from // in buffer to out buffer. uint32_t channelCount = effectChains[i]->sessionId() == AUDIO_SESSION_OUTPUT_STAGE ? mixerChannelCount : mChannelCount; const size_t audioBufferSize = mNormalFrameCount * audio_bytes_per_frame(mChannelCount, EFFECT_BUFFER_FORMAT); * audio_bytes_per_frame(channelCount, EFFECT_BUFFER_FORMAT); memcpy_by_audio_format( (uint8_t*)effectChains[i]->outBuffer() + audioBufferSize, EFFECT_BUFFER_FORMAT, Loading Loading @@ -3932,8 +3943,23 @@ bool AudioFlinger::PlaybackThread::threadLoop() mBalance.process((float *)mEffectBuffer, mNormalFrameCount); } if (mType == SPATIALIZER) { memcpy_by_audio_format(mEffectToSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat, mNormalFrameCount * (mChannelCount + mHapticChannelCount)); accumulate_by_audio_format(mSinkBuffer, mEffectToSinkBuffer, mFormat, mNormalFrameCount * mChannelCount); const size_t audioBufferSize = mNormalFrameCount * audio_bytes_per_frame(mChannelCount, mFormat); memcpy_by_audio_format( (uint8_t*)mSinkBuffer + audioBufferSize, mFormat, (uint8_t*)mEffectToSinkBuffer + audioBufferSize, mFormat, mNormalFrameCount * mHapticChannelCount); } 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) { Loading Loading @@ -4588,6 +4614,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud && Intersection(outDeviceTypes(), getAudioDeviceOutAllA2dpSet()).empty(); break; } ALOG_ASSERT(initFastMixer && mType == SPATIALIZER); ALOGW_IF(initFastMixer == false && mFrameCount < mNormalFrameCount, "FastMixer is preferred for this sink as frameCount %zu is less than threshold %zu", mFrameCount, mNormalFrameCount); Loading Loading @@ -4946,6 +4973,9 @@ void AudioFlinger::MixerThread::threadLoop_sleepTime() // before effects processing or output. if (mMixerBufferValid) { memset(mMixerBuffer, 0, mMixerBufferSize); if (mType == SPATIALIZER) { memset(mSinkBuffer, 0, mSinkBufferSize); } } else { memset(mSinkBuffer, 0, mSinkBufferSize); } Loading Loading @@ -5438,11 +5468,21 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac trackId, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, (void *)(uintptr_t)track->channelMask()); if (mType == SPATIALIZER && !track->canBeSpatialized()) { mAudioMixer->setParameter( trackId, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, (void *)(uintptr_t)(mChannelMask | mHapticChannelMask)); } else { mAudioMixer->setParameter( trackId, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, (void *)(uintptr_t)(mMixerChannelMask | 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(); Loading Loading @@ -5479,6 +5519,16 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac if (mMixerBufferEnabled && (track->mainBuffer() == mSinkBuffer || track->mainBuffer() == mMixerBuffer)) { if (mType == SPATIALIZER && !track->canBeSpatialized()) { mAudioMixer->setParameter( trackId, AudioMixer::TRACK, AudioMixer::MIXER_FORMAT, (void *)mFormat); mAudioMixer->setParameter( trackId, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER, (void *)mSinkBuffer); } else { mAudioMixer->setParameter( trackId, AudioMixer::TRACK, Loading @@ -5489,6 +5539,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac AudioMixer::MAIN_BUFFER, (void *)mMixerBuffer); // TODO: override track->mainBuffer()? mMixerBufferValid = true; } } else { mAudioMixer->setParameter( trackId, Loading Loading @@ -5678,8 +5729,10 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac // sink or mix buffer must be cleared if all tracks are connected to an // effect chain as in this case the mixer will not write to the sink or mix buffer // and track effects will accumulate into it if ((mBytesRemaining == 0) && ((mixedTracks != 0 && mixedTracks == tracksWithEffect) || (mixedTracks == 0 && fastTracks > 0))) { // always clear sink buffer for spatializer output as the output of the spatializer // effect will be accumulated into it if ((mBytesRemaining == 0) && (((mixedTracks != 0 && mixedTracks == tracksWithEffect) || (mixedTracks == 0 && fastTracks > 0)) || (mType == SPATIALIZER))) { // FIXME as a performance optimization, should remember previous zero status if (mMixerBufferValid) { memset(mMixerBuffer, 0, mMixerBufferSize); Loading
services/audioflinger/Threads.h +5 −0 Original line number Diff line number Diff line Loading @@ -1122,6 +1122,11 @@ protected: // for any processing (including output processing). bool mEffectBufferValid; // Frame size aligned buffer used to convert mEffectBuffer samples to mSinkBuffer format prior // to accumulate into mSinkBuffer on SPATIALIZER threads void* mEffectToSinkBuffer = nullptr; // suspend count, > 0 means suspended. While suspended, the thread continues to pull from // tracks and mix, but doesn't write to HAL. A2DP and SCO HAL implementations can't handle // concurrent use of both of them, so Audio Policy Service suspends one of the threads to Loading
services/audiopolicy/managerdefault/AudioPolicyManager.cpp +104 −42 Original line number Diff line number Diff line Loading @@ -248,9 +248,7 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescript // been opened by checkOutputsForDevice() to query dynamic parameters if ((state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) || (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) && (desc->mDirectOpenCount == 0)) || (((desc->mFlags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0) && (desc != mSpatializerOutput))) { (desc->mDirectOpenCount == 0))) { clearAudioSourcesForOutput(output); closeOutput(output); } Loading Loading @@ -928,8 +926,7 @@ sp<IOProfile> AudioPolicyManager::getProfileForOutput( } sp<IOProfile> AudioPolicyManager::getSpatializerOutputProfile( const audio_config_t *config __unused, const AudioDeviceTypeAddrVector &devices, bool forOpening) const const audio_config_t *config __unused, const AudioDeviceTypeAddrVector &devices) const { for (const auto& hwModule : mHwModules) { for (const auto& curProfile : hwModule->getOutputProfiles()) { Loading @@ -947,9 +944,6 @@ sp<IOProfile> AudioPolicyManager::getSpatializerOutputProfile( continue; } } if (forOpening && !curProfile->canOpenNewIo()) { continue; } ALOGV("%s found profile %s", __func__, curProfile->getName().c_str()); return curProfile; } Loading Loading @@ -4843,6 +4837,21 @@ sp<SourceClientDescriptor> AudioPolicyManager::getSourceForAttributesOnOutput( return source; } /* static */ bool AudioPolicyManager::isChannelMaskSpatialized(audio_channel_mask_t channels) { switch (channels) { case AUDIO_CHANNEL_OUT_5POINT1: case AUDIO_CHANNEL_OUT_5POINT1POINT2: case AUDIO_CHANNEL_OUT_5POINT1POINT4: case AUDIO_CHANNEL_OUT_7POINT1: case AUDIO_CHANNEL_OUT_7POINT1POINT2: case AUDIO_CHANNEL_OUT_7POINT1POINT4: return true; default: return false; } } bool AudioPolicyManager::canBeSpatialized(const audio_attributes_t *attr, const audio_config_t *config, const AudioDeviceTypeAddrVector &devices) const Loading @@ -4851,17 +4860,21 @@ bool AudioPolicyManager::canBeSpatialized(const audio_attributes_t *attr, // the AUDIO_ATTRIBUTES_INITIALIZER value. // If attributes are specified, current policy is to only allow spatialization for media // and game usages. if (attr != nullptr && *attr != AUDIO_ATTRIBUTES_INITIALIZER && attr->usage != AUDIO_USAGE_MEDIA && attr->usage != AUDIO_USAGE_GAME) { if (attr != nullptr && *attr != AUDIO_ATTRIBUTES_INITIALIZER) { if (attr->usage != AUDIO_USAGE_MEDIA && attr->usage != AUDIO_USAGE_GAME) { return false; } if ((attr->flags & (AUDIO_FLAG_CONTENT_SPATIALIZED | AUDIO_FLAG_NEVER_SPATIALIZE)) != 0) { return false; } } // The caller can have the devices criteria ignored by passing and empty vector, and // getSpatializerOutputProfile() will ignore the devices when looking for a match. // Otherwise an output profile supporting a spatializer effect that can be routed // to the specified devices must exist. sp<IOProfile> profile = getSpatializerOutputProfile(config, devices, false /*forOpening*/); getSpatializerOutputProfile(config, devices); if (profile == nullptr) { return false; } Loading @@ -4869,37 +4882,36 @@ bool AudioPolicyManager::canBeSpatialized(const audio_attributes_t *attr, // The caller can have the audio config criteria ignored by either passing a null ptr or // the AUDIO_CONFIG_INITIALIZER value. // If an audio config is specified, current policy is to only allow spatialization for // 5.1, 7.1and 7.1.4 audio. // some positional channel masks. // If the spatializer output is already opened, only channel masks included in the // spatializer output mixer channel mask are allowed. if (config != nullptr && *config != AUDIO_CONFIG_INITIALIZER) { if (config->channel_mask != AUDIO_CHANNEL_OUT_5POINT1 && config->channel_mask != AUDIO_CHANNEL_OUT_7POINT1 && config->channel_mask != AUDIO_CHANNEL_OUT_7POINT1POINT4) { if (!isChannelMaskSpatialized(config->channel_mask)) { return false; } if (mSpatializerOutput != nullptr) { if (mSpatializerOutput != nullptr && mSpatializerOutput->mProfile == profile) { if ((config->channel_mask & mSpatializerOutput->mMixerChannelMask) != config->channel_mask) { return false; } } } return true; } void AudioPolicyManager::checkVirtualizerClientRoutes() { std::set<audio_stream_type_t> streamsToInvalidate; for (size_t i = 0; i < mOutputs.size(); i++) { const sp<SwAudioOutputDescriptor>& outputDescriptor = mOutputs[i]; for (const sp<TrackClientDescriptor>& client : outputDescriptor->getClientIterable()) { const sp<SwAudioOutputDescriptor>& desc = mOutputs[i]; for (const sp<TrackClientDescriptor>& client : desc->getClientIterable()) { audio_attributes_t attr = client->attributes(); DeviceVector devices = mEngine->getOutputDevicesForAttributes(attr, nullptr, false); AudioDeviceTypeAddrVector devicesTypeAddress = devices.toTypeAddrVector(); audio_config_base_t clientConfig = client->config(); audio_config_t config = audio_config_initializer(&clientConfig); if (canBeSpatialized(&attr, &config, devicesTypeAddress)) { if (desc != mSpatializerOutput && canBeSpatialized(&attr, &config, devicesTypeAddress)) { streamsToInvalidate.insert(client->stream()); } } Loading @@ -4915,10 +4927,6 @@ status_t AudioPolicyManager::getSpatializerOutput(const audio_config_base_t *mix audio_io_handle_t *output) { *output = AUDIO_IO_HANDLE_NONE; if (mSpatializerOutput != nullptr) { return INVALID_OPERATION; } DeviceVector devices = mEngine->getOutputDevicesForAttributes(*attr, nullptr, false); AudioDeviceTypeAddrVector devicesTypeAddress = devices.toTypeAddrVector(); audio_config_t *configPtr = nullptr; Loading @@ -4928,35 +4936,87 @@ status_t AudioPolicyManager::getSpatializerOutput(const audio_config_base_t *mix configPtr = &config; } if (!canBeSpatialized(attr, configPtr, devicesTypeAddress)) { ALOGW("%s provided attributes or mixer config cannot be spatialized", __func__); return BAD_VALUE; } sp<IOProfile> profile = getSpatializerOutputProfile(configPtr, devicesTypeAddress, true /*forOpening*/); getSpatializerOutputProfile(configPtr, devicesTypeAddress); if (profile == nullptr) { ALOGW("%s no suitable output profile for provided attributes or mixer config", __func__); return BAD_VALUE; } mSpatializerOutput = new SwAudioOutputDescriptor(profile, mpClientInterface); status_t status = mSpatializerOutput->open(nullptr, mixerConfig, devices, if (mSpatializerOutput != nullptr && mSpatializerOutput->mProfile == profile && configPtr != nullptr && configPtr->channel_mask == mSpatializerOutput->mMixerChannelMask) { *output = mSpatializerOutput->mIoHandle; ALOGV("%s returns current spatializer output %d", __func__, *output); return NO_ERROR; } mSpatializerOutput.clear(); for (size_t i = 0; i < mOutputs.size(); i++) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); if (!desc->isDuplicated() && desc->mProfile == profile) { mSpatializerOutput = desc; break; } } if (mSpatializerOutput == nullptr) { ALOGW("%s no opened spatializer output for profile %s", __func__, profile->getName().c_str()); return BAD_VALUE; } if (configPtr != nullptr && configPtr->channel_mask != mSpatializerOutput->mMixerChannelMask) { audio_config_base_t savedMixerConfig = { .sample_rate = mSpatializerOutput->getSamplingRate(), .format = mSpatializerOutput->getFormat(), .channel_mask = mSpatializerOutput->mMixerChannelMask, }; DeviceVector savedDevices = mSpatializerOutput->devices(); closeOutput(mSpatializerOutput->mIoHandle); mSpatializerOutput.clear(); const sp<SwAudioOutputDescriptor> desc = new SwAudioOutputDescriptor(profile, mpClientInterface); status_t status = desc->open(nullptr, mixerConfig, devices, mEngine->getStreamTypeForAttributes(*attr), AUDIO_OUTPUT_FLAG_SPATIALIZER, output); if (status != NO_ERROR) { ALOGV("%s failed opening output: status %d, output %d", __func__, status, *output); ALOGW("%s failed opening output: status %d, output %d", __func__, status, *output); if (*output != AUDIO_IO_HANDLE_NONE) { mSpatializerOutput->close(); desc->close(); } mSpatializerOutput.clear(); // re open the spatializer output with previous channel mask status_t newStatus = desc->open(nullptr, &savedMixerConfig, savedDevices, mEngine->getStreamTypeForAttributes(*attr), AUDIO_OUTPUT_FLAG_SPATIALIZER, output); if (newStatus != NO_ERROR) { if (*output != AUDIO_IO_HANDLE_NONE) { desc->close(); } ALOGE("%s failed to re-open mSpatializerOutput, status %d", __func__, newStatus); } else { mSpatializerOutput = desc; addOutput(*output, desc); } mPreviousOutputs = mOutputs; mpClientInterface->onAudioPortListUpdate(); *output = AUDIO_IO_HANDLE_NONE; return status; } checkVirtualizerClientRoutes(); addOutput(*output, mSpatializerOutput); mSpatializerOutput = desc; addOutput(*output, desc); mPreviousOutputs = mOutputs; mpClientInterface->onAudioPortListUpdate(); } checkVirtualizerClientRoutes(); *output = mSpatializerOutput->mIoHandle; ALOGV("%s returns new spatializer output %d", __func__, *output); return NO_ERROR; } Loading @@ -4968,8 +5028,11 @@ status_t AudioPolicyManager::releaseSpatializerOutput(audio_io_handle_t output) if (mSpatializerOutput->mIoHandle != output) { return BAD_VALUE; } closeOutput(output); mSpatializerOutput.clear(); checkVirtualizerClientRoutes(); return NO_ERROR; } Loading Loading @@ -5186,8 +5249,7 @@ void AudioPolicyManager::onNewAudioModulesAvailableInt(DeviceVector *newDevices) outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) { mPrimaryOutput = outputDesc; } if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0 || (outProfile->getFlags() & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0 ) { if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) { outputDesc->close(); } else { addOutput(output, outputDesc); Loading
services/audiopolicy/managerdefault/AudioPolicyManager.h +3 −2 Original line number Diff line number Diff line Loading @@ -962,8 +962,9 @@ private: audio_io_handle_t *output); sp<IOProfile> getSpatializerOutputProfile(const audio_config_t *config, const AudioDeviceTypeAddrVector &devices, bool forOpening) const; const AudioDeviceTypeAddrVector &devices) const; static bool isChannelMaskSpatialized(audio_channel_mask_t channels); void checkVirtualizerClientRoutes(); Loading