1 /*
2  * Copyright (C) 2021 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 #if MAJOR_VERSION >= 7
18 #include <android_audio_policy_configuration_V7_0-enums.h>
19 #endif
20 #include <HidlUtils.h>
21 #include <log/log.h>
22 
23 #include "util/CoreUtils.h"
24 
25 using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
26 #if MAJOR_VERSION >= 7
27 namespace xsd {
28 using namespace ::android::audio::policy::configuration::V7_0;
29 }
30 #endif
31 
32 namespace android {
33 namespace hardware {
34 namespace audio {
35 namespace CPP_VERSION {
36 namespace implementation {
37 
38 #define CONVERT_CHECKED(expr, result)                   \
39     if (status_t status = (expr); status != NO_ERROR) { \
40         result = status;                                \
41     }
42 
deviceAddressToHal(const DeviceAddress & device,audio_devices_t * halDeviceType,char * halDeviceAddress)43 status_t CoreUtils::deviceAddressToHal(const DeviceAddress& device, audio_devices_t* halDeviceType,
44                                        char* halDeviceAddress) {
45 #if MAJOR_VERSION >= 5
46     return HidlUtils::deviceAddressToHal(device, halDeviceType, halDeviceAddress);
47 #else
48     return HidlUtils::deviceAddressToHalImpl(device, halDeviceType, halDeviceAddress);
49 #endif
50 }
51 
deviceAddressFromHal(audio_devices_t halDeviceType,const char * halDeviceAddress,DeviceAddress * device)52 status_t CoreUtils::deviceAddressFromHal(audio_devices_t halDeviceType,
53                                          const char* halDeviceAddress, DeviceAddress* device) {
54 #if MAJOR_VERSION >= 5
55     return HidlUtils::deviceAddressFromHal(halDeviceType, halDeviceAddress, device);
56 #else
57     return HidlUtils::deviceAddressFromHalImpl(halDeviceType, halDeviceAddress, device);
58 #endif
59 }
60 
61 #if MAJOR_VERSION >= 4
microphoneInfoFromHal(const struct audio_microphone_characteristic_t & halMicInfo,MicrophoneInfo * micInfo)62 status_t CoreUtils::microphoneInfoFromHal(
63         const struct audio_microphone_characteristic_t& halMicInfo, MicrophoneInfo* micInfo) {
64     status_t result = NO_ERROR;
65     micInfo->deviceId = halMicInfo.device_id;
66     CONVERT_CHECKED(
67             deviceAddressFromHal(halMicInfo.device, halMicInfo.address, &micInfo->deviceAddress),
68             result);
69     int chCount;
70     for (chCount = AUDIO_CHANNEL_COUNT_MAX - 1; chCount >= 0; --chCount) {
71         if (halMicInfo.channel_mapping[chCount] != AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED) {
72             break;
73         }
74     }
75     micInfo->channelMapping.resize(chCount + 1);
76     for (size_t ch = 0; ch < micInfo->channelMapping.size(); ch++) {
77         micInfo->channelMapping[ch] = AudioMicrophoneChannelMapping(halMicInfo.channel_mapping[ch]);
78     }
79     micInfo->location = AudioMicrophoneLocation(halMicInfo.location);
80     micInfo->group = AudioMicrophoneGroup(halMicInfo.group);
81     micInfo->indexInTheGroup = static_cast<uint32_t>(halMicInfo.index_in_the_group);
82     micInfo->sensitivity = halMicInfo.sensitivity;
83     micInfo->maxSpl = halMicInfo.max_spl;
84     micInfo->minSpl = halMicInfo.min_spl;
85     micInfo->directionality = AudioMicrophoneDirectionality(halMicInfo.directionality);
86     micInfo->frequencyResponse.resize(halMicInfo.num_frequency_responses);
87     for (size_t k = 0; k < halMicInfo.num_frequency_responses; k++) {
88         micInfo->frequencyResponse[k].frequency = halMicInfo.frequency_responses[0][k];
89         micInfo->frequencyResponse[k].level = halMicInfo.frequency_responses[1][k];
90     }
91     micInfo->position.x = halMicInfo.geometric_location.x;
92     micInfo->position.y = halMicInfo.geometric_location.y;
93     micInfo->position.z = halMicInfo.geometric_location.z;
94     micInfo->orientation.x = halMicInfo.orientation.x;
95     micInfo->orientation.y = halMicInfo.orientation.y;
96     micInfo->orientation.z = halMicInfo.orientation.z;
97     return result;
98 }
99 
microphoneInfoToHal(const MicrophoneInfo & micInfo,audio_microphone_characteristic_t * halMicInfo)100 status_t CoreUtils::microphoneInfoToHal(const MicrophoneInfo& micInfo,
101                                         audio_microphone_characteristic_t* halMicInfo) {
102     status_t result = NO_ERROR;
103     strncpy(halMicInfo->device_id, micInfo.deviceId.c_str(), AUDIO_MICROPHONE_ID_MAX_LEN);
104     halMicInfo->device_id[AUDIO_MICROPHONE_ID_MAX_LEN - 1] = '\0';
105     if (micInfo.deviceId.size() >= AUDIO_MICROPHONE_ID_MAX_LEN) {
106         ALOGE("HIDL MicrophoneInfo device ID is too long: %zu", micInfo.deviceId.size());
107         result = BAD_VALUE;
108     }
109     CONVERT_CHECKED(
110             deviceAddressToHal(micInfo.deviceAddress, &halMicInfo->device, halMicInfo->address),
111             result);
112     if (micInfo.channelMapping.size() > AUDIO_CHANNEL_COUNT_MAX) {
113         ALOGE("HIDL MicrophoneInfo has too many channelMapping elements: %zu",
114               micInfo.channelMapping.size());
115         result = BAD_VALUE;
116     }
117     size_t ch;
118     for (ch = 0; ch < micInfo.channelMapping.size() && ch < AUDIO_CHANNEL_COUNT_MAX; ch++) {
119         halMicInfo->channel_mapping[ch] =
120                 static_cast<audio_microphone_channel_mapping_t>(micInfo.channelMapping[ch]);
121     }
122     for (; ch < AUDIO_CHANNEL_COUNT_MAX; ch++) {
123         halMicInfo->channel_mapping[ch] = AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED;
124     }
125     halMicInfo->location = static_cast<audio_microphone_location_t>(micInfo.location);
126     halMicInfo->group = static_cast<audio_microphone_group_t>(micInfo.group);
127     halMicInfo->index_in_the_group = static_cast<unsigned int>(micInfo.indexInTheGroup);
128     halMicInfo->sensitivity = micInfo.sensitivity;
129     halMicInfo->max_spl = micInfo.maxSpl;
130     halMicInfo->min_spl = micInfo.minSpl;
131     halMicInfo->directionality =
132             static_cast<audio_microphone_directionality_t>(micInfo.directionality);
133     halMicInfo->num_frequency_responses =
134             static_cast<unsigned int>(micInfo.frequencyResponse.size());
135     if (halMicInfo->num_frequency_responses > AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES) {
136         ALOGE("HIDL MicrophoneInfo has too many frequency responses: %u",
137               halMicInfo->num_frequency_responses);
138         halMicInfo->num_frequency_responses = AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES;
139         result = BAD_VALUE;
140     }
141     for (size_t k = 0; k < halMicInfo->num_frequency_responses; k++) {
142         halMicInfo->frequency_responses[0][k] = micInfo.frequencyResponse[k].frequency;
143         halMicInfo->frequency_responses[1][k] = micInfo.frequencyResponse[k].level;
144     }
145     halMicInfo->geometric_location.x = micInfo.position.x;
146     halMicInfo->geometric_location.y = micInfo.position.y;
147     halMicInfo->geometric_location.z = micInfo.position.z;
148     halMicInfo->orientation.x = micInfo.orientation.x;
149     halMicInfo->orientation.y = micInfo.orientation.y;
150     halMicInfo->orientation.z = micInfo.orientation.z;
151     return result;
152 }
153 
sinkMetadataFromHal(const std::vector<record_track_metadata_t> & halTracks,SinkMetadata * sinkMetadata)154 status_t CoreUtils::sinkMetadataFromHal(const std::vector<record_track_metadata_t>& halTracks,
155                                         SinkMetadata* sinkMetadata) {
156     status_t result = NO_ERROR;
157     sinkMetadata->tracks.resize(halTracks.size());
158     for (size_t i = 0; i < sinkMetadata->tracks.size(); ++i) {
159         const auto& halTrackMetadata = halTracks[i];
160         RecordTrackMetadata trackMetadata{};
161         CONVERT_CHECKED(
162                 HidlUtils::audioSourceFromHal(halTrackMetadata.source, &trackMetadata.source),
163                 result);
164         trackMetadata.gain = halTrackMetadata.gain;
165 #if MAJOR_VERSION >= 5
166         if (halTrackMetadata.dest_device != AUDIO_DEVICE_NONE) {
167             DeviceAddress address;
168             if (status_t status =
169                         deviceAddressFromHal(halTrackMetadata.dest_device,
170                                              halTrackMetadata.dest_device_address, &address);
171                 status == NO_ERROR) {
172                 trackMetadata.destination.device(std::move(address));
173             } else {
174                 result = status;
175             }
176         }
177 #if MAJOR_VERSION >= 7
178         trackMetadata.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE);
179 #endif
180 #endif  // MAJOR_VERSION >= 5
181         sinkMetadata->tracks[i] = std::move(trackMetadata);
182     }
183     return result;
184 }
185 
sinkMetadataFromHalV7(const std::vector<record_track_metadata_v7_t> & halTracks,bool ignoreNonVendorTags,SinkMetadata * sinkMetadata)186 status_t CoreUtils::sinkMetadataFromHalV7(const std::vector<record_track_metadata_v7_t>& halTracks,
187                                           bool ignoreNonVendorTags, SinkMetadata* sinkMetadata) {
188     std::vector<record_track_metadata_t> bases;
189     bases.reserve(halTracks.size());
190     std::transform(halTracks.begin(), halTracks.end(), std::back_inserter(bases),
191                    [](const record_track_metadata_v7_t& src) -> record_track_metadata_t {
192                        record_track_metadata_t result;
193                        record_track_metadata_from_v7(&result, &src);
194                        return result;
195                    });
196     status_t result = sinkMetadataFromHal(bases, sinkMetadata);
197 #if MAJOR_VERSION >= 7
198     for (size_t i = 0; i < halTracks.size(); ++i) {
199         auto& trackMetadata = sinkMetadata->tracks[i];
200         const auto& halTrackMetadata = halTracks[i];
201         CONVERT_CHECKED(
202                 HidlUtils::audioChannelMaskFromHal(halTrackMetadata.channel_mask, true /*isInput*/,
203                                                    &trackMetadata.channelMask),
204                 result);
205         std::vector<std::string> strTags = HidlUtils::splitAudioTags(halTrackMetadata.tags);
206         if (ignoreNonVendorTags) {
207             strTags = HidlUtils::filterOutNonVendorTags(strTags);
208         }
209         CONVERT_CHECKED(HidlUtils::audioTagsFromHal(strTags, &trackMetadata.tags), result);
210     }
211 #else
212     (void)ignoreNonVendorTags;
213 #endif
214     return result;
215 }
216 
sinkMetadataToHal(const SinkMetadata & sinkMetadata,std::vector<record_track_metadata_t> * halTracks)217 status_t CoreUtils::sinkMetadataToHal(const SinkMetadata& sinkMetadata,
218                                       std::vector<record_track_metadata_t>* halTracks) {
219     status_t result = NO_ERROR;
220     if (halTracks != nullptr) {
221         halTracks->reserve(sinkMetadata.tracks.size());
222     }
223     for (auto& trackMetadata : sinkMetadata.tracks) {
224         record_track_metadata halTrackMetadata{.gain = trackMetadata.gain};
225         CONVERT_CHECKED(HidlUtils::audioSourceToHal(trackMetadata.source, &halTrackMetadata.source),
226                         result);
227 #if MAJOR_VERSION >= 5
228         if (trackMetadata.destination.getDiscriminator() ==
229             RecordTrackMetadata::Destination::hidl_discriminator::device) {
230             CONVERT_CHECKED(deviceAddressToHal(trackMetadata.destination.device(),
231                                                &halTrackMetadata.dest_device,
232                                                halTrackMetadata.dest_device_address),
233                             result);
234         }
235 #endif
236         if (halTracks != nullptr) {
237             halTracks->push_back(std::move(halTrackMetadata));
238         }
239     }
240     return result;
241 }
242 
sinkMetadataToHalV7(const SinkMetadata & sinkMetadata,bool ignoreNonVendorTags,std::vector<record_track_metadata_v7_t> * halTracks)243 status_t CoreUtils::sinkMetadataToHalV7(const SinkMetadata& sinkMetadata, bool ignoreNonVendorTags,
244                                         std::vector<record_track_metadata_v7_t>* halTracks) {
245     std::vector<record_track_metadata> bases;
246     status_t result = sinkMetadataToHal(sinkMetadata, halTracks != nullptr ? &bases : nullptr);
247     if (halTracks != nullptr) {
248         halTracks->reserve(sinkMetadata.tracks.size());
249     }
250     for (size_t i = 0; i < sinkMetadata.tracks.size(); ++i) {
251         record_track_metadata_v7_t halTrackMetadata;
252         if (halTracks != nullptr) {
253             record_track_metadata_to_v7(&halTrackMetadata, &bases[i]);
254         }
255 #if MAJOR_VERSION >= 7
256         const auto& trackMetadata = sinkMetadata.tracks[i];
257         CONVERT_CHECKED(HidlUtils::audioChannelMaskToHal(trackMetadata.channelMask,
258                                                          &halTrackMetadata.channel_mask),
259                         result);
260         if (ignoreNonVendorTags) {
261             CONVERT_CHECKED(
262                     HidlUtils::audioTagsToHal(HidlUtils::filterOutNonVendorTags(trackMetadata.tags),
263                                               halTrackMetadata.tags),
264                     result);
265         } else {
266             CONVERT_CHECKED(HidlUtils::audioTagsToHal(trackMetadata.tags, halTrackMetadata.tags),
267                             result);
268         }
269 #else
270         (void)ignoreNonVendorTags;
271 #endif
272         if (halTracks != nullptr) {
273             halTracks->push_back(std::move(halTrackMetadata));
274         }
275     }
276     return result;
277 }
278 
sourceMetadataFromHal(const std::vector<playback_track_metadata_t> & halTracks,SourceMetadata * sourceMetadata)279 status_t CoreUtils::sourceMetadataFromHal(const std::vector<playback_track_metadata_t>& halTracks,
280                                           SourceMetadata* sourceMetadata) {
281     status_t result = NO_ERROR;
282     sourceMetadata->tracks.resize(halTracks.size());
283     for (size_t i = 0; i < sourceMetadata->tracks.size(); ++i) {
284         const auto& halTrackMetadata = halTracks[i];
285         PlaybackTrackMetadata trackMetadata{};
286         CONVERT_CHECKED(HidlUtils::audioUsageFromHal(halTrackMetadata.usage, &trackMetadata.usage),
287                         result);
288         CONVERT_CHECKED(HidlUtils::audioContentTypeFromHal(halTrackMetadata.content_type,
289                                                            &trackMetadata.contentType),
290                         result);
291         trackMetadata.gain = halTrackMetadata.gain;
292 #if MAJOR_VERSION >= 7
293         trackMetadata.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE);
294 #endif
295         sourceMetadata->tracks[i] = std::move(trackMetadata);
296     }
297     return result;
298 }
299 
sourceMetadataFromHalV7(const std::vector<playback_track_metadata_v7_t> & halTracks,bool ignoreNonVendorTags,SourceMetadata * sourceMetadata)300 status_t CoreUtils::sourceMetadataFromHalV7(
301         const std::vector<playback_track_metadata_v7_t>& halTracks, bool ignoreNonVendorTags,
302         SourceMetadata* sourceMetadata) {
303     std::vector<playback_track_metadata_t> bases;
304     bases.reserve(halTracks.size());
305     std::transform(halTracks.begin(), halTracks.end(), std::back_inserter(bases),
306                    [](const playback_track_metadata_v7_t& src) -> playback_track_metadata_t {
307                        playback_track_metadata_t result;
308                        playback_track_metadata_from_v7(&result, &src);
309                        return result;
310                    });
311     status_t result = sourceMetadataFromHal(bases, sourceMetadata);
312 #if MAJOR_VERSION >= 7
313     for (size_t i = 0; i < halTracks.size(); ++i) {
314         auto& trackMetadata = sourceMetadata->tracks[i];
315         const auto& halTrackMetadata = halTracks[i];
316         CONVERT_CHECKED(
317                 HidlUtils::audioChannelMaskFromHal(halTrackMetadata.channel_mask, false /*isInput*/,
318                                                    &trackMetadata.channelMask),
319                 result);
320         std::vector<std::string> strTags = HidlUtils::splitAudioTags(halTrackMetadata.tags);
321         if (ignoreNonVendorTags) {
322             strTags = HidlUtils::filterOutNonVendorTags(strTags);
323         }
324         CONVERT_CHECKED(HidlUtils::audioTagsFromHal(strTags, &trackMetadata.tags), result);
325     }
326 #else
327     (void)ignoreNonVendorTags;
328 #endif
329     return result;
330 }
331 
sourceMetadataToHal(const SourceMetadata & sourceMetadata,std::vector<playback_track_metadata_t> * halTracks)332 status_t CoreUtils::sourceMetadataToHal(const SourceMetadata& sourceMetadata,
333                                         std::vector<playback_track_metadata_t>* halTracks) {
334     status_t result = NO_ERROR;
335     if (halTracks != nullptr) {
336         halTracks->reserve(sourceMetadata.tracks.size());
337     }
338     for (auto& trackMetadata : sourceMetadata.tracks) {
339         playback_track_metadata_t halTrackMetadata{.gain = trackMetadata.gain};
340         CONVERT_CHECKED(HidlUtils::audioUsageToHal(trackMetadata.usage, &halTrackMetadata.usage),
341                         result);
342         CONVERT_CHECKED(HidlUtils::audioContentTypeToHal(trackMetadata.contentType,
343                                                          &halTrackMetadata.content_type),
344                         result);
345         if (halTracks != nullptr) {
346             halTracks->push_back(std::move(halTrackMetadata));
347         }
348     }
349     return result;
350 }
351 
sourceMetadataToHalV7(const SourceMetadata & sourceMetadata,bool ignoreNonVendorTags,std::vector<playback_track_metadata_v7_t> * halTracks)352 status_t CoreUtils::sourceMetadataToHalV7(const SourceMetadata& sourceMetadata,
353                                           bool ignoreNonVendorTags,
354                                           std::vector<playback_track_metadata_v7_t>* halTracks) {
355     std::vector<playback_track_metadata_t> bases;
356     status_t result = sourceMetadataToHal(sourceMetadata, halTracks != nullptr ? &bases : nullptr);
357     if (halTracks != nullptr) {
358         halTracks->reserve(sourceMetadata.tracks.size());
359     }
360     for (size_t i = 0; i < sourceMetadata.tracks.size(); ++i) {
361         playback_track_metadata_v7_t halTrackMetadata;
362         if (halTracks != nullptr) {
363             playback_track_metadata_to_v7(&halTrackMetadata, &bases[i]);
364         }
365 #if MAJOR_VERSION >= 7
366         const auto& trackMetadata = sourceMetadata.tracks[i];
367         CONVERT_CHECKED(HidlUtils::audioChannelMaskToHal(trackMetadata.channelMask,
368                                                          &halTrackMetadata.channel_mask),
369                         result);
370         if (ignoreNonVendorTags) {
371             CONVERT_CHECKED(
372                     HidlUtils::audioTagsToHal(HidlUtils::filterOutNonVendorTags(trackMetadata.tags),
373                                               halTrackMetadata.tags),
374                     result);
375         } else {
376             CONVERT_CHECKED(HidlUtils::audioTagsToHal(trackMetadata.tags, halTrackMetadata.tags),
377                             result);
378         }
379 #else
380         (void)ignoreNonVendorTags;
381 #endif
382         if (halTracks != nullptr) {
383             halTracks->push_back(std::move(halTrackMetadata));
384         }
385     }
386     return result;
387 }
388 #endif  // MAJOR_VERSION >= 4
389 
390 #if MAJOR_VERSION >= 7
391 namespace xsd {
392 using namespace ::android::audio::policy::configuration::V7_0;
393 }
394 
audioInputFlagsFromHal(audio_input_flags_t halFlagMask,AudioInputFlags * flags)395 status_t CoreUtils::audioInputFlagsFromHal(audio_input_flags_t halFlagMask,
396                                            AudioInputFlags* flags) {
397     status_t status = NO_ERROR;
398     std::vector<AudioInOutFlag> result;
399     for (uint32_t bit = 0; halFlagMask != 0 && bit < sizeof(audio_input_flags_t) * 8; ++bit) {
400         audio_input_flags_t flag = static_cast<audio_input_flags_t>(1u << bit);
401         if ((flag & halFlagMask) == flag) {
402             AudioInOutFlag flagStr = audio_input_flag_to_string(flag);
403             if (!flagStr.empty() && !xsd::isUnknownAudioInOutFlag(flagStr)) {
404                 result.push_back(flagStr);
405             } else {
406                 ALOGE("Unknown audio input flag value 0x%X", flag);
407                 status = BAD_VALUE;
408             }
409             halFlagMask = static_cast<audio_input_flags_t>(halFlagMask & ~flag);
410         }
411     }
412     *flags = result;
413     return status;
414 }
415 
audioInputFlagsToHal(const AudioInputFlags & flags,audio_input_flags_t * halFlagMask)416 status_t CoreUtils::audioInputFlagsToHal(const AudioInputFlags& flags,
417                                          audio_input_flags_t* halFlagMask) {
418     status_t status = NO_ERROR;
419     *halFlagMask = {};
420     for (const auto& flag : flags) {
421         audio_input_flags_t halFlag;
422         if (!xsd::isUnknownAudioInOutFlag(flag) &&
423             audio_input_flag_from_string(flag.c_str(), &halFlag)) {
424             *halFlagMask = static_cast<audio_input_flags_t>(*halFlagMask | halFlag);
425         } else {
426             ALOGE("Unknown audio input flag \"%s\"", flag.c_str());
427             status = BAD_VALUE;
428         }
429     }
430     return status;
431 }
432 
audioOutputFlagsFromHal(audio_output_flags_t halFlagMask,AudioOutputFlags * flags)433 status_t CoreUtils::audioOutputFlagsFromHal(audio_output_flags_t halFlagMask,
434                                             AudioOutputFlags* flags) {
435     status_t status = NO_ERROR;
436     std::vector<AudioInOutFlag> result;
437     for (uint32_t bit = 0; halFlagMask != 0 && bit < sizeof(audio_output_flags_t) * 8; ++bit) {
438         audio_output_flags_t flag = static_cast<audio_output_flags_t>(1u << bit);
439         if ((flag & halFlagMask) == flag) {
440             AudioInOutFlag flagStr = audio_output_flag_to_string(flag);
441             if (!flagStr.empty() && !xsd::isUnknownAudioInOutFlag(flagStr)) {
442                 result.push_back(flagStr);
443             } else {
444                 ALOGE("Unknown audio output flag value 0x%X", flag);
445                 status = BAD_VALUE;
446             }
447             halFlagMask = static_cast<audio_output_flags_t>(halFlagMask & ~flag);
448         }
449     }
450     *flags = result;
451     return status;
452 }
453 
audioOutputFlagsToHal(const AudioOutputFlags & flags,audio_output_flags_t * halFlagMask)454 status_t CoreUtils::audioOutputFlagsToHal(const AudioOutputFlags& flags,
455                                           audio_output_flags_t* halFlagMask) {
456     status_t status = NO_ERROR;
457     *halFlagMask = {};
458     for (const auto& flag : flags) {
459         audio_output_flags_t halFlag;
460         if (!xsd::isUnknownAudioInOutFlag(flag) &&
461             audio_output_flag_from_string(flag.c_str(), &halFlag)) {
462             *halFlagMask = static_cast<audio_output_flags_t>(*halFlagMask | halFlag);
463         } else {
464             ALOGE("Unknown audio output flag \"%s\"", flag.c_str());
465             status = BAD_VALUE;
466         }
467     }
468     return status;
469 }
470 #endif
471 
472 }  // namespace implementation
473 }  // namespace CPP_VERSION
474 }  // namespace audio
475 }  // namespace hardware
476 }  // namespace android
477