blob: c08dddb397704ce77d1f728428da1512ece8471a [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>
Mikhail Naganovac917ac2018-11-28 14:03:52 -080022#include <media/AudioParameter.h>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080023#include <mediautils/SchedulingPolicyService.h>
24#include <utils/Log.h>
25
26#include "DeviceHalHidl.h"
27#include "EffectHalHidl.h"
28#include "StreamHalHidl.h"
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080029#include "VersionUtils.h"
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080030
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080031using ::android::hardware::MQDescriptorSync;
32using ::android::hardware::Return;
33using ::android::hardware::Void;
Kevin Rocarddf9b4202018-05-10 19:56:08 -070034
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080035namespace android {
Kevin Rocard070e7512018-05-22 09:29:13 -070036namespace CPP_VERSION {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080037
Mikhail Naganov595caa32018-12-13 11:08:28 -080038using EffectHalHidl = ::android::effect::CPP_VERSION::EffectHalHidl;
Mikhail Naganov9ccaa162018-12-12 10:27:29 -080039using ReadCommand = ::android::hardware::audio::CPP_VERSION::IStreamIn::ReadCommand;
40
41using namespace ::android::hardware::audio::common::CPP_VERSION;
42using namespace ::android::hardware::audio::CPP_VERSION;
43
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080044StreamHalHidl::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.
Andy Hung8c2e5822019-04-01 18:09:07 -070052 if (mStream != nullptr /* && mStreamPowerLog.isUserDebugOrEngBuild() */) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080053 // Obtain audio properties (see StreamHalHidl::getAudioProperties() below).
54 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080055 [&](auto sr, auto m, auto f) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080056 mStreamPowerLog.init(sr,
57 static_cast<audio_channel_mask_t>(m),
58 static_cast<audio_format_t>(f));
59 });
60 }
61}
62
63StreamHalHidl::~StreamHalHidl() {
64 mStream = nullptr;
65}
66
67status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
68 if (!mStream) return NO_INIT;
69 return processReturn("getSampleRate", mStream->getSampleRate(), rate);
70}
71
72status_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
81status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
82 if (!mStream) return NO_INIT;
83 return processReturn("getChannelMask", mStream->getChannelMask(), mask);
84}
85
86status_t StreamHalHidl::getFormat(audio_format_t *format) {
87 if (!mStream) return NO_INIT;
88 return processReturn("getFormat", mStream->getFormat(), format);
89}
90
91status_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(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080095 [&](uint32_t sr, auto m, auto f) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080096 *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
103status_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;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800108 return processReturn("setParameters",
Dean Wheatley7b417a22019-01-31 20:39:42 +1100109 utils::setParameters(mStream, {} /* context */, hidlParams));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800110}
111
112status_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;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800119 Return<void> ret = utils::getParameters(
120 mStream,
121 {} /* context */,
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800122 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
132status_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
138status_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
144status_t StreamHalHidl::standby() {
145 if (!mStream) return NO_INIT;
146 return processReturn("standby", mStream->standby());
147}
148
149status_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;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800153 Return<void> ret = mStream->debug(hidlHandle, {} /* options */);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800154 native_handle_delete(hidlHandle);
155 mStreamPowerLog.dump(fd);
156 return processReturn("dump", ret);
157}
158
159status_t StreamHalHidl::start() {
160 if (!mStream) return NO_INIT;
161 return processReturn("start", mStream->start());
162}
163
164status_t StreamHalHidl::stop() {
165 if (!mStream) return NO_INIT;
166 return processReturn("stop", mStream->stop());
167}
168
169status_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];
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800180#if MAJOR_VERSION >= 4
Kevin Rocard734334f2018-07-12 19:37:41 -0700181 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
182#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800183 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700184 // 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 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800191 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
202status_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
215status_t StreamHalHidl::setHalThreadPriority(int priority) {
216 mHalThreadPriority = priority;
217 return OK;
218}
219
220status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
221 if (mCachedBufferSize != 0) {
222 *size = mCachedBufferSize;
223 return OK;
224 }
225 return getBufferSize(size);
226}
227
228bool 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
241namespace {
242
243/* Notes on callback ownership.
244
245This is how (Hw)Binder ownership model looks like. The server implementation
246is owned by Binder framework (via sp<>). Proxies are owned by clients.
247When the last proxy disappears, Binder framework releases the server impl.
248
249Thus, it is not needed to keep any references to StreamOutCallback (this is
250the server impl) -- it will live as long as HAL server holds a strong ref to
251IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
252from the destructor of StreamOutHalHidl.
253
254The callback only keeps a weak reference to the stream. The stream is owned
255by AudioFlinger.
256
257*/
258
259struct StreamOutCallback : public IStreamOutCallback {
260 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
261
262 // IStreamOutCallback implementation
263 Return<void> onWriteReady() override {
264 sp<StreamOutHalHidl> stream = mStream.promote();
265 if (stream != 0) {
266 stream->onWriteReady();
267 }
268 return Void();
269 }
270
271 Return<void> onDrainReady() override {
272 sp<StreamOutHalHidl> stream = mStream.promote();
273 if (stream != 0) {
274 stream->onDrainReady();
275 }
276 return Void();
277 }
278
279 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
293StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
294 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
295}
296
297StreamOutHalHidl::~StreamOutHalHidl() {
298 if (mStream != 0) {
299 if (mCallback.unsafe_get()) {
300 processReturn("clearCallback", mStream->clearCallback());
301 }
302 processReturn("close", mStream->close());
303 mStream.clear();
304 }
305 mCallback.clear();
306 hardware::IPCThreadState::self()->flushCommands();
307 if (mEfGroup) {
308 EventFlag::deleteEventFlag(&mEfGroup);
309 }
310}
311
312status_t StreamOutHalHidl::getFrameSize(size_t *size) {
313 if (mStream == 0) return NO_INIT;
314 return processReturn("getFrameSize", mStream->getFrameSize(), size);
315}
316
317status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
318 if (mStream == 0) return NO_INIT;
319 if (mWriterClient == gettid() && mCommandMQ) {
320 return callWriterThread(
321 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
322 [&](const WriteStatus& writeStatus) {
323 *latency = writeStatus.reply.latencyMs;
324 });
325 } else {
326 return processReturn("getLatency", mStream->getLatency(), latency);
327 }
328}
329
330status_t StreamOutHalHidl::setVolume(float left, float right) {
331 if (mStream == 0) return NO_INIT;
332 return processReturn("setVolume", mStream->setVolume(left, right));
333}
334
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800335#if MAJOR_VERSION == 2
336status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
337 if (mStream == 0) return NO_INIT;
338 std::vector<ParameterValue> parameters;
339 String8 halParameters;
340 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
341 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
342 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
343 return setParameters(halParameters);
344}
Kevin Rocard1cf6b4d2018-11-20 18:05:44 -0800345#elif MAJOR_VERSION >= 4
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800346status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
347 if (mStream == 0) return NO_INIT;
348 return processReturn("selectPresentation",
349 mStream->selectPresentation(presentationId, programId));
350}
351#endif
352
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800353status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
354 if (mStream == 0) return NO_INIT;
355 *written = 0;
356
357 if (bytes == 0 && !mDataMQ) {
358 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
359 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
360 return OK;
361 }
362
363 status_t status;
364 if (!mDataMQ) {
365 // In case if playback starts close to the end of a compressed track, the bytes
366 // that need to be written is less than the actual buffer size. Need to use
367 // full buffer size for the MQ since otherwise after seeking back to the middle
368 // data will be truncated.
369 size_t bufferSize;
370 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
371 return status;
372 }
373 if (bytes > bufferSize) bufferSize = bytes;
374 if ((status = prepareForWriting(bufferSize)) != OK) {
375 return status;
376 }
377 }
378
379 status = callWriterThread(
380 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
381 [&] (const WriteStatus& writeStatus) {
382 *written = writeStatus.reply.written;
383 // Diagnostics of the cause of b/35813113.
384 ALOGE_IF(*written > bytes,
385 "hal reports more bytes written than asked for: %lld > %lld",
386 (long long)*written, (long long)bytes);
387 });
388 mStreamPowerLog.log(buffer, *written);
389 return status;
390}
391
392status_t StreamOutHalHidl::callWriterThread(
393 WriteCommand cmd, const char* cmdName,
394 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
395 if (!mCommandMQ->write(&cmd)) {
396 ALOGE("command message queue write failed for \"%s\"", cmdName);
397 return -EAGAIN;
398 }
399 if (data != nullptr) {
400 size_t availableToWrite = mDataMQ->availableToWrite();
401 if (dataSize > availableToWrite) {
402 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
403 (long long)dataSize, (long long)availableToWrite);
404 dataSize = availableToWrite;
405 }
406 if (!mDataMQ->write(data, dataSize)) {
407 ALOGE("data message queue write failed for \"%s\"", cmdName);
408 }
409 }
410 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
411
412 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
413 uint32_t efState = 0;
414retry:
415 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
416 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
417 WriteStatus writeStatus;
418 writeStatus.retval = Result::NOT_INITIALIZED;
419 if (!mStatusMQ->read(&writeStatus)) {
420 ALOGE("status message read failed for \"%s\"", cmdName);
421 }
422 if (writeStatus.retval == Result::OK) {
423 ret = OK;
424 callback(writeStatus);
425 } else {
426 ret = processReturn(cmdName, writeStatus.retval);
427 }
428 return ret;
429 }
430 if (ret == -EAGAIN || ret == -EINTR) {
431 // Spurious wakeup. This normally retries no more than once.
432 goto retry;
433 }
434 return ret;
435}
436
437status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
438 std::unique_ptr<CommandMQ> tempCommandMQ;
439 std::unique_ptr<DataMQ> tempDataMQ;
440 std::unique_ptr<StatusMQ> tempStatusMQ;
441 Result retval;
442 pid_t halThreadPid, halThreadTid;
443 Return<void> ret = mStream->prepareForWriting(
444 1, bufferSize,
445 [&](Result r,
446 const CommandMQ::Descriptor& commandMQ,
447 const DataMQ::Descriptor& dataMQ,
448 const StatusMQ::Descriptor& statusMQ,
449 const ThreadInfo& halThreadInfo) {
450 retval = r;
451 if (retval == Result::OK) {
452 tempCommandMQ.reset(new CommandMQ(commandMQ));
453 tempDataMQ.reset(new DataMQ(dataMQ));
454 tempStatusMQ.reset(new StatusMQ(statusMQ));
455 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
456 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
457 }
458 halThreadPid = halThreadInfo.pid;
459 halThreadTid = halThreadInfo.tid;
460 }
461 });
462 if (!ret.isOk() || retval != Result::OK) {
463 return processReturn("prepareForWriting", ret, retval);
464 }
465 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
466 !tempDataMQ || !tempDataMQ->isValid() ||
467 !tempStatusMQ || !tempStatusMQ->isValid() ||
468 !mEfGroup) {
469 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
470 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
471 "Command message queue for writing is invalid");
472 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
473 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
474 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
475 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
476 "Status message queue for writing is invalid");
477 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
478 return NO_INIT;
479 }
480 requestHalThreadPriority(halThreadPid, halThreadTid);
481
482 mCommandMQ = std::move(tempCommandMQ);
483 mDataMQ = std::move(tempDataMQ);
484 mStatusMQ = std::move(tempStatusMQ);
485 mWriterClient = gettid();
486 return OK;
487}
488
489status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
490 if (mStream == 0) return NO_INIT;
491 Result retval;
492 Return<void> ret = mStream->getRenderPosition(
493 [&](Result r, uint32_t d) {
494 retval = r;
495 if (retval == Result::OK) {
496 *dspFrames = d;
497 }
498 });
499 return processReturn("getRenderPosition", ret, retval);
500}
501
502status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
503 if (mStream == 0) return NO_INIT;
504 Result retval;
505 Return<void> ret = mStream->getNextWriteTimestamp(
506 [&](Result r, int64_t t) {
507 retval = r;
508 if (retval == Result::OK) {
509 *timestamp = t;
510 }
511 });
512 return processReturn("getRenderPosition", ret, retval);
513}
514
515status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
516 if (mStream == 0) return NO_INIT;
517 status_t status = processReturn(
518 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
519 if (status == OK) {
520 mCallback = callback;
521 }
522 return status;
523}
524
525status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
526 if (mStream == 0) return NO_INIT;
527 Return<void> ret = mStream->supportsPauseAndResume(
528 [&](bool p, bool r) {
529 *supportsPause = p;
530 *supportsResume = r;
531 });
532 return processReturn("supportsPauseAndResume", ret);
533}
534
535status_t StreamOutHalHidl::pause() {
536 if (mStream == 0) return NO_INIT;
537 return processReturn("pause", mStream->pause());
538}
539
540status_t StreamOutHalHidl::resume() {
541 if (mStream == 0) return NO_INIT;
542 return processReturn("pause", mStream->resume());
543}
544
545status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
546 if (mStream == 0) return NO_INIT;
547 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
548}
549
550status_t StreamOutHalHidl::drain(bool earlyNotify) {
551 if (mStream == 0) return NO_INIT;
552 return processReturn(
553 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
554}
555
556status_t StreamOutHalHidl::flush() {
557 if (mStream == 0) return NO_INIT;
558 return processReturn("pause", mStream->flush());
559}
560
561status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
562 if (mStream == 0) return NO_INIT;
563 if (mWriterClient == gettid() && mCommandMQ) {
564 return callWriterThread(
565 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
566 [&](const WriteStatus& writeStatus) {
567 *frames = writeStatus.reply.presentationPosition.frames;
568 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
569 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
570 });
571 } else {
572 Result retval;
573 Return<void> ret = mStream->getPresentationPosition(
574 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
575 retval = r;
576 if (retval == Result::OK) {
577 *frames = hidlFrames;
578 timestamp->tv_sec = hidlTimeStamp.tvSec;
579 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
580 }
581 });
582 return processReturn("getPresentationPosition", ret, retval);
583 }
584}
585
Kevin Rocard070e7512018-05-22 09:29:13 -0700586#if MAJOR_VERSION == 2
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800587status_t StreamOutHalHidl::updateSourceMetadata(
588 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700589 // Audio HAL V2.0 does not support propagating source metadata
590 return INVALID_OPERATION;
591}
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800592#elif MAJOR_VERSION >= 4
Kevin Rocarda8975a72018-03-27 10:16:52 -0700593/** Transform a standard collection to an HIDL vector. */
594template <class Values, class ElementConverter>
595static auto transformToHidlVec(const Values& values, ElementConverter converter) {
596 hidl_vec<decltype(converter(*values.begin()))> result{values.size()};
597 using namespace std;
598 transform(begin(values), end(values), begin(result), converter);
599 return result;
600}
601
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800602status_t StreamOutHalHidl::updateSourceMetadata(
603 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
604 CPP_VERSION::SourceMetadata halMetadata = {
Kevin Rocarda8975a72018-03-27 10:16:52 -0700605 .tracks = transformToHidlVec(sourceMetadata.tracks,
606 [](const playback_track_metadata& metadata) -> PlaybackTrackMetadata {
607 return {
608 .usage=static_cast<AudioUsage>(metadata.usage),
609 .contentType=static_cast<AudioContentType>(metadata.content_type),
610 .gain=metadata.gain,
611 };
612 })};
613 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(halMetadata));
614}
Kevin Rocard070e7512018-05-22 09:29:13 -0700615#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700616
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800617void StreamOutHalHidl::onWriteReady() {
618 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
619 if (callback == 0) return;
620 ALOGV("asyncCallback onWriteReady");
621 callback->onWriteReady();
622}
623
624void StreamOutHalHidl::onDrainReady() {
625 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
626 if (callback == 0) return;
627 ALOGV("asyncCallback onDrainReady");
628 callback->onDrainReady();
629}
630
631void StreamOutHalHidl::onError() {
632 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
633 if (callback == 0) return;
634 ALOGV("asyncCallback onError");
635 callback->onError();
636}
637
638
639StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
640 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
641}
642
643StreamInHalHidl::~StreamInHalHidl() {
644 if (mStream != 0) {
645 processReturn("close", mStream->close());
646 mStream.clear();
647 hardware::IPCThreadState::self()->flushCommands();
648 }
649 if (mEfGroup) {
650 EventFlag::deleteEventFlag(&mEfGroup);
651 }
652}
653
654status_t StreamInHalHidl::getFrameSize(size_t *size) {
655 if (mStream == 0) return NO_INIT;
656 return processReturn("getFrameSize", mStream->getFrameSize(), size);
657}
658
659status_t StreamInHalHidl::setGain(float gain) {
660 if (mStream == 0) return NO_INIT;
661 return processReturn("setGain", mStream->setGain(gain));
662}
663
664status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
665 if (mStream == 0) return NO_INIT;
666 *read = 0;
667
668 if (bytes == 0 && !mDataMQ) {
669 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
670 return OK;
671 }
672
673 status_t status;
674 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
675 return status;
676 }
677
678 ReadParameters params;
679 params.command = ReadCommand::READ;
680 params.params.read = bytes;
681 status = callReaderThread(params, "read",
682 [&](const ReadStatus& readStatus) {
683 const size_t availToRead = mDataMQ->availableToRead();
684 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
685 ALOGE("data message queue read failed for \"read\"");
686 }
687 ALOGW_IF(availToRead != readStatus.reply.read,
688 "HAL read report inconsistent: mq = %d, status = %d",
689 (int32_t)availToRead, (int32_t)readStatus.reply.read);
690 *read = readStatus.reply.read;
691 });
692 mStreamPowerLog.log(buffer, *read);
693 return status;
694}
695
696status_t StreamInHalHidl::callReaderThread(
697 const ReadParameters& params, const char* cmdName,
698 StreamInHalHidl::ReaderCallback callback) {
699 if (!mCommandMQ->write(&params)) {
700 ALOGW("command message queue write failed");
701 return -EAGAIN;
702 }
703 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
704
705 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
706 uint32_t efState = 0;
707retry:
708 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
709 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
710 ReadStatus readStatus;
711 readStatus.retval = Result::NOT_INITIALIZED;
712 if (!mStatusMQ->read(&readStatus)) {
713 ALOGE("status message read failed for \"%s\"", cmdName);
714 }
715 if (readStatus.retval == Result::OK) {
716 ret = OK;
717 callback(readStatus);
718 } else {
719 ret = processReturn(cmdName, readStatus.retval);
720 }
721 return ret;
722 }
723 if (ret == -EAGAIN || ret == -EINTR) {
724 // Spurious wakeup. This normally retries no more than once.
725 goto retry;
726 }
727 return ret;
728}
729
730status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
731 std::unique_ptr<CommandMQ> tempCommandMQ;
732 std::unique_ptr<DataMQ> tempDataMQ;
733 std::unique_ptr<StatusMQ> tempStatusMQ;
734 Result retval;
735 pid_t halThreadPid, halThreadTid;
736 Return<void> ret = mStream->prepareForReading(
737 1, bufferSize,
738 [&](Result r,
739 const CommandMQ::Descriptor& commandMQ,
740 const DataMQ::Descriptor& dataMQ,
741 const StatusMQ::Descriptor& statusMQ,
742 const ThreadInfo& halThreadInfo) {
743 retval = r;
744 if (retval == Result::OK) {
745 tempCommandMQ.reset(new CommandMQ(commandMQ));
746 tempDataMQ.reset(new DataMQ(dataMQ));
747 tempStatusMQ.reset(new StatusMQ(statusMQ));
748 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
749 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
750 }
751 halThreadPid = halThreadInfo.pid;
752 halThreadTid = halThreadInfo.tid;
753 }
754 });
755 if (!ret.isOk() || retval != Result::OK) {
756 return processReturn("prepareForReading", ret, retval);
757 }
758 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
759 !tempDataMQ || !tempDataMQ->isValid() ||
760 !tempStatusMQ || !tempStatusMQ->isValid() ||
761 !mEfGroup) {
762 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
763 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
764 "Command message queue for writing is invalid");
765 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
766 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
767 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
768 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
769 "Status message queue for reading is invalid");
770 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
771 return NO_INIT;
772 }
773 requestHalThreadPriority(halThreadPid, halThreadTid);
774
775 mCommandMQ = std::move(tempCommandMQ);
776 mDataMQ = std::move(tempDataMQ);
777 mStatusMQ = std::move(tempStatusMQ);
778 mReaderClient = gettid();
779 return OK;
780}
781
782status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
783 if (mStream == 0) return NO_INIT;
784 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
785}
786
787status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
788 if (mStream == 0) return NO_INIT;
789 if (mReaderClient == gettid() && mCommandMQ) {
790 ReadParameters params;
791 params.command = ReadCommand::GET_CAPTURE_POSITION;
792 return callReaderThread(params, "getCapturePosition",
793 [&](const ReadStatus& readStatus) {
794 *frames = readStatus.reply.capturePosition.frames;
795 *time = readStatus.reply.capturePosition.time;
796 });
797 } else {
798 Result retval;
799 Return<void> ret = mStream->getCapturePosition(
800 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
801 retval = r;
802 if (retval == Result::OK) {
803 *frames = hidlFrames;
804 *time = hidlTime;
805 }
806 });
807 return processReturn("getCapturePosition", ret, retval);
808 }
809}
810
Kevin Rocard070e7512018-05-22 09:29:13 -0700811#if MAJOR_VERSION == 2
812status_t StreamInHalHidl::getActiveMicrophones(
813 std::vector<media::MicrophoneInfo> *microphones __unused) {
814 if (mStream == 0) return NO_INIT;
815 return INVALID_OPERATION;
816}
817
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800818status_t StreamInHalHidl::updateSinkMetadata(
819 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700820 // Audio HAL V2.0 does not support propagating sink metadata
821 return INVALID_OPERATION;
822}
823
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800824#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -0700825status_t StreamInHalHidl::getActiveMicrophones(
826 std::vector<media::MicrophoneInfo> *microphonesInfo) {
827 if (!mStream) return NO_INIT;
828 Result retval;
829 Return<void> ret = mStream->getActiveMicrophones(
830 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
831 retval = r;
832 for (size_t k = 0; k < micArrayHal.size(); k++) {
833 audio_microphone_characteristic_t dst;
834 // convert
835 microphoneInfoToHal(micArrayHal[k], &dst);
836 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
837 microphonesInfo->push_back(microphone);
838 }
839 });
840 return processReturn("getActiveMicrophones", ret, retval);
841}
842
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800843status_t StreamInHalHidl::updateSinkMetadata(const
844 StreamInHalInterface::SinkMetadata& sinkMetadata) {
845 CPP_VERSION::SinkMetadata halMetadata = {
Kevin Rocarda8975a72018-03-27 10:16:52 -0700846 .tracks = transformToHidlVec(sinkMetadata.tracks,
847 [](const record_track_metadata& metadata) -> RecordTrackMetadata {
848 return {
849 .source=static_cast<AudioSource>(metadata.source),
850 .gain=metadata.gain,
851 };
852 })};
853 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(halMetadata));
854}
Kevin Rocard070e7512018-05-22 09:29:13 -0700855#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700856
Paul McLean03a6e6a2018-12-04 10:54:13 -0700857#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -0600858status_t StreamInHalHidl::setPreferredMicrophoneDirection(
859 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -0700860 if (mStream == 0) return NO_INIT;
861 return INVALID_OPERATION;
862}
863
Paul McLean12340082019-03-19 09:35:05 -0600864status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -0700865 if (mStream == 0) return NO_INIT;
866 return INVALID_OPERATION;
867}
868#else
Paul McLean12340082019-03-19 09:35:05 -0600869status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Paul McLean03a6e6a2018-12-04 10:54:13 -0700870 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -0600871 return processReturn("setPreferredMicrophoneDirection",
872 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -0700873}
874
Paul McLean12340082019-03-19 09:35:05 -0600875status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Paul McLean03a6e6a2018-12-04 10:54:13 -0700876 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -0600877 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -0700878 mStream->setMicrophoneFieldDimension(zoom));
879}
880#endif
881
Kevin Rocard070e7512018-05-22 09:29:13 -0700882} // namespace CPP_VERSION
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800883} // namespace android