X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=audio%2FAudioPolicyManagerBase.cpp;h=85b0084e3bc48df8725f0f8c0915dadc295c591f;hb=47d073a97d95d9ec9a5c580aa557de5da022aaf9;hp=cac157594ebb37e968ff9d5bc0dc3b2649ff4f74;hpb=dcc6e9f2994d1f8e3c0aa6d71c4fc6f423a07c55;p=android-x86%2Fhardware-libhardware_legacy.git diff --git a/audio/AudioPolicyManagerBase.cpp b/audio/AudioPolicyManagerBase.cpp index cac1575..85b0084 100644 --- a/audio/AudioPolicyManagerBase.cpp +++ b/audio/AudioPolicyManagerBase.cpp @@ -31,13 +31,16 @@ // active output devices in isStreamActiveRemotely() #define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX +#include +#include + +#include #include -#include -#include + #include -#include +#include #include -#include +#include namespace android_audio_legacy { @@ -50,9 +53,12 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device AudioSystem::device_connection_state state, const char *device_address) { - SortedVector 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; @@ -64,12 +70,13 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device // handle output devices if (audio_is_output_device(device)) { + SortedVector 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; } @@ -92,12 +99,12 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device } 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); } @@ -105,21 +112,21 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device 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; @@ -133,18 +140,18 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device 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 @@ -182,19 +189,14 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device 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 inputs; + String8 paramStr; switch (state) { // handle input device connection @@ -203,6 +205,20 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device 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; @@ -213,30 +229,19 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device 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; @@ -245,11 +250,15 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device 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; } @@ -257,8 +266,8 @@ AudioSystem::device_connection_state AudioPolicyManagerBase::getDeviceConnection 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; } @@ -933,8 +942,8 @@ audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource, 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; } @@ -952,6 +961,7 @@ audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource, inputDesc->mFormat = format; inputDesc->mChannelMask = channelMask; inputDesc->mRefCount = 0; + input = mpClientInterface->openInput(profile->mModule->mHandle, &inputDesc->mDevice, &inputDesc->mSamplingRate, @@ -963,7 +973,7 @@ audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource, (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); @@ -971,7 +981,8 @@ audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource, delete inputDesc; return 0; } - mInputs.add(input, inputDesc); + addInput(input, inputDesc); + return input; } @@ -1070,9 +1081,17 @@ void AudioPolicyManagerBase::releaseInput(audio_io_handle_t 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) @@ -1168,7 +1187,7 @@ audio_io_handle_t AudioPolicyManagerBase::selectOutputForEffects( 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]; } @@ -1377,7 +1396,7 @@ status_t AudioPolicyManagerBase::dump(int fd) 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); @@ -1401,7 +1420,7 @@ status_t AudioPolicyManagerBase::dump(int fd) 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); } @@ -1428,7 +1447,7 @@ status_t AudioPolicyManagerBase::dump(int 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); } @@ -1455,7 +1474,7 @@ status_t AudioPolicyManagerBase::dump(int 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, @@ -1541,7 +1560,7 @@ AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clien 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) { @@ -1813,6 +1832,11 @@ void AudioPolicyManagerBase::addOutput(audio_io_handle_t id, AudioOutputDescript 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, @@ -1840,7 +1864,7 @@ status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device, 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]); } } @@ -1886,83 +1910,98 @@ status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device, &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; + } } } } @@ -1981,7 +2020,7 @@ status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device, 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); @@ -1991,6 +2030,7 @@ status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device, 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) { @@ -1999,9 +2039,8 @@ status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device, 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(); @@ -2022,6 +2061,184 @@ status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device, return NO_ERROR; } +status_t AudioPolicyManagerBase::checkInputsForDevice(audio_devices_t device, + AudioSystem::device_connection_state state, + SortedVector& 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 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); @@ -2637,7 +2854,22 @@ uint32_t AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, 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: @@ -2667,7 +2899,6 @@ AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getInputProfile(audio { // 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) { @@ -2676,6 +2907,7 @@ AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getInputProfile(audio 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; @@ -2699,6 +2931,12 @@ audio_devices_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource) 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: @@ -2707,6 +2945,8 @@ audio_devices_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource) 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; } @@ -2913,7 +3153,7 @@ const AudioPolicyManagerBase::VolumeCurvePoint }; 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 @@ -2969,7 +3209,7 @@ const AudioPolicyManagerBase::VolumeCurvePoint 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]; @@ -3006,9 +3246,7 @@ float AudioPolicyManagerBase::computeVolume(int stream, 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; } @@ -3252,7 +3490,8 @@ AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor( : 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++) { @@ -3401,10 +3640,15 @@ status_t AudioPolicyManagerBase::AudioOutputDescriptor::dump(int fd) // --- 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) @@ -3521,7 +3765,7 @@ void AudioPolicyManagerBase::HwModule::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); } @@ -3529,7 +3773,7 @@ void AudioPolicyManagerBase::HwModule::dump(int 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); } @@ -3633,6 +3877,31 @@ void AudioPolicyManagerBase::IOProfile::dump(int 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 { @@ -3668,6 +3937,7 @@ const struct StringToEnum sDeviceNameToEnumTable[] = { 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[] = { @@ -3689,6 +3959,11 @@ const struct StringToEnum sFormatNameToEnumTable[] = { 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[] = { @@ -3891,7 +4166,7 @@ status_t AudioPolicyManagerBase::loadInput(cnode *root, HwModule *module) (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;