1 /*
2 * Copyright (C) 2016 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 "StreamHalHidl"
18 //#define LOG_NDEBUG 0
19
20 #include PATH(android/hardware/audio/FILE_VERSION/IStreamOutCallback.h)
21 #include <hwbinder/IPCThreadState.h>
22 #include <media/AudioParameter.h>
23 #include <mediautils/SchedulingPolicyService.h>
24 #include <utils/Log.h>
25
26 #include "DeviceHalHidl.h"
27 #include "EffectHalHidl.h"
28 #include "StreamHalHidl.h"
29 #include "VersionUtils.h"
30
31 using ::android::hardware::MQDescriptorSync;
32 using ::android::hardware::Return;
33 using ::android::hardware::Void;
34
35 namespace android {
36 namespace CPP_VERSION {
37
38 using EffectHalHidl = ::android::effect::CPP_VERSION::EffectHalHidl;
39 using ReadCommand = ::android::hardware::audio::CPP_VERSION::IStreamIn::ReadCommand;
40
41 using namespace ::android::hardware::audio::common::CPP_VERSION;
42 using namespace ::android::hardware::audio::CPP_VERSION;
43
StreamHalHidl(IStream * stream)44 StreamHalHidl::StreamHalHidl(IStream *stream)
45 : ConversionHelperHidl("Stream"),
46 mStream(stream),
47 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
48 mCachedBufferSize(0){
49
50 // Instrument audio signal power logging.
51 // Note: This assumes channel mask, format, and sample rate do not change after creation.
52 if (mStream != nullptr /* && mStreamPowerLog.isUserDebugOrEngBuild() */) {
53 // Obtain audio properties (see StreamHalHidl::getAudioProperties() below).
54 Return<void> ret = mStream->getAudioProperties(
55 [&](auto sr, auto m, auto f) {
56 mStreamPowerLog.init(sr,
57 static_cast<audio_channel_mask_t>(m),
58 static_cast<audio_format_t>(f));
59 });
60 }
61 }
62
~StreamHalHidl()63 StreamHalHidl::~StreamHalHidl() {
64 mStream = nullptr;
65 }
66
getSampleRate(uint32_t * rate)67 status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
68 if (!mStream) return NO_INIT;
69 return processReturn("getSampleRate", mStream->getSampleRate(), rate);
70 }
71
getBufferSize(size_t * size)72 status_t StreamHalHidl::getBufferSize(size_t *size) {
73 if (!mStream) return NO_INIT;
74 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
75 if (status == OK) {
76 mCachedBufferSize = *size;
77 }
78 return status;
79 }
80
getChannelMask(audio_channel_mask_t * mask)81 status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
82 if (!mStream) return NO_INIT;
83 return processReturn("getChannelMask", mStream->getChannelMask(), mask);
84 }
85
getFormat(audio_format_t * format)86 status_t StreamHalHidl::getFormat(audio_format_t *format) {
87 if (!mStream) return NO_INIT;
88 return processReturn("getFormat", mStream->getFormat(), format);
89 }
90
getAudioProperties(uint32_t * sampleRate,audio_channel_mask_t * mask,audio_format_t * format)91 status_t StreamHalHidl::getAudioProperties(
92 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
93 if (!mStream) return NO_INIT;
94 Return<void> ret = mStream->getAudioProperties(
95 [&](uint32_t sr, auto m, auto f) {
96 *sampleRate = sr;
97 *mask = static_cast<audio_channel_mask_t>(m);
98 *format = static_cast<audio_format_t>(f);
99 });
100 return processReturn("getAudioProperties", ret);
101 }
102
setParameters(const String8 & kvPairs)103 status_t StreamHalHidl::setParameters(const String8& kvPairs) {
104 if (!mStream) return NO_INIT;
105 hidl_vec<ParameterValue> hidlParams;
106 status_t status = parametersFromHal(kvPairs, &hidlParams);
107 if (status != OK) return status;
108 return processReturn("setParameters",
109 utils::setParameters(mStream, {} /* context */, hidlParams));
110 }
111
getParameters(const String8 & keys,String8 * values)112 status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
113 values->clear();
114 if (!mStream) return NO_INIT;
115 hidl_vec<hidl_string> hidlKeys;
116 status_t status = keysFromHal(keys, &hidlKeys);
117 if (status != OK) return status;
118 Result retval;
119 Return<void> ret = utils::getParameters(
120 mStream,
121 {} /* context */,
122 hidlKeys,
123 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
124 retval = r;
125 if (retval == Result::OK) {
126 parametersToHal(parameters, values);
127 }
128 });
129 return processReturn("getParameters", ret, retval);
130 }
131
addEffect(sp<EffectHalInterface> effect)132 status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
133 if (!mStream) return NO_INIT;
134 return processReturn("addEffect", mStream->addEffect(
135 static_cast<EffectHalHidl*>(effect.get())->effectId()));
136 }
137
removeEffect(sp<EffectHalInterface> effect)138 status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
139 if (!mStream) return NO_INIT;
140 return processReturn("removeEffect", mStream->removeEffect(
141 static_cast<EffectHalHidl*>(effect.get())->effectId()));
142 }
143
standby()144 status_t StreamHalHidl::standby() {
145 if (!mStream) return NO_INIT;
146 return processReturn("standby", mStream->standby());
147 }
148
dump(int fd)149 status_t StreamHalHidl::dump(int fd) {
150 if (!mStream) return NO_INIT;
151 native_handle_t* hidlHandle = native_handle_create(1, 0);
152 hidlHandle->data[0] = fd;
153 Return<void> ret = mStream->debug(hidlHandle, {} /* options */);
154 native_handle_delete(hidlHandle);
155 mStreamPowerLog.dump(fd);
156 return processReturn("dump", ret);
157 }
158
start()159 status_t StreamHalHidl::start() {
160 if (!mStream) return NO_INIT;
161 return processReturn("start", mStream->start());
162 }
163
stop()164 status_t StreamHalHidl::stop() {
165 if (!mStream) return NO_INIT;
166 return processReturn("stop", mStream->stop());
167 }
168
createMmapBuffer(int32_t minSizeFrames,struct audio_mmap_buffer_info * info)169 status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
170 struct audio_mmap_buffer_info *info) {
171 Result retval;
172 Return<void> ret = mStream->createMmapBuffer(
173 minSizeFrames,
174 [&](Result r, const MmapBufferInfo& hidlInfo) {
175 retval = r;
176 if (retval == Result::OK) {
177 const native_handle *handle = hidlInfo.sharedMemory.handle();
178 if (handle->numFds > 0) {
179 info->shared_memory_fd = handle->data[0];
180 #if MAJOR_VERSION >= 4
181 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
182 #endif
183 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
184 // Negative buffer size frame was a hack in O and P to
185 // indicate that the buffer is shareable to applications
186 if (info->buffer_size_frames < 0) {
187 info->buffer_size_frames *= -1;
188 info->flags = audio_mmap_buffer_flag(
189 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
190 }
191 info->burst_size_frames = hidlInfo.burstSizeFrames;
192 // info->shared_memory_address is not needed in HIDL context
193 info->shared_memory_address = NULL;
194 } else {
195 retval = Result::NOT_INITIALIZED;
196 }
197 }
198 });
199 return processReturn("createMmapBuffer", ret, retval);
200 }
201
getMmapPosition(struct audio_mmap_position * position)202 status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
203 Result retval;
204 Return<void> ret = mStream->getMmapPosition(
205 [&](Result r, const MmapPosition& hidlPosition) {
206 retval = r;
207 if (retval == Result::OK) {
208 position->time_nanoseconds = hidlPosition.timeNanoseconds;
209 position->position_frames = hidlPosition.positionFrames;
210 }
211 });
212 return processReturn("getMmapPosition", ret, retval);
213 }
214
setHalThreadPriority(int priority)215 status_t StreamHalHidl::setHalThreadPriority(int priority) {
216 mHalThreadPriority = priority;
217 return OK;
218 }
219
getCachedBufferSize(size_t * size)220 status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
221 if (mCachedBufferSize != 0) {
222 *size = mCachedBufferSize;
223 return OK;
224 }
225 return getBufferSize(size);
226 }
227
requestHalThreadPriority(pid_t threadPid,pid_t threadId)228 bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
229 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
230 return true;
231 }
232 int err = requestPriority(
233 threadPid, threadId,
234 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
235 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
236 mHalThreadPriority, threadPid, threadId, err);
237 // Audio will still work, but latency will be higher and sometimes unacceptable.
238 return err == 0;
239 }
240
241 namespace {
242
243 /* Notes on callback ownership.
244
245 This is how (Hw)Binder ownership model looks like. The server implementation
246 is owned by Binder framework (via sp<>). Proxies are owned by clients.
247 When the last proxy disappears, Binder framework releases the server impl.
248
249 Thus, it is not needed to keep any references to StreamOutCallback (this is
250 the server impl) -- it will live as long as HAL server holds a strong ref to
251 IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
252 from the destructor of StreamOutHalHidl.
253
254 The callback only keeps a weak reference to the stream. The stream is owned
255 by AudioFlinger.
256
257 */
258
259 struct StreamOutCallback : public IStreamOutCallback {
StreamOutCallbackandroid::CPP_VERSION::__anon995fb1ee0611::StreamOutCallback260 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
261
262 // IStreamOutCallback implementation
onWriteReadyandroid::CPP_VERSION::__anon995fb1ee0611::StreamOutCallback263 Return<void> onWriteReady() override {
264 sp<StreamOutHalHidl> stream = mStream.promote();
265 if (stream != 0) {
266 stream->onWriteReady();
267 }
268 return Void();
269 }
270
onDrainReadyandroid::CPP_VERSION::__anon995fb1ee0611::StreamOutCallback271 Return<void> onDrainReady() override {
272 sp<StreamOutHalHidl> stream = mStream.promote();
273 if (stream != 0) {
274 stream->onDrainReady();
275 }
276 return Void();
277 }
278
onErrorandroid::CPP_VERSION::__anon995fb1ee0611::StreamOutCallback279 Return<void> onError() override {
280 sp<StreamOutHalHidl> stream = mStream.promote();
281 if (stream != 0) {
282 stream->onError();
283 }
284 return Void();
285 }
286
287 private:
288 wp<StreamOutHalHidl> mStream;
289 };
290
291 } // namespace
292
StreamOutHalHidl(const sp<IStreamOut> & stream)293 StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
294 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
295 }
296
~StreamOutHalHidl()297 StreamOutHalHidl::~StreamOutHalHidl() {
298 if (mStream != 0) {
299 if (mCallback.unsafe_get()) {
300 processReturn("clearCallback", mStream->clearCallback());
301 }
302 processReturn("close", mStream->close());
303 mStream.clear();
304 }
305 mCallback.clear();
306 hardware::IPCThreadState::self()->flushCommands();
307 if (mEfGroup) {
308 EventFlag::deleteEventFlag(&mEfGroup);
309 }
310 }
311
getFrameSize(size_t * size)312 status_t StreamOutHalHidl::getFrameSize(size_t *size) {
313 if (mStream == 0) return NO_INIT;
314 return processReturn("getFrameSize", mStream->getFrameSize(), size);
315 }
316
getLatency(uint32_t * latency)317 status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
318 if (mStream == 0) return NO_INIT;
319 if (mWriterClient == gettid() && mCommandMQ) {
320 return callWriterThread(
321 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
322 [&](const WriteStatus& writeStatus) {
323 *latency = writeStatus.reply.latencyMs;
324 });
325 } else {
326 return processReturn("getLatency", mStream->getLatency(), latency);
327 }
328 }
329
setVolume(float left,float right)330 status_t StreamOutHalHidl::setVolume(float left, float right) {
331 if (mStream == 0) return NO_INIT;
332 return processReturn("setVolume", mStream->setVolume(left, right));
333 }
334
335 #if MAJOR_VERSION == 2
selectPresentation(int presentationId,int programId)336 status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
337 if (mStream == 0) return NO_INIT;
338 std::vector<ParameterValue> parameters;
339 String8 halParameters;
340 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
341 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
342 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
343 return setParameters(halParameters);
344 }
345 #elif MAJOR_VERSION >= 4
selectPresentation(int presentationId,int programId)346 status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
347 if (mStream == 0) return NO_INIT;
348 return processReturn("selectPresentation",
349 mStream->selectPresentation(presentationId, programId));
350 }
351 #endif
352
write(const void * buffer,size_t bytes,size_t * written)353 status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
354 if (mStream == 0) return NO_INIT;
355 *written = 0;
356
357 if (bytes == 0 && !mDataMQ) {
358 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
359 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
360 return OK;
361 }
362
363 status_t status;
364 if (!mDataMQ) {
365 // In case if playback starts close to the end of a compressed track, the bytes
366 // that need to be written is less than the actual buffer size. Need to use
367 // full buffer size for the MQ since otherwise after seeking back to the middle
368 // data will be truncated.
369 size_t bufferSize;
370 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
371 return status;
372 }
373 if (bytes > bufferSize) bufferSize = bytes;
374 if ((status = prepareForWriting(bufferSize)) != OK) {
375 return status;
376 }
377 }
378
379 status = callWriterThread(
380 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
381 [&] (const WriteStatus& writeStatus) {
382 *written = writeStatus.reply.written;
383 // Diagnostics of the cause of b/35813113.
384 ALOGE_IF(*written > bytes,
385 "hal reports more bytes written than asked for: %lld > %lld",
386 (long long)*written, (long long)bytes);
387 });
388 mStreamPowerLog.log(buffer, *written);
389 return status;
390 }
391
callWriterThread(WriteCommand cmd,const char * cmdName,const uint8_t * data,size_t dataSize,StreamOutHalHidl::WriterCallback callback)392 status_t StreamOutHalHidl::callWriterThread(
393 WriteCommand cmd, const char* cmdName,
394 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
395 if (!mCommandMQ->write(&cmd)) {
396 ALOGE("command message queue write failed for \"%s\"", cmdName);
397 return -EAGAIN;
398 }
399 if (data != nullptr) {
400 size_t availableToWrite = mDataMQ->availableToWrite();
401 if (dataSize > availableToWrite) {
402 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
403 (long long)dataSize, (long long)availableToWrite);
404 dataSize = availableToWrite;
405 }
406 if (!mDataMQ->write(data, dataSize)) {
407 ALOGE("data message queue write failed for \"%s\"", cmdName);
408 }
409 }
410 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
411
412 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
413 uint32_t efState = 0;
414 retry:
415 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
416 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
417 WriteStatus writeStatus;
418 writeStatus.retval = Result::NOT_INITIALIZED;
419 if (!mStatusMQ->read(&writeStatus)) {
420 ALOGE("status message read failed for \"%s\"", cmdName);
421 }
422 if (writeStatus.retval == Result::OK) {
423 ret = OK;
424 callback(writeStatus);
425 } else {
426 ret = processReturn(cmdName, writeStatus.retval);
427 }
428 return ret;
429 }
430 if (ret == -EAGAIN || ret == -EINTR) {
431 // Spurious wakeup. This normally retries no more than once.
432 goto retry;
433 }
434 return ret;
435 }
436
prepareForWriting(size_t bufferSize)437 status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
438 std::unique_ptr<CommandMQ> tempCommandMQ;
439 std::unique_ptr<DataMQ> tempDataMQ;
440 std::unique_ptr<StatusMQ> tempStatusMQ;
441 Result retval;
442 pid_t halThreadPid, halThreadTid;
443 Return<void> ret = mStream->prepareForWriting(
444 1, bufferSize,
445 [&](Result r,
446 const CommandMQ::Descriptor& commandMQ,
447 const DataMQ::Descriptor& dataMQ,
448 const StatusMQ::Descriptor& statusMQ,
449 const ThreadInfo& halThreadInfo) {
450 retval = r;
451 if (retval == Result::OK) {
452 tempCommandMQ.reset(new CommandMQ(commandMQ));
453 tempDataMQ.reset(new DataMQ(dataMQ));
454 tempStatusMQ.reset(new StatusMQ(statusMQ));
455 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
456 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
457 }
458 halThreadPid = halThreadInfo.pid;
459 halThreadTid = halThreadInfo.tid;
460 }
461 });
462 if (!ret.isOk() || retval != Result::OK) {
463 return processReturn("prepareForWriting", ret, retval);
464 }
465 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
466 !tempDataMQ || !tempDataMQ->isValid() ||
467 !tempStatusMQ || !tempStatusMQ->isValid() ||
468 !mEfGroup) {
469 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
470 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
471 "Command message queue for writing is invalid");
472 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
473 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
474 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
475 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
476 "Status message queue for writing is invalid");
477 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
478 return NO_INIT;
479 }
480 requestHalThreadPriority(halThreadPid, halThreadTid);
481
482 mCommandMQ = std::move(tempCommandMQ);
483 mDataMQ = std::move(tempDataMQ);
484 mStatusMQ = std::move(tempStatusMQ);
485 mWriterClient = gettid();
486 return OK;
487 }
488
getRenderPosition(uint32_t * dspFrames)489 status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
490 if (mStream == 0) return NO_INIT;
491 Result retval;
492 Return<void> ret = mStream->getRenderPosition(
493 [&](Result r, uint32_t d) {
494 retval = r;
495 if (retval == Result::OK) {
496 *dspFrames = d;
497 }
498 });
499 return processReturn("getRenderPosition", ret, retval);
500 }
501
getNextWriteTimestamp(int64_t * timestamp)502 status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
503 if (mStream == 0) return NO_INIT;
504 Result retval;
505 Return<void> ret = mStream->getNextWriteTimestamp(
506 [&](Result r, int64_t t) {
507 retval = r;
508 if (retval == Result::OK) {
509 *timestamp = t;
510 }
511 });
512 return processReturn("getRenderPosition", ret, retval);
513 }
514
setCallback(wp<StreamOutHalInterfaceCallback> callback)515 status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
516 if (mStream == 0) return NO_INIT;
517 status_t status = processReturn(
518 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
519 if (status == OK) {
520 mCallback = callback;
521 }
522 return status;
523 }
524
supportsPauseAndResume(bool * supportsPause,bool * supportsResume)525 status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
526 if (mStream == 0) return NO_INIT;
527 Return<void> ret = mStream->supportsPauseAndResume(
528 [&](bool p, bool r) {
529 *supportsPause = p;
530 *supportsResume = r;
531 });
532 return processReturn("supportsPauseAndResume", ret);
533 }
534
pause()535 status_t StreamOutHalHidl::pause() {
536 if (mStream == 0) return NO_INIT;
537 return processReturn("pause", mStream->pause());
538 }
539
resume()540 status_t StreamOutHalHidl::resume() {
541 if (mStream == 0) return NO_INIT;
542 return processReturn("pause", mStream->resume());
543 }
544
supportsDrain(bool * supportsDrain)545 status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
546 if (mStream == 0) return NO_INIT;
547 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
548 }
549
drain(bool earlyNotify)550 status_t StreamOutHalHidl::drain(bool earlyNotify) {
551 if (mStream == 0) return NO_INIT;
552 return processReturn(
553 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
554 }
555
flush()556 status_t StreamOutHalHidl::flush() {
557 if (mStream == 0) return NO_INIT;
558 return processReturn("pause", mStream->flush());
559 }
560
getPresentationPosition(uint64_t * frames,struct timespec * timestamp)561 status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
562 if (mStream == 0) return NO_INIT;
563 if (mWriterClient == gettid() && mCommandMQ) {
564 return callWriterThread(
565 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
566 [&](const WriteStatus& writeStatus) {
567 *frames = writeStatus.reply.presentationPosition.frames;
568 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
569 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
570 });
571 } else {
572 Result retval;
573 Return<void> ret = mStream->getPresentationPosition(
574 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
575 retval = r;
576 if (retval == Result::OK) {
577 *frames = hidlFrames;
578 timestamp->tv_sec = hidlTimeStamp.tvSec;
579 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
580 }
581 });
582 return processReturn("getPresentationPosition", ret, retval);
583 }
584 }
585
586 #if MAJOR_VERSION == 2
updateSourceMetadata(const StreamOutHalInterface::SourceMetadata &)587 status_t StreamOutHalHidl::updateSourceMetadata(
588 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
589 // Audio HAL V2.0 does not support propagating source metadata
590 return INVALID_OPERATION;
591 }
592 #elif MAJOR_VERSION >= 4
593 /** Transform a standard collection to an HIDL vector. */
594 template <class Values, class ElementConverter>
transformToHidlVec(const Values & values,ElementConverter converter)595 static auto transformToHidlVec(const Values& values, ElementConverter converter) {
596 hidl_vec<decltype(converter(*values.begin()))> result{values.size()};
597 using namespace std;
598 transform(begin(values), end(values), begin(result), converter);
599 return result;
600 }
601
updateSourceMetadata(const StreamOutHalInterface::SourceMetadata & sourceMetadata)602 status_t StreamOutHalHidl::updateSourceMetadata(
603 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
604 CPP_VERSION::SourceMetadata halMetadata = {
605 .tracks = transformToHidlVec(sourceMetadata.tracks,
606 [](const playback_track_metadata& metadata) -> PlaybackTrackMetadata {
607 return {
608 .usage=static_cast<AudioUsage>(metadata.usage),
609 .contentType=static_cast<AudioContentType>(metadata.content_type),
610 .gain=metadata.gain,
611 };
612 })};
613 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(halMetadata));
614 }
615 #endif
616
onWriteReady()617 void StreamOutHalHidl::onWriteReady() {
618 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
619 if (callback == 0) return;
620 ALOGV("asyncCallback onWriteReady");
621 callback->onWriteReady();
622 }
623
onDrainReady()624 void StreamOutHalHidl::onDrainReady() {
625 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
626 if (callback == 0) return;
627 ALOGV("asyncCallback onDrainReady");
628 callback->onDrainReady();
629 }
630
onError()631 void StreamOutHalHidl::onError() {
632 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
633 if (callback == 0) return;
634 ALOGV("asyncCallback onError");
635 callback->onError();
636 }
637
638
StreamInHalHidl(const sp<IStreamIn> & stream)639 StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
640 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
641 }
642
~StreamInHalHidl()643 StreamInHalHidl::~StreamInHalHidl() {
644 if (mStream != 0) {
645 processReturn("close", mStream->close());
646 mStream.clear();
647 hardware::IPCThreadState::self()->flushCommands();
648 }
649 if (mEfGroup) {
650 EventFlag::deleteEventFlag(&mEfGroup);
651 }
652 }
653
getFrameSize(size_t * size)654 status_t StreamInHalHidl::getFrameSize(size_t *size) {
655 if (mStream == 0) return NO_INIT;
656 return processReturn("getFrameSize", mStream->getFrameSize(), size);
657 }
658
setGain(float gain)659 status_t StreamInHalHidl::setGain(float gain) {
660 if (mStream == 0) return NO_INIT;
661 return processReturn("setGain", mStream->setGain(gain));
662 }
663
read(void * buffer,size_t bytes,size_t * read)664 status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
665 if (mStream == 0) return NO_INIT;
666 *read = 0;
667
668 if (bytes == 0 && !mDataMQ) {
669 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
670 return OK;
671 }
672
673 status_t status;
674 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
675 return status;
676 }
677
678 ReadParameters params;
679 params.command = ReadCommand::READ;
680 params.params.read = bytes;
681 status = callReaderThread(params, "read",
682 [&](const ReadStatus& readStatus) {
683 const size_t availToRead = mDataMQ->availableToRead();
684 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
685 ALOGE("data message queue read failed for \"read\"");
686 }
687 ALOGW_IF(availToRead != readStatus.reply.read,
688 "HAL read report inconsistent: mq = %d, status = %d",
689 (int32_t)availToRead, (int32_t)readStatus.reply.read);
690 *read = readStatus.reply.read;
691 });
692 mStreamPowerLog.log(buffer, *read);
693 return status;
694 }
695
callReaderThread(const ReadParameters & params,const char * cmdName,StreamInHalHidl::ReaderCallback callback)696 status_t StreamInHalHidl::callReaderThread(
697 const ReadParameters& params, const char* cmdName,
698 StreamInHalHidl::ReaderCallback callback) {
699 if (!mCommandMQ->write(¶ms)) {
700 ALOGW("command message queue write failed");
701 return -EAGAIN;
702 }
703 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
704
705 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
706 uint32_t efState = 0;
707 retry:
708 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
709 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
710 ReadStatus readStatus;
711 readStatus.retval = Result::NOT_INITIALIZED;
712 if (!mStatusMQ->read(&readStatus)) {
713 ALOGE("status message read failed for \"%s\"", cmdName);
714 }
715 if (readStatus.retval == Result::OK) {
716 ret = OK;
717 callback(readStatus);
718 } else {
719 ret = processReturn(cmdName, readStatus.retval);
720 }
721 return ret;
722 }
723 if (ret == -EAGAIN || ret == -EINTR) {
724 // Spurious wakeup. This normally retries no more than once.
725 goto retry;
726 }
727 return ret;
728 }
729
prepareForReading(size_t bufferSize)730 status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
731 std::unique_ptr<CommandMQ> tempCommandMQ;
732 std::unique_ptr<DataMQ> tempDataMQ;
733 std::unique_ptr<StatusMQ> tempStatusMQ;
734 Result retval;
735 pid_t halThreadPid, halThreadTid;
736 Return<void> ret = mStream->prepareForReading(
737 1, bufferSize,
738 [&](Result r,
739 const CommandMQ::Descriptor& commandMQ,
740 const DataMQ::Descriptor& dataMQ,
741 const StatusMQ::Descriptor& statusMQ,
742 const ThreadInfo& halThreadInfo) {
743 retval = r;
744 if (retval == Result::OK) {
745 tempCommandMQ.reset(new CommandMQ(commandMQ));
746 tempDataMQ.reset(new DataMQ(dataMQ));
747 tempStatusMQ.reset(new StatusMQ(statusMQ));
748 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
749 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
750 }
751 halThreadPid = halThreadInfo.pid;
752 halThreadTid = halThreadInfo.tid;
753 }
754 });
755 if (!ret.isOk() || retval != Result::OK) {
756 return processReturn("prepareForReading", ret, retval);
757 }
758 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
759 !tempDataMQ || !tempDataMQ->isValid() ||
760 !tempStatusMQ || !tempStatusMQ->isValid() ||
761 !mEfGroup) {
762 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
763 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
764 "Command message queue for writing is invalid");
765 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
766 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
767 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
768 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
769 "Status message queue for reading is invalid");
770 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
771 return NO_INIT;
772 }
773 requestHalThreadPriority(halThreadPid, halThreadTid);
774
775 mCommandMQ = std::move(tempCommandMQ);
776 mDataMQ = std::move(tempDataMQ);
777 mStatusMQ = std::move(tempStatusMQ);
778 mReaderClient = gettid();
779 return OK;
780 }
781
getInputFramesLost(uint32_t * framesLost)782 status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
783 if (mStream == 0) return NO_INIT;
784 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
785 }
786
getCapturePosition(int64_t * frames,int64_t * time)787 status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
788 if (mStream == 0) return NO_INIT;
789 if (mReaderClient == gettid() && mCommandMQ) {
790 ReadParameters params;
791 params.command = ReadCommand::GET_CAPTURE_POSITION;
792 return callReaderThread(params, "getCapturePosition",
793 [&](const ReadStatus& readStatus) {
794 *frames = readStatus.reply.capturePosition.frames;
795 *time = readStatus.reply.capturePosition.time;
796 });
797 } else {
798 Result retval;
799 Return<void> ret = mStream->getCapturePosition(
800 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
801 retval = r;
802 if (retval == Result::OK) {
803 *frames = hidlFrames;
804 *time = hidlTime;
805 }
806 });
807 return processReturn("getCapturePosition", ret, retval);
808 }
809 }
810
811 #if MAJOR_VERSION == 2
getActiveMicrophones(std::vector<media::MicrophoneInfo> * microphones __unused)812 status_t StreamInHalHidl::getActiveMicrophones(
813 std::vector<media::MicrophoneInfo> *microphones __unused) {
814 if (mStream == 0) return NO_INIT;
815 return INVALID_OPERATION;
816 }
817
updateSinkMetadata(const StreamInHalInterface::SinkMetadata &)818 status_t StreamInHalHidl::updateSinkMetadata(
819 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
820 // Audio HAL V2.0 does not support propagating sink metadata
821 return INVALID_OPERATION;
822 }
823
824 #elif MAJOR_VERSION >= 4
getActiveMicrophones(std::vector<media::MicrophoneInfo> * microphonesInfo)825 status_t StreamInHalHidl::getActiveMicrophones(
826 std::vector<media::MicrophoneInfo> *microphonesInfo) {
827 if (!mStream) return NO_INIT;
828 Result retval;
829 Return<void> ret = mStream->getActiveMicrophones(
830 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
831 retval = r;
832 for (size_t k = 0; k < micArrayHal.size(); k++) {
833 audio_microphone_characteristic_t dst;
834 // convert
835 microphoneInfoToHal(micArrayHal[k], &dst);
836 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
837 microphonesInfo->push_back(microphone);
838 }
839 });
840 return processReturn("getActiveMicrophones", ret, retval);
841 }
842
updateSinkMetadata(const StreamInHalInterface::SinkMetadata & sinkMetadata)843 status_t StreamInHalHidl::updateSinkMetadata(const
844 StreamInHalInterface::SinkMetadata& sinkMetadata) {
845 CPP_VERSION::SinkMetadata halMetadata = {
846 .tracks = transformToHidlVec(sinkMetadata.tracks,
847 [](const record_track_metadata& metadata) -> RecordTrackMetadata {
848 return {
849 .source=static_cast<AudioSource>(metadata.source),
850 .gain=metadata.gain,
851 };
852 })};
853 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(halMetadata));
854 }
855 #endif
856
857 #if MAJOR_VERSION < 5
setPreferredMicrophoneDirection(audio_microphone_direction_t direction __unused)858 status_t StreamInHalHidl::setPreferredMicrophoneDirection(
859 audio_microphone_direction_t direction __unused) {
860 if (mStream == 0) return NO_INIT;
861 return INVALID_OPERATION;
862 }
863
setPreferredMicrophoneFieldDimension(float zoom __unused)864 status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
865 if (mStream == 0) return NO_INIT;
866 return INVALID_OPERATION;
867 }
868 #else
setPreferredMicrophoneDirection(audio_microphone_direction_t direction)869 status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
870 if (!mStream) return NO_INIT;
871 return processReturn("setPreferredMicrophoneDirection",
872 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
873 }
874
setPreferredMicrophoneFieldDimension(float zoom)875 status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
876 if (!mStream) return NO_INIT;
877 return processReturn("setPreferredMicrophoneFieldDimension",
878 mStream->setMicrophoneFieldDimension(zoom));
879 }
880 #endif
881
882 } // namespace CPP_VERSION
883 } // namespace android
884