blob: 3a1fce8adb25cb81d42eb7b032bdbb2c91e74e89 [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
Andy Hungacb5b982021-01-20 10:12:00 -080064StreamHalHidl::~StreamHalHidl() {
65 // The last step is to flush all binder commands so that the deletion
66 // of IStreamIn / IStreamOut (mStream) is issued with less delay. See b/35394629.
67 hardware::IPCThreadState::self()->flushCommands();
68}
69
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080070status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
71 if (!mStream) return NO_INIT;
72 return processReturn("getSampleRate", mStream->getSampleRate(), rate);
73}
74
75status_t StreamHalHidl::getBufferSize(size_t *size) {
76 if (!mStream) return NO_INIT;
77 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
78 if (status == OK) {
79 mCachedBufferSize = *size;
80 }
81 return status;
82}
83
84status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
85 if (!mStream) return NO_INIT;
86 return processReturn("getChannelMask", mStream->getChannelMask(), mask);
87}
88
89status_t StreamHalHidl::getFormat(audio_format_t *format) {
90 if (!mStream) return NO_INIT;
91 return processReturn("getFormat", mStream->getFormat(), format);
92}
93
94status_t StreamHalHidl::getAudioProperties(
95 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
96 if (!mStream) return NO_INIT;
97 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080098 [&](uint32_t sr, auto m, auto f) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080099 *sampleRate = sr;
100 *mask = static_cast<audio_channel_mask_t>(m);
101 *format = static_cast<audio_format_t>(f);
102 });
103 return processReturn("getAudioProperties", ret);
104}
105
106status_t StreamHalHidl::setParameters(const String8& kvPairs) {
107 if (!mStream) return NO_INIT;
108 hidl_vec<ParameterValue> hidlParams;
109 status_t status = parametersFromHal(kvPairs, &hidlParams);
110 if (status != OK) return status;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800111 return processReturn("setParameters",
Dean Wheatley7b417a22019-01-31 20:39:42 +1100112 utils::setParameters(mStream, {} /* context */, hidlParams));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800113}
114
115status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
116 values->clear();
117 if (!mStream) return NO_INIT;
118 hidl_vec<hidl_string> hidlKeys;
119 status_t status = keysFromHal(keys, &hidlKeys);
120 if (status != OK) return status;
121 Result retval;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800122 Return<void> ret = utils::getParameters(
123 mStream,
124 {} /* context */,
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800125 hidlKeys,
126 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
127 retval = r;
128 if (retval == Result::OK) {
129 parametersToHal(parameters, values);
130 }
131 });
132 return processReturn("getParameters", ret, retval);
133}
134
135status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
136 if (!mStream) return NO_INIT;
137 return processReturn("addEffect", mStream->addEffect(
138 static_cast<EffectHalHidl*>(effect.get())->effectId()));
139}
140
141status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
142 if (!mStream) return NO_INIT;
143 return processReturn("removeEffect", mStream->removeEffect(
144 static_cast<EffectHalHidl*>(effect.get())->effectId()));
145}
146
147status_t StreamHalHidl::standby() {
148 if (!mStream) return NO_INIT;
149 return processReturn("standby", mStream->standby());
150}
151
152status_t StreamHalHidl::dump(int fd) {
153 if (!mStream) return NO_INIT;
154 native_handle_t* hidlHandle = native_handle_create(1, 0);
155 hidlHandle->data[0] = fd;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800156 Return<void> ret = mStream->debug(hidlHandle, {} /* options */);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800157 native_handle_delete(hidlHandle);
158 mStreamPowerLog.dump(fd);
159 return processReturn("dump", ret);
160}
161
162status_t StreamHalHidl::start() {
163 if (!mStream) return NO_INIT;
164 return processReturn("start", mStream->start());
165}
166
167status_t StreamHalHidl::stop() {
168 if (!mStream) return NO_INIT;
169 return processReturn("stop", mStream->stop());
170}
171
172status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
173 struct audio_mmap_buffer_info *info) {
174 Result retval;
175 Return<void> ret = mStream->createMmapBuffer(
176 minSizeFrames,
177 [&](Result r, const MmapBufferInfo& hidlInfo) {
178 retval = r;
179 if (retval == Result::OK) {
180 const native_handle *handle = hidlInfo.sharedMemory.handle();
181 if (handle->numFds > 0) {
182 info->shared_memory_fd = handle->data[0];
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800183#if MAJOR_VERSION >= 4
Kevin Rocard734334f2018-07-12 19:37:41 -0700184 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
185#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800186 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700187 // Negative buffer size frame was a hack in O and P to
188 // indicate that the buffer is shareable to applications
189 if (info->buffer_size_frames < 0) {
190 info->buffer_size_frames *= -1;
191 info->flags = audio_mmap_buffer_flag(
192 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
193 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800194 info->burst_size_frames = hidlInfo.burstSizeFrames;
195 // info->shared_memory_address is not needed in HIDL context
196 info->shared_memory_address = NULL;
197 } else {
198 retval = Result::NOT_INITIALIZED;
199 }
200 }
201 });
202 return processReturn("createMmapBuffer", ret, retval);
203}
204
205status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
206 Result retval;
207 Return<void> ret = mStream->getMmapPosition(
208 [&](Result r, const MmapPosition& hidlPosition) {
209 retval = r;
210 if (retval == Result::OK) {
211 position->time_nanoseconds = hidlPosition.timeNanoseconds;
212 position->position_frames = hidlPosition.positionFrames;
213 }
214 });
215 return processReturn("getMmapPosition", ret, retval);
216}
217
218status_t StreamHalHidl::setHalThreadPriority(int priority) {
219 mHalThreadPriority = priority;
220 return OK;
221}
222
223status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
224 if (mCachedBufferSize != 0) {
225 *size = mCachedBufferSize;
226 return OK;
227 }
228 return getBufferSize(size);
229}
230
231bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
232 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
233 return true;
234 }
235 int err = requestPriority(
236 threadPid, threadId,
237 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
238 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
239 mHalThreadPriority, threadPid, threadId, err);
240 // Audio will still work, but latency will be higher and sometimes unacceptable.
241 return err == 0;
242}
243
244namespace {
245
246/* Notes on callback ownership.
247
248This is how (Hw)Binder ownership model looks like. The server implementation
249is owned by Binder framework (via sp<>). Proxies are owned by clients.
250When the last proxy disappears, Binder framework releases the server impl.
251
252Thus, it is not needed to keep any references to StreamOutCallback (this is
253the server impl) -- it will live as long as HAL server holds a strong ref to
254IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
255from the destructor of StreamOutHalHidl.
256
257The callback only keeps a weak reference to the stream. The stream is owned
258by AudioFlinger.
259
260*/
261
262struct StreamOutCallback : public IStreamOutCallback {
263 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
264
265 // IStreamOutCallback implementation
266 Return<void> onWriteReady() override {
267 sp<StreamOutHalHidl> stream = mStream.promote();
268 if (stream != 0) {
269 stream->onWriteReady();
270 }
271 return Void();
272 }
273
274 Return<void> onDrainReady() override {
275 sp<StreamOutHalHidl> stream = mStream.promote();
276 if (stream != 0) {
277 stream->onDrainReady();
278 }
279 return Void();
280 }
281
282 Return<void> onError() override {
283 sp<StreamOutHalHidl> stream = mStream.promote();
284 if (stream != 0) {
285 stream->onError();
286 }
287 return Void();
288 }
289
290 private:
Andy Hung638f45b2021-01-18 20:02:56 -0800291 const wp<StreamOutHalHidl> mStream;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800292};
293
294} // namespace
295
296StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
297 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
298}
299
300StreamOutHalHidl::~StreamOutHalHidl() {
301 if (mStream != 0) {
Andy Hung638f45b2021-01-18 20:02:56 -0800302 if (mCallback.load().unsafe_get()) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800303 processReturn("clearCallback", mStream->clearCallback());
304 }
jiabinf6eb4c32020-02-25 14:06:25 -0800305#if MAJOR_VERSION >= 6
Andy Hung638f45b2021-01-18 20:02:56 -0800306 if (mEventCallback.load().unsafe_get() != nullptr) {
jiabinf6eb4c32020-02-25 14:06:25 -0800307 processReturn("setEventCallback",
308 mStream->setEventCallback(nullptr));
309 }
310#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800311 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800312 }
Andy Hung638f45b2021-01-18 20:02:56 -0800313 mCallback = nullptr;
314 mEventCallback = nullptr;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800315 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.
Andy Hung638f45b2021-01-18 20:02:56 -0800367 ALOGW_IF(mCallback.load().unsafe_get(), "First call to async write with 0 bytes");
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800368 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 Laurent94579172020-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 Laurent94579172020-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() {
Andy Hung638f45b2021-01-18 20:02:56 -0800683 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800684 if (callback == 0) return;
685 ALOGV("asyncCallback onWriteReady");
686 callback->onWriteReady();
687}
688
689void StreamOutHalHidl::onDrainReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800690 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800691 if (callback == 0) return;
692 ALOGV("asyncCallback onDrainReady");
693 callback->onDrainReady();
694}
695
696void StreamOutHalHidl::onError() {
Andy Hung638f45b2021-01-18 20:02:56 -0800697 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800698 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) {
Andy Hung638f45b2021-01-18 20:02:56 -0800704 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
jiabinf6eb4c32020-02-25 14:06:25 -0800705 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());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800718 }
719 if (mEfGroup) {
720 EventFlag::deleteEventFlag(&mEfGroup);
721 }
722}
723
724status_t StreamInHalHidl::getFrameSize(size_t *size) {
725 if (mStream == 0) return NO_INIT;
726 return processReturn("getFrameSize", mStream->getFrameSize(), size);
727}
728
729status_t StreamInHalHidl::setGain(float gain) {
730 if (mStream == 0) return NO_INIT;
731 return processReturn("setGain", mStream->setGain(gain));
732}
733
734status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
735 if (mStream == 0) return NO_INIT;
736 *read = 0;
737
738 if (bytes == 0 && !mDataMQ) {
739 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
740 return OK;
741 }
742
743 status_t status;
744 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
745 return status;
746 }
747
748 ReadParameters params;
749 params.command = ReadCommand::READ;
750 params.params.read = bytes;
751 status = callReaderThread(params, "read",
752 [&](const ReadStatus& readStatus) {
753 const size_t availToRead = mDataMQ->availableToRead();
754 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
755 ALOGE("data message queue read failed for \"read\"");
756 }
757 ALOGW_IF(availToRead != readStatus.reply.read,
758 "HAL read report inconsistent: mq = %d, status = %d",
759 (int32_t)availToRead, (int32_t)readStatus.reply.read);
760 *read = readStatus.reply.read;
761 });
762 mStreamPowerLog.log(buffer, *read);
763 return status;
764}
765
766status_t StreamInHalHidl::callReaderThread(
767 const ReadParameters& params, const char* cmdName,
768 StreamInHalHidl::ReaderCallback callback) {
769 if (!mCommandMQ->write(&params)) {
770 ALOGW("command message queue write failed");
771 return -EAGAIN;
772 }
773 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
774
775 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
776 uint32_t efState = 0;
777retry:
778 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
779 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
780 ReadStatus readStatus;
781 readStatus.retval = Result::NOT_INITIALIZED;
782 if (!mStatusMQ->read(&readStatus)) {
783 ALOGE("status message read failed for \"%s\"", cmdName);
784 }
785 if (readStatus.retval == Result::OK) {
786 ret = OK;
787 callback(readStatus);
788 } else {
789 ret = processReturn(cmdName, readStatus.retval);
790 }
791 return ret;
792 }
793 if (ret == -EAGAIN || ret == -EINTR) {
794 // Spurious wakeup. This normally retries no more than once.
795 goto retry;
796 }
797 return ret;
798}
799
800status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
801 std::unique_ptr<CommandMQ> tempCommandMQ;
802 std::unique_ptr<DataMQ> tempDataMQ;
803 std::unique_ptr<StatusMQ> tempStatusMQ;
804 Result retval;
805 pid_t halThreadPid, halThreadTid;
806 Return<void> ret = mStream->prepareForReading(
807 1, bufferSize,
808 [&](Result r,
809 const CommandMQ::Descriptor& commandMQ,
810 const DataMQ::Descriptor& dataMQ,
811 const StatusMQ::Descriptor& statusMQ,
812 const ThreadInfo& halThreadInfo) {
813 retval = r;
814 if (retval == Result::OK) {
815 tempCommandMQ.reset(new CommandMQ(commandMQ));
816 tempDataMQ.reset(new DataMQ(dataMQ));
817 tempStatusMQ.reset(new StatusMQ(statusMQ));
818 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
819 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
820 }
821 halThreadPid = halThreadInfo.pid;
822 halThreadTid = halThreadInfo.tid;
823 }
824 });
825 if (!ret.isOk() || retval != Result::OK) {
826 return processReturn("prepareForReading", ret, retval);
827 }
828 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
829 !tempDataMQ || !tempDataMQ->isValid() ||
830 !tempStatusMQ || !tempStatusMQ->isValid() ||
831 !mEfGroup) {
832 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
833 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
834 "Command message queue for writing is invalid");
835 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
836 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
837 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
838 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
839 "Status message queue for reading is invalid");
840 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
841 return NO_INIT;
842 }
843 requestHalThreadPriority(halThreadPid, halThreadTid);
844
845 mCommandMQ = std::move(tempCommandMQ);
846 mDataMQ = std::move(tempDataMQ);
847 mStatusMQ = std::move(tempStatusMQ);
848 mReaderClient = gettid();
849 return OK;
850}
851
852status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
853 if (mStream == 0) return NO_INIT;
854 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
855}
856
857status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
858 if (mStream == 0) return NO_INIT;
859 if (mReaderClient == gettid() && mCommandMQ) {
860 ReadParameters params;
861 params.command = ReadCommand::GET_CAPTURE_POSITION;
862 return callReaderThread(params, "getCapturePosition",
863 [&](const ReadStatus& readStatus) {
864 *frames = readStatus.reply.capturePosition.frames;
865 *time = readStatus.reply.capturePosition.time;
866 });
867 } else {
868 Result retval;
869 Return<void> ret = mStream->getCapturePosition(
870 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
871 retval = r;
872 if (retval == Result::OK) {
873 *frames = hidlFrames;
874 *time = hidlTime;
875 }
876 });
877 return processReturn("getCapturePosition", ret, retval);
878 }
879}
880
Kevin Rocard070e7512018-05-22 09:29:13 -0700881#if MAJOR_VERSION == 2
882status_t StreamInHalHidl::getActiveMicrophones(
883 std::vector<media::MicrophoneInfo> *microphones __unused) {
884 if (mStream == 0) return NO_INIT;
885 return INVALID_OPERATION;
886}
887
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800888status_t StreamInHalHidl::updateSinkMetadata(
889 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700890 // Audio HAL V2.0 does not support propagating sink metadata
891 return INVALID_OPERATION;
892}
893
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800894#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -0700895status_t StreamInHalHidl::getActiveMicrophones(
896 std::vector<media::MicrophoneInfo> *microphonesInfo) {
897 if (!mStream) return NO_INIT;
898 Result retval;
899 Return<void> ret = mStream->getActiveMicrophones(
900 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
901 retval = r;
902 for (size_t k = 0; k < micArrayHal.size(); k++) {
903 audio_microphone_characteristic_t dst;
904 // convert
905 microphoneInfoToHal(micArrayHal[k], &dst);
906 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
907 microphonesInfo->push_back(microphone);
908 }
909 });
910 return processReturn("getActiveMicrophones", ret, retval);
911}
912
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800913status_t StreamInHalHidl::updateSinkMetadata(const
914 StreamInHalInterface::SinkMetadata& sinkMetadata) {
915 CPP_VERSION::SinkMetadata halMetadata = {
Kevin Rocarda8975a72018-03-27 10:16:52 -0700916 .tracks = transformToHidlVec(sinkMetadata.tracks,
Eric Laurent94579172020-11-20 18:41:04 +0100917 [](const record_track_metadata_v7& metadata) -> RecordTrackMetadata {
918 RecordTrackMetadata halTrackMetadata = {
919 .source=static_cast<AudioSource>(metadata.base.source),
920 .gain=metadata.base.gain,
Kevin Rocarda8975a72018-03-27 10:16:52 -0700921 };
Eric Laurent94579172020-11-20 18:41:04 +0100922#if MAJOR_VERSION >= 7
923 HidlUtils::audioChannelMaskFromHal(metadata.channel_mask, true /*isInput*/,
924 &halTrackMetadata.channelMask);
925 std::istringstream tags{metadata.tags};
926 std::string tag;
927 while (std::getline(tags, tag, HidlUtils::sAudioTagSeparator)) {
928 if (!tag.empty()) {
929 halTrackMetadata.tags.push_back(tag);
930 }
931 }
932#endif
933 return halTrackMetadata;
Kevin Rocarda8975a72018-03-27 10:16:52 -0700934 })};
935 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(halMetadata));
936}
Kevin Rocard070e7512018-05-22 09:29:13 -0700937#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700938
Paul McLean03a6e6a2018-12-04 10:54:13 -0700939#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -0600940status_t StreamInHalHidl::setPreferredMicrophoneDirection(
941 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -0700942 if (mStream == 0) return NO_INIT;
943 return INVALID_OPERATION;
944}
945
Paul McLean12340082019-03-19 09:35:05 -0600946status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -0700947 if (mStream == 0) return NO_INIT;
948 return INVALID_OPERATION;
949}
950#else
Paul McLean12340082019-03-19 09:35:05 -0600951status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Paul McLean03a6e6a2018-12-04 10:54:13 -0700952 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -0600953 return processReturn("setPreferredMicrophoneDirection",
954 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -0700955}
956
Paul McLean12340082019-03-19 09:35:05 -0600957status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Paul McLean03a6e6a2018-12-04 10:54:13 -0700958 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -0600959 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -0700960 mStream->setMicrophoneFieldDimension(zoom));
961}
962#endif
963
Kevin Rocard070e7512018-05-22 09:29:13 -0700964} // namespace CPP_VERSION
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800965} // namespace android