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