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