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