• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 "StreamInHAL"
18 
19 #include "core/default/StreamIn.h"
20 #include "core/default/Util.h"
21 #include "common/all-versions/HidlSupport.h"
22 
23 //#define LOG_NDEBUG 0
24 #define ATRACE_TAG ATRACE_TAG_AUDIO
25 
26 #include <HidlUtils.h>
27 #include <android/log.h>
28 #include <hardware/audio.h>
29 #include <util/CoreUtils.h>
30 #include <utils/Trace.h>
31 #include <cmath>
32 #include <memory>
33 
34 namespace android {
35 namespace hardware {
36 namespace audio {
37 namespace CPP_VERSION {
38 namespace implementation {
39 
40 using ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::implementation::HidlUtils;
41 using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::implementation::CoreUtils;
42 namespace util {
43 using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION::implementation::util;
44 }
45 
46 namespace {
47 
48 class ReadThread : public Thread {
49    public:
50     // ReadThread's lifespan never exceeds StreamIn's lifespan.
ReadThread(std::atomic<bool> * stop,audio_stream_in_t * stream,StreamIn::CommandMQ * commandMQ,StreamIn::DataMQ * dataMQ,StreamIn::StatusMQ * statusMQ,EventFlag * efGroup)51     ReadThread(std::atomic<bool>* stop, audio_stream_in_t* stream, StreamIn::CommandMQ* commandMQ,
52                StreamIn::DataMQ* dataMQ, StreamIn::StatusMQ* statusMQ, EventFlag* efGroup)
53         : Thread(false /*canCallJava*/),
54           mStop(stop),
55           mStream(stream),
56           mCommandMQ(commandMQ),
57           mDataMQ(dataMQ),
58           mStatusMQ(statusMQ),
59           mEfGroup(efGroup),
60           mBuffer(nullptr) {}
init()61     bool init() {
62         mBuffer.reset(new (std::nothrow) uint8_t[mDataMQ->getQuantumCount()]);
63         return mBuffer != nullptr;
64     }
~ReadThread()65     virtual ~ReadThread() {}
66 
67    private:
68     std::atomic<bool>* mStop;
69     audio_stream_in_t* mStream;
70     StreamIn::CommandMQ* mCommandMQ;
71     StreamIn::DataMQ* mDataMQ;
72     StreamIn::StatusMQ* mStatusMQ;
73     EventFlag* mEfGroup;
74     std::unique_ptr<uint8_t[]> mBuffer;
75     IStreamIn::ReadParameters mParameters;
76     IStreamIn::ReadStatus mStatus;
77 
78     bool threadLoop() override;
79 
80     void doGetCapturePosition();
81     void doRead();
82 };
83 
doRead()84 void ReadThread::doRead() {
85     size_t availableToWrite = mDataMQ->availableToWrite();
86     size_t requestedToRead = mParameters.params.read;
87     if (requestedToRead > availableToWrite) {
88         ALOGW(
89             "truncating read data from %d to %d due to insufficient data queue "
90             "space",
91             (int32_t)requestedToRead, (int32_t)availableToWrite);
92         requestedToRead = availableToWrite;
93     }
94     ssize_t readResult = mStream->read(mStream, &mBuffer[0], requestedToRead);
95     mStatus.retval = Result::OK;
96     if (readResult >= 0) {
97         mStatus.reply.read = readResult;
98         if (!mDataMQ->write(&mBuffer[0], readResult)) {
99             ALOGW("data message queue write failed");
100         }
101     } else {
102         mStatus.retval = Stream::analyzeStatus("read", readResult);
103     }
104 }
105 
doGetCapturePosition()106 void ReadThread::doGetCapturePosition() {
107     mStatus.retval = StreamIn::getCapturePositionImpl(
108         mStream, &mStatus.reply.capturePosition.frames, &mStatus.reply.capturePosition.time);
109 }
110 
threadLoop()111 bool ReadThread::threadLoop() {
112     // This implementation doesn't return control back to the Thread until it
113     // decides to stop,
114     // as the Thread uses mutexes, and this can lead to priority inversion.
115     while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
116         uint32_t efState = 0;
117         mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
118         if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL))) {
119             continue;  // Nothing to do.
120         }
121         if (!mCommandMQ->read(&mParameters)) {
122             continue;  // Nothing to do.
123         }
124         mStatus.replyTo = mParameters.command;
125         switch (mParameters.command) {
126             case IStreamIn::ReadCommand::READ:
127                 doRead();
128                 break;
129             case IStreamIn::ReadCommand::GET_CAPTURE_POSITION:
130                 doGetCapturePosition();
131                 break;
132             default:
133                 ALOGE("Unknown read thread command code %d", mParameters.command);
134                 mStatus.retval = Result::NOT_SUPPORTED;
135                 break;
136         }
137         if (!mStatusMQ->write(&mStatus)) {
138             ALOGW("status message queue write failed");
139         }
140         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
141     }
142 
143     return false;
144 }
145 
146 }  // namespace
147 
StreamIn(const sp<Device> & device,audio_stream_in_t * stream)148 StreamIn::StreamIn(const sp<Device>& device, audio_stream_in_t* stream)
149     : mDevice(device),
150       mStream(stream),
151       mStreamCommon(new Stream(true /*isInput*/, &stream->common)),
152       mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
153       mEfGroup(nullptr),
154       mStopReadThread(false) {}
155 
~StreamIn()156 StreamIn::~StreamIn() {
157     ATRACE_CALL();
158     close();
159     if (mReadThread.get()) {
160         ATRACE_NAME("mReadThread->join");
161         status_t status = mReadThread->join();
162         ALOGE_IF(status, "read thread exit error: %s", strerror(-status));
163     }
164     if (mEfGroup) {
165         status_t status = EventFlag::deleteEventFlag(&mEfGroup);
166         ALOGE_IF(status, "read MQ event flag deletion error: %s", strerror(-status));
167     }
168 #if MAJOR_VERSION <= 5
169     mDevice->closeInputStream(mStream);
170 #endif
171     mStream = nullptr;
172 }
173 
174 // Methods from ::android::hardware::audio::CPP_VERSION::IStream follow.
getFrameSize()175 Return<uint64_t> StreamIn::getFrameSize() {
176     return audio_stream_in_frame_size(mStream);
177 }
178 
getFrameCount()179 Return<uint64_t> StreamIn::getFrameCount() {
180     return mStreamCommon->getFrameCount();
181 }
182 
getBufferSize()183 Return<uint64_t> StreamIn::getBufferSize() {
184     return mStreamCommon->getBufferSize();
185 }
186 
187 #if MAJOR_VERSION <= 6
getSampleRate()188 Return<uint32_t> StreamIn::getSampleRate() {
189     return mStreamCommon->getSampleRate();
190 }
191 
192 #if MAJOR_VERSION == 2
getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb)193 Return<void> StreamIn::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
194     return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
195 }
getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb)196 Return<void> StreamIn::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
197     return mStreamCommon->getSupportedSampleRates(_hidl_cb);
198 }
199 #endif
200 
getSupportedChannelMasks(AudioFormat format,getSupportedChannelMasks_cb _hidl_cb)201 Return<void> StreamIn::getSupportedChannelMasks(AudioFormat format,
202                                                 getSupportedChannelMasks_cb _hidl_cb) {
203     return mStreamCommon->getSupportedChannelMasks(format, _hidl_cb);
204 }
getSupportedSampleRates(AudioFormat format,getSupportedSampleRates_cb _hidl_cb)205 Return<void> StreamIn::getSupportedSampleRates(AudioFormat format,
206                                                getSupportedSampleRates_cb _hidl_cb) {
207     return mStreamCommon->getSupportedSampleRates(format, _hidl_cb);
208 }
209 
setSampleRate(uint32_t sampleRateHz)210 Return<Result> StreamIn::setSampleRate(uint32_t sampleRateHz) {
211     return mStreamCommon->setSampleRate(sampleRateHz);
212 }
213 
getChannelMask()214 Return<AudioChannelBitfield> StreamIn::getChannelMask() {
215     return mStreamCommon->getChannelMask();
216 }
217 
setChannelMask(AudioChannelBitfield mask)218 Return<Result> StreamIn::setChannelMask(AudioChannelBitfield mask) {
219     return mStreamCommon->setChannelMask(mask);
220 }
221 
getFormat()222 Return<AudioFormat> StreamIn::getFormat() {
223     return mStreamCommon->getFormat();
224 }
225 
getSupportedFormats(getSupportedFormats_cb _hidl_cb)226 Return<void> StreamIn::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
227     return mStreamCommon->getSupportedFormats(_hidl_cb);
228 }
229 
setFormat(AudioFormat format)230 Return<Result> StreamIn::setFormat(AudioFormat format) {
231     return mStreamCommon->setFormat(format);
232 }
233 
234 #else
235 
getSupportedProfiles(getSupportedProfiles_cb _hidl_cb)236 Return<void> StreamIn::getSupportedProfiles(getSupportedProfiles_cb _hidl_cb) {
237     return mStreamCommon->getSupportedProfiles(_hidl_cb);
238 }
239 
setAudioProperties(const AudioConfigBaseOptional & config)240 Return<Result> StreamIn::setAudioProperties(const AudioConfigBaseOptional& config) {
241     return mStreamCommon->setAudioProperties(config);
242 }
243 
244 #endif  // MAJOR_VERSION <= 6
245 
getAudioProperties(getAudioProperties_cb _hidl_cb)246 Return<void> StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) {
247     return mStreamCommon->getAudioProperties(_hidl_cb);
248 }
249 
addEffect(uint64_t effectId)250 Return<Result> StreamIn::addEffect(uint64_t effectId) {
251     return mStreamCommon->addEffect(effectId);
252 }
253 
removeEffect(uint64_t effectId)254 Return<Result> StreamIn::removeEffect(uint64_t effectId) {
255     return mStreamCommon->removeEffect(effectId);
256 }
257 
standby()258 Return<Result> StreamIn::standby() {
259     return mStreamCommon->standby();
260 }
261 
setHwAvSync(uint32_t hwAvSync)262 Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) {
263     return mStreamCommon->setHwAvSync(hwAvSync);
264 }
265 
266 #if MAJOR_VERSION == 2
setConnectedState(const DeviceAddress & address,bool connected)267 Return<Result> StreamIn::setConnectedState(const DeviceAddress& address, bool connected) {
268     return mStreamCommon->setConnectedState(address, connected);
269 }
270 
getDevice()271 Return<AudioDevice> StreamIn::getDevice() {
272     return mStreamCommon->getDevice();
273 }
274 
setDevice(const DeviceAddress & address)275 Return<Result> StreamIn::setDevice(const DeviceAddress& address) {
276     return mStreamCommon->setDevice(address);
277 }
278 
getParameters(const hidl_vec<hidl_string> & keys,getParameters_cb _hidl_cb)279 Return<void> StreamIn::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
280     return mStreamCommon->getParameters(keys, _hidl_cb);
281 }
282 
setParameters(const hidl_vec<ParameterValue> & parameters)283 Return<Result> StreamIn::setParameters(const hidl_vec<ParameterValue>& parameters) {
284     return mStreamCommon->setParameters(parameters);
285 }
286 
debugDump(const hidl_handle & fd)287 Return<void> StreamIn::debugDump(const hidl_handle& fd) {
288     return mStreamCommon->debugDump(fd);
289 }
290 #elif MAJOR_VERSION >= 4
getDevices(getDevices_cb _hidl_cb)291 Return<void> StreamIn::getDevices(getDevices_cb _hidl_cb) {
292     return mStreamCommon->getDevices(_hidl_cb);
293 }
294 
setDevices(const hidl_vec<DeviceAddress> & devices)295 Return<Result> StreamIn::setDevices(const hidl_vec<DeviceAddress>& devices) {
296     return mStreamCommon->setDevices(devices);
297 }
getParameters(const hidl_vec<ParameterValue> & context,const hidl_vec<hidl_string> & keys,getParameters_cb _hidl_cb)298 Return<void> StreamIn::getParameters(const hidl_vec<ParameterValue>& context,
299                                      const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
300     return mStreamCommon->getParameters(context, keys, _hidl_cb);
301 }
302 
setParameters(const hidl_vec<ParameterValue> & context,const hidl_vec<ParameterValue> & parameters)303 Return<Result> StreamIn::setParameters(const hidl_vec<ParameterValue>& context,
304                                        const hidl_vec<ParameterValue>& parameters) {
305     return mStreamCommon->setParameters(context, parameters);
306 }
307 #endif
308 
start()309 Return<Result> StreamIn::start() {
310     return mStreamMmap->start();
311 }
312 
stop()313 Return<Result> StreamIn::stop() {
314     return mStreamMmap->stop();
315 }
316 
createMmapBuffer(int32_t minSizeFrames,createMmapBuffer_cb _hidl_cb)317 Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) {
318     return mStreamMmap->createMmapBuffer(minSizeFrames, audio_stream_in_frame_size(mStream),
319                                          _hidl_cb);
320 }
321 
getMmapPosition(getMmapPosition_cb _hidl_cb)322 Return<void> StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) {
323     return mStreamMmap->getMmapPosition(_hidl_cb);
324 }
325 
close()326 Return<Result> StreamIn::close() {
327     if (mStopReadThread.load(std::memory_order_relaxed)) {  // only this thread writes
328         return Result::INVALID_STATE;
329     }
330     mStopReadThread.store(true, std::memory_order_release);
331     if (mEfGroup) {
332         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
333     }
334 #if MAJOR_VERSION >= 6
335     mDevice->closeInputStream(mStream);
336 #endif
337     return Result::OK;
338 }
339 
340 // Methods from ::android::hardware::audio::CPP_VERSION::IStreamIn follow.
getAudioSource(getAudioSource_cb _hidl_cb)341 Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
342     int halSource;
343     Result retval = mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource);
344     AudioSource source = {};
345     if (retval == Result::OK) {
346         retval = Stream::analyzeStatus(
347                 "get_audio_source",
348                 HidlUtils::audioSourceFromHal(static_cast<audio_source_t>(halSource), &source));
349     }
350     _hidl_cb(retval, source);
351     return Void();
352 }
353 
setGain(float gain)354 Return<Result> StreamIn::setGain(float gain) {
355     if (!util::isGainNormalized(gain)) {
356         ALOGW("Can not set a stream input gain (%f) outside [0,1]", gain);
357         return Result::INVALID_ARGUMENTS;
358     }
359     return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain));
360 }
361 
prepareForReading(uint32_t frameSize,uint32_t framesCount,prepareForReading_cb _hidl_cb)362 Return<void> StreamIn::prepareForReading(uint32_t frameSize, uint32_t framesCount,
363                                          prepareForReading_cb _hidl_cb) {
364     status_t status;
365 #if MAJOR_VERSION <= 6
366     ThreadInfo threadInfo = {0, 0};
367 #else
368     int32_t threadInfo = 0;
369 #endif
370 
371     // Wrap the _hidl_cb to return an error
372     auto sendError = [&threadInfo, &_hidl_cb](Result result) {
373         _hidl_cb(result, CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(),
374                  threadInfo);
375     };
376 
377     // Create message queues.
378     if (mDataMQ) {
379         ALOGE("the client attempts to call prepareForReading twice");
380         sendError(Result::INVALID_STATE);
381         return Void();
382     }
383     std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
384 
385     // Check frameSize and framesCount
386     if (frameSize == 0 || framesCount == 0) {
387         ALOGE("Null frameSize (%u) or framesCount (%u)", frameSize, framesCount);
388         sendError(Result::INVALID_ARGUMENTS);
389         return Void();
390     }
391 
392     if (frameSize > Stream::MAX_BUFFER_SIZE / framesCount) {
393         ALOGE("Buffer too big: %u*%u bytes > MAX_BUFFER_SIZE (%u)", frameSize, framesCount,
394               Stream::MAX_BUFFER_SIZE);
395         sendError(Result::INVALID_ARGUMENTS);
396         return Void();
397     }
398     std::unique_ptr<DataMQ> tempDataMQ(new DataMQ(frameSize * framesCount, true /* EventFlag */));
399 
400     std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
401     if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
402         ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
403         ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
404         ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
405         sendError(Result::INVALID_ARGUMENTS);
406         return Void();
407     }
408     EventFlag* tempRawEfGroup{};
409     status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &tempRawEfGroup);
410     std::unique_ptr<EventFlag, void (*)(EventFlag*)> tempElfGroup(
411         tempRawEfGroup, [](auto* ef) { EventFlag::deleteEventFlag(&ef); });
412     if (status != OK || !tempElfGroup) {
413         ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
414         sendError(Result::INVALID_ARGUMENTS);
415         return Void();
416     }
417 
418     // Create and launch the thread.
419     auto tempReadThread =
420             sp<ReadThread>::make(&mStopReadThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
421                                  tempStatusMQ.get(), tempElfGroup.get());
422     if (!tempReadThread->init()) {
423         ALOGW("failed to start reader thread: %s", strerror(-status));
424         sendError(Result::INVALID_ARGUMENTS);
425         return Void();
426     }
427     status = tempReadThread->run("reader", PRIORITY_URGENT_AUDIO);
428     if (status != OK) {
429         ALOGW("failed to start reader thread: %s", strerror(-status));
430         sendError(Result::INVALID_ARGUMENTS);
431         return Void();
432     }
433 
434     mCommandMQ = std::move(tempCommandMQ);
435     mDataMQ = std::move(tempDataMQ);
436     mStatusMQ = std::move(tempStatusMQ);
437     mReadThread = tempReadThread;
438     mEfGroup = tempElfGroup.release();
439 #if MAJOR_VERSION <= 6
440     threadInfo.pid = getpid();
441     threadInfo.tid = mReadThread->getTid();
442 #else
443     threadInfo = mReadThread->getTid();
444 #endif
445     _hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(),
446              threadInfo);
447     return Void();
448 }
449 
getInputFramesLost()450 Return<uint32_t> StreamIn::getInputFramesLost() {
451     return mStream->get_input_frames_lost(mStream);
452 }
453 
454 // static
getCapturePositionImpl(audio_stream_in_t * stream,uint64_t * frames,uint64_t * time)455 Result StreamIn::getCapturePositionImpl(audio_stream_in_t* stream, uint64_t* frames,
456                                         uint64_t* time) {
457     // HAL may have a stub function, always returning ENOSYS, don't
458     // spam the log in this case.
459     static const std::vector<int> ignoredErrors{ENOSYS};
460     Result retval(Result::NOT_SUPPORTED);
461     if (stream->get_capture_position == NULL) return retval;
462     int64_t halFrames, halTime;
463     retval = Stream::analyzeStatus("get_capture_position",
464                                    stream->get_capture_position(stream, &halFrames, &halTime),
465                                    ignoredErrors);
466     if (retval == Result::OK) {
467         *frames = halFrames;
468         *time = halTime;
469     }
470     return retval;
471 };
472 
getCapturePosition(getCapturePosition_cb _hidl_cb)473 Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) {
474     uint64_t frames = 0, time = 0;
475     Result retval = getCapturePositionImpl(mStream, &frames, &time);
476     _hidl_cb(retval, frames, time);
477     return Void();
478 }
479 
debug(const hidl_handle & fd,const hidl_vec<hidl_string> & options)480 Return<void> StreamIn::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
481     return mStreamCommon->debug(fd, options);
482 }
483 
484 #if MAJOR_VERSION >= 4
doUpdateSinkMetadata(const SinkMetadata & sinkMetadata)485 Result StreamIn::doUpdateSinkMetadata(const SinkMetadata& sinkMetadata) {
486     std::vector<record_track_metadata> halTracks;
487 #if MAJOR_VERSION <= 6
488     (void)CoreUtils::sinkMetadataToHal(sinkMetadata, &halTracks);
489 #else
490     // Validate whether a conversion to V7 is possible. This is needed
491     // to have a consistent behavior of the HAL regardless of the API
492     // version of the legacy HAL (and also to be consistent with openInputStream).
493     std::vector<record_track_metadata_v7> halTracksV7;
494     if (status_t status = CoreUtils::sinkMetadataToHalV7(
495                 sinkMetadata, false /*ignoreNonVendorTags*/, &halTracksV7);
496         status == NO_ERROR) {
497         halTracks.reserve(halTracksV7.size());
498         for (auto metadata_v7 : halTracksV7) {
499             halTracks.push_back(std::move(metadata_v7.base));
500         }
501     } else {
502         return Stream::analyzeStatus("sinkMetadataToHal", status);
503     }
504 #endif  // MAJOR_VERSION <= 6
505     const sink_metadata_t halMetadata = {
506         .track_count = halTracks.size(),
507         .tracks = halTracks.data(),
508     };
509     mStream->update_sink_metadata(mStream, &halMetadata);
510     return Result::OK;
511 }
512 
513 #if MAJOR_VERSION >= 7
doUpdateSinkMetadataV7(const SinkMetadata & sinkMetadata)514 Result StreamIn::doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata) {
515     std::vector<record_track_metadata_v7> halTracks;
516     if (status_t status = CoreUtils::sinkMetadataToHalV7(sinkMetadata,
517                                                          false /*ignoreNonVendorTags*/, &halTracks);
518         status != NO_ERROR) {
519         return Stream::analyzeStatus("sinkMetadataToHal", status);
520     }
521     const sink_metadata_v7_t halMetadata = {
522             .track_count = halTracks.size(),
523             .tracks = halTracks.data(),
524     };
525     mStream->update_sink_metadata_v7(mStream, &halMetadata);
526     return Result::OK;
527 }
528 #endif  //  MAJOR_VERSION >= 7
529 
530 #if MAJOR_VERSION <= 6
updateSinkMetadata(const SinkMetadata & sinkMetadata)531 Return<void> StreamIn::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
532     if (mStream->update_sink_metadata == nullptr) {
533         return Void();  // not supported by the HAL
534     }
535     (void)doUpdateSinkMetadata(sinkMetadata);
536     return Void();
537 }
538 #elif MAJOR_VERSION >= 7
updateSinkMetadata(const SinkMetadata & sinkMetadata)539 Return<Result> StreamIn::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
540     if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) {
541         if (mStream->update_sink_metadata == nullptr) {
542             return Result::NOT_SUPPORTED;
543         }
544         return doUpdateSinkMetadata(sinkMetadata);
545     } else {
546         if (mStream->update_sink_metadata_v7 == nullptr) {
547             return Result::NOT_SUPPORTED;
548         }
549         return doUpdateSinkMetadataV7(sinkMetadata);
550     }
551 }
552 #endif
553 
getActiveMicrophones(getActiveMicrophones_cb _hidl_cb)554 Return<void> StreamIn::getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) {
555     Result retval = Result::NOT_SUPPORTED;
556     size_t actual_mics = AUDIO_MICROPHONE_MAX_COUNT;
557     audio_microphone_characteristic_t mic_array[AUDIO_MICROPHONE_MAX_COUNT];
558 
559     hidl_vec<MicrophoneInfo> microphones;
560     if (mStream->get_active_microphones != NULL &&
561         mStream->get_active_microphones(mStream, &mic_array[0], &actual_mics) == 0) {
562         microphones.resize(actual_mics);
563         for (size_t i = 0; i < actual_mics; ++i) {
564             (void)CoreUtils::microphoneInfoFromHal(mic_array[i], &microphones[i]);
565         }
566         retval = Result::OK;
567     }
568 
569     _hidl_cb(retval, microphones);
570     return Void();
571 }
572 #endif
573 
574 #if MAJOR_VERSION >= 5
setMicrophoneDirection(MicrophoneDirection direction)575 Return<Result> StreamIn::setMicrophoneDirection(MicrophoneDirection direction) {
576     if (mStream->set_microphone_direction == nullptr) {
577         return Result::NOT_SUPPORTED;
578     }
579     if (!common::utils::isValidHidlEnum(direction)) {
580         ALOGE("%s: Invalid direction %d", __func__, direction);
581         return Result::INVALID_ARGUMENTS;
582     }
583     return Stream::analyzeStatus(
584             "set_microphone_direction",
585             mStream->set_microphone_direction(
586                     mStream, static_cast<audio_microphone_direction_t>(direction)));
587 }
588 
setMicrophoneFieldDimension(float zoom)589 Return<Result> StreamIn::setMicrophoneFieldDimension(float zoom) {
590     if (mStream->set_microphone_field_dimension == nullptr) {
591         return Result::NOT_SUPPORTED;
592     }
593     if (std::isnan(zoom) || zoom < -1 || zoom > 1) {
594         ALOGE("%s: Invalid zoom %f", __func__, zoom);
595         return Result::INVALID_ARGUMENTS;
596     }
597     return Stream::analyzeStatus("set_microphone_field_dimension",
598                                  mStream->set_microphone_field_dimension(mStream, zoom));
599 }
600 
601 #endif
602 
603 }  // namespace implementation
604 }  // namespace CPP_VERSION
605 }  // namespace audio
606 }  // namespace hardware
607 }  // namespace android
608