blob: 1c2fdb092d015a2475d704987bf2d17535039b2c [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];
191 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
192 info->burst_size_frames = hidlInfo.burstSizeFrames;
193 // info->shared_memory_address is not needed in HIDL context
194 info->shared_memory_address = NULL;
195 } else {
196 retval = Result::NOT_INITIALIZED;
197 }
198 }
199 });
200 return processReturn("createMmapBuffer", ret, retval);
201}
202
203status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
204 Result retval;
205 Return<void> ret = mStream->getMmapPosition(
206 [&](Result r, const MmapPosition& hidlPosition) {
207 retval = r;
208 if (retval == Result::OK) {
209 position->time_nanoseconds = hidlPosition.timeNanoseconds;
210 position->position_frames = hidlPosition.positionFrames;
211 }
212 });
213 return processReturn("getMmapPosition", ret, retval);
214}
215
216status_t StreamHalHidl::setHalThreadPriority(int priority) {
217 mHalThreadPriority = priority;
218 return OK;
219}
220
221status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
222 if (mCachedBufferSize != 0) {
223 *size = mCachedBufferSize;
224 return OK;
225 }
226 return getBufferSize(size);
227}
228
229bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
230 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
231 return true;
232 }
233 int err = requestPriority(
234 threadPid, threadId,
235 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
236 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
237 mHalThreadPriority, threadPid, threadId, err);
238 // Audio will still work, but latency will be higher and sometimes unacceptable.
239 return err == 0;
240}
241
242namespace {
243
244/* Notes on callback ownership.
245
246This is how (Hw)Binder ownership model looks like. The server implementation
247is owned by Binder framework (via sp<>). Proxies are owned by clients.
248When the last proxy disappears, Binder framework releases the server impl.
249
250Thus, it is not needed to keep any references to StreamOutCallback (this is
251the server impl) -- it will live as long as HAL server holds a strong ref to
252IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
253from the destructor of StreamOutHalHidl.
254
255The callback only keeps a weak reference to the stream. The stream is owned
256by AudioFlinger.
257
258*/
259
260struct StreamOutCallback : public IStreamOutCallback {
261 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
262
263 // IStreamOutCallback implementation
264 Return<void> onWriteReady() override {
265 sp<StreamOutHalHidl> stream = mStream.promote();
266 if (stream != 0) {
267 stream->onWriteReady();
268 }
269 return Void();
270 }
271
272 Return<void> onDrainReady() override {
273 sp<StreamOutHalHidl> stream = mStream.promote();
274 if (stream != 0) {
275 stream->onDrainReady();
276 }
277 return Void();
278 }
279
280 Return<void> onError() override {
281 sp<StreamOutHalHidl> stream = mStream.promote();
282 if (stream != 0) {
283 stream->onError();
284 }
285 return Void();
286 }
287
288 private:
289 wp<StreamOutHalHidl> mStream;
290};
291
292} // namespace
293
294StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
295 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
296}
297
298StreamOutHalHidl::~StreamOutHalHidl() {
299 if (mStream != 0) {
300 if (mCallback.unsafe_get()) {
301 processReturn("clearCallback", mStream->clearCallback());
302 }
303 processReturn("close", mStream->close());
304 mStream.clear();
305 }
306 mCallback.clear();
307 hardware::IPCThreadState::self()->flushCommands();
308 if (mEfGroup) {
309 EventFlag::deleteEventFlag(&mEfGroup);
310 }
311}
312
313status_t StreamOutHalHidl::getFrameSize(size_t *size) {
314 if (mStream == 0) return NO_INIT;
315 return processReturn("getFrameSize", mStream->getFrameSize(), size);
316}
317
318status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
319 if (mStream == 0) return NO_INIT;
320 if (mWriterClient == gettid() && mCommandMQ) {
321 return callWriterThread(
322 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
323 [&](const WriteStatus& writeStatus) {
324 *latency = writeStatus.reply.latencyMs;
325 });
326 } else {
327 return processReturn("getLatency", mStream->getLatency(), latency);
328 }
329}
330
331status_t StreamOutHalHidl::setVolume(float left, float right) {
332 if (mStream == 0) return NO_INIT;
333 return processReturn("setVolume", mStream->setVolume(left, right));
334}
335
336status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
337 if (mStream == 0) return NO_INIT;
338 *written = 0;
339
340 if (bytes == 0 && !mDataMQ) {
341 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
342 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
343 return OK;
344 }
345
346 status_t status;
347 if (!mDataMQ) {
348 // In case if playback starts close to the end of a compressed track, the bytes
349 // that need to be written is less than the actual buffer size. Need to use
350 // full buffer size for the MQ since otherwise after seeking back to the middle
351 // data will be truncated.
352 size_t bufferSize;
353 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
354 return status;
355 }
356 if (bytes > bufferSize) bufferSize = bytes;
357 if ((status = prepareForWriting(bufferSize)) != OK) {
358 return status;
359 }
360 }
361
362 status = callWriterThread(
363 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
364 [&] (const WriteStatus& writeStatus) {
365 *written = writeStatus.reply.written;
366 // Diagnostics of the cause of b/35813113.
367 ALOGE_IF(*written > bytes,
368 "hal reports more bytes written than asked for: %lld > %lld",
369 (long long)*written, (long long)bytes);
370 });
371 mStreamPowerLog.log(buffer, *written);
372 return status;
373}
374
375status_t StreamOutHalHidl::callWriterThread(
376 WriteCommand cmd, const char* cmdName,
377 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
378 if (!mCommandMQ->write(&cmd)) {
379 ALOGE("command message queue write failed for \"%s\"", cmdName);
380 return -EAGAIN;
381 }
382 if (data != nullptr) {
383 size_t availableToWrite = mDataMQ->availableToWrite();
384 if (dataSize > availableToWrite) {
385 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
386 (long long)dataSize, (long long)availableToWrite);
387 dataSize = availableToWrite;
388 }
389 if (!mDataMQ->write(data, dataSize)) {
390 ALOGE("data message queue write failed for \"%s\"", cmdName);
391 }
392 }
393 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
394
395 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
396 uint32_t efState = 0;
397retry:
398 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
399 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
400 WriteStatus writeStatus;
401 writeStatus.retval = Result::NOT_INITIALIZED;
402 if (!mStatusMQ->read(&writeStatus)) {
403 ALOGE("status message read failed for \"%s\"", cmdName);
404 }
405 if (writeStatus.retval == Result::OK) {
406 ret = OK;
407 callback(writeStatus);
408 } else {
409 ret = processReturn(cmdName, writeStatus.retval);
410 }
411 return ret;
412 }
413 if (ret == -EAGAIN || ret == -EINTR) {
414 // Spurious wakeup. This normally retries no more than once.
415 goto retry;
416 }
417 return ret;
418}
419
420status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
421 std::unique_ptr<CommandMQ> tempCommandMQ;
422 std::unique_ptr<DataMQ> tempDataMQ;
423 std::unique_ptr<StatusMQ> tempStatusMQ;
424 Result retval;
425 pid_t halThreadPid, halThreadTid;
426 Return<void> ret = mStream->prepareForWriting(
427 1, bufferSize,
428 [&](Result r,
429 const CommandMQ::Descriptor& commandMQ,
430 const DataMQ::Descriptor& dataMQ,
431 const StatusMQ::Descriptor& statusMQ,
432 const ThreadInfo& halThreadInfo) {
433 retval = r;
434 if (retval == Result::OK) {
435 tempCommandMQ.reset(new CommandMQ(commandMQ));
436 tempDataMQ.reset(new DataMQ(dataMQ));
437 tempStatusMQ.reset(new StatusMQ(statusMQ));
438 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
439 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
440 }
441 halThreadPid = halThreadInfo.pid;
442 halThreadTid = halThreadInfo.tid;
443 }
444 });
445 if (!ret.isOk() || retval != Result::OK) {
446 return processReturn("prepareForWriting", ret, retval);
447 }
448 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
449 !tempDataMQ || !tempDataMQ->isValid() ||
450 !tempStatusMQ || !tempStatusMQ->isValid() ||
451 !mEfGroup) {
452 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
453 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
454 "Command message queue for writing is invalid");
455 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
456 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
457 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
458 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
459 "Status message queue for writing is invalid");
460 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
461 return NO_INIT;
462 }
463 requestHalThreadPriority(halThreadPid, halThreadTid);
464
465 mCommandMQ = std::move(tempCommandMQ);
466 mDataMQ = std::move(tempDataMQ);
467 mStatusMQ = std::move(tempStatusMQ);
468 mWriterClient = gettid();
469 return OK;
470}
471
472status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
473 if (mStream == 0) return NO_INIT;
474 Result retval;
475 Return<void> ret = mStream->getRenderPosition(
476 [&](Result r, uint32_t d) {
477 retval = r;
478 if (retval == Result::OK) {
479 *dspFrames = d;
480 }
481 });
482 return processReturn("getRenderPosition", ret, retval);
483}
484
485status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
486 if (mStream == 0) return NO_INIT;
487 Result retval;
488 Return<void> ret = mStream->getNextWriteTimestamp(
489 [&](Result r, int64_t t) {
490 retval = r;
491 if (retval == Result::OK) {
492 *timestamp = t;
493 }
494 });
495 return processReturn("getRenderPosition", ret, retval);
496}
497
498status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
499 if (mStream == 0) return NO_INIT;
500 status_t status = processReturn(
501 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
502 if (status == OK) {
503 mCallback = callback;
504 }
505 return status;
506}
507
508status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
509 if (mStream == 0) return NO_INIT;
510 Return<void> ret = mStream->supportsPauseAndResume(
511 [&](bool p, bool r) {
512 *supportsPause = p;
513 *supportsResume = r;
514 });
515 return processReturn("supportsPauseAndResume", ret);
516}
517
518status_t StreamOutHalHidl::pause() {
519 if (mStream == 0) return NO_INIT;
520 return processReturn("pause", mStream->pause());
521}
522
523status_t StreamOutHalHidl::resume() {
524 if (mStream == 0) return NO_INIT;
525 return processReturn("pause", mStream->resume());
526}
527
528status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
529 if (mStream == 0) return NO_INIT;
530 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
531}
532
533status_t StreamOutHalHidl::drain(bool earlyNotify) {
534 if (mStream == 0) return NO_INIT;
535 return processReturn(
536 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
537}
538
539status_t StreamOutHalHidl::flush() {
540 if (mStream == 0) return NO_INIT;
541 return processReturn("pause", mStream->flush());
542}
543
544status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
545 if (mStream == 0) return NO_INIT;
546 if (mWriterClient == gettid() && mCommandMQ) {
547 return callWriterThread(
548 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
549 [&](const WriteStatus& writeStatus) {
550 *frames = writeStatus.reply.presentationPosition.frames;
551 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
552 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
553 });
554 } else {
555 Result retval;
556 Return<void> ret = mStream->getPresentationPosition(
557 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
558 retval = r;
559 if (retval == Result::OK) {
560 *frames = hidlFrames;
561 timestamp->tv_sec = hidlTimeStamp.tvSec;
562 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
563 }
564 });
565 return processReturn("getPresentationPosition", ret, retval);
566 }
567}
568
Kevin Rocarda8975a72018-03-27 10:16:52 -0700569/** Transform a standard collection to an HIDL vector. */
570template <class Values, class ElementConverter>
571static auto transformToHidlVec(const Values& values, ElementConverter converter) {
572 hidl_vec<decltype(converter(*values.begin()))> result{values.size()};
573 using namespace std;
574 transform(begin(values), end(values), begin(result), converter);
575 return result;
576}
577
578status_t StreamOutHalHidl::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
579 hardware::audio::V4_0::SourceMetadata halMetadata = {
580 .tracks = transformToHidlVec(sourceMetadata.tracks,
581 [](const playback_track_metadata& metadata) -> PlaybackTrackMetadata {
582 return {
583 .usage=static_cast<AudioUsage>(metadata.usage),
584 .contentType=static_cast<AudioContentType>(metadata.content_type),
585 .gain=metadata.gain,
586 };
587 })};
588 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(halMetadata));
589}
590
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800591void StreamOutHalHidl::onWriteReady() {
592 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
593 if (callback == 0) return;
594 ALOGV("asyncCallback onWriteReady");
595 callback->onWriteReady();
596}
597
598void StreamOutHalHidl::onDrainReady() {
599 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
600 if (callback == 0) return;
601 ALOGV("asyncCallback onDrainReady");
602 callback->onDrainReady();
603}
604
605void StreamOutHalHidl::onError() {
606 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
607 if (callback == 0) return;
608 ALOGV("asyncCallback onError");
609 callback->onError();
610}
611
612
613StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
614 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
615}
616
617StreamInHalHidl::~StreamInHalHidl() {
618 if (mStream != 0) {
619 processReturn("close", mStream->close());
620 mStream.clear();
621 hardware::IPCThreadState::self()->flushCommands();
622 }
623 if (mEfGroup) {
624 EventFlag::deleteEventFlag(&mEfGroup);
625 }
626}
627
628status_t StreamInHalHidl::getFrameSize(size_t *size) {
629 if (mStream == 0) return NO_INIT;
630 return processReturn("getFrameSize", mStream->getFrameSize(), size);
631}
632
633status_t StreamInHalHidl::setGain(float gain) {
634 if (mStream == 0) return NO_INIT;
635 return processReturn("setGain", mStream->setGain(gain));
636}
637
638status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
639 if (mStream == 0) return NO_INIT;
640 *read = 0;
641
642 if (bytes == 0 && !mDataMQ) {
643 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
644 return OK;
645 }
646
647 status_t status;
648 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
649 return status;
650 }
651
652 ReadParameters params;
653 params.command = ReadCommand::READ;
654 params.params.read = bytes;
655 status = callReaderThread(params, "read",
656 [&](const ReadStatus& readStatus) {
657 const size_t availToRead = mDataMQ->availableToRead();
658 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
659 ALOGE("data message queue read failed for \"read\"");
660 }
661 ALOGW_IF(availToRead != readStatus.reply.read,
662 "HAL read report inconsistent: mq = %d, status = %d",
663 (int32_t)availToRead, (int32_t)readStatus.reply.read);
664 *read = readStatus.reply.read;
665 });
666 mStreamPowerLog.log(buffer, *read);
667 return status;
668}
669
670status_t StreamInHalHidl::callReaderThread(
671 const ReadParameters& params, const char* cmdName,
672 StreamInHalHidl::ReaderCallback callback) {
673 if (!mCommandMQ->write(&params)) {
674 ALOGW("command message queue write failed");
675 return -EAGAIN;
676 }
677 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
678
679 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
680 uint32_t efState = 0;
681retry:
682 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
683 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
684 ReadStatus readStatus;
685 readStatus.retval = Result::NOT_INITIALIZED;
686 if (!mStatusMQ->read(&readStatus)) {
687 ALOGE("status message read failed for \"%s\"", cmdName);
688 }
689 if (readStatus.retval == Result::OK) {
690 ret = OK;
691 callback(readStatus);
692 } else {
693 ret = processReturn(cmdName, readStatus.retval);
694 }
695 return ret;
696 }
697 if (ret == -EAGAIN || ret == -EINTR) {
698 // Spurious wakeup. This normally retries no more than once.
699 goto retry;
700 }
701 return ret;
702}
703
704status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
705 std::unique_ptr<CommandMQ> tempCommandMQ;
706 std::unique_ptr<DataMQ> tempDataMQ;
707 std::unique_ptr<StatusMQ> tempStatusMQ;
708 Result retval;
709 pid_t halThreadPid, halThreadTid;
710 Return<void> ret = mStream->prepareForReading(
711 1, bufferSize,
712 [&](Result r,
713 const CommandMQ::Descriptor& commandMQ,
714 const DataMQ::Descriptor& dataMQ,
715 const StatusMQ::Descriptor& statusMQ,
716 const ThreadInfo& halThreadInfo) {
717 retval = r;
718 if (retval == Result::OK) {
719 tempCommandMQ.reset(new CommandMQ(commandMQ));
720 tempDataMQ.reset(new DataMQ(dataMQ));
721 tempStatusMQ.reset(new StatusMQ(statusMQ));
722 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
723 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
724 }
725 halThreadPid = halThreadInfo.pid;
726 halThreadTid = halThreadInfo.tid;
727 }
728 });
729 if (!ret.isOk() || retval != Result::OK) {
730 return processReturn("prepareForReading", ret, retval);
731 }
732 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
733 !tempDataMQ || !tempDataMQ->isValid() ||
734 !tempStatusMQ || !tempStatusMQ->isValid() ||
735 !mEfGroup) {
736 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
737 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
738 "Command message queue for writing is invalid");
739 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
740 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
741 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
742 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
743 "Status message queue for reading is invalid");
744 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
745 return NO_INIT;
746 }
747 requestHalThreadPriority(halThreadPid, halThreadTid);
748
749 mCommandMQ = std::move(tempCommandMQ);
750 mDataMQ = std::move(tempDataMQ);
751 mStatusMQ = std::move(tempStatusMQ);
752 mReaderClient = gettid();
753 return OK;
754}
755
756status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
757 if (mStream == 0) return NO_INIT;
758 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
759}
760
761status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
762 if (mStream == 0) return NO_INIT;
763 if (mReaderClient == gettid() && mCommandMQ) {
764 ReadParameters params;
765 params.command = ReadCommand::GET_CAPTURE_POSITION;
766 return callReaderThread(params, "getCapturePosition",
767 [&](const ReadStatus& readStatus) {
768 *frames = readStatus.reply.capturePosition.frames;
769 *time = readStatus.reply.capturePosition.time;
770 });
771 } else {
772 Result retval;
773 Return<void> ret = mStream->getCapturePosition(
774 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
775 retval = r;
776 if (retval == Result::OK) {
777 *frames = hidlFrames;
778 *time = hidlTime;
779 }
780 });
781 return processReturn("getCapturePosition", ret, retval);
782 }
783}
784
jiabin9ff780e2018-03-19 18:19:52 -0700785
786status_t StreamInHalHidl::getActiveMicrophones(
787 std::vector<media::MicrophoneInfo> *microphonesInfo) {
788 if (!mStream) return NO_INIT;
789 Result retval;
790 Return<void> ret = mStream->getActiveMicrophones(
791 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
792 retval = r;
793 for (size_t k = 0; k < micArrayHal.size(); k++) {
794 audio_microphone_characteristic_t dst;
795 // convert
796 microphoneInfoToHal(micArrayHal[k], &dst);
797 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
798 microphonesInfo->push_back(microphone);
799 }
800 });
801 return processReturn("getActiveMicrophones", ret, retval);
802}
803
Kevin Rocarda8975a72018-03-27 10:16:52 -0700804status_t StreamInHalHidl::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
805 hardware::audio::V4_0::SinkMetadata halMetadata = {
806 .tracks = transformToHidlVec(sinkMetadata.tracks,
807 [](const record_track_metadata& metadata) -> RecordTrackMetadata {
808 return {
809 .source=static_cast<AudioSource>(metadata.source),
810 .gain=metadata.gain,
811 };
812 })};
813 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(halMetadata));
814}
815
Kevin Rocard51e076a2018-02-28 14:36:53 -0800816} // namespace V4_0
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800817} // namespace android