Code changes for audio offload support
- Share existing offload output if compatible instead of creating a new one. Hardware has limited number of offload channels (possible only 1) so we must use as few as possible - Changes to routing handling for offloaded outputs Change-Id: I11111d8f504828595bd8dbf66444cbd1202e7192 Signed-off-by: Eric Laurent <elaurent@google.com>
This commit is contained in:
parent
cb2388428a
commit
a527ffd3c2
5 changed files with 116 additions and 50 deletions
|
@ -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;
|
||||
|
|
|
@ -204,6 +204,10 @@ String8 AudioStreamInStub::getParameters(const String8& keys)
|
|||
return param.toString();
|
||||
}
|
||||
|
||||
AudioHardwareInterface* createAudioHardware(void) {
|
||||
return new AudioHardwareStub();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
@ -491,14 +494,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 (flags & AUDIO_OUTPUT_FLAG_DIRECT) {
|
||||
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;
|
||||
|
@ -515,8 +528,8 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str
|
|||
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) {
|
||||
|
@ -552,6 +565,13 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str
|
|||
#endif //AUDIO_POLICY_TEST
|
||||
|
||||
// open a direct output if required by specified parameters
|
||||
//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);
|
||||
}
|
||||
|
||||
IOProfile *profile = getProfileForDirectOutput(device,
|
||||
samplingRate,
|
||||
format,
|
||||
|
@ -569,7 +589,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);
|
||||
}
|
||||
}
|
||||
|
@ -584,8 +604,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)
|
||||
(outputDesc->mFlags | 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;
|
||||
|
@ -595,7 +614,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 ||
|
||||
|
@ -622,13 +642,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);
|
||||
// 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);
|
||||
|
||||
output = selectOutput(outputs, flags);
|
||||
|
||||
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);
|
||||
|
@ -790,7 +812,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,
|
||||
|
@ -841,7 +863,6 @@ void AudioPolicyManagerBase::releaseOutput(audio_io_handle_t output)
|
|||
closeOutput(output);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource,
|
||||
|
@ -1319,10 +1340,54 @@ 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)
|
||||
{
|
||||
// Stub implementation
|
||||
return false;
|
||||
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;
|
||||
}
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -1368,11 +1433,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);
|
||||
|
@ -3011,17 +3079,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;
|
||||
|
@ -3164,7 +3221,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);
|
||||
|
@ -3402,7 +3459,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" : ", ");
|
||||
}
|
||||
|
@ -3410,14 +3467,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());
|
||||
|
@ -3518,6 +3575,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,10 @@ namespace android_audio_legacy {
|
|||
|
||||
#define NUM_VOL_CURVE_KNEES 2
|
||||
|
||||
// Default minimum length allowed for offloading a compressed track
|
||||
// Can be overridden by the audio.offload.min.duration.secs property
|
||||
#define OFFLOAD_DEFAULT_MIN_DURATION_SECS 5
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// AudioPolicyManagerBase implements audio policy manager behavior common to all platforms.
|
||||
// Each platform must implement an AudioPolicyManager class derived from AudioPolicyManagerBase
|
||||
|
@ -444,16 +448,6 @@ protected:
|
|||
|
||||
void updateDevicesAndOutputs();
|
||||
|
||||
// true if current platform requires a specific output to be opened for this particular
|
||||
// set of parameters. This function is called by getOutput() and is implemented by platform
|
||||
// specific audio policy manager.
|
||||
virtual bool 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);
|
||||
|
||||
virtual uint32_t getMaxEffectsCpuLoad();
|
||||
virtual uint32_t getMaxEffectsMemory();
|
||||
#ifdef AUDIO_POLICY_TEST
|
||||
|
|
Loading…
Reference in a new issue