blob: 5b06b734613bdc020c6f0d16aff7201c238450a8 [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;
Mikhail Naganovd15f1272017-02-28 09:10:43 -0800318 // Diagnostics of the cause of b/35813113.
319 ALOGE_IF(*written > bytes,
320 "hal reports more bytes written than asked for: %lld > %lld",
321 (long long)*written, (long long)bytes);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800322 });
323}
324
325status_t StreamOutHalHidl::callWriterThread(
326 WriteCommand cmd, const char* cmdName,
327 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
328 if (!mCommandMQ->write(&cmd)) {
329 ALOGE("command message queue write failed for \"%s\"", cmdName);
330 return -EAGAIN;
331 }
332 if (data != nullptr) {
333 size_t availableToWrite = mDataMQ->availableToWrite();
334 if (dataSize > availableToWrite) {
Mikhail Naganovd15f1272017-02-28 09:10:43 -0800335 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
336 (long long)dataSize, (long long)availableToWrite);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800337 dataSize = availableToWrite;
338 }
339 if (!mDataMQ->write(data, dataSize)) {
340 ALOGE("data message queue write failed for \"%s\"", cmdName);
341 }
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800342 }
343 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
344
345 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
346 uint32_t efState = 0;
347retry:
Mikhail Naganovb4e77912017-02-15 10:23:09 -0800348 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800349 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800350 WriteStatus writeStatus;
351 writeStatus.retval = Result::NOT_INITIALIZED;
352 if (!mStatusMQ->read(&writeStatus)) {
353 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800354 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800355 if (writeStatus.retval == Result::OK) {
356 ret = OK;
357 callback(writeStatus);
358 } else {
359 ret = processReturn(cmdName, writeStatus.retval);
360 }
361 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800362 }
Mikhail Naganovd2ae9cd2017-03-03 09:15:01 -0800363 if (ret == -EAGAIN || ret == -EINTR) {
364 // Spurious wakeup. This normally retries no more than once.
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800365 goto retry;
366 }
367 return ret;
368}
369
370status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800371 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800372 std::unique_ptr<DataMQ> tempDataMQ;
373 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800374 Result retval;
Mikhail Naganov83f04272017-02-07 10:45:09 -0800375 pid_t halThreadPid, halThreadTid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800376 Return<void> ret = mStream->prepareForWriting(
Mikhail Naganov83f04272017-02-07 10:45:09 -0800377 1, bufferSize,
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800378 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800379 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800380 const DataMQ::Descriptor& dataMQ,
Mikhail Naganov83f04272017-02-07 10:45:09 -0800381 const StatusMQ::Descriptor& statusMQ,
382 const ThreadInfo& halThreadInfo) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800383 retval = r;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800384 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800385 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800386 tempDataMQ.reset(new DataMQ(dataMQ));
387 tempStatusMQ.reset(new StatusMQ(statusMQ));
388 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
389 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
390 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800391 halThreadPid = halThreadInfo.pid;
392 halThreadTid = halThreadInfo.tid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800393 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800394 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800395 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800396 return processReturn("prepareForWriting", ret, retval);
397 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800398 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
399 !tempDataMQ || !tempDataMQ->isValid() ||
400 !tempStatusMQ || !tempStatusMQ->isValid() ||
401 !mEfGroup) {
402 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
403 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
404 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800405 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
406 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
407 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
408 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
409 "Status message queue for writing is invalid");
410 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
411 return NO_INIT;
412 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800413 requestHalThreadPriority(halThreadPid, halThreadTid);
414
Mikhail Naganovc8381902017-01-31 13:56:25 -0800415 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800416 mDataMQ = std::move(tempDataMQ);
417 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800418 mWriterClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800419 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800420}
421
422status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
423 if (mStream == 0) return NO_INIT;
424 Result retval;
425 Return<void> ret = mStream->getRenderPosition(
426 [&](Result r, uint32_t d) {
427 retval = r;
428 if (retval == Result::OK) {
429 *dspFrames = d;
430 }
431 });
432 return processReturn("getRenderPosition", ret, retval);
433}
434
435status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
436 if (mStream == 0) return NO_INIT;
437 Result retval;
438 Return<void> ret = mStream->getNextWriteTimestamp(
439 [&](Result r, int64_t t) {
440 retval = r;
441 if (retval == Result::OK) {
442 *timestamp = t;
443 }
444 });
445 return processReturn("getRenderPosition", ret, retval);
446}
447
448status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
449 if (mStream == 0) return NO_INIT;
450 status_t status = processReturn(
451 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
452 if (status == OK) {
453 mCallback = callback;
454 }
455 return status;
456}
457
458status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
459 if (mStream == 0) return NO_INIT;
460 Return<void> ret = mStream->supportsPauseAndResume(
461 [&](bool p, bool r) {
462 *supportsPause = p;
463 *supportsResume = r;
464 });
465 return processReturn("supportsPauseAndResume", ret);
466}
467
468status_t StreamOutHalHidl::pause() {
469 if (mStream == 0) return NO_INIT;
470 return processReturn("pause", mStream->pause());
471}
472
473status_t StreamOutHalHidl::resume() {
474 if (mStream == 0) return NO_INIT;
475 return processReturn("pause", mStream->resume());
476}
477
478status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
479 if (mStream == 0) return NO_INIT;
480 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
481}
482
483status_t StreamOutHalHidl::drain(bool earlyNotify) {
484 if (mStream == 0) return NO_INIT;
485 return processReturn(
486 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
487}
488
489status_t StreamOutHalHidl::flush() {
490 if (mStream == 0) return NO_INIT;
491 return processReturn("pause", mStream->flush());
492}
493
494status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
495 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800496 if (mWriterClient == gettid() && mCommandMQ) {
497 return callWriterThread(
498 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
499 [&](const WriteStatus& writeStatus) {
500 *frames = writeStatus.reply.presentationPosition.frames;
501 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
502 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
503 });
504 } else {
505 Result retval;
506 Return<void> ret = mStream->getPresentationPosition(
507 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
508 retval = r;
509 if (retval == Result::OK) {
510 *frames = hidlFrames;
511 timestamp->tv_sec = hidlTimeStamp.tvSec;
512 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
513 }
514 });
515 return processReturn("getPresentationPosition", ret, retval);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800516 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800517}
518
519void StreamOutHalHidl::onWriteReady() {
520 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
521 if (callback == 0) return;
522 ALOGV("asyncCallback onWriteReady");
523 callback->onWriteReady();
524}
525
526void StreamOutHalHidl::onDrainReady() {
527 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
528 if (callback == 0) return;
529 ALOGV("asyncCallback onDrainReady");
530 callback->onDrainReady();
531}
532
533void StreamOutHalHidl::onError() {
534 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
535 if (callback == 0) return;
536 ALOGV("asyncCallback onError");
537 callback->onError();
538}
539
540
541StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
Mikhail Naganovc8381902017-01-31 13:56:25 -0800542 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800543}
544
545StreamInHalHidl::~StreamInHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800546 if (mStream != 0) {
547 processReturn("close", mStream->close());
Mikhail Naganov23feba22017-02-23 11:00:55 -0800548 mStream.clear();
549 hardware::IPCThreadState::self()->flushCommands();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800550 }
551 if (mEfGroup) {
552 EventFlag::deleteEventFlag(&mEfGroup);
553 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800554}
555
556status_t StreamInHalHidl::getFrameSize(size_t *size) {
557 if (mStream == 0) return NO_INIT;
558 return processReturn("getFrameSize", mStream->getFrameSize(), size);
559}
560
561status_t StreamInHalHidl::setGain(float gain) {
562 if (mStream == 0) return NO_INIT;
563 return processReturn("setGain", mStream->setGain(gain));
564}
565
566status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
567 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800568 *read = 0;
569
570 if (bytes == 0 && !mDataMQ) {
571 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
572 return OK;
573 }
574
575 status_t status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800576 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
577 return status;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800578 }
579
Mikhail Naganovc8381902017-01-31 13:56:25 -0800580 ReadParameters params;
581 params.command = ReadCommand::READ;
582 params.params.read = bytes;
583 return callReaderThread(params, "read",
584 [&](const ReadStatus& readStatus) {
585 const size_t availToRead = mDataMQ->availableToRead();
586 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
587 ALOGE("data message queue read failed for \"read\"");
588 }
589 ALOGW_IF(availToRead != readStatus.reply.read,
590 "HAL read report inconsistent: mq = %d, status = %d",
591 (int32_t)availToRead, (int32_t)readStatus.reply.read);
592 *read = readStatus.reply.read;
593 });
594}
595
596status_t StreamInHalHidl::callReaderThread(
597 const ReadParameters& params, const char* cmdName,
598 StreamInHalHidl::ReaderCallback callback) {
599 if (!mCommandMQ->write(&params)) {
600 ALOGW("command message queue write failed");
601 return -EAGAIN;
602 }
603 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
604
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800605 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
606 uint32_t efState = 0;
607retry:
Mikhail Naganovb4e77912017-02-15 10:23:09 -0800608 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800609 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800610 ReadStatus readStatus;
611 readStatus.retval = Result::NOT_INITIALIZED;
612 if (!mStatusMQ->read(&readStatus)) {
613 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800614 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800615 if (readStatus.retval == Result::OK) {
616 ret = OK;
617 callback(readStatus);
618 } else {
619 ret = processReturn(cmdName, readStatus.retval);
620 }
621 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800622 }
Mikhail Naganovd2ae9cd2017-03-03 09:15:01 -0800623 if (ret == -EAGAIN || ret == -EINTR) {
624 // Spurious wakeup. This normally retries no more than once.
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800625 goto retry;
626 }
627 return ret;
628}
629
630status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800631 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800632 std::unique_ptr<DataMQ> tempDataMQ;
633 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800634 Result retval;
Mikhail Naganov83f04272017-02-07 10:45:09 -0800635 pid_t halThreadPid, halThreadTid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800636 Return<void> ret = mStream->prepareForReading(
Mikhail Naganov83f04272017-02-07 10:45:09 -0800637 1, bufferSize,
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800638 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800639 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800640 const DataMQ::Descriptor& dataMQ,
Mikhail Naganov83f04272017-02-07 10:45:09 -0800641 const StatusMQ::Descriptor& statusMQ,
642 const ThreadInfo& halThreadInfo) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800643 retval = r;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800644 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800645 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800646 tempDataMQ.reset(new DataMQ(dataMQ));
647 tempStatusMQ.reset(new StatusMQ(statusMQ));
648 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
649 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
650 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800651 halThreadPid = halThreadInfo.pid;
652 halThreadTid = halThreadInfo.tid;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800653 }
654 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800655 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800656 return processReturn("prepareForReading", ret, retval);
657 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800658 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
659 !tempDataMQ || !tempDataMQ->isValid() ||
660 !tempStatusMQ || !tempStatusMQ->isValid() ||
661 !mEfGroup) {
662 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
663 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
664 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800665 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
666 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
667 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
668 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
669 "Status message queue for reading is invalid");
670 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
671 return NO_INIT;
672 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800673 requestHalThreadPriority(halThreadPid, halThreadTid);
674
Mikhail Naganovc8381902017-01-31 13:56:25 -0800675 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800676 mDataMQ = std::move(tempDataMQ);
677 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800678 mReaderClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800679 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800680}
681
682status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
683 if (mStream == 0) return NO_INIT;
684 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
685}
686
687status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
688 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800689 if (mReaderClient == gettid() && mCommandMQ) {
690 ReadParameters params;
691 params.command = ReadCommand::GET_CAPTURE_POSITION;
692 return callReaderThread(params, "getCapturePosition",
693 [&](const ReadStatus& readStatus) {
694 *frames = readStatus.reply.capturePosition.frames;
695 *time = readStatus.reply.capturePosition.time;
696 });
697 } else {
698 Result retval;
699 Return<void> ret = mStream->getCapturePosition(
700 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
701 retval = r;
702 if (retval == Result::OK) {
703 *frames = hidlFrames;
704 *time = hidlTime;
705 }
706 });
707 return processReturn("getCapturePosition", ret, retval);
708 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800709}
710
711} // namespace android