blob: 26cd4b554c486a85463abcb0b98d5581b88b9b36 [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 Naganov23feba22017-02-23 11:00:55 -080021#include <hwbinder/IPCThreadState.h>
Mikhail Naganov83f04272017-02-07 10:45:09 -080022#include <mediautils/SchedulingPolicyService.h>
Mikhail Naganovf558e022016-11-14 17:45:17 -080023#include <utils/Log.h>
24
25#include "DeviceHalHidl.h"
26#include "EffectHalHidl.h"
27#include "StreamHalHidl.h"
28
29using ::android::hardware::audio::common::V2_0::AudioChannelMask;
30using ::android::hardware::audio::common::V2_0::AudioFormat;
Mikhail Naganov83f04272017-02-07 10:45:09 -080031using ::android::hardware::audio::common::V2_0::ThreadInfo;
Mikhail Naganovf558e022016-11-14 17:45:17 -080032using ::android::hardware::audio::V2_0::AudioDrain;
33using ::android::hardware::audio::V2_0::IStreamOutCallback;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080034using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
Eric Laurentaf35aad2016-12-15 14:25:36 -080035using ::android::hardware::audio::V2_0::MmapBufferInfo;
36using ::android::hardware::audio::V2_0::MmapPosition;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080037using ::android::hardware::audio::V2_0::ParameterValue;
38using ::android::hardware::audio::V2_0::Result;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080039using ::android::hardware::audio::V2_0::TimeSpec;
40using ::android::hardware::MQDescriptorSync;
Mikhail Naganovf558e022016-11-14 17:45:17 -080041using ::android::hardware::Return;
42using ::android::hardware::Void;
Mikhail Naganovc8381902017-01-31 13:56:25 -080043using ReadCommand = ::android::hardware::audio::V2_0::IStreamIn::ReadCommand;
Mikhail Naganovf558e022016-11-14 17:45:17 -080044
45namespace android {
46
47StreamHalHidl::StreamHalHidl(IStream *stream)
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080048 : ConversionHelperHidl("Stream"),
Mikhail Naganov83f04272017-02-07 10:45:09 -080049 mStream(stream),
50 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT) {
Mikhail Naganovf558e022016-11-14 17:45:17 -080051}
52
53StreamHalHidl::~StreamHalHidl() {
54 mStream = nullptr;
55}
56
57status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
58 if (!mStream) return NO_INIT;
59 return processReturn("getSampleRate", mStream->getSampleRate(), rate);
60}
61
62status_t StreamHalHidl::getBufferSize(size_t *size) {
63 if (!mStream) return NO_INIT;
64 return processReturn("getBufferSize", mStream->getBufferSize(), size);
65}
66
67status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
68 if (!mStream) return NO_INIT;
69 return processReturn("getChannelMask", mStream->getChannelMask(), mask);
70}
71
72status_t StreamHalHidl::getFormat(audio_format_t *format) {
73 if (!mStream) return NO_INIT;
74 return processReturn("getFormat", mStream->getFormat(), format);
75}
76
77status_t StreamHalHidl::getAudioProperties(
78 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
79 if (!mStream) return NO_INIT;
80 Return<void> ret = mStream->getAudioProperties(
81 [&](uint32_t sr, AudioChannelMask m, AudioFormat f) {
82 *sampleRate = sr;
83 *mask = static_cast<audio_channel_mask_t>(m);
84 *format = static_cast<audio_format_t>(f);
85 });
86 return processReturn("getAudioProperties", ret);
87}
88
89status_t StreamHalHidl::setParameters(const String8& kvPairs) {
90 if (!mStream) return NO_INIT;
91 hidl_vec<ParameterValue> hidlParams;
92 status_t status = parametersFromHal(kvPairs, &hidlParams);
93 if (status != OK) return status;
94 return processReturn("setParameters", mStream->setParameters(hidlParams));
95}
96
97status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
98 values->clear();
99 if (!mStream) return NO_INIT;
100 hidl_vec<hidl_string> hidlKeys;
101 status_t status = keysFromHal(keys, &hidlKeys);
102 if (status != OK) return status;
103 Result retval;
104 Return<void> ret = mStream->getParameters(
105 hidlKeys,
106 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
107 retval = r;
108 if (retval == Result::OK) {
109 parametersToHal(parameters, values);
110 }
111 });
112 return processReturn("getParameters", ret, retval);
113}
114
115status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
116 if (!mStream) return NO_INIT;
117 return processReturn("addEffect", mStream->addEffect(
118 static_cast<EffectHalHidl*>(effect.get())->effectId()));
119}
120
121status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
122 if (!mStream) return NO_INIT;
123 return processReturn("removeEffect", mStream->removeEffect(
124 static_cast<EffectHalHidl*>(effect.get())->effectId()));
125}
126
127status_t StreamHalHidl::standby() {
128 if (!mStream) return NO_INIT;
129 return processReturn("standby", mStream->standby());
130}
131
132status_t StreamHalHidl::dump(int fd) {
133 if (!mStream) return NO_INIT;
134 native_handle_t* hidlHandle = native_handle_create(1, 0);
135 hidlHandle->data[0] = fd;
136 Return<void> ret = mStream->debugDump(hidlHandle);
137 native_handle_delete(hidlHandle);
138 return processReturn("dump", ret);
139}
140
Eric Laurentaf35aad2016-12-15 14:25:36 -0800141status_t StreamHalHidl::start() {
142 if (!mStream) return NO_INIT;
143 return processReturn("start", mStream->start());
144}
145
146status_t StreamHalHidl::stop() {
147 if (!mStream) return NO_INIT;
148 return processReturn("stop", mStream->stop());
149}
150
151status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
152 struct audio_mmap_buffer_info *info) {
153 Result retval;
154 Return<void> ret = mStream->createMmapBuffer(
155 minSizeFrames,
156 [&](Result r, const MmapBufferInfo& hidlInfo) {
157 retval = r;
158 if (retval == Result::OK) {
Eric Laurentb8753072016-12-21 12:04:10 -0800159 const native_handle *handle = hidlInfo.sharedMemory.handle();
Eric Laurentaf35aad2016-12-15 14:25:36 -0800160 if (handle->numFds > 0) {
161 info->shared_memory_fd = dup(handle->data[0]);
162 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
163 info->burst_size_frames = hidlInfo.burstSizeFrames;
164 // info->shared_memory_address is not needed in HIDL context
165 info->shared_memory_address = NULL;
166 } else {
167 retval = Result::NOT_INITIALIZED;
168 }
169 }
170 });
171 return processReturn("createMmapBuffer", ret, retval);
172}
173
174status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
175 Result retval;
176 Return<void> ret = mStream->getMmapPosition(
177 [&](Result r, const MmapPosition& hidlPosition) {
178 retval = r;
179 if (retval == Result::OK) {
180 position->time_nanoseconds = hidlPosition.timeNanoseconds;
181 position->position_frames = hidlPosition.positionFrames;
182 }
183 });
184 return processReturn("getMmapPosition", ret, retval);
185}
Mikhail Naganovf558e022016-11-14 17:45:17 -0800186
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800187status_t StreamHalHidl::setHalThreadPriority(int priority) {
188 mHalThreadPriority = priority;
189 return OK;
190}
191
Mikhail Naganov83f04272017-02-07 10:45:09 -0800192bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
193 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
194 return true;
195 }
196 int err = requestPriority(
197 threadPid, threadId,
198 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
199 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
200 mHalThreadPriority, threadPid, threadId, err);
201 // Audio will still work, but latency will be higher and sometimes unacceptable.
202 return err == 0;
203}
204
Mikhail Naganovf558e022016-11-14 17:45:17 -0800205namespace {
206
207/* Notes on callback ownership.
208
209This is how (Hw)Binder ownership model looks like. The server implementation
210is owned by Binder framework (via sp<>). Proxies are owned by clients.
211When the last proxy disappears, Binder framework releases the server impl.
212
213Thus, it is not needed to keep any references to StreamOutCallback (this is
214the server impl) -- it will live as long as HAL server holds a strong ref to
215IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
216from the destructor of StreamOutHalHidl.
217
218The callback only keeps a weak reference to the stream. The stream is owned
219by AudioFlinger.
220
221*/
222
223struct StreamOutCallback : public IStreamOutCallback {
224 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
225
226 // IStreamOutCallback implementation
227 Return<void> onWriteReady() override {
228 sp<StreamOutHalHidl> stream = mStream.promote();
229 if (stream != 0) {
230 stream->onWriteReady();
231 }
232 return Void();
233 }
234
235 Return<void> onDrainReady() override {
236 sp<StreamOutHalHidl> stream = mStream.promote();
237 if (stream != 0) {
238 stream->onDrainReady();
239 }
240 return Void();
241 }
242
243 Return<void> onError() override {
244 sp<StreamOutHalHidl> stream = mStream.promote();
245 if (stream != 0) {
246 stream->onError();
247 }
248 return Void();
249 }
250
251 private:
252 wp<StreamOutHalHidl> mStream;
253};
254
255} // namespace
256
257StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
Mikhail Naganovc8381902017-01-31 13:56:25 -0800258 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800259}
260
261StreamOutHalHidl::~StreamOutHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800262 if (mStream != 0) {
263 if (mCallback.unsafe_get()) {
264 processReturn("clearCallback", mStream->clearCallback());
265 }
266 processReturn("close", mStream->close());
Mikhail Naganov23feba22017-02-23 11:00:55 -0800267 mStream.clear();
Mikhail Naganovf558e022016-11-14 17:45:17 -0800268 }
269 mCallback.clear();
Mikhail Naganov23feba22017-02-23 11:00:55 -0800270 hardware::IPCThreadState::self()->flushCommands();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800271 if (mEfGroup) {
272 EventFlag::deleteEventFlag(&mEfGroup);
273 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800274}
275
276status_t StreamOutHalHidl::getFrameSize(size_t *size) {
277 if (mStream == 0) return NO_INIT;
278 return processReturn("getFrameSize", mStream->getFrameSize(), size);
279}
280
281status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
282 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800283 if (mWriterClient == gettid() && mCommandMQ) {
284 return callWriterThread(
285 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
286 [&](const WriteStatus& writeStatus) {
287 *latency = writeStatus.reply.latencyMs;
288 });
289 } else {
290 return processReturn("getLatency", mStream->getLatency(), latency);
291 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800292}
293
294status_t StreamOutHalHidl::setVolume(float left, float right) {
295 if (mStream == 0) return NO_INIT;
296 return processReturn("setVolume", mStream->setVolume(left, right));
297}
298
299status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
300 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800301 *written = 0;
302
303 if (bytes == 0 && !mDataMQ) {
304 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
305 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
306 return OK;
307 }
308
309 status_t status;
310 if (!mDataMQ && (status = prepareForWriting(bytes)) != OK) {
311 return status;
312 }
313
Mikhail Naganovc8381902017-01-31 13:56:25 -0800314 return callWriterThread(
315 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
316 [&] (const WriteStatus& writeStatus) {
317 *written = writeStatus.reply.written;
318 });
319}
320
321status_t StreamOutHalHidl::callWriterThread(
322 WriteCommand cmd, const char* cmdName,
323 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
324 if (!mCommandMQ->write(&cmd)) {
325 ALOGE("command message queue write failed for \"%s\"", cmdName);
326 return -EAGAIN;
327 }
328 if (data != nullptr) {
329 size_t availableToWrite = mDataMQ->availableToWrite();
330 if (dataSize > availableToWrite) {
331 ALOGW("truncating write data from %d to %d due to insufficient data queue space",
332 (int32_t)dataSize, (int32_t)availableToWrite);
333 dataSize = availableToWrite;
334 }
335 if (!mDataMQ->write(data, dataSize)) {
336 ALOGE("data message queue write failed for \"%s\"", cmdName);
337 }
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800338 }
339 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
340
341 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
342 uint32_t efState = 0;
343retry:
Mikhail Naganovb4e77912017-02-15 10:23:09 -0800344 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800345 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800346 WriteStatus writeStatus;
347 writeStatus.retval = Result::NOT_INITIALIZED;
348 if (!mStatusMQ->read(&writeStatus)) {
349 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800350 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800351 if (writeStatus.retval == Result::OK) {
352 ret = OK;
353 callback(writeStatus);
354 } else {
355 ret = processReturn(cmdName, writeStatus.retval);
356 }
357 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800358 }
Mikhail Naganovd2ae9cd2017-03-03 09:15:01 -0800359 if (ret == -EAGAIN || ret == -EINTR) {
360 // Spurious wakeup. This normally retries no more than once.
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800361 goto retry;
362 }
363 return ret;
364}
365
366status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800367 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800368 std::unique_ptr<DataMQ> tempDataMQ;
369 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800370 Result retval;
Mikhail Naganov83f04272017-02-07 10:45:09 -0800371 pid_t halThreadPid, halThreadTid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800372 Return<void> ret = mStream->prepareForWriting(
Mikhail Naganov83f04272017-02-07 10:45:09 -0800373 1, bufferSize,
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800374 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800375 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800376 const DataMQ::Descriptor& dataMQ,
Mikhail Naganov83f04272017-02-07 10:45:09 -0800377 const StatusMQ::Descriptor& statusMQ,
378 const ThreadInfo& halThreadInfo) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800379 retval = r;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800380 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800381 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800382 tempDataMQ.reset(new DataMQ(dataMQ));
383 tempStatusMQ.reset(new StatusMQ(statusMQ));
384 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
385 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
386 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800387 halThreadPid = halThreadInfo.pid;
388 halThreadTid = halThreadInfo.tid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800389 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800390 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800391 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800392 return processReturn("prepareForWriting", ret, retval);
393 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800394 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
395 !tempDataMQ || !tempDataMQ->isValid() ||
396 !tempStatusMQ || !tempStatusMQ->isValid() ||
397 !mEfGroup) {
398 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
399 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
400 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800401 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
402 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
403 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
404 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
405 "Status message queue for writing is invalid");
406 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
407 return NO_INIT;
408 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800409 requestHalThreadPriority(halThreadPid, halThreadTid);
410
Mikhail Naganovc8381902017-01-31 13:56:25 -0800411 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800412 mDataMQ = std::move(tempDataMQ);
413 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800414 mWriterClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800415 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800416}
417
418status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
419 if (mStream == 0) return NO_INIT;
420 Result retval;
421 Return<void> ret = mStream->getRenderPosition(
422 [&](Result r, uint32_t d) {
423 retval = r;
424 if (retval == Result::OK) {
425 *dspFrames = d;
426 }
427 });
428 return processReturn("getRenderPosition", ret, retval);
429}
430
431status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
432 if (mStream == 0) return NO_INIT;
433 Result retval;
434 Return<void> ret = mStream->getNextWriteTimestamp(
435 [&](Result r, int64_t t) {
436 retval = r;
437 if (retval == Result::OK) {
438 *timestamp = t;
439 }
440 });
441 return processReturn("getRenderPosition", ret, retval);
442}
443
444status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
445 if (mStream == 0) return NO_INIT;
446 status_t status = processReturn(
447 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
448 if (status == OK) {
449 mCallback = callback;
450 }
451 return status;
452}
453
454status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
455 if (mStream == 0) return NO_INIT;
456 Return<void> ret = mStream->supportsPauseAndResume(
457 [&](bool p, bool r) {
458 *supportsPause = p;
459 *supportsResume = r;
460 });
461 return processReturn("supportsPauseAndResume", ret);
462}
463
464status_t StreamOutHalHidl::pause() {
465 if (mStream == 0) return NO_INIT;
466 return processReturn("pause", mStream->pause());
467}
468
469status_t StreamOutHalHidl::resume() {
470 if (mStream == 0) return NO_INIT;
471 return processReturn("pause", mStream->resume());
472}
473
474status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
475 if (mStream == 0) return NO_INIT;
476 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
477}
478
479status_t StreamOutHalHidl::drain(bool earlyNotify) {
480 if (mStream == 0) return NO_INIT;
481 return processReturn(
482 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
483}
484
485status_t StreamOutHalHidl::flush() {
486 if (mStream == 0) return NO_INIT;
487 return processReturn("pause", mStream->flush());
488}
489
490status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
491 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800492 if (mWriterClient == gettid() && mCommandMQ) {
493 return callWriterThread(
494 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
495 [&](const WriteStatus& writeStatus) {
496 *frames = writeStatus.reply.presentationPosition.frames;
497 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
498 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
499 });
500 } else {
501 Result retval;
502 Return<void> ret = mStream->getPresentationPosition(
503 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
504 retval = r;
505 if (retval == Result::OK) {
506 *frames = hidlFrames;
507 timestamp->tv_sec = hidlTimeStamp.tvSec;
508 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
509 }
510 });
511 return processReturn("getPresentationPosition", ret, retval);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800512 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800513}
514
515void StreamOutHalHidl::onWriteReady() {
516 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
517 if (callback == 0) return;
518 ALOGV("asyncCallback onWriteReady");
519 callback->onWriteReady();
520}
521
522void StreamOutHalHidl::onDrainReady() {
523 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
524 if (callback == 0) return;
525 ALOGV("asyncCallback onDrainReady");
526 callback->onDrainReady();
527}
528
529void StreamOutHalHidl::onError() {
530 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
531 if (callback == 0) return;
532 ALOGV("asyncCallback onError");
533 callback->onError();
534}
535
536
537StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
Mikhail Naganovc8381902017-01-31 13:56:25 -0800538 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800539}
540
541StreamInHalHidl::~StreamInHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800542 if (mStream != 0) {
543 processReturn("close", mStream->close());
Mikhail Naganov23feba22017-02-23 11:00:55 -0800544 mStream.clear();
545 hardware::IPCThreadState::self()->flushCommands();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800546 }
547 if (mEfGroup) {
548 EventFlag::deleteEventFlag(&mEfGroup);
549 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800550}
551
552status_t StreamInHalHidl::getFrameSize(size_t *size) {
553 if (mStream == 0) return NO_INIT;
554 return processReturn("getFrameSize", mStream->getFrameSize(), size);
555}
556
557status_t StreamInHalHidl::setGain(float gain) {
558 if (mStream == 0) return NO_INIT;
559 return processReturn("setGain", mStream->setGain(gain));
560}
561
562status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
563 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800564 *read = 0;
565
566 if (bytes == 0 && !mDataMQ) {
567 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
568 return OK;
569 }
570
571 status_t status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800572 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
573 return status;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800574 }
575
Mikhail Naganovc8381902017-01-31 13:56:25 -0800576 ReadParameters params;
577 params.command = ReadCommand::READ;
578 params.params.read = bytes;
579 return callReaderThread(params, "read",
580 [&](const ReadStatus& readStatus) {
581 const size_t availToRead = mDataMQ->availableToRead();
582 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
583 ALOGE("data message queue read failed for \"read\"");
584 }
585 ALOGW_IF(availToRead != readStatus.reply.read,
586 "HAL read report inconsistent: mq = %d, status = %d",
587 (int32_t)availToRead, (int32_t)readStatus.reply.read);
588 *read = readStatus.reply.read;
589 });
590}
591
592status_t StreamInHalHidl::callReaderThread(
593 const ReadParameters& params, const char* cmdName,
594 StreamInHalHidl::ReaderCallback callback) {
595 if (!mCommandMQ->write(&params)) {
596 ALOGW("command message queue write failed");
597 return -EAGAIN;
598 }
599 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
600
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800601 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
602 uint32_t efState = 0;
603retry:
Mikhail Naganovb4e77912017-02-15 10:23:09 -0800604 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800605 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800606 ReadStatus readStatus;
607 readStatus.retval = Result::NOT_INITIALIZED;
608 if (!mStatusMQ->read(&readStatus)) {
609 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800610 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800611 if (readStatus.retval == Result::OK) {
612 ret = OK;
613 callback(readStatus);
614 } else {
615 ret = processReturn(cmdName, readStatus.retval);
616 }
617 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800618 }
Mikhail Naganovd2ae9cd2017-03-03 09:15:01 -0800619 if (ret == -EAGAIN || ret == -EINTR) {
620 // Spurious wakeup. This normally retries no more than once.
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800621 goto retry;
622 }
623 return ret;
624}
625
626status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800627 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800628 std::unique_ptr<DataMQ> tempDataMQ;
629 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800630 Result retval;
Mikhail Naganov83f04272017-02-07 10:45:09 -0800631 pid_t halThreadPid, halThreadTid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800632 Return<void> ret = mStream->prepareForReading(
Mikhail Naganov83f04272017-02-07 10:45:09 -0800633 1, bufferSize,
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800634 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800635 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800636 const DataMQ::Descriptor& dataMQ,
Mikhail Naganov83f04272017-02-07 10:45:09 -0800637 const StatusMQ::Descriptor& statusMQ,
638 const ThreadInfo& halThreadInfo) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800639 retval = r;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800640 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800641 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800642 tempDataMQ.reset(new DataMQ(dataMQ));
643 tempStatusMQ.reset(new StatusMQ(statusMQ));
644 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
645 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
646 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800647 halThreadPid = halThreadInfo.pid;
648 halThreadTid = halThreadInfo.tid;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800649 }
650 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800651 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800652 return processReturn("prepareForReading", ret, retval);
653 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800654 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
655 !tempDataMQ || !tempDataMQ->isValid() ||
656 !tempStatusMQ || !tempStatusMQ->isValid() ||
657 !mEfGroup) {
658 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
659 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
660 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800661 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
662 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
663 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
664 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
665 "Status message queue for reading is invalid");
666 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
667 return NO_INIT;
668 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800669 requestHalThreadPriority(halThreadPid, halThreadTid);
670
Mikhail Naganovc8381902017-01-31 13:56:25 -0800671 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800672 mDataMQ = std::move(tempDataMQ);
673 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800674 mReaderClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800675 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800676}
677
678status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
679 if (mStream == 0) return NO_INIT;
680 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
681}
682
683status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
684 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800685 if (mReaderClient == gettid() && mCommandMQ) {
686 ReadParameters params;
687 params.command = ReadCommand::GET_CAPTURE_POSITION;
688 return callReaderThread(params, "getCapturePosition",
689 [&](const ReadStatus& readStatus) {
690 *frames = readStatus.reply.capturePosition.frames;
691 *time = readStatus.reply.capturePosition.time;
692 });
693 } else {
694 Result retval;
695 Return<void> ret = mStream->getCapturePosition(
696 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
697 retval = r;
698 if (retval == Result::OK) {
699 *frames = hidlFrames;
700 *time = hidlTime;
701 }
702 });
703 return processReturn("getCapturePosition", ret, retval);
704 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800705}
706
707} // namespace android