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