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