• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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