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