| /* |
| * Copyright (C) 2018 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 <log/log.h> |
| #include <system/audio.h> |
| #include PATH(APM_XSD_ENUMS_H_FILENAME) |
| #include "primary_device.h" |
| #include "stream_in.h" |
| #include "stream_out.h" |
| #include "util.h" |
| #include "debug.h" |
| |
| namespace xsd { |
| using namespace ::android::audio::policy::configuration::CPP_VERSION; |
| } |
| |
| namespace android { |
| namespace hardware { |
| namespace audio { |
| namespace CPP_VERSION { |
| namespace implementation { |
| |
| constexpr size_t kInBufferDurationMs = 15; |
| constexpr size_t kOutBufferDurationMs = 22; |
| |
| using ::android::hardware::Void; |
| |
| Device::Device() {} |
| |
| Return<Result> Device::initCheck() { |
| return Result::OK; |
| } |
| |
| Return<Result> Device::setMasterVolume(float volume) { |
| if (isnan(volume) || volume < 0 || volume > 1.0) { |
| return FAILURE(Result::INVALID_ARGUMENTS); |
| } |
| |
| mMasterVolume = volume; |
| updateOutputStreamVolume(mMasterMute ? 0.0f : volume); |
| return Result::OK; |
| } |
| |
| Return<void> Device::getMasterVolume(getMasterVolume_cb _hidl_cb) { |
| _hidl_cb(Result::OK, mMasterVolume); |
| return Void(); |
| } |
| |
| Return<Result> Device::setMicMute(bool mute) { |
| mMicMute = mute; |
| updateInputStreamMicMute(mute); |
| return Result::OK; |
| } |
| |
| Return<void> Device::getMicMute(getMicMute_cb _hidl_cb) { |
| _hidl_cb(Result::OK, mMicMute); |
| return Void(); |
| } |
| |
| Return<Result> Device::setMasterMute(bool mute) { |
| mMasterMute = mute; |
| updateOutputStreamVolume(mute ? 0.0f : mMasterVolume); |
| return Result::OK; |
| } |
| |
| Return<void> Device::getMasterMute(getMasterMute_cb _hidl_cb) { |
| _hidl_cb(Result::OK, mMasterMute); |
| return Void(); |
| } |
| |
| Return<void> Device::getInputBufferSize(const AudioConfig& config, getInputBufferSize_cb _hidl_cb) { |
| AudioConfig suggestedConfig; |
| if (util::checkAudioConfig(false, kInBufferDurationMs, config, suggestedConfig)) { |
| const size_t sz = |
| suggestedConfig.frameCount |
| * util::countChannels(suggestedConfig.base.channelMask) |
| * util::getBytesPerSample(suggestedConfig.base.format); |
| |
| _hidl_cb(Result::OK, sz); |
| } else { |
| _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), 0); |
| } |
| |
| return Void(); |
| } |
| |
| Return<void> Device::openOutputStream(int32_t ioHandle, |
| const DeviceAddress& device, |
| const AudioConfig& config, |
| const hidl_vec<AudioInOutFlag>& flags, |
| const SourceMetadata& sourceMetadata, |
| openOutputStream_cb _hidl_cb) { |
| auto [result, stream, cfg] = openOutputStreamImpl(ioHandle, device, |
| config, flags, sourceMetadata); |
| _hidl_cb(result, stream, cfg); |
| return Void(); |
| } |
| |
| Return<void> Device::openInputStream(int32_t ioHandle, |
| const DeviceAddress& device, |
| const AudioConfig& config, |
| const hidl_vec<AudioInOutFlag>& flags, |
| const SinkMetadata& sinkMetadata, |
| openInputStream_cb _hidl_cb) { |
| auto [result, stream, cfg] = openInputStreamImpl(ioHandle, device, |
| config, flags, sinkMetadata); |
| _hidl_cb(result, stream, cfg); |
| return Void(); |
| } |
| |
| Return<bool> Device::supportsAudioPatches() { |
| return true; |
| } |
| |
| Return<void> Device::createAudioPatch(const hidl_vec<AudioPortConfig>& sources, |
| const hidl_vec<AudioPortConfig>& sinks, |
| createAudioPatch_cb _hidl_cb) { |
| if (sources.size() == 1 && sinks.size() == 1) { |
| AudioPatch patch; |
| if (!util::checkAudioPortConfig(sources[0]) || !util::checkAudioPortConfig(sinks[0])) { |
| _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), 0); |
| return Void(); |
| } |
| patch.source = sources[0]; |
| patch.sink = sinks[0]; |
| |
| AudioPatchHandle handle; |
| while (true) { |
| handle = mNextAudioPatchHandle; |
| mNextAudioPatchHandle = std::max(handle + 1, 0); |
| if (mAudioPatches.insert({handle, patch}).second) { |
| break; |
| } |
| } |
| |
| _hidl_cb(Result::OK, handle); |
| } else { |
| _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0); |
| } |
| |
| return Void(); |
| } |
| |
| Return<void> Device::updateAudioPatch(AudioPatchHandle previousPatchHandle, |
| const hidl_vec<AudioPortConfig>& sources, |
| const hidl_vec<AudioPortConfig>& sinks, |
| updateAudioPatch_cb _hidl_cb) { |
| const auto i = mAudioPatches.find(previousPatchHandle); |
| if (i == mAudioPatches.end()) { |
| _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), previousPatchHandle); |
| } else { |
| if (sources.size() == 1 && sinks.size() == 1) { |
| AudioPatch patch; |
| patch.source = sources[0]; |
| patch.sink = sinks[0]; |
| i->second = patch; |
| |
| _hidl_cb(Result::OK, previousPatchHandle); |
| } else { |
| _hidl_cb(Result::NOT_SUPPORTED, previousPatchHandle); |
| } |
| } |
| |
| return Void(); |
| } |
| |
| Return<Result> Device::releaseAudioPatch(AudioPatchHandle patchHandle) { |
| return (mAudioPatches.erase(patchHandle) == 1) ? Result::OK : FAILURE(Result::INVALID_ARGUMENTS); |
| } |
| |
| Return<void> Device::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) { |
| _hidl_cb(FAILURE(Result::NOT_SUPPORTED), port); |
| return Void(); |
| } |
| |
| Return<Result> Device::setAudioPortConfig(const AudioPortConfig& config) { |
| (void)config; |
| return FAILURE(Result::NOT_SUPPORTED); |
| } |
| |
| Return<Result> Device::setScreenState(bool turnedOn) { |
| (void)turnedOn; |
| return Result::OK; |
| } |
| |
| Return<void> Device::getHwAvSync(getHwAvSync_cb _hidl_cb) { |
| _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {}); |
| return Void(); |
| } |
| |
| Return<void> Device::getParameters(const hidl_vec<ParameterValue>& context, |
| const hidl_vec<hidl_string>& keys, |
| getParameters_cb _hidl_cb) { |
| (void)context; |
| if (keys.size() == 0) { |
| _hidl_cb(Result::OK, {}); |
| } else { |
| _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {}); |
| } |
| return Void(); |
| } |
| |
| Return<Result> Device::setParameters(const hidl_vec<ParameterValue>& context, |
| const hidl_vec<ParameterValue>& parameters) { |
| (void)context; |
| (void)parameters; |
| return Result::OK; |
| } |
| |
| Return<void> Device::getMicrophones(getMicrophones_cb _hidl_cb) { |
| _hidl_cb(Result::OK, {util::getMicrophoneInfo()}); |
| return Void(); |
| } |
| |
| Return<Result> Device::setConnectedState(const DeviceAddress& dev_addr, bool connected) { |
| (void)dev_addr; |
| (void)connected; |
| return FAILURE(Result::NOT_SUPPORTED); |
| } |
| |
| Return<Result> Device::close() { |
| std::lock_guard<std::mutex> guard(mMutex); |
| |
| return (mInputStreams.empty() && mOutputStreams.empty()) |
| ? Result::OK : FAILURE(Result::INVALID_STATE); |
| } |
| |
| Return<Result> Device::addDeviceEffect(AudioPortHandle device, uint64_t effectId) { |
| (void)device; |
| (void)effectId; |
| return FAILURE(Result::NOT_SUPPORTED); |
| } |
| |
| Return<Result> Device::removeDeviceEffect(AudioPortHandle device, uint64_t effectId) { |
| (void)device; |
| (void)effectId; |
| return FAILURE(Result::NOT_SUPPORTED); |
| } |
| |
| void Device::unrefDevice(StreamIn *sin) { |
| std::lock_guard<std::mutex> guard(mMutex); |
| LOG_ALWAYS_FATAL_IF(mInputStreams.erase(sin) < 1); |
| } |
| |
| void Device::unrefDevice(StreamOut *sout) { |
| std::lock_guard<std::mutex> guard(mMutex); |
| LOG_ALWAYS_FATAL_IF(mOutputStreams.erase(sout) < 1); |
| } |
| |
| void Device::updateOutputStreamVolume(float masterVolume) const { |
| std::lock_guard<std::mutex> guard(mMutex); |
| for (StreamOut *stream : mOutputStreams) { |
| stream->setMasterVolume(masterVolume); |
| } |
| } |
| |
| void Device::updateInputStreamMicMute(bool micMute) const { |
| std::lock_guard<std::mutex> guard(mMutex); |
| for (StreamIn *stream : mInputStreams) { |
| stream->setMicMute(micMute); |
| } |
| } |
| |
| std::tuple<Result, sp<IStreamOut>, AudioConfig> Device::openOutputStreamImpl( |
| int32_t ioHandle, const DeviceAddress& device, |
| const AudioConfig& config, const hidl_vec<AudioInOutFlag>& flags, |
| const SourceMetadata& sourceMetadata) { |
| if (!StreamOut::validateDeviceAddress(device) |
| || !util::checkAudioConfig(config) |
| || !StreamOut::validateFlags(flags) |
| || !StreamOut::validateSourceMetadata(sourceMetadata)) { |
| return {FAILURE(Result::INVALID_ARGUMENTS), {}, {}}; |
| } |
| |
| AudioConfig suggestedConfig; |
| if (util::checkAudioConfig(true, kOutBufferDurationMs, config, suggestedConfig)) { |
| auto stream = std::make_unique<StreamOut>( |
| this, ioHandle, device, suggestedConfig, flags, sourceMetadata); |
| |
| stream->setMasterVolume(mMasterMute ? 0.0f : mMasterVolume); |
| |
| { |
| std::lock_guard<std::mutex> guard(mMutex); |
| LOG_ALWAYS_FATAL_IF(!mOutputStreams.insert(stream.get()).second); |
| } |
| |
| return {Result::OK, stream.release(), suggestedConfig}; |
| } |
| return {FAILURE(Result::INVALID_ARGUMENTS), {}, suggestedConfig}; |
| } |
| |
| std::tuple<Result, sp<IStreamIn>, AudioConfig> Device::openInputStreamImpl( |
| int32_t ioHandle, const DeviceAddress& device, |
| const AudioConfig& config, const hidl_vec<AudioInOutFlag>& flags, |
| const SinkMetadata& sinkMetadata) { |
| if (!StreamIn::validateDeviceAddress(device) |
| || !util::checkAudioConfig(config) |
| || !StreamIn::validateFlags(flags) |
| || !StreamIn::validateSinkMetadata(sinkMetadata)) { |
| return {FAILURE(Result::INVALID_ARGUMENTS), {}, {}}; |
| } |
| |
| AudioConfig suggestedConfig; |
| if (util::checkAudioConfig(false, kInBufferDurationMs, config, suggestedConfig)) { |
| auto stream = std::make_unique<StreamIn>( |
| this, ioHandle, device, suggestedConfig, flags, sinkMetadata); |
| |
| stream->setMicMute(mMicMute); |
| |
| { |
| std::lock_guard<std::mutex> guard(mMutex); |
| LOG_ALWAYS_FATAL_IF(!mInputStreams.insert(stream.get()).second); |
| } |
| |
| return {Result::OK, stream.release(), suggestedConfig}; |
| } |
| return {FAILURE(Result::INVALID_ARGUMENTS), {}, suggestedConfig}; |
| } |
| |
| #if MAJOR_VERSION == 7 && MINOR_VERSION == 1 |
| Return<void> Device::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) { |
| auto [result, stream, cfg] = openOutputStreamImpl(ioHandle, device, |
| config, flags, sourceMetadata); |
| _hidl_cb(result, stream, cfg); |
| return Void(); |
| } |
| |
| Return<Result> Device::setConnectedState_7_1(const AudioPort& devicePort, |
| bool connected) { |
| (void)devicePort; |
| (void)connected; |
| return FAILURE(Result::NOT_SUPPORTED); |
| } |
| #endif |
| |
| // ================== |
| |
| PrimaryDevice::PrimaryDevice() : mDevice(sp<Device>::make()) { |
| } |
| |
| Return<Result> PrimaryDevice::initCheck() { |
| return mDevice->initCheck(); |
| } |
| |
| Return<Result> PrimaryDevice::setMasterVolume(float volume) { |
| return mDevice->setMasterVolume(volume); |
| } |
| |
| Return<void> PrimaryDevice::getMasterVolume(getMasterVolume_cb _hidl_cb) { |
| return mDevice->getMasterVolume(_hidl_cb); |
| } |
| |
| Return<Result> PrimaryDevice::setMicMute(bool mute) { |
| return mDevice->setMicMute(mute); |
| } |
| |
| Return<void> PrimaryDevice::getMicMute(getMicMute_cb _hidl_cb) { |
| return mDevice->getMicMute(_hidl_cb); |
| } |
| |
| Return<Result> PrimaryDevice::setMasterMute(bool mute) { |
| return mDevice->setMasterMute(mute); |
| } |
| |
| Return<void> PrimaryDevice::getMasterMute(getMasterMute_cb _hidl_cb) { |
| return mDevice->getMasterMute(_hidl_cb); |
| } |
| |
| Return<void> PrimaryDevice::getInputBufferSize(const AudioConfig& config, |
| getInputBufferSize_cb _hidl_cb) { |
| return mDevice->getInputBufferSize(config, _hidl_cb); |
| } |
| |
| Return<void> PrimaryDevice::openOutputStream(int32_t ioHandle, |
| const DeviceAddress& device, |
| const AudioConfig& config, |
| const hidl_vec<AudioInOutFlag>& flags, |
| const SourceMetadata& sourceMetadata, |
| openOutputStream_cb _hidl_cb) { |
| return mDevice->openOutputStream(ioHandle, device, config, flags, sourceMetadata, _hidl_cb); |
| } |
| |
| Return<void> PrimaryDevice::openInputStream(int32_t ioHandle, |
| const DeviceAddress& device, |
| const AudioConfig& config, |
| const hidl_vec<AudioInOutFlag>& flags, |
| const SinkMetadata& sinkMetadata, |
| openInputStream_cb _hidl_cb) { |
| return mDevice->openInputStream(ioHandle, device, config, flags, sinkMetadata, _hidl_cb); |
| } |
| |
| Return<bool> PrimaryDevice::supportsAudioPatches() { |
| return mDevice->supportsAudioPatches(); |
| } |
| |
| Return<void> PrimaryDevice::createAudioPatch(const hidl_vec<AudioPortConfig>& sources, |
| const hidl_vec<AudioPortConfig>& sinks, |
| createAudioPatch_cb _hidl_cb) { |
| return mDevice->createAudioPatch(sources, sinks, _hidl_cb); |
| } |
| |
| Return<void> PrimaryDevice::updateAudioPatch(int32_t previousPatch, |
| const hidl_vec<AudioPortConfig>& sources, |
| const hidl_vec<AudioPortConfig>& sinks, |
| updateAudioPatch_cb _hidl_cb) { |
| return mDevice->updateAudioPatch(previousPatch, sources, sinks, _hidl_cb); |
| } |
| |
| Return<Result> PrimaryDevice::releaseAudioPatch(int32_t patch) { |
| return mDevice->releaseAudioPatch(patch); |
| } |
| |
| Return<void> PrimaryDevice::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) { |
| return mDevice->getAudioPort(port, _hidl_cb); |
| } |
| |
| Return<Result> PrimaryDevice::setAudioPortConfig(const AudioPortConfig& config) { |
| return mDevice->setAudioPortConfig(config); |
| } |
| |
| Return<Result> PrimaryDevice::setScreenState(bool turnedOn) { |
| return mDevice->setScreenState(turnedOn); |
| } |
| |
| Return<void> PrimaryDevice::getHwAvSync(getHwAvSync_cb _hidl_cb) { |
| return mDevice->getHwAvSync(_hidl_cb); |
| } |
| |
| Return<void> PrimaryDevice::getParameters(const hidl_vec<ParameterValue>& context, |
| const hidl_vec<hidl_string>& keys, |
| getParameters_cb _hidl_cb) { |
| return mDevice->getParameters(context, keys, _hidl_cb); |
| } |
| |
| Return<Result> PrimaryDevice::setParameters(const hidl_vec<ParameterValue>& context, |
| const hidl_vec<ParameterValue>& parameters) { |
| return mDevice->setParameters(context, parameters); |
| } |
| |
| Return<void> PrimaryDevice::getMicrophones(getMicrophones_cb _hidl_cb) { |
| return mDevice->getMicrophones(_hidl_cb); |
| } |
| |
| Return<Result> PrimaryDevice::setConnectedState(const DeviceAddress& dev_addr, bool connected) { |
| return mDevice->setConnectedState(dev_addr, connected); |
| } |
| |
| Return<Result> PrimaryDevice::close() { |
| return mDevice->close(); |
| } |
| |
| Return<Result> PrimaryDevice::addDeviceEffect(AudioPortHandle device, uint64_t effectId) { |
| return mDevice->addDeviceEffect(device, effectId); |
| } |
| |
| Return<Result> PrimaryDevice::removeDeviceEffect(AudioPortHandle device, uint64_t effectId) { |
| return mDevice->removeDeviceEffect(device, effectId); |
| } |
| |
| Return<Result> PrimaryDevice::setVoiceVolume(float volume) { |
| return (volume >= 0 && volume <= 1.0) ? Result::OK : FAILURE(Result::INVALID_ARGUMENTS); |
| } |
| |
| Return<Result> PrimaryDevice::setMode(AudioMode mode) { |
| switch (mode) { |
| case AudioMode::NORMAL: |
| case AudioMode::RINGTONE: |
| case AudioMode::IN_CALL: |
| case AudioMode::IN_COMMUNICATION: |
| return Result::OK; |
| |
| default: |
| return FAILURE(Result::INVALID_ARGUMENTS); |
| } |
| } |
| |
| Return<Result> PrimaryDevice::setBtScoHeadsetDebugName(const hidl_string& name) { |
| (void)name; |
| return FAILURE(Result::NOT_SUPPORTED); |
| } |
| |
| Return<void> PrimaryDevice::getBtScoNrecEnabled(getBtScoNrecEnabled_cb _hidl_cb) { |
| _hidl_cb(FAILURE(Result::NOT_SUPPORTED), false); |
| return Void(); |
| } |
| |
| Return<Result> PrimaryDevice::setBtScoNrecEnabled(bool enabled) { |
| (void)enabled; |
| return FAILURE(Result::NOT_SUPPORTED); |
| } |
| |
| Return<void> PrimaryDevice::getBtScoWidebandEnabled(getBtScoWidebandEnabled_cb _hidl_cb) { |
| _hidl_cb(FAILURE(Result::NOT_SUPPORTED), false); |
| return Void(); |
| } |
| |
| Return<Result> PrimaryDevice::setBtScoWidebandEnabled(bool enabled) { |
| (void)enabled; |
| return FAILURE(Result::NOT_SUPPORTED); |
| } |
| |
| Return<void> PrimaryDevice::getTtyMode(getTtyMode_cb _hidl_cb) { |
| _hidl_cb(FAILURE(Result::NOT_SUPPORTED), TtyMode::OFF); |
| return Void(); |
| } |
| |
| Return<Result> PrimaryDevice::setTtyMode(IPrimaryDevice::TtyMode mode) { |
| (void)mode; |
| return FAILURE(Result::NOT_SUPPORTED); |
| } |
| |
| Return<void> PrimaryDevice::getHacEnabled(getHacEnabled_cb _hidl_cb) { |
| _hidl_cb(FAILURE(Result::NOT_SUPPORTED), false); |
| return Void(); |
| } |
| |
| Return<Result> PrimaryDevice::setHacEnabled(bool enabled) { |
| (void)enabled; |
| return FAILURE(Result::NOT_SUPPORTED); |
| } |
| |
| Return<void> PrimaryDevice::getBtHfpEnabled(getBtHfpEnabled_cb _hidl_cb) { |
| _hidl_cb(FAILURE(Result::NOT_SUPPORTED), false); |
| return Void(); |
| } |
| |
| Return<Result> PrimaryDevice::setBtHfpEnabled(bool enabled) { |
| (void)enabled; |
| return FAILURE(Result::NOT_SUPPORTED); |
| } |
| |
| Return<Result> PrimaryDevice::setBtHfpSampleRate(uint32_t sampleRateHz) { |
| (void)sampleRateHz; |
| return FAILURE(Result::NOT_SUPPORTED); |
| } |
| |
| Return<Result> PrimaryDevice::setBtHfpVolume(float volume) { |
| (void)volume; |
| return FAILURE(Result::NOT_SUPPORTED); |
| } |
| |
| Return<Result> PrimaryDevice::updateRotation(IPrimaryDevice::Rotation rotation) { |
| (void)rotation; |
| return FAILURE(Result::NOT_SUPPORTED); |
| } |
| |
| } // namespace implementation |
| } // namespace CPP_VERSION |
| } // namespace audio |
| } // namespace hardware |
| } // namespace android |