DO NOT MERGE - audioflinger: first patch panel implementation.
Added a new PatchPanel subclass to AudioFlinger
to handle audio ports and audio patches configuration
and connection.
The first implementation does not add new functionnality.
AudioPolicyManager uses patch panel interface to control
device routing.
AudioFlinger:
- Added PatchPanel class. The first implementation does not
add new functionnality. PatchPanel handles routing commands
for audio HAL after 3.0 or converts to setParameters for audio
HALs before 3.0.
- Added config events to ThreadBase to control synchronized
audio patch connection.
AudioPolicyManager:
- Use PatchPanel API to control device selection isntead of setParameters.
- New base class AudioPort common to audio device descriptors
and input output stream profiles. This class is RefBase and groups
attributes common to audio ports.
- Use same device selection flow for input as for outputs:
getNewInputDevice -> getDeviceForInptusiource -> setInputDevice
Change-Id: Idaa5a883b19a45816651c58cac697640dc717cd9
diff --git a/services/audiopolicy/AudioPolicyClientImpl.cpp b/services/audiopolicy/AudioPolicyClientImpl.cpp
index 44c47c3..8225e36 100644
--- a/services/audiopolicy/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/AudioPolicyClientImpl.cpp
@@ -182,6 +182,17 @@
return af->moveEffects(session, src_output, dst_output);
}
+status_t AudioPolicyService::AudioPolicyClient::createAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs)
+{
+ return mAudioPolicyService->clientCreateAudioPatch(patch, handle, delayMs);
+}
+status_t AudioPolicyService::AudioPolicyClient::releaseAudioPatch(audio_patch_handle_t handle,
+ int delayMs)
+{
+ return mAudioPolicyService->clientReleaseAudioPatch(handle, delayMs);
+}
}; // namespace android
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 66260e3..bb2deb6 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -246,6 +246,15 @@
audio_io_handle_t srcOutput,
audio_io_handle_t dstOutput) = 0;
+ /* Create a patch between several source and sink ports */
+ virtual status_t createAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs) = 0;
+
+ /* Release a patch */
+ virtual status_t releaseAudioPatch(audio_patch_handle_t handle,
+ int delayMs) = 0;
+
};
extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface);
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index bd9b15a..b047e1d 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -267,7 +267,7 @@
// also force a device 0 for the two outputs it is duplicated to which may override
// a valid device selection on those outputs.
setOutputDevice(mOutputs.keyAt(i),
- getNewDevice(mOutputs.keyAt(i), true /*fromCache*/),
+ getNewOutputDevice(mOutputs.keyAt(i), true /*fromCache*/),
!mOutputs.valueAt(i)->isDuplicated(),
0);
}
@@ -419,7 +419,7 @@
}
// check for device and output changes triggered by new phone state
- newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/);
+ newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
checkA2dpSuspend();
checkOutputForAllStrategies();
updateDevicesAndOutputs();
@@ -544,7 +544,7 @@
updateDevicesAndOutputs();
for (size_t i = 0; i < mOutputs.size(); i++) {
audio_io_handle_t output = mOutputs.keyAt(i);
- audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/);
+ audio_devices_t newDevice = getNewOutputDevice(output, true /*fromCache*/);
setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE));
if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) {
applyStreamVolumes(output, newDevice, 0, true);
@@ -553,16 +553,7 @@
audio_io_handle_t activeInput = getActiveInput();
if (activeInput != 0) {
- AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
- audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
- if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
- ALOGV("setForceUse() changing device from %x to %x for input %d",
- inputDesc->mDevice, newDevice, activeInput);
- inputDesc->mDevice = newDevice;
- AudioParameter param = AudioParameter();
- param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
- mpClientInterface->setParameters(activeInput, param.toString());
- }
+ setInputDevice(activeInput, getNewInputDevice(activeInput));
}
}
@@ -579,7 +570,7 @@
// Find a direct output profile compatible with the parameters passed, even if the input flags do
// not explicitly request a direct output
-AudioPolicyManager::IOProfile *AudioPolicyManager::getProfileForDirectOutput(
+sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getProfileForDirectOutput(
audio_devices_t device,
uint32_t samplingRate,
audio_format_t format,
@@ -591,7 +582,7 @@
continue;
}
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
- IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
+ sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
bool found = false;
if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
if (profile->isCompatibleProfile(device, samplingRate, format,
@@ -676,7 +667,7 @@
// 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;
+ sp<IOProfile> profile;
if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
!isNonOffloadableEffectEnabled()) {
profile = getProfileForDirectOutput(device,
@@ -686,7 +677,7 @@
(audio_output_flags_t)flags);
}
- if (profile != NULL) {
+ if (profile != 0) {
AudioOutputDescriptor *outputDesc = NULL;
for (size_t i = 0; i < mOutputs.size(); i++) {
@@ -705,7 +696,7 @@
}
// close direct output if currently open and configured with different parameters
if (outputDesc != NULL) {
- closeOutput(outputDesc->mId);
+ closeOutput(outputDesc->mIoHandle);
}
outputDesc = new AudioOutputDescriptor(profile);
outputDesc->mDevice = device;
@@ -837,7 +828,7 @@
outputDesc->changeRefCount(stream, 1);
if (outputDesc->mRefCount[stream] == 1) {
- audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+ audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/);
routing_strategy strategy = getStrategy(stream);
bool shouldWait = (strategy == STRATEGY_SONIFICATION) ||
(strategy == STRATEGY_SONIFICATION_RESPECTFUL);
@@ -910,7 +901,7 @@
// store time at which the stream was stopped - see isStreamActive()
if (outputDesc->mRefCount[stream] == 0) {
outputDesc->mStopTime[stream] = systemTime();
- audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+ audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/);
// delay the device switch by twice the latency because stopOutput() is executed when
// the track stop() command is received and at that time the audio track buffer can
// still contain data that needs to be drained. The latency only covers the audio HAL
@@ -928,7 +919,7 @@
outputDesc->sharesHwModuleWith(desc) &&
(newDevice != desc->device())) {
setOutputDevice(curOutput,
- getNewDevice(curOutput, false /*fromCache*/),
+ getNewOutputDevice(curOutput, false /*fromCache*/),
true,
outputDesc->mLatency*2);
}
@@ -1018,11 +1009,11 @@
break;
}
- IOProfile *profile = getInputProfile(device,
+ sp<IOProfile> profile = getInputProfile(device,
samplingRate,
format,
channelMask);
- if (profile == NULL) {
+ if (profile == 0) {
ALOGW("getInput() could not find profile for device %04x, samplingRate %d, format %d, "
"channelMask %04x",
device, samplingRate, format, channelMask);
@@ -1095,10 +1086,7 @@
}
}
- audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
- if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
- inputDesc->mDevice = newDevice;
- }
+ setInputDevice(input, getNewInputDevice(input), true /* force */);
// automatically enable the remote submix output when input is started
if (audio_is_remote_submix_device(inputDesc->mDevice)) {
@@ -1106,17 +1094,8 @@
AUDIO_POLICY_DEVICE_STATE_AVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
}
- AudioParameter param = AudioParameter();
- param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice);
-
- 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());
-
inputDesc->mRefCount = 1;
return NO_ERROR;
}
@@ -1141,9 +1120,7 @@
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
}
- AudioParameter param = AudioParameter();
- param.addInt(String8(AudioParameter::keyRouting), 0);
- mpClientInterface->setParameters(input, param.toString());
+ resetInputDevice(input);
inputDesc->mRefCount = 0;
return NO_ERROR;
}
@@ -1608,13 +1585,13 @@
// See if there is a profile to support this.
// AUDIO_DEVICE_NONE
- IOProfile *profile = getProfileForDirectOutput(AUDIO_DEVICE_NONE /*ignore device */,
+ sp<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);
+ ALOGV("isOffloadSupported() profile %sfound", profile != 0 ? "" : "NOT ");
+ return (profile != 0);
}
// ----------------------------------------------------------------------------
@@ -1671,7 +1648,7 @@
// This also validates mAvailableOutputDevices list
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
{
- const IOProfile *outProfile = mHwModules[i]->mOutputProfiles[j];
+ const sp<IOProfile> outProfile = mHwModules[i]->mOutputProfiles[j];
if (outProfile->mSupportedDevices.isEmpty()) {
ALOGW("Output profile contains no device on module %s", mHwModules[i]->mName);
@@ -1683,7 +1660,7 @@
((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) {
AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(outProfile);
- outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice->mType & profileTypes);
+ outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice->mDeviceType & profileTypes);
audio_io_handle_t output = mpClientInterface->openOutput(
outProfile->mModule->mHandle,
&outputDesc->mDevice,
@@ -1699,7 +1676,7 @@
delete outputDesc;
} else {
for (size_t k = 0; k < outProfile->mSupportedDevices.size(); k++) {
- audio_devices_t type = outProfile->mSupportedDevices[k]->mType;
+ audio_devices_t type = outProfile->mSupportedDevices[k]->mDeviceType;
ssize_t index =
mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[k]);
// give a valid ID to an attached device once confirmed it is reachable
@@ -1722,7 +1699,7 @@
// mAvailableInputDevices list
for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
{
- const IOProfile *inProfile = mHwModules[i]->mInputProfiles[j];
+ const sp<IOProfile> inProfile = mHwModules[i]->mInputProfiles[j];
if (inProfile->mSupportedDevices.isEmpty()) {
ALOGW("Input profile contains no device on module %s", mHwModules[i]->mName);
@@ -1734,7 +1711,7 @@
AudioInputDescriptor *inputDesc = new AudioInputDescriptor(inProfile);
inputDesc->mInputSource = AUDIO_SOURCE_MIC;
- inputDesc->mDevice = inProfile->mSupportedDevices[0]->mType;
+ inputDesc->mDevice = inProfile->mSupportedDevices[0]->mDeviceType;
audio_io_handle_t input = mpClientInterface->openInput(
inProfile->mModule->mHandle,
&inputDesc->mDevice,
@@ -1744,7 +1721,7 @@
if (input != 0) {
for (size_t k = 0; k < inProfile->mSupportedDevices.size(); k++) {
- audio_devices_t type = inProfile->mSupportedDevices[k]->mType;
+ audio_devices_t type = inProfile->mSupportedDevices[k]->mDeviceType;
ssize_t index =
mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]);
// give a valid ID to an attached device once confirmed it is reachable
@@ -1765,7 +1742,7 @@
// make sure all attached devices have been allocated a unique ID
for (size_t i = 0; i < mAvailableOutputDevices.size();) {
if (mAvailableOutputDevices[i]->mId == 0) {
- ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->mType);
+ ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->mDeviceType);
mAvailableOutputDevices.remove(mAvailableOutputDevices[i]);
continue;
}
@@ -1773,7 +1750,7 @@
}
for (size_t i = 0; i < mAvailableInputDevices.size();) {
if (mAvailableInputDevices[i]->mId == 0) {
- ALOGW("Input device %08x unreachable", mAvailableInputDevices[i]->mType);
+ ALOGW("Input device %08x unreachable", mAvailableInputDevices[i]->mDeviceType);
mAvailableInputDevices.remove(mAvailableInputDevices[i]);
continue;
}
@@ -1781,7 +1758,7 @@
}
// make sure default device is reachable
if (mAvailableOutputDevices.indexOf(mDefaultOutputDevice) < 0) {
- ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->mType);
+ ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->mDeviceType);
}
ALOGE_IF((mPrimaryOutput == 0), "Failed to open primary output");
@@ -1990,16 +1967,18 @@
// ---
-void AudioPolicyManager::addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc)
+void AudioPolicyManager::addOutput(audio_io_handle_t output, AudioOutputDescriptor *outputDesc)
{
- outputDesc->mId = id;
- mOutputs.add(id, outputDesc);
+ outputDesc->mIoHandle = output;
+ outputDesc->mId = nextUniqueId();
+ mOutputs.add(output, outputDesc);
}
-void AudioPolicyManager::addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc)
+void AudioPolicyManager::addInput(audio_io_handle_t input, AudioInputDescriptor *inputDesc)
{
- inputDesc->mId = id;
- mInputs.add(id, inputDesc);
+ inputDesc->mIoHandle = input;
+ inputDesc->mId = nextUniqueId();
+ mInputs.add(input, inputDesc);
}
String8 AudioPolicyManager::addressToParameter(audio_devices_t device, const String8 address)
@@ -2027,7 +2006,7 @@
}
}
// then look for output profiles that can be routed to this device
- SortedVector<IOProfile *> profiles;
+ SortedVector< sp<IOProfile> > profiles;
for (size_t i = 0; i < mHwModules.size(); i++)
{
if (mHwModules[i]->mHandle == 0) {
@@ -2050,7 +2029,7 @@
// open outputs for matching profiles if needed. Direct outputs are also opened to
// query for dynamic parameters and will be closed later by setDeviceConnectionState()
for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
- IOProfile *profile = profiles[profile_index];
+ sp<IOProfile> profile = profiles[profile_index];
// nothing to do if one output is already opened for this profile
size_t j;
@@ -2096,7 +2075,7 @@
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
- loadSamplingRates(value + 1, profile);
+ profile->loadSamplingRates(value + 1);
}
}
if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
@@ -2106,7 +2085,7 @@
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
- loadFormats(value + 1, profile);
+ profile->loadFormats(value + 1);
}
}
if (profile->mChannelMasks[0] == 0) {
@@ -2116,7 +2095,7 @@
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
- loadOutChannels(value + 1, profile);
+ profile->loadOutChannels(value + 1);
}
}
if (((profile->mSamplingRates[0] == 0) &&
@@ -2211,7 +2190,7 @@
}
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
{
- IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
+ sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
if (profile->mSupportedDevices.types() & device) {
ALOGV("checkOutputsForDevice(): "
"clearing direct output profile %zu on module %zu", j, i);
@@ -2251,7 +2230,7 @@
}
// then look for input profiles that can be routed to this device
- SortedVector<IOProfile *> profiles;
+ SortedVector< sp<IOProfile> > profiles;
for (size_t module_idx = 0; module_idx < mHwModules.size(); module_idx++)
{
if (mHwModules[module_idx]->mHandle == 0) {
@@ -2279,7 +2258,7 @@
// query for dynamic parameters and will be closed later by setDeviceConnectionState()
for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
- IOProfile *profile = profiles[profile_index];
+ sp<IOProfile> profile = profiles[profile_index];
// nothing to do if one input is already opened for this profile
size_t input_index;
for (input_index = 0; input_index < mInputs.size(); input_index++) {
@@ -2317,7 +2296,7 @@
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
- loadSamplingRates(value + 1, profile);
+ profile->loadSamplingRates(value + 1);
}
}
if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
@@ -2326,7 +2305,7 @@
ALOGV("checkInputsForDevice() direct input sup formats %s", reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
- loadFormats(value + 1, profile);
+ profile->loadFormats(value + 1);
}
}
if (profile->mChannelMasks[0] == 0) {
@@ -2336,7 +2315,7 @@
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
- loadInChannels(value + 1, profile);
+ profile->loadInChannels(value + 1);
}
}
if (((profile->mSamplingRates[0] == 0) && (profile->mSamplingRates.size() < 2)) ||
@@ -2386,7 +2365,7 @@
for (size_t profile_index = 0;
profile_index < mHwModules[module_index]->mInputProfiles.size();
profile_index++) {
- IOProfile *profile = mHwModules[module_index]->mInputProfiles[profile_index];
+ sp<IOProfile> profile = mHwModules[module_index]->mInputProfiles[profile_index];
if (profile->mSupportedDevices.types() & device) {
ALOGV("checkInputsForDevice(): clearing direct input profile %d on module %d",
profile_index, module_index);
@@ -2605,7 +2584,7 @@
}
}
-audio_devices_t AudioPolicyManager::getNewDevice(audio_io_handle_t output, bool fromCache)
+audio_devices_t AudioPolicyManager::getNewOutputDevice(audio_io_handle_t output, bool fromCache)
{
audio_devices_t device = AUDIO_DEVICE_NONE;
@@ -2638,7 +2617,16 @@
device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
}
- ALOGV("getNewDevice() selected device %x", device);
+ ALOGV("getNewOutputDevice() selected device %x", device);
+ return device;
+}
+
+audio_devices_t AudioPolicyManager::getNewInputDevice(audio_io_handle_t input)
+{
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(input);
+ audio_devices_t device = getDeviceForInputSource(inputDesc->mInputSource);
+
+ ALOGV("getNewInputDevice() selected device %x", device);
return device;
}
@@ -2784,7 +2772,7 @@
}
device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_EARPIECE;
if (device) break;
- device = mDefaultOutputDevice->mType;
+ device = mDefaultOutputDevice->mDeviceType;
if (device == AUDIO_DEVICE_NONE) {
ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
}
@@ -2813,7 +2801,7 @@
}
device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER;
if (device) break;
- device = mDefaultOutputDevice->mType;
+ device = mDefaultOutputDevice->mDeviceType;
if (device == AUDIO_DEVICE_NONE) {
ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
}
@@ -2895,7 +2883,7 @@
// STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
device |= device2;
if (device) break;
- device = mDefaultOutputDevice->mType;
+ device = mDefaultOutputDevice->mDeviceType;
if (device == AUDIO_DEVICE_NONE) {
ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA");
}
@@ -2981,9 +2969,9 @@
}
for (size_t i = 0; i < NUM_STRATEGIES; i++) {
if (outputDesc->isStrategyActive((routing_strategy)i)) {
- setStrategyMute((routing_strategy)i, true, outputDesc->mId);
+ setStrategyMute((routing_strategy)i, true, outputDesc->mIoHandle);
// do tempMute unmute after twice the mute wait time
- setStrategyMute((routing_strategy)i, false, outputDesc->mId,
+ setStrategyMute((routing_strategy)i, false, outputDesc->mIoHandle,
muteWaitMs *2, device);
}
}
@@ -3009,8 +2997,8 @@
uint32_t muteWaitMs;
if (outputDesc->isDuplicated()) {
- muteWaitMs = setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
- muteWaitMs += setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
+ muteWaitMs = setOutputDevice(outputDesc->mOutput1->mIoHandle, device, force, delayMs);
+ muteWaitMs += setOutputDevice(outputDesc->mOutput2->mIoHandle, device, force, delayMs);
return muteWaitMs;
}
// no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
@@ -3042,9 +3030,34 @@
}
ALOGV("setOutputDevice() changing device");
+
// do the routing
- param.addInt(String8(AudioParameter::keyRouting), (int)device);
- mpClientInterface->setParameters(output, param.toString(), delayMs);
+ if (device == AUDIO_DEVICE_NONE) {
+ resetOutputDevice(output, delayMs);
+ } else {
+ DeviceVector deviceList = mAvailableOutputDevices.getDevicesFromType(device);
+ if (!deviceList.isEmpty()) {
+ struct audio_patch patch;
+ outputDesc->toAudioPortConfig(&patch.sources[0]);
+ patch.num_sources = 1;
+ patch.num_sinks = 0;
+ for (size_t i = 0; i < deviceList.size() && i < AUDIO_PATCH_PORTS_MAX; i++) {
+ deviceList.itemAt(i)->toAudioPortConfig(&patch.sinks[i]);
+ patch.sinks[i].ext.device.hw_module = patch.sources[0].ext.mix.hw_module;
+ patch.num_sinks++;
+ }
+ audio_patch_handle_t patchHandle = outputDesc->mPatchHandle;
+ status_t status = mpClientInterface->createAudioPatch(&patch,
+ &patchHandle,
+ delayMs);
+ ALOGV("setOutputDevice() createAudioPatch returned %d patchHandle %d"
+ "num_sources %d num_sinks %d",
+ status, patchHandle, patch.num_sources, patch.num_sinks);
+ if (status == NO_ERROR) {
+ outputDesc->mPatchHandle = patchHandle;
+ }
+ }
+ }
// update stream volumes according to new device
applyStreamVolumes(output, device, delayMs);
@@ -3052,7 +3065,65 @@
return muteWaitMs;
}
-AudioPolicyManager::IOProfile *AudioPolicyManager::getInputProfile(audio_devices_t device,
+status_t AudioPolicyManager::resetOutputDevice(audio_io_handle_t output,
+ int delayMs)
+{
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+ if (outputDesc->mPatchHandle == 0) {
+ return INVALID_OPERATION;
+ }
+ status_t status = mpClientInterface->releaseAudioPatch(outputDesc->mPatchHandle, delayMs);
+ ALOGV("resetOutputDevice() releaseAudioPatch returned %d", status);
+ outputDesc->mPatchHandle = 0;
+ return status;
+}
+
+status_t AudioPolicyManager::setInputDevice(audio_io_handle_t input,
+ audio_devices_t device,
+ bool force)
+{
+ status_t status = NO_ERROR;
+
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(input);
+ if ((device != AUDIO_DEVICE_NONE) && ((device != inputDesc->mDevice) || force)) {
+ inputDesc->mDevice = device;
+
+ DeviceVector deviceList = mAvailableInputDevices.getDevicesFromType(device);
+ if (!deviceList.isEmpty()) {
+ struct audio_patch patch;
+ inputDesc->toAudioPortConfig(&patch.sinks[0]);
+ patch.num_sinks = 1;
+ //only one input device for now
+ deviceList.itemAt(0)->toAudioPortConfig(&patch.sources[0]);
+ patch.sources[0].ext.device.hw_module = patch.sinks[0].ext.mix.hw_module;
+ patch.num_sources = 1;
+ audio_patch_handle_t patchHandle = inputDesc->mPatchHandle;
+ status_t status = mpClientInterface->createAudioPatch(&patch,
+ &patchHandle,
+ 0);
+ ALOGV("setInputDevice() createAudioPatch returned %d patchHandle %d",
+ status, patchHandle);
+ if (status == NO_ERROR) {
+ inputDesc->mPatchHandle = patchHandle;
+ }
+ }
+ }
+ return status;
+}
+
+status_t AudioPolicyManager::resetInputDevice(audio_io_handle_t input)
+{
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(input);
+ if (inputDesc->mPatchHandle == 0) {
+ return INVALID_OPERATION;
+ }
+ status_t status = mpClientInterface->releaseAudioPatch(inputDesc->mPatchHandle, 0);
+ ALOGV("resetInputDevice() releaseAudioPatch returned %d", status);
+ inputDesc->mPatchHandle = 0;
+ return status;
+}
+
+sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask)
@@ -3067,7 +3138,7 @@
}
for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
{
- IOProfile *profile = mHwModules[i]->mInputProfiles[j];
+ sp<IOProfile> profile = mHwModules[i]->mInputProfiles[j];
// profile->log();
if (profile->isCompatibleProfile(device, samplingRate, format,
channelMask, AUDIO_OUTPUT_FLAG_NONE)) {
@@ -3648,10 +3719,10 @@
// --- AudioOutputDescriptor class implementation
AudioPolicyManager::AudioOutputDescriptor::AudioOutputDescriptor(
- const IOProfile *profile)
- : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT),
+ const sp<IOProfile>& profile)
+ : mId(0), mIoHandle(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT),
mChannelMask(0), mLatency(0),
- mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE),
+ mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0),
mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0)
{
// clear usage count for all stream types
@@ -3770,6 +3841,32 @@
return false;
}
+void AudioPolicyManager::AudioOutputDescriptor::toAudioPortConfig(
+ struct audio_port_config *config) const
+{
+ config->id = mId;
+ config->role = AUDIO_PORT_ROLE_SOURCE;
+ config->type = AUDIO_PORT_TYPE_MIX;
+ config->sample_rate = mSamplingRate;
+ config->channel_mask = mChannelMask;
+ config->format = mFormat;
+ config->gain.index = -1;
+ config->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
+ AUDIO_PORT_CONFIG_FORMAT;
+ config->ext.mix.hw_module = mProfile->mModule->mHandle;
+ config->ext.mix.handle = mIoHandle;
+ config->ext.mix.usecase.stream = AUDIO_STREAM_DEFAULT;
+}
+
+void AudioPolicyManager::AudioOutputDescriptor::toAudioPort(
+ struct audio_port *port) const
+{
+ mProfile->toAudioPort(port);
+ port->id = mId;
+ port->ext.mix.handle = mIoHandle;
+ port->ext.mix.latency_class =
+ mFlags & AUDIO_OUTPUT_FLAG_FAST ? AUDIO_LATENCY_LOW : AUDIO_LATENCY_NORMAL;
+}
status_t AudioPolicyManager::AudioOutputDescriptor::dump(int fd)
{
@@ -3803,9 +3900,10 @@
// --- AudioInputDescriptor class implementation
-AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const IOProfile *profile)
- : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0),
- mDevice(AUDIO_DEVICE_NONE), mRefCount(0),
+AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile)
+ : mId(0), mIoHandle(0), mSamplingRate(0),
+ mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0),
+ mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0), mRefCount(0),
mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile)
{
if (profile != NULL) {
@@ -3815,6 +3913,33 @@
}
}
+void AudioPolicyManager::AudioInputDescriptor::toAudioPortConfig(
+ struct audio_port_config *config) const
+{
+ config->id = mId;
+ config->role = AUDIO_PORT_ROLE_SINK;
+ config->type = AUDIO_PORT_TYPE_MIX;
+ config->sample_rate = mSamplingRate;
+ config->channel_mask = mChannelMask;
+ config->format = mFormat;
+ config->gain.index = -1;
+ config->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
+ AUDIO_PORT_CONFIG_FORMAT;
+ config->ext.mix.hw_module = mProfile->mModule->mHandle;
+ config->ext.mix.handle = mIoHandle;
+ config->ext.mix.usecase.source = (mInputSource == AUDIO_SOURCE_HOTWORD) ?
+ AUDIO_SOURCE_VOICE_RECOGNITION : mInputSource;
+}
+
+void AudioPolicyManager::AudioInputDescriptor::toAudioPort(
+ struct audio_port *port) const
+{
+ mProfile->toAudioPort(port);
+ port->id = mId;
+ port->ext.mix.handle = mIoHandle;
+ port->ext.mix.latency_class = AUDIO_LATENCY_NORMAL;
+}
+
status_t AudioPolicyManager::AudioInputDescriptor::dump(int fd)
{
const size_t SIZE = 256;
@@ -3897,7 +4022,7 @@
return NO_ERROR;
}
-// --- IOProfile class implementation
+// --- HwModule class implementation
AudioPolicyManager::HwModule::HwModule(const char *name)
: mName(strndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN)), mHandle(0)
@@ -3908,11 +4033,9 @@
{
for (size_t i = 0; i < mOutputProfiles.size(); i++) {
mOutputProfiles[i]->mSupportedDevices.clear();
- delete mOutputProfiles[i];
}
for (size_t i = 0; i < mInputProfiles.size(); i++) {
mInputProfiles[i]->mSupportedDevices.clear();
- delete mInputProfiles[i];
}
free((void *)mName);
}
@@ -3946,8 +4069,129 @@
}
}
-AudioPolicyManager::IOProfile::IOProfile(HwModule *module)
- : mFlags((audio_output_flags_t)0), mModule(module)
+// --- AudioPort class implementation
+
+void AudioPolicyManager::AudioPort::toAudioPort(struct audio_port *port) const
+{
+ port->role = mRole;
+ port->type = mType;
+ unsigned int i;
+ for (i = 0; i < mSamplingRates.size() && i < AUDIO_PORT_MAX_SAMPLING_RATES; i++) {
+ port->sample_rates[i] = mSamplingRates[i];
+ }
+ port->num_sample_rates = i;
+ for (i = 0; i < mChannelMasks.size() && i < AUDIO_PORT_MAX_CHANNEL_MASKS; i++) {
+ port->channel_masks[i] = mChannelMasks[i];
+ }
+ port->num_channel_masks = i;
+ for (i = 0; i < mFormats.size() && i < AUDIO_PORT_MAX_FORMATS; i++) {
+ port->formats[i] = mFormats[i];
+ }
+ port->num_formats = i;
+ port->num_gains = 0;
+}
+
+
+void AudioPolicyManager::AudioPort::loadSamplingRates(char *name)
+{
+ char *str = strtok(name, "|");
+
+ // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
+ // rates should be read from the output stream after it is opened for the first time
+ if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+ mSamplingRates.add(0);
+ return;
+ }
+
+ while (str != NULL) {
+ uint32_t rate = atoi(str);
+ if (rate != 0) {
+ ALOGV("loadSamplingRates() adding rate %d", rate);
+ mSamplingRates.add(rate);
+ }
+ str = strtok(NULL, "|");
+ }
+ return;
+}
+
+void AudioPolicyManager::AudioPort::loadFormats(char *name)
+{
+ char *str = strtok(name, "|");
+
+ // by convention, "0' in the first entry in mFormats indicates the supported formats
+ // should be read from the output stream after it is opened for the first time
+ if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+ mFormats.add(AUDIO_FORMAT_DEFAULT);
+ return;
+ }
+
+ while (str != NULL) {
+ audio_format_t format = (audio_format_t)stringToEnum(sFormatNameToEnumTable,
+ ARRAY_SIZE(sFormatNameToEnumTable),
+ str);
+ if (format != AUDIO_FORMAT_DEFAULT) {
+ mFormats.add(format);
+ }
+ str = strtok(NULL, "|");
+ }
+ return;
+}
+
+void AudioPolicyManager::AudioPort::loadInChannels(char *name)
+{
+ const char *str = strtok(name, "|");
+
+ ALOGV("loadInChannels() %s", name);
+
+ if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+ mChannelMasks.add(0);
+ return;
+ }
+
+ while (str != NULL) {
+ audio_channel_mask_t channelMask =
+ (audio_channel_mask_t)stringToEnum(sInChannelsNameToEnumTable,
+ ARRAY_SIZE(sInChannelsNameToEnumTable),
+ str);
+ if (channelMask != 0) {
+ ALOGV("loadInChannels() adding channelMask %04x", channelMask);
+ mChannelMasks.add(channelMask);
+ }
+ str = strtok(NULL, "|");
+ }
+ return;
+}
+
+void AudioPolicyManager::AudioPort::loadOutChannels(char *name)
+{
+ const char *str = strtok(name, "|");
+
+ ALOGV("loadOutChannels() %s", name);
+
+ // 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) {
+ mChannelMasks.add(0);
+ return;
+ }
+
+ while (str != NULL) {
+ audio_channel_mask_t channelMask =
+ (audio_channel_mask_t)stringToEnum(sOutChannelsNameToEnumTable,
+ ARRAY_SIZE(sOutChannelsNameToEnumTable),
+ str);
+ if (channelMask != 0) {
+ mChannelMasks.add(channelMask);
+ }
+ str = strtok(NULL, "|");
+ }
+ return;
+}
+
+// --- IOProfile class implementation
+
+AudioPolicyManager::IOProfile::IOProfile(audio_port_role_t role, HwModule *module)
+ : AudioPort(AUDIO_PORT_TYPE_MIX, role, module), mFlags((audio_output_flags_t)0)
{
}
@@ -4083,7 +4327,7 @@
// - are of the same type (a device type cannot be AUDIO_DEVICE_NONE)
// - have the same address or one device does not specify the address
// - have the same channel mask or one device does not specify the channel mask
- return (mType == other->mType) &&
+ return (mDeviceType == other->mDeviceType) &&
(mAddress == "" || other->mAddress == "" || mAddress == other->mAddress) &&
(mChannelMask == 0 || other->mChannelMask == 0 ||
mChannelMask == other->mChannelMask);
@@ -4091,11 +4335,11 @@
void AudioPolicyManager::DeviceVector::refreshTypes()
{
- mTypes = AUDIO_DEVICE_NONE;
+ mDeviceTypes = AUDIO_DEVICE_NONE;
for(size_t i = 0; i < size(); i++) {
- mTypes |= itemAt(i)->mType;
+ mDeviceTypes |= itemAt(i)->mDeviceType;
}
- ALOGV("DeviceVector::refreshTypes() mTypes %08x", mTypes);
+ ALOGV("DeviceVector::refreshTypes() mDeviceTypes %08x", mDeviceTypes);
}
ssize_t AudioPolicyManager::DeviceVector::indexOf(const sp<DeviceDescriptor>& item) const
@@ -4118,7 +4362,7 @@
refreshTypes();
}
} else {
- ALOGW("DeviceVector::add device %08x already in", item->mType);
+ ALOGW("DeviceVector::add device %08x already in", item->mDeviceType);
ret = -1;
}
return ret;
@@ -4130,7 +4374,7 @@
ssize_t ret = indexOf(item);
if (ret < 0) {
- ALOGW("DeviceVector::remove device %08x not in", item->mType);
+ ALOGW("DeviceVector::remove device %08x not in", item->mDeviceType);
} else {
ret = SortedVector::removeAt(ret);
if (ret >= 0) {
@@ -4155,6 +4399,61 @@
}
}
+sp<AudioPolicyManager::DeviceDescriptor> AudioPolicyManager::DeviceVector::getDevice(
+ audio_devices_t type, String8 address) const
+{
+ sp<DeviceDescriptor> device;
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->mDeviceType == type) {
+ device = itemAt(i);
+ if (itemAt(i)->mAddress = address) {
+ break;
+ }
+ }
+ }
+ ALOGV("DeviceVector::getDevice() for type %d address %s found %p",
+ type, address.string(), device.get());
+ return device;
+}
+
+AudioPolicyManager::DeviceVector AudioPolicyManager::DeviceVector::getDevicesFromType(
+ audio_devices_t type) const
+{
+ DeviceVector devices;
+ for (size_t i = 0; (i < size()) && (type != AUDIO_DEVICE_NONE); i++) {
+ if (itemAt(i)->mDeviceType & type & ~AUDIO_DEVICE_BIT_IN) {
+ devices.add(itemAt(i));
+ type &= ~itemAt(i)->mDeviceType;
+ ALOGV("DeviceVector::getDevicesFromType() for type %x found %p",
+ itemAt(i)->mDeviceType, itemAt(i).get());
+ }
+ }
+ return devices;
+}
+
+void AudioPolicyManager::DeviceDescriptor::toAudioPortConfig(struct audio_port_config *config) const
+{
+ config->id = mId;
+ config->role = audio_is_output_device(mDeviceType) ?
+ AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
+ config->type = AUDIO_PORT_TYPE_DEVICE;
+ config->sample_rate = 0;
+ config->channel_mask = mChannelMask;
+ config->format = AUDIO_FORMAT_DEFAULT;
+ config->config_mask = AUDIO_PORT_CONFIG_CHANNEL_MASK;
+ config->gain.index = -1;
+ config->ext.device.type = mDeviceType;
+ strncpy(config->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN);
+}
+
+void AudioPolicyManager::DeviceDescriptor::toAudioPort(struct audio_port *port) const
+{
+ AudioPort::toAudioPort(port);
+ port->id = mId;
+ port->ext.device.type = mDeviceType;
+ strncpy(port->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN);
+}
+
void AudioPolicyManager::DeviceDescriptor::dumpHeader(int fd, int spaces)
{
const size_t SIZE = 256;
@@ -4174,7 +4473,7 @@
spaces, "",
enumToString(sDeviceNameToEnumTable,
ARRAY_SIZE(sDeviceNameToEnumTable),
- mType),
+ mDeviceType),
mId, mChannelMask, mAddress.string());
write(fd, buffer, strlen(buffer));
@@ -4225,115 +4524,19 @@
return device;
}
-void AudioPolicyManager::loadSamplingRates(char *name, IOProfile *profile)
-{
- char *str = strtok(name, "|");
-
- // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
- // rates 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->mSamplingRates.add(0);
- return;
- }
-
- while (str != NULL) {
- uint32_t rate = atoi(str);
- if (rate != 0) {
- ALOGV("loadSamplingRates() adding rate %d", rate);
- profile->mSamplingRates.add(rate);
- }
- str = strtok(NULL, "|");
- }
- return;
-}
-
-void AudioPolicyManager::loadFormats(char *name, IOProfile *profile)
-{
- char *str = strtok(name, "|");
-
- // by convention, "0' in the first entry in mFormats indicates the supported formats
- // 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->mFormats.add(AUDIO_FORMAT_DEFAULT);
- return;
- }
-
- while (str != NULL) {
- audio_format_t format = (audio_format_t)stringToEnum(sFormatNameToEnumTable,
- ARRAY_SIZE(sFormatNameToEnumTable),
- str);
- if (format != AUDIO_FORMAT_DEFAULT) {
- profile->mFormats.add(format);
- }
- str = strtok(NULL, "|");
- }
- return;
-}
-
-void AudioPolicyManager::loadInChannels(char *name, IOProfile *profile)
-{
- const char *str = strtok(name, "|");
-
- ALOGV("loadInChannels() %s", name);
-
- if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
- profile->mChannelMasks.add(0);
- return;
- }
-
- while (str != NULL) {
- audio_channel_mask_t channelMask =
- (audio_channel_mask_t)stringToEnum(sInChannelsNameToEnumTable,
- ARRAY_SIZE(sInChannelsNameToEnumTable),
- str);
- if (channelMask != 0) {
- ALOGV("loadInChannels() adding channelMask %04x", channelMask);
- profile->mChannelMasks.add(channelMask);
- }
- str = strtok(NULL, "|");
- }
- return;
-}
-
-void AudioPolicyManager::loadOutChannels(char *name, IOProfile *profile)
-{
- const char *str = strtok(name, "|");
-
- ALOGV("loadOutChannels() %s", name);
-
- // 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(0);
- return;
- }
-
- while (str != NULL) {
- audio_channel_mask_t channelMask =
- (audio_channel_mask_t)stringToEnum(sOutChannelsNameToEnumTable,
- ARRAY_SIZE(sOutChannelsNameToEnumTable),
- str);
- if (channelMask != 0) {
- profile->mChannelMasks.add(channelMask);
- }
- str = strtok(NULL, "|");
- }
- return;
-}
-
status_t AudioPolicyManager::loadInput(cnode *root, HwModule *module)
{
cnode *node = root->first_child;
- IOProfile *profile = new IOProfile(module);
+ sp<IOProfile> profile = new IOProfile(AUDIO_PORT_ROLE_SINK, module);
while (node) {
if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
- loadSamplingRates((char *)node->value, profile);
+ profile->loadSamplingRates((char *)node->value);
} else if (strcmp(node->name, FORMATS_TAG) == 0) {
- loadFormats((char *)node->value, profile);
+ profile->loadFormats((char *)node->value);
} else if (strcmp(node->name, CHANNELS_TAG) == 0) {
- loadInChannels((char *)node->value, profile);
+ profile->loadInChannels((char *)node->value);
} else if (strcmp(node->name, DEVICES_TAG) == 0) {
profile->mSupportedDevices.loadDevicesFromType(parseDeviceNames((char *)node->value));
}
@@ -4358,7 +4561,6 @@
module->mInputProfiles.add(profile);
return NO_ERROR;
} else {
- delete profile;
return BAD_VALUE;
}
}
@@ -4367,15 +4569,15 @@
{
cnode *node = root->first_child;
- IOProfile *profile = new IOProfile(module);
+ sp<IOProfile> profile = new IOProfile(AUDIO_PORT_ROLE_SOURCE, module);
while (node) {
if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
- loadSamplingRates((char *)node->value, profile);
+ profile->loadSamplingRates((char *)node->value);
} else if (strcmp(node->name, FORMATS_TAG) == 0) {
- loadFormats((char *)node->value, profile);
+ profile->loadFormats((char *)node->value);
} else if (strcmp(node->name, CHANNELS_TAG) == 0) {
- loadOutChannels((char *)node->value, profile);
+ profile->loadOutChannels((char *)node->value);
} else if (strcmp(node->name, DEVICES_TAG) == 0) {
profile->mSupportedDevices.loadDevicesFromType(parseDeviceNames((char *)node->value));
} else if (strcmp(node->name, FLAGS_TAG) == 0) {
@@ -4402,7 +4604,6 @@
module->mOutputProfiles.add(profile);
return NO_ERROR;
} else {
- delete profile;
return BAD_VALUE;
}
}
@@ -4480,7 +4681,7 @@
} else {
ALOGW("loadGlobalConfig() default device not specified");
}
- ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", mDefaultOutputDevice->mType);
+ ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", mDefaultOutputDevice->mDeviceType);
} else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
mAvailableInputDevices.loadDevicesFromType(parseDeviceNames((char *)node->value));
ALOGV("loadGlobalConfig() Available InputDevices %08x", mAvailableInputDevices.types());
@@ -4519,14 +4720,14 @@
void AudioPolicyManager::defaultAudioPolicyConfig(void)
{
HwModule *module;
- IOProfile *profile;
+ sp<IOProfile> profile;
sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
mAvailableOutputDevices.add(mDefaultOutputDevice);
mAvailableInputDevices.add(defaultInputDevice);
module = new HwModule("primary");
- profile = new IOProfile(module);
+ profile = new IOProfile(AUDIO_PORT_ROLE_SOURCE, module);
profile->mSamplingRates.add(44100);
profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
profile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO);
@@ -4534,7 +4735,7 @@
profile->mFlags = AUDIO_OUTPUT_FLAG_PRIMARY;
module->mOutputProfiles.add(profile);
- profile = new IOProfile(module);
+ profile = new IOProfile(AUDIO_PORT_ROLE_SINK, module);
profile->mSamplingRates.add(8000);
profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
profile->mChannelMasks.add(AUDIO_CHANNEL_IN_MONO);
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
index f00fa8a..905a3c8 100644
--- a/services/audiopolicy/AudioPolicyManager.h
+++ b/services/audiopolicy/AudioPolicyManager.h
@@ -175,47 +175,6 @@
class IOProfile;
- class DeviceDescriptor: public RefBase
- {
- public:
- DeviceDescriptor(audio_devices_t type, String8 address,
- audio_channel_mask_t channelMask) :
- mType(type), mAddress(address),
- mChannelMask(channelMask), mId(0) {}
-
- DeviceDescriptor(audio_devices_t type) :
- mType(type), mAddress(""),
- mChannelMask(0), mId(0) {}
-
- status_t dump(int fd, int spaces) const;
- static void dumpHeader(int fd, int spaces);
-
- bool equals(const sp<DeviceDescriptor>& other) const;
-
- audio_devices_t mType;
- String8 mAddress;
- audio_channel_mask_t mChannelMask;
- uint32_t mId;
- };
-
- class DeviceVector : public SortedVector< sp<DeviceDescriptor> >
- {
- public:
- DeviceVector() : SortedVector(), mTypes(AUDIO_DEVICE_NONE) {}
-
- ssize_t add(const sp<DeviceDescriptor>& item);
- ssize_t remove(const sp<DeviceDescriptor>& item);
- ssize_t indexOf(const sp<DeviceDescriptor>& item) const;
-
- audio_devices_t types() const { return mTypes; }
-
- void loadDevicesFromType(audio_devices_t types);
-
- private:
- void refreshTypes();
- audio_devices_t mTypes;
- };
-
class HwModule {
public:
HwModule(const char *name);
@@ -225,8 +184,88 @@
const char *const mName; // base name of the audio HW module (primary, a2dp ...)
audio_module_handle_t mHandle;
- Vector <IOProfile *> mOutputProfiles; // output profiles exposed by this module
- Vector <IOProfile *> mInputProfiles; // input profiles exposed by this module
+ Vector < sp<IOProfile> > mOutputProfiles; // output profiles exposed by this module
+ Vector < sp<IOProfile> > mInputProfiles; // input profiles exposed by this module
+ };
+
+ class AudioPort: public RefBase
+ {
+ public:
+ AudioPort(audio_port_type_t type, audio_port_role_t role, HwModule *module) :
+ mType(type), mRole(role), mModule(module) {}
+ virtual ~AudioPort() {}
+
+ virtual void toAudioPort(struct audio_port *port) const;
+
+ void loadSamplingRates(char *name);
+ void loadFormats(char *name);
+ void loadOutChannels(char *name);
+ void loadInChannels(char *name);
+
+ audio_port_type_t mType;
+ audio_port_role_t mRole;
+ // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
+ // indicates the supported parameters should be read from the output stream
+ // after it is opened for the first time
+ Vector <uint32_t> mSamplingRates; // supported sampling rates
+ Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks
+ Vector <audio_format_t> mFormats; // supported audio formats
+ HwModule *mModule; // audio HW module exposing this I/O stream
+ };
+
+
+ class DeviceDescriptor: public AudioPort
+ {
+ public:
+ DeviceDescriptor(audio_devices_t type, String8 address,
+ audio_channel_mask_t channelMask) :
+ AudioPort(AUDIO_PORT_TYPE_DEVICE,
+ audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
+ AUDIO_PORT_ROLE_SOURCE,
+ NULL),
+ mDeviceType(type), mAddress(address),
+ mChannelMask(channelMask), mId(0) {}
+
+ DeviceDescriptor(audio_devices_t type) :
+ AudioPort(AUDIO_PORT_TYPE_DEVICE,
+ audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
+ AUDIO_PORT_ROLE_SOURCE,
+ NULL),
+ mDeviceType(type), mAddress(""),
+ mChannelMask(0), mId(0) {}
+ virtual ~DeviceDescriptor() {}
+
+ bool equals(const sp<DeviceDescriptor>& other) const;
+ void toAudioPortConfig(struct audio_port_config *config) const;
+ virtual void toAudioPort(struct audio_port *port) const;
+
+ status_t dump(int fd, int spaces) const;
+ static void dumpHeader(int fd, int spaces);
+
+ audio_devices_t mDeviceType;
+ String8 mAddress;
+ audio_channel_mask_t mChannelMask;
+ audio_port_handle_t mId;
+ };
+
+ class DeviceVector : public SortedVector< sp<DeviceDescriptor> >
+ {
+ public:
+ DeviceVector() : SortedVector(), mDeviceTypes(AUDIO_DEVICE_NONE) {}
+
+ ssize_t add(const sp<DeviceDescriptor>& item);
+ ssize_t remove(const sp<DeviceDescriptor>& item);
+ ssize_t indexOf(const sp<DeviceDescriptor>& item) const;
+
+ audio_devices_t types() const { return mDeviceTypes; }
+
+ void loadDevicesFromType(audio_devices_t types);
+ sp<DeviceDescriptor> getDevice(audio_devices_t type, String8 address) const;
+ DeviceVector getDevicesFromType(audio_devices_t types) const;
+
+ private:
+ void refreshTypes();
+ audio_devices_t mDeviceTypes;
};
// the IOProfile class describes the capabilities of an output or input stream.
@@ -234,11 +273,11 @@
// It is used by the policy manager to determine if an output or input is suitable for
// a given use case, open/close it accordingly and connect/disconnect audio tracks
// to/from it.
- class IOProfile
+ class IOProfile : public AudioPort
{
public:
- IOProfile(HwModule *module);
- ~IOProfile();
+ IOProfile(audio_port_role_t role, HwModule *module);
+ virtual ~IOProfile();
bool isCompatibleProfile(audio_devices_t device,
uint32_t samplingRate,
@@ -249,17 +288,10 @@
void dump(int fd);
void log();
- // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
- // indicates the supported parameters should be read from the output stream
- // after it is opened for the first time
- Vector <uint32_t> mSamplingRates; // supported sampling rates
- Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks
- Vector <audio_format_t> mFormats; // supported audio formats
DeviceVector mSupportedDevices; // supported devices
// (devices this output can be routed to)
audio_output_flags_t mFlags; // attribute flags (e.g primary output,
// direct output...). For outputs only.
- HwModule *mModule; // audio HW module exposing this I/O stream
};
// default volume curve
@@ -284,7 +316,7 @@
class AudioOutputDescriptor
{
public:
- AudioOutputDescriptor(const IOProfile *profile);
+ AudioOutputDescriptor(const sp<IOProfile>& profile);
status_t dump(int fd);
@@ -303,20 +335,25 @@
uint32_t inPastMs = 0,
nsecs_t sysTime = 0) const;
- audio_io_handle_t mId; // output handle
+ void toAudioPortConfig(struct audio_port_config *config) const;
+ void toAudioPort(struct audio_port *port) const;
+
+ audio_port_handle_t mId;
+ audio_io_handle_t mIoHandle; // output handle
uint32_t mSamplingRate; //
audio_format_t mFormat; //
audio_channel_mask_t mChannelMask; // output configuration
uint32_t mLatency; //
audio_output_flags_t mFlags; //
audio_devices_t mDevice; // current device this output is routed to
+ audio_patch_handle_t mPatchHandle;
uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output
nsecs_t mStopTime[AUDIO_STREAM_CNT];
AudioOutputDescriptor *mOutput1; // used by duplicated outputs: first output
AudioOutputDescriptor *mOutput2; // used by duplicated outputs: second output
float mCurVolume[AUDIO_STREAM_CNT]; // current stream volume
int mMuteCount[AUDIO_STREAM_CNT]; // mute request counter
- const IOProfile *mProfile; // I/O profile this output derives from
+ const sp<IOProfile> mProfile; // I/O profile this output derives from
bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible
// device selection. See checkDeviceMuteStrategies()
uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only)
@@ -327,18 +364,23 @@
class AudioInputDescriptor
{
public:
- AudioInputDescriptor(const IOProfile *profile);
+ AudioInputDescriptor(const sp<IOProfile>& profile);
status_t dump(int fd);
- audio_io_handle_t mId; // input handle
+ audio_port_handle_t mId;
+ audio_io_handle_t mIoHandle; // input handle
uint32_t mSamplingRate; //
audio_format_t mFormat; // input configuration
audio_channel_mask_t mChannelMask; //
audio_devices_t mDevice; // current device this input is routed to
+ audio_patch_handle_t mPatchHandle;
uint32_t mRefCount; // number of AudioRecord clients using this output
audio_source_t mInputSource; // input source selected by application (mediarecorder.h)
- const IOProfile *mProfile; // I/O profile this output derives from
+ const sp<IOProfile> mProfile; // I/O profile this output derives from
+
+ void toAudioPortConfig(struct audio_port_config *config) const;
+ void toAudioPort(struct audio_port *port) const;
};
// stream descriptor used for volume control
@@ -372,8 +414,8 @@
bool mEnabled; // enabled state: CPU load being used or not
};
- void addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc);
- void addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc);
+ void addOutput(audio_io_handle_t output, AudioOutputDescriptor *outputDesc);
+ void addInput(audio_io_handle_t input, AudioInputDescriptor *inputDesc);
// return the strategy corresponding to a given stream type
static routing_strategy getStrategy(audio_stream_type_t stream);
@@ -398,6 +440,12 @@
audio_devices_t device,
bool force = false,
int delayMs = 0);
+ status_t resetOutputDevice(audio_io_handle_t output,
+ int delayMs = 0);
+ status_t setInputDevice(audio_io_handle_t input,
+ audio_devices_t device,
+ bool force = false);
+ status_t resetInputDevice(audio_io_handle_t input);
// select input device corresponding to requested audio source
virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource);
@@ -484,16 +532,18 @@
// must be called every time a condition that affects the device choice for a given output is
// changed: connected device, phone state, force use, output start, output stop..
// see getDeviceForStrategy() for the use of fromCache parameter
+ audio_devices_t getNewOutputDevice(audio_io_handle_t output, bool fromCache);
- audio_devices_t getNewDevice(audio_io_handle_t output, bool fromCache);
// updates cache of device used by all strategies (mDeviceForStrategy[])
// must be called every time a condition that affects the device choice for a given strategy is
// changed: connected device, phone state, force use...
// cached values are used by getDeviceForStrategy() if parameter fromCache is true.
// Must be called after checkOutputForAllStrategies()
-
void updateDevicesAndOutputs();
+ // selects the most appropriate device on input for current state
+ audio_devices_t getNewInputDevice(audio_io_handle_t input);
+
virtual uint32_t getMaxEffectsCpuLoad();
virtual uint32_t getMaxEffectsMemory();
#ifdef AUDIO_POLICY_TEST
@@ -525,11 +575,11 @@
audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& outputs,
audio_output_flags_t flags);
- IOProfile *getInputProfile(audio_devices_t device,
+ sp<IOProfile> getInputProfile(audio_devices_t device,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask);
- IOProfile *getProfileForDirectOutput(audio_devices_t device,
+ sp<IOProfile> getProfileForDirectOutput(audio_devices_t device,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
@@ -551,10 +601,6 @@
static bool stringToBool(const char *value);
static audio_output_flags_t parseFlagNames(char *name);
static audio_devices_t parseDeviceNames(char *name);
- void loadSamplingRates(char *name, IOProfile *profile);
- void loadFormats(char *name, IOProfile *profile);
- void loadOutChannels(char *name, IOProfile *profile);
- void loadInChannels(char *name, IOProfile *profile);
status_t loadOutput(cnode *root, HwModule *module);
status_t loadInput(cnode *root, HwModule *module);
void loadHwModule(cnode *root);
diff --git a/services/audiopolicy/AudioPolicyService.cpp b/services/audiopolicy/AudioPolicyService.cpp
index 4e9a2f0..ea573a4 100644
--- a/services/audiopolicy/AudioPolicyService.cpp
+++ b/services/audiopolicy/AudioPolicyService.cpp
@@ -150,6 +150,19 @@
#endif
}
+status_t AudioPolicyService::clientCreateAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs)
+{
+ return mAudioCommandThread->createAudioPatchCommand(patch, handle, delayMs);
+}
+
+status_t AudioPolicyService::clientReleaseAudioPatch(audio_patch_handle_t handle,
+ int delayMs)
+{
+ return mAudioCommandThread->releaseAudioPatchCommand(handle, delayMs);
+}
+
void AudioPolicyService::binderDied(const wp<IBinder>& who) {
ALOGW("binderDied() %p, calling pid %d", who.unsafe_get(),
@@ -357,6 +370,26 @@
svc->doReleaseOutput(data->mIO);
mLock.lock();
}break;
+ case CREATE_AUDIO_PATCH: {
+ CreateAudioPatchData *data = (CreateAudioPatchData *)command->mParam.get();
+ ALOGV("AudioCommandThread() processing create audio patch");
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ command->mStatus = PERMISSION_DENIED;
+ } else {
+ command->mStatus = af->createAudioPatch(&data->mPatch, &data->mHandle);
+ }
+ } break;
+ case RELEASE_AUDIO_PATCH: {
+ ReleaseAudioPatchData *data = (ReleaseAudioPatchData *)command->mParam.get();
+ ALOGV("AudioCommandThread() processing release audio patch");
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ command->mStatus = PERMISSION_DENIED;
+ } else {
+ command->mStatus = af->releaseAudioPatch(data->mHandle);
+ }
+ } break;
default:
ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
}
@@ -516,6 +549,41 @@
sendCommand(command);
}
+status_t AudioPolicyService::AudioCommandThread::createAudioPatchCommand(
+ const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs)
+{
+ status_t status = NO_ERROR;
+
+ sp<AudioCommand> command = new AudioCommand();
+ command->mCommand = CREATE_AUDIO_PATCH;
+ CreateAudioPatchData *data = new CreateAudioPatchData();
+ data->mPatch = *patch;
+ data->mHandle = *handle;
+ command->mParam = data;
+ command->mWaitStatus = true;
+ ALOGV("AudioCommandThread() adding create patch delay %d", delayMs);
+ status = sendCommand(command, delayMs);
+ if (status == NO_ERROR) {
+ *handle = data->mHandle;
+ }
+ return status;
+}
+
+status_t AudioPolicyService::AudioCommandThread::releaseAudioPatchCommand(audio_patch_handle_t handle,
+ int delayMs)
+{
+ sp<AudioCommand> command = new AudioCommand();
+ command->mCommand = RELEASE_AUDIO_PATCH;
+ ReleaseAudioPatchData *data = new ReleaseAudioPatchData();
+ data->mHandle = handle;
+ command->mParam = data;
+ command->mWaitStatus = true;
+ ALOGV("AudioCommandThread() adding release patch delay %d", delayMs);
+ return sendCommand(command, delayMs);
+}
+
status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
{
{
@@ -534,6 +602,7 @@
return command->mStatus;
}
+
// insertCommand_l() must be called with mLock held
void AudioPolicyService::AudioCommandThread::insertCommand_l(sp<AudioCommand>& command, int delayMs)
{
diff --git a/services/audiopolicy/AudioPolicyService.h b/services/audiopolicy/AudioPolicyService.h
index 26037e4..a7ed9e8 100644
--- a/services/audiopolicy/AudioPolicyService.h
+++ b/services/audiopolicy/AudioPolicyService.h
@@ -145,6 +145,12 @@
int session = 0);
void doReleaseOutput(audio_io_handle_t output);
+ status_t clientCreateAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs);
+ status_t clientReleaseAudioPatch(audio_patch_handle_t handle,
+ int delayMs);
+
private:
AudioPolicyService() ANDROID_API;
virtual ~AudioPolicyService();
@@ -169,7 +175,9 @@
SET_PARAMETERS,
SET_VOICE_VOLUME,
STOP_OUTPUT,
- RELEASE_OUTPUT
+ RELEASE_OUTPUT,
+ CREATE_AUDIO_PATCH,
+ RELEASE_AUDIO_PATCH,
};
AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -196,6 +204,13 @@
void releaseOutputCommand(audio_io_handle_t output);
status_t sendCommand(sp<AudioCommand>& command, int delayMs = 0);
void insertCommand_l(sp<AudioCommand>& command, int delayMs = 0);
+ status_t createAudioPatchCommand(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs);
+ status_t releaseAudioPatchCommand(audio_patch_handle_t handle,
+ int delayMs);
+
+ void insertCommand_l(AudioCommand *command, int delayMs = 0);
private:
class AudioCommandData;
@@ -261,6 +276,17 @@
audio_io_handle_t mIO;
};
+ class CreateAudioPatchData : public AudioCommandData {
+ public:
+ struct audio_patch mPatch;
+ audio_patch_handle_t mHandle;
+ };
+
+ class ReleaseAudioPatchData : public AudioCommandData {
+ public:
+ audio_patch_handle_t mHandle;
+ };
+
Mutex mLock;
Condition mWaitWorkCV;
Vector < sp<AudioCommand> > mAudioCommands; // list of pending commands
@@ -405,6 +431,15 @@
audio_io_handle_t srcOutput,
audio_io_handle_t dstOutput);
+ /* Create a patch between several source and sink ports */
+ virtual status_t createAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs);
+
+ /* Release a patch */
+ virtual status_t releaseAudioPatch(audio_patch_handle_t handle,
+ int delayMs);
+
private:
AudioPolicyService *mAudioPolicyService;
};