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