• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 #include <log/log.h>
18 #include <fmq/EventFlag.h>
19 #include <fmq/MessageQueue.h>
20 #include <hidl/MQDescriptor.h>
21 #include <hidl/Status.h>
22 #include <utils/ThreadDefs.h>
23 #include PATH(APM_XSD_ENUMS_H_FILENAME)
24 #include <future>
25 #include <thread>
26 #include "stream_out.h"
27 #include "device_port_sink.h"
28 #include "deleters.h"
29 #include "audio_ops.h"
30 #include "util.h"
31 #include "debug.h"
32 
33 namespace xsd {
34 using namespace ::android::audio::policy::configuration::CPP_VERSION;
35 }
36 
37 namespace android {
38 namespace hardware {
39 namespace audio {
40 namespace CPP_VERSION {
41 namespace implementation {
42 
43 using ::android::hardware::Void;
44 using namespace ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION;
45 using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION;
46 
47 namespace {
48 
49 class WriteThread : public IOThread {
50     typedef MessageQueue<IStreamOut::WriteCommand, kSynchronizedReadWrite> CommandMQ;
51     typedef MessageQueue<IStreamOut::WriteStatus, kSynchronizedReadWrite> StatusMQ;
52     typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ;
53 
54 public:
WriteThread(StreamOut * stream,const size_t mqBufferSize)55     WriteThread(StreamOut *stream, const size_t mqBufferSize)
56             : mStream(stream)
57             , mCommandMQ(1)
58             , mStatusMQ(1)
59             , mDataMQ(mqBufferSize, true /* EventFlag */) {
60         if (!mCommandMQ.isValid()) {
61             ALOGE("WriteThread::%s:%d: mCommandMQ is invalid", __func__, __LINE__);
62             return;
63         }
64         if (!mDataMQ.isValid()) {
65             ALOGE("WriteThread::%s:%d: mDataMQ is invalid", __func__, __LINE__);
66             return;
67         }
68         if (!mStatusMQ.isValid()) {
69             ALOGE("WriteThread::%s:%d: mStatusMQ is invalid", __func__, __LINE__);
70             return;
71         }
72 
73         status_t status;
74 
75         EventFlag* rawEfGroup = nullptr;
76         status = EventFlag::createEventFlag(mDataMQ.getEventFlagWord(), &rawEfGroup);
77         if (status != OK || !rawEfGroup) {
78             ALOGE("WriteThread::%s:%d: rawEfGroup is invalid", __func__, __LINE__);
79             return;
80         } else {
81             mEfGroup.reset(rawEfGroup);
82         }
83 
84         mThread = std::thread(&WriteThread::threadLoop, this);
85     }
86 
~WriteThread()87     ~WriteThread() {
88         if (mThread.joinable()) {
89             requestExit();
90             mThread.join();
91         }
92     }
93 
getEventFlag()94     EventFlag *getEventFlag() override {
95         return mEfGroup.get();
96     }
97 
isRunning() const98     bool isRunning() const {
99         return mThread.joinable();
100     }
101 
getTid()102     std::future<pthread_t> getTid() {
103         return mTid.get_future();
104     }
105 
getPresentationPosition(uint64_t & frames,TimeSpec & ts) const106     Result getPresentationPosition(uint64_t &frames, TimeSpec &ts) const {
107         std::lock_guard l(mExternalSinkReadLock);
108         if (mSink == nullptr) {
109             // this could return a slightly stale position under data race.
110             frames = mFrames,
111             ts = util::nsecs2TimeSpec(systemTime(SYSTEM_TIME_MONOTONIC));
112             return Result::OK;
113         } else {
114             return mSink->getPresentationPosition(frames, ts);
115         }
116     }
117 
getDescriptors() const118     auto getDescriptors() const {
119         return std::make_tuple(
120                 mCommandMQ.getDesc(), mDataMQ.getDesc(), mStatusMQ.getDesc());
121     }
122 
123 private:
threadLoop()124     void threadLoop() {
125         util::setThreadPriority(SP_AUDIO_SYS, PRIORITY_AUDIO);
126         mTid.set_value(pthread_self());
127 
128         while (true) {
129             uint32_t efState = 0;
130             mEfGroup->wait(MessageQueueFlagBits::NOT_EMPTY | STAND_BY_REQUEST | EXIT_REQUEST,
131                            &efState);
132             if (efState & EXIT_REQUEST) {
133                 return;
134             }
135 
136             if (efState & STAND_BY_REQUEST) {
137                 ALOGD("%s: entering standby, frames: %llu", __func__, (unsigned long long)mFrames);
138                 std::lock_guard l(mExternalSinkReadLock);
139                 mSink.reset();
140             }
141 
142             if (efState & (MessageQueueFlagBits::NOT_EMPTY | 0)) {
143                 if (!mSink) {
144                     mFrameSize = mStream->getFrameSize();
145                     auto sink = DevicePortSink::create(mDataMQ.getQuantumCount(),
146                                                    mStream->getDeviceAddress(),
147                                                    mStream->getAudioConfig(),
148                                                    mStream->getAudioOutputFlags(),
149                                                    mFrames);
150                     LOG_ALWAYS_FATAL_IF(!sink);
151                     std::lock_guard l(mExternalSinkReadLock);
152                     mSink = std::move(sink);
153                 }
154 
155                 processCommand();
156             }
157         }
158     }
159 
processCommand()160     void processCommand() {
161         IStreamOut::WriteCommand wCommand;
162 
163         if (!mCommandMQ.read(&wCommand)) {
164             return;  // Nothing to do.
165         }
166 
167         IStreamOut::WriteStatus wStatus;
168         switch (wCommand) {
169             case IStreamOut::WriteCommand::WRITE:
170                 wStatus = doWrite();
171                 break;
172 
173             case IStreamOut::WriteCommand::GET_PRESENTATION_POSITION:
174                 wStatus = doGetPresentationPosition();
175                 break;
176 
177             case IStreamOut::WriteCommand::GET_LATENCY:
178                 wStatus = doGetLatency();
179                 break;
180 
181             default:
182                 ALOGE("WriteThread::%s:%d: Unknown write thread command code %d",
183                       __func__, __LINE__, wCommand);
184                 wStatus.retval = FAILURE(Result::NOT_SUPPORTED);
185                 break;
186         }
187 
188         wStatus.replyTo = wCommand;
189 
190         if (!mStatusMQ.write(&wStatus)) {
191             ALOGE("status message queue write failed");
192         }
193 
194         mEfGroup->wake(MessageQueueFlagBits::NOT_FULL | 0);
195     }
196 
doWrite()197     IStreamOut::WriteStatus doWrite() {
198         struct MQReader : public IReader {
199             explicit MQReader(DataMQ &mq) : dataMQ(mq) {}
200 
201             size_t operator()(void *dst, size_t sz) override {
202                 if (dataMQ.read(static_cast<uint8_t *>(dst), sz)) {
203                     totalRead += sz;
204                     return sz;
205                 } else {
206                     ALOGE("WriteThread::%s:%d: DataMQ::read failed",
207                           __func__, __LINE__);
208                     return 0;
209                 }
210             }
211 
212             size_t totalRead = 0;
213             DataMQ &dataMQ;
214         };
215 
216         MQReader reader(mDataMQ);
217         mSink->write(mStream->getEffectiveVolume(), mDataMQ.availableToRead(), reader);
218 
219         const size_t written = reader.totalRead / mFrameSize;
220         mFrames += written;
221         ALOGV("%s: mFrames: %llu  %zu", __func__, (unsigned long long) mFrames, written);
222 
223         IStreamOut::WriteStatus status;
224         status.retval = Result::OK;
225         status.reply.written = reader.totalRead;
226         return status;
227     }
228 
doGetPresentationPosition()229     IStreamOut::WriteStatus doGetPresentationPosition() {
230         IStreamOut::WriteStatus status;
231 
232         status.retval = mSink->getPresentationPosition(
233             status.reply.presentationPosition.frames,
234             status.reply.presentationPosition.timeStamp);
235 
236         ALOGV("%s: presentation position: %llu  %lld", __func__,
237                 (unsigned long long) status.reply.presentationPosition.frames,
238                 (long long) util::timespec2Nsecs( status.reply.presentationPosition.timeStamp));
239 
240         return status;
241     }
242 
doGetLatency()243     IStreamOut::WriteStatus doGetLatency() {
244         IStreamOut::WriteStatus status;
245 
246         const int latencyMs =
247             DevicePortSink::getLatencyMs(mStream->getDeviceAddress(),
248                                          mStream->getAudioConfig());
249 
250         if (latencyMs >= 0) {
251             status.retval = Result::OK;
252             status.reply.latencyMs = latencyMs;
253         } else {
254             status.retval = Result::INVALID_STATE;
255         }
256 
257         return status;
258     }
259 
260     StreamOut *const mStream;
261     CommandMQ mCommandMQ;
262     StatusMQ mStatusMQ;
263     DataMQ mDataMQ;
264     std::unique_ptr<EventFlag, deleters::forEventFlag> mEfGroup;
265     std::thread mThread;
266     std::promise<pthread_t> mTid;
267     size_t mFrameSize = 1;                    // updated when the sink is created.
268     std::atomic<uint64_t> mFrames = 0;        // preserve framecount during standby.
269     mutable std::mutex mExternalSinkReadLock; // used for external access to mSink.
270     std::unique_ptr<DevicePortSink> mSink;
271 };
272 
273 } // namespace
274 
StreamOut(sp<Device> dev,int32_t ioHandle,const DeviceAddress & device,const AudioConfig & config,hidl_vec<AudioInOutFlag> flags,const SourceMetadata & sourceMetadata)275 StreamOut::StreamOut(sp<Device> dev,
276                      int32_t ioHandle,
277                      const DeviceAddress& device,
278                      const AudioConfig& config,
279                      hidl_vec<AudioInOutFlag> flags,
280                      const SourceMetadata& sourceMetadata)
281         : mDev(std::move(dev))
282         , mCommon(ioHandle, device, config, std::move(flags))
283         , mSourceMetadata(sourceMetadata) {}
284 
~StreamOut()285 StreamOut::~StreamOut() {
286     closeImpl(true);
287 }
288 
getFrameSize()289 Return<uint64_t> StreamOut::getFrameSize() {
290     return mCommon.getFrameSize();
291 }
292 
getFrameCount()293 Return<uint64_t> StreamOut::getFrameCount() {
294     return mCommon.getFrameCount();
295 }
296 
getBufferSize()297 Return<uint64_t> StreamOut::getBufferSize() {
298     return mCommon.getBufferSize();
299 }
300 
getSupportedProfiles(getSupportedProfiles_cb _hidl_cb)301 Return<void> StreamOut::getSupportedProfiles(getSupportedProfiles_cb _hidl_cb) {
302     mCommon.getSupportedProfiles(_hidl_cb);
303     return Void();
304 }
305 
getAudioProperties(getAudioProperties_cb _hidl_cb)306 Return<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) {
307     mCommon.getAudioProperties(_hidl_cb);
308     return Void();
309 }
310 
setAudioProperties(const AudioConfigBaseOptional & config)311 Return<Result> StreamOut::setAudioProperties(const AudioConfigBaseOptional& config) {
312     (void)config;
313     return FAILURE(Result::NOT_SUPPORTED);
314 }
315 
addEffect(uint64_t effectId)316 Return<Result> StreamOut::addEffect(uint64_t effectId) {
317     (void)effectId;
318     return FAILURE(Result::INVALID_ARGUMENTS);
319 }
320 
removeEffect(uint64_t effectId)321 Return<Result> StreamOut::removeEffect(uint64_t effectId) {
322     (void)effectId;
323     return FAILURE(Result::INVALID_ARGUMENTS);
324 }
325 
standby()326 Return<Result> StreamOut::standby() {
327     if (mWriteThread) {
328         LOG_ALWAYS_FATAL_IF(!mWriteThread->standby());
329     }
330 
331     return Result::OK;
332 }
333 
getDevices(getDevices_cb _hidl_cb)334 Return<void> StreamOut::getDevices(getDevices_cb _hidl_cb) {
335     mCommon.getDevices(_hidl_cb);
336     return Void();
337 }
338 
setDevices(const hidl_vec<DeviceAddress> & devices)339 Return<Result> StreamOut::setDevices(const hidl_vec<DeviceAddress>& devices) {
340     return mCommon.setDevices(devices);
341 }
342 
getParameters(const hidl_vec<ParameterValue> & context,const hidl_vec<hidl_string> & keys,getParameters_cb _hidl_cb)343 Return<void> StreamOut::getParameters(const hidl_vec<ParameterValue>& context,
344                                       const hidl_vec<hidl_string>& keys,
345                                       getParameters_cb _hidl_cb) {
346     (void)context;
347     _hidl_cb((keys.size() > 0) ? Result::NOT_SUPPORTED : Result::OK, {});
348     return Void();
349 }
350 
setParameters(const hidl_vec<ParameterValue> & context,const hidl_vec<ParameterValue> & parameters)351 Return<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& context,
352                                         const hidl_vec<ParameterValue>& parameters) {
353     (void)context;
354     (void)parameters;
355     return Result::OK;
356 }
357 
setHwAvSync(uint32_t hwAvSync)358 Return<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) {
359     (void)hwAvSync;
360     return FAILURE(Result::NOT_SUPPORTED);
361 }
362 
closeImpl(const bool fromDctor)363 Result StreamOut::closeImpl(const bool fromDctor) {
364     if (mDev) {
365         mWriteThread.reset();
366         mDev->unrefDevice(this);
367         mDev = nullptr;
368         return Result::OK;
369     } else if (fromDctor) {
370         // closeImpl is always called from the dctor, it is ok if mDev is null,
371         // we don't want to log the error in this case.
372         return Result::OK;
373     } else {
374         return FAILURE(Result::INVALID_STATE);
375     }
376 }
377 
close()378 Return<Result> StreamOut::close() {
379     return closeImpl(false);
380 }
381 
start()382 Return<Result> StreamOut::start() {
383     return FAILURE(Result::NOT_SUPPORTED);
384 }
385 
stop()386 Return<Result> StreamOut::stop() {
387     return FAILURE(Result::NOT_SUPPORTED);
388 }
389 
createMmapBuffer(int32_t minSizeFrames,createMmapBuffer_cb _hidl_cb)390 Return<void> StreamOut::createMmapBuffer(int32_t minSizeFrames,
391                                          createMmapBuffer_cb _hidl_cb) {
392     (void)minSizeFrames;
393     _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
394     return Void();
395 }
396 
getMmapPosition(getMmapPosition_cb _hidl_cb)397 Return<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) {
398     _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
399     return Void();
400 }
401 
getLatency()402 Return<uint32_t> StreamOut::getLatency() {
403     const int latencyMs = DevicePortSink::getLatencyMs(getDeviceAddress(), getAudioConfig());
404 
405     return (latencyMs >= 0) ? latencyMs :
406         (mCommon.getFrameCount() * 1000 / mCommon.getSampleRate());
407 }
408 
setVolume(float left,float right)409 Return<Result> StreamOut::setVolume(float left, float right) {
410     if (isnan(left) || left < 0.0f || left > 1.0f
411         || right < 0.0f || right > 1.0f || isnan(right)) {
412         return FAILURE(Result::INVALID_ARGUMENTS);
413     }
414 
415     std::lock_guard<std::mutex> guard(mMutex);
416     mStreamVolume = (left + right) / 2.0f;
417     updateEffectiveVolumeLocked();
418     return Result::OK;
419 }
420 
updateSourceMetadata(const SourceMetadata & sourceMetadata)421 Return<Result> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
422     (void)sourceMetadata;
423     return Result::NOT_SUPPORTED;
424 }
425 
prepareForWriting(uint32_t frameSize,uint32_t framesCount,prepareForWriting_cb _hidl_cb)426 Return<void> StreamOut::prepareForWriting(uint32_t frameSize,
427                                           uint32_t framesCount,
428                                           prepareForWriting_cb _hidl_cb) {
429     if (!frameSize || !framesCount || frameSize > 256 || framesCount > (1u << 20)) {
430         _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), {}, {}, {}, -1);
431         return Void();
432     }
433 
434     if (mWriteThread) {  // INVALID_STATE if the method was already called.
435         _hidl_cb(FAILURE(Result::INVALID_STATE), {}, {}, {}, -1);
436         return Void();
437     }
438 
439     auto t = std::make_unique<WriteThread>(this, frameSize * framesCount);
440 
441     if (t->isRunning()) {
442         const auto [commandDesc, dataDesc, statusDesc ] = t->getDescriptors();
443         _hidl_cb(Result::OK,
444                  *commandDesc,
445                  *dataDesc,
446                  *statusDesc,
447                  t->getTid().get());
448 
449         mWriteThread = std::move(t);
450     } else {
451         _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), {}, {}, {}, -1);
452     }
453 
454     return Void();
455 }
456 
getRenderPosition(getRenderPosition_cb _hidl_cb)457 Return<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) {
458     _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0);
459     return Void();
460 }
461 
getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb)462 Return<void> StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) {
463     _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0);
464     return Void();
465 }
466 
setCallback(const sp<IStreamOutCallback> & callback)467 Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) {
468     (void)callback;
469     return FAILURE(Result::NOT_SUPPORTED);
470 }
471 
clearCallback()472 Return<Result> StreamOut::clearCallback() {
473     return FAILURE(Result::NOT_SUPPORTED);
474 }
475 
setEventCallback(const sp<IStreamOutEventCallback> & callback)476 Return<Result> StreamOut::setEventCallback(const sp<IStreamOutEventCallback>& callback) {
477     (void)callback;
478     return Result::NOT_SUPPORTED;
479 }
480 
supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb)481 Return<void> StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) {
482     _hidl_cb(false, false);
483     return Void();
484 }
485 
pause()486 Return<Result> StreamOut::pause() {
487     return FAILURE(Result::NOT_SUPPORTED);
488 }
489 
resume()490 Return<Result> StreamOut::resume() {
491     return FAILURE(Result::NOT_SUPPORTED);
492 }
493 
supportsDrain()494 Return<bool> StreamOut::supportsDrain() {
495     return false;
496 }
497 
drain(AudioDrain type)498 Return<Result> StreamOut::drain(AudioDrain type) {
499     (void)type;
500     return FAILURE(Result::NOT_SUPPORTED);
501 }
502 
flush()503 Return<Result> StreamOut::flush() {
504     return FAILURE(Result::NOT_SUPPORTED);
505 }
506 
getPresentationPosition(getPresentationPosition_cb _hidl_cb)507 Return<void> StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl_cb) {
508     const auto w = static_cast<WriteThread*>(mWriteThread.get());
509     if (!w) {
510         _hidl_cb(FAILURE(Result::INVALID_STATE), {}, {});
511         return Void();
512     }
513     uint64_t frames{};
514     TimeSpec ts{};
515     const Result r = w->getPresentationPosition(frames, ts);
516     ALOGV("%s: presentation position: %llu  %lld", __func__,
517             (unsigned long long) frames, (long long) util::timespec2Nsecs(ts));
518     _hidl_cb(r, frames, ts);
519     return Void();
520 }
521 
selectPresentation(int32_t presentationId,int32_t programId)522 Return<Result> StreamOut::selectPresentation(int32_t presentationId,
523                                              int32_t programId) {
524     (void)presentationId;
525     (void)programId;
526     return FAILURE(Result::NOT_SUPPORTED);
527 }
528 
getDualMonoMode(getDualMonoMode_cb _hidl_cb)529 Return<void> StreamOut::getDualMonoMode(getDualMonoMode_cb _hidl_cb) {
530     _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
531     return Void();
532 }
533 
setDualMonoMode(DualMonoMode mode)534 Return<Result> StreamOut::setDualMonoMode(DualMonoMode mode) {
535     (void)mode;
536     return FAILURE(Result::NOT_SUPPORTED);
537 }
538 
getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb)539 Return<void> StreamOut::getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb) {
540     _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0);
541     return Void();
542 }
543 
setAudioDescriptionMixLevel(float leveldB)544 Return<Result> StreamOut::setAudioDescriptionMixLevel(float leveldB) {
545     (void)leveldB;
546     return FAILURE(Result::NOT_SUPPORTED);
547 }
548 
getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb)549 Return<void> StreamOut::getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb) {
550     _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
551     return Void();
552 }
553 
setPlaybackRateParameters(const PlaybackRate & playbackRate)554 Return<Result> StreamOut::setPlaybackRateParameters(const PlaybackRate &playbackRate) {
555     (void)playbackRate;
556     return FAILURE(Result::NOT_SUPPORTED);
557 }
558 
559 #if MAJOR_VERSION == 7 && MINOR_VERSION == 1
setLatencyMode(LatencyMode mode __unused)560 Return<Result> StreamOut::setLatencyMode(LatencyMode mode __unused) {
561     return Result::NOT_SUPPORTED;
562 };
563 
getRecommendedLatencyModes(getRecommendedLatencyModes_cb _hidl_cb)564 Return<void> StreamOut::getRecommendedLatencyModes(getRecommendedLatencyModes_cb _hidl_cb) {
565     hidl_vec<LatencyMode> hidlModes;
566     _hidl_cb(Result::NOT_SUPPORTED, hidlModes);
567     return Void();
568 };
569 
setLatencyModeCallback(const sp<IStreamOutLatencyModeCallback> & callback __unused)570 Return<Result> StreamOut::setLatencyModeCallback(
571         const sp<IStreamOutLatencyModeCallback>& callback __unused) {
572     return Result::NOT_SUPPORTED;
573 };
574 #endif
575 
setMasterVolume(float masterVolume)576 void StreamOut::setMasterVolume(float masterVolume) {
577     std::lock_guard<std::mutex> guard(mMutex);
578     mMasterVolume = masterVolume;
579     updateEffectiveVolumeLocked();
580 }
581 
updateEffectiveVolumeLocked()582 void StreamOut::updateEffectiveVolumeLocked() {
583     mEffectiveVolume = mMasterVolume * mStreamVolume;
584 }
585 
validateDeviceAddress(const DeviceAddress & device)586 bool StreamOut::validateDeviceAddress(const DeviceAddress& device) {
587     return DevicePortSink::validateDeviceAddress(device);
588 }
589 
validateFlags(const hidl_vec<AudioInOutFlag> & flags)590 bool StreamOut::validateFlags(const hidl_vec<AudioInOutFlag>& flags) {
591     return std::all_of(flags.begin(), flags.end(), [](const AudioInOutFlag& flag){
592         return xsd::stringToAudioInOutFlag(flag) != xsd::AudioInOutFlag::UNKNOWN;
593     });
594 }
595 
validateSourceMetadata(const SourceMetadata & sourceMetadata)596 bool StreamOut::validateSourceMetadata(const SourceMetadata& sourceMetadata) {
597     for (const auto& track : sourceMetadata.tracks) {
598         if (xsd::isUnknownAudioUsage(track.usage)
599                 || xsd::isUnknownAudioContentType(track.contentType)
600                 || xsd::isUnknownAudioChannelMask(track.channelMask)) {
601             return false;
602         }
603         for (const auto& tag : track.tags) {
604             if (!xsd::isVendorExtension(tag)) {
605                 return false;
606             }
607         }
608     }
609     return true;
610 }
611 
612 }  // namespace implementation
613 }  // namespace CPP_VERSION
614 }  // namespace audio
615 }  // namespace hardware
616 }  // namespace android
617