blob: e01be8a3c635e9c4f6393a3d81aea17e3bddc08f [file] [log] [blame]
Mikhail Naganovcf824f62023-07-24 14:51:36 -07001/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <limits>
18
19#define LOG_TAG "AHAL_StreamPrimary"
20#include <android-base/logging.h>
21#include <android-base/properties.h>
22#include <error/expected_utils.h>
23
24#include "PrimaryMixer.h"
25#include "core-impl/StreamPrimary.h"
26#include "core-impl/StreamStub.h"
27
28using aidl::android::hardware::audio::common::SinkMetadata;
29using aidl::android::hardware::audio::common::SourceMetadata;
30using aidl::android::media::audio::common::AudioDevice;
31using aidl::android::media::audio::common::AudioDeviceDescription;
32using aidl::android::media::audio::common::AudioDeviceType;
33using aidl::android::media::audio::common::AudioOffloadInfo;
34using aidl::android::media::audio::common::MicrophoneInfo;
35using android::base::GetBoolProperty;
36
37namespace aidl::android::hardware::audio::core {
38
39StreamPrimary::StreamPrimary(StreamContext* context, const Metadata& metadata)
40 : StreamAlsa(context, metadata, 3 /*readWriteRetries*/), mIsInput(isInput(metadata)) {}
41
42std::vector<alsa::DeviceProfile> StreamPrimary::getDeviceProfiles() {
43 static const std::vector<alsa::DeviceProfile> kBuiltInSource{
44 alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard,
45 .device = primary::PrimaryMixer::kAlsaDevice,
46 .direction = PCM_IN,
47 .isExternal = false}};
48 static const std::vector<alsa::DeviceProfile> kBuiltInSink{
49 alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard,
50 .device = primary::PrimaryMixer::kAlsaDevice,
51 .direction = PCM_OUT,
52 .isExternal = false}};
53 return mIsInput ? kBuiltInSource : kBuiltInSink;
54}
55
56StreamInPrimary::StreamInPrimary(StreamContext&& context, const SinkMetadata& sinkMetadata,
57 const std::vector<MicrophoneInfo>& microphones)
58 : StreamIn(std::move(context), microphones),
59 StreamSwitcher(&mContextInstance, sinkMetadata),
60 StreamInHwGainHelper(&mContextInstance) {}
61
62bool StreamInPrimary::useStubStream(const AudioDevice& device) {
63 static const bool kSimulateInput =
64 GetBoolProperty("ro.boot.audio.tinyalsa.simulate_input", false);
65 return kSimulateInput || device.type.type == AudioDeviceType::IN_TELEPHONY_RX ||
66 device.type.type == AudioDeviceType::IN_FM_TUNER ||
67 device.type.connection == AudioDeviceDescription::CONNECTION_BUS;
68}
69
70StreamSwitcher::DeviceSwitchBehavior StreamInPrimary::switchCurrentStream(
71 const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
72 LOG(DEBUG) << __func__;
73 if (devices.size() > 1) {
74 LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: "
75 << devices.size();
76 return DeviceSwitchBehavior::UNSUPPORTED_DEVICES;
77 }
78 if (devices.empty() || useStubStream(devices[0]) == isStubStream()) {
79 return DeviceSwitchBehavior::USE_CURRENT_STREAM;
80 }
81 return DeviceSwitchBehavior::CREATE_NEW_STREAM;
82}
83
84std::unique_ptr<StreamCommonInterfaceEx> StreamInPrimary::createNewStream(
85 const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
86 StreamContext* context, const Metadata& metadata) {
87 if (devices.empty()) {
88 LOG(FATAL) << __func__ << ": called with empty devices"; // see 'switchCurrentStream'
89 }
90 if (useStubStream(devices[0])) {
91 return std::unique_ptr<StreamCommonInterfaceEx>(
92 new InnerStreamWrapper<StreamStub>(context, metadata));
93 }
94 return std::unique_ptr<StreamCommonInterfaceEx>(
95 new InnerStreamWrapper<StreamPrimary>(context, metadata));
96}
97
98ndk::ScopedAStatus StreamInPrimary::getHwGain(std::vector<float>* _aidl_return) {
99 if (isStubStream()) {
100 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
101 }
102 return getHwGainImpl(_aidl_return);
103}
104
105ndk::ScopedAStatus StreamInPrimary::setHwGain(const std::vector<float>& in_channelGains) {
106 if (isStubStream()) {
107 LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelGains);
108 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
109 }
110 auto currentGains = mHwGains;
111 RETURN_STATUS_IF_ERROR(setHwGainImpl(in_channelGains));
112 if (in_channelGains.size() < 1) {
113 LOG(FATAL) << __func__ << ": unexpected gain vector size: " << in_channelGains.size();
114 }
115 if (auto status = primary::PrimaryMixer::getInstance().setMicGain(in_channelGains[0]);
116 !status.isOk()) {
117 mHwGains = currentGains;
118 return status;
119 }
120 return ndk::ScopedAStatus::ok();
121}
122
123StreamOutPrimary::StreamOutPrimary(StreamContext&& context, const SourceMetadata& sourceMetadata,
124 const std::optional<AudioOffloadInfo>& offloadInfo)
125 : StreamOut(std::move(context), offloadInfo),
126 StreamSwitcher(&mContextInstance, sourceMetadata),
127 StreamOutHwVolumeHelper(&mContextInstance) {}
128
129bool StreamOutPrimary::useStubStream(const AudioDevice& device) {
130 static const bool kSimulateOutput =
131 GetBoolProperty("ro.boot.audio.tinyalsa.ignore_output", false);
132 return kSimulateOutput || device.type.type == AudioDeviceType::OUT_TELEPHONY_TX ||
133 device.type.connection == AudioDeviceDescription::CONNECTION_BUS;
134}
135
136StreamSwitcher::DeviceSwitchBehavior StreamOutPrimary::switchCurrentStream(
137 const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
138 LOG(DEBUG) << __func__;
139 if (devices.size() > 1) {
140 LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: "
141 << devices.size();
142 return DeviceSwitchBehavior::UNSUPPORTED_DEVICES;
143 }
144 if (devices.empty() || useStubStream(devices[0]) == isStubStream()) {
145 return DeviceSwitchBehavior::USE_CURRENT_STREAM;
146 }
147 return DeviceSwitchBehavior::CREATE_NEW_STREAM;
148}
149
150std::unique_ptr<StreamCommonInterfaceEx> StreamOutPrimary::createNewStream(
151 const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
152 StreamContext* context, const Metadata& metadata) {
153 if (devices.empty()) {
154 LOG(FATAL) << __func__ << ": called with empty devices"; // see 'switchCurrentStream'
155 }
156 if (useStubStream(devices[0])) {
157 return std::unique_ptr<StreamCommonInterfaceEx>(
158 new InnerStreamWrapper<StreamStub>(context, metadata));
159 }
160 return std::unique_ptr<StreamCommonInterfaceEx>(
161 new InnerStreamWrapper<StreamPrimary>(context, metadata));
162}
163
164ndk::ScopedAStatus StreamOutPrimary::getHwVolume(std::vector<float>* _aidl_return) {
165 if (isStubStream()) {
166 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
167 }
168 return getHwVolumeImpl(_aidl_return);
169}
170
171ndk::ScopedAStatus StreamOutPrimary::setHwVolume(const std::vector<float>& in_channelVolumes) {
172 if (isStubStream()) {
173 LOG(DEBUG) << __func__ << ": volumes " << ::android::internal::ToString(in_channelVolumes);
174 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
175 }
176 auto currentVolumes = mHwVolumes;
177 RETURN_STATUS_IF_ERROR(setHwVolumeImpl(in_channelVolumes));
178 if (auto status = primary::PrimaryMixer::getInstance().setVolumes(in_channelVolumes);
179 !status.isOk()) {
180 mHwVolumes = currentVolumes;
181 return status;
182 }
183 return ndk::ScopedAStatus::ok();
184}
185
186} // namespace aidl::android::hardware::audio::core