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], µphones[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