blob: b66ba2be9dcd1ff526931606aa0a03dbd715a4a3 [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:
Mikhail Naganovb4e77912017-02-15 10:23:09 -0800341 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800342 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800343 WriteStatus writeStatus;
344 writeStatus.retval = Result::NOT_INITIALIZED;
345 if (!mStatusMQ->read(&writeStatus)) {
346 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800347 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800348 if (writeStatus.retval == Result::OK) {
349 ret = OK;
350 callback(writeStatus);
351 } else {
352 ret = processReturn(cmdName, writeStatus.retval);
353 }
354 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800355 }
356 if (ret == -EAGAIN) {
357 // This normally retries no more than once.
358 goto retry;
359 }
360 return ret;
361}
362
363status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800364 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800365 std::unique_ptr<DataMQ> tempDataMQ;
366 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800367 Result retval;
Mikhail Naganov83f04272017-02-07 10:45:09 -0800368 pid_t halThreadPid, halThreadTid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800369 Return<void> ret = mStream->prepareForWriting(
Mikhail Naganov83f04272017-02-07 10:45:09 -0800370 1, bufferSize,
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800371 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800372 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800373 const DataMQ::Descriptor& dataMQ,
Mikhail Naganov83f04272017-02-07 10:45:09 -0800374 const StatusMQ::Descriptor& statusMQ,
375 const ThreadInfo& halThreadInfo) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800376 retval = r;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800377 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800378 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800379 tempDataMQ.reset(new DataMQ(dataMQ));
380 tempStatusMQ.reset(new StatusMQ(statusMQ));
381 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
382 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
383 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800384 halThreadPid = halThreadInfo.pid;
385 halThreadTid = halThreadInfo.tid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800386 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800387 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800388 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800389 return processReturn("prepareForWriting", ret, retval);
390 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800391 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
392 !tempDataMQ || !tempDataMQ->isValid() ||
393 !tempStatusMQ || !tempStatusMQ->isValid() ||
394 !mEfGroup) {
395 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
396 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
397 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800398 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
399 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
400 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
401 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
402 "Status message queue for writing is invalid");
403 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
404 return NO_INIT;
405 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800406 requestHalThreadPriority(halThreadPid, halThreadTid);
407
Mikhail Naganovc8381902017-01-31 13:56:25 -0800408 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800409 mDataMQ = std::move(tempDataMQ);
410 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800411 mWriterClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800412 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800413}
414
415status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
416 if (mStream == 0) return NO_INIT;
417 Result retval;
418 Return<void> ret = mStream->getRenderPosition(
419 [&](Result r, uint32_t d) {
420 retval = r;
421 if (retval == Result::OK) {
422 *dspFrames = d;
423 }
424 });
425 return processReturn("getRenderPosition", ret, retval);
426}
427
428status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
429 if (mStream == 0) return NO_INIT;
430 Result retval;
431 Return<void> ret = mStream->getNextWriteTimestamp(
432 [&](Result r, int64_t t) {
433 retval = r;
434 if (retval == Result::OK) {
435 *timestamp = t;
436 }
437 });
438 return processReturn("getRenderPosition", ret, retval);
439}
440
441status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
442 if (mStream == 0) return NO_INIT;
443 status_t status = processReturn(
444 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
445 if (status == OK) {
446 mCallback = callback;
447 }
448 return status;
449}
450
451status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
452 if (mStream == 0) return NO_INIT;
453 Return<void> ret = mStream->supportsPauseAndResume(
454 [&](bool p, bool r) {
455 *supportsPause = p;
456 *supportsResume = r;
457 });
458 return processReturn("supportsPauseAndResume", ret);
459}
460
461status_t StreamOutHalHidl::pause() {
462 if (mStream == 0) return NO_INIT;
463 return processReturn("pause", mStream->pause());
464}
465
466status_t StreamOutHalHidl::resume() {
467 if (mStream == 0) return NO_INIT;
468 return processReturn("pause", mStream->resume());
469}
470
471status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
472 if (mStream == 0) return NO_INIT;
473 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
474}
475
476status_t StreamOutHalHidl::drain(bool earlyNotify) {
477 if (mStream == 0) return NO_INIT;
478 return processReturn(
479 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
480}
481
482status_t StreamOutHalHidl::flush() {
483 if (mStream == 0) return NO_INIT;
484 return processReturn("pause", mStream->flush());
485}
486
487status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
488 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800489 if (mWriterClient == gettid() && mCommandMQ) {
490 return callWriterThread(
491 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
492 [&](const WriteStatus& writeStatus) {
493 *frames = writeStatus.reply.presentationPosition.frames;
494 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
495 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
496 });
497 } else {
498 Result retval;
499 Return<void> ret = mStream->getPresentationPosition(
500 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
501 retval = r;
502 if (retval == Result::OK) {
503 *frames = hidlFrames;
504 timestamp->tv_sec = hidlTimeStamp.tvSec;
505 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
506 }
507 });
508 return processReturn("getPresentationPosition", ret, retval);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800509 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800510}
511
512void StreamOutHalHidl::onWriteReady() {
513 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
514 if (callback == 0) return;
515 ALOGV("asyncCallback onWriteReady");
516 callback->onWriteReady();
517}
518
519void StreamOutHalHidl::onDrainReady() {
520 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
521 if (callback == 0) return;
522 ALOGV("asyncCallback onDrainReady");
523 callback->onDrainReady();
524}
525
526void StreamOutHalHidl::onError() {
527 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
528 if (callback == 0) return;
529 ALOGV("asyncCallback onError");
530 callback->onError();
531}
532
533
534StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
Mikhail Naganovc8381902017-01-31 13:56:25 -0800535 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800536}
537
538StreamInHalHidl::~StreamInHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800539 if (mStream != 0) {
540 processReturn("close", mStream->close());
541 }
542 if (mEfGroup) {
543 EventFlag::deleteEventFlag(&mEfGroup);
544 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800545}
546
547status_t StreamInHalHidl::getFrameSize(size_t *size) {
548 if (mStream == 0) return NO_INIT;
549 return processReturn("getFrameSize", mStream->getFrameSize(), size);
550}
551
552status_t StreamInHalHidl::setGain(float gain) {
553 if (mStream == 0) return NO_INIT;
554 return processReturn("setGain", mStream->setGain(gain));
555}
556
557status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
558 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800559 *read = 0;
560
561 if (bytes == 0 && !mDataMQ) {
562 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
563 return OK;
564 }
565
566 status_t status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800567 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
568 return status;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800569 }
570
Mikhail Naganovc8381902017-01-31 13:56:25 -0800571 ReadParameters params;
572 params.command = ReadCommand::READ;
573 params.params.read = bytes;
574 return callReaderThread(params, "read",
575 [&](const ReadStatus& readStatus) {
576 const size_t availToRead = mDataMQ->availableToRead();
577 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
578 ALOGE("data message queue read failed for \"read\"");
579 }
580 ALOGW_IF(availToRead != readStatus.reply.read,
581 "HAL read report inconsistent: mq = %d, status = %d",
582 (int32_t)availToRead, (int32_t)readStatus.reply.read);
583 *read = readStatus.reply.read;
584 });
585}
586
587status_t StreamInHalHidl::callReaderThread(
588 const ReadParameters& params, const char* cmdName,
589 StreamInHalHidl::ReaderCallback callback) {
590 if (!mCommandMQ->write(&params)) {
591 ALOGW("command message queue write failed");
592 return -EAGAIN;
593 }
594 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
595
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800596 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
597 uint32_t efState = 0;
598retry:
Mikhail Naganovb4e77912017-02-15 10:23:09 -0800599 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800600 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800601 ReadStatus readStatus;
602 readStatus.retval = Result::NOT_INITIALIZED;
603 if (!mStatusMQ->read(&readStatus)) {
604 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800605 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800606 if (readStatus.retval == Result::OK) {
607 ret = OK;
608 callback(readStatus);
609 } else {
610 ret = processReturn(cmdName, readStatus.retval);
611 }
612 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800613 }
614 if (ret == -EAGAIN) {
615 // This normally retries no more than once.
616 goto retry;
617 }
618 return ret;
619}
620
621status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800622 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800623 std::unique_ptr<DataMQ> tempDataMQ;
624 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800625 Result retval;
Mikhail Naganov83f04272017-02-07 10:45:09 -0800626 pid_t halThreadPid, halThreadTid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800627 Return<void> ret = mStream->prepareForReading(
Mikhail Naganov83f04272017-02-07 10:45:09 -0800628 1, bufferSize,
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800629 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800630 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800631 const DataMQ::Descriptor& dataMQ,
Mikhail Naganov83f04272017-02-07 10:45:09 -0800632 const StatusMQ::Descriptor& statusMQ,
633 const ThreadInfo& halThreadInfo) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800634 retval = r;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800635 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800636 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800637 tempDataMQ.reset(new DataMQ(dataMQ));
638 tempStatusMQ.reset(new StatusMQ(statusMQ));
639 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
640 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
641 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800642 halThreadPid = halThreadInfo.pid;
643 halThreadTid = halThreadInfo.tid;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800644 }
645 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800646 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800647 return processReturn("prepareForReading", ret, retval);
648 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800649 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
650 !tempDataMQ || !tempDataMQ->isValid() ||
651 !tempStatusMQ || !tempStatusMQ->isValid() ||
652 !mEfGroup) {
653 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
654 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
655 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800656 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
657 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
658 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
659 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
660 "Status message queue for reading is invalid");
661 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
662 return NO_INIT;
663 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800664 requestHalThreadPriority(halThreadPid, halThreadTid);
665
Mikhail Naganovc8381902017-01-31 13:56:25 -0800666 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800667 mDataMQ = std::move(tempDataMQ);
668 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800669 mReaderClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800670 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800671}
672
673status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
674 if (mStream == 0) return NO_INIT;
675 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
676}
677
678status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
679 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800680 if (mReaderClient == gettid() && mCommandMQ) {
681 ReadParameters params;
682 params.command = ReadCommand::GET_CAPTURE_POSITION;
683 return callReaderThread(params, "getCapturePosition",
684 [&](const ReadStatus& readStatus) {
685 *frames = readStatus.reply.capturePosition.frames;
686 *time = readStatus.reply.capturePosition.time;
687 });
688 } else {
689 Result retval;
690 Return<void> ret = mStream->getCapturePosition(
691 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
692 retval = r;
693 if (retval == Result::OK) {
694 *frames = hidlFrames;
695 *time = hidlTime;
696 }
697 });
698 return processReturn("getCapturePosition", ret, retval);
699 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800700}
701
702} // namespace android