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