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
isCompatibleProfile(const 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 bool IOProfile::isCompatibleProfile(const DeviceVector &devices,
37 uint32_t samplingRate,
38 uint32_t *updatedSamplingRate,
39 audio_format_t format,
40 audio_format_t *updatedFormat,
41 audio_channel_mask_t channelMask,
42 audio_channel_mask_t *updatedChannelMask,
43 // FIXME type punning here
44 uint32_t flags,
45 bool exactMatchRequiredForInputFlags) const
46 {
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 false;
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 false;
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 if (isRecordThread)
73 {
74 if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
75 if (checkExactAudioProfile(&config) != NO_ERROR) {
76 return false;
77 }
78 } else if (checkCompatibleAudioProfile(
79 myUpdatedSamplingRate, myUpdatedChannelMask, myUpdatedFormat) != NO_ERROR) {
80 return false;
81 }
82 } else {
83 if (checkExactAudioProfile(&config) != NO_ERROR) {
84 return false;
85 }
86 }
87
88 if (updatedSamplingRate != NULL) {
89 *updatedSamplingRate = myUpdatedSamplingRate;
90 }
91 if (updatedFormat != NULL) {
92 *updatedFormat = myUpdatedFormat;
93 }
94 if (updatedChannelMask != NULL) {
95 *updatedChannelMask = myUpdatedChannelMask;
96 }
97 return true;
98 }
99
areAllDevicesSupported(const DeviceVector & devices) const100 bool IOProfile::areAllDevicesSupported(const DeviceVector &devices) const {
101 if (devices.empty()) {
102 return true;
103 }
104 return mSupportedDevices.containsAllDevices(devices);
105 }
106
isCompatibleProfileForFlags(uint32_t flags,bool exactMatchRequiredForInputFlags) const107 bool IOProfile::isCompatibleProfileForFlags(uint32_t flags,
108 bool exactMatchRequiredForInputFlags) const {
109 const bool isPlaybackThread =
110 getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SOURCE;
111 const bool isRecordThread =
112 getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SINK;
113 ALOG_ASSERT(isPlaybackThread != isRecordThread);
114
115 const uint32_t mustMatchOutputFlags =
116 AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
117 if (isPlaybackThread &&
118 !audio_output_flags_is_subset((audio_output_flags_t)getFlags(),
119 (audio_output_flags_t)flags,
120 mustMatchOutputFlags)) {
121 return false;
122 }
123 // The only input flag that is allowed to be different is the fast flag.
124 // An existing fast stream is compatible with a normal track request.
125 // An existing normal stream is compatible with a fast track request,
126 // but the fast request will be denied by AudioFlinger and converted to normal track.
127 if (isRecordThread && ((getFlags() ^ flags) &
128 ~(exactMatchRequiredForInputFlags ? AUDIO_INPUT_FLAG_NONE : AUDIO_INPUT_FLAG_FAST))) {
129 return false;
130 }
131
132 return true;
133 }
134
containsSingleDeviceSupportingEncodedFormats(const sp<DeviceDescriptor> & device) const135 bool IOProfile::containsSingleDeviceSupportingEncodedFormats(
136 const sp<DeviceDescriptor>& device) const {
137 if (device == nullptr) {
138 return false;
139 }
140 DeviceVector deviceList = mSupportedDevices.getDevicesFromType(device->type());
141 return std::count_if(deviceList.begin(), deviceList.end(),
142 [&device](sp<DeviceDescriptor> deviceDesc) {
143 return device == deviceDesc && deviceDesc->hasCurrentEncodedFormat(); }) == 1;
144 }
145
toSupportedMixerAttributes(std::vector<audio_mixer_attributes_t> * mixerAttributes) const146 void IOProfile::toSupportedMixerAttributes(
147 std::vector<audio_mixer_attributes_t> *mixerAttributes) const {
148 if (!hasDynamicAudioProfile()) {
149 // The mixer attributes is only supported when there is a dynamic profile.
150 return;
151 }
152 for (const auto& profile : mProfiles) {
153 if (!profile->isValid()) {
154 continue;
155 }
156 for (const auto sampleRate : profile->getSampleRates()) {
157 for (const auto channelMask : profile->getChannels()) {
158 const audio_config_base_t config = {
159 .format = profile->getFormat(),
160 .sample_rate = sampleRate,
161 .channel_mask = channelMask
162 };
163 for (const auto mixerBehavior : mMixerBehaviors) {
164 mixerAttributes->push_back({
165 .config = config,
166 .mixer_behavior = mixerBehavior
167 });
168 }
169 }
170 }
171 }
172 }
173
refreshMixerBehaviors()174 void IOProfile::refreshMixerBehaviors() {
175 if (getRole() == AUDIO_PORT_ROLE_SOURCE) {
176 mMixerBehaviors.clear();
177 mMixerBehaviors.insert(AUDIO_MIXER_BEHAVIOR_DEFAULT);
178 if (mFlags.output & AUDIO_OUTPUT_FLAG_BIT_PERFECT) {
179 mMixerBehaviors.insert(AUDIO_MIXER_BEHAVIOR_BIT_PERFECT);
180 }
181 }
182 }
183
readFromParcelable(const media::AudioPortFw & parcelable)184 status_t IOProfile::readFromParcelable(const media::AudioPortFw &parcelable) {
185 status_t status = AudioPort::readFromParcelable(parcelable);
186 if (status == OK) {
187 refreshMixerBehaviors();
188 }
189 return status;
190 }
191
dump(String8 * dst,int spaces) const192 void IOProfile::dump(String8 *dst, int spaces) const
193 {
194 String8 extraInfo;
195 extraInfo.appendFormat("0x%04x", getFlags());
196 std::string flagsLiteral =
197 getRole() == AUDIO_PORT_ROLE_SINK ?
198 toString(static_cast<audio_input_flags_t>(getFlags())) :
199 getRole() == AUDIO_PORT_ROLE_SOURCE ?
200 toString(static_cast<audio_output_flags_t>(getFlags())) : "";
201 if (!flagsLiteral.empty()) {
202 extraInfo.appendFormat(" (%s)", flagsLiteral.c_str());
203 }
204
205 std::string portStr;
206 AudioPort::dump(&portStr, spaces, extraInfo.c_str());
207 dst->append(portStr.c_str());
208
209 mSupportedDevices.dump(dst, String8("- Supported"), spaces - 2, false);
210 dst->appendFormat("%*s- maxOpenCount: %u; curOpenCount: %u\n",
211 spaces - 2, "", maxOpenCount, curOpenCount);
212 dst->appendFormat("%*s- maxActiveCount: %u; curActiveCount: %u\n",
213 spaces - 2, "", maxActiveCount, curActiveCount);
214 dst->appendFormat("%*s- recommendedMuteDurationMs: %u ms\n",
215 spaces - 2, "", recommendedMuteDurationMs);
216 if (hasDynamicAudioProfile() && !mMixerBehaviors.empty()) {
217 dst->appendFormat("%*s- mixerBehaviors: %s\n",
218 spaces - 2, "", dumpMixerBehaviors(mMixerBehaviors).c_str());
219 }
220 }
221
log()222 void IOProfile::log()
223 {
224 // @TODO: forward log to AudioPort
225 }
226
227 } // namespace android
228