4、音频设备管理 【基于Android Q 】
audio policy xml里面有2种角色:source和sink,每种角色又分为devicePorts和mixPorts。
type为AUDIO_PORT_TYPE_DEVICE
devicePorts(source):为实际的硬件输入设备,对应安卓的role为AUDIO_PORT_ROLE_SOURCE ;
devicePorts(sink):为实际的硬件输出设备,对应安卓的role为AUDIO_PORT_ROLE_SINK ;
type为AUDIO_PORT_TYPE_MIX
mixPorts(source):为AudioFlinger中的播放(AudioTrack)的线程,对应安卓的role为AUDIO_PORT_ROLE_SOURCE,mOutputs;
mixPorts(sink):为AudioFlinger中的录音(AudioRecord)的线程,对应安卓的role为AUDIO_PORT_ROLE_SINK,mInputs
routes:定义devicePort和mixPorts的路由策略。
通过该接口AudioSystem.listAudioPorts可获取到当前所有的端口
status_t AudioPolicyManager::listAudioPorts(audio_port_role_t role,
audio_port_type_t type,
unsigned int *num_ports,
struct audio_port *ports,
unsigned int *generation)
{
...
if (type == AUDIO_PORT_TYPE_NONE || type == AUDIO_PORT_TYPE_DEVICE) {
// do not report devices with type AUDIO_DEVICE_IN_STUB or AUDIO_DEVICE_OUT_STUB
// as they are used by stub HALs by convention
if (role == AUDIO_PORT_ROLE_SINK || role == AUDIO_PORT_ROLE_NONE) {
for (const auto& dev : mAvailableOutputDevices) {
if (dev->type() == AUDIO_DEVICE_OUT_STUB) {
continue;
}
if (portsWritten < portsMax) {
dev->toAudioPort(&ports[portsWritten++]);
ALOGD("[%s:%d] output device role:%d, name:%s, type:%#x", __func__, __LINE__,
ports[portsWritten-1].role, ports[portsWritten-1].name, ports[portsWritten-1].ext.device.type);
}
(*num_ports)++;
}
}
if (role == AUDIO_PORT_ROLE_SOURCE || role == AUDIO_PORT_ROLE_NONE) {
for (const auto& dev : mAvailableInputDevices) {
if (dev->type() == AUDIO_DEVICE_IN_STUB) {
continue;
}
if (portsWritten < portsMax) {
dev->toAudioPort(&ports[portsWritten++]);
ALOGD("[%s:%d] input device role:%d, name:%s, type:%#x", __func__, __LINE__,
ports[portsWritten-1].role, ports[portsWritten-1].name, ports[portsWritten-1].ext.device.type);
}
(*num_ports)++;
}
}
}
if (type == AUDIO_PORT_TYPE_NONE || type == AUDIO_PORT_TYPE_MIX) {
if (role == AUDIO_PORT_ROLE_SINK || role == AUDIO_PORT_ROLE_NONE) {
for (size_t i = 0; i < mInputs.size() && portsWritten < portsMax; i++) {
mInputs[i]->toAudioPort(&ports[portsWritten++]);
ALOGD("[%s:%d] sink mix role:%d, name:%s, handle:%d", __func__, __LINE__,
ports[portsWritten-1].role, ports[portsWritten-1].name, ports[portsWritten-1].ext.mix.handle);
}
*num_ports += mInputs.size();
}
if (role == AUDIO_PORT_ROLE_SOURCE || role == AUDIO_PORT_ROLE_NONE) {
size_t numOutputs = 0;
for (size_t i = 0; i < mOutputs.size(); i++) {
if (!mOutputs[i]->isDuplicated()) {
numOutputs++;
if (portsWritten < portsMax) {
mOutputs[i]->toAudioPort(&ports[portsWritten++]);
ALOGD("[%s:%d] source mix role:%d, name:%s, handle:%d", __func__, __LINE__,
ports[portsWritten-1].role, ports[portsWritten-1].name, ports[portsWritten-1].ext.mix.handle);
}
}
}
*num_ports += numOutputs;
}
}
*generation = curAudioPortGeneration();
ALOGD("listAudioPorts() got %zu ports needed %d, generation:%d", portsWritten, *num_ports, *generation);
return NO_ERROR;
}
typedef enum {
AUDIO_PORT_ROLE_NONE = 0,
AUDIO_PORT_ROLE_SOURCE = 1, // (::android::hardware::audio::common::V4_0::AudioPortRole.NONE implicitly + 1)
AUDIO_PORT_ROLE_SINK = 2, // (::android::hardware::audio::common::V4_0::AudioPortRole.SOURCE implicitly + 1)
} audio_port_role_t;
typedef enum {
AUDIO_PORT_TYPE_NONE = 0,
AUDIO_PORT_TYPE_DEVICE = 1, // (::android::hardware::audio::common::V4_0::AudioPortType.NONE implicitly + 1)
AUDIO_PORT_TYPE_MIX = 2, // (::android::hardware::audio::common::V4_0::AudioPortType.DEVICE implicitly + 1)
AUDIO_PORT_TYPE_SESSION = 3, // (::android::hardware::audio::common::V4_0::AudioPortType.MIX implicitly + 1)
} audio_port_type_t;
status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor>& device,
audio_policy_dev_state_t state,
SortedVector<audio_io_handle_t>& outputs)
{
audio_devices_t deviceType = device->type();
const String8 &address = device->address();
sp<SwAudioOutputDescriptor> desc;
if (audio_device_is_digital(deviceType)) {
// erase all current sample rates, formats and channel masks
device->clearAudioProfiles();
}
if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
// first list already open outputs that can be routed to this device
for (size_t i = 0; i < mOutputs.size(); i++) {
desc = mOutputs.valueAt(i);
if (!desc->isDuplicated() && desc->supportsDevice(device)
&& desc->deviceSupportsEncodedFormats(deviceType)) {
ALOGV("checkOutputsForDevice(): adding opened output %d on device %s",
mOutputs.keyAt(i), device->toString().c_str());
outputs.add(mOutputs.keyAt(i));
}
}
// then look for output profiles that can be routed to this device
SortedVector< sp<IOProfile> > profiles;
// 遍历所有xml的包含该device的profiles
for (const auto& hwModule : mHwModules) {
for (size_t j = 0; j < hwModule->getOutputProfiles().size(); j++) {
sp<IOProfile> profile = hwModule->getOutputProfiles()[j];
if (profile->supportsDevice(device)) {
profiles.add(profile);
ALOGV("checkOutputsForDevice(): adding profile %zu from module %s",
j, hwModule->getName());
}
}
}
ALOGV(" found %zu profiles, %zu outputs", profiles.size(), outputs.size());
if (profiles.isEmpty() && outputs.isEmpty()) {
ALOGW("checkOutputsForDevice(): No output available for device %04x", deviceType);
return BAD_VALUE;
}
// 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++) {
sp<IOProfile> profile = profiles[profile_index];
// nothing to do if one output is already opened for this profile
size_t j;
for (j = 0; j < outputs.size(); j++) {
desc = mOutputs.valueFor(outputs.itemAt(j));
if (!desc->isDuplicated() && desc->mProfile == profile) {
// matching profile: save the sample rates, format and channel masks supported
// by the profile in our device descriptor
if (audio_device_is_digital(deviceType)) {
device->importAudioPort(profile);
}
break;
}
}
if (j != outputs.size()) {
continue;
}
if (!profile->canOpenNewIo()) {
ALOGW("Max Output number %u already opened for this profile %s",
profile->maxOpenCount, profile->getTagName().c_str());
continue;
}
ALOGD("opening output for device %08x with params %s profile %p name %s",
deviceType, address.string(), profile.get(), profile->getName().string());
desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
ALOGI("[%s:%d] open_ ", __func__, __LINE__);
status_t status = desc->open(nullptr, DeviceVector(device),
AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE, &output);
if (status == NO_ERROR) {
// Here is where the out_set_parameters() for card & device gets called
if (!address.isEmpty()) {
char *param = audio_device_address_to_parameter(deviceType, address);
mpClientInterface->setParameters(output, String8(param));
free(param);
}
updateAudioProfiles(device, output, profile->getAudioProfiles());
if (!profile->hasValidAudioProfile()) {
ALOGW("checkOutputsForDevice() missing param");
desc->close();
output = AUDIO_IO_HANDLE_NONE;
} else if (profile->hasDynamicAudioProfile()) {
ALOGI("[%s:%d] close_ ", __func__, __LINE__);
desc->close();
output = AUDIO_IO_HANDLE_NONE;
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
profile->pickAudioProfile(
config.sample_rate, config.channel_mask, config.format);
config.offload_info.sample_rate = config.sample_rate;
config.offload_info.channel_mask = config.channel_mask;
config.offload_info.format = config.format;
ALOGI("[%s:%d] open_ ", __func__, __LINE__);
status_t status = desc->open(&config, DeviceVector(device),
AUDIO_STREAM_DEFAULT,
AUDIO_OUTPUT_FLAG_NONE, &output);
if (status != NO_ERROR) {
output = AUDIO_IO_HANDLE_NONE;
}
...