blob: 03b2791c7848d2ad0446205a677eb9864952e1e5 [file] [log] [blame]
/*
* 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 "primary_device.h"
#include "stream_in.h"
#include "stream_out.h"
#include "util.h"
namespace android {
namespace hardware {
namespace audio {
namespace V6_0 {
namespace implementation {
constexpr size_t kInBufferDurationMs = 15;
constexpr size_t kOutBufferDurationMs = 15;
using ::android::hardware::Void;
PrimaryDevice::PrimaryDevice()
: mMixer(talsa::mixerOpen(talsa::kPcmDevice)) {
if (mMixer) {
mMixerMasterVolumeCtl = mixer_get_ctl_by_name(mMixer.get(), "Master Playback Volume");
mMixerCaptureVolumeCtl = mixer_get_ctl_by_name(mMixer.get(), "Capture Volume");
mMixerMasterPaybackSwitchCtl = mixer_get_ctl_by_name(mMixer.get(), "Master Playback Switch");
mMixerCaptureSwitchCtl = mixer_get_ctl_by_name(mMixer.get(), "Capture Switch");
talsa::mixerSetPercentAll(mMixerMasterVolumeCtl, 100);
talsa::mixerSetPercentAll(mMixerCaptureVolumeCtl, 100);
talsa::mixerSetValueAll(mMixerMasterPaybackSwitchCtl, 1);
talsa::mixerSetValueAll(mMixerCaptureSwitchCtl, 1);
}
}
Return<Result> PrimaryDevice::initCheck() {
return mMixer ? Result::OK : Result::NOT_INITIALIZED;
}
Return<Result> PrimaryDevice::setMasterVolume(float volume) {
if (volume < 0 || volume > 1.0) {
return Result::INVALID_ARGUMENTS;
}
if (!mMixerMasterVolumeCtl) {
return Result::INVALID_STATE;
}
talsa::mixerSetPercentAll(mMixerMasterVolumeCtl, int(100 * volume));
return Result::OK;
}
Return<void> PrimaryDevice::getMasterVolume(getMasterVolume_cb _hidl_cb) {
if (mMixerMasterVolumeCtl) {
_hidl_cb(Result::OK,
mixer_ctl_get_percent(mMixerMasterVolumeCtl, 0) / 100.0);
} else {
_hidl_cb(Result::INVALID_STATE, 0);
}
return Void();
}
Return<Result> PrimaryDevice::PrimaryDevice::setMicMute(bool mute) {
if (mMixerCaptureSwitchCtl) {
talsa::mixerSetValueAll(mMixerCaptureSwitchCtl, mute ? 0 : 1);
return Result::OK;
} else {
return Result::INVALID_STATE;
}
}
Return<void> PrimaryDevice::getMicMute(getMicMute_cb _hidl_cb) {
if (mMixerCaptureSwitchCtl) {
const int value = mixer_ctl_get_value(mMixerCaptureSwitchCtl, 0);
_hidl_cb(Result::OK, value == 0);
} else {
_hidl_cb(Result::INVALID_STATE, 0);
}
return Void();
}
Return<Result> PrimaryDevice::setMasterMute(bool mute) {
if (mMixerMasterPaybackSwitchCtl) {
talsa::mixerSetValueAll(mMixerMasterPaybackSwitchCtl, mute ? 0 : 1);
return Result::OK;
} else {
return Result::INVALID_STATE;
}
}
Return<void> PrimaryDevice::getMasterMute(getMasterMute_cb _hidl_cb) {
if (mMixerMasterPaybackSwitchCtl) {
const int value = mixer_ctl_get_value(mMixerMasterPaybackSwitchCtl, 0);
_hidl_cb(Result::OK, value == 0);
} else {
_hidl_cb(Result::NOT_SUPPORTED, 0);
}
return Void();
}
Return<void> PrimaryDevice::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.channelMask)
* util::getBytesPerSample(suggestedConfig.format);
_hidl_cb(Result::OK, sz);
} else {
ALOGE("PrimaryDevice::%s:%d failed", __func__, __LINE__);
_hidl_cb(Result::INVALID_ARGUMENTS, 0);
}
return Void();
}
Return<void> PrimaryDevice::openOutputStream(int32_t ioHandle,
const DeviceAddress& device,
const AudioConfig& config,
hidl_bitfield<AudioOutputFlag> flags,
const SourceMetadata& sourceMetadata,
openOutputStream_cb _hidl_cb) {
AudioConfig suggestedConfig;
if (util::checkAudioConfig(true, kOutBufferDurationMs, config, suggestedConfig)) {
++mNStreams;
_hidl_cb(Result::OK,
new StreamOut(this, &unrefDevice,
ioHandle, device, suggestedConfig, flags, sourceMetadata),
config);
} else {
ALOGE("PrimaryDevice::%s:%d failed", __func__, __LINE__);
_hidl_cb(Result::INVALID_ARGUMENTS, nullptr, suggestedConfig);
}
return Void();
}
Return<void> PrimaryDevice::openInputStream(int32_t ioHandle,
const DeviceAddress& device,
const AudioConfig& config,
hidl_bitfield<AudioInputFlag> flags,
const SinkMetadata& sinkMetadata,
openInputStream_cb _hidl_cb) {
AudioConfig suggestedConfig;
if (util::checkAudioConfig(false, kInBufferDurationMs, config, suggestedConfig)) {
++mNStreams;
_hidl_cb(Result::OK,
new StreamIn(this, &unrefDevice,
ioHandle, device, suggestedConfig, flags, sinkMetadata),
config);
} else {
ALOGE("PrimaryDevice::%s:%d failed", __func__, __LINE__);
_hidl_cb(Result::INVALID_ARGUMENTS, nullptr, suggestedConfig);
}
return Void();
}
Return<bool> PrimaryDevice::supportsAudioPatches() {
return false;
}
Return<void> PrimaryDevice::createAudioPatch(const hidl_vec<AudioPortConfig>& sources,
const hidl_vec<AudioPortConfig>& sinks,
createAudioPatch_cb _hidl_cb) {
(void)sources;
(void)sinks;
_hidl_cb(Result::NOT_SUPPORTED, 0);
return Void();
}
Return<void> PrimaryDevice::updateAudioPatch(int32_t previousPatch,
const hidl_vec<AudioPortConfig>& sources,
const hidl_vec<AudioPortConfig>& sinks,
updateAudioPatch_cb _hidl_cb) {
(void)previousPatch;
(void)sources;
(void)sinks;
_hidl_cb(Result::NOT_SUPPORTED, 0);
return Void();
}
Return<Result> PrimaryDevice::releaseAudioPatch(int32_t patch) {
(void)patch;
return Result::NOT_SUPPORTED;
}
Return<void> PrimaryDevice::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, port);
return Void();
}
Return<Result> PrimaryDevice::setAudioPortConfig(const AudioPortConfig& config) {
(void)config;
return Result::NOT_SUPPORTED;
}
Return<Result> PrimaryDevice::setScreenState(bool turnedOn) {
(void)turnedOn;
return Result::OK;
}
Return<void> PrimaryDevice::getHwAvSync(getHwAvSync_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, {});
return Void();
}
Return<void> PrimaryDevice::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(Result::NOT_SUPPORTED, {});
}
return Void();
}
Return<Result> PrimaryDevice::setParameters(const hidl_vec<ParameterValue>& context,
const hidl_vec<ParameterValue>& parameters) {
(void)context;
if (parameters.size() == 0) {
return Result::OK;
} else {
return Result::NOT_SUPPORTED;
}
}
Return<void> PrimaryDevice::getMicrophones(getMicrophones_cb _hidl_cb) {
_hidl_cb(Result::OK, {util::getMicrophoneInfo()});
return Void();
}
Return<Result> PrimaryDevice::setConnectedState(const DeviceAddress& dev_addr, bool connected) {
(void)dev_addr;
(void)connected;
return Result::NOT_SUPPORTED;
}
Return<Result> PrimaryDevice::close() {
if (mNStreams > 0) {
return Result::INVALID_STATE;
} else if (mMixer) {
mMixerMasterVolumeCtl = nullptr;
mMixerCaptureVolumeCtl = nullptr;
mMixerMasterPaybackSwitchCtl = nullptr;
mMixerCaptureSwitchCtl = nullptr;
mMixer.reset();
return Result::OK;
} else {
return Result::INVALID_STATE;
}
}
Return<Result> PrimaryDevice::addDeviceEffect(AudioPortHandle device, uint64_t effectId) {
(void)device;
(void)effectId;
return Result::NOT_SUPPORTED;
}
Return<Result> PrimaryDevice::removeDeviceEffect(AudioPortHandle device, uint64_t effectId) {
(void)device;
(void)effectId;
return Result::NOT_SUPPORTED;
}
Return<Result> PrimaryDevice::setVoiceVolume(float volume) {
return (volume >= 0 && volume <= 1.0) ? Result::OK : 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 Result::INVALID_ARGUMENTS;
}
}
Return<Result> PrimaryDevice::setBtScoHeadsetDebugName(const hidl_string& name) {
(void)name;
return Result::NOT_SUPPORTED;
}
Return<void> PrimaryDevice::getBtScoNrecEnabled(getBtScoNrecEnabled_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, false);
return Void();
}
Return<Result> PrimaryDevice::setBtScoNrecEnabled(bool enabled) {
(void)enabled;
return Result::NOT_SUPPORTED;
}
Return<void> PrimaryDevice::getBtScoWidebandEnabled(getBtScoWidebandEnabled_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, false);
return Void();
}
Return<Result> PrimaryDevice::setBtScoWidebandEnabled(bool enabled) {
(void)enabled;
return Result::NOT_SUPPORTED;
}
Return<void> PrimaryDevice::getTtyMode(getTtyMode_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, TtyMode::OFF);
return Void();
}
Return<Result> PrimaryDevice::setTtyMode(IPrimaryDevice::TtyMode mode) {
(void)mode;
return Result::NOT_SUPPORTED;
}
Return<void> PrimaryDevice::getHacEnabled(getHacEnabled_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, false);
return Void();
}
Return<Result> PrimaryDevice::setHacEnabled(bool enabled) {
(void)enabled;
return Result::NOT_SUPPORTED;
}
Return<void> PrimaryDevice::getBtHfpEnabled(getBtHfpEnabled_cb _hidl_cb) {
_hidl_cb(Result::NOT_SUPPORTED, false);
return Void();
}
Return<Result> PrimaryDevice::setBtHfpEnabled(bool enabled) {
(void)enabled;
return Result::NOT_SUPPORTED;
}
Return<Result> PrimaryDevice::setBtHfpSampleRate(uint32_t sampleRateHz) {
(void)sampleRateHz;
return Result::NOT_SUPPORTED;
}
Return<Result> PrimaryDevice::setBtHfpVolume(float volume) {
(void)volume;
return Result::NOT_SUPPORTED;
}
Return<Result> PrimaryDevice::updateRotation(IPrimaryDevice::Rotation rotation) {
(void)rotation;
return Result::NOT_SUPPORTED;
}
void PrimaryDevice::unrefDevice(IDevice *dev) {
static_cast<PrimaryDevice *>(dev)->unrefDeviceImpl();
}
void PrimaryDevice::unrefDeviceImpl() {
LOG_ALWAYS_FATAL_IF(--mNStreams < 0);
}
} // namespace implementation
} // namespace V6_0
} // namespace audio
} // namespace hardware
} // namespace android