• 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 
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