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