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