xref: /aosp_15_r20/hardware/interfaces/audio/aidl/default/primary/StreamPrimary.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker  * Copyright (C) 2023 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker  *
4*4d7e907cSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker  *
8*4d7e907cSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker  *
10*4d7e907cSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker  * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker  */
16*4d7e907cSAndroid Build Coastguard Worker 
17*4d7e907cSAndroid Build Coastguard Worker #define LOG_TAG "AHAL_StreamPrimary"
18*4d7e907cSAndroid Build Coastguard Worker 
19*4d7e907cSAndroid Build Coastguard Worker #include <cstdio>
20*4d7e907cSAndroid Build Coastguard Worker 
21*4d7e907cSAndroid Build Coastguard Worker #include <android-base/logging.h>
22*4d7e907cSAndroid Build Coastguard Worker #include <android-base/parseint.h>
23*4d7e907cSAndroid Build Coastguard Worker #include <android-base/properties.h>
24*4d7e907cSAndroid Build Coastguard Worker #include <audio_utils/clock.h>
25*4d7e907cSAndroid Build Coastguard Worker #include <error/Result.h>
26*4d7e907cSAndroid Build Coastguard Worker #include <error/expected_utils.h>
27*4d7e907cSAndroid Build Coastguard Worker 
28*4d7e907cSAndroid Build Coastguard Worker #include "core-impl/StreamPrimary.h"
29*4d7e907cSAndroid Build Coastguard Worker 
30*4d7e907cSAndroid Build Coastguard Worker using aidl::android::hardware::audio::common::SinkMetadata;
31*4d7e907cSAndroid Build Coastguard Worker using aidl::android::hardware::audio::common::SourceMetadata;
32*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioDevice;
33*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioDeviceAddress;
34*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioDeviceDescription;
35*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioDeviceType;
36*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioOffloadInfo;
37*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::MicrophoneInfo;
38*4d7e907cSAndroid Build Coastguard Worker using android::base::GetBoolProperty;
39*4d7e907cSAndroid Build Coastguard Worker 
40*4d7e907cSAndroid Build Coastguard Worker namespace aidl::android::hardware::audio::core {
41*4d7e907cSAndroid Build Coastguard Worker 
StreamPrimary(StreamContext * context,const Metadata & metadata)42*4d7e907cSAndroid Build Coastguard Worker StreamPrimary::StreamPrimary(StreamContext* context, const Metadata& metadata)
43*4d7e907cSAndroid Build Coastguard Worker     : StreamAlsa(context, metadata, 3 /*readWriteRetries*/),
44*4d7e907cSAndroid Build Coastguard Worker       mIsAsynchronous(!!getContext().getAsyncCallback()),
45*4d7e907cSAndroid Build Coastguard Worker       mStubDriver(getContext()) {
46*4d7e907cSAndroid Build Coastguard Worker     context->startStreamDataProcessor();
47*4d7e907cSAndroid Build Coastguard Worker }
48*4d7e907cSAndroid Build Coastguard Worker 
init()49*4d7e907cSAndroid Build Coastguard Worker ::android::status_t StreamPrimary::init() {
50*4d7e907cSAndroid Build Coastguard Worker     RETURN_STATUS_IF_ERROR(mStubDriver.init());
51*4d7e907cSAndroid Build Coastguard Worker     return StreamAlsa::init();
52*4d7e907cSAndroid Build Coastguard Worker }
53*4d7e907cSAndroid Build Coastguard Worker 
drain(StreamDescriptor::DrainMode mode)54*4d7e907cSAndroid Build Coastguard Worker ::android::status_t StreamPrimary::drain(StreamDescriptor::DrainMode mode) {
55*4d7e907cSAndroid Build Coastguard Worker     return isStubStreamOnWorker() ? mStubDriver.drain(mode) : StreamAlsa::drain(mode);
56*4d7e907cSAndroid Build Coastguard Worker }
57*4d7e907cSAndroid Build Coastguard Worker 
flush()58*4d7e907cSAndroid Build Coastguard Worker ::android::status_t StreamPrimary::flush() {
59*4d7e907cSAndroid Build Coastguard Worker     RETURN_STATUS_IF_ERROR(isStubStreamOnWorker() ? mStubDriver.flush() : StreamAlsa::flush());
60*4d7e907cSAndroid Build Coastguard Worker     // TODO(b/372951987): consider if this needs to be done from 'StreamInWorkerLogic::cycle'.
61*4d7e907cSAndroid Build Coastguard Worker     return mIsInput ? standby() : ::android::OK;
62*4d7e907cSAndroid Build Coastguard Worker }
63*4d7e907cSAndroid Build Coastguard Worker 
pause()64*4d7e907cSAndroid Build Coastguard Worker ::android::status_t StreamPrimary::pause() {
65*4d7e907cSAndroid Build Coastguard Worker     return isStubStreamOnWorker() ? mStubDriver.pause() : StreamAlsa::pause();
66*4d7e907cSAndroid Build Coastguard Worker }
67*4d7e907cSAndroid Build Coastguard Worker 
standby()68*4d7e907cSAndroid Build Coastguard Worker ::android::status_t StreamPrimary::standby() {
69*4d7e907cSAndroid Build Coastguard Worker     return isStubStreamOnWorker() ? mStubDriver.standby() : StreamAlsa::standby();
70*4d7e907cSAndroid Build Coastguard Worker }
71*4d7e907cSAndroid Build Coastguard Worker 
start()72*4d7e907cSAndroid Build Coastguard Worker ::android::status_t StreamPrimary::start() {
73*4d7e907cSAndroid Build Coastguard Worker     bool isStub = true, shutdownAlsaStream = false;
74*4d7e907cSAndroid Build Coastguard Worker     {
75*4d7e907cSAndroid Build Coastguard Worker         std::lock_guard l(mLock);
76*4d7e907cSAndroid Build Coastguard Worker         isStub = mAlsaDeviceId == kStubDeviceId;
77*4d7e907cSAndroid Build Coastguard Worker         shutdownAlsaStream =
78*4d7e907cSAndroid Build Coastguard Worker                 mCurrAlsaDeviceId != mAlsaDeviceId && mCurrAlsaDeviceId != kStubDeviceId;
79*4d7e907cSAndroid Build Coastguard Worker         mCurrAlsaDeviceId = mAlsaDeviceId;
80*4d7e907cSAndroid Build Coastguard Worker     }
81*4d7e907cSAndroid Build Coastguard Worker     if (shutdownAlsaStream) {
82*4d7e907cSAndroid Build Coastguard Worker         StreamAlsa::shutdown();  // Close currently opened ALSA devices.
83*4d7e907cSAndroid Build Coastguard Worker     }
84*4d7e907cSAndroid Build Coastguard Worker     if (isStub) {
85*4d7e907cSAndroid Build Coastguard Worker         return mStubDriver.start();
86*4d7e907cSAndroid Build Coastguard Worker     }
87*4d7e907cSAndroid Build Coastguard Worker     RETURN_STATUS_IF_ERROR(StreamAlsa::start());
88*4d7e907cSAndroid Build Coastguard Worker     mStartTimeNs = ::android::uptimeNanos();
89*4d7e907cSAndroid Build Coastguard Worker     mFramesSinceStart = 0;
90*4d7e907cSAndroid Build Coastguard Worker     mSkipNextTransfer = false;
91*4d7e907cSAndroid Build Coastguard Worker     return ::android::OK;
92*4d7e907cSAndroid Build Coastguard Worker }
93*4d7e907cSAndroid Build Coastguard Worker 
transfer(void * buffer,size_t frameCount,size_t * actualFrameCount,int32_t * latencyMs)94*4d7e907cSAndroid Build Coastguard Worker ::android::status_t StreamPrimary::transfer(void* buffer, size_t frameCount,
95*4d7e907cSAndroid Build Coastguard Worker                                             size_t* actualFrameCount, int32_t* latencyMs) {
96*4d7e907cSAndroid Build Coastguard Worker     if (isStubStreamOnWorker()) {
97*4d7e907cSAndroid Build Coastguard Worker         return mStubDriver.transfer(buffer, frameCount, actualFrameCount, latencyMs);
98*4d7e907cSAndroid Build Coastguard Worker     }
99*4d7e907cSAndroid Build Coastguard Worker     // This is a workaround for the emulator implementation which has a host-side buffer
100*4d7e907cSAndroid Build Coastguard Worker     // and is not being able to achieve real-time behavior similar to ADSPs (b/302587331).
101*4d7e907cSAndroid Build Coastguard Worker     if (!mSkipNextTransfer) {
102*4d7e907cSAndroid Build Coastguard Worker         RETURN_STATUS_IF_ERROR(
103*4d7e907cSAndroid Build Coastguard Worker                 StreamAlsa::transfer(buffer, frameCount, actualFrameCount, latencyMs));
104*4d7e907cSAndroid Build Coastguard Worker     } else {
105*4d7e907cSAndroid Build Coastguard Worker         LOG(DEBUG) << __func__ << ": skipping transfer (" << frameCount << " frames)";
106*4d7e907cSAndroid Build Coastguard Worker         *actualFrameCount = frameCount;
107*4d7e907cSAndroid Build Coastguard Worker         if (mIsInput) memset(buffer, 0, frameCount * mFrameSizeBytes);
108*4d7e907cSAndroid Build Coastguard Worker         mSkipNextTransfer = false;
109*4d7e907cSAndroid Build Coastguard Worker     }
110*4d7e907cSAndroid Build Coastguard Worker     if (!mIsAsynchronous) {
111*4d7e907cSAndroid Build Coastguard Worker         const long bufferDurationUs =
112*4d7e907cSAndroid Build Coastguard Worker                 (*actualFrameCount) * MICROS_PER_SECOND / mContext.getSampleRate();
113*4d7e907cSAndroid Build Coastguard Worker         const auto totalDurationUs =
114*4d7e907cSAndroid Build Coastguard Worker                 (::android::uptimeNanos() - mStartTimeNs) / NANOS_PER_MICROSECOND;
115*4d7e907cSAndroid Build Coastguard Worker         mFramesSinceStart += *actualFrameCount;
116*4d7e907cSAndroid Build Coastguard Worker         const long totalOffsetUs =
117*4d7e907cSAndroid Build Coastguard Worker                 mFramesSinceStart * MICROS_PER_SECOND / mContext.getSampleRate() - totalDurationUs;
118*4d7e907cSAndroid Build Coastguard Worker         LOG(VERBOSE) << __func__ << ": totalOffsetUs " << totalOffsetUs;
119*4d7e907cSAndroid Build Coastguard Worker         if (totalOffsetUs > 0) {
120*4d7e907cSAndroid Build Coastguard Worker             const long sleepTimeUs = std::min(totalOffsetUs, bufferDurationUs);
121*4d7e907cSAndroid Build Coastguard Worker             LOG(VERBOSE) << __func__ << ": sleeping for " << sleepTimeUs << " us";
122*4d7e907cSAndroid Build Coastguard Worker             usleep(sleepTimeUs);
123*4d7e907cSAndroid Build Coastguard Worker         } else {
124*4d7e907cSAndroid Build Coastguard Worker             mSkipNextTransfer = true;
125*4d7e907cSAndroid Build Coastguard Worker         }
126*4d7e907cSAndroid Build Coastguard Worker     } else {
127*4d7e907cSAndroid Build Coastguard Worker         LOG(VERBOSE) << __func__ << ": asynchronous transfer";
128*4d7e907cSAndroid Build Coastguard Worker     }
129*4d7e907cSAndroid Build Coastguard Worker     return ::android::OK;
130*4d7e907cSAndroid Build Coastguard Worker }
131*4d7e907cSAndroid Build Coastguard Worker 
refinePosition(StreamDescriptor::Position *)132*4d7e907cSAndroid Build Coastguard Worker ::android::status_t StreamPrimary::refinePosition(StreamDescriptor::Position*) {
133*4d7e907cSAndroid Build Coastguard Worker     // Since not all data is actually sent to the HAL, use the position maintained by Stream class
134*4d7e907cSAndroid Build Coastguard Worker     // which accounts for all frames passed from / to the client.
135*4d7e907cSAndroid Build Coastguard Worker     return ::android::OK;
136*4d7e907cSAndroid Build Coastguard Worker }
137*4d7e907cSAndroid Build Coastguard Worker 
shutdown()138*4d7e907cSAndroid Build Coastguard Worker void StreamPrimary::shutdown() {
139*4d7e907cSAndroid Build Coastguard Worker     StreamAlsa::shutdown();
140*4d7e907cSAndroid Build Coastguard Worker     mStubDriver.shutdown();
141*4d7e907cSAndroid Build Coastguard Worker }
142*4d7e907cSAndroid Build Coastguard Worker 
setConnectedDevices(const ConnectedDevices & devices)143*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus StreamPrimary::setConnectedDevices(const ConnectedDevices& devices) {
144*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(devices);
145*4d7e907cSAndroid Build Coastguard Worker     if (devices.size() > 1) {
146*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: "
147*4d7e907cSAndroid Build Coastguard Worker                    << devices.size();
148*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
149*4d7e907cSAndroid Build Coastguard Worker     }
150*4d7e907cSAndroid Build Coastguard Worker     {
151*4d7e907cSAndroid Build Coastguard Worker         const bool useStubDriver = devices.empty() || useStubStream(mIsInput, devices[0]);
152*4d7e907cSAndroid Build Coastguard Worker         std::lock_guard l(mLock);
153*4d7e907cSAndroid Build Coastguard Worker         mAlsaDeviceId = useStubDriver ? kStubDeviceId : getCardAndDeviceId(devices);
154*4d7e907cSAndroid Build Coastguard Worker     }
155*4d7e907cSAndroid Build Coastguard Worker     if (!devices.empty()) {
156*4d7e907cSAndroid Build Coastguard Worker         auto streamDataProcessor = getContext().getStreamDataProcessor().lock();
157*4d7e907cSAndroid Build Coastguard Worker         if (streamDataProcessor != nullptr) {
158*4d7e907cSAndroid Build Coastguard Worker             streamDataProcessor->setAudioDevice(devices[0]);
159*4d7e907cSAndroid Build Coastguard Worker         }
160*4d7e907cSAndroid Build Coastguard Worker     }
161*4d7e907cSAndroid Build Coastguard Worker     return StreamAlsa::setConnectedDevices(devices);
162*4d7e907cSAndroid Build Coastguard Worker }
163*4d7e907cSAndroid Build Coastguard Worker 
getDeviceProfiles()164*4d7e907cSAndroid Build Coastguard Worker std::vector<alsa::DeviceProfile> StreamPrimary::getDeviceProfiles() {
165*4d7e907cSAndroid Build Coastguard Worker     return {alsa::DeviceProfile{.card = mCurrAlsaDeviceId.first,
166*4d7e907cSAndroid Build Coastguard Worker                                 .device = mCurrAlsaDeviceId.second,
167*4d7e907cSAndroid Build Coastguard Worker                                 .direction = mIsInput ? PCM_IN : PCM_OUT,
168*4d7e907cSAndroid Build Coastguard Worker                                 .isExternal = false}};
169*4d7e907cSAndroid Build Coastguard Worker }
170*4d7e907cSAndroid Build Coastguard Worker 
isStubStream()171*4d7e907cSAndroid Build Coastguard Worker bool StreamPrimary::isStubStream() {
172*4d7e907cSAndroid Build Coastguard Worker     std::lock_guard l(mLock);
173*4d7e907cSAndroid Build Coastguard Worker     return mAlsaDeviceId == kStubDeviceId;
174*4d7e907cSAndroid Build Coastguard Worker }
175*4d7e907cSAndroid Build Coastguard Worker 
176*4d7e907cSAndroid Build Coastguard Worker // static
getCardAndDeviceId(const std::vector<AudioDevice> & devices)177*4d7e907cSAndroid Build Coastguard Worker StreamPrimary::AlsaDeviceId StreamPrimary::getCardAndDeviceId(
178*4d7e907cSAndroid Build Coastguard Worker         const std::vector<AudioDevice>& devices) {
179*4d7e907cSAndroid Build Coastguard Worker     if (devices.empty() || devices[0].address.getTag() != AudioDeviceAddress::id) {
180*4d7e907cSAndroid Build Coastguard Worker         return kDefaultCardAndDeviceId;
181*4d7e907cSAndroid Build Coastguard Worker     }
182*4d7e907cSAndroid Build Coastguard Worker     std::string deviceAddress = devices[0].address.get<AudioDeviceAddress::id>();
183*4d7e907cSAndroid Build Coastguard Worker     AlsaDeviceId cardAndDeviceId;
184*4d7e907cSAndroid Build Coastguard Worker     if (const size_t suffixPos = deviceAddress.rfind("CARD_");
185*4d7e907cSAndroid Build Coastguard Worker         suffixPos == std::string::npos ||
186*4d7e907cSAndroid Build Coastguard Worker         sscanf(deviceAddress.c_str() + suffixPos, "CARD_%d_DEV_%d", &cardAndDeviceId.first,
187*4d7e907cSAndroid Build Coastguard Worker                &cardAndDeviceId.second) != 2) {
188*4d7e907cSAndroid Build Coastguard Worker         return kDefaultCardAndDeviceId;
189*4d7e907cSAndroid Build Coastguard Worker     }
190*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << __func__ << ": parsed with card id " << cardAndDeviceId.first << ", device id "
191*4d7e907cSAndroid Build Coastguard Worker                << cardAndDeviceId.second;
192*4d7e907cSAndroid Build Coastguard Worker     return cardAndDeviceId;
193*4d7e907cSAndroid Build Coastguard Worker }
194*4d7e907cSAndroid Build Coastguard Worker 
195*4d7e907cSAndroid Build Coastguard Worker // static
useStubStream(bool isInput,const::aidl::android::media::audio::common::AudioDevice & device)196*4d7e907cSAndroid Build Coastguard Worker bool StreamPrimary::useStubStream(
197*4d7e907cSAndroid Build Coastguard Worker         bool isInput, const ::aidl::android::media::audio::common::AudioDevice& device) {
198*4d7e907cSAndroid Build Coastguard Worker     static const bool kSimulateInput =
199*4d7e907cSAndroid Build Coastguard Worker             GetBoolProperty("ro.boot.audio.tinyalsa.simulate_input", false);
200*4d7e907cSAndroid Build Coastguard Worker     static const bool kSimulateOutput =
201*4d7e907cSAndroid Build Coastguard Worker             GetBoolProperty("ro.boot.audio.tinyalsa.ignore_output", false);
202*4d7e907cSAndroid Build Coastguard Worker     if (isInput) {
203*4d7e907cSAndroid Build Coastguard Worker         return kSimulateInput || device.type.type == AudioDeviceType::IN_TELEPHONY_RX ||
204*4d7e907cSAndroid Build Coastguard Worker                device.type.type == AudioDeviceType::IN_FM_TUNER ||
205*4d7e907cSAndroid Build Coastguard Worker                device.type.connection == AudioDeviceDescription::CONNECTION_BUS /*deprecated */;
206*4d7e907cSAndroid Build Coastguard Worker     }
207*4d7e907cSAndroid Build Coastguard Worker     return kSimulateOutput || device.type.type == AudioDeviceType::OUT_TELEPHONY_TX ||
208*4d7e907cSAndroid Build Coastguard Worker            device.type.connection == AudioDeviceDescription::CONNECTION_BUS /*deprecated*/;
209*4d7e907cSAndroid Build Coastguard Worker }
210*4d7e907cSAndroid Build Coastguard Worker 
StreamInPrimary(StreamContext && context,const SinkMetadata & sinkMetadata,const std::vector<MicrophoneInfo> & microphones)211*4d7e907cSAndroid Build Coastguard Worker StreamInPrimary::StreamInPrimary(StreamContext&& context, const SinkMetadata& sinkMetadata,
212*4d7e907cSAndroid Build Coastguard Worker                                  const std::vector<MicrophoneInfo>& microphones)
213*4d7e907cSAndroid Build Coastguard Worker     : StreamIn(std::move(context), microphones),
214*4d7e907cSAndroid Build Coastguard Worker       StreamPrimary(&mContextInstance, sinkMetadata),
215*4d7e907cSAndroid Build Coastguard Worker       StreamInHwGainHelper(&mContextInstance) {}
216*4d7e907cSAndroid Build Coastguard Worker 
getHwGain(std::vector<float> * _aidl_return)217*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus StreamInPrimary::getHwGain(std::vector<float>* _aidl_return) {
218*4d7e907cSAndroid Build Coastguard Worker     if (isStubStream()) {
219*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
220*4d7e907cSAndroid Build Coastguard Worker     }
221*4d7e907cSAndroid Build Coastguard Worker     if (mHwGains.empty()) {
222*4d7e907cSAndroid Build Coastguard Worker         float gain;
223*4d7e907cSAndroid Build Coastguard Worker         RETURN_STATUS_IF_ERROR(primary::PrimaryMixer::getInstance().getMicGain(&gain));
224*4d7e907cSAndroid Build Coastguard Worker         _aidl_return->resize(mChannelCount, gain);
225*4d7e907cSAndroid Build Coastguard Worker         RETURN_STATUS_IF_ERROR(setHwGainImpl(*_aidl_return));
226*4d7e907cSAndroid Build Coastguard Worker     }
227*4d7e907cSAndroid Build Coastguard Worker     return getHwGainImpl(_aidl_return);
228*4d7e907cSAndroid Build Coastguard Worker }
229*4d7e907cSAndroid Build Coastguard Worker 
setHwGain(const std::vector<float> & in_channelGains)230*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus StreamInPrimary::setHwGain(const std::vector<float>& in_channelGains) {
231*4d7e907cSAndroid Build Coastguard Worker     if (isStubStream()) {
232*4d7e907cSAndroid Build Coastguard Worker         LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelGains);
233*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
234*4d7e907cSAndroid Build Coastguard Worker     }
235*4d7e907cSAndroid Build Coastguard Worker     auto currentGains = mHwGains;
236*4d7e907cSAndroid Build Coastguard Worker     RETURN_STATUS_IF_ERROR(setHwGainImpl(in_channelGains));
237*4d7e907cSAndroid Build Coastguard Worker     if (in_channelGains.size() < 1) {
238*4d7e907cSAndroid Build Coastguard Worker         LOG(FATAL) << __func__ << ": unexpected gain vector size: " << in_channelGains.size();
239*4d7e907cSAndroid Build Coastguard Worker     }
240*4d7e907cSAndroid Build Coastguard Worker     if (auto status = primary::PrimaryMixer::getInstance().setMicGain(in_channelGains[0]);
241*4d7e907cSAndroid Build Coastguard Worker         !status.isOk()) {
242*4d7e907cSAndroid Build Coastguard Worker         mHwGains = currentGains;
243*4d7e907cSAndroid Build Coastguard Worker         return status;
244*4d7e907cSAndroid Build Coastguard Worker     }
245*4d7e907cSAndroid Build Coastguard Worker     float gain;
246*4d7e907cSAndroid Build Coastguard Worker     RETURN_STATUS_IF_ERROR(primary::PrimaryMixer::getInstance().getMicGain(&gain));
247*4d7e907cSAndroid Build Coastguard Worker     // Due to rounding errors, round trip conversions between percents and indexed values may not
248*4d7e907cSAndroid Build Coastguard Worker     // match.
249*4d7e907cSAndroid Build Coastguard Worker     if (gain != in_channelGains[0]) {
250*4d7e907cSAndroid Build Coastguard Worker         LOG(WARNING) << __func__ << ": unmatched gain: set: " << in_channelGains[0]
251*4d7e907cSAndroid Build Coastguard Worker                      << ", from mixer: " << gain;
252*4d7e907cSAndroid Build Coastguard Worker     }
253*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
254*4d7e907cSAndroid Build Coastguard Worker }
255*4d7e907cSAndroid Build Coastguard Worker 
StreamOutPrimary(StreamContext && context,const SourceMetadata & sourceMetadata,const std::optional<AudioOffloadInfo> & offloadInfo)256*4d7e907cSAndroid Build Coastguard Worker StreamOutPrimary::StreamOutPrimary(StreamContext&& context, const SourceMetadata& sourceMetadata,
257*4d7e907cSAndroid Build Coastguard Worker                                    const std::optional<AudioOffloadInfo>& offloadInfo)
258*4d7e907cSAndroid Build Coastguard Worker     : StreamOut(std::move(context), offloadInfo),
259*4d7e907cSAndroid Build Coastguard Worker       StreamPrimary(&mContextInstance, sourceMetadata),
260*4d7e907cSAndroid Build Coastguard Worker       StreamOutHwVolumeHelper(&mContextInstance) {}
261*4d7e907cSAndroid Build Coastguard Worker 
getHwVolume(std::vector<float> * _aidl_return)262*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus StreamOutPrimary::getHwVolume(std::vector<float>* _aidl_return) {
263*4d7e907cSAndroid Build Coastguard Worker     if (isStubStream()) {
264*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
265*4d7e907cSAndroid Build Coastguard Worker     }
266*4d7e907cSAndroid Build Coastguard Worker     if (mHwVolumes.empty()) {
267*4d7e907cSAndroid Build Coastguard Worker         RETURN_STATUS_IF_ERROR(primary::PrimaryMixer::getInstance().getVolumes(_aidl_return));
268*4d7e907cSAndroid Build Coastguard Worker         _aidl_return->resize(mChannelCount);
269*4d7e907cSAndroid Build Coastguard Worker         RETURN_STATUS_IF_ERROR(setHwVolumeImpl(*_aidl_return));
270*4d7e907cSAndroid Build Coastguard Worker     }
271*4d7e907cSAndroid Build Coastguard Worker     return getHwVolumeImpl(_aidl_return);
272*4d7e907cSAndroid Build Coastguard Worker }
273*4d7e907cSAndroid Build Coastguard Worker 
setHwVolume(const std::vector<float> & in_channelVolumes)274*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus StreamOutPrimary::setHwVolume(const std::vector<float>& in_channelVolumes) {
275*4d7e907cSAndroid Build Coastguard Worker     if (isStubStream()) {
276*4d7e907cSAndroid Build Coastguard Worker         LOG(DEBUG) << __func__ << ": volumes " << ::android::internal::ToString(in_channelVolumes);
277*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
278*4d7e907cSAndroid Build Coastguard Worker     }
279*4d7e907cSAndroid Build Coastguard Worker     auto currentVolumes = mHwVolumes;
280*4d7e907cSAndroid Build Coastguard Worker     RETURN_STATUS_IF_ERROR(setHwVolumeImpl(in_channelVolumes));
281*4d7e907cSAndroid Build Coastguard Worker     if (auto status = primary::PrimaryMixer::getInstance().setVolumes(in_channelVolumes);
282*4d7e907cSAndroid Build Coastguard Worker         !status.isOk()) {
283*4d7e907cSAndroid Build Coastguard Worker         mHwVolumes = currentVolumes;
284*4d7e907cSAndroid Build Coastguard Worker         return status;
285*4d7e907cSAndroid Build Coastguard Worker     }
286*4d7e907cSAndroid Build Coastguard Worker     std::vector<float> volumes;
287*4d7e907cSAndroid Build Coastguard Worker     RETURN_STATUS_IF_ERROR(primary::PrimaryMixer::getInstance().getVolumes(&volumes));
288*4d7e907cSAndroid Build Coastguard Worker     // Due to rounding errors, round trip conversions between percents and indexed values may not
289*4d7e907cSAndroid Build Coastguard Worker     // match.
290*4d7e907cSAndroid Build Coastguard Worker     if (volumes != in_channelVolumes) {
291*4d7e907cSAndroid Build Coastguard Worker         LOG(WARNING) << __func__ << ": unmatched volumes: set: "
292*4d7e907cSAndroid Build Coastguard Worker                      << ::android::internal::ToString(in_channelVolumes)
293*4d7e907cSAndroid Build Coastguard Worker                      << ", from mixer: " << ::android::internal::ToString(volumes);
294*4d7e907cSAndroid Build Coastguard Worker     }
295*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
296*4d7e907cSAndroid Build Coastguard Worker }
297*4d7e907cSAndroid Build Coastguard Worker 
298*4d7e907cSAndroid Build Coastguard Worker }  // namespace aidl::android::hardware::audio::core
299