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