1 /*
2 * Copyright (C) 2015 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 "APM::IOProfile"
18 //#define LOG_NDEBUG 0
19
20 #include <system/audio.h>
21 #include "IOProfile.h"
22 #include "HwModule.h"
23 #include "TypeConverter.h"
24
25 namespace android {
26
IOProfile(const std::string & name,audio_port_role_t role)27 IOProfile::IOProfile(const std::string &name, audio_port_role_t role)
28 : AudioPort(name, AUDIO_PORT_TYPE_MIX, role),
29 curOpenCount(0),
30 curActiveCount(0) {
31 if (role == AUDIO_PORT_ROLE_SOURCE) {
32 mMixerBehaviors.insert(AUDIO_MIXER_BEHAVIOR_DEFAULT);
33 }
34 }
35
getCompatibilityScore(const android::DeviceVector & devices,uint32_t samplingRate,uint32_t * updatedSamplingRate,audio_format_t format,audio_format_t * updatedFormat,audio_channel_mask_t channelMask,audio_channel_mask_t * updatedChannelMask,uint32_t flags) const36 IOProfile::CompatibilityScore IOProfile::getCompatibilityScore(
37 const android::DeviceVector &devices,
38 uint32_t samplingRate,
39 uint32_t *updatedSamplingRate,
40 audio_format_t format,
41 audio_format_t *updatedFormat,
42 audio_channel_mask_t channelMask,
43 audio_channel_mask_t *updatedChannelMask,
44 // FIXME type punning here
45 uint32_t flags) const {
46 const bool isPlaybackThread =
47 getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SOURCE;
48 const bool isRecordThread =
49 getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SINK;
50 ALOG_ASSERT(isPlaybackThread != isRecordThread);
51 const auto flagsCompatibleScore = getFlagsCompatibleScore(flags);
52 if (!areAllDevicesSupported(devices) || flagsCompatibleScore == NO_MATCH) {
53 return NO_MATCH;
54 }
55
56 if (!audio_is_valid_format(format) ||
57 (isPlaybackThread && (samplingRate == 0 || !audio_is_output_channel(channelMask))) ||
58 (isRecordThread && (!audio_is_input_channel(channelMask)))) {
59 return NO_MATCH;
60 }
61
62 audio_format_t myUpdatedFormat = format;
63 audio_channel_mask_t myUpdatedChannelMask = channelMask;
64 uint32_t myUpdatedSamplingRate = samplingRate;
65 const struct audio_port_config config = {
66 .config_mask = AUDIO_PORT_CONFIG_ALL & ~AUDIO_PORT_CONFIG_GAIN,
67 .sample_rate = samplingRate,
68 .channel_mask = channelMask,
69 .format = format,
70 };
71 auto result = NO_MATCH;
72 if (isRecordThread)
73 {
74 if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
75 if (checkIdenticalAudioProfile(&config) != NO_ERROR) {
76 return result;
77 }
78 result = EXACT_MATCH;
79 } else if (checkExactAudioProfile(&config) == NO_ERROR) {
80 result = EXACT_MATCH;
81 } else if (checkCompatibleAudioProfile(
82 myUpdatedSamplingRate, myUpdatedChannelMask, myUpdatedFormat) == NO_ERROR) {
83 if (flagsCompatibleScore == EXACT_MATCH) {
84 result = PARTIAL_MATCH_WITH_FLAG;
85 } else {
86 result = PARTIAL_MATCH;
87 }
88 } else {
89 return result;
90 }
91 } else {
92 if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) != 0 ||
93 (flags & AUDIO_OUTPUT_FLAG_BIT_PERFECT) != 0) {
94 if (checkIdenticalAudioProfile(&config) != NO_ERROR) {
95 return result;
96 }
97 result = EXACT_MATCH;
98 } else if (checkExactAudioProfile(&config) == NO_ERROR) {
99 result = EXACT_MATCH;
100 } else {
101 return result;
102 }
103 }
104
105 if (updatedSamplingRate != nullptr) {
106 *updatedSamplingRate = myUpdatedSamplingRate;
107 }
108 if (updatedFormat != nullptr) {
109 *updatedFormat = myUpdatedFormat;
110 }
111 if (updatedChannelMask != nullptr) {
112 *updatedChannelMask = myUpdatedChannelMask;
113 }
114 return result;
115 }
116
areAllDevicesSupported(const DeviceVector & devices) const117 bool IOProfile::areAllDevicesSupported(const DeviceVector &devices) const {
118 if (devices.empty()) {
119 return true;
120 }
121 return mSupportedDevices.containsAllDevices(devices);
122 }
123
isCompatibleProfileForFlags(uint32_t flags) const124 bool IOProfile::isCompatibleProfileForFlags(uint32_t flags) const {
125 return getFlagsCompatibleScore(flags) != NO_MATCH;
126 }
127
containsSingleDeviceSupportingEncodedFormats(const sp<DeviceDescriptor> & device) const128 bool IOProfile::containsSingleDeviceSupportingEncodedFormats(
129 const sp<DeviceDescriptor>& device) const {
130 if (device == nullptr) {
131 return false;
132 }
133 DeviceVector deviceList = mSupportedDevices.getDevicesFromType(device->type());
134 return std::count_if(deviceList.begin(), deviceList.end(),
135 [&device](sp<DeviceDescriptor> deviceDesc) {
136 return device == deviceDesc && deviceDesc->hasCurrentEncodedFormat(); }) == 1;
137 }
138
toSupportedMixerAttributes(std::vector<audio_mixer_attributes_t> * mixerAttributes) const139 void IOProfile::toSupportedMixerAttributes(
140 std::vector<audio_mixer_attributes_t> *mixerAttributes) const {
141 if (!hasDynamicAudioProfile()) {
142 // The mixer attributes is only supported when there is a dynamic profile.
143 return;
144 }
145 for (const auto& profile : mProfiles) {
146 if (!profile->isValid()) {
147 continue;
148 }
149 for (const auto sampleRate : profile->getSampleRates()) {
150 for (const auto channelMask : profile->getChannels()) {
151 const audio_config_base_t config = {
152 .sample_rate = sampleRate,
153 .channel_mask = channelMask,
154 .format = profile->getFormat(),
155 };
156 for (const auto mixerBehavior : mMixerBehaviors) {
157 mixerAttributes->push_back({
158 .config = config,
159 .mixer_behavior = mixerBehavior
160 });
161 }
162 }
163 }
164 }
165 }
166
refreshMixerBehaviors()167 void IOProfile::refreshMixerBehaviors() {
168 if (getRole() == AUDIO_PORT_ROLE_SOURCE) {
169 mMixerBehaviors.clear();
170 mMixerBehaviors.insert(AUDIO_MIXER_BEHAVIOR_DEFAULT);
171 if (mFlags.output & AUDIO_OUTPUT_FLAG_BIT_PERFECT) {
172 mMixerBehaviors.insert(AUDIO_MIXER_BEHAVIOR_BIT_PERFECT);
173 }
174 }
175 }
176
readFromParcelable(const media::AudioPortFw & parcelable)177 status_t IOProfile::readFromParcelable(const media::AudioPortFw &parcelable) {
178 status_t status = AudioPort::readFromParcelable(parcelable);
179 if (status == OK) {
180 refreshMixerBehaviors();
181 }
182 return status;
183 }
184
importAudioPort(const audio_port_v7 & port)185 void IOProfile::importAudioPort(const audio_port_v7 &port) {
186 if (mProfiles.hasDynamicFormat()) {
187 std::set<audio_format_t> formats;
188 for (size_t i = 0; i < port.num_audio_profiles; ++i) {
189 formats.insert(port.audio_profiles[i].format);
190 }
191 addProfilesForFormats(mProfiles, FormatVector(formats.begin(), formats.end()));
192 }
193 for (audio_format_t format : mProfiles.getSupportedFormats()) {
194 for (size_t i = 0; i < port.num_audio_profiles; ++i) {
195 if (port.audio_profiles[i].format == format) {
196 ChannelMaskSet channelMasks(port.audio_profiles[i].channel_masks,
197 port.audio_profiles[i].channel_masks +
198 port.audio_profiles[i].num_channel_masks);
199 SampleRateSet sampleRates(port.audio_profiles[i].sample_rates,
200 port.audio_profiles[i].sample_rates +
201 port.audio_profiles[i].num_sample_rates);
202 addDynamicAudioProfileAndSort(
203 mProfiles, sp<AudioProfile>::make(
204 format, channelMasks, sampleRates));
205 }
206 }
207 }
208 }
209
getFlagsCompatibleScore(uint32_t flags) const210 IOProfile::CompatibilityScore IOProfile::getFlagsCompatibleScore(uint32_t flags) const {
211 const bool isPlaybackThread =
212 getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SOURCE;
213 const bool isRecordThread =
214 getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SINK;
215 ALOG_ASSERT(isPlaybackThread != isRecordThread);
216
217 const uint32_t mustMatchOutputFlags =
218 AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
219 if (isPlaybackThread &&
220 !audio_output_flags_is_subset((audio_output_flags_t)getFlags(),
221 (audio_output_flags_t)flags,
222 mustMatchOutputFlags)) {
223 return NO_MATCH;
224 }
225 // The only input flag that is allowed to be different is the fast flag.
226 // An existing fast stream is compatible with a normal track request.
227 // An existing normal stream is compatible with a fast track request,
228 // but the fast request will be denied by AudioFlinger and converted to normal track.
229 if (isRecordThread) {
230 const auto unmatchedFlag = getFlags() ^ flags;
231 if (unmatchedFlag == AUDIO_INPUT_FLAG_NONE) {
232 return EXACT_MATCH;
233 } else if (unmatchedFlag == AUDIO_INPUT_FLAG_FAST) {
234 return PARTIAL_MATCH;
235 } else {
236 return NO_MATCH;
237 }
238 }
239
240 return EXACT_MATCH;
241 }
242
dump(String8 * dst,int spaces) const243 void IOProfile::dump(String8 *dst, int spaces) const
244 {
245 String8 extraInfo;
246 extraInfo.appendFormat("0x%04x", getFlags());
247 std::string flagsLiteral =
248 getRole() == AUDIO_PORT_ROLE_SINK ?
249 toString(static_cast<audio_input_flags_t>(getFlags())) :
250 getRole() == AUDIO_PORT_ROLE_SOURCE ?
251 toString(static_cast<audio_output_flags_t>(getFlags())) : "";
252 if (!flagsLiteral.empty()) {
253 extraInfo.appendFormat(" (%s)", flagsLiteral.c_str());
254 }
255
256 std::string portStr;
257 AudioPort::dump(&portStr, spaces, extraInfo.c_str());
258 dst->append(portStr.c_str());
259
260 mSupportedDevices.dump(dst, String8("- Supported"), spaces - 2, false);
261 dst->appendFormat("%*s- maxOpenCount: %u; curOpenCount: %u\n",
262 spaces - 2, "", maxOpenCount, curOpenCount);
263 dst->appendFormat("%*s- maxActiveCount: %u; curActiveCount: %u\n",
264 spaces - 2, "", maxActiveCount, curActiveCount);
265 dst->appendFormat("%*s- recommendedMuteDurationMs: %u ms\n",
266 spaces - 2, "", recommendedMuteDurationMs);
267 if (hasDynamicAudioProfile() && !mMixerBehaviors.empty()) {
268 dst->appendFormat("%*s- mixerBehaviors: %s\n",
269 spaces - 2, "", dumpMixerBehaviors(mMixerBehaviors).c_str());
270 }
271 }
272
log()273 void IOProfile::log()
274 {
275 // @TODO: forward log to AudioPort
276 }
277
278 } // namespace android
279