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