blob: 176abee88bc46477f9374957d011b9b37841479b [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) {
Andy Hung953608f2017-06-13 15:21:49 -070051
52 // Instrument audio signal power logging.
53 // Note: This assumes channel mask, format, and sample rate do not change after creation.
54 if (mStream != nullptr && mStreamPowerLog.isUserDebugOrEngBuild()) {
55 // Obtain audio properties (see StreamHalHidl::getAudioProperties() below).
56 Return<void> ret = mStream->getAudioProperties(
57 [&](uint32_t sr, AudioChannelMask m, AudioFormat f) {
58 mStreamPowerLog.init(sr,
59 static_cast<audio_channel_mask_t>(m),
60 static_cast<audio_format_t>(f));
61 });
62 }
Mikhail Naganovf558e022016-11-14 17:45:17 -080063}
64
65StreamHalHidl::~StreamHalHidl() {
66 mStream = nullptr;
67}
68
69status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
70 if (!mStream) return NO_INIT;
71 return processReturn("getSampleRate", mStream->getSampleRate(), rate);
72}
73
74status_t StreamHalHidl::getBufferSize(size_t *size) {
75 if (!mStream) return NO_INIT;
76 return processReturn("getBufferSize", mStream->getBufferSize(), size);
77}
78
79status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
80 if (!mStream) return NO_INIT;
81 return processReturn("getChannelMask", mStream->getChannelMask(), mask);
82}
83
84status_t StreamHalHidl::getFormat(audio_format_t *format) {
85 if (!mStream) return NO_INIT;
86 return processReturn("getFormat", mStream->getFormat(), format);
87}
88
89status_t StreamHalHidl::getAudioProperties(
90 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
91 if (!mStream) return NO_INIT;
92 Return<void> ret = mStream->getAudioProperties(
93 [&](uint32_t sr, AudioChannelMask m, AudioFormat f) {
94 *sampleRate = sr;
95 *mask = static_cast<audio_channel_mask_t>(m);
96 *format = static_cast<audio_format_t>(f);
97 });
98 return processReturn("getAudioProperties", ret);
99}
100
101status_t StreamHalHidl::setParameters(const String8& kvPairs) {
102 if (!mStream) return NO_INIT;
103 hidl_vec<ParameterValue> hidlParams;
104 status_t status = parametersFromHal(kvPairs, &hidlParams);
105 if (status != OK) return status;
106 return processReturn("setParameters", mStream->setParameters(hidlParams));
107}
108
109status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
110 values->clear();
111 if (!mStream) return NO_INIT;
112 hidl_vec<hidl_string> hidlKeys;
113 status_t status = keysFromHal(keys, &hidlKeys);
114 if (status != OK) return status;
115 Result retval;
116 Return<void> ret = mStream->getParameters(
117 hidlKeys,
118 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
119 retval = r;
120 if (retval == Result::OK) {
121 parametersToHal(parameters, values);
122 }
123 });
124 return processReturn("getParameters", ret, retval);
125}
126
127status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
128 if (!mStream) return NO_INIT;
129 return processReturn("addEffect", mStream->addEffect(
130 static_cast<EffectHalHidl*>(effect.get())->effectId()));
131}
132
133status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
134 if (!mStream) return NO_INIT;
135 return processReturn("removeEffect", mStream->removeEffect(
136 static_cast<EffectHalHidl*>(effect.get())->effectId()));
137}
138
139status_t StreamHalHidl::standby() {
140 if (!mStream) return NO_INIT;
141 return processReturn("standby", mStream->standby());
142}
143
144status_t StreamHalHidl::dump(int fd) {
145 if (!mStream) return NO_INIT;
146 native_handle_t* hidlHandle = native_handle_create(1, 0);
147 hidlHandle->data[0] = fd;
148 Return<void> ret = mStream->debugDump(hidlHandle);
149 native_handle_delete(hidlHandle);
Andy Hung953608f2017-06-13 15:21:49 -0700150 mStreamPowerLog.dump(fd);
Mikhail Naganovf558e022016-11-14 17:45:17 -0800151 return processReturn("dump", ret);
152}
153
Eric Laurentaf35aad2016-12-15 14:25:36 -0800154status_t StreamHalHidl::start() {
155 if (!mStream) return NO_INIT;
156 return processReturn("start", mStream->start());
157}
158
159status_t StreamHalHidl::stop() {
160 if (!mStream) return NO_INIT;
161 return processReturn("stop", mStream->stop());
162}
163
164status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
165 struct audio_mmap_buffer_info *info) {
166 Result retval;
167 Return<void> ret = mStream->createMmapBuffer(
168 minSizeFrames,
169 [&](Result r, const MmapBufferInfo& hidlInfo) {
170 retval = r;
171 if (retval == Result::OK) {
Eric Laurentb8753072016-12-21 12:04:10 -0800172 const native_handle *handle = hidlInfo.sharedMemory.handle();
Eric Laurentaf35aad2016-12-15 14:25:36 -0800173 if (handle->numFds > 0) {
Eric Laurent3a85e562017-05-11 18:08:51 -0700174 info->shared_memory_fd = handle->data[0];
Eric Laurentaf35aad2016-12-15 14:25:36 -0800175 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
176 info->burst_size_frames = hidlInfo.burstSizeFrames;
177 // info->shared_memory_address is not needed in HIDL context
178 info->shared_memory_address = NULL;
179 } else {
180 retval = Result::NOT_INITIALIZED;
181 }
182 }
183 });
184 return processReturn("createMmapBuffer", ret, retval);
185}
186
187status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
188 Result retval;
189 Return<void> ret = mStream->getMmapPosition(
190 [&](Result r, const MmapPosition& hidlPosition) {
191 retval = r;
192 if (retval == Result::OK) {
193 position->time_nanoseconds = hidlPosition.timeNanoseconds;
194 position->position_frames = hidlPosition.positionFrames;
195 }
196 });
197 return processReturn("getMmapPosition", ret, retval);
198}
Mikhail Naganovf558e022016-11-14 17:45:17 -0800199
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800200status_t StreamHalHidl::setHalThreadPriority(int priority) {
201 mHalThreadPriority = priority;
202 return OK;
203}
204
Mikhail Naganov83f04272017-02-07 10:45:09 -0800205bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
206 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
207 return true;
208 }
209 int err = requestPriority(
210 threadPid, threadId,
211 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
212 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
213 mHalThreadPriority, threadPid, threadId, err);
214 // Audio will still work, but latency will be higher and sometimes unacceptable.
215 return err == 0;
216}
217
Mikhail Naganovf558e022016-11-14 17:45:17 -0800218namespace {
219
220/* Notes on callback ownership.
221
222This is how (Hw)Binder ownership model looks like. The server implementation
223is owned by Binder framework (via sp<>). Proxies are owned by clients.
224When the last proxy disappears, Binder framework releases the server impl.
225
226Thus, it is not needed to keep any references to StreamOutCallback (this is
227the server impl) -- it will live as long as HAL server holds a strong ref to
228IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
229from the destructor of StreamOutHalHidl.
230
231The callback only keeps a weak reference to the stream. The stream is owned
232by AudioFlinger.
233
234*/
235
236struct StreamOutCallback : public IStreamOutCallback {
237 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
238
239 // IStreamOutCallback implementation
240 Return<void> onWriteReady() override {
241 sp<StreamOutHalHidl> stream = mStream.promote();
242 if (stream != 0) {
243 stream->onWriteReady();
244 }
245 return Void();
246 }
247
248 Return<void> onDrainReady() override {
249 sp<StreamOutHalHidl> stream = mStream.promote();
250 if (stream != 0) {
251 stream->onDrainReady();
252 }
253 return Void();
254 }
255
256 Return<void> onError() override {
257 sp<StreamOutHalHidl> stream = mStream.promote();
258 if (stream != 0) {
259 stream->onError();
260 }
261 return Void();
262 }
263
264 private:
265 wp<StreamOutHalHidl> mStream;
266};
267
268} // namespace
269
270StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
Mikhail Naganovc8381902017-01-31 13:56:25 -0800271 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800272}
273
274StreamOutHalHidl::~StreamOutHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800275 if (mStream != 0) {
276 if (mCallback.unsafe_get()) {
277 processReturn("clearCallback", mStream->clearCallback());
278 }
279 processReturn("close", mStream->close());
Mikhail Naganov23feba22017-02-23 11:00:55 -0800280 mStream.clear();
Mikhail Naganovf558e022016-11-14 17:45:17 -0800281 }
282 mCallback.clear();
Mikhail Naganov23feba22017-02-23 11:00:55 -0800283 hardware::IPCThreadState::self()->flushCommands();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800284 if (mEfGroup) {
285 EventFlag::deleteEventFlag(&mEfGroup);
286 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800287}
288
289status_t StreamOutHalHidl::getFrameSize(size_t *size) {
290 if (mStream == 0) return NO_INIT;
291 return processReturn("getFrameSize", mStream->getFrameSize(), size);
292}
293
294status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
295 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800296 if (mWriterClient == gettid() && mCommandMQ) {
297 return callWriterThread(
298 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
299 [&](const WriteStatus& writeStatus) {
300 *latency = writeStatus.reply.latencyMs;
301 });
302 } else {
303 return processReturn("getLatency", mStream->getLatency(), latency);
304 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800305}
306
307status_t StreamOutHalHidl::setVolume(float left, float right) {
308 if (mStream == 0) return NO_INIT;
309 return processReturn("setVolume", mStream->setVolume(left, right));
310}
311
312status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
313 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800314 *written = 0;
315
316 if (bytes == 0 && !mDataMQ) {
317 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
318 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
319 return OK;
320 }
321
322 status_t status;
323 if (!mDataMQ && (status = prepareForWriting(bytes)) != OK) {
324 return status;
325 }
326
Andy Hung953608f2017-06-13 15:21:49 -0700327 status = callWriterThread(
Mikhail Naganovc8381902017-01-31 13:56:25 -0800328 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
329 [&] (const WriteStatus& writeStatus) {
330 *written = writeStatus.reply.written;
Mikhail Naganovd15f1272017-02-28 09:10:43 -0800331 // Diagnostics of the cause of b/35813113.
332 ALOGE_IF(*written > bytes,
333 "hal reports more bytes written than asked for: %lld > %lld",
334 (long long)*written, (long long)bytes);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800335 });
Andy Hung953608f2017-06-13 15:21:49 -0700336 mStreamPowerLog.log(buffer, *written);
337 return status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800338}
339
340status_t StreamOutHalHidl::callWriterThread(
341 WriteCommand cmd, const char* cmdName,
342 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
343 if (!mCommandMQ->write(&cmd)) {
344 ALOGE("command message queue write failed for \"%s\"", cmdName);
345 return -EAGAIN;
346 }
347 if (data != nullptr) {
348 size_t availableToWrite = mDataMQ->availableToWrite();
349 if (dataSize > availableToWrite) {
Mikhail Naganovd15f1272017-02-28 09:10:43 -0800350 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
351 (long long)dataSize, (long long)availableToWrite);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800352 dataSize = availableToWrite;
353 }
354 if (!mDataMQ->write(data, dataSize)) {
355 ALOGE("data message queue write failed for \"%s\"", cmdName);
356 }
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800357 }
358 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
359
360 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
361 uint32_t efState = 0;
362retry:
Mikhail Naganovb4e77912017-02-15 10:23:09 -0800363 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800364 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800365 WriteStatus writeStatus;
366 writeStatus.retval = Result::NOT_INITIALIZED;
367 if (!mStatusMQ->read(&writeStatus)) {
368 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800369 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800370 if (writeStatus.retval == Result::OK) {
371 ret = OK;
372 callback(writeStatus);
373 } else {
374 ret = processReturn(cmdName, writeStatus.retval);
375 }
376 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800377 }
Mikhail Naganovd2ae9cd2017-03-03 09:15:01 -0800378 if (ret == -EAGAIN || ret == -EINTR) {
379 // Spurious wakeup. This normally retries no more than once.
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800380 goto retry;
381 }
382 return ret;
383}
384
385status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800386 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800387 std::unique_ptr<DataMQ> tempDataMQ;
388 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800389 Result retval;
Mikhail Naganov83f04272017-02-07 10:45:09 -0800390 pid_t halThreadPid, halThreadTid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800391 Return<void> ret = mStream->prepareForWriting(
Mikhail Naganov83f04272017-02-07 10:45:09 -0800392 1, bufferSize,
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800393 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800394 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800395 const DataMQ::Descriptor& dataMQ,
Mikhail Naganov83f04272017-02-07 10:45:09 -0800396 const StatusMQ::Descriptor& statusMQ,
397 const ThreadInfo& halThreadInfo) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800398 retval = r;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800399 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800400 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800401 tempDataMQ.reset(new DataMQ(dataMQ));
402 tempStatusMQ.reset(new StatusMQ(statusMQ));
403 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
404 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
405 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800406 halThreadPid = halThreadInfo.pid;
407 halThreadTid = halThreadInfo.tid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800408 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800409 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800410 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800411 return processReturn("prepareForWriting", ret, retval);
412 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800413 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
414 !tempDataMQ || !tempDataMQ->isValid() ||
415 !tempStatusMQ || !tempStatusMQ->isValid() ||
416 !mEfGroup) {
417 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
418 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
419 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800420 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
421 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
422 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
423 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
424 "Status message queue for writing is invalid");
425 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
426 return NO_INIT;
427 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800428 requestHalThreadPriority(halThreadPid, halThreadTid);
429
Mikhail Naganovc8381902017-01-31 13:56:25 -0800430 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800431 mDataMQ = std::move(tempDataMQ);
432 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800433 mWriterClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800434 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800435}
436
437status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
438 if (mStream == 0) return NO_INIT;
439 Result retval;
440 Return<void> ret = mStream->getRenderPosition(
441 [&](Result r, uint32_t d) {
442 retval = r;
443 if (retval == Result::OK) {
444 *dspFrames = d;
445 }
446 });
447 return processReturn("getRenderPosition", ret, retval);
448}
449
450status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
451 if (mStream == 0) return NO_INIT;
452 Result retval;
453 Return<void> ret = mStream->getNextWriteTimestamp(
454 [&](Result r, int64_t t) {
455 retval = r;
456 if (retval == Result::OK) {
457 *timestamp = t;
458 }
459 });
460 return processReturn("getRenderPosition", ret, retval);
461}
462
463status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
464 if (mStream == 0) return NO_INIT;
465 status_t status = processReturn(
466 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
467 if (status == OK) {
468 mCallback = callback;
469 }
470 return status;
471}
472
473status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
474 if (mStream == 0) return NO_INIT;
475 Return<void> ret = mStream->supportsPauseAndResume(
476 [&](bool p, bool r) {
477 *supportsPause = p;
478 *supportsResume = r;
479 });
480 return processReturn("supportsPauseAndResume", ret);
481}
482
483status_t StreamOutHalHidl::pause() {
484 if (mStream == 0) return NO_INIT;
485 return processReturn("pause", mStream->pause());
486}
487
488status_t StreamOutHalHidl::resume() {
489 if (mStream == 0) return NO_INIT;
490 return processReturn("pause", mStream->resume());
491}
492
493status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
494 if (mStream == 0) return NO_INIT;
495 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
496}
497
498status_t StreamOutHalHidl::drain(bool earlyNotify) {
499 if (mStream == 0) return NO_INIT;
500 return processReturn(
501 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
502}
503
504status_t StreamOutHalHidl::flush() {
505 if (mStream == 0) return NO_INIT;
506 return processReturn("pause", mStream->flush());
507}
508
509status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
510 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800511 if (mWriterClient == gettid() && mCommandMQ) {
512 return callWriterThread(
513 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
514 [&](const WriteStatus& writeStatus) {
515 *frames = writeStatus.reply.presentationPosition.frames;
516 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
517 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
518 });
519 } else {
520 Result retval;
521 Return<void> ret = mStream->getPresentationPosition(
522 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
523 retval = r;
524 if (retval == Result::OK) {
525 *frames = hidlFrames;
526 timestamp->tv_sec = hidlTimeStamp.tvSec;
527 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
528 }
529 });
530 return processReturn("getPresentationPosition", ret, retval);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800531 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800532}
533
534void StreamOutHalHidl::onWriteReady() {
535 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
536 if (callback == 0) return;
537 ALOGV("asyncCallback onWriteReady");
538 callback->onWriteReady();
539}
540
541void StreamOutHalHidl::onDrainReady() {
542 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
543 if (callback == 0) return;
544 ALOGV("asyncCallback onDrainReady");
545 callback->onDrainReady();
546}
547
548void StreamOutHalHidl::onError() {
549 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
550 if (callback == 0) return;
551 ALOGV("asyncCallback onError");
552 callback->onError();
553}
554
555
556StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
Mikhail Naganovc8381902017-01-31 13:56:25 -0800557 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800558}
559
560StreamInHalHidl::~StreamInHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800561 if (mStream != 0) {
562 processReturn("close", mStream->close());
Mikhail Naganov23feba22017-02-23 11:00:55 -0800563 mStream.clear();
564 hardware::IPCThreadState::self()->flushCommands();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800565 }
566 if (mEfGroup) {
567 EventFlag::deleteEventFlag(&mEfGroup);
568 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800569}
570
571status_t StreamInHalHidl::getFrameSize(size_t *size) {
572 if (mStream == 0) return NO_INIT;
573 return processReturn("getFrameSize", mStream->getFrameSize(), size);
574}
575
576status_t StreamInHalHidl::setGain(float gain) {
577 if (mStream == 0) return NO_INIT;
578 return processReturn("setGain", mStream->setGain(gain));
579}
580
581status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
582 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800583 *read = 0;
584
585 if (bytes == 0 && !mDataMQ) {
586 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
587 return OK;
588 }
589
590 status_t status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800591 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
592 return status;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800593 }
594
Mikhail Naganovc8381902017-01-31 13:56:25 -0800595 ReadParameters params;
596 params.command = ReadCommand::READ;
597 params.params.read = bytes;
Andy Hung953608f2017-06-13 15:21:49 -0700598 status = callReaderThread(params, "read",
Mikhail Naganovc8381902017-01-31 13:56:25 -0800599 [&](const ReadStatus& readStatus) {
600 const size_t availToRead = mDataMQ->availableToRead();
601 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
602 ALOGE("data message queue read failed for \"read\"");
603 }
604 ALOGW_IF(availToRead != readStatus.reply.read,
605 "HAL read report inconsistent: mq = %d, status = %d",
606 (int32_t)availToRead, (int32_t)readStatus.reply.read);
607 *read = readStatus.reply.read;
608 });
Andy Hung953608f2017-06-13 15:21:49 -0700609 mStreamPowerLog.log(buffer, *read);
610 return status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800611}
612
613status_t StreamInHalHidl::callReaderThread(
614 const ReadParameters& params, const char* cmdName,
615 StreamInHalHidl::ReaderCallback callback) {
616 if (!mCommandMQ->write(&params)) {
617 ALOGW("command message queue write failed");
618 return -EAGAIN;
619 }
620 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
621
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800622 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
623 uint32_t efState = 0;
624retry:
Mikhail Naganovb4e77912017-02-15 10:23:09 -0800625 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800626 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800627 ReadStatus readStatus;
628 readStatus.retval = Result::NOT_INITIALIZED;
629 if (!mStatusMQ->read(&readStatus)) {
630 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800631 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800632 if (readStatus.retval == Result::OK) {
633 ret = OK;
634 callback(readStatus);
635 } else {
636 ret = processReturn(cmdName, readStatus.retval);
637 }
638 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800639 }
Mikhail Naganovd2ae9cd2017-03-03 09:15:01 -0800640 if (ret == -EAGAIN || ret == -EINTR) {
641 // Spurious wakeup. This normally retries no more than once.
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800642 goto retry;
643 }
644 return ret;
645}
646
647status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800648 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800649 std::unique_ptr<DataMQ> tempDataMQ;
650 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800651 Result retval;
Mikhail Naganov83f04272017-02-07 10:45:09 -0800652 pid_t halThreadPid, halThreadTid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800653 Return<void> ret = mStream->prepareForReading(
Mikhail Naganov83f04272017-02-07 10:45:09 -0800654 1, bufferSize,
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800655 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800656 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800657 const DataMQ::Descriptor& dataMQ,
Mikhail Naganov83f04272017-02-07 10:45:09 -0800658 const StatusMQ::Descriptor& statusMQ,
659 const ThreadInfo& halThreadInfo) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800660 retval = r;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800661 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800662 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800663 tempDataMQ.reset(new DataMQ(dataMQ));
664 tempStatusMQ.reset(new StatusMQ(statusMQ));
665 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
666 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
667 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800668 halThreadPid = halThreadInfo.pid;
669 halThreadTid = halThreadInfo.tid;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800670 }
671 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800672 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800673 return processReturn("prepareForReading", ret, retval);
674 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800675 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
676 !tempDataMQ || !tempDataMQ->isValid() ||
677 !tempStatusMQ || !tempStatusMQ->isValid() ||
678 !mEfGroup) {
679 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
680 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
681 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800682 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
683 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
684 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
685 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
686 "Status message queue for reading is invalid");
687 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
688 return NO_INIT;
689 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800690 requestHalThreadPriority(halThreadPid, halThreadTid);
691
Mikhail Naganovc8381902017-01-31 13:56:25 -0800692 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800693 mDataMQ = std::move(tempDataMQ);
694 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800695 mReaderClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800696 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800697}
698
699status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
700 if (mStream == 0) return NO_INIT;
701 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
702}
703
704status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
705 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800706 if (mReaderClient == gettid() && mCommandMQ) {
707 ReadParameters params;
708 params.command = ReadCommand::GET_CAPTURE_POSITION;
709 return callReaderThread(params, "getCapturePosition",
710 [&](const ReadStatus& readStatus) {
711 *frames = readStatus.reply.capturePosition.frames;
712 *time = readStatus.reply.capturePosition.time;
713 });
714 } else {
715 Result retval;
716 Return<void> ret = mStream->getCapturePosition(
717 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
718 retval = r;
719 if (retval == Result::OK) {
720 *frames = hidlFrames;
721 *time = hidlTime;
722 }
723 });
724 return processReturn("getCapturePosition", ret, retval);
725 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800726}
727
728} // namespace android