Commit e43c5c4c authored by Eric Laurent's avatar Eric Laurent
Browse files

Fix issue 5440852: Youtube volume is too small ...

When no DRC is applied by the platform when playing
over the device speaker, faint audio signals are not boosted and
barely audible until the media volume is raised to about one fourth
of the range.

Compensate this by applying a different volume curve for music stream
when the speaker is selected.

Change-Id: I03f316fb28150eda50b05dfa12310701e2674648
parent 3a9b3983
......@@ -1868,61 +1868,146 @@ audio_io_handle_t AudioPolicyManagerBase::getActiveInput()
return 0;
}
AudioPolicyManagerBase::device_category AudioPolicyManagerBase::getDeviceCategory(uint32_t device)
{
if (device == 0) {
// this happens when forcing a route update and no track is active on an output.
// In this case the returned category is not important.
return DEVICE_CATEGORY_SPEAKER;
}
if (AudioSystem::popCount(device) > 1) {
// Multiple device selection is either:
// - speaker + one other device: give priority to speaker in this case.
// - one A2DP device + another device: happens with duplicated output. In this case
// retain the device on the A2DP output as the other must not correspond to an active
// selection if not the speaker.
if (device & AUDIO_DEVICE_OUT_SPEAKER)
return DEVICE_CATEGORY_SPEAKER;
device &= AUDIO_DEVICE_OUT_ALL_A2DP;
}
LOGW_IF(AudioSystem::popCount(device) != 1,
"getDeviceCategory() invalid device combination: %08x",
device);
switch(device) {
case AUDIO_DEVICE_OUT_EARPIECE:
return DEVICE_CATEGORY_EARPIECE;
case AUDIO_DEVICE_OUT_WIRED_HEADSET:
case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
return DEVICE_CATEGORY_HEADSET;
case AUDIO_DEVICE_OUT_SPEAKER:
case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
default:
return DEVICE_CATEGORY_SPEAKER;
}
}
float AudioPolicyManagerBase::volIndexToAmpl(uint32_t device, const StreamDescriptor& streamDesc,
int indexInUi) {
int indexInUi)
{
device_category deviceCategory = getDeviceCategory(device);
const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory];
// the volume index in the UI is relative to the min and max volume indices for this stream type
int nbSteps = 1 + streamDesc.mVolumeCurve[VOLMAX].mIndex -
streamDesc.mVolumeCurve[VOLMIN].mIndex;
int nbSteps = 1 + curve[VOLMAX].mIndex -
curve[VOLMIN].mIndex;
int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) /
(streamDesc.mIndexMax - streamDesc.mIndexMin);
// find what part of the curve this index volume belongs to, or if it's out of bounds
int segment = 0;
if (volIdx < streamDesc.mVolumeCurve[VOLMIN].mIndex) { // out of bounds
if (volIdx < curve[VOLMIN].mIndex) { // out of bounds
return 0.0f;
} else if (volIdx < streamDesc.mVolumeCurve[VOLKNEE1].mIndex) {
} else if (volIdx < curve[VOLKNEE1].mIndex) {
segment = 0;
} else if (volIdx < streamDesc.mVolumeCurve[VOLKNEE2].mIndex) {
} else if (volIdx < curve[VOLKNEE2].mIndex) {
segment = 1;
} else if (volIdx <= streamDesc.mVolumeCurve[VOLMAX].mIndex) {
} else if (volIdx <= curve[VOLMAX].mIndex) {
segment = 2;
} else { // out of bounds
return 1.0f;
}
// linear interpolation in the attenuation table in dB
float decibels = streamDesc.mVolumeCurve[segment].mDBAttenuation +
((float)(volIdx - streamDesc.mVolumeCurve[segment].mIndex)) *
( (streamDesc.mVolumeCurve[segment+1].mDBAttenuation -
streamDesc.mVolumeCurve[segment].mDBAttenuation) /
((float)(streamDesc.mVolumeCurve[segment+1].mIndex -
streamDesc.mVolumeCurve[segment].mIndex)) );
float decibels = curve[segment].mDBAttenuation +
((float)(volIdx - curve[segment].mIndex)) *
( (curve[segment+1].mDBAttenuation -
curve[segment].mDBAttenuation) /
((float)(curve[segment+1].mIndex -
curve[segment].mIndex)) );
float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
LOGV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f] ampl=%.5f",
streamDesc.mVolumeCurve[segment].mIndex, volIdx,
streamDesc.mVolumeCurve[segment+1].mIndex,
streamDesc.mVolumeCurve[segment].mDBAttenuation,
curve[segment].mIndex, volIdx,
curve[segment+1].mIndex,
curve[segment].mDBAttenuation,
decibels,
streamDesc.mVolumeCurve[segment+1].mDBAttenuation,
curve[segment+1].mDBAttenuation,
amplification);
return amplification;
}
const AudioPolicyManagerBase::VolumeCurvePoint
AudioPolicyManagerBase::sVolumeProfiles[AudioPolicyManagerBase::NUM_STRATEGIES]
[AudioPolicyManagerBase::VOLCNT] = {
{ {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f}}, // STRATEGY_MEDIA
{ {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f}}, // STRATEGY_PHONE
{ {1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f}}, // STRATEGY_SONIFICATION
{ {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f}} // STRATEGY_DTMF
AudioPolicyManagerBase::sDefaultVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
{1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f}
};
const AudioPolicyManagerBase::VolumeCurvePoint
AudioPolicyManagerBase::sDefaultMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
{1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f}
};
void AudioPolicyManagerBase::initializeVolumeCurves() {
for (int i=0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
for (int j=0; j < VOLCNT; j++) {
const AudioPolicyManagerBase::VolumeCurvePoint
AudioPolicyManagerBase::sSpeakerMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
{1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f}
};
const AudioPolicyManagerBase::VolumeCurvePoint
AudioPolicyManagerBase::sSpeakerSonificationVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
{1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f}
};
const AudioPolicyManagerBase::VolumeCurvePoint
*AudioPolicyManagerBase::sVolumeProfiles[AudioPolicyManagerBase::NUM_STRATEGIES]
[AudioPolicyManagerBase::DEVICE_CATEGORY_CNT] = {
{ // STRATEGY_MEDIA
sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EARPIECE
},
{ // STRATEGY_PHONE
sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
sDefaultVolumeCurve, // DEVICE_CATEGORY_SPEAKER
sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE
},
{ // STRATEGY_SONIFICATION
sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE
},
{ // STRATEGY_DTMF
sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
sDefaultVolumeCurve, // DEVICE_CATEGORY_SPEAKER
sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE
}
};
void AudioPolicyManagerBase::initializeVolumeCurves()
{
for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
mStreams[i].mVolumeCurve[j] =
sVolumeProfiles[getStrategy((AudioSystem::stream_type)i)][j];
}
......
......@@ -146,7 +146,24 @@ protected:
float mDBAttenuation;
};
static const VolumeCurvePoint sVolumeProfiles[NUM_STRATEGIES][VOLCNT];
// device categories used for volume curve management.
enum device_category {
DEVICE_CATEGORY_HEADSET,
DEVICE_CATEGORY_SPEAKER,
DEVICE_CATEGORY_EARPIECE,
DEVICE_CATEGORY_CNT
};
// default volume curve
static const VolumeCurvePoint sDefaultVolumeCurve[AudioPolicyManagerBase::VOLCNT];
// default volume curve for media strategy
static const VolumeCurvePoint sDefaultMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT];
// volume curve for media strategy on speakers
static const VolumeCurvePoint sSpeakerMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT];
// volume curve for sonification strategy on speakers
static const VolumeCurvePoint sSpeakerSonificationVolumeCurve[AudioPolicyManagerBase::VOLCNT];
// default volume curves per strategy and device category. See initializeVolumeCurves()
static const VolumeCurvePoint *sVolumeProfiles[NUM_STRATEGIES][DEVICE_CATEGORY_CNT];
// descriptor for audio outputs. Used to maintain current configuration of each opened audio output
// and keep track of the usage of this output by each audio stream type.
......@@ -211,7 +228,7 @@ protected:
int mIndexCur; // current volume index
bool mCanBeMuted; // true is the stream can be muted
VolumeCurvePoint mVolumeCurve[VOLCNT];
const VolumeCurvePoint *mVolumeCurve[DEVICE_CATEGORY_CNT];
};
// stream descriptor used for volume control
......@@ -249,7 +266,8 @@ protected:
virtual uint32_t getDeviceForInputSource(int inputSource);
// return io handle of active input or 0 if no input is active
audio_io_handle_t getActiveInput();
virtual void initializeVolumeCurves();
// initialize volume curves for each strategy and device category
void initializeVolumeCurves();
// compute the actual volume for a given stream according to the requested index and a particular
// device
virtual float computeVolume(int stream, int index, audio_io_handle_t output, uint32_t device);
......@@ -319,6 +337,9 @@ protected:
status_t setEffectEnabled(EffectDescriptor *pDesc, bool enabled);
// returns the category the device belongs to with regard to volume curve management
static device_category getDeviceCategory(uint32_t device);
AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
audio_io_handle_t mHardwareOutput; // hardware output handler
audio_io_handle_t mA2dpOutput; // A2DP output handler
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment