blob: 4054aaa71fe524d68d354e07a86d7b7d0a8f619f [file] [log] [blame]
Mikhail Naganovf558e022016-11-14 17:45:17 -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
20#include <android/hardware/audio/2.0/IStreamOutCallback.h>
Mikhail Naganov83f04272017-02-07 10:45:09 -080021#include <mediautils/SchedulingPolicyService.h>
Mikhail Naganovf558e022016-11-14 17:45:17 -080022#include <utils/Log.h>
23
24#include "DeviceHalHidl.h"
25#include "EffectHalHidl.h"
26#include "StreamHalHidl.h"
27
28using ::android::hardware::audio::common::V2_0::AudioChannelMask;
29using ::android::hardware::audio::common::V2_0::AudioFormat;
Mikhail Naganov83f04272017-02-07 10:45:09 -080030using ::android::hardware::audio::common::V2_0::ThreadInfo;
Mikhail Naganovf558e022016-11-14 17:45:17 -080031using ::android::hardware::audio::V2_0::AudioDrain;
32using ::android::hardware::audio::V2_0::IStreamOutCallback;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080033using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
Eric Laurentaf35aad2016-12-15 14:25:36 -080034using ::android::hardware::audio::V2_0::MmapBufferInfo;
35using ::android::hardware::audio::V2_0::MmapPosition;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080036using ::android::hardware::audio::V2_0::ParameterValue;
37using ::android::hardware::audio::V2_0::Result;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080038using ::android::hardware::audio::V2_0::TimeSpec;
39using ::android::hardware::MQDescriptorSync;
Mikhail Naganovf558e022016-11-14 17:45:17 -080040using ::android::hardware::Return;
41using ::android::hardware::Void;
Mikhail Naganovc8381902017-01-31 13:56:25 -080042using ReadCommand = ::android::hardware::audio::V2_0::IStreamIn::ReadCommand;
Mikhail Naganovf558e022016-11-14 17:45:17 -080043
44namespace android {
45
46StreamHalHidl::StreamHalHidl(IStream *stream)
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080047 : ConversionHelperHidl("Stream"),
Mikhail Naganov83f04272017-02-07 10:45:09 -080048 mStream(stream),
49 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT) {
Mikhail Naganovf558e022016-11-14 17:45:17 -080050}
51
52StreamHalHidl::~StreamHalHidl() {
53 mStream = nullptr;
54}
55
56status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
57 if (!mStream) return NO_INIT;
58 return processReturn("getSampleRate", mStream->getSampleRate(), rate);
59}
60
61status_t StreamHalHidl::getBufferSize(size_t *size) {
62 if (!mStream) return NO_INIT;
63 return processReturn("getBufferSize", mStream->getBufferSize(), size);
64}
65
66status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
67 if (!mStream) return NO_INIT;
68 return processReturn("getChannelMask", mStream->getChannelMask(), mask);
69}
70
71status_t StreamHalHidl::getFormat(audio_format_t *format) {
72 if (!mStream) return NO_INIT;
73 return processReturn("getFormat", mStream->getFormat(), format);
74}
75
76status_t StreamHalHidl::getAudioProperties(
77 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
78 if (!mStream) return NO_INIT;
79 Return<void> ret = mStream->getAudioProperties(
80 [&](uint32_t sr, AudioChannelMask m, AudioFormat f) {
81 *sampleRate = sr;
82 *mask = static_cast<audio_channel_mask_t>(m);
83 *format = static_cast<audio_format_t>(f);
84 });
85 return processReturn("getAudioProperties", ret);
86}
87
88status_t StreamHalHidl::setParameters(const String8& kvPairs) {
89 if (!mStream) return NO_INIT;
90 hidl_vec<ParameterValue> hidlParams;
91 status_t status = parametersFromHal(kvPairs, &hidlParams);
92 if (status != OK) return status;
93 return processReturn("setParameters", mStream->setParameters(hidlParams));
94}
95
96status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
97 values->clear();
98 if (!mStream) return NO_INIT;
99 hidl_vec<hidl_string> hidlKeys;
100 status_t status = keysFromHal(keys, &hidlKeys);
101 if (status != OK) return status;
102 Result retval;
103 Return<void> ret = mStream->getParameters(
104 hidlKeys,
105 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
106 retval = r;
107 if (retval == Result::OK) {
108 parametersToHal(parameters, values);
109 }
110 });
111 return processReturn("getParameters", ret, retval);
112}
113
114status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
115 if (!mStream) return NO_INIT;
116 return processReturn("addEffect", mStream->addEffect(
117 static_cast<EffectHalHidl*>(effect.get())->effectId()));
118}
119
120status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
121 if (!mStream) return NO_INIT;
122 return processReturn("removeEffect", mStream->removeEffect(
123 static_cast<EffectHalHidl*>(effect.get())->effectId()));
124}
125
126status_t StreamHalHidl::standby() {
127 if (!mStream) return NO_INIT;
128 return processReturn("standby", mStream->standby());
129}
130
131status_t StreamHalHidl::dump(int fd) {
132 if (!mStream) return NO_INIT;
133 native_handle_t* hidlHandle = native_handle_create(1, 0);
134 hidlHandle->data[0] = fd;
135 Return<void> ret = mStream->debugDump(hidlHandle);
136 native_handle_delete(hidlHandle);
137 return processReturn("dump", ret);
138}
139
Eric Laurentaf35aad2016-12-15 14:25:36 -0800140status_t StreamHalHidl::start() {
141 if (!mStream) return NO_INIT;
142 return processReturn("start", mStream->start());
143}
144
145status_t StreamHalHidl::stop() {
146 if (!mStream) return NO_INIT;
147 return processReturn("stop", mStream->stop());
148}
149
150status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
151 struct audio_mmap_buffer_info *info) {
152 Result retval;
153 Return<void> ret = mStream->createMmapBuffer(
154 minSizeFrames,
155 [&](Result r, const MmapBufferInfo& hidlInfo) {
156 retval = r;
157 if (retval == Result::OK) {
Eric Laurentb8753072016-12-21 12:04:10 -0800158 const native_handle *handle = hidlInfo.sharedMemory.handle();
Eric Laurentaf35aad2016-12-15 14:25:36 -0800159 if (handle->numFds > 0) {
160 info->shared_memory_fd = dup(handle->data[0]);
161 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
162 info->burst_size_frames = hidlInfo.burstSizeFrames;
163 // info->shared_memory_address is not needed in HIDL context
164 info->shared_memory_address = NULL;
165 } else {
166 retval = Result::NOT_INITIALIZED;
167 }
168 }
169 });
170 return processReturn("createMmapBuffer", ret, retval);
171}
172
173status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
174 Result retval;
175 Return<void> ret = mStream->getMmapPosition(
176 [&](Result r, const MmapPosition& hidlPosition) {
177 retval = r;
178 if (retval == Result::OK) {
179 position->time_nanoseconds = hidlPosition.timeNanoseconds;
180 position->position_frames = hidlPosition.positionFrames;
181 }
182 });
183 return processReturn("getMmapPosition", ret, retval);
184}
Mikhail Naganovf558e022016-11-14 17:45:17 -0800185
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800186status_t StreamHalHidl::setHalThreadPriority(int priority) {
187 mHalThreadPriority = priority;
188 return OK;
189}
190
Mikhail Naganov83f04272017-02-07 10:45:09 -0800191bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
192 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
193 return true;
194 }
195 int err = requestPriority(
196 threadPid, threadId,
197 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
198 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
199 mHalThreadPriority, threadPid, threadId, err);
200 // Audio will still work, but latency will be higher and sometimes unacceptable.
201 return err == 0;
202}
203
Mikhail Naganovf558e022016-11-14 17:45:17 -0800204namespace {
205
206/* Notes on callback ownership.
207
208This is how (Hw)Binder ownership model looks like. The server implementation
209is owned by Binder framework (via sp<>). Proxies are owned by clients.
210When the last proxy disappears, Binder framework releases the server impl.
211
212Thus, it is not needed to keep any references to StreamOutCallback (this is
213the server impl) -- it will live as long as HAL server holds a strong ref to
214IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
215from the destructor of StreamOutHalHidl.
216
217The callback only keeps a weak reference to the stream. The stream is owned
218by AudioFlinger.
219
220*/
221
222struct StreamOutCallback : public IStreamOutCallback {
223 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
224
225 // IStreamOutCallback implementation
226 Return<void> onWriteReady() override {
227 sp<StreamOutHalHidl> stream = mStream.promote();
228 if (stream != 0) {
229 stream->onWriteReady();
230 }
231 return Void();
232 }
233
234 Return<void> onDrainReady() override {
235 sp<StreamOutHalHidl> stream = mStream.promote();
236 if (stream != 0) {
237 stream->onDrainReady();
238 }
239 return Void();
240 }
241
242 Return<void> onError() override {
243 sp<StreamOutHalHidl> stream = mStream.promote();
244 if (stream != 0) {
245 stream->onError();
246 }
247 return Void();
248 }
249
250 private:
251 wp<StreamOutHalHidl> mStream;
252};
253
254} // namespace
255
256StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
Mikhail Naganovc8381902017-01-31 13:56:25 -0800257 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800258}
259
260StreamOutHalHidl::~StreamOutHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800261 if (mStream != 0) {
262 if (mCallback.unsafe_get()) {
263 processReturn("clearCallback", mStream->clearCallback());
264 }
265 processReturn("close", mStream->close());
Mikhail Naganovf558e022016-11-14 17:45:17 -0800266 }
267 mCallback.clear();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800268 if (mEfGroup) {
269 EventFlag::deleteEventFlag(&mEfGroup);
270 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800271}
272
273status_t StreamOutHalHidl::getFrameSize(size_t *size) {
274 if (mStream == 0) return NO_INIT;
275 return processReturn("getFrameSize", mStream->getFrameSize(), size);
276}
277
278status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
279 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800280 if (mWriterClient == gettid() && mCommandMQ) {
281 return callWriterThread(
282 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
283 [&](const WriteStatus& writeStatus) {
284 *latency = writeStatus.reply.latencyMs;
285 });
286 } else {
287 return processReturn("getLatency", mStream->getLatency(), latency);
288 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800289}
290
291status_t StreamOutHalHidl::setVolume(float left, float right) {
292 if (mStream == 0) return NO_INIT;
293 return processReturn("setVolume", mStream->setVolume(left, right));
294}
295
296status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
297 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800298 *written = 0;
299
300 if (bytes == 0 && !mDataMQ) {
301 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
302 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
303 return OK;
304 }
305
306 status_t status;
307 if (!mDataMQ && (status = prepareForWriting(bytes)) != OK) {
308 return status;
309 }
310
Mikhail Naganovc8381902017-01-31 13:56:25 -0800311 return callWriterThread(
312 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
313 [&] (const WriteStatus& writeStatus) {
314 *written = writeStatus.reply.written;
315 });
316}
317
318status_t StreamOutHalHidl::callWriterThread(
319 WriteCommand cmd, const char* cmdName,
320 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
321 if (!mCommandMQ->write(&cmd)) {
322 ALOGE("command message queue write failed for \"%s\"", cmdName);
323 return -EAGAIN;
324 }
325 if (data != nullptr) {
326 size_t availableToWrite = mDataMQ->availableToWrite();
327 if (dataSize > availableToWrite) {
328 ALOGW("truncating write data from %d to %d due to insufficient data queue space",
329 (int32_t)dataSize, (int32_t)availableToWrite);
330 dataSize = availableToWrite;
331 }
332 if (!mDataMQ->write(data, dataSize)) {
333 ALOGE("data message queue write failed for \"%s\"", cmdName);
334 }
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800335 }
336 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
337
338 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
339 uint32_t efState = 0;
340retry:
341 status_t ret = mEfGroup->wait(
342 static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState, NS_PER_SEC);
343 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800344 WriteStatus writeStatus;
345 writeStatus.retval = Result::NOT_INITIALIZED;
346 if (!mStatusMQ->read(&writeStatus)) {
347 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800348 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800349 if (writeStatus.retval == Result::OK) {
350 ret = OK;
351 callback(writeStatus);
352 } else {
353 ret = processReturn(cmdName, writeStatus.retval);
354 }
355 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800356 }
357 if (ret == -EAGAIN) {
358 // This normally retries no more than once.
359 goto retry;
360 }
361 return ret;
362}
363
364status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800365 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800366 std::unique_ptr<DataMQ> tempDataMQ;
367 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800368 Result retval;
Mikhail Naganov83f04272017-02-07 10:45:09 -0800369 pid_t halThreadPid, halThreadTid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800370 Return<void> ret = mStream->prepareForWriting(
Mikhail Naganov83f04272017-02-07 10:45:09 -0800371 1, bufferSize,
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800372 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800373 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800374 const DataMQ::Descriptor& dataMQ,
Mikhail Naganov83f04272017-02-07 10:45:09 -0800375 const StatusMQ::Descriptor& statusMQ,
376 const ThreadInfo& halThreadInfo) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800377 retval = r;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800378 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800379 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800380 tempDataMQ.reset(new DataMQ(dataMQ));
381 tempStatusMQ.reset(new StatusMQ(statusMQ));
382 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
383 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
384 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800385 halThreadPid = halThreadInfo.pid;
386 halThreadTid = halThreadInfo.tid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800387 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800388 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800389 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800390 return processReturn("prepareForWriting", ret, retval);
391 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800392 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
393 !tempDataMQ || !tempDataMQ->isValid() ||
394 !tempStatusMQ || !tempStatusMQ->isValid() ||
395 !mEfGroup) {
396 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
397 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
398 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800399 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
400 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
401 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
402 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
403 "Status message queue for writing is invalid");
404 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
405 return NO_INIT;
406 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800407 requestHalThreadPriority(halThreadPid, halThreadTid);
408
Mikhail Naganovc8381902017-01-31 13:56:25 -0800409 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800410 mDataMQ = std::move(tempDataMQ);
411 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800412 mWriterClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800413 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800414}
415
416status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
417 if (mStream == 0) return NO_INIT;
418 Result retval;
419 Return<void> ret = mStream->getRenderPosition(
420 [&](Result r, uint32_t d) {
421 retval = r;
422 if (retval == Result::OK) {
423 *dspFrames = d;
424 }
425 });
426 return processReturn("getRenderPosition", ret, retval);
427}
428
429status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
430 if (mStream == 0) return NO_INIT;
431 Result retval;
432 Return<void> ret = mStream->getNextWriteTimestamp(
433 [&](Result r, int64_t t) {
434 retval = r;
435 if (retval == Result::OK) {
436 *timestamp = t;
437 }
438 });
439 return processReturn("getRenderPosition", ret, retval);
440}
441
442status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
443 if (mStream == 0) return NO_INIT;
444 status_t status = processReturn(
445 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
446 if (status == OK) {
447 mCallback = callback;
448 }
449 return status;
450}
451
452status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
453 if (mStream == 0) return NO_INIT;
454 Return<void> ret = mStream->supportsPauseAndResume(
455 [&](bool p, bool r) {
456 *supportsPause = p;
457 *supportsResume = r;
458 });
459 return processReturn("supportsPauseAndResume", ret);
460}
461
462status_t StreamOutHalHidl::pause() {
463 if (mStream == 0) return NO_INIT;
464 return processReturn("pause", mStream->pause());
465}
466
467status_t StreamOutHalHidl::resume() {
468 if (mStream == 0) return NO_INIT;
469 return processReturn("pause", mStream->resume());
470}
471
472status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
473 if (mStream == 0) return NO_INIT;
474 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
475}
476
477status_t StreamOutHalHidl::drain(bool earlyNotify) {
478 if (mStream == 0) return NO_INIT;
479 return processReturn(
480 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
481}
482
483status_t StreamOutHalHidl::flush() {
484 if (mStream == 0) return NO_INIT;
485 return processReturn("pause", mStream->flush());
486}
487
488status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
489 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800490 if (mWriterClient == gettid() && mCommandMQ) {
491 return callWriterThread(
492 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
493 [&](const WriteStatus& writeStatus) {
494 *frames = writeStatus.reply.presentationPosition.frames;
495 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
496 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
497 });
498 } else {
499 Result retval;
500 Return<void> ret = mStream->getPresentationPosition(
501 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
502 retval = r;
503 if (retval == Result::OK) {
504 *frames = hidlFrames;
505 timestamp->tv_sec = hidlTimeStamp.tvSec;
506 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
507 }
508 });
509 return processReturn("getPresentationPosition", ret, retval);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800510 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800511}
512
513void StreamOutHalHidl::onWriteReady() {
514 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
515 if (callback == 0) return;
516 ALOGV("asyncCallback onWriteReady");
517 callback->onWriteReady();
518}
519
520void StreamOutHalHidl::onDrainReady() {
521 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
522 if (callback == 0) return;
523 ALOGV("asyncCallback onDrainReady");
524 callback->onDrainReady();
525}
526
527void StreamOutHalHidl::onError() {
528 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
529 if (callback == 0) return;
530 ALOGV("asyncCallback onError");
531 callback->onError();
532}
533
534
535StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
Mikhail Naganovc8381902017-01-31 13:56:25 -0800536 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800537}
538
539StreamInHalHidl::~StreamInHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800540 if (mStream != 0) {
541 processReturn("close", mStream->close());
542 }
543 if (mEfGroup) {
544 EventFlag::deleteEventFlag(&mEfGroup);
545 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800546}
547
548status_t StreamInHalHidl::getFrameSize(size_t *size) {
549 if (mStream == 0) return NO_INIT;
550 return processReturn("getFrameSize", mStream->getFrameSize(), size);
551}
552
553status_t StreamInHalHidl::setGain(float gain) {
554 if (mStream == 0) return NO_INIT;
555 return processReturn("setGain", mStream->setGain(gain));
556}
557
558status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
559 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800560 *read = 0;
561
562 if (bytes == 0 && !mDataMQ) {
563 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
564 return OK;
565 }
566
567 status_t status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800568 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
569 return status;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800570 }
571
Mikhail Naganovc8381902017-01-31 13:56:25 -0800572 ReadParameters params;
573 params.command = ReadCommand::READ;
574 params.params.read = bytes;
575 return callReaderThread(params, "read",
576 [&](const ReadStatus& readStatus) {
577 const size_t availToRead = mDataMQ->availableToRead();
578 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
579 ALOGE("data message queue read failed for \"read\"");
580 }
581 ALOGW_IF(availToRead != readStatus.reply.read,
582 "HAL read report inconsistent: mq = %d, status = %d",
583 (int32_t)availToRead, (int32_t)readStatus.reply.read);
584 *read = readStatus.reply.read;
585 });
586}
587
588status_t StreamInHalHidl::callReaderThread(
589 const ReadParameters& params, const char* cmdName,
590 StreamInHalHidl::ReaderCallback callback) {
591 if (!mCommandMQ->write(&params)) {
592 ALOGW("command message queue write failed");
593 return -EAGAIN;
594 }
595 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
596
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800597 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
598 uint32_t efState = 0;
599retry:
600 status_t ret = mEfGroup->wait(
601 static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState, NS_PER_SEC);
602 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800603 ReadStatus readStatus;
604 readStatus.retval = Result::NOT_INITIALIZED;
605 if (!mStatusMQ->read(&readStatus)) {
606 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800607 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800608 if (readStatus.retval == Result::OK) {
609 ret = OK;
610 callback(readStatus);
611 } else {
612 ret = processReturn(cmdName, readStatus.retval);
613 }
614 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800615 }
616 if (ret == -EAGAIN) {
617 // This normally retries no more than once.
618 goto retry;
619 }
620 return ret;
621}
622
623status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800624 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800625 std::unique_ptr<DataMQ> tempDataMQ;
626 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800627 Result retval;
Mikhail Naganov83f04272017-02-07 10:45:09 -0800628 pid_t halThreadPid, halThreadTid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800629 Return<void> ret = mStream->prepareForReading(
Mikhail Naganov83f04272017-02-07 10:45:09 -0800630 1, bufferSize,
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800631 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800632 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800633 const DataMQ::Descriptor& dataMQ,
Mikhail Naganov83f04272017-02-07 10:45:09 -0800634 const StatusMQ::Descriptor& statusMQ,
635 const ThreadInfo& halThreadInfo) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800636 retval = r;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800637 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800638 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800639 tempDataMQ.reset(new DataMQ(dataMQ));
640 tempStatusMQ.reset(new StatusMQ(statusMQ));
641 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
642 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
643 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800644 halThreadPid = halThreadInfo.pid;
645 halThreadTid = halThreadInfo.tid;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800646 }
647 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800648 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800649 return processReturn("prepareForReading", ret, retval);
650 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800651 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
652 !tempDataMQ || !tempDataMQ->isValid() ||
653 !tempStatusMQ || !tempStatusMQ->isValid() ||
654 !mEfGroup) {
655 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
656 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
657 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800658 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
659 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
660 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
661 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
662 "Status message queue for reading is invalid");
663 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
664 return NO_INIT;
665 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800666 requestHalThreadPriority(halThreadPid, halThreadTid);
667
Mikhail Naganovc8381902017-01-31 13:56:25 -0800668 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800669 mDataMQ = std::move(tempDataMQ);
670 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800671 mReaderClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800672 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800673}
674
675status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
676 if (mStream == 0) return NO_INIT;
677 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
678}
679
680status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
681 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800682 if (mReaderClient == gettid() && mCommandMQ) {
683 ReadParameters params;
684 params.command = ReadCommand::GET_CAPTURE_POSITION;
685 return callReaderThread(params, "getCapturePosition",
686 [&](const ReadStatus& readStatus) {
687 *frames = readStatus.reply.capturePosition.frames;
688 *time = readStatus.reply.capturePosition.time;
689 });
690 } else {
691 Result retval;
692 Return<void> ret = mStream->getCapturePosition(
693 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
694 retval = r;
695 if (retval == Result::OK) {
696 *frames = hidlFrames;
697 *time = hidlTime;
698 }
699 });
700 return processReturn("getCapturePosition", ret, retval);
701 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800702}
703
704} // namespace android