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