blob: 17e1ab42f14ffab6efe88c766ac736732fa5baeb [file] [log] [blame]
jiabin253bd322023-01-25 23:57:31 +00001/*
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
Mikhail Naganov49712b52023-06-27 16:39:33 -070017#include <limits>
18
jiabin253bd322023-01-25 23:57:31 +000019#define LOG_TAG "AHAL_StreamUsb"
20#include <android-base/logging.h>
21
jiabin783c48b2023-02-28 18:28:06 +000022#include <Utils.h>
Mikhail Naganovd5554cf2023-06-21 15:20:31 -070023#include <error/expected_utils.h>
jiabin783c48b2023-02-28 18:28:06 +000024
25#include "UsbAlsaMixerControl.h"
jiabin253bd322023-01-25 23:57:31 +000026#include "UsbAlsaUtils.h"
27#include "core-impl/Module.h"
28#include "core-impl/StreamUsb.h"
29
30extern "C" {
31#include "alsa_device_profile.h"
32}
33
Mikhail Naganov872d4a62023-03-09 18:19:01 -080034using aidl::android::hardware::audio::common::getChannelCount;
jiabin253bd322023-01-25 23:57:31 +000035using aidl::android::hardware::audio::common::SinkMetadata;
36using aidl::android::hardware::audio::common::SourceMetadata;
37using aidl::android::media::audio::common::AudioDevice;
38using aidl::android::media::audio::common::AudioDeviceAddress;
39using aidl::android::media::audio::common::AudioOffloadInfo;
jiabin783c48b2023-02-28 18:28:06 +000040using aidl::android::media::audio::common::AudioPortExt;
Mikhail Naganov6725ef52023-02-09 17:52:50 -080041using aidl::android::media::audio::common::MicrophoneDynamicInfo;
42using aidl::android::media::audio::common::MicrophoneInfo;
jiabin783c48b2023-02-28 18:28:06 +000043using android::OK;
44using android::status_t;
jiabin253bd322023-01-25 23:57:31 +000045
46namespace aidl::android::hardware::audio::core {
47
Mikhail Naganovd5554cf2023-06-21 15:20:31 -070048StreamUsb::StreamUsb(const Metadata& metadata, StreamContext&& context)
49 : StreamCommonImpl(metadata, std::move(context)),
Mikhail Naganov49712b52023-06-27 16:39:33 -070050 mFrameSizeBytes(getContext().getFrameSize()),
51 mIsInput(isInput(metadata)),
52 mConfig(maybePopulateConfig(getContext(), mIsInput)) {}
53
54// static
55std::optional<struct pcm_config> StreamUsb::maybePopulateConfig(const StreamContext& context,
56 bool isInput) {
jiabin253bd322023-01-25 23:57:31 +000057 struct pcm_config config;
Mikhail Naganov49712b52023-06-27 16:39:33 -070058 config.channels = usb::getChannelCountFromChannelMask(context.getChannelLayout(), isInput);
jiabin253bd322023-01-25 23:57:31 +000059 if (config.channels == 0) {
60 LOG(ERROR) << __func__ << ": invalid channel=" << context.getChannelLayout().toString();
Mikhail Naganov49712b52023-06-27 16:39:33 -070061 return std::nullopt;
jiabin253bd322023-01-25 23:57:31 +000062 }
63 config.format = usb::aidl2legacy_AudioFormatDescription_pcm_format(context.getFormat());
64 if (config.format == PCM_FORMAT_INVALID) {
65 LOG(ERROR) << __func__ << ": invalid format=" << context.getFormat().toString();
Mikhail Naganov49712b52023-06-27 16:39:33 -070066 return std::nullopt;
jiabin253bd322023-01-25 23:57:31 +000067 }
68 config.rate = context.getSampleRate();
69 if (config.rate == 0) {
70 LOG(ERROR) << __func__ << ": invalid sample rate=" << config.rate;
Mikhail Naganov49712b52023-06-27 16:39:33 -070071 return std::nullopt;
jiabin253bd322023-01-25 23:57:31 +000072 }
Mikhail Naganov49712b52023-06-27 16:39:33 -070073 return config;
jiabin253bd322023-01-25 23:57:31 +000074}
75
Mikhail Naganovd5554cf2023-06-21 15:20:31 -070076::android::status_t StreamUsb::init() {
jiabin253bd322023-01-25 23:57:31 +000077 return mConfig.has_value() ? ::android::OK : ::android::NO_INIT;
78}
79
Mikhail Naganovd5554cf2023-06-21 15:20:31 -070080const StreamCommonInterface::ConnectedDevices& StreamUsb::getConnectedDevices() const {
81 std::lock_guard guard(mLock);
82 return mConnectedDevices;
83}
84
85ndk::ScopedAStatus StreamUsb::setConnectedDevices(
jiabin253bd322023-01-25 23:57:31 +000086 const std::vector<AudioDevice>& connectedDevices) {
87 if (mIsInput && connectedDevices.size() > 1) {
88 LOG(ERROR) << __func__ << ": wrong device size(" << connectedDevices.size()
89 << ") for input stream";
Mikhail Naganovd5554cf2023-06-21 15:20:31 -070090 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
jiabin253bd322023-01-25 23:57:31 +000091 }
92 for (const auto& connectedDevice : connectedDevices) {
93 if (connectedDevice.address.getTag() != AudioDeviceAddress::alsa) {
94 LOG(ERROR) << __func__ << ": bad device address" << connectedDevice.address.toString();
Mikhail Naganovd5554cf2023-06-21 15:20:31 -070095 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
jiabin253bd322023-01-25 23:57:31 +000096 }
97 }
98 std::lock_guard guard(mLock);
Mikhail Naganovd5554cf2023-06-21 15:20:31 -070099 RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
Mikhail Naganov49712b52023-06-27 16:39:33 -0700100 mConnectedDevicesUpdated.store(true, std::memory_order_release);
Mikhail Naganovd5554cf2023-06-21 15:20:31 -0700101 return ndk::ScopedAStatus::ok();
jiabin253bd322023-01-25 23:57:31 +0000102}
103
Mikhail Naganovd5554cf2023-06-21 15:20:31 -0700104::android::status_t StreamUsb::drain(StreamDescriptor::DrainMode) {
jiabin253bd322023-01-25 23:57:31 +0000105 usleep(1000);
106 return ::android::OK;
107}
108
Mikhail Naganovd5554cf2023-06-21 15:20:31 -0700109::android::status_t StreamUsb::flush() {
jiabin253bd322023-01-25 23:57:31 +0000110 usleep(1000);
111 return ::android::OK;
112}
113
Mikhail Naganovd5554cf2023-06-21 15:20:31 -0700114::android::status_t StreamUsb::pause() {
jiabin253bd322023-01-25 23:57:31 +0000115 usleep(1000);
116 return ::android::OK;
117}
118
Mikhail Naganovd5554cf2023-06-21 15:20:31 -0700119::android::status_t StreamUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
jiabin253bd322023-01-25 23:57:31 +0000120 int32_t* latencyMs) {
Mikhail Naganov49712b52023-06-27 16:39:33 -0700121 if (mConnectedDevicesUpdated.load(std::memory_order_acquire)) {
122 // 'setConnectedDevices' has been called. I/O will be restarted.
123 *actualFrameCount = 0;
124 *latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
125 return ::android::OK;
jiabin253bd322023-01-25 23:57:31 +0000126 }
127 const size_t bytesToTransfer = frameCount * mFrameSizeBytes;
Mikhail Naganov49712b52023-06-27 16:39:33 -0700128 unsigned maxLatency = 0;
jiabin253bd322023-01-25 23:57:31 +0000129 if (mIsInput) {
Mikhail Naganov49712b52023-06-27 16:39:33 -0700130 if (mAlsaDeviceProxies.empty()) {
131 LOG(FATAL) << __func__ << ": no input devices";
132 return ::android::NO_INIT;
133 }
jiabin253bd322023-01-25 23:57:31 +0000134 // For input case, only support single device.
Mikhail Naganov49712b52023-06-27 16:39:33 -0700135 proxy_read(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer);
136 maxLatency = proxy_get_latency(mAlsaDeviceProxies[0].get());
jiabin253bd322023-01-25 23:57:31 +0000137 } else {
Mikhail Naganov49712b52023-06-27 16:39:33 -0700138 for (auto& proxy : mAlsaDeviceProxies) {
jiabin253bd322023-01-25 23:57:31 +0000139 proxy_write(proxy.get(), buffer, bytesToTransfer);
Mikhail Naganov49712b52023-06-27 16:39:33 -0700140 maxLatency = std::max(maxLatency, proxy_get_latency(proxy.get()));
jiabin253bd322023-01-25 23:57:31 +0000141 }
142 }
143 *actualFrameCount = frameCount;
Mikhail Naganov49712b52023-06-27 16:39:33 -0700144 maxLatency = std::min(maxLatency, static_cast<unsigned>(std::numeric_limits<int32_t>::max()));
145 *latencyMs = maxLatency;
jiabin253bd322023-01-25 23:57:31 +0000146 return ::android::OK;
147}
148
Mikhail Naganovd5554cf2023-06-21 15:20:31 -0700149::android::status_t StreamUsb::standby() {
Mikhail Naganov49712b52023-06-27 16:39:33 -0700150 mAlsaDeviceProxies.clear();
jiabin253bd322023-01-25 23:57:31 +0000151 return ::android::OK;
152}
153
Mikhail Naganov49712b52023-06-27 16:39:33 -0700154void StreamUsb::shutdown() {
155 mAlsaDeviceProxies.clear();
156}
Mikhail Naganovd5554cf2023-06-21 15:20:31 -0700157
Mikhail Naganov49712b52023-06-27 16:39:33 -0700158::android::status_t StreamUsb::start() {
jiabin253bd322023-01-25 23:57:31 +0000159 std::vector<AudioDeviceAddress> connectedDevices;
160 {
161 std::lock_guard guard(mLock);
Mikhail Naganovd5554cf2023-06-21 15:20:31 -0700162 std::transform(mConnectedDevices.begin(), mConnectedDevices.end(),
163 std::back_inserter(connectedDevices),
164 [](const auto& device) { return device.address; });
Mikhail Naganov49712b52023-06-27 16:39:33 -0700165 mConnectedDevicesUpdated.store(false, std::memory_order_release);
jiabin253bd322023-01-25 23:57:31 +0000166 }
Mikhail Naganov49712b52023-06-27 16:39:33 -0700167 decltype(mAlsaDeviceProxies) alsaDeviceProxies;
jiabin253bd322023-01-25 23:57:31 +0000168 for (const auto& device : connectedDevices) {
169 alsa_device_profile profile;
jiabinfdee3222023-03-22 22:16:13 +0000170 profile_init(&profile, mIsInput ? PCM_IN : PCM_OUT);
jiabin253bd322023-01-25 23:57:31 +0000171 profile.card = device.get<AudioDeviceAddress::alsa>()[0];
172 profile.device = device.get<AudioDeviceAddress::alsa>()[1];
173 if (!profile_read_device_info(&profile)) {
174 LOG(ERROR) << __func__
175 << ": unable to read device info, device address=" << device.toString();
176 return ::android::UNKNOWN_ERROR;
177 }
178
Mikhail Naganov49712b52023-06-27 16:39:33 -0700179 AlsaDeviceProxy proxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) {
180 proxy_close(proxy);
181 free(proxy);
182 });
jiabin253bd322023-01-25 23:57:31 +0000183 // Always ask for alsa configure as required since the configuration should be supported
184 // by the connected device. That is guaranteed by `setAudioPortConfig` and
185 // `setAudioPatch`.
Mikhail Naganov49712b52023-06-27 16:39:33 -0700186 if (int err = proxy_prepare(proxy.get(), &profile,
187 const_cast<struct pcm_config*>(&mConfig.value()),
188 true /*is_bit_perfect*/);
jiabin253bd322023-01-25 23:57:31 +0000189 err != 0) {
190 LOG(ERROR) << __func__ << ": fail to prepare for device address=" << device.toString()
191 << " error=" << err;
192 return ::android::UNKNOWN_ERROR;
193 }
jiabinfdee3222023-03-22 22:16:13 +0000194 if (int err = proxy_open(proxy.get()); err != 0) {
195 LOG(ERROR) << __func__ << ": failed to open device, address=" << device.toString()
196 << " error=" << err;
197 return ::android::UNKNOWN_ERROR;
198 }
jiabin253bd322023-01-25 23:57:31 +0000199 alsaDeviceProxies.push_back(std::move(proxy));
200 }
Mikhail Naganov49712b52023-06-27 16:39:33 -0700201 mAlsaDeviceProxies = std::move(alsaDeviceProxies);
jiabin253bd322023-01-25 23:57:31 +0000202 return ::android::OK;
203}
204
jiabin253bd322023-01-25 23:57:31 +0000205StreamInUsb::StreamInUsb(const SinkMetadata& sinkMetadata, StreamContext&& context,
206 const std::vector<MicrophoneInfo>& microphones)
Mikhail Naganovd5554cf2023-06-21 15:20:31 -0700207 : StreamUsb(sinkMetadata, std::move(context)), StreamIn(microphones) {}
jiabin253bd322023-01-25 23:57:31 +0000208
209ndk::ScopedAStatus StreamInUsb::getActiveMicrophones(
210 std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
211 LOG(DEBUG) << __func__ << ": not supported";
212 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
213}
214
jiabin253bd322023-01-25 23:57:31 +0000215StreamOutUsb::StreamOutUsb(const SourceMetadata& sourceMetadata, StreamContext&& context,
216 const std::optional<AudioOffloadInfo>& offloadInfo)
Mikhail Naganovd5554cf2023-06-21 15:20:31 -0700217 : StreamUsb(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {
218 mChannelCount = getChannelCount(getContext().getChannelLayout());
jiabin783c48b2023-02-28 18:28:06 +0000219}
220
221ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector<float>* _aidl_return) {
222 *_aidl_return = mHwVolumes;
223 return ndk::ScopedAStatus::ok();
224}
225
226ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector<float>& in_channelVolumes) {
Mikhail Naganovd5554cf2023-06-21 15:20:31 -0700227 for (const auto& device : getConnectedDevices()) {
jiabin783c48b2023-02-28 18:28:06 +0000228 if (device.address.getTag() != AudioDeviceAddress::alsa) {
229 LOG(DEBUG) << __func__ << ": skip as the device address is not alsa";
230 continue;
231 }
232 const int card = device.address.get<AudioDeviceAddress::alsa>()[0];
233 if (auto result =
234 usb::UsbAlsaMixerControl::getInstance().setVolumes(card, in_channelVolumes);
235 !result.isOk()) {
236 LOG(ERROR) << __func__ << ": failed to set volume for device, card=" << card;
237 return result;
238 }
239 }
240 mHwVolumes = in_channelVolumes;
241 return ndk::ScopedAStatus::ok();
242}
jiabin253bd322023-01-25 23:57:31 +0000243
Mikhail Naganov6725ef52023-02-09 17:52:50 -0800244} // namespace aidl::android::hardware::audio::core