// active output devices in isStreamActiveRemotely()
#define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+#include <inttypes.h>
+#include <math.h>
+
+#include <cutils/properties.h>
#include <utils/Log.h>
-#include <hardware_legacy/AudioPolicyManagerBase.h>
-#include <hardware/audio_effect.h>
+
#include <hardware/audio.h>
-#include <math.h>
+#include <hardware/audio_effect.h>
#include <hardware_legacy/audio_policy_conf.h>
-#include <cutils/properties.h>
+#include <hardware_legacy/AudioPolicyManagerBase.h>
namespace android_audio_legacy {
AudioSystem::device_connection_state state,
const char *device_address)
{
- SortedVector <audio_io_handle_t> outputs;
-
- ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);
+ // device_address can be NULL and should be handled as an empty string in this case,
+ // and it is not checked by AudioPolicyInterfaceImpl.cpp
+ if (device_address == NULL) {
+ device_address = "";
+ }
+ ALOGV("setDeviceConnectionState() device: 0x%X, state %d, address %s", device, state, device_address);
// connect/disconnect only 1 device at a time
if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
// handle output devices
if (audio_is_output_device(device)) {
+ SortedVector <audio_io_handle_t> outputs;
- if (!mHasA2dp && audio_is_a2dp_device(device)) {
+ if (!mHasA2dp && audio_is_a2dp_out_device(device)) {
ALOGE("setDeviceConnectionState() invalid A2DP device: %x", device);
return BAD_VALUE;
}
- if (!mHasUsb && audio_is_usb_device(device)) {
+ if (!mHasUsb && audio_is_usb_out_device(device)) {
ALOGE("setDeviceConnectionState() invalid USB audio device: %x", device);
return BAD_VALUE;
}
}
ALOGV("setDeviceConnectionState() connecting device %x", device);
- if (mHasA2dp && audio_is_a2dp_device(device)) {
+ if (mHasA2dp && audio_is_a2dp_out_device(device)) {
// handle A2DP device connection
AudioParameter param;
param.add(String8(AUDIO_PARAMETER_A2DP_SINK_ADDRESS), String8(device_address));
paramStr = param.toString();
- } else if (mHasUsb && audio_is_usb_device(device)) {
+ } else if (mHasUsb && audio_is_usb_out_device(device)) {
// handle USB device connection
paramStr = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
}
if (checkOutputsForDevice(device, state, outputs, paramStr) != NO_ERROR) {
return INVALID_OPERATION;
}
- ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %d outputs",
+ ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs",
outputs.size());
// register new device as available
mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | device);
- if (mHasA2dp && audio_is_a2dp_device(device)) {
+ if (mHasA2dp && audio_is_a2dp_out_device(device)) {
// handle A2DP device connection
mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
mA2dpSuspended = false;
} else if (audio_is_bluetooth_sco_device(device)) {
// handle SCO device connection
mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
- } else if (mHasUsb && audio_is_usb_device(device)) {
+ } else if (mHasUsb && audio_is_usb_out_device(device)) {
// handle USB device connection
- mUsbCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ mUsbOutCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
}
break;
ALOGV("setDeviceConnectionState() disconnecting device %x", device);
// remove device from available output devices
mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device);
-
checkOutputsForDevice(device, state, outputs, paramStr);
- if (mHasA2dp && audio_is_a2dp_device(device)) {
+
+ if (mHasA2dp && audio_is_a2dp_out_device(device)) {
// handle A2DP device disconnection
mA2dpDeviceAddress = "";
mA2dpSuspended = false;
} else if (audio_is_bluetooth_sco_device(device)) {
// handle SCO device disconnection
mScoDeviceAddress = "";
- } else if (mHasUsb && audio_is_usb_device(device)) {
+ } else if (mHasUsb && audio_is_usb_out_device(device)) {
// handle USB device disconnection
- mUsbCardAndDevice = "";
+ mUsbOutCardAndDevice = "";
}
// not currently handling multiple simultaneous submixes: ignoring remote submix
// case and address
0);
}
- if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET) {
- device = AUDIO_DEVICE_IN_WIRED_HEADSET;
- } else if (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO ||
- device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
- device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
- device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
- } else {
- return NO_ERROR;
- }
- }
+ return NO_ERROR;
+ } // end if is output device
+
// handle input devices
if (audio_is_input_device(device)) {
+ SortedVector <audio_io_handle_t> inputs;
+ String8 paramStr;
switch (state)
{
// handle input device connection
ALOGW("setDeviceConnectionState() device already connected: %d", device);
return INVALID_OPERATION;
}
+
+ if (mHasUsb && audio_is_usb_in_device(device)) {
+ // handle USB device connection
+ paramStr = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ } else if (mHasA2dp && audio_is_a2dp_in_device(device)) {
+ // handle A2DP device connection
+ AudioParameter param;
+ param.add(String8(AUDIO_PARAMETER_A2DP_SOURCE_ADDRESS), String8(device_address));
+ paramStr = param.toString();
+ }
+
+ if (checkInputsForDevice(device, state, inputs, paramStr) != NO_ERROR) {
+ return INVALID_OPERATION;
+ }
mAvailableInputDevices = mAvailableInputDevices | (device & ~AUDIO_DEVICE_BIT_IN);
}
break;
ALOGW("setDeviceConnectionState() device not connected: %d", device);
return INVALID_OPERATION;
}
+ checkInputsForDevice(device, state, inputs, paramStr);
mAvailableInputDevices = (audio_devices_t) (mAvailableInputDevices & ~device);
- } break;
+ } break;
default:
ALOGE("setDeviceConnectionState() invalid state: %x", state);
return BAD_VALUE;
}
- 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("setDeviceConnectionState() 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());
- }
- }
+ closeAllInputs();
return NO_ERROR;
- }
+ } // end if is input device
ALOGW("setDeviceConnectionState() invalid device: %x", device);
return BAD_VALUE;
AudioSystem::device_connection_state AudioPolicyManagerBase::getDeviceConnectionState(audio_devices_t device,
const char *device_address)
{
+ // similar to setDeviceConnectionState
+ if (device_address == NULL) {
+ device_address = "";
+ }
AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE;
String8 address = String8(device_address);
if (audio_is_output_device(device)) {
if (device & mAvailableOutputDevices) {
- if (audio_is_a2dp_device(device) &&
+ if (audio_is_a2dp_out_device(device) &&
(!mHasA2dp || (address != "" && mA2dpDeviceAddress != address))) {
return state;
}
address != "" && mScoDeviceAddress != address) {
return state;
}
- if (audio_is_usb_device(device) &&
- (!mHasUsb || (address != "" && mUsbCardAndDevice != address))) {
+ if (audio_is_usb_out_device(device) &&
+ (!mHasUsb || (address != "" && mUsbOutCardAndDevice != address))) {
ALOGE("getDeviceConnectionState() invalid device: %x", device);
return state;
}
format,
channelMask);
if (profile == NULL) {
- ALOGW("getInput() could not find profile for device %04x, samplingRate %d, format %d, "
- "channelMask %04x",
+ ALOGW("getInput() could not find profile for device 0x%X, samplingRate %d, format %d, "
+ "channelMask 0x%X",
device, samplingRate, format, channelMask);
return 0;
}
inputDesc->mFormat = format;
inputDesc->mChannelMask = channelMask;
inputDesc->mRefCount = 0;
+
input = mpClientInterface->openInput(profile->mModule->mHandle,
&inputDesc->mDevice,
&inputDesc->mSamplingRate,
(samplingRate != inputDesc->mSamplingRate) ||
(format != inputDesc->mFormat) ||
(channelMask != inputDesc->mChannelMask)) {
- ALOGI("getInput() failed opening input: samplingRate %d, format %d, channelMask %x",
+ ALOGI("getInput() failed opening input: samplingRate %d, format %d, channelMask 0x%X",
samplingRate, format, channelMask);
if (input != 0) {
mpClientInterface->closeInput(input);
delete inputDesc;
return 0;
}
- mInputs.add(input, inputDesc);
+ addInput(input, inputDesc);
+
return input;
}
mpClientInterface->closeInput(input);
delete mInputs.valueAt(index);
mInputs.removeItem(input);
+
ALOGV("releaseInput() exit");
}
+void AudioPolicyManagerBase::closeAllInputs() {
+ for(size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+ mpClientInterface->closeInput(mInputs.keyAt(input_index));
+ }
+ mInputs.clear();
+}
+
void AudioPolicyManagerBase::initStreamVolume(AudioSystem::stream_type stream,
int indexMin,
int indexMax)
for (size_t i = 0; i < outputs.size(); i++) {
AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]);
- ALOGV("selectOutputForEffects outputs[%d] flags %x", i, desc->mFlags);
+ ALOGV("selectOutputForEffects outputs[%zu] flags %x", i, desc->mFlags);
if ((desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
outputOffloaded = outputs[i];
}
result.append(buffer);
snprintf(buffer, SIZE, " SCO device address: %s\n", mScoDeviceAddress.string());
result.append(buffer);
- snprintf(buffer, SIZE, " USB audio ALSA %s\n", mUsbCardAndDevice.string());
+ snprintf(buffer, SIZE, " USB audio ALSA %s\n", mUsbOutCardAndDevice.string());
result.append(buffer);
snprintf(buffer, SIZE, " Output devices: %08x\n", mAvailableOutputDevices);
result.append(buffer);
snprintf(buffer, SIZE, "\nHW Modules dump:\n");
write(fd, buffer, strlen(buffer));
for (size_t i = 0; i < mHwModules.size(); i++) {
- snprintf(buffer, SIZE, "- HW Module %d:\n", i + 1);
+ snprintf(buffer, SIZE, "- HW Module %zu:\n", i + 1);
write(fd, buffer, strlen(buffer));
mHwModules[i]->dump(fd);
}
" Stream Can be muted Index Min Index Max Index Cur [device : index]...\n");
write(fd, buffer, strlen(buffer));
for (size_t i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
- snprintf(buffer, SIZE, " %02d ", i);
+ snprintf(buffer, SIZE, " %02zu ", i);
write(fd, buffer, strlen(buffer));
mStreams[i].dump(fd);
}
bool AudioPolicyManagerBase::isOffloadSupported(const audio_offload_info_t& offloadInfo)
{
ALOGV("isOffloadSupported: SR=%u, CM=0x%x, Format=0x%x, StreamType=%d,"
- " BitRate=%u, duration=%lld us, has_video=%d",
+ " BitRate=%u, duration=%" PRId64 " us, has_video=%d",
offloadInfo.sample_rate, offloadInfo.channel_mask,
offloadInfo.format,
offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
mA2dpDeviceAddress = String8("");
mScoDeviceAddress = String8("");
- mUsbCardAndDevice = String8("");
+ mUsbOutCardAndDevice = String8("");
if (loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE) != NO_ERROR) {
if (loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE) != NO_ERROR) {
mOutputs.add(id, outputDesc);
}
+void AudioPolicyManagerBase::addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc)
+{
+ inputDesc->mId = id;
+ mInputs.add(id, inputDesc);
+}
status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device,
AudioSystem::device_connection_state state,
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
{
if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices & device) {
- ALOGV("checkOutputsForDevice(): adding profile %d from module %d", j, i);
+ ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i);
profiles.add(mHwModules[i]->mOutputProfiles[j]);
}
}
&offloadInfo);
if (output != 0) {
if (!paramStr.isEmpty()) {
+ // Here is where the out_set_parameters() for card & device gets called
mpClientInterface->setParameters(output, paramStr);
}
- if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
- String8 reply;
- char *value;
- if (profile->mSamplingRates[0] == 0) {
- reply = mpClientInterface->getParameters(output,
- String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
- ALOGV("checkOutputsForDevice() direct output sup sampling rates %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- loadSamplingRates(value + 1, profile);
- }
+ // Here is where we step through and resolve any "dynamic" fields
+ String8 reply;
+ char *value;
+ if (profile->mSamplingRates[0] == 0) {
+ reply = mpClientInterface->getParameters(output,
+ String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
+ ALOGV("checkOutputsForDevice() direct output sup sampling rates %s",
+ reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadSamplingRates(value + 1, profile);
}
- if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
- reply = mpClientInterface->getParameters(output,
- String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
- ALOGV("checkOutputsForDevice() direct output sup formats %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- loadFormats(value + 1, profile);
- }
- }
- if (profile->mChannelMasks[0] == 0) {
- reply = mpClientInterface->getParameters(output,
- String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
- ALOGV("checkOutputsForDevice() direct output sup channel masks %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- loadOutChannels(value + 1, profile);
- }
+ }
+ if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+ reply = mpClientInterface->getParameters(output,
+ String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+ ALOGV("checkOutputsForDevice() direct output sup formats %s",
+ reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadFormats(value + 1, profile);
}
- if (((profile->mSamplingRates[0] == 0) &&
- (profile->mSamplingRates.size() < 2)) ||
- ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) &&
- (profile->mFormats.size() < 2)) ||
- ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) &&
- (profile->mChannelMasks.size() < 2))) {
- ALOGW("checkOutputsForDevice() direct output missing param");
- mpClientInterface->closeOutput(output);
- output = 0;
- } else {
- addOutput(output, desc);
+ }
+ if (profile->mChannelMasks[0] == 0) {
+ reply = mpClientInterface->getParameters(output,
+ String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
+ ALOGV("checkOutputsForDevice() direct output sup channel masks %s",
+ reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadOutChannels(value + 1, profile);
}
- } else {
- audio_io_handle_t duplicatedOutput = 0;
- // add output descriptor
+ }
+ if (((profile->mSamplingRates[0] == 0) &&
+ (profile->mSamplingRates.size() < 2)) ||
+ ((profile->mFormats[0] == 0) &&
+ (profile->mFormats.size() < 2)) ||
+ ((profile->mChannelMasks[0] == 0) &&
+ (profile->mChannelMasks.size() < 2))) {
+ ALOGW("checkOutputsForDevice() direct output missing param");
+ mpClientInterface->closeOutput(output);
+ output = 0;
+ } else if (profile->mSamplingRates[0] == 0) {
+ mpClientInterface->closeOutput(output);
+ desc->mSamplingRate = profile->mSamplingRates[1];
+ offloadInfo.sample_rate = desc->mSamplingRate;
+ output = mpClientInterface->openOutput(
+ profile->mModule->mHandle,
+ &desc->mDevice,
+ &desc->mSamplingRate,
+ &desc->mFormat,
+ &desc->mChannelMask,
+ &desc->mLatency,
+ desc->mFlags,
+ &offloadInfo);
+ }
+
+ if (output != 0) {
addOutput(output, desc);
- // set initial stream volume for device
- applyStreamVolumes(output, device, 0, true);
-
- //TODO: configure audio effect output stage here
-
- // open a duplicating output thread for the new output and the primary output
- duplicatedOutput = mpClientInterface->openDuplicateOutput(output,
- mPrimaryOutput);
- if (duplicatedOutput != 0) {
- // add duplicated output descriptor
- AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(NULL);
- dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput);
- dupOutputDesc->mOutput2 = mOutputs.valueFor(output);
- dupOutputDesc->mSamplingRate = desc->mSamplingRate;
- dupOutputDesc->mFormat = desc->mFormat;
- dupOutputDesc->mChannelMask = desc->mChannelMask;
- dupOutputDesc->mLatency = desc->mLatency;
- addOutput(duplicatedOutput, dupOutputDesc);
- applyStreamVolumes(duplicatedOutput, device, 0, true);
- } else {
- ALOGW("checkOutputsForDevice() could not open dup output for %d and %d",
- mPrimaryOutput, output);
- mpClientInterface->closeOutput(output);
- mOutputs.removeItem(output);
- output = 0;
+ if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) {
+ audio_io_handle_t duplicatedOutput = 0;
+
+ // set initial stream volume for device
+ applyStreamVolumes(output, device, 0, true);
+
+ //TODO: configure audio effect output stage here
+
+ // open a duplicating output thread for the new output and the primary output
+ duplicatedOutput = mpClientInterface->openDuplicateOutput(output,
+ mPrimaryOutput);
+ if (duplicatedOutput != 0) {
+ // add duplicated output descriptor
+ AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(NULL);
+ dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput);
+ dupOutputDesc->mOutput2 = mOutputs.valueFor(output);
+ dupOutputDesc->mSamplingRate = desc->mSamplingRate;
+ dupOutputDesc->mFormat = desc->mFormat;
+ dupOutputDesc->mChannelMask = desc->mChannelMask;
+ dupOutputDesc->mLatency = desc->mLatency;
+ addOutput(duplicatedOutput, dupOutputDesc);
+ applyStreamVolumes(duplicatedOutput, device, 0, true);
+ } else {
+ ALOGW("checkOutputsForDevice() could not open dup output for %d and %d",
+ mPrimaryOutput, output);
+ mpClientInterface->closeOutput(output);
+ mOutputs.removeItem(output);
+ output = 0;
+ }
}
}
}
ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
return BAD_VALUE;
}
- } else {
+ } else { // Disconnect
// check if one opened output is not needed any more after disconnecting one device
for (size_t i = 0; i < mOutputs.size(); i++) {
desc = mOutputs.valueAt(i);
outputs.add(mOutputs.keyAt(i));
}
}
+ // Clear any profiles associated with the disconnected device.
for (size_t i = 0; i < mHwModules.size(); i++)
{
if (mHwModules[i]->mHandle == 0) {
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
{
IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
- if ((profile->mSupportedDevices & device) &&
- (profile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
- ALOGV("checkOutputsForDevice(): clearing direct output profile %d on module %d",
+ if (profile->mSupportedDevices & device) {
+ ALOGV("checkOutputsForDevice(): clearing direct output profile %zu on module %zu",
j, i);
if (profile->mSamplingRates[0] == 0) {
profile->mSamplingRates.clear();
return NO_ERROR;
}
+status_t AudioPolicyManagerBase::checkInputsForDevice(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ SortedVector<audio_io_handle_t>& inputs,
+ const String8 paramStr)
+{
+ AudioInputDescriptor *desc;
+ if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
+ // first list already open inputs that can be routed to this device
+ for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+ desc = mInputs.valueAt(input_index);
+ if (desc->mProfile->mSupportedDevices & (device & ~AUDIO_DEVICE_BIT_IN)) {
+ ALOGV("checkInputsForDevice(): adding opened input %d", mInputs.keyAt(input_index));
+ inputs.add(mInputs.keyAt(input_index));
+ }
+ }
+
+ // then look for input profiles that can be routed to this device
+ SortedVector<IOProfile *> profiles;
+ for (size_t module_index = 0; module_index < mHwModules.size(); module_index++)
+ {
+ if (mHwModules[module_index]->mHandle == 0) {
+ continue;
+ }
+ for (size_t profile_index = 0;
+ profile_index < mHwModules[module_index]->mInputProfiles.size();
+ profile_index++)
+ {
+ if (mHwModules[module_index]->mInputProfiles[profile_index]->mSupportedDevices
+ & (device & ~AUDIO_DEVICE_BIT_IN)) {
+ ALOGV("checkInputsForDevice(): adding profile %d from module %d",
+ profile_index, module_index);
+ profiles.add(mHwModules[module_index]->mInputProfiles[profile_index]);
+ }
+ }
+ }
+
+ if (profiles.isEmpty() && inputs.isEmpty()) {
+ ALOGW("checkInputsForDevice(): No input available for device 0x%X", device);
+ return BAD_VALUE;
+ }
+
+ // open inputs for matching profiles if needed. Direct inputs 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];
+ // 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++) {
+ desc = mInputs.valueAt(input_index);
+ if (desc->mProfile == profile) {
+ break;
+ }
+ }
+ if (input_index != mInputs.size()) {
+ continue;
+ }
+
+ ALOGV("opening input for device 0x%X with params %s", device, paramStr.string());
+ desc = new AudioInputDescriptor(profile);
+ desc->mDevice = device;
+
+ audio_io_handle_t input = mpClientInterface->openInput(profile->mModule->mHandle,
+ &desc->mDevice,
+ &desc->mSamplingRate,
+ &desc->mFormat,
+ &desc->mChannelMask);
+
+ if (input != 0) {
+ if (!paramStr.isEmpty()) {
+ mpClientInterface->setParameters(input, paramStr);
+ }
+
+ // Here is where we step through and resolve any "dynamic" fields
+ String8 reply;
+ char *value;
+ if (profile->mSamplingRates[0] == 0) {
+ reply = mpClientInterface->getParameters(input,
+ String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
+ ALOGV("checkInputsForDevice() direct input sup sampling rates %s",
+ reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadSamplingRates(value + 1, profile);
+ }
+ }
+ if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+ reply = mpClientInterface->getParameters(input,
+ String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+ ALOGV("checkInputsForDevice() direct input sup formats %s", reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadFormats(value + 1, profile);
+ }
+ }
+ if (profile->mChannelMasks[0] == 0) {
+ reply = mpClientInterface->getParameters(input,
+ String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
+ ALOGV("checkInputsForDevice() direct input sup channel masks %s",
+ reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadInChannels(value + 1, profile);
+ }
+ }
+ if (((profile->mSamplingRates[0] == 0) && (profile->mSamplingRates.size() < 2)) ||
+ ((profile->mFormats[0] == 0) && (profile->mFormats.size() < 2)) ||
+ ((profile->mChannelMasks[0] == 0) && (profile->mChannelMasks.size() < 2))) {
+ ALOGW("checkInputsForDevice() direct input missing param");
+ mpClientInterface->closeInput(input);
+ input = 0;
+ }
+
+ if (input != 0) {
+ addInput(input, desc);
+ }
+ } // endif input != 0
+
+ if (input == 0) {
+ ALOGW("checkInputsForDevice() could not open input for device 0x%X", device);
+ delete desc;
+ profiles.removeAt(profile_index);
+ profile_index--;
+ } else {
+ inputs.add(input);
+ ALOGV("checkInputsForDevice(): adding input %d", input);
+ }
+ } // end scan profiles
+
+ if (profiles.isEmpty()) {
+ ALOGW("checkInputsForDevice(): No input available for device 0x%X", device);
+ return BAD_VALUE;
+ }
+ } else {
+ // Disconnect
+ // check if one opened input is not needed any more after disconnecting one device
+ for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+ desc = mInputs.valueAt(input_index);
+ if (!(desc->mProfile->mSupportedDevices & mAvailableInputDevices)) {
+ ALOGV("checkInputsForDevice(): disconnecting adding input %d",
+ mInputs.keyAt(input_index));
+ inputs.add(mInputs.keyAt(input_index));
+ }
+ }
+ // Clear any profiles associated with the disconnected device.
+ for (size_t module_index = 0; module_index < mHwModules.size(); module_index++)
+ {
+ if (mHwModules[module_index]->mHandle == 0) {
+ continue;
+ }
+ for (size_t profile_index = 0;
+ profile_index < mHwModules[module_index]->mInputProfiles.size();
+ profile_index++)
+ {
+ IOProfile *profile = mHwModules[module_index]->mInputProfiles[profile_index];
+ if (profile->mSupportedDevices & device) {
+ ALOGV("checkInputsForDevice(): clearing direct input profile %d on module %d",
+ profile_index, module_index);
+ if (profile->mSamplingRates[0] == 0) {
+ profile->mSamplingRates.clear();
+ profile->mSamplingRates.add(0);
+ }
+ if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+ profile->mFormats.clear();
+ profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
+ }
+ if (profile->mChannelMasks[0] == 0) {
+ profile->mChannelMasks.clear();
+ profile->mChannelMasks.add(0);
+ }
+ }
+ }
+ }
+ } // end disconnect
+
+ return NO_ERROR;
+}
+
void AudioPolicyManagerBase::closeOutput(audio_io_handle_t output)
{
ALOGV("closeOutput(%d)", output);
// Move tracks associated to this strategy from previous output to new output
for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
if (getStrategy((AudioSystem::stream_type)i) == strategy) {
- //FIXME see fixme on name change
- mpClientInterface->setStreamOutput((AudioSystem::stream_type)i,
- dstOutputs[0] /* ignored */);
+ mpClientInterface->invalidateStream((AudioSystem::stream_type)i);
}
}
}
if (device != AUDIO_DEVICE_NONE) {
outputDesc->mDevice = device;
+
+ // Force routing if previously asked for this output
+ if (outputDesc->mForceRouting) {
+ ALOGV("Force routing to current device as previous device was null for this output");
+ force = true;
+
+ // Request consumed. Reset mForceRouting to false
+ outputDesc->mForceRouting = false;
+ }
+ }
+ else {
+ // Device is null and does not reflect the routing. Save the necessity to force
+ // re-routing upon next attempt to select a non-null device for this output
+ outputDesc->mForceRouting = true;
}
+
muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
// Do not change the routing if:
{
// Choose an input profile based on the requested capture parameters: select the first available
// profile supporting all requested parameters.
-
for (size_t i = 0; i < mHwModules.size(); i++)
{
if (mHwModules[i]->mHandle == 0) {
for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
{
IOProfile *profile = mHwModules[i]->mInputProfiles[j];
+ // profile->log();
if (profile->isCompatibleProfile(device, samplingRate, format,
channelMask, AUDIO_OUTPUT_FLAG_NONE)) {
return profile;
case AUDIO_SOURCE_DEFAULT:
case AUDIO_SOURCE_MIC:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
+ device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+ break;
+ }
+ // FALL THROUGH
+
case AUDIO_SOURCE_VOICE_RECOGNITION:
case AUDIO_SOURCE_HOTWORD:
case AUDIO_SOURCE_VOICE_COMMUNICATION:
device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
} else if (mAvailableInputDevices & AUDIO_DEVICE_IN_WIRED_HEADSET) {
device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_USB_DEVICE) {
+ device = AUDIO_DEVICE_IN_USB_DEVICE;
} else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
device = AUDIO_DEVICE_IN_BUILTIN_MIC;
}
};
const AudioPolicyManagerBase::VolumeCurvePoint
- *AudioPolicyManagerBase::sVolumeProfiles[AUDIO_STREAM_CNT]
+ *AudioPolicyManagerBase::sVolumeProfiles[AudioSystem::NUM_STREAM_TYPES]
[AudioPolicyManagerBase::DEVICE_CATEGORY_CNT] = {
{ // AUDIO_STREAM_VOICE_CALL
sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
void AudioPolicyManagerBase::initializeVolumeCurves()
{
- for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
+ for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
mStreams[i].mVolumeCurve[j] =
sVolumeProfiles[i][j];
if (stream == AudioSystem::MUSIC &&
index != mStreams[stream].mIndexMin &&
(device == AUDIO_DEVICE_OUT_AUX_DIGITAL ||
- device == AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET ||
- device == AUDIO_DEVICE_OUT_USB_ACCESSORY ||
- device == AUDIO_DEVICE_OUT_USB_DEVICE)) {
+ device == AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)) {
return 1.0;
}
: mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT),
mChannelMask(0), mLatency(0),
mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE),
- mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0)
+ mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0),
+ mForceRouting(false)
{
// clear usage count for all stream types
for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
// --- AudioInputDescriptor class implementation
AudioPolicyManagerBase::AudioInputDescriptor::AudioInputDescriptor(const IOProfile *profile)
- : mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0),
+ : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0),
mDevice(AUDIO_DEVICE_NONE), mRefCount(0),
mInputSource(0), mProfile(profile)
{
+ if (profile != NULL) {
+ mSamplingRate = profile->mSamplingRates[0];
+ mFormat = profile->mFormats[0];
+ mChannelMask = profile->mChannelMasks[0];
+ }
}
status_t AudioPolicyManagerBase::AudioInputDescriptor::dump(int fd)
if (mOutputProfiles.size()) {
write(fd, " - outputs:\n", strlen(" - outputs:\n"));
for (size_t i = 0; i < mOutputProfiles.size(); i++) {
- snprintf(buffer, SIZE, " output %d:\n", i);
+ snprintf(buffer, SIZE, " output %zu:\n", i);
write(fd, buffer, strlen(buffer));
mOutputProfiles[i]->dump(fd);
}
if (mInputProfiles.size()) {
write(fd, " - inputs:\n", strlen(" - inputs:\n"));
for (size_t i = 0; i < mInputProfiles.size(); i++) {
- snprintf(buffer, SIZE, " input %d:\n", i);
+ snprintf(buffer, SIZE, " input %zu:\n", i);
write(fd, buffer, strlen(buffer));
mInputProfiles[i]->dump(fd);
}
write(fd, result.string(), result.size());
}
+void AudioPolicyManagerBase::IOProfile::log()
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ ALOGV(" - sampling rates: ");
+ for (size_t i = 0; i < mSamplingRates.size(); i++) {
+ ALOGV(" %d", mSamplingRates[i]);
+ }
+
+ ALOGV(" - channel masks: ");
+ for (size_t i = 0; i < mChannelMasks.size(); i++) {
+ ALOGV(" 0x%04x", mChannelMasks[i]);
+ }
+
+ ALOGV(" - formats: ");
+ for (size_t i = 0; i < mFormats.size(); i++) {
+ ALOGV(" 0x%08x", mFormats[i]);
+ }
+
+ ALOGV(" - devices: 0x%04x\n", mSupportedDevices);
+ ALOGV(" - flags: 0x%04x\n", mFlags);
+}
+
// --- audio_policy.conf file parsing
struct StringToEnum {
STRING_TO_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
STRING_TO_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_DEVICE),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
};
const struct StringToEnum sFlagNameToEnumTable[] = {
const struct StringToEnum sFormatNameToEnumTable[] = {
STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_32_BIT),
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_FLOAT),
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
STRING_TO_ENUM(AUDIO_FORMAT_MP3),
STRING_TO_ENUM(AUDIO_FORMAT_AAC),
STRING_TO_ENUM(AUDIO_FORMAT_VORBIS),
+ STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V1),
+ STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V2),
+ STRING_TO_ENUM(AUDIO_FORMAT_OPUS),
+ STRING_TO_ENUM(AUDIO_FORMAT_AC3),
+ STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
};
const struct StringToEnum sOutChannelsNameToEnumTable[] = {
(profile->mSamplingRates.size() != 0) &&
(profile->mFormats.size() != 0)) {
- ALOGV("loadInput() adding input mSupportedDevices %04x", profile->mSupportedDevices);
+ ALOGV("loadInput() adding input mSupportedDevices 0x%X", profile->mSupportedDevices);
module->mInputProfiles.add(profile);
return NO_ERROR;