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::__anonb47d31e50611::StreamOutCallback260 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
261
262 // IStreamOutCallback implementation
onWriteReadyandroid::CPP_VERSION::__anonb47d31e50611::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::__anonb47d31e50611::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::__anonb47d31e50611::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 #if MAJOR_VERSION >= 6
303 if (mEventCallback.unsafe_get() != nullptr) {
304 processReturn("setEventCallback",
305 mStream->setEventCallback(nullptr));
306 }
307 #endif
308 processReturn("close", mStream->close());
309 mStream.clear();
310 }
311 mCallback.clear();
312 mEventCallback.clear();
313 hardware::IPCThreadState::self()->flushCommands();
314 if (mEfGroup) {
315 EventFlag::deleteEventFlag(&mEfGroup);
316 }
317 }
318
getFrameSize(size_t * size)319 status_t StreamOutHalHidl::getFrameSize(size_t *size) {
320 if (mStream == 0) return NO_INIT;
321 return processReturn("getFrameSize", mStream->getFrameSize(), size);
322 }
323
getLatency(uint32_t * latency)324 status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
325 if (mStream == 0) return NO_INIT;
326 if (mWriterClient == gettid() && mCommandMQ) {
327 return callWriterThread(
328 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
329 [&](const WriteStatus& writeStatus) {
330 *latency = writeStatus.reply.latencyMs;
331 });
332 } else {
333 return processReturn("getLatency", mStream->getLatency(), latency);
334 }
335 }
336
setVolume(float left,float right)337 status_t StreamOutHalHidl::setVolume(float left, float right) {
338 if (mStream == 0) return NO_INIT;
339 return processReturn("setVolume", mStream->setVolume(left, right));
340 }
341
342 #if MAJOR_VERSION == 2
selectPresentation(int presentationId,int programId)343 status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
344 if (mStream == 0) return NO_INIT;
345 std::vector<ParameterValue> parameters;
346 String8 halParameters;
347 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
348 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
349 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
350 return setParameters(halParameters);
351 }
352 #elif MAJOR_VERSION >= 4
selectPresentation(int presentationId,int programId)353 status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
354 if (mStream == 0) return NO_INIT;
355 return processReturn("selectPresentation",
356 mStream->selectPresentation(presentationId, programId));
357 }
358 #endif
359
write(const void * buffer,size_t bytes,size_t * written)360 status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
361 if (mStream == 0) return NO_INIT;
362 *written = 0;
363
364 if (bytes == 0 && !mDataMQ) {
365 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
366 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
367 return OK;
368 }
369
370 status_t status;
371 if (!mDataMQ) {
372 // In case if playback starts close to the end of a compressed track, the bytes
373 // that need to be written is less than the actual buffer size. Need to use
374 // full buffer size for the MQ since otherwise after seeking back to the middle
375 // data will be truncated.
376 size_t bufferSize;
377 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
378 return status;
379 }
380 if (bytes > bufferSize) bufferSize = bytes;
381 if ((status = prepareForWriting(bufferSize)) != OK) {
382 return status;
383 }
384 }
385
386 status = callWriterThread(
387 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
388 [&] (const WriteStatus& writeStatus) {
389 *written = writeStatus.reply.written;
390 // Diagnostics of the cause of b/35813113.
391 ALOGE_IF(*written > bytes,
392 "hal reports more bytes written than asked for: %lld > %lld",
393 (long long)*written, (long long)bytes);
394 });
395 mStreamPowerLog.log(buffer, *written);
396 return status;
397 }
398
callWriterThread(WriteCommand cmd,const char * cmdName,const uint8_t * data,size_t dataSize,StreamOutHalHidl::WriterCallback callback)399 status_t StreamOutHalHidl::callWriterThread(
400 WriteCommand cmd, const char* cmdName,
401 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
402 if (!mCommandMQ->write(&cmd)) {
403 ALOGE("command message queue write failed for \"%s\"", cmdName);
404 return -EAGAIN;
405 }
406 if (data != nullptr) {
407 size_t availableToWrite = mDataMQ->availableToWrite();
408 if (dataSize > availableToWrite) {
409 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
410 (long long)dataSize, (long long)availableToWrite);
411 dataSize = availableToWrite;
412 }
413 if (!mDataMQ->write(data, dataSize)) {
414 ALOGE("data message queue write failed for \"%s\"", cmdName);
415 }
416 }
417 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
418
419 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
420 uint32_t efState = 0;
421 retry:
422 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
423 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
424 WriteStatus writeStatus;
425 writeStatus.retval = Result::NOT_INITIALIZED;
426 if (!mStatusMQ->read(&writeStatus)) {
427 ALOGE("status message read failed for \"%s\"", cmdName);
428 }
429 if (writeStatus.retval == Result::OK) {
430 ret = OK;
431 callback(writeStatus);
432 } else {
433 ret = processReturn(cmdName, writeStatus.retval);
434 }
435 return ret;
436 }
437 if (ret == -EAGAIN || ret == -EINTR) {
438 // Spurious wakeup. This normally retries no more than once.
439 goto retry;
440 }
441 return ret;
442 }
443
prepareForWriting(size_t bufferSize)444 status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
445 std::unique_ptr<CommandMQ> tempCommandMQ;
446 std::unique_ptr<DataMQ> tempDataMQ;
447 std::unique_ptr<StatusMQ> tempStatusMQ;
448 Result retval;
449 pid_t halThreadPid, halThreadTid;
450 Return<void> ret = mStream->prepareForWriting(
451 1, bufferSize,
452 [&](Result r,
453 const CommandMQ::Descriptor& commandMQ,
454 const DataMQ::Descriptor& dataMQ,
455 const StatusMQ::Descriptor& statusMQ,
456 const ThreadInfo& halThreadInfo) {
457 retval = r;
458 if (retval == Result::OK) {
459 tempCommandMQ.reset(new CommandMQ(commandMQ));
460 tempDataMQ.reset(new DataMQ(dataMQ));
461 tempStatusMQ.reset(new StatusMQ(statusMQ));
462 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
463 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
464 }
465 halThreadPid = halThreadInfo.pid;
466 halThreadTid = halThreadInfo.tid;
467 }
468 });
469 if (!ret.isOk() || retval != Result::OK) {
470 return processReturn("prepareForWriting", ret, retval);
471 }
472 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
473 !tempDataMQ || !tempDataMQ->isValid() ||
474 !tempStatusMQ || !tempStatusMQ->isValid() ||
475 !mEfGroup) {
476 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
477 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
478 "Command message queue for writing is invalid");
479 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
480 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
481 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
482 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
483 "Status message queue for writing is invalid");
484 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
485 return NO_INIT;
486 }
487 requestHalThreadPriority(halThreadPid, halThreadTid);
488
489 mCommandMQ = std::move(tempCommandMQ);
490 mDataMQ = std::move(tempDataMQ);
491 mStatusMQ = std::move(tempStatusMQ);
492 mWriterClient = gettid();
493 return OK;
494 }
495
getRenderPosition(uint32_t * dspFrames)496 status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
497 if (mStream == 0) return NO_INIT;
498 Result retval;
499 Return<void> ret = mStream->getRenderPosition(
500 [&](Result r, uint32_t d) {
501 retval = r;
502 if (retval == Result::OK) {
503 *dspFrames = d;
504 }
505 });
506 return processReturn("getRenderPosition", ret, retval);
507 }
508
getNextWriteTimestamp(int64_t * timestamp)509 status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
510 if (mStream == 0) return NO_INIT;
511 Result retval;
512 Return<void> ret = mStream->getNextWriteTimestamp(
513 [&](Result r, int64_t t) {
514 retval = r;
515 if (retval == Result::OK) {
516 *timestamp = t;
517 }
518 });
519 return processReturn("getRenderPosition", ret, retval);
520 }
521
setCallback(wp<StreamOutHalInterfaceCallback> callback)522 status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
523 if (mStream == 0) return NO_INIT;
524 status_t status = processReturn(
525 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
526 if (status == OK) {
527 mCallback = callback;
528 }
529 return status;
530 }
531
supportsPauseAndResume(bool * supportsPause,bool * supportsResume)532 status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
533 if (mStream == 0) return NO_INIT;
534 Return<void> ret = mStream->supportsPauseAndResume(
535 [&](bool p, bool r) {
536 *supportsPause = p;
537 *supportsResume = r;
538 });
539 return processReturn("supportsPauseAndResume", ret);
540 }
541
pause()542 status_t StreamOutHalHidl::pause() {
543 if (mStream == 0) return NO_INIT;
544 return processReturn("pause", mStream->pause());
545 }
546
resume()547 status_t StreamOutHalHidl::resume() {
548 if (mStream == 0) return NO_INIT;
549 return processReturn("pause", mStream->resume());
550 }
551
supportsDrain(bool * supportsDrain)552 status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
553 if (mStream == 0) return NO_INIT;
554 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
555 }
556
drain(bool earlyNotify)557 status_t StreamOutHalHidl::drain(bool earlyNotify) {
558 if (mStream == 0) return NO_INIT;
559 return processReturn(
560 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
561 }
562
flush()563 status_t StreamOutHalHidl::flush() {
564 if (mStream == 0) return NO_INIT;
565 return processReturn("pause", mStream->flush());
566 }
567
getPresentationPosition(uint64_t * frames,struct timespec * timestamp)568 status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
569 if (mStream == 0) return NO_INIT;
570 if (mWriterClient == gettid() && mCommandMQ) {
571 return callWriterThread(
572 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
573 [&](const WriteStatus& writeStatus) {
574 *frames = writeStatus.reply.presentationPosition.frames;
575 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
576 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
577 });
578 } else {
579 Result retval;
580 Return<void> ret = mStream->getPresentationPosition(
581 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
582 retval = r;
583 if (retval == Result::OK) {
584 *frames = hidlFrames;
585 timestamp->tv_sec = hidlTimeStamp.tvSec;
586 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
587 }
588 });
589 return processReturn("getPresentationPosition", ret, retval);
590 }
591 }
592
593 #if MAJOR_VERSION == 2
updateSourceMetadata(const StreamOutHalInterface::SourceMetadata &)594 status_t StreamOutHalHidl::updateSourceMetadata(
595 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
596 // Audio HAL V2.0 does not support propagating source metadata
597 return INVALID_OPERATION;
598 }
599 #elif MAJOR_VERSION >= 4
600 /** Transform a standard collection to an HIDL vector. */
601 template <class Values, class ElementConverter>
transformToHidlVec(const Values & values,ElementConverter converter)602 static auto transformToHidlVec(const Values& values, ElementConverter converter) {
603 hidl_vec<decltype(converter(*values.begin()))> result{values.size()};
604 using namespace std;
605 transform(begin(values), end(values), begin(result), converter);
606 return result;
607 }
608
updateSourceMetadata(const StreamOutHalInterface::SourceMetadata & sourceMetadata)609 status_t StreamOutHalHidl::updateSourceMetadata(
610 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
611 CPP_VERSION::SourceMetadata halMetadata = {
612 .tracks = transformToHidlVec(sourceMetadata.tracks,
613 [](const playback_track_metadata& metadata) -> PlaybackTrackMetadata {
614 return {
615 .usage=static_cast<AudioUsage>(metadata.usage),
616 .contentType=static_cast<AudioContentType>(metadata.content_type),
617 .gain=metadata.gain,
618 };
619 })};
620 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(halMetadata));
621 }
622 #endif
623
624 #if MAJOR_VERSION < 6
setEventCallback(const sp<StreamOutHalInterfaceEventCallback> & callback __unused)625 status_t StreamOutHalHidl::setEventCallback(
626 const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
627 // Codec format callback is supported starting from audio HAL V6.0
628 return INVALID_OPERATION;
629 }
630 #else
631
632 #include PATH(android/hardware/audio/FILE_VERSION/IStreamOutEventCallback.h)
633
634 namespace {
635
636 struct StreamOutEventCallback : public IStreamOutEventCallback {
StreamOutEventCallbackandroid::CPP_VERSION::__anonb47d31e51011::StreamOutEventCallback637 StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
638
639 // IStreamOutEventCallback implementation
onCodecFormatChangedandroid::CPP_VERSION::__anonb47d31e51011::StreamOutEventCallback640 Return<void> onCodecFormatChanged(
641 const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
642 sp<StreamOutHalHidl> stream = mStream.promote();
643 if (stream != nullptr) {
644 std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
645 stream->onCodecFormatChanged(metadataBs);
646 }
647 return Void();
648 }
649
650 private:
651 wp<StreamOutHalHidl> mStream;
652 };
653
654 } // namespace
655
setEventCallback(const sp<StreamOutHalInterfaceEventCallback> & callback)656 status_t StreamOutHalHidl::setEventCallback(
657 const sp<StreamOutHalInterfaceEventCallback>& callback) {
658 if (mStream == nullptr) return NO_INIT;
659 mEventCallback = callback;
660 status_t status = processReturn(
661 "setEventCallback",
662 mStream->setEventCallback(
663 callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
664 return status;
665 }
666 #endif
667
onWriteReady()668 void StreamOutHalHidl::onWriteReady() {
669 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
670 if (callback == 0) return;
671 ALOGV("asyncCallback onWriteReady");
672 callback->onWriteReady();
673 }
674
onDrainReady()675 void StreamOutHalHidl::onDrainReady() {
676 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
677 if (callback == 0) return;
678 ALOGV("asyncCallback onDrainReady");
679 callback->onDrainReady();
680 }
681
onError()682 void StreamOutHalHidl::onError() {
683 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
684 if (callback == 0) return;
685 ALOGV("asyncCallback onError");
686 callback->onError();
687 }
688
onCodecFormatChanged(const std::basic_string<uint8_t> & metadataBs)689 void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
690 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.promote();
691 if (callback == nullptr) return;
692 ALOGV("asyncCodecFormatCallback %s", __func__);
693 callback->onCodecFormatChanged(metadataBs);
694 }
695
696
StreamInHalHidl(const sp<IStreamIn> & stream)697 StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
698 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
699 }
700
~StreamInHalHidl()701 StreamInHalHidl::~StreamInHalHidl() {
702 if (mStream != 0) {
703 processReturn("close", mStream->close());
704 mStream.clear();
705 hardware::IPCThreadState::self()->flushCommands();
706 }
707 if (mEfGroup) {
708 EventFlag::deleteEventFlag(&mEfGroup);
709 }
710 }
711
getFrameSize(size_t * size)712 status_t StreamInHalHidl::getFrameSize(size_t *size) {
713 if (mStream == 0) return NO_INIT;
714 return processReturn("getFrameSize", mStream->getFrameSize(), size);
715 }
716
setGain(float gain)717 status_t StreamInHalHidl::setGain(float gain) {
718 if (mStream == 0) return NO_INIT;
719 return processReturn("setGain", mStream->setGain(gain));
720 }
721
read(void * buffer,size_t bytes,size_t * read)722 status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
723 if (mStream == 0) return NO_INIT;
724 *read = 0;
725
726 if (bytes == 0 && !mDataMQ) {
727 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
728 return OK;
729 }
730
731 status_t status;
732 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
733 return status;
734 }
735
736 ReadParameters params;
737 params.command = ReadCommand::READ;
738 params.params.read = bytes;
739 status = callReaderThread(params, "read",
740 [&](const ReadStatus& readStatus) {
741 const size_t availToRead = mDataMQ->availableToRead();
742 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
743 ALOGE("data message queue read failed for \"read\"");
744 }
745 ALOGW_IF(availToRead != readStatus.reply.read,
746 "HAL read report inconsistent: mq = %d, status = %d",
747 (int32_t)availToRead, (int32_t)readStatus.reply.read);
748 *read = readStatus.reply.read;
749 });
750 mStreamPowerLog.log(buffer, *read);
751 return status;
752 }
753
callReaderThread(const ReadParameters & params,const char * cmdName,StreamInHalHidl::ReaderCallback callback)754 status_t StreamInHalHidl::callReaderThread(
755 const ReadParameters& params, const char* cmdName,
756 StreamInHalHidl::ReaderCallback callback) {
757 if (!mCommandMQ->write(¶ms)) {
758 ALOGW("command message queue write failed");
759 return -EAGAIN;
760 }
761 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
762
763 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
764 uint32_t efState = 0;
765 retry:
766 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
767 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
768 ReadStatus readStatus;
769 readStatus.retval = Result::NOT_INITIALIZED;
770 if (!mStatusMQ->read(&readStatus)) {
771 ALOGE("status message read failed for \"%s\"", cmdName);
772 }
773 if (readStatus.retval == Result::OK) {
774 ret = OK;
775 callback(readStatus);
776 } else {
777 ret = processReturn(cmdName, readStatus.retval);
778 }
779 return ret;
780 }
781 if (ret == -EAGAIN || ret == -EINTR) {
782 // Spurious wakeup. This normally retries no more than once.
783 goto retry;
784 }
785 return ret;
786 }
787
prepareForReading(size_t bufferSize)788 status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
789 std::unique_ptr<CommandMQ> tempCommandMQ;
790 std::unique_ptr<DataMQ> tempDataMQ;
791 std::unique_ptr<StatusMQ> tempStatusMQ;
792 Result retval;
793 pid_t halThreadPid, halThreadTid;
794 Return<void> ret = mStream->prepareForReading(
795 1, bufferSize,
796 [&](Result r,
797 const CommandMQ::Descriptor& commandMQ,
798 const DataMQ::Descriptor& dataMQ,
799 const StatusMQ::Descriptor& statusMQ,
800 const ThreadInfo& halThreadInfo) {
801 retval = r;
802 if (retval == Result::OK) {
803 tempCommandMQ.reset(new CommandMQ(commandMQ));
804 tempDataMQ.reset(new DataMQ(dataMQ));
805 tempStatusMQ.reset(new StatusMQ(statusMQ));
806 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
807 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
808 }
809 halThreadPid = halThreadInfo.pid;
810 halThreadTid = halThreadInfo.tid;
811 }
812 });
813 if (!ret.isOk() || retval != Result::OK) {
814 return processReturn("prepareForReading", ret, retval);
815 }
816 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
817 !tempDataMQ || !tempDataMQ->isValid() ||
818 !tempStatusMQ || !tempStatusMQ->isValid() ||
819 !mEfGroup) {
820 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
821 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
822 "Command message queue for writing is invalid");
823 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
824 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
825 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
826 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
827 "Status message queue for reading is invalid");
828 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
829 return NO_INIT;
830 }
831 requestHalThreadPriority(halThreadPid, halThreadTid);
832
833 mCommandMQ = std::move(tempCommandMQ);
834 mDataMQ = std::move(tempDataMQ);
835 mStatusMQ = std::move(tempStatusMQ);
836 mReaderClient = gettid();
837 return OK;
838 }
839
getInputFramesLost(uint32_t * framesLost)840 status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
841 if (mStream == 0) return NO_INIT;
842 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
843 }
844
getCapturePosition(int64_t * frames,int64_t * time)845 status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
846 if (mStream == 0) return NO_INIT;
847 if (mReaderClient == gettid() && mCommandMQ) {
848 ReadParameters params;
849 params.command = ReadCommand::GET_CAPTURE_POSITION;
850 return callReaderThread(params, "getCapturePosition",
851 [&](const ReadStatus& readStatus) {
852 *frames = readStatus.reply.capturePosition.frames;
853 *time = readStatus.reply.capturePosition.time;
854 });
855 } else {
856 Result retval;
857 Return<void> ret = mStream->getCapturePosition(
858 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
859 retval = r;
860 if (retval == Result::OK) {
861 *frames = hidlFrames;
862 *time = hidlTime;
863 }
864 });
865 return processReturn("getCapturePosition", ret, retval);
866 }
867 }
868
869 #if MAJOR_VERSION == 2
getActiveMicrophones(std::vector<media::MicrophoneInfo> * microphones __unused)870 status_t StreamInHalHidl::getActiveMicrophones(
871 std::vector<media::MicrophoneInfo> *microphones __unused) {
872 if (mStream == 0) return NO_INIT;
873 return INVALID_OPERATION;
874 }
875
updateSinkMetadata(const StreamInHalInterface::SinkMetadata &)876 status_t StreamInHalHidl::updateSinkMetadata(
877 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
878 // Audio HAL V2.0 does not support propagating sink metadata
879 return INVALID_OPERATION;
880 }
881
882 #elif MAJOR_VERSION >= 4
getActiveMicrophones(std::vector<media::MicrophoneInfo> * microphonesInfo)883 status_t StreamInHalHidl::getActiveMicrophones(
884 std::vector<media::MicrophoneInfo> *microphonesInfo) {
885 if (!mStream) return NO_INIT;
886 Result retval;
887 Return<void> ret = mStream->getActiveMicrophones(
888 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
889 retval = r;
890 for (size_t k = 0; k < micArrayHal.size(); k++) {
891 audio_microphone_characteristic_t dst;
892 // convert
893 microphoneInfoToHal(micArrayHal[k], &dst);
894 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
895 microphonesInfo->push_back(microphone);
896 }
897 });
898 return processReturn("getActiveMicrophones", ret, retval);
899 }
900
updateSinkMetadata(const StreamInHalInterface::SinkMetadata & sinkMetadata)901 status_t StreamInHalHidl::updateSinkMetadata(const
902 StreamInHalInterface::SinkMetadata& sinkMetadata) {
903 CPP_VERSION::SinkMetadata halMetadata = {
904 .tracks = transformToHidlVec(sinkMetadata.tracks,
905 [](const record_track_metadata& metadata) -> RecordTrackMetadata {
906 return {
907 .source=static_cast<AudioSource>(metadata.source),
908 .gain=metadata.gain,
909 };
910 })};
911 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(halMetadata));
912 }
913 #endif
914
915 #if MAJOR_VERSION < 5
setPreferredMicrophoneDirection(audio_microphone_direction_t direction __unused)916 status_t StreamInHalHidl::setPreferredMicrophoneDirection(
917 audio_microphone_direction_t direction __unused) {
918 if (mStream == 0) return NO_INIT;
919 return INVALID_OPERATION;
920 }
921
setPreferredMicrophoneFieldDimension(float zoom __unused)922 status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
923 if (mStream == 0) return NO_INIT;
924 return INVALID_OPERATION;
925 }
926 #else
setPreferredMicrophoneDirection(audio_microphone_direction_t direction)927 status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
928 if (!mStream) return NO_INIT;
929 return processReturn("setPreferredMicrophoneDirection",
930 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
931 }
932
setPreferredMicrophoneFieldDimension(float zoom)933 status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
934 if (!mStream) return NO_INIT;
935 return processReturn("setPreferredMicrophoneFieldDimension",
936 mStream->setMicrophoneFieldDimension(zoom));
937 }
938 #endif
939
940 } // namespace CPP_VERSION
941 } // namespace android
942