blob: 17de2baf7a11da821d6386d8694f8bd6e10e61f3 [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)
Mikhail Naganov3c8b6ce2023-10-31 11:20:30 -070040 : StreamAlsa(context, metadata, 3 /*readWriteRetries*/), mIsInput(isInput(metadata)) {
41 context->startStreamDataProcessor();
42}
Mikhail Naganovcf824f62023-07-24 14:51:36 -070043
44std::vector<alsa::DeviceProfile> StreamPrimary::getDeviceProfiles() {
45 static const std::vector<alsa::DeviceProfile> kBuiltInSource{
46 alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard,
47 .device = primary::PrimaryMixer::kAlsaDevice,
48 .direction = PCM_IN,
49 .isExternal = false}};
50 static const std::vector<alsa::DeviceProfile> kBuiltInSink{
51 alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard,
52 .device = primary::PrimaryMixer::kAlsaDevice,
53 .direction = PCM_OUT,
54 .isExternal = false}};
55 return mIsInput ? kBuiltInSource : kBuiltInSink;
56}
57
58StreamInPrimary::StreamInPrimary(StreamContext&& context, const SinkMetadata& sinkMetadata,
59 const std::vector<MicrophoneInfo>& microphones)
60 : StreamIn(std::move(context), microphones),
61 StreamSwitcher(&mContextInstance, sinkMetadata),
62 StreamInHwGainHelper(&mContextInstance) {}
63
64bool StreamInPrimary::useStubStream(const AudioDevice& device) {
65 static const bool kSimulateInput =
66 GetBoolProperty("ro.boot.audio.tinyalsa.simulate_input", false);
67 return kSimulateInput || device.type.type == AudioDeviceType::IN_TELEPHONY_RX ||
68 device.type.type == AudioDeviceType::IN_FM_TUNER ||
69 device.type.connection == AudioDeviceDescription::CONNECTION_BUS;
70}
71
72StreamSwitcher::DeviceSwitchBehavior StreamInPrimary::switchCurrentStream(
73 const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
74 LOG(DEBUG) << __func__;
75 if (devices.size() > 1) {
76 LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: "
77 << devices.size();
78 return DeviceSwitchBehavior::UNSUPPORTED_DEVICES;
79 }
80 if (devices.empty() || useStubStream(devices[0]) == isStubStream()) {
81 return DeviceSwitchBehavior::USE_CURRENT_STREAM;
82 }
83 return DeviceSwitchBehavior::CREATE_NEW_STREAM;
84}
85
86std::unique_ptr<StreamCommonInterfaceEx> StreamInPrimary::createNewStream(
87 const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
88 StreamContext* context, const Metadata& metadata) {
89 if (devices.empty()) {
90 LOG(FATAL) << __func__ << ": called with empty devices"; // see 'switchCurrentStream'
91 }
92 if (useStubStream(devices[0])) {
93 return std::unique_ptr<StreamCommonInterfaceEx>(
94 new InnerStreamWrapper<StreamStub>(context, metadata));
95 }
96 return std::unique_ptr<StreamCommonInterfaceEx>(
97 new InnerStreamWrapper<StreamPrimary>(context, metadata));
98}
99
100ndk::ScopedAStatus StreamInPrimary::getHwGain(std::vector<float>* _aidl_return) {
101 if (isStubStream()) {
102 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
103 }
104 return getHwGainImpl(_aidl_return);
105}
106
107ndk::ScopedAStatus StreamInPrimary::setHwGain(const std::vector<float>& in_channelGains) {
108 if (isStubStream()) {
109 LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelGains);
110 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
111 }
112 auto currentGains = mHwGains;
113 RETURN_STATUS_IF_ERROR(setHwGainImpl(in_channelGains));
114 if (in_channelGains.size() < 1) {
115 LOG(FATAL) << __func__ << ": unexpected gain vector size: " << in_channelGains.size();
116 }
117 if (auto status = primary::PrimaryMixer::getInstance().setMicGain(in_channelGains[0]);
118 !status.isOk()) {
119 mHwGains = currentGains;
120 return status;
121 }
122 return ndk::ScopedAStatus::ok();
123}
124
125StreamOutPrimary::StreamOutPrimary(StreamContext&& context, const SourceMetadata& sourceMetadata,
126 const std::optional<AudioOffloadInfo>& offloadInfo)
127 : StreamOut(std::move(context), offloadInfo),
128 StreamSwitcher(&mContextInstance, sourceMetadata),
129 StreamOutHwVolumeHelper(&mContextInstance) {}
130
131bool StreamOutPrimary::useStubStream(const AudioDevice& device) {
132 static const bool kSimulateOutput =
133 GetBoolProperty("ro.boot.audio.tinyalsa.ignore_output", false);
134 return kSimulateOutput || device.type.type == AudioDeviceType::OUT_TELEPHONY_TX ||
135 device.type.connection == AudioDeviceDescription::CONNECTION_BUS;
136}
137
138StreamSwitcher::DeviceSwitchBehavior StreamOutPrimary::switchCurrentStream(
139 const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
140 LOG(DEBUG) << __func__;
141 if (devices.size() > 1) {
142 LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: "
143 << devices.size();
144 return DeviceSwitchBehavior::UNSUPPORTED_DEVICES;
145 }
146 if (devices.empty() || useStubStream(devices[0]) == isStubStream()) {
147 return DeviceSwitchBehavior::USE_CURRENT_STREAM;
148 }
149 return DeviceSwitchBehavior::CREATE_NEW_STREAM;
150}
151
152std::unique_ptr<StreamCommonInterfaceEx> StreamOutPrimary::createNewStream(
153 const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
154 StreamContext* context, const Metadata& metadata) {
155 if (devices.empty()) {
156 LOG(FATAL) << __func__ << ": called with empty devices"; // see 'switchCurrentStream'
157 }
158 if (useStubStream(devices[0])) {
159 return std::unique_ptr<StreamCommonInterfaceEx>(
160 new InnerStreamWrapper<StreamStub>(context, metadata));
161 }
162 return std::unique_ptr<StreamCommonInterfaceEx>(
163 new InnerStreamWrapper<StreamPrimary>(context, metadata));
164}
165
166ndk::ScopedAStatus StreamOutPrimary::getHwVolume(std::vector<float>* _aidl_return) {
167 if (isStubStream()) {
168 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
169 }
170 return getHwVolumeImpl(_aidl_return);
171}
172
173ndk::ScopedAStatus StreamOutPrimary::setHwVolume(const std::vector<float>& in_channelVolumes) {
174 if (isStubStream()) {
175 LOG(DEBUG) << __func__ << ": volumes " << ::android::internal::ToString(in_channelVolumes);
176 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
177 }
178 auto currentVolumes = mHwVolumes;
179 RETURN_STATUS_IF_ERROR(setHwVolumeImpl(in_channelVolumes));
180 if (auto status = primary::PrimaryMixer::getInstance().setVolumes(in_channelVolumes);
181 !status.isOk()) {
182 mHwVolumes = currentVolumes;
183 return status;
184 }
185 return ndk::ScopedAStatus::ok();
186}
187
Mikhail Naganov3c8b6ce2023-10-31 11:20:30 -0700188ndk::ScopedAStatus StreamOutPrimary::setConnectedDevices(
189 const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
190 if (!devices.empty()) {
191 auto streamDataProcessor = mContextInstance.getStreamDataProcessor().lock();
192 if (streamDataProcessor != nullptr) {
193 streamDataProcessor->setAudioDevice(devices[0]);
194 }
195 }
196 return StreamSwitcher::setConnectedDevices(devices);
197}
198
Mikhail Naganovcf824f62023-07-24 14:51:36 -0700199} // namespace aidl::android::hardware::audio::core