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,
- uint32_t format,
- uint32_t channelMask,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
audio_output_flags_t flags)
{
for (size_t i = 0; i < mHwModules.size(); i++) {
return mHwModules[i]->mOutputProfiles[j];
}
}
- } else if (flags & AUDIO_OUTPUT_FLAG_DIRECT) {
+ } else {
if (profile->isCompatibleProfile(device, samplingRate, format,
channelMask,
AUDIO_OUTPUT_FLAG_DIRECT)) {
audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type stream,
uint32_t samplingRate,
- uint32_t format,
- uint32_t channelMask,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
AudioSystem::output_flags flags,
const audio_offload_info_t *offloadInfo)
{
flags = (AudioSystem::output_flags)(flags | AUDIO_OUTPUT_FLAG_DIRECT);
}
- IOProfile *profile = getProfileForDirectOutput(device,
- samplingRate,
- format,
- channelMask,
- (audio_output_flags_t)flags);
+ // 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;
outputDesc->mDevice = device;
outputDesc->mSamplingRate = samplingRate;
outputDesc->mFormat = (audio_format_t)format;
- outputDesc->mChannelMask = (audio_channel_mask_t)channelMask;
+ outputDesc->mChannelMask = channelMask;
outputDesc->mLatency = 0;
outputDesc->mFlags =(audio_output_flags_t) (outputDesc->mFlags | flags);
outputDesc->mRefCount[stream] = 0;
ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session);
ssize_t index = mOutputs.indexOfKey(output);
if (index < 0) {
- ALOGW("startOutput() unknow output %d", output);
+ ALOGW("startOutput() unknown output %d", output);
return BAD_VALUE;
}
ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
ssize_t index = mOutputs.indexOfKey(output);
if (index < 0) {
- ALOGW("stopOutput() unknow output %d", output);
+ ALOGW("stopOutput() unknown output %d", output);
return BAD_VALUE;
}
audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource,
uint32_t samplingRate,
- uint32_t format,
- uint32_t channelMask,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
AudioSystem::audio_in_acoustics acoustics)
{
audio_io_handle_t input = 0;
// adapt channel selection to input source
switch(inputSource) {
case AUDIO_SOURCE_VOICE_UPLINK:
- channelMask = AudioSystem::CHANNEL_IN_VOICE_UPLINK;
+ channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK;
break;
case AUDIO_SOURCE_VOICE_DOWNLINK:
- channelMask = AudioSystem::CHANNEL_IN_VOICE_DNLINK;
+ channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK;
break;
case AUDIO_SOURCE_VOICE_CALL:
- channelMask = (AudioSystem::CHANNEL_IN_VOICE_UPLINK | AudioSystem::CHANNEL_IN_VOICE_DNLINK);
+ channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK;
break;
default:
break;
format,
channelMask);
if (profile == NULL) {
- ALOGW("getInput() could not find profile for device %04x, samplingRate %d, format %d,"
+ ALOGW("getInput() could not find profile for device %04x, samplingRate %d, format %d, "
"channelMask %04x",
device, samplingRate, format, channelMask);
return 0;
inputDesc->mDevice = device;
inputDesc->mSamplingRate = samplingRate;
inputDesc->mFormat = (audio_format_t)format;
- inputDesc->mChannelMask = (audio_channel_mask_t)channelMask;
+ inputDesc->mChannelMask = channelMask;
inputDesc->mRefCount = 0;
input = mpClientInterface->openInput(profile->mModule->mHandle,
&inputDesc->mDevice,
(samplingRate != inputDesc->mSamplingRate) ||
(format != inputDesc->mFormat) ||
(channelMask != inputDesc->mChannelMask)) {
- ALOGV("getInput() failed opening input: samplingRate %d, format %d, channelMask %d",
+ ALOGI("getInput() failed opening input: samplingRate %d, format %d, channelMask %x",
samplingRate, format, channelMask);
if (input != 0) {
mpClientInterface->closeInput(input);
ALOGV("startInput() input %d", input);
ssize_t index = mInputs.indexOfKey(input);
if (index < 0) {
- ALOGW("startInput() unknow input %d", input);
+ ALOGW("startInput() unknown input %d", input);
return BAD_VALUE;
}
AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
stopInput(activeInput);
releaseInput(activeInput);
} else {
- ALOGW("startInput() input %d failed: other input already started..", input);
+ ALOGW("startInput() input %d failed: other input already started", input);
return INVALID_OPERATION;
}
}
ALOGV("stopInput() input %d", input);
ssize_t index = mInputs.indexOfKey(input);
if (index < 0) {
- ALOGW("stopInput() unknow input %d", input);
+ ALOGW("stopInput() unknown input %d", input);
return BAD_VALUE;
}
AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
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();
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 */,
mPhoneState(AudioSystem::MODE_NORMAL),
mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0),
- mA2dpSuspended(false), mHasA2dp(false), mHasUsb(false), mHasRemoteSubmix(false)
+ mA2dpSuspended(false), mHasA2dp(false), mHasUsb(false), mHasRemoteSubmix(false),
+ mSpeakerDrcEnabled(false)
{
mpClientInterface = clientInterface;
mForceUse[i] = AudioSystem::FORCE_NONE;
}
- initializeVolumeCurves();
-
mA2dpDeviceAddress = String8("");
mScoDeviceAddress = String8("");
mUsbCardAndDevice = String8("");
}
}
+ // must be done after reading the policy
+ initializeVolumeCurves();
+
// open all output streams needed to access attached devices
for (size_t i = 0; i < mHwModules.size(); i++) {
mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);
}
if (profile->mChannelMasks[0] == 0) {
profile->mChannelMasks.clear();
- profile->mChannelMasks.add((audio_channel_mask_t)0);
+ profile->mChannelMasks.add(0);
}
}
}
AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getInputProfile(audio_devices_t device,
uint32_t samplingRate,
- uint32_t format,
- uint32_t channelMask)
+ audio_format_t format,
+ audio_channel_mask_t channelMask)
{
// Choose an input profile based on the requested capture parameters: select the first available
// profile supporting all requested parameters.
{1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f}
};
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sSpeakerSonificationVolumeCurveDrc[AudioPolicyManagerBase::VOLCNT] = {
+ {1, -35.7f}, {33, -26.1f}, {66, -13.2f}, {100, 0.0f}
+};
+
// AUDIO_STREAM_SYSTEM, AUDIO_STREAM_ENFORCED_AUDIBLE and AUDIO_STREAM_DTMF volume tracks
// 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).
};
const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sDefaultSystemVolumeCurveDrc[AudioPolicyManagerBase::VOLCNT] = {
+ {1, -34.0f}, {33, -24.0f}, {66, -15.0f}, {100, -6.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
AudioPolicyManagerBase::sHeadsetSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
{1, -30.0f}, {33, -26.0f}, {66, -22.0f}, {100, -18.0f}
};
sVolumeProfiles[i][j];
}
}
+
+ // Check availability of DRC on speaker path: if available, override some of the speaker curves
+ if (mSpeakerDrcEnabled) {
+ mStreams[AUDIO_STREAM_SYSTEM].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+ sDefaultSystemVolumeCurveDrc;
+ mStreams[AUDIO_STREAM_RING].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+ sSpeakerSonificationVolumeCurveDrc;
+ mStreams[AUDIO_STREAM_ALARM].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+ sSpeakerSonificationVolumeCurveDrc;
+ mStreams[AUDIO_STREAM_NOTIFICATION].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+ sSpeakerSonificationVolumeCurveDrc;
+ }
}
float AudioPolicyManagerBase::computeVolume(int stream,
AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor(
const IOProfile *profile)
: mId(0), mSamplingRate(0), mFormat((audio_format_t)0),
- mChannelMask((audio_channel_mask_t)0), mLatency(0),
+ mChannelMask(0), mLatency(0),
mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE),
mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0)
{
// --- AudioInputDescriptor class implementation
AudioPolicyManagerBase::AudioInputDescriptor::AudioInputDescriptor(const IOProfile *profile)
- : mSamplingRate(0), mFormat((audio_format_t)0), mChannelMask((audio_channel_mask_t)0),
+ : mSamplingRate(0), mFormat((audio_format_t)0), mChannelMask(0),
mDevice(AUDIO_DEVICE_NONE), mRefCount(0),
mInputSource(0), mProfile(profile)
{
{
}
-// 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_format_t format,
+ audio_channel_mask_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)
return 0;
}
+bool AudioPolicyManagerBase::stringToBool(const char *value)
+{
+ return ((strcasecmp("true", value) == 0) || (strcmp("1", value) == 0));
+}
+
audio_output_flags_t AudioPolicyManagerBase::parseFlagNames(char *name)
{
uint32_t flag = 0;
ALOGV("loadInChannels() %s", name);
if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
- profile->mChannelMasks.add((audio_channel_mask_t)0);
+ profile->mChannelMasks.add(0);
return;
}
// by convention, "0' in the first entry in mChannelMasks indicates the supported channel
// masks should be read from the output stream after it is opened for the first time
if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
- profile->mChannelMasks.add((audio_channel_mask_t)0);
+ profile->mChannelMasks.add(0);
return;
}
} else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
mAvailableInputDevices = parseDeviceNames((char *)node->value) & ~AUDIO_DEVICE_BIT_IN;
ALOGV("loadGlobalConfig() mAvailableInputDevices %04x", mAvailableInputDevices);
+ } else if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
+ mSpeakerDrcEnabled = stringToBool((char *)node->value);
+ ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", mSpeakerDrcEnabled);
}
node = node->next;
}