blob: e8034209d8acae3a504258580d6d3c45e1001594 [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
17#define LOG_TAG "AHAL_ModuleUsb"
18
19#include <vector>
20
21#include <Utils.h>
22#include <android-base/logging.h>
23#include <tinyalsa/asoundlib.h>
24
25#include "UsbAlsaUtils.h"
26#include "core-impl/ModuleUsb.h"
27
28extern "C" {
29#include "alsa_device_profile.h"
30}
31
32using aidl::android::media::audio::common::AudioChannelLayout;
33using aidl::android::media::audio::common::AudioDeviceAddress;
34using aidl::android::media::audio::common::AudioDeviceDescription;
35using aidl::android::media::audio::common::AudioDeviceType;
36using aidl::android::media::audio::common::AudioFormatDescription;
37using aidl::android::media::audio::common::AudioFormatType;
38using aidl::android::media::audio::common::AudioPort;
39using aidl::android::media::audio::common::AudioPortConfig;
40using aidl::android::media::audio::common::AudioPortExt;
41using aidl::android::media::audio::common::AudioProfile;
42using android::hardware::audio::common::isUsbInputDeviceType;
43
44namespace aidl::android::hardware::audio::core {
45
46namespace {
47
48std::vector<AudioChannelLayout> populateChannelMasksFromProfile(const alsa_device_profile* profile,
49 bool isInput) {
50 std::vector<AudioChannelLayout> channels;
51 for (size_t i = 0; i < AUDIO_PORT_MAX_CHANNEL_MASKS && profile->channel_counts[i] != 0; ++i) {
52 auto layoutMask =
53 usb::getChannelLayoutMaskFromChannelCount(profile->channel_counts[i], isInput);
54 if (layoutMask.getTag() == AudioChannelLayout::Tag::layoutMask) {
55 channels.push_back(layoutMask);
56 }
57 auto indexMask = usb::getChannelIndexMaskFromChannelCount(profile->channel_counts[i]);
58 if (indexMask.getTag() == AudioChannelLayout::Tag::indexMask) {
59 channels.push_back(indexMask);
60 }
61 }
62 return channels;
63}
64
65std::vector<int> populateSampleRatesFromProfile(const alsa_device_profile* profile) {
66 std::vector<int> sampleRates;
67 for (int i = 0; i < std::min(MAX_PROFILE_SAMPLE_RATES, AUDIO_PORT_MAX_SAMPLING_RATES) &&
68 profile->sample_rates[i] != 0;
69 i++) {
70 sampleRates.push_back(profile->sample_rates[i]);
71 }
72 return sampleRates;
73}
74
75} // namespace
76
77ndk::ScopedAStatus ModuleUsb::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
78 *_aidl_return = nullptr;
79 LOG(DEBUG) << __func__ << ": returning null";
80 return ndk::ScopedAStatus::ok();
81}
82
83ndk::ScopedAStatus ModuleUsb::getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) {
84 *_aidl_return = nullptr;
85 LOG(DEBUG) << __func__ << ": returning null";
86 return ndk::ScopedAStatus::ok();
87}
88
89ndk::ScopedAStatus ModuleUsb::getMasterMute(bool* _aidl_return __unused) {
90 LOG(DEBUG) << __func__ << ": is not supported";
91 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
92}
93
94ndk::ScopedAStatus ModuleUsb::setMasterMute(bool in_mute __unused) {
95 LOG(DEBUG) << __func__ << ": is not supported";
96 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
97}
98
99ndk::ScopedAStatus ModuleUsb::getMasterVolume(float* _aidl_return __unused) {
100 LOG(DEBUG) << __func__ << ": is not supported";
101 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
102}
103
104ndk::ScopedAStatus ModuleUsb::setMasterVolume(float in_volume __unused) {
105 LOG(DEBUG) << __func__ << ": is not supported";
106 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
107}
108
109ndk::ScopedAStatus ModuleUsb::getMicMute(bool* _aidl_return __unused) {
110 LOG(DEBUG) << __func__ << ": is not supported";
111 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
112}
113
114ndk::ScopedAStatus ModuleUsb::setMicMute(bool in_mute __unused) {
115 LOG(DEBUG) << __func__ << ": is not supported";
116 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
117}
118
119ndk::ScopedAStatus ModuleUsb::populateConnectedDevicePort(AudioPort* audioPort) {
120 if (audioPort->ext.getTag() != AudioPortExt::Tag::device) {
121 LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not a device port";
122 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
123 }
124 auto& devicePort = audioPort->ext.get<AudioPortExt::Tag::device>();
125 if (devicePort.device.type.connection != AudioDeviceDescription::CONNECTION_USB) {
126 LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not a usb device port";
127 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
128 }
129 if (devicePort.device.address.getTag() != AudioDeviceAddress::Tag::alsa) {
130 LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not using alsa address";
131 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
132 }
133 auto& alsaAddress = devicePort.device.address.get<AudioDeviceAddress::Tag::alsa>();
134 if (alsaAddress.size() != 2 || alsaAddress[0] < 0 || alsaAddress[1] < 0) {
135 LOG(ERROR) << __func__ << ": port id " << audioPort->id << " invalid alsa address";
136 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
137 }
138
139 const bool isInput = isUsbInputDeviceType(devicePort.device.type.type);
140 alsa_device_profile profile;
141 profile_init(&profile, isInput ? PCM_IN : PCM_OUT);
142 if (!profile_read_device_info(&profile)) {
143 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
144 }
145
146 std::vector<AudioChannelLayout> channels = populateChannelMasksFromProfile(&profile, isInput);
147 std::vector<int> sampleRates = populateSampleRatesFromProfile(&profile);
148
149 for (size_t i = 0; i < std::min(MAX_PROFILE_FORMATS, AUDIO_PORT_MAX_AUDIO_PROFILES) &&
150 profile.formats[i] != 0;
151 ++i) {
152 auto audioFormatDescription =
153 usb::legacy2aidl_pcm_format_AudioFormatDescription(profile.formats[i]);
154 if (audioFormatDescription.type == AudioFormatType::DEFAULT) {
155 LOG(WARNING) << __func__ << ": unknown pcm type=" << profile.formats[i];
156 continue;
157 }
158 AudioProfile audioProfile = {.format = audioFormatDescription,
159 .channelMasks = channels,
160 .sampleRates = sampleRates};
161 audioPort->profiles.push_back(std::move(audioProfile));
162 }
163
164 return ndk::ScopedAStatus::ok();
165}
166
167ndk::ScopedAStatus ModuleUsb::checkAudioPatchEndpointsMatch(
168 const std::vector<AudioPortConfig*>& sources, const std::vector<AudioPortConfig*>& sinks) {
169 for (const auto& source : sources) {
170 for (const auto& sink : sinks) {
171 if (source->sampleRate != sink->sampleRate ||
172 source->channelMask != sink->channelMask || source->format != sink->format) {
173 LOG(ERROR) << __func__
174 << ": mismatch port configuration, source=" << source->toString()
175 << ", sink=" << sink->toString();
176 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
177 }
178 }
179 }
180 return ndk::ScopedAStatus::ok();
181}
182
183} // namespace aidl::android::hardware::audio::core