diff options
Diffstat (limited to 'audio')
-rw-r--r-- | audio/AudioHardwareGeneric.h | 2 | ||||
-rw-r--r-- | audio/AudioHardwareStub.cpp | 4 | ||||
-rw-r--r-- | audio/AudioHardwareStub.h | 2 | ||||
-rw-r--r-- | audio/AudioPolicyCompatClient.cpp | 5 | ||||
-rw-r--r-- | audio/AudioPolicyCompatClient.h | 3 | ||||
-rw-r--r-- | audio/AudioPolicyManagerBase.cpp | 441 | ||||
-rw-r--r-- | audio/audio_policy.conf | 20 | ||||
-rw-r--r-- | audio/audio_policy_hal.cpp | 14 |
8 files changed, 366 insertions, 125 deletions
diff --git a/audio/AudioHardwareGeneric.h b/audio/AudioHardwareGeneric.h index 7b41e95..55498dc 100644 --- a/audio/AudioHardwareGeneric.h +++ b/audio/AudioHardwareGeneric.h @@ -92,6 +92,8 @@ public: virtual status_t setParameters(const String8& keyValuePairs); virtual String8 getParameters(const String8& keys); virtual unsigned int getInputFramesLost() const { return 0; } + virtual status_t addAudioEffect(effect_handle_t effect) { return NO_ERROR; } + virtual status_t removeAudioEffect(effect_handle_t effect) { return NO_ERROR; } private: AudioHardwareGeneric *mAudioHardware; diff --git a/audio/AudioHardwareStub.cpp b/audio/AudioHardwareStub.cpp index 70a8309..1083889 100644 --- a/audio/AudioHardwareStub.cpp +++ b/audio/AudioHardwareStub.cpp @@ -204,6 +204,10 @@ String8 AudioStreamInStub::getParameters(const String8& keys) return param.toString(); } +AudioHardwareInterface* createAudioHardware(void) { + return new AudioHardwareStub(); +} + // ---------------------------------------------------------------------------- }; // namespace android diff --git a/audio/AudioHardwareStub.h b/audio/AudioHardwareStub.h index 0858f37..c5f7a80 100644 --- a/audio/AudioHardwareStub.h +++ b/audio/AudioHardwareStub.h @@ -58,6 +58,8 @@ public: virtual status_t setParameters(const String8& keyValuePairs) { return NO_ERROR;} virtual String8 getParameters(const String8& keys); virtual unsigned int getInputFramesLost() const { return 0; } + virtual status_t addAudioEffect(effect_handle_t effect) { return NO_ERROR; } + virtual status_t removeAudioEffect(effect_handle_t effect) { return NO_ERROR; } }; class AudioHardwareStub : public AudioHardwareBase diff --git a/audio/AudioPolicyCompatClient.cpp b/audio/AudioPolicyCompatClient.cpp index 4c80428..162968c 100644 --- a/audio/AudioPolicyCompatClient.cpp +++ b/audio/AudioPolicyCompatClient.cpp @@ -41,11 +41,12 @@ audio_io_handle_t AudioPolicyCompatClient::openOutput(audio_module_handle_t modu audio_format_t *pFormat, audio_channel_mask_t *pChannelMask, uint32_t *pLatencyMs, - audio_output_flags_t flags) + audio_output_flags_t flags, + const audio_offload_info_t *offloadInfo) { return mServiceOps->open_output_on_module(mService, module, pDevices, pSamplingRate, pFormat, pChannelMask, pLatencyMs, - flags); + flags, offloadInfo); } audio_io_handle_t AudioPolicyCompatClient::openDuplicateOutput(audio_io_handle_t output1, diff --git a/audio/AudioPolicyCompatClient.h b/audio/AudioPolicyCompatClient.h index 5399c8c..494c8af 100644 --- a/audio/AudioPolicyCompatClient.h +++ b/audio/AudioPolicyCompatClient.h @@ -43,7 +43,8 @@ public: audio_format_t *pFormat, audio_channel_mask_t *pChannelMask, uint32_t *pLatencyMs, - audio_output_flags_t flags); + audio_output_flags_t flags, + const audio_offload_info_t *offloadInfo); virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2); virtual status_t closeOutput(audio_io_handle_t output); diff --git a/audio/AudioPolicyManagerBase.cpp b/audio/AudioPolicyManagerBase.cpp index bf3f36a..dbca8ff 100644 --- a/audio/AudioPolicyManagerBase.cpp +++ b/audio/AudioPolicyManagerBase.cpp @@ -37,6 +37,7 @@ #include <hardware/audio.h> #include <math.h> #include <hardware_legacy/audio_policy_conf.h> +#include <cutils/properties.h> namespace android_audio_legacy { @@ -161,10 +162,12 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device // outputs must be closed after checkOutputForAllStrategies() is executed if (!outputs.isEmpty()) { for (size_t i = 0; i < outputs.size(); i++) { + AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]); // close unused outputs after device disconnection or direct outputs that have been // opened by checkOutputsForDevice() to query dynamic parameters if ((state == AudioSystem::DEVICE_STATE_UNAVAILABLE) || - (mOutputs.valueFor(outputs[i])->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) { + (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) && + (desc->mDirectOpenCount == 0))) { closeOutput(outputs[i]); } } @@ -309,11 +312,19 @@ void AudioPolicyManagerBase::setPhoneState(int state) // force routing command to audio hardware when starting a call // even if no device change is needed force = true; + for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) { + mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] = + sVolumeProfiles[AUDIO_STREAM_VOICE_CALL][j]; + } } else if (isStateInCall(oldState) && !isStateInCall(state)) { ALOGV(" Exiting call in setPhoneState()"); // force routing command to audio hardware when exiting a call // even if no device change is needed force = true; + for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) { + mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] = + sVolumeProfiles[AUDIO_STREAM_DTMF][j]; + } } else if (isStateInCall(state) && (state != oldState)) { ALOGV(" Switching between telephony and VoIP in setPhoneState()"); // force routing command to audio hardware when switching between telephony and VoIP @@ -479,6 +490,8 @@ void AudioPolicyManagerBase::setSystemProperty(const char* property, const char* ALOGV("setSystemProperty() property %s, value %s", property, value); } +// Find a direct output profile compatible with the parameters passed, even if the input flags do +// not explicitly request a direct output AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getProfileForDirectOutput( audio_devices_t device, uint32_t samplingRate, @@ -491,14 +504,24 @@ AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getProfileForDirectOu continue; } for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { - IOProfile *profile = mHwModules[i]->mOutputProfiles[j]; - if (profile->isCompatibleProfile(device, samplingRate, format, + IOProfile *profile = mHwModules[i]->mOutputProfiles[j]; + if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { + if (profile->isCompatibleProfile(device, samplingRate, format, + channelMask, + AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) { + if (mAvailableOutputDevices & profile->mSupportedDevices) { + return mHwModules[i]->mOutputProfiles[j]; + } + } + } else { + if (profile->isCompatibleProfile(device, samplingRate, format, channelMask, AUDIO_OUTPUT_FLAG_DIRECT)) { - if (mAvailableOutputDevices & profile->mSupportedDevices) { - return mHwModules[i]->mOutputProfiles[j]; - } - } + if (mAvailableOutputDevices & profile->mSupportedDevices) { + return mHwModules[i]->mOutputProfiles[j]; + } + } + } } } return 0; @@ -508,14 +531,15 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str uint32_t samplingRate, uint32_t format, uint32_t channelMask, - AudioSystem::output_flags flags) + AudioSystem::output_flags flags, + const audio_offload_info_t *offloadInfo) { audio_io_handle_t output = 0; uint32_t latency = 0; routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream); audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/); - ALOGV("getOutput() stream %d, samplingRate %d, format %d, channelMask %x, flags %x", - stream, samplingRate, format, channelMask, flags); + ALOGV("getOutput() device %d, stream %d, samplingRate %d, format %x, channelMask %x, flags %x", + device, stream, samplingRate, format, channelMask, flags); #ifdef AUDIO_POLICY_TEST if (mCurOutput != 0) { @@ -537,7 +561,8 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str &outputDesc->mFormat, &outputDesc->mChannelMask, &outputDesc->mLatency, - outputDesc->mFlags); + outputDesc->mFlags, + offloadInfo); if (mTestOutputs[mCurOutput]) { AudioParameter outputCmd = AudioParameter(); outputCmd.addInt(String8("set_id"),mCurOutput); @@ -550,11 +575,29 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str #endif //AUDIO_POLICY_TEST // open a direct output if required by specified parameters - IOProfile *profile = getProfileForDirectOutput(device, - samplingRate, - format, - channelMask, - (audio_output_flags_t)flags); + //force direct flag if offload flag is set: offloading implies a direct output stream + // and all common behaviors are driven by checking only the direct flag + // this should normally be set appropriately in the policy configuration file + if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) { + flags = (AudioSystem::output_flags)(flags | AUDIO_OUTPUT_FLAG_DIRECT); + } + + // Do not allow offloading if one non offloadable effect is enabled. This prevents from + // creating an offloaded track and tearing it down immediately after start when audioflinger + // detects there is an active non offloadable effect. + // FIXME: We should check the audio session here but we do not have it in this context. + // This may prevent offloading in rare situations where effects are left active by apps + // in the background. + IOProfile *profile = NULL; + if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) || + !isNonOffloadableEffectEnabled()) { + profile = getProfileForDirectOutput(device, + samplingRate, + format, + channelMask, + (audio_output_flags_t)flags); + } + if (profile != NULL) { AudioOutputDescriptor *outputDesc = NULL; @@ -567,7 +610,7 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str (format == outputDesc->mFormat) && (channelMask == outputDesc->mChannelMask)) { outputDesc->mDirectOpenCount++; - ALOGV("getOutput() reusing direct output %d", output); + ALOGV("getOutput() reusing direct output %d", mOutputs.keyAt(i)); return mOutputs.keyAt(i); } } @@ -582,7 +625,7 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str outputDesc->mFormat = (audio_format_t)format; outputDesc->mChannelMask = (audio_channel_mask_t)channelMask; outputDesc->mLatency = 0; - outputDesc->mFlags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT);; + outputDesc->mFlags =(audio_output_flags_t) (outputDesc->mFlags | flags); outputDesc->mRefCount[stream] = 0; outputDesc->mStopTime[stream] = 0; outputDesc->mDirectOpenCount = 1; @@ -592,7 +635,8 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str &outputDesc->mFormat, &outputDesc->mChannelMask, &outputDesc->mLatency, - outputDesc->mFlags); + outputDesc->mFlags, + offloadInfo); // only accept an output with the requested parameters if (output == 0 || @@ -609,7 +653,12 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str delete outputDesc; return 0; } + audio_io_handle_t srcOutput = getOutputForEffect(); addOutput(output, outputDesc); + audio_io_handle_t dstOutput = getOutputForEffect(); + if (dstOutput == output) { + mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, srcOutput, dstOutput); + } mPreviousOutputs = mOutputs; ALOGV("getOutput() returns new direct output %d", output); return output; @@ -619,13 +668,15 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str // open a non direct output - // get which output is suitable for the specified stream. The actual routing change will happen - // when startOutput() will be called - SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs); - - output = selectOutput(outputs, flags); + // for non direct outputs, only PCM is supported + if (audio_is_linear_pcm((audio_format_t)format)) { + // get which output is suitable for the specified stream. The actual + // routing change will happen when startOutput() will be called + SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs); - ALOGW_IF((output ==0), "getOutput() could not find output for stream %d, samplingRate %d," + output = selectOutput(outputs, flags); + } + ALOGW_IF((output == 0), "getOutput() could not find output for stream %d, samplingRate %d," "format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags); ALOGV("getOutput() returns output %d", output); @@ -787,7 +838,7 @@ status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, if (curOutput != output && desc->isActive() && outputDesc->sharesHwModuleWith(desc) && - newDevice != desc->device()) { + (newDevice != desc->device())) { setOutputDevice(curOutput, getNewDevice(curOutput, false /*fromCache*/), true, @@ -836,11 +887,17 @@ void AudioPolicyManagerBase::releaseOutput(audio_io_handle_t output) } if (--desc->mDirectOpenCount == 0) { closeOutput(output); + // If effects where present on the output, audioflinger moved them to the primary + // output by default: move them back to the appropriate output. + audio_io_handle_t dstOutput = getOutputForEffect(); + if (dstOutput != mPrimaryOutput) { + mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, mPrimaryOutput, dstOutput); + } } } - } + audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource, uint32_t samplingRate, uint32_t format, @@ -934,10 +991,19 @@ status_t AudioPolicyManagerBase::startInput(audio_io_handle_t input) if (mTestInput == 0) #endif //AUDIO_POLICY_TEST { - // refuse 2 active AudioRecord clients at the same time - if (getActiveInput() != 0) { - ALOGW("startInput() input %d failed: other input already started", input); - return INVALID_OPERATION; + // refuse 2 active AudioRecord clients at the same time except if the active input + // uses AUDIO_SOURCE_HOTWORD in which case it is closed. + audio_io_handle_t activeInput = getActiveInput(); + if (!isVirtualInputDevice(inputDesc->mDevice) && activeInput != 0) { + AudioInputDescriptor *activeDesc = mInputs.valueFor(activeInput); + if (activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) { + ALOGW("startInput() preempting already started low-priority input %d", activeInput); + stopInput(activeInput); + releaseInput(activeInput); + } else { + ALOGW("startInput() input %d failed: other input already started..", input); + return INVALID_OPERATION; + } } } @@ -945,10 +1011,20 @@ status_t AudioPolicyManagerBase::startInput(audio_io_handle_t input) if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) { inputDesc->mDevice = newDevice; } + + // automatically enable the remote submix output when input is started + if (audio_is_remote_submix_device(inputDesc->mDevice)) { + setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, + AudioSystem::DEVICE_STATE_AVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS); + } + AudioParameter param = AudioParameter(); param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice); - param.addInt(String8(AudioParameter::keyInputSource), (int)inputDesc->mInputSource); + int aliasSource = (inputDesc->mInputSource == AUDIO_SOURCE_HOTWORD) ? + AUDIO_SOURCE_VOICE_RECOGNITION : inputDesc->mInputSource; + + param.addInt(String8(AudioParameter::keyInputSource), aliasSource); ALOGV("AudioPolicyManager::startInput() input source = %d", inputDesc->mInputSource); mpClientInterface->setParameters(input, param.toString()); @@ -971,6 +1047,12 @@ status_t AudioPolicyManagerBase::stopInput(audio_io_handle_t input) ALOGW("stopInput() input %d already stopped", input); return INVALID_OPERATION; } else { + // automatically disable the remote submix output when input is stopped + if (audio_is_remote_submix_device(inputDesc->mDevice)) { + setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, + AudioSystem::DEVICE_STATE_UNAVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS); + } + AudioParameter param = AudioParameter(); param.addInt(String8(AudioParameter::keyRouting), 0); mpClientInterface->setParameters(input, param.toString()); @@ -1068,22 +1150,60 @@ status_t AudioPolicyManagerBase::getStreamVolumeIndex(AudioSystem::stream_type s return NO_ERROR; } +audio_io_handle_t AudioPolicyManagerBase::selectOutputForEffects( + const SortedVector<audio_io_handle_t>& outputs) +{ + // select one output among several suitable for global effects. + // The priority is as follows: + // 1: An offloaded output. If the effect ends up not being offloadable, + // AudioFlinger will invalidate the track and the offloaded output + // will be closed causing the effect to be moved to a PCM output. + // 2: A deep buffer output + // 3: the first output in the list + + if (outputs.size() == 0) { + return 0; + } + + audio_io_handle_t outputOffloaded = 0; + audio_io_handle_t outputDeepBuffer = 0; + + for (size_t i = 0; i < outputs.size(); i++) { + AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]); + ALOGV("selectOutputForEffects outputs[%d] flags %x", i, desc->mFlags); + if ((desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) { + outputOffloaded = outputs[i]; + } + if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) { + outputDeepBuffer = outputs[i]; + } + } + + ALOGV("selectOutputForEffects outputOffloaded %d outputDeepBuffer %d", + outputOffloaded, outputDeepBuffer); + if (outputOffloaded != 0) { + return outputOffloaded; + } + if (outputDeepBuffer != 0) { + return outputDeepBuffer; + } + + return outputs[0]; +} + audio_io_handle_t AudioPolicyManagerBase::getOutputForEffect(const effect_descriptor_t *desc) { - ALOGV("getOutputForEffect()"); // apply simple rule where global effects are attached to the same output as MUSIC streams routing_strategy strategy = getStrategy(AudioSystem::MUSIC); audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/); SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(device, mOutputs); - int outIdx = 0; - for (size_t i = 0; i < dstOutputs.size(); i++) { - AudioOutputDescriptor *desc = mOutputs.valueFor(dstOutputs[i]); - if (desc->mFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) { - outIdx = i; - } - } - return dstOutputs[outIdx]; + + audio_io_handle_t output = selectOutputForEffects(dstOutputs); + ALOGV("getOutputForEffect() got output %d for fx %s flags %x", + output, (desc == NULL) ? "unspecified" : desc->name, (desc == NULL) ? 0 : desc->flags); + + return output; } status_t AudioPolicyManagerBase::registerEffect(const effect_descriptor_t *desc, @@ -1190,6 +1310,20 @@ status_t AudioPolicyManagerBase::setEffectEnabled(EffectDescriptor *pDesc, bool return NO_ERROR; } +bool AudioPolicyManagerBase::isNonOffloadableEffectEnabled() +{ + for (size_t i = 0; i < mEffects.size(); i++) { + const EffectDescriptor * const pDesc = mEffects.valueAt(i); + if (pDesc->mEnabled && (pDesc->mStrategy == STRATEGY_MEDIA) && + ((pDesc->mDesc.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) == 0)) { + ALOGV("isNonOffloadableEffectEnabled() non offloadable effect %s enabled on session %d", + pDesc->mDesc.name, pDesc->mSession); + return true; + } + } + return false; +} + bool AudioPolicyManagerBase::isStreamActive(int stream, uint32_t inPastMs) const { nsecs_t sysTime = systemTime(); @@ -1219,8 +1353,10 @@ bool AudioPolicyManagerBase::isSourceActive(audio_source_t source) const { for (size_t i = 0; i < mInputs.size(); i++) { const AudioInputDescriptor * inputDescriptor = mInputs.valueAt(i); - if ((inputDescriptor->mInputSource == (int) source) - && (inputDescriptor->mRefCount > 0)) { + if ((inputDescriptor->mInputSource == (int)source || + (source == (audio_source_t)AUDIO_SOURCE_VOICE_RECOGNITION && + inputDescriptor->mInputSource == AUDIO_SOURCE_HOTWORD)) + && (inputDescriptor->mRefCount > 0)) { return true; } } @@ -1228,7 +1364,6 @@ bool AudioPolicyManagerBase::isSourceActive(audio_source_t source) const } - status_t AudioPolicyManagerBase::dump(int fd) { const size_t SIZE = 256; @@ -1316,6 +1451,73 @@ status_t AudioPolicyManagerBase::dump(int fd) return NO_ERROR; } +// This function checks for the parameters which can be offloaded. +// This can be enhanced depending on the capability of the DSP and policy +// of the system. +bool AudioPolicyManagerBase::isOffloadSupported(const audio_offload_info_t& offloadInfo) +{ + ALOGV("isOffloadSupported: SR=%u, CM=0x%x, Format=0x%x, StreamType=%d," + " BitRate=%u, duration=%lld us, has_video=%d", + offloadInfo.sample_rate, offloadInfo.channel_mask, + offloadInfo.format, + offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us, + offloadInfo.has_video); + + // Check if offload has been disabled + char propValue[PROPERTY_VALUE_MAX]; + if (property_get("audio.offload.disable", propValue, "0")) { + if (atoi(propValue) != 0) { + ALOGV("offload disabled by audio.offload.disable=%s", propValue ); + return false; + } + } + + // Check if stream type is music, then only allow offload as of now. + if (offloadInfo.stream_type != AUDIO_STREAM_MUSIC) + { + ALOGV("isOffloadSupported: stream_type != MUSIC, returning false"); + return false; + } + + //TODO: enable audio offloading with video when ready + if (offloadInfo.has_video) + { + ALOGV("isOffloadSupported: has_video == true, returning false"); + return false; + } + + //If duration is less than minimum value defined in property, return false + if (property_get("audio.offload.min.duration.secs", propValue, NULL)) { + if (offloadInfo.duration_us < (atoi(propValue) * 1000000 )) { + ALOGV("Offload denied by duration < audio.offload.min.duration.secs(=%s)", propValue); + return false; + } + } else if (offloadInfo.duration_us < OFFLOAD_DEFAULT_MIN_DURATION_SECS * 1000000) { + ALOGV("Offload denied by duration < default min(=%u)", OFFLOAD_DEFAULT_MIN_DURATION_SECS); + return false; + } + + // Do not allow offloading if one non offloadable effect is enabled. This prevents from + // creating an offloaded track and tearing it down immediately after start when audioflinger + // detects there is an active non offloadable effect. + // FIXME: We should check the audio session here but we do not have it in this context. + // This may prevent offloading in rare situations where effects are left active by apps + // in the background. + if (isNonOffloadableEffectEnabled()) { + return false; + } + + // See if there is a profile to support this. + // AUDIO_DEVICE_NONE + IOProfile *profile = getProfileForDirectOutput(AUDIO_DEVICE_NONE /*ignore device */, + offloadInfo.sample_rate, + offloadInfo.format, + offloadInfo.channel_mask, + AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD); + ALOGV("isOffloadSupported() profile %sfound", profile != NULL ? "" : "NOT "); + return (profile != NULL); +} + // ---------------------------------------------------------------------------- // AudioPolicyManagerBase // ---------------------------------------------------------------------------- @@ -1359,11 +1561,14 @@ AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clien continue; } // open all output streams needed to access attached devices + // except for direct output streams that are only opened when they are actually + // required by an app. for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { const IOProfile *outProfile = mHwModules[i]->mOutputProfiles[j]; - if (outProfile->mSupportedDevices & mAttachedOutputDevices) { + if ((outProfile->mSupportedDevices & mAttachedOutputDevices) && + ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) { AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(outProfile); outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice & outProfile->mSupportedDevices); @@ -1665,13 +1870,19 @@ status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device, ALOGV("opening output for device %08x", device); desc = new AudioOutputDescriptor(profile); desc->mDevice = device; + audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER; + offloadInfo.sample_rate = desc->mSamplingRate; + offloadInfo.format = desc->mFormat; + offloadInfo.channel_mask = desc->mChannelMask; + audio_io_handle_t output = mpClientInterface->openOutput(profile->mModule->mHandle, &desc->mDevice, &desc->mSamplingRate, &desc->mFormat, &desc->mChannelMask, &desc->mLatency, - desc->mFlags); + desc->mFlags, + &offloadInfo); if (output != 0) { if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) { String8 reply; @@ -1907,26 +2118,20 @@ void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy) // Move effects associated to this strategy from previous output to new output if (strategy == STRATEGY_MEDIA) { - int outIdx = 0; - for (size_t i = 0; i < dstOutputs.size(); i++) { - AudioOutputDescriptor *desc = mOutputs.valueFor(dstOutputs[i]); - if (desc->mFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) { - outIdx = i; - } - } + audio_io_handle_t fxOutput = selectOutputForEffects(dstOutputs); SortedVector<audio_io_handle_t> moved; for (size_t i = 0; i < mEffects.size(); i++) { EffectDescriptor *desc = mEffects.valueAt(i); if (desc->mSession == AUDIO_SESSION_OUTPUT_MIX && - desc->mIo != dstOutputs[outIdx]) { + desc->mIo != fxOutput) { if (moved.indexOf(desc->mIo) < 0) { ALOGV("checkOutputForStrategy() moving effect %d to output %d", - mEffects.keyAt(i), dstOutputs[outIdx]); + mEffects.keyAt(i), fxOutput); mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, desc->mIo, - dstOutputs[outIdx]); + fxOutput); moved.add(desc->mIo); } - desc->mIo = dstOutputs[outIdx]; + desc->mIo = fxOutput; } } } @@ -2492,6 +2697,7 @@ audio_devices_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource) case AUDIO_SOURCE_DEFAULT: case AUDIO_SOURCE_MIC: case AUDIO_SOURCE_VOICE_RECOGNITION: + case AUDIO_SOURCE_HOTWORD: case AUDIO_SOURCE_VOICE_COMMUNICATION: if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO && mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) { @@ -2669,8 +2875,10 @@ const AudioPolicyManagerBase::VolumeCurvePoint }; // AUDIO_STREAM_SYSTEM, AUDIO_STREAM_ENFORCED_AUDIBLE and AUDIO_STREAM_DTMF volume tracks -// AUDIO_STREAM_RING on phones and AUDIO_STREAM_MUSIC on tablets (See AudioService.java). +// AUDIO_STREAM_RING on phones and AUDIO_STREAM_MUSIC on tablets. +// AUDIO_STREAM_DTMF tracks AUDIO_STREAM_VOICE_CALL while in call (See AudioService.java). // The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset. + const AudioPolicyManagerBase::VolumeCurvePoint AudioPolicyManagerBase::sDefaultSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT] = { {1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f} @@ -3002,17 +3210,6 @@ bool AudioPolicyManagerBase::isStateInCall(int state) { (state == AudioSystem::MODE_IN_COMMUNICATION)); } -bool AudioPolicyManagerBase::needsDirectOuput(audio_stream_type_t stream, - uint32_t samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - audio_output_flags_t flags, - audio_devices_t device) -{ - return ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) || - (format != 0 && !AudioSystem::isLinearPCM(format))); -} - uint32_t AudioPolicyManagerBase::getMaxEffectsCpuLoad() { return MAX_EFFECTS_CPU_LOAD; @@ -3155,7 +3352,7 @@ status_t AudioPolicyManagerBase::AudioOutputDescriptor::dump(int fd) snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate); result.append(buffer); - snprintf(buffer, SIZE, " Format: %d\n", mFormat); + snprintf(buffer, SIZE, " Format: %08x\n", mFormat); result.append(buffer); snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask); result.append(buffer); @@ -3323,57 +3520,54 @@ AudioPolicyManagerBase::IOProfile::~IOProfile() { } -// checks if the IO profile is compatible with specified parameters. By convention a value of 0 -// means a parameter is don't care +// checks if the IO profile is compatible with specified parameters. +// Sampling rate, format and channel mask must be specified in order to +// get a valid a match bool AudioPolicyManagerBase::IOProfile::isCompatibleProfile(audio_devices_t device, uint32_t samplingRate, uint32_t format, uint32_t channelMask, audio_output_flags_t flags) const { - if ((mSupportedDevices & device) != device) { - return false; - } - if ((mFlags & flags) != flags) { - return false; - } - if (samplingRate != 0) { - size_t i; - for (i = 0; i < mSamplingRates.size(); i++) - { - if (mSamplingRates[i] == samplingRate) { - break; - } - } - if (i == mSamplingRates.size()) { - return false; - } - } - if (format != 0) { - size_t i; - for (i = 0; i < mFormats.size(); i++) - { - if (mFormats[i] == format) { - break; - } - } - if (i == mFormats.size()) { - return false; - } - } - if (channelMask != 0) { - size_t i; - for (i = 0; i < mChannelMasks.size(); i++) - { - if (mChannelMasks[i] == channelMask) { - break; - } - } - if (i == mChannelMasks.size()) { - return false; - } - } - return true; + if (samplingRate == 0 || format == 0 || channelMask == 0) { + return false; + } + + if ((mSupportedDevices & device) != device) { + return false; + } + if ((mFlags & flags) != flags) { + return false; + } + size_t i; + for (i = 0; i < mSamplingRates.size(); i++) + { + if (mSamplingRates[i] == samplingRate) { + break; + } + } + if (i == mSamplingRates.size()) { + return false; + } + for (i = 0; i < mFormats.size(); i++) + { + if (mFormats[i] == format) { + break; + } + } + if (i == mFormats.size()) { + return false; + } + for (i = 0; i < mChannelMasks.size(); i++) + { + if (mChannelMasks[i] == channelMask) { + break; + } + } + if (i == mChannelMasks.size()) { + return false; + } + return true; } void AudioPolicyManagerBase::IOProfile::dump(int fd) @@ -3393,7 +3587,7 @@ void AudioPolicyManagerBase::IOProfile::dump(int fd) snprintf(buffer, SIZE, " - channel masks: "); result.append(buffer); for (size_t i = 0; i < mChannelMasks.size(); i++) { - snprintf(buffer, SIZE, "%04x", mChannelMasks[i]); + snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]); result.append(buffer); result.append(i == (mChannelMasks.size() - 1) ? "\n" : ", "); } @@ -3401,14 +3595,14 @@ void AudioPolicyManagerBase::IOProfile::dump(int fd) snprintf(buffer, SIZE, " - formats: "); result.append(buffer); for (size_t i = 0; i < mFormats.size(); i++) { - snprintf(buffer, SIZE, "%d", mFormats[i]); + snprintf(buffer, SIZE, "0x%08x", mFormats[i]); result.append(buffer); result.append(i == (mFormats.size() - 1) ? "\n" : ", "); } - snprintf(buffer, SIZE, " - devices: %04x\n", mSupportedDevices); + snprintf(buffer, SIZE, " - devices: 0x%04x\n", mSupportedDevices); result.append(buffer); - snprintf(buffer, SIZE, " - flags: %04x\n", mFlags); + snprintf(buffer, SIZE, " - flags: 0x%04x\n", mFlags); result.append(buffer); write(fd, result.string(), result.size()); @@ -3455,6 +3649,8 @@ const struct StringToEnum sFlagNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY), STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST), STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER), + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD), + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING), }; const struct StringToEnum sFormatNameToEnumTable[] = { @@ -3507,6 +3703,13 @@ audio_output_flags_t AudioPolicyManagerBase::parseFlagNames(char *name) } flagName = strtok(NULL, "|"); } + //force direct flag if offload flag is set: offloading implies a direct output stream + // and all common behaviors are driven by checking only the direct flag + // this should normally be set appropriately in the policy configuration file + if ((flag & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) { + flag |= AUDIO_OUTPUT_FLAG_DIRECT; + } + return (audio_output_flags_t)flag; } diff --git a/audio/audio_policy.conf b/audio/audio_policy.conf index d4e7844..3e29976 100644 --- a/audio/audio_policy.conf +++ b/audio/audio_policy.conf @@ -9,7 +9,7 @@ global_configuration { attached_output_devices AUDIO_DEVICE_OUT_SPEAKER default_output_device AUDIO_DEVICE_OUT_SPEAKER - attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC + attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_REMOTE_SUBMIX } # audio hardware module section: contains descriptors for all audio hw modules present on the @@ -43,4 +43,22 @@ audio_hw_modules { } } } + r_submix { + outputs { + submix { + sampling_rates 48000 + channel_masks AUDIO_CHANNEL_OUT_STEREO + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_OUT_REMOTE_SUBMIX + } + } + inputs { + submix { + sampling_rates 48000 + channel_masks AUDIO_CHANNEL_IN_STEREO + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_IN_REMOTE_SUBMIX + } + } + } } diff --git a/audio/audio_policy_hal.cpp b/audio/audio_policy_hal.cpp index b5dcb05..755e930 100644 --- a/audio/audio_policy_hal.cpp +++ b/audio/audio_policy_hal.cpp @@ -138,14 +138,16 @@ static audio_io_handle_t ap_get_output(struct audio_policy *pol, uint32_t sampling_rate, audio_format_t format, audio_channel_mask_t channelMask, - audio_output_flags_t flags) + audio_output_flags_t flags, + const audio_offload_info_t *offloadInfo) { struct legacy_audio_policy *lap = to_lap(pol); ALOGV("%s: tid %d", __func__, gettid()); return lap->apm->getOutput((AudioSystem::stream_type)stream, sampling_rate, (int) format, channelMask, - (AudioSystem::output_flags)flags); + (AudioSystem::output_flags)flags, + offloadInfo); } static int ap_start_output(struct audio_policy *pol, audio_io_handle_t output, @@ -321,6 +323,13 @@ static int ap_dump(const struct audio_policy *pol, int fd) return lap->apm->dump(fd); } +static bool ap_is_offload_supported(const struct audio_policy *pol, + const audio_offload_info_t *info) +{ + const struct legacy_audio_policy *lap = to_clap(pol); + return lap->apm->isOffloadSupported(*info); +} + static int create_legacy_ap(const struct audio_policy_device *device, struct audio_policy_service_ops *aps_ops, void *service, @@ -368,6 +377,7 @@ static int create_legacy_ap(const struct audio_policy_device *device, lap->policy.is_stream_active_remotely = ap_is_stream_active_remotely; lap->policy.is_source_active = ap_is_source_active; lap->policy.dump = ap_dump; + lap->policy.is_offload_supported = ap_is_offload_supported; lap->service = service; lap->aps_ops = aps_ops; |