Refactor opening output interface between AF and AP.

Refactor interface between audio flinger and audio policy. Use device
descriptor instead of audio device type and address. DeviceDescriptor
can contain more information that may be useful when opening an output
stream.
In audio policy, if multiple audio devices are passed in when opening
an output stream, one device is extracted using the same strategy as
when selecting a device for volume application. When starting source,
audio policy manager will call audio flinger to create audio patch. In
that case, multiple devices will still be patched to the output stream.

Test: atest AudioTrackTest AudioPlaybackCaptureTest
Test: atest audiopolicy_tests, audio smoke test
Change-Id: I46dc2da621614f8716c6c73cf807fe7d2d672cda
gugelfrei
jiabin 5 years ago
parent c6fe9c4246
commit 4381040f77

@ -1,7 +1,15 @@
cc_library_headers { cc_library_headers {
name: "libaudioclient_headers", name: "libaudioclient_headers",
vendor_available: true, vendor_available: true,
export_include_dirs: ["include"], header_libs: [
"libaudiofoundation_headers",
],
export_include_dirs: [
"include",
],
export_header_lib_headers: [
"libaudiofoundation_headers",
],
} }
cc_library_shared { cc_library_shared {
@ -63,6 +71,7 @@ cc_library_shared {
"TrackPlayerBase.cpp", "TrackPlayerBase.cpp",
], ],
shared_libs: [ shared_libs: [
"libaudiofoundation",
"libaudioutils", "libaudioutils",
"libaudiopolicy", "libaudiopolicy",
"libaudiomanager", "libaudiomanager",

@ -392,20 +392,18 @@ public:
virtual status_t openOutput(audio_module_handle_t module, virtual status_t openOutput(audio_module_handle_t module,
audio_io_handle_t *output, audio_io_handle_t *output,
audio_config_t *config, audio_config_t *config,
audio_devices_t *devices, const sp<DeviceDescriptorBase>& device,
const String8& address,
uint32_t *latencyMs, uint32_t *latencyMs,
audio_output_flags_t flags) audio_output_flags_t flags)
{ {
if (output == NULL || config == NULL || devices == NULL || latencyMs == NULL) { if (output == nullptr || config == nullptr || device == nullptr || latencyMs == nullptr) {
return BAD_VALUE; return BAD_VALUE;
} }
Parcel data, reply; Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(module); data.writeInt32(module);
data.write(config, sizeof(audio_config_t)); data.write(config, sizeof(audio_config_t));
data.writeInt32(*devices); data.writeParcelable(*device);
data.writeString8(address);
data.writeInt32((int32_t) flags); data.writeInt32((int32_t) flags);
status_t status = remote()->transact(OPEN_OUTPUT, data, &reply); status_t status = remote()->transact(OPEN_OUTPUT, data, &reply);
if (status != NO_ERROR) { if (status != NO_ERROR) {
@ -420,7 +418,6 @@ public:
*output = (audio_io_handle_t)reply.readInt32(); *output = (audio_io_handle_t)reply.readInt32();
ALOGV("openOutput() returned output, %d", *output); ALOGV("openOutput() returned output, %d", *output);
reply.read(config, sizeof(audio_config_t)); reply.read(config, sizeof(audio_config_t));
*devices = (audio_devices_t)reply.readInt32();
*latencyMs = reply.readInt32(); *latencyMs = reply.readInt32();
return NO_ERROR; return NO_ERROR;
} }
@ -1198,19 +1195,21 @@ status_t BnAudioFlinger::onTransact(
if (data.read(&config, sizeof(audio_config_t)) != NO_ERROR) { if (data.read(&config, sizeof(audio_config_t)) != NO_ERROR) {
ALOGE("b/23905951"); ALOGE("b/23905951");
} }
audio_devices_t devices = (audio_devices_t)data.readInt32(); sp<DeviceDescriptorBase> device = new DeviceDescriptorBase(AUDIO_DEVICE_NONE);
String8 address(data.readString8()); status_t status = NO_ERROR;
if ((status = data.readParcelable(device.get())) != NO_ERROR) {
reply->writeInt32((int32_t)status);
return NO_ERROR;
}
audio_output_flags_t flags = (audio_output_flags_t) data.readInt32(); audio_output_flags_t flags = (audio_output_flags_t) data.readInt32();
uint32_t latencyMs = 0; uint32_t latencyMs = 0;
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE; audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
status_t status = openOutput(module, &output, &config, status = openOutput(module, &output, &config, device, &latencyMs, flags);
&devices, address, &latencyMs, flags);
ALOGV("OPEN_OUTPUT output, %d", output); ALOGV("OPEN_OUTPUT output, %d", output);
reply->writeInt32((int32_t)status); reply->writeInt32((int32_t)status);
if (status == NO_ERROR) { if (status == NO_ERROR) {
reply->writeInt32((int32_t)output); reply->writeInt32((int32_t)output);
reply->write(&config, sizeof(audio_config_t)); reply->write(&config, sizeof(audio_config_t));
reply->writeInt32(devices);
reply->writeInt32(latencyMs); reply->writeInt32(latencyMs);
} }
return NO_ERROR; return NO_ERROR;

@ -27,6 +27,7 @@
#include <binder/Parcel.h> #include <binder/Parcel.h>
#include <binder/Parcelable.h> #include <binder/Parcelable.h>
#include <media/AudioClient.h> #include <media/AudioClient.h>
#include <media/DeviceDescriptorBase.h>
#include <media/IAudioTrack.h> #include <media/IAudioTrack.h>
#include <media/IAudioFlingerClient.h> #include <media/IAudioFlingerClient.h>
#include <system/audio.h> #include <system/audio.h>
@ -416,8 +417,7 @@ public:
virtual status_t openOutput(audio_module_handle_t module, virtual status_t openOutput(audio_module_handle_t module,
audio_io_handle_t *output, audio_io_handle_t *output,
audio_config_t *config, audio_config_t *config,
audio_devices_t *devices, const sp<DeviceDescriptorBase>& device,
const String8& address,
uint32_t *latencyMs, uint32_t *latencyMs,
audio_output_flags_t flags) = 0; audio_output_flags_t flags) = 0;
virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,

@ -15,6 +15,7 @@ cc_library_headers {
cc_library { cc_library {
name: "libaudiofoundation", name: "libaudiofoundation",
vendor_available: true, vendor_available: true,
double_loadable: true,
srcs: [ srcs: [
"AudioContainers.cpp", "AudioContainers.cpp",

@ -17,6 +17,7 @@
#pragma once #pragma once
#include <algorithm> #include <algorithm>
#include <functional>
#include <iterator> #include <iterator>
#include <set> #include <set>
#include <vector> #include <vector>
@ -78,6 +79,11 @@ static inline bool isSingleDeviceType(const DeviceTypeSet& deviceTypes,
return deviceTypes.size() == 1 && p(*(deviceTypes.begin())); return deviceTypes.size() == 1 && p(*(deviceTypes.begin()));
} }
static inline bool areAllOfSameDeviceType(const DeviceTypeSet& deviceTypes,
std::function<bool(audio_devices_t)> p) {
return std::all_of(deviceTypes.begin(), deviceTypes.end(), p);
}
static inline void resetDeviceTypes(DeviceTypeSet& deviceTypes, audio_devices_t typeToAdd) { static inline void resetDeviceTypes(DeviceTypeSet& deviceTypes, audio_devices_t typeToAdd) {
deviceTypes.clear(); deviceTypes.clear();
deviceTypes.insert(typeToAdd); deviceTypes.insert(typeToAdd);

@ -229,14 +229,14 @@ status_t DeviceHalHidl::getInputBufferSize(
status_t DeviceHalHidl::openOutputStream( status_t DeviceHalHidl::openOutputStream(
audio_io_handle_t handle, audio_io_handle_t handle,
audio_devices_t devices, audio_devices_t deviceType,
audio_output_flags_t flags, audio_output_flags_t flags,
struct audio_config *config, struct audio_config *config,
const char *address, const char *address,
sp<StreamOutHalInterface> *outStream) { sp<StreamOutHalInterface> *outStream) {
if (mDevice == 0) return NO_INIT; if (mDevice == 0) return NO_INIT;
DeviceAddress hidlDevice; DeviceAddress hidlDevice;
status_t status = deviceAddressFromHal(devices, address, &hidlDevice); status_t status = deviceAddressFromHal(deviceType, address, &hidlDevice);
if (status != OK) return status; if (status != OK) return status;
AudioConfig hidlConfig; AudioConfig hidlConfig;
HidlUtils::audioConfigFromHal(*config, &hidlConfig); HidlUtils::audioConfigFromHal(*config, &hidlConfig);

@ -104,7 +104,7 @@ status_t DeviceHalLocal::getInputBufferSize(
status_t DeviceHalLocal::openOutputStream( status_t DeviceHalLocal::openOutputStream(
audio_io_handle_t handle, audio_io_handle_t handle,
audio_devices_t devices, audio_devices_t deviceType,
audio_output_flags_t flags, audio_output_flags_t flags,
struct audio_config *config, struct audio_config *config,
const char *address, const char *address,
@ -112,11 +112,11 @@ status_t DeviceHalLocal::openOutputStream(
audio_stream_out_t *halStream; audio_stream_out_t *halStream;
ALOGV("open_output_stream handle: %d devices: %x flags: %#x" ALOGV("open_output_stream handle: %d devices: %x flags: %#x"
"srate: %d format %#x channels %x address %s", "srate: %d format %#x channels %x address %s",
handle, devices, flags, handle, deviceType, flags,
config->sample_rate, config->format, config->channel_mask, config->sample_rate, config->format, config->channel_mask,
address); address);
int openResut = mDev->open_output_stream( int openResut = mDev->open_output_stream(
mDev, handle, devices, flags, config, &halStream, address); mDev, handle, deviceType, flags, config, &halStream, address);
if (openResut == OK) { if (openResut == OK) {
*outStream = new StreamOutHalLocal(halStream, this); *outStream = new StreamOutHalLocal(halStream, this);
} }

@ -69,7 +69,7 @@ class DeviceHalInterface : public RefBase
// by releasing all references to the returned object. // by releasing all references to the returned object.
virtual status_t openOutputStream( virtual status_t openOutputStream(
audio_io_handle_t handle, audio_io_handle_t handle,
audio_devices_t devices, audio_devices_t deviceType,
audio_output_flags_t flags, audio_output_flags_t flags,
struct audio_config *config, struct audio_config *config,
const char *address, const char *address,

@ -34,6 +34,7 @@ cc_library_shared {
], ],
shared_libs: [ shared_libs: [
"libaudiofoundation",
"libaudiohal", "libaudiohal",
"libaudioprocessing", "libaudioprocessing",
"libaudiospdif", "libaudiospdif",

@ -381,7 +381,7 @@ static const char * const audio_interfaces[] = {
AudioHwDevice* AudioFlinger::findSuitableHwDev_l( AudioHwDevice* AudioFlinger::findSuitableHwDev_l(
audio_module_handle_t module, audio_module_handle_t module,
audio_devices_t devices) audio_devices_t deviceType)
{ {
// if module is 0, the request comes from an old policy manager and we should load // if module is 0, the request comes from an old policy manager and we should load
// well known modules // well known modules
@ -396,7 +396,7 @@ AudioHwDevice* AudioFlinger::findSuitableHwDev_l(
sp<DeviceHalInterface> dev = audioHwDevice->hwDevice(); sp<DeviceHalInterface> dev = audioHwDevice->hwDevice();
uint32_t supportedDevices; uint32_t supportedDevices;
if (dev->getSupportedDevices(&supportedDevices) == OK && if (dev->getSupportedDevices(&supportedDevices) == OK &&
(supportedDevices & devices) == devices) { (supportedDevices & deviceType) == deviceType) {
return audioHwDevice; return audioHwDevice;
} }
} }
@ -2304,13 +2304,13 @@ void AudioFlinger::setAudioHwSyncForSession_l(PlaybackThread *thread, audio_sess
sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module, sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
audio_io_handle_t *output, audio_io_handle_t *output,
audio_config_t *config, audio_config_t *config,
audio_devices_t devices, audio_devices_t deviceType,
const String8& address, const String8& address,
audio_output_flags_t flags) audio_output_flags_t flags)
{ {
AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices); AudioHwDevice *outHwDev = findSuitableHwDev_l(module, deviceType);
if (outHwDev == NULL) { if (outHwDev == NULL) {
return 0; return 0;
} }
@ -2351,7 +2351,7 @@ sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t mo
status_t status = outHwDev->openOutputStream( status_t status = outHwDev->openOutputStream(
&outputStream, &outputStream,
*output, *output,
devices, deviceType,
flags, flags,
config, config,
address.string()); address.string());
@ -2362,7 +2362,7 @@ sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t mo
if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) { if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
sp<MmapPlaybackThread> thread = sp<MmapPlaybackThread> thread =
new MmapPlaybackThread(this, *output, outHwDev, outputStream, new MmapPlaybackThread(this, *output, outHwDev, outputStream,
devices, AUDIO_DEVICE_NONE, mSystemReady); deviceType, AUDIO_DEVICE_NONE, mSystemReady);
mMmapThreads.add(*output, thread); mMmapThreads.add(*output, thread);
ALOGV("openOutput_l() created mmap playback thread: ID %d thread %p", ALOGV("openOutput_l() created mmap playback thread: ID %d thread %p",
*output, thread.get()); *output, thread.get());
@ -2370,17 +2370,18 @@ sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t mo
} else { } else {
sp<PlaybackThread> thread; sp<PlaybackThread> thread;
if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady); thread = new OffloadThread(this, outputStream, *output, deviceType, mSystemReady);
ALOGV("openOutput_l() created offload output: ID %d thread %p", ALOGV("openOutput_l() created offload output: ID %d thread %p",
*output, thread.get()); *output, thread.get());
} else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
|| !isValidPcmSinkFormat(config->format) || !isValidPcmSinkFormat(config->format)
|| !isValidPcmSinkChannelMask(config->channel_mask)) { || !isValidPcmSinkChannelMask(config->channel_mask)) {
thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady); thread = new DirectOutputThread(
this, outputStream, *output, deviceType, mSystemReady);
ALOGV("openOutput_l() created direct output: ID %d thread %p", ALOGV("openOutput_l() created direct output: ID %d thread %p",
*output, thread.get()); *output, thread.get());
} else { } else {
thread = new MixerThread(this, outputStream, *output, devices, mSystemReady); thread = new MixerThread(this, outputStream, *output, deviceType, mSystemReady);
ALOGV("openOutput_l() created mixer output: ID %d thread %p", ALOGV("openOutput_l() created mixer output: ID %d thread %p",
*output, thread.get()); *output, thread.get());
} }
@ -2396,27 +2397,29 @@ sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t mo
status_t AudioFlinger::openOutput(audio_module_handle_t module, status_t AudioFlinger::openOutput(audio_module_handle_t module,
audio_io_handle_t *output, audio_io_handle_t *output,
audio_config_t *config, audio_config_t *config,
audio_devices_t *devices, const sp<DeviceDescriptorBase>& device,
const String8& address,
uint32_t *latencyMs, uint32_t *latencyMs,
audio_output_flags_t flags) audio_output_flags_t flags)
{ {
ALOGI("openOutput() this %p, module %d Device %#x, SamplingRate %d, Format %#08x, " ALOGI("openOutput() this %p, module %d Device %s, SamplingRate %d, Format %#08x, "
"Channels %#x, flags %#x", "Channels %#x, flags %#x",
this, module, this, module,
(devices != NULL) ? *devices : 0, device->toString().c_str(),
config->sample_rate, config->sample_rate,
config->format, config->format,
config->channel_mask, config->channel_mask,
flags); flags);
if (devices == NULL || *devices == AUDIO_DEVICE_NONE) { audio_devices_t deviceType = device->type();
const String8 address = String8(device->address().c_str());
if (deviceType == AUDIO_DEVICE_NONE) {
return BAD_VALUE; return BAD_VALUE;
} }
Mutex::Autolock _l(mLock); Mutex::Autolock _l(mLock);
sp<ThreadBase> thread = openOutput_l(module, output, config, *devices, address, flags); sp<ThreadBase> thread = openOutput_l(module, output, config, deviceType, address, flags);
if (thread != 0) { if (thread != 0) {
if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0) { if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0) {
PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); PlaybackThread *playbackThread = (PlaybackThread *)thread.get();

@ -175,8 +175,7 @@ public:
virtual status_t openOutput(audio_module_handle_t module, virtual status_t openOutput(audio_module_handle_t module,
audio_io_handle_t *output, audio_io_handle_t *output,
audio_config_t *config, audio_config_t *config,
audio_devices_t *devices, const sp<DeviceDescriptorBase>& device,
const String8& address,
uint32_t *latencyMs, uint32_t *latencyMs,
audio_output_flags_t flags); audio_output_flags_t flags);
@ -372,7 +371,7 @@ private:
virtual void onFirstRef(); virtual void onFirstRef();
AudioHwDevice* findSuitableHwDev_l(audio_module_handle_t module, AudioHwDevice* findSuitableHwDev_l(audio_module_handle_t module,
audio_devices_t devices); audio_devices_t deviceType);
// Set kEnableExtendedChannels to true to enable greater than stereo output // Set kEnableExtendedChannels to true to enable greater than stereo output
// for the MixerThread and device sink. Number of channels allowed is // for the MixerThread and device sink. Number of channels allowed is
@ -678,11 +677,11 @@ using effect_buffer_t = int16_t;
audio_devices_t outputDevice, audio_devices_t outputDevice,
const String8& outputDeviceAddress); const String8& outputDeviceAddress);
sp<ThreadBase> openOutput_l(audio_module_handle_t module, sp<ThreadBase> openOutput_l(audio_module_handle_t module,
audio_io_handle_t *output, audio_io_handle_t *output,
audio_config_t *config, audio_config_t *config,
audio_devices_t devices, audio_devices_t deviceType,
const String8& address, const String8& address,
audio_output_flags_t flags); audio_output_flags_t flags);
void closeOutputFinish(const sp<PlaybackThread>& thread); void closeOutputFinish(const sp<PlaybackThread>& thread);
void closeInputFinish(const sp<RecordThread>& thread); void closeInputFinish(const sp<RecordThread>& thread);

@ -34,7 +34,7 @@ namespace android {
status_t AudioHwDevice::openOutputStream( status_t AudioHwDevice::openOutputStream(
AudioStreamOut **ppStreamOut, AudioStreamOut **ppStreamOut,
audio_io_handle_t handle, audio_io_handle_t handle,
audio_devices_t devices, audio_devices_t deviceType,
audio_output_flags_t flags, audio_output_flags_t flags,
struct audio_config *config, struct audio_config *config,
const char *address) const char *address)
@ -50,7 +50,7 @@ status_t AudioHwDevice::openOutputStream(
config->sample_rate, config->sample_rate,
config->format, config->format,
config->channel_mask); config->channel_mask);
status_t status = outputStream->open(handle, devices, config, address); status_t status = outputStream->open(handle, deviceType, config, address);
if (status != NO_ERROR) { if (status != NO_ERROR) {
delete outputStream; delete outputStream;
@ -75,7 +75,7 @@ status_t AudioHwDevice::openOutputStream(
if (wrapperNeeded) { if (wrapperNeeded) {
if (SPDIFEncoder::isFormatSupported(originalConfig.format)) { if (SPDIFEncoder::isFormatSupported(originalConfig.format)) {
outputStream = new SpdifStreamOut(this, flags, originalConfig.format); outputStream = new SpdifStreamOut(this, flags, originalConfig.format);
status = outputStream->open(handle, devices, &originalConfig, address); status = outputStream->open(handle, deviceType, &originalConfig, address);
if (status != NO_ERROR) { if (status != NO_ERROR) {
ALOGE("ERROR - openOutputStream(), SPDIF open returned %d", ALOGE("ERROR - openOutputStream(), SPDIF open returned %d",
status); status);

@ -76,7 +76,7 @@ public:
status_t openOutputStream( status_t openOutputStream(
AudioStreamOut **ppStreamOut, AudioStreamOut **ppStreamOut,
audio_io_handle_t handle, audio_io_handle_t handle,
audio_devices_t devices, audio_devices_t deviceType,
audio_output_flags_t flags, audio_output_flags_t flags,
struct audio_config *config, struct audio_config *config,
const char *address); const char *address);

@ -118,7 +118,7 @@ status_t AudioStreamOut::getPresentationPosition(uint64_t *frames, struct timesp
status_t AudioStreamOut::open( status_t AudioStreamOut::open(
audio_io_handle_t handle, audio_io_handle_t handle,
audio_devices_t devices, audio_devices_t deviceType,
struct audio_config *config, struct audio_config *config,
const char *address) const char *address)
{ {
@ -130,7 +130,7 @@ status_t AudioStreamOut::open(
int status = hwDev()->openOutputStream( int status = hwDev()->openOutputStream(
handle, handle,
devices, deviceType,
customFlags, customFlags,
config, config,
address, address,
@ -152,7 +152,7 @@ status_t AudioStreamOut::open(
status = hwDev()->openOutputStream( status = hwDev()->openOutputStream(
handle, handle,
devices, deviceType,
customFlags, customFlags,
&customConfig, &customConfig,
address, address,

@ -47,7 +47,7 @@ public:
virtual status_t open( virtual status_t open(
audio_io_handle_t handle, audio_io_handle_t handle,
audio_devices_t devices, audio_devices_t deviceType,
struct audio_config *config, struct audio_config *config,
const char *address); const char *address);

@ -19,6 +19,7 @@
#include <media/AudioSystem.h> #include <media/AudioSystem.h>
#include <media/AudioPolicy.h> #include <media/AudioPolicy.h>
#include <media/DeviceDescriptorBase.h>
#include <utils/String8.h> #include <utils/String8.h>
namespace android { namespace android {
@ -296,8 +297,7 @@ public:
virtual status_t openOutput(audio_module_handle_t module, virtual status_t openOutput(audio_module_handle_t module,
audio_io_handle_t *output, audio_io_handle_t *output,
audio_config_t *config, audio_config_t *config,
audio_devices_t *devices, const sp<DeviceDescriptorBase>& device,
const String8& address,
uint32_t *latencyMs, uint32_t *latencyMs,
audio_output_flags_t flags) = 0; audio_output_flags_t flags) = 0;
// creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by // creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by

@ -22,6 +22,8 @@
#include <utils/Log.h> #include <utils/Log.h>
#include <math.h> #include <math.h>
#include "policy.h"
namespace android { namespace android {
/** /**
@ -85,43 +87,14 @@ public:
*/ */
static audio_devices_t getDeviceForVolume(const android::DeviceTypeSet& deviceTypes) static audio_devices_t getDeviceForVolume(const android::DeviceTypeSet& deviceTypes)
{ {
audio_devices_t deviceType = AUDIO_DEVICE_NONE;
if (deviceTypes.empty()) { if (deviceTypes.empty()) {
// this happens when forcing a route update and no track is active on an output. // this happens when forcing a route update and no track is active on an output.
// In this case the returned category is not important. // In this case the returned category is not important.
deviceType = AUDIO_DEVICE_OUT_SPEAKER; return AUDIO_DEVICE_OUT_SPEAKER;
} else if (deviceTypes.size() > 1) {
// Multiple device selection is either:
// - speaker + one other device: give priority to speaker in this case.
// - one A2DP device + another device: happens with duplicated output. In this case
// retain the device on the A2DP output as the other must not correspond to an active
// selection if not the speaker.
// - HDMI-CEC system audio mode only output: give priority to available item in order.
if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER) != 0) {
deviceType = AUDIO_DEVICE_OUT_SPEAKER;
} else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER_SAFE) != 0) {
deviceType = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
} else if (deviceTypes.count(AUDIO_DEVICE_OUT_HDMI_ARC) != 0) {
deviceType = AUDIO_DEVICE_OUT_HDMI_ARC;
} else if (deviceTypes.count(AUDIO_DEVICE_OUT_AUX_LINE) != 0) {
deviceType = AUDIO_DEVICE_OUT_AUX_LINE;
} else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPDIF) != 0) {
deviceType = AUDIO_DEVICE_OUT_SPDIF;
} else {
std::vector<audio_devices_t> a2dpDevices = android::Intersection(
deviceTypes, android::getAudioDeviceOutAllA2dpSet());
if (a2dpDevices.size() > 1) {
ALOGW("getDeviceForVolume() invalid device combination: %s",
android::dumpDeviceTypes(deviceTypes).c_str());
}
if (!a2dpDevices.empty()) {
deviceType = a2dpDevices[0];
}
}
} else {
deviceType = *(deviceTypes.begin());
} }
audio_devices_t deviceType = apm_extract_one_audio_device(deviceTypes);
/*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/ /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/
if (deviceType == AUDIO_DEVICE_OUT_SPEAKER_SAFE) { if (deviceType == AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
deviceType = AUDIO_DEVICE_OUT_SPEAKER; deviceType = AUDIO_DEVICE_OUT_SPEAKER;

@ -19,6 +19,8 @@
#include <system/audio.h> #include <system/audio.h>
#include <vector> #include <vector>
#include <media/AudioContainers.h>
namespace android { namespace android {
using StreamTypeVector = std::vector<audio_stream_type_t>; using StreamTypeVector = std::vector<audio_stream_type_t>;
@ -199,3 +201,43 @@ static inline bool hasVoiceStream(const android::StreamTypeVector &streams)
{ {
return hasStream(streams, AUDIO_STREAM_VOICE_CALL); return hasStream(streams, AUDIO_STREAM_VOICE_CALL);
} }
/**
* @brief extract one device relevant from multiple device selection
* @param deviceTypes collection of audio device type
* @return the device type that is selected
*/
static inline audio_devices_t apm_extract_one_audio_device(
const android::DeviceTypeSet& deviceTypes) {
if (deviceTypes.empty()) {
return AUDIO_DEVICE_NONE;
} else if (deviceTypes.size() == 1) {
return *(deviceTypes.begin());
} else {
// Multiple device selection is either:
// - speaker + one other device: give priority to speaker in this case.
// - one A2DP device + another device: happens with duplicated output. In this case
// retain the device on the A2DP output as the other must not correspond to an active
// selection if not the speaker.
// - HDMI-CEC system audio mode only output: give priority to available item in order.
if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER) != 0) {
return AUDIO_DEVICE_OUT_SPEAKER;
} else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER_SAFE) != 0) {
return AUDIO_DEVICE_OUT_SPEAKER_SAFE;
} else if (deviceTypes.count(AUDIO_DEVICE_OUT_HDMI_ARC) != 0) {
return AUDIO_DEVICE_OUT_HDMI_ARC;
} else if (deviceTypes.count(AUDIO_DEVICE_OUT_AUX_LINE) != 0) {
return AUDIO_DEVICE_OUT_AUX_LINE;
} else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPDIF) != 0) {
return AUDIO_DEVICE_OUT_SPDIF;
} else {
std::vector<audio_devices_t> a2dpDevices = android::Intersection(
deviceTypes, android::getAudioDeviceOutAllA2dpSet());
if (a2dpDevices.empty() || a2dpDevices.size() > 1) {
ALOGW("%s invalid device combination: %s",
__func__, android::dumpDeviceTypes(deviceTypes).c_str());
}
return a2dpDevices.empty() ? AUDIO_DEVICE_NONE : a2dpDevices[0];
}
}
}

@ -130,6 +130,14 @@ public:
DeviceVector getFirstDevicesFromTypes(std::vector<audio_devices_t> orderedTypes) const; DeviceVector getFirstDevicesFromTypes(std::vector<audio_devices_t> orderedTypes) const;
sp<DeviceDescriptor> getFirstExistingDevice(std::vector<audio_devices_t> orderedTypes) const; sp<DeviceDescriptor> getFirstExistingDevice(std::vector<audio_devices_t> orderedTypes) const;
// Return device descriptor that is used to open an input/output stream.
// Null pointer will be returned if
// 1) this collection is empty
// 2) the device descriptors are not the same category(input or output)
// 3) there are more than one device type for input case
// 4) the combination of all devices is invalid for selection
sp<DeviceDescriptor> getDeviceForOpening() const;
// If there are devices with the given type and the devices to add is not empty, // If there are devices with the given type and the devices to add is not empty,
// remove all the devices with the given type and add all the devices to add. // remove all the devices with the given type and add all the devices to add.
void replaceDevicesByType(audio_devices_t typeToRemove, const DeviceVector &devicesToAdd); void replaceDevicesByType(audio_devices_t typeToRemove, const DeviceVector &devicesToAdd);

@ -467,8 +467,11 @@ status_t SwAudioOutputDescriptor::open(const audio_config_t *config,
audio_io_handle_t *output) audio_io_handle_t *output)
{ {
mDevices = devices; mDevices = devices;
const String8& address = devices.getFirstValidAddress(); sp<DeviceDescriptor> device = devices.getDeviceForOpening();
DeviceTypeSet deviceTypes = devices.types(); LOG_ALWAYS_FATAL_IF(device == nullptr,
"%s failed to get device descriptor for opening "
"with the requested devices, all device types: %s",
__func__, dumpDeviceTypes(devices.types()).c_str());
audio_config_t lConfig; audio_config_t lConfig;
if (config == nullptr) { if (config == nullptr) {
@ -500,25 +503,19 @@ status_t SwAudioOutputDescriptor::open(const audio_config_t *config,
ALOGV("opening output for device %s profile %p name %s", ALOGV("opening output for device %s profile %p name %s",
mDevices.toString().c_str(), mProfile.get(), mProfile->getName().c_str()); mDevices.toString().c_str(), mProfile.get(), mProfile->getName().c_str());
// FIXME: Stop using device types as bit mask when the interface updated.
audio_devices_t deviceType = deviceTypesToBitMask(deviceTypes);
status_t status = mClientInterface->openOutput(mProfile->getModuleHandle(), status_t status = mClientInterface->openOutput(mProfile->getModuleHandle(),
output, output,
&lConfig, &lConfig,
&deviceType, device,
address,
&mLatency, &mLatency,
mFlags); mFlags);
deviceTypes = deviceTypesFromBitMask(deviceType);
LOG_ALWAYS_FATAL_IF(mDevices.types() != deviceTypes,
"%s openOutput returned device %s when given device %s",
__FUNCTION__, dumpDeviceTypes(mDevices.types()).c_str(),
dumpDeviceTypes(deviceTypes).c_str());
if (status == NO_ERROR) { if (status == NO_ERROR) {
LOG_ALWAYS_FATAL_IF(*output == AUDIO_IO_HANDLE_NONE, LOG_ALWAYS_FATAL_IF(*output == AUDIO_IO_HANDLE_NONE,
"%s openOutput returned output handle %d for device %s", "%s openOutput returned output handle %d for device %s, "
__FUNCTION__, *output, dumpDeviceTypes(deviceTypes).c_str()); "selected device %s for opening",
__FUNCTION__, *output, devices.toString().c_str(),
device->toString().c_str());
mSamplingRate = lConfig.sample_rate; mSamplingRate = lConfig.sample_rate;
mChannelMask = lConfig.channel_mask; mChannelMask = lConfig.channel_mask;
mFormat = lConfig.format; mFormat = lConfig.format;

@ -328,6 +328,24 @@ sp<DeviceDescriptor> DeviceVector::getFirstExistingDevice(
return device; return device;
} }
sp<DeviceDescriptor> DeviceVector::getDeviceForOpening() const
{
if (isEmpty()) {
// Return nullptr if this collection is empty.
return nullptr;
} else if (areAllOfSameDeviceType(types(), audio_is_input_device)) {
// For input case, return the first one when there is only one device.
return size() > 1 ? nullptr : *begin();
} else if (areAllOfSameDeviceType(types(), audio_is_output_device)) {
// For output case, return the device descriptor according to apm strategy.
audio_devices_t deviceType = apm_extract_one_audio_device(types());
return deviceType == AUDIO_DEVICE_NONE ? nullptr :
getDevice(deviceType, String8(""), AUDIO_FORMAT_DEFAULT);
}
// Return null pointer if the devices are not all input/output device.
return nullptr;
}
void DeviceVector::replaceDevicesByType( void DeviceVector::replaceDevicesByType(
audio_devices_t typeToRemove, const DeviceVector &devicesToAdd) { audio_devices_t typeToRemove, const DeviceVector &devicesToAdd) {
DeviceVector devicesToRemove = getDevicesFromType(typeToRemove); DeviceVector devicesToRemove = getDevicesFromType(typeToRemove);

@ -39,8 +39,7 @@ audio_module_handle_t AudioPolicyService::AudioPolicyClient::loadHwModule(const
status_t AudioPolicyService::AudioPolicyClient::openOutput(audio_module_handle_t module, status_t AudioPolicyService::AudioPolicyClient::openOutput(audio_module_handle_t module,
audio_io_handle_t *output, audio_io_handle_t *output,
audio_config_t *config, audio_config_t *config,
audio_devices_t *devices, const sp<DeviceDescriptorBase>& device,
const String8& address,
uint32_t *latencyMs, uint32_t *latencyMs,
audio_output_flags_t flags) audio_output_flags_t flags)
{ {
@ -49,7 +48,7 @@ status_t AudioPolicyService::AudioPolicyClient::openOutput(audio_module_handle_t
ALOGW("%s: could not get AudioFlinger", __func__); ALOGW("%s: could not get AudioFlinger", __func__);
return PERMISSION_DENIED; return PERMISSION_DENIED;
} }
return af->openOutput(module, output, config, devices, address, latencyMs, flags); return af->openOutput(module, output, config, device, latencyMs, flags);
} }
audio_io_handle_t AudioPolicyService::AudioPolicyClient::openDuplicateOutput( audio_io_handle_t AudioPolicyService::AudioPolicyClient::openDuplicateOutput(

@ -622,8 +622,7 @@ private:
virtual status_t openOutput(audio_module_handle_t module, virtual status_t openOutput(audio_module_handle_t module,
audio_io_handle_t *output, audio_io_handle_t *output,
audio_config_t *config, audio_config_t *config,
audio_devices_t *devices, const sp<DeviceDescriptorBase>& device,
const String8& address,
uint32_t *latencyMs, uint32_t *latencyMs,
audio_output_flags_t flags); audio_output_flags_t flags);
// creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by // creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by

@ -34,8 +34,7 @@ public:
status_t openOutput(audio_module_handle_t module, status_t openOutput(audio_module_handle_t module,
audio_io_handle_t *output, audio_io_handle_t *output,
audio_config_t * /*config*/, audio_config_t * /*config*/,
audio_devices_t * /*devices*/, const sp<DeviceDescriptorBase>& /*device*/,
const String8 & /*address*/,
uint32_t * /*latencyMs*/, uint32_t * /*latencyMs*/,
audio_output_flags_t /*flags*/) override { audio_output_flags_t /*flags*/) override {
if (module >= mNextModuleHandle) { if (module >= mNextModuleHandle) {

@ -31,8 +31,7 @@ public:
status_t openOutput(audio_module_handle_t /*module*/, status_t openOutput(audio_module_handle_t /*module*/,
audio_io_handle_t* /*output*/, audio_io_handle_t* /*output*/,
audio_config_t* /*config*/, audio_config_t* /*config*/,
audio_devices_t* /*devices*/, const sp<DeviceDescriptorBase>& /*device*/,
const String8& /*address*/,
uint32_t* /*latencyMs*/, uint32_t* /*latencyMs*/,
audio_output_flags_t /*flags*/) override { return NO_INIT; } audio_output_flags_t /*flags*/) override { return NO_INIT; }
audio_io_handle_t openDuplicateOutput(audio_io_handle_t /*output1*/, audio_io_handle_t openDuplicateOutput(audio_io_handle_t /*output1*/,

Loading…
Cancel
Save