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