android13/device/google/atv/audio_proxy/service/DeviceImpl.cpp

498 lines
16 KiB
C++

// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "DeviceImpl.h"
#include <android-base/logging.h>
#include <android-base/strings.h>
#include <system/audio-hal-enums.h>
#include <utils/RefBase.h>
#include <optional>
#include "AidlTypes.h"
#include "BusOutputStream.h"
#include "BusStreamProvider.h"
#include "ServiceConfig.h"
#include "StreamOutImpl.h"
using namespace ::android::hardware::audio::common::CPP_VERSION;
using namespace ::android::hardware::audio::CPP_VERSION;
using ::android::wp;
namespace audio_proxy {
namespace service {
namespace {
AudioPatchHandle gNextAudioPatchHandle = 1;
#if MAJOR_VERSION >= 7
std::optional<AidlAudioConfig> toAidlAudioConfig(
const AudioConfigBase& hidl_config) {
audio_format_t format = AUDIO_FORMAT_INVALID;
if (!audio_format_from_string(hidl_config.format.c_str(), &format)) {
return std::nullopt;
}
audio_channel_mask_t channelMask = AUDIO_CHANNEL_INVALID;
if (!audio_channel_mask_from_string(hidl_config.channelMask.c_str(),
&channelMask)) {
return std::nullopt;
}
AidlAudioConfig aidlConfig = {
.format = static_cast<AidlAudioFormat>(format),
.sampleRateHz = static_cast<int32_t>(hidl_config.sampleRateHz),
.channelMask = static_cast<AidlAudioChannelMask>(channelMask)};
return aidlConfig;
}
std::optional<int32_t> toAidlAudioOutputFlags(
const hidl_vec<AudioInOutFlag>& flags) {
int32_t outputFlags = static_cast<int32_t>(AUDIO_OUTPUT_FLAG_NONE);
for (const auto& flag : flags) {
audio_output_flags_t outputFlag = AUDIO_OUTPUT_FLAG_NONE;
if (audio_output_flag_from_string(flag.c_str(), &outputFlag)) {
outputFlags |= static_cast<int32_t>(outputFlag);
} else {
return std::nullopt;
}
}
return outputFlags;
}
bool checkSourceMetadata(const SourceMetadata& metadata) {
for (const auto& track : metadata.tracks) {
audio_usage_t usage;
if (!audio_usage_from_string(track.usage.c_str(), &usage)) {
return false;
}
audio_content_type_t contentType;
if (!audio_content_type_from_string(track.contentType.c_str(),
&contentType)) {
return false;
}
audio_channel_mask_t channelMask;
if (!audio_channel_mask_from_string(track.channelMask.c_str(),
&channelMask)) {
return false;
}
// From types.hal:
// Tags are set by vendor specific applications and must be prefixed by
// "VX_". Vendor must namespace their tag names to avoid conflicts. See
// 'vendorExtension' in audio_policy_configuration.xsd for a formal
// definition.
//
// From audio_policy_configuration.xsd:
// Vendor extension names must be prefixed by "VX_" to distinguish them from
// AOSP values. Vendors must namespace their names to avoid conflicts. The
// namespace part must only use capital latin characters and decimal digits
// and consist of at least 3 characters.
for (const auto& tag : track.tags) {
if (!android::base::StartsWith(tag.c_str(), "VX_")) {
return false;
}
}
}
return true;
}
bool checkAudioPortConfig(const AudioPortConfig& config) {
if (config.base.format.getDiscriminator() ==
AudioConfigBaseOptional::Format::hidl_discriminator::value) {
audio_format_t format;
if (!audio_format_from_string(config.base.format.value().c_str(),
&format)) {
return false;
}
}
if (config.base.channelMask.getDiscriminator() ==
AudioConfigBaseOptional::ChannelMask::hidl_discriminator::value) {
audio_channel_mask_t channelMask;
if (!audio_channel_mask_from_string(config.base.channelMask.value().c_str(),
&channelMask)) {
return false;
}
}
if (config.gain.getDiscriminator() ==
AudioPortConfig::OptionalGain::hidl_discriminator::config) {
for (const auto& mode : config.gain.config().mode) {
audio_gain_mode_t gainMode;
if (!audio_gain_mode_from_string(mode.c_str(), &gainMode)) {
return false;
}
}
audio_channel_mask_t channelMask;
if (!audio_channel_mask_from_string(
config.gain.config().channelMask.c_str(), &channelMask)) {
return false;
}
}
if (config.ext.getDiscriminator() ==
AudioPortExtendedInfo::hidl_discriminator::device) {
audio_devices_t deviceType;
if (!audio_device_from_string(config.ext.device().deviceType.c_str(),
&deviceType)) {
return false;
}
}
if (config.ext.getDiscriminator() ==
AudioPortExtendedInfo::hidl_discriminator::mix) {
const auto& useCase = config.ext.mix().useCase;
if (useCase.getDiscriminator() == AudioPortExtendedInfo::AudioPortMixExt::
UseCase::hidl_discriminator::stream) {
audio_stream_type_t audioStreamType;
if (!audio_stream_type_from_string(useCase.stream().c_str(),
&audioStreamType)) {
return false;
}
} else {
audio_source_t audioSource;
if (!audio_source_from_string(useCase.source().c_str(), &audioSource)) {
return false;
}
}
}
return true;
}
#else
AidlAudioConfig toAidlAudioConfig(const AudioConfig& hidl_config) {
AidlAudioConfig aidlConfig = {
.format = static_cast<AidlAudioFormat>(hidl_config.format),
.sampleRateHz = static_cast<int32_t>(hidl_config.sampleRateHz),
.channelMask =
static_cast<AidlAudioChannelMask>(hidl_config.channelMask)};
return aidlConfig;
}
// Before 7.0, the fields are using enum instead of string. There's no need to
// validate them.
bool checkAudioPortConfig(const AudioPortConfig& config) { return true; }
#endif
} // namespace
DeviceImpl::DeviceImpl(BusStreamProvider& busStreamProvider,
const ServiceConfig& serviceConfig)
: mBusStreamProvider(busStreamProvider), mServiceConfig(serviceConfig) {}
// Methods from ::android::hardware::audio::V5_0::IDevice follow.
Return<Result> DeviceImpl::initCheck() { return Result::OK; }
Return<Result> DeviceImpl::setMasterVolume(float volume) {
// software mixer will emulate this ability
return Result::NOT_SUPPORTED;
}
Return<void> DeviceImpl::getMasterVolume(getMasterVolume_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, 0.f);
return Void();
}
Return<Result> DeviceImpl::setMicMute(bool mute) {
return Result::NOT_SUPPORTED;
}
Return<void> DeviceImpl::getMicMute(getMicMute_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, false);
return Void();
}
Return<Result> DeviceImpl::setMasterMute(bool mute) {
return Result::NOT_SUPPORTED;
}
Return<void> DeviceImpl::getMasterMute(getMasterMute_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, false);
return Void();
}
Return<void> DeviceImpl::getInputBufferSize(const AudioConfig& config,
getInputBufferSize_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, 0);
return Void();
}
#if MAJOR_VERSION >= 7
template <typename CallbackType>
Return<void> DeviceImpl::openOutputStreamImpl(
int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config,
const hidl_vec<AudioInOutFlag>& flags, const SourceMetadata& sourceMetadata,
CallbackType _hidl_cb) {
std::optional<AidlAudioConfig> aidlConfig = toAidlAudioConfig(config.base);
if (!aidlConfig) {
_hidl_cb(Result::INVALID_ARGUMENTS, nullptr, {});
return Void();
}
std::optional<int32_t> outputFlags = toAidlAudioOutputFlags(flags);
if (!outputFlags) {
_hidl_cb(Result::INVALID_ARGUMENTS, nullptr, {});
return Void();
}
if (!checkSourceMetadata(sourceMetadata)) {
_hidl_cb(Result::INVALID_ARGUMENTS, nullptr, {});
return Void();
}
std::string address;
// Default device is used for VTS test.
if (device.deviceType == "AUDIO_DEVICE_OUT_DEFAULT") {
address = "default";
} else if (device.deviceType == "AUDIO_DEVICE_OUT_BUS") {
address = device.address.id();
} else {
_hidl_cb(Result::INVALID_ARGUMENTS, nullptr, {});
return Void();
}
const auto configIt = mServiceConfig.streams.find(address);
if (configIt == mServiceConfig.streams.end()) {
_hidl_cb(Result::INVALID_ARGUMENTS, nullptr, {});
return Void();
}
std::shared_ptr<BusOutputStream> busOutputStream =
mBusStreamProvider.openOutputStream(address, *aidlConfig, *outputFlags);
DCHECK(busOutputStream);
auto streamOut = sp<StreamOutImpl>::make(
std::move(busOutputStream), config.base, configIt->second.bufferSizeMs,
configIt->second.latencyMs);
mBusStreamProvider.onStreamOutCreated(streamOut);
_hidl_cb(Result::OK, streamOut, config);
return Void();
}
Return<void> DeviceImpl::openOutputStream(int32_t ioHandle,
const DeviceAddress& device,
const AudioConfig& config,
const hidl_vec<AudioInOutFlag>& flags,
const SourceMetadata& sourceMetadata,
openOutputStream_cb _hidl_cb) {
return openOutputStreamImpl(ioHandle, device, config, flags, sourceMetadata,
_hidl_cb);
}
Return<void> DeviceImpl::openInputStream(int32_t ioHandle,
const DeviceAddress& device,
const AudioConfig& config,
const hidl_vec<AudioInOutFlag>& flags,
const SinkMetadata& sinkMetadata,
openInputStream_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, sp<IStreamIn>(), config);
return Void();
}
#else
Return<void> DeviceImpl::openOutputStream(int32_t ioHandle,
const DeviceAddress& device,
const AudioConfig& config,
hidl_bitfield<AudioOutputFlag> flags,
const SourceMetadata& sourceMetadata,
openOutputStream_cb _hidl_cb) {
std::string address;
if (device.device == AudioDevice::OUT_DEFAULT) {
address = "default";
} else if (device.device == AudioDevice::OUT_BUS) {
address = device.busAddress;
} else {
_hidl_cb(Result::INVALID_ARGUMENTS, nullptr, {});
return Void();
}
const auto configIt = mServiceConfig.streams.find(address);
if (configIt == mServiceConfig.streams.end()) {
_hidl_cb(Result::INVALID_ARGUMENTS, nullptr, {});
return Void();
}
std::shared_ptr<BusOutputStream> busOutputStream =
mBusStreamProvider.openOutputStream(address,
toAidlAudioConfig(config),
static_cast<int32_t>(flags));
DCHECK(busOutputStream);
auto streamOut = sp<StreamOutImpl>::make(std::move(busOutputStream), config,
configIt->second.bufferSizeMs,
configIt->second.latencyMs);
mBusStreamProvider.onStreamOutCreated(streamOut);
_hidl_cb(Result::OK, streamOut, config);
return Void();
}
Return<void> DeviceImpl::openInputStream(int32_t ioHandle,
const DeviceAddress& device,
const AudioConfig& config,
hidl_bitfield<AudioInputFlag> flags,
const SinkMetadata& sinkMetadata,
openInputStream_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, sp<IStreamIn>(), config);
return Void();
}
#endif
Return<bool> DeviceImpl::supportsAudioPatches() { return true; }
// Create a do-nothing audio patch.
Return<void> DeviceImpl::createAudioPatch(
const hidl_vec<AudioPortConfig>& sources,
const hidl_vec<AudioPortConfig>& sinks, createAudioPatch_cb _hidl_cb) {
for (const auto& config : sources) {
if (!checkAudioPortConfig(config)) {
_hidl_cb(Result::INVALID_ARGUMENTS, 0);
return Void();
}
}
for (const auto& config : sinks) {
if (!checkAudioPortConfig(config)) {
_hidl_cb(Result::INVALID_ARGUMENTS, 0);
return Void();
}
}
AudioPatchHandle handle = gNextAudioPatchHandle++;
mAudioPatchHandles.insert(handle);
_hidl_cb(Result::OK, handle);
return Void();
}
Return<Result> DeviceImpl::releaseAudioPatch(AudioPatchHandle patch) {
size_t removed = mAudioPatchHandles.erase(patch);
return removed > 0 ? Result::OK : Result::INVALID_ARGUMENTS;
}
Return<void> DeviceImpl::getAudioPort(const AudioPort& port,
getAudioPort_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, port);
return Void();
}
Return<Result> DeviceImpl::setAudioPortConfig(const AudioPortConfig& config) {
return Result::NOT_SUPPORTED;
}
Return<void> DeviceImpl::getHwAvSync(getHwAvSync_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, 0);
return Void();
}
Return<Result> DeviceImpl::setScreenState(bool turnedOn) {
return Result::NOT_SUPPORTED;
}
Return<void> DeviceImpl::getParameters(const hidl_vec<ParameterValue>& context,
const hidl_vec<hidl_string>& keys,
getParameters_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, hidl_vec<ParameterValue>());
return Void();
}
Return<Result> DeviceImpl::setParameters(
const hidl_vec<ParameterValue>& context,
const hidl_vec<ParameterValue>& parameters) {
return Result::NOT_SUPPORTED;
}
Return<void> DeviceImpl::getMicrophones(getMicrophones_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, hidl_vec<MicrophoneInfo>());
return Void();
}
Return<Result> DeviceImpl::setConnectedState(const DeviceAddress& address,
bool connected) {
#if MAJOR_VERSION >= 7
audio_devices_t deviceType = AUDIO_DEVICE_NONE;
if (!audio_device_from_string(address.deviceType.c_str(), &deviceType)) {
return Result::INVALID_ARGUMENTS;
}
if (deviceType != AUDIO_DEVICE_OUT_BUS) {
return Result::NOT_SUPPORTED;
}
const auto& busAddress = address.address.id();
#else
if (address.device != AudioDevice::OUT_BUS) {
return Result::NOT_SUPPORTED;
}
const auto& busAddress = address.busAddress;
#endif
return mServiceConfig.streams.count(busAddress) > 0 ? Result::OK
: Result::NOT_SUPPORTED;
}
#if MAJOR_VERSION >= 6
Return<void> DeviceImpl::updateAudioPatch(
AudioPatchHandle previousPatch, const hidl_vec<AudioPortConfig>& sources,
const hidl_vec<AudioPortConfig>& sinks, updateAudioPatch_cb _hidl_cb) {
if (mAudioPatchHandles.erase(previousPatch) == 0) {
_hidl_cb(Result::INVALID_ARGUMENTS, 0);
return Void();
}
AudioPatchHandle newPatch = gNextAudioPatchHandle++;
mAudioPatchHandles.insert(newPatch);
_hidl_cb(Result::OK, newPatch);
return Void();
}
Return<Result> DeviceImpl::close() {
return mBusStreamProvider.cleanAndCountStreamOuts() == 0
? Result::OK
: Result::INVALID_STATE;
}
Return<Result> DeviceImpl::addDeviceEffect(AudioPortHandle device,
uint64_t effectId) {
return Result::NOT_SUPPORTED;
}
Return<Result> DeviceImpl::removeDeviceEffect(AudioPortHandle device,
uint64_t effectId) {
return Result::NOT_SUPPORTED;
}
#endif
#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
Return<void> DeviceImpl::openOutputStream_7_1(
int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config,
const hidl_vec<AudioInOutFlag>& flags, const SourceMetadata& sourceMetadata,
openOutputStream_7_1_cb _hidl_cb) {
return openOutputStreamImpl(ioHandle, device, config, flags, sourceMetadata,
_hidl_cb);
}
Return<Result> DeviceImpl::setConnectedState_7_1(const AudioPort& devicePort,
bool connected) {
return Result::OK;
}
#endif
} // namespace service
} // namespace audio_proxy