blob: 22cbd4580f3f4178c4c3596d54c9738c9f3e7e3b [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),
Mikhail Naganov10fd0562017-08-01 17:20:24 -070050 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
51 mCachedBufferSize(0){
Andy Hung953608f2017-06-13 15:21:49 -070052
53 // Instrument audio signal power logging.
54 // Note: This assumes channel mask, format, and sample rate do not change after creation.
55 if (mStream != nullptr && mStreamPowerLog.isUserDebugOrEngBuild()) {
56 // Obtain audio properties (see StreamHalHidl::getAudioProperties() below).
57 Return<void> ret = mStream->getAudioProperties(
58 [&](uint32_t sr, AudioChannelMask m, AudioFormat f) {
59 mStreamPowerLog.init(sr,
60 static_cast<audio_channel_mask_t>(m),
61 static_cast<audio_format_t>(f));
62 });
63 }
Mikhail Naganovf558e022016-11-14 17:45:17 -080064}
65
66StreamHalHidl::~StreamHalHidl() {
67 mStream = nullptr;
68}
69
70status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
71 if (!mStream) return NO_INIT;
72 return processReturn("getSampleRate", mStream->getSampleRate(), rate);
73}
74
75status_t StreamHalHidl::getBufferSize(size_t *size) {
76 if (!mStream) return NO_INIT;
Mikhail Naganov10fd0562017-08-01 17:20:24 -070077 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
78 if (status == OK) {
79 mCachedBufferSize = *size;
80 }
81 return status;
Mikhail Naganovf558e022016-11-14 17:45:17 -080082}
83
84status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
85 if (!mStream) return NO_INIT;
86 return processReturn("getChannelMask", mStream->getChannelMask(), mask);
87}
88
89status_t StreamHalHidl::getFormat(audio_format_t *format) {
90 if (!mStream) return NO_INIT;
91 return processReturn("getFormat", mStream->getFormat(), format);
92}
93
94status_t StreamHalHidl::getAudioProperties(
95 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
96 if (!mStream) return NO_INIT;
97 Return<void> ret = mStream->getAudioProperties(
98 [&](uint32_t sr, AudioChannelMask m, AudioFormat f) {
99 *sampleRate = sr;
100 *mask = static_cast<audio_channel_mask_t>(m);
101 *format = static_cast<audio_format_t>(f);
102 });
103 return processReturn("getAudioProperties", ret);
104}
105
106status_t StreamHalHidl::setParameters(const String8& kvPairs) {
107 if (!mStream) return NO_INIT;
108 hidl_vec<ParameterValue> hidlParams;
109 status_t status = parametersFromHal(kvPairs, &hidlParams);
110 if (status != OK) return status;
111 return processReturn("setParameters", mStream->setParameters(hidlParams));
112}
113
114status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
115 values->clear();
116 if (!mStream) return NO_INIT;
117 hidl_vec<hidl_string> hidlKeys;
118 status_t status = keysFromHal(keys, &hidlKeys);
119 if (status != OK) return status;
120 Result retval;
121 Return<void> ret = mStream->getParameters(
122 hidlKeys,
123 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
124 retval = r;
125 if (retval == Result::OK) {
126 parametersToHal(parameters, values);
127 }
128 });
129 return processReturn("getParameters", ret, retval);
130}
131
132status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
133 if (!mStream) return NO_INIT;
134 return processReturn("addEffect", mStream->addEffect(
135 static_cast<EffectHalHidl*>(effect.get())->effectId()));
136}
137
138status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
139 if (!mStream) return NO_INIT;
140 return processReturn("removeEffect", mStream->removeEffect(
141 static_cast<EffectHalHidl*>(effect.get())->effectId()));
142}
143
144status_t StreamHalHidl::standby() {
145 if (!mStream) return NO_INIT;
146 return processReturn("standby", mStream->standby());
147}
148
149status_t StreamHalHidl::dump(int fd) {
150 if (!mStream) return NO_INIT;
151 native_handle_t* hidlHandle = native_handle_create(1, 0);
152 hidlHandle->data[0] = fd;
153 Return<void> ret = mStream->debugDump(hidlHandle);
154 native_handle_delete(hidlHandle);
Andy Hung953608f2017-06-13 15:21:49 -0700155 mStreamPowerLog.dump(fd);
Mikhail Naganovf558e022016-11-14 17:45:17 -0800156 return processReturn("dump", ret);
157}
158
Eric Laurentaf35aad2016-12-15 14:25:36 -0800159status_t StreamHalHidl::start() {
160 if (!mStream) return NO_INIT;
161 return processReturn("start", mStream->start());
162}
163
164status_t StreamHalHidl::stop() {
165 if (!mStream) return NO_INIT;
166 return processReturn("stop", mStream->stop());
167}
168
169status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
170 struct audio_mmap_buffer_info *info) {
171 Result retval;
172 Return<void> ret = mStream->createMmapBuffer(
173 minSizeFrames,
174 [&](Result r, const MmapBufferInfo& hidlInfo) {
175 retval = r;
176 if (retval == Result::OK) {
Eric Laurentb8753072016-12-21 12:04:10 -0800177 const native_handle *handle = hidlInfo.sharedMemory.handle();
Eric Laurentaf35aad2016-12-15 14:25:36 -0800178 if (handle->numFds > 0) {
Eric Laurent3a85e562017-05-11 18:08:51 -0700179 info->shared_memory_fd = handle->data[0];
Eric Laurentaf35aad2016-12-15 14:25:36 -0800180 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard0b21bdd2018-07-12 19:37:41 -0700181 // Negative buffer size frame was a hack in O and P to
182 // indicate that the buffer is shareable to applications
183 if (info->buffer_size_frames < 0) {
184 info->buffer_size_frames *= -1;
185 info->flags = audio_mmap_buffer_flag(
186 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
187 }
Eric Laurentaf35aad2016-12-15 14:25:36 -0800188 info->burst_size_frames = hidlInfo.burstSizeFrames;
189 // info->shared_memory_address is not needed in HIDL context
190 info->shared_memory_address = NULL;
191 } else {
192 retval = Result::NOT_INITIALIZED;
193 }
194 }
195 });
196 return processReturn("createMmapBuffer", ret, retval);
197}
198
199status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
200 Result retval;
201 Return<void> ret = mStream->getMmapPosition(
202 [&](Result r, const MmapPosition& hidlPosition) {
203 retval = r;
204 if (retval == Result::OK) {
205 position->time_nanoseconds = hidlPosition.timeNanoseconds;
206 position->position_frames = hidlPosition.positionFrames;
207 }
208 });
209 return processReturn("getMmapPosition", ret, retval);
210}
Mikhail Naganovf558e022016-11-14 17:45:17 -0800211
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800212status_t StreamHalHidl::setHalThreadPriority(int priority) {
213 mHalThreadPriority = priority;
214 return OK;
215}
216
Mikhail Naganov10fd0562017-08-01 17:20:24 -0700217status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
218 if (mCachedBufferSize != 0) {
219 *size = mCachedBufferSize;
220 return OK;
221 }
222 return getBufferSize(size);
223}
224
Mikhail Naganov83f04272017-02-07 10:45:09 -0800225bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
226 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
227 return true;
228 }
229 int err = requestPriority(
230 threadPid, threadId,
231 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
232 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
233 mHalThreadPriority, threadPid, threadId, err);
234 // Audio will still work, but latency will be higher and sometimes unacceptable.
235 return err == 0;
236}
237
Mikhail Naganovf558e022016-11-14 17:45:17 -0800238namespace {
239
240/* Notes on callback ownership.
241
242This is how (Hw)Binder ownership model looks like. The server implementation
243is owned by Binder framework (via sp<>). Proxies are owned by clients.
244When the last proxy disappears, Binder framework releases the server impl.
245
246Thus, it is not needed to keep any references to StreamOutCallback (this is
247the server impl) -- it will live as long as HAL server holds a strong ref to
248IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
249from the destructor of StreamOutHalHidl.
250
251The callback only keeps a weak reference to the stream. The stream is owned
252by AudioFlinger.
253
254*/
255
256struct StreamOutCallback : public IStreamOutCallback {
257 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
258
259 // IStreamOutCallback implementation
260 Return<void> onWriteReady() override {
261 sp<StreamOutHalHidl> stream = mStream.promote();
262 if (stream != 0) {
263 stream->onWriteReady();
264 }
265 return Void();
266 }
267
268 Return<void> onDrainReady() override {
269 sp<StreamOutHalHidl> stream = mStream.promote();
270 if (stream != 0) {
271 stream->onDrainReady();
272 }
273 return Void();
274 }
275
276 Return<void> onError() override {
277 sp<StreamOutHalHidl> stream = mStream.promote();
278 if (stream != 0) {
279 stream->onError();
280 }
281 return Void();
282 }
283
284 private:
285 wp<StreamOutHalHidl> mStream;
286};
287
288} // namespace
289
290StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
Mikhail Naganovc8381902017-01-31 13:56:25 -0800291 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800292}
293
294StreamOutHalHidl::~StreamOutHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800295 if (mStream != 0) {
296 if (mCallback.unsafe_get()) {
297 processReturn("clearCallback", mStream->clearCallback());
298 }
299 processReturn("close", mStream->close());
Mikhail Naganov23feba22017-02-23 11:00:55 -0800300 mStream.clear();
Mikhail Naganovf558e022016-11-14 17:45:17 -0800301 }
302 mCallback.clear();
Mikhail Naganov23feba22017-02-23 11:00:55 -0800303 hardware::IPCThreadState::self()->flushCommands();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800304 if (mEfGroup) {
305 EventFlag::deleteEventFlag(&mEfGroup);
306 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800307}
308
309status_t StreamOutHalHidl::getFrameSize(size_t *size) {
310 if (mStream == 0) return NO_INIT;
311 return processReturn("getFrameSize", mStream->getFrameSize(), size);
312}
313
314status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
315 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800316 if (mWriterClient == gettid() && mCommandMQ) {
317 return callWriterThread(
318 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
319 [&](const WriteStatus& writeStatus) {
320 *latency = writeStatus.reply.latencyMs;
321 });
322 } else {
323 return processReturn("getLatency", mStream->getLatency(), latency);
324 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800325}
326
327status_t StreamOutHalHidl::setVolume(float left, float right) {
328 if (mStream == 0) return NO_INIT;
329 return processReturn("setVolume", mStream->setVolume(left, right));
330}
331
332status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
333 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800334 *written = 0;
335
336 if (bytes == 0 && !mDataMQ) {
337 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
338 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
339 return OK;
340 }
341
342 status_t status;
Mikhail Naganov10fd0562017-08-01 17:20:24 -0700343 if (!mDataMQ) {
344 // In case if playback starts close to the end of a compressed track, the bytes
345 // that need to be written is less than the actual buffer size. Need to use
346 // full buffer size for the MQ since otherwise after seeking back to the middle
347 // data will be truncated.
348 size_t bufferSize;
349 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
350 return status;
351 }
352 if (bytes > bufferSize) bufferSize = bytes;
353 if ((status = prepareForWriting(bufferSize)) != OK) {
354 return status;
355 }
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800356 }
357
Andy Hung953608f2017-06-13 15:21:49 -0700358 status = callWriterThread(
Mikhail Naganovc8381902017-01-31 13:56:25 -0800359 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
360 [&] (const WriteStatus& writeStatus) {
361 *written = writeStatus.reply.written;
Mikhail Naganovd15f1272017-02-28 09:10:43 -0800362 // Diagnostics of the cause of b/35813113.
363 ALOGE_IF(*written > bytes,
364 "hal reports more bytes written than asked for: %lld > %lld",
365 (long long)*written, (long long)bytes);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800366 });
Andy Hung953608f2017-06-13 15:21:49 -0700367 mStreamPowerLog.log(buffer, *written);
368 return status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800369}
370
371status_t StreamOutHalHidl::callWriterThread(
372 WriteCommand cmd, const char* cmdName,
373 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
374 if (!mCommandMQ->write(&cmd)) {
375 ALOGE("command message queue write failed for \"%s\"", cmdName);
376 return -EAGAIN;
377 }
378 if (data != nullptr) {
379 size_t availableToWrite = mDataMQ->availableToWrite();
380 if (dataSize > availableToWrite) {
Mikhail Naganovd15f1272017-02-28 09:10:43 -0800381 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
382 (long long)dataSize, (long long)availableToWrite);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800383 dataSize = availableToWrite;
384 }
385 if (!mDataMQ->write(data, dataSize)) {
386 ALOGE("data message queue write failed for \"%s\"", cmdName);
387 }
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800388 }
389 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
390
391 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
392 uint32_t efState = 0;
393retry:
Mikhail Naganovb4e77912017-02-15 10:23:09 -0800394 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800395 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800396 WriteStatus writeStatus;
397 writeStatus.retval = Result::NOT_INITIALIZED;
398 if (!mStatusMQ->read(&writeStatus)) {
399 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800400 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800401 if (writeStatus.retval == Result::OK) {
402 ret = OK;
403 callback(writeStatus);
404 } else {
405 ret = processReturn(cmdName, writeStatus.retval);
406 }
407 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800408 }
Mikhail Naganovd2ae9cd2017-03-03 09:15:01 -0800409 if (ret == -EAGAIN || ret == -EINTR) {
410 // Spurious wakeup. This normally retries no more than once.
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800411 goto retry;
412 }
413 return ret;
414}
415
416status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800417 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800418 std::unique_ptr<DataMQ> tempDataMQ;
419 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800420 Result retval;
Mikhail Naganov83f04272017-02-07 10:45:09 -0800421 pid_t halThreadPid, halThreadTid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800422 Return<void> ret = mStream->prepareForWriting(
Mikhail Naganov83f04272017-02-07 10:45:09 -0800423 1, bufferSize,
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800424 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800425 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800426 const DataMQ::Descriptor& dataMQ,
Mikhail Naganov83f04272017-02-07 10:45:09 -0800427 const StatusMQ::Descriptor& statusMQ,
428 const ThreadInfo& halThreadInfo) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800429 retval = r;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800430 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800431 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800432 tempDataMQ.reset(new DataMQ(dataMQ));
433 tempStatusMQ.reset(new StatusMQ(statusMQ));
434 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
435 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
436 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800437 halThreadPid = halThreadInfo.pid;
438 halThreadTid = halThreadInfo.tid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800439 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800440 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800441 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800442 return processReturn("prepareForWriting", ret, retval);
443 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800444 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
445 !tempDataMQ || !tempDataMQ->isValid() ||
446 !tempStatusMQ || !tempStatusMQ->isValid() ||
447 !mEfGroup) {
448 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
449 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
450 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800451 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
452 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
453 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
454 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
455 "Status message queue for writing is invalid");
456 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
457 return NO_INIT;
458 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800459 requestHalThreadPriority(halThreadPid, halThreadTid);
460
Mikhail Naganovc8381902017-01-31 13:56:25 -0800461 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800462 mDataMQ = std::move(tempDataMQ);
463 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800464 mWriterClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800465 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800466}
467
468status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
469 if (mStream == 0) return NO_INIT;
470 Result retval;
471 Return<void> ret = mStream->getRenderPosition(
472 [&](Result r, uint32_t d) {
473 retval = r;
474 if (retval == Result::OK) {
475 *dspFrames = d;
476 }
477 });
478 return processReturn("getRenderPosition", ret, retval);
479}
480
481status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
482 if (mStream == 0) return NO_INIT;
483 Result retval;
484 Return<void> ret = mStream->getNextWriteTimestamp(
485 [&](Result r, int64_t t) {
486 retval = r;
487 if (retval == Result::OK) {
488 *timestamp = t;
489 }
490 });
491 return processReturn("getRenderPosition", ret, retval);
492}
493
494status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
495 if (mStream == 0) return NO_INIT;
496 status_t status = processReturn(
497 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
498 if (status == OK) {
499 mCallback = callback;
500 }
501 return status;
502}
503
504status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
505 if (mStream == 0) return NO_INIT;
506 Return<void> ret = mStream->supportsPauseAndResume(
507 [&](bool p, bool r) {
508 *supportsPause = p;
509 *supportsResume = r;
510 });
511 return processReturn("supportsPauseAndResume", ret);
512}
513
514status_t StreamOutHalHidl::pause() {
515 if (mStream == 0) return NO_INIT;
516 return processReturn("pause", mStream->pause());
517}
518
519status_t StreamOutHalHidl::resume() {
520 if (mStream == 0) return NO_INIT;
521 return processReturn("pause", mStream->resume());
522}
523
524status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
525 if (mStream == 0) return NO_INIT;
526 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
527}
528
529status_t StreamOutHalHidl::drain(bool earlyNotify) {
530 if (mStream == 0) return NO_INIT;
531 return processReturn(
532 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
533}
534
535status_t StreamOutHalHidl::flush() {
536 if (mStream == 0) return NO_INIT;
537 return processReturn("pause", mStream->flush());
538}
539
540status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
541 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800542 if (mWriterClient == gettid() && mCommandMQ) {
543 return callWriterThread(
544 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
545 [&](const WriteStatus& writeStatus) {
546 *frames = writeStatus.reply.presentationPosition.frames;
547 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
548 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
549 });
550 } else {
551 Result retval;
552 Return<void> ret = mStream->getPresentationPosition(
553 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
554 retval = r;
555 if (retval == Result::OK) {
556 *frames = hidlFrames;
557 timestamp->tv_sec = hidlTimeStamp.tvSec;
558 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
559 }
560 });
561 return processReturn("getPresentationPosition", ret, retval);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800562 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800563}
564
Kevin Rocarda8975a72018-03-27 10:16:52 -0700565status_t StreamOutHalHidl::updateSourceMetadata(const SourceMetadata& /* sourceMetadata */) {
566 // Audio HAL V2.0 does not support propagating source metadata
567 return INVALID_OPERATION;
568}
569
Mikhail Naganovf558e022016-11-14 17:45:17 -0800570void StreamOutHalHidl::onWriteReady() {
571 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
572 if (callback == 0) return;
573 ALOGV("asyncCallback onWriteReady");
574 callback->onWriteReady();
575}
576
577void StreamOutHalHidl::onDrainReady() {
578 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
579 if (callback == 0) return;
580 ALOGV("asyncCallback onDrainReady");
581 callback->onDrainReady();
582}
583
584void StreamOutHalHidl::onError() {
585 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
586 if (callback == 0) return;
587 ALOGV("asyncCallback onError");
588 callback->onError();
589}
590
591
592StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
Mikhail Naganovc8381902017-01-31 13:56:25 -0800593 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800594}
595
596StreamInHalHidl::~StreamInHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800597 if (mStream != 0) {
598 processReturn("close", mStream->close());
Mikhail Naganov23feba22017-02-23 11:00:55 -0800599 mStream.clear();
600 hardware::IPCThreadState::self()->flushCommands();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800601 }
602 if (mEfGroup) {
603 EventFlag::deleteEventFlag(&mEfGroup);
604 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800605}
606
607status_t StreamInHalHidl::getFrameSize(size_t *size) {
608 if (mStream == 0) return NO_INIT;
609 return processReturn("getFrameSize", mStream->getFrameSize(), size);
610}
611
612status_t StreamInHalHidl::setGain(float gain) {
613 if (mStream == 0) return NO_INIT;
614 return processReturn("setGain", mStream->setGain(gain));
615}
616
617status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
618 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800619 *read = 0;
620
621 if (bytes == 0 && !mDataMQ) {
622 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
623 return OK;
624 }
625
626 status_t status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800627 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
628 return status;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800629 }
630
Mikhail Naganovc8381902017-01-31 13:56:25 -0800631 ReadParameters params;
632 params.command = ReadCommand::READ;
633 params.params.read = bytes;
Andy Hung953608f2017-06-13 15:21:49 -0700634 status = callReaderThread(params, "read",
Mikhail Naganovc8381902017-01-31 13:56:25 -0800635 [&](const ReadStatus& readStatus) {
636 const size_t availToRead = mDataMQ->availableToRead();
637 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
638 ALOGE("data message queue read failed for \"read\"");
639 }
640 ALOGW_IF(availToRead != readStatus.reply.read,
641 "HAL read report inconsistent: mq = %d, status = %d",
642 (int32_t)availToRead, (int32_t)readStatus.reply.read);
643 *read = readStatus.reply.read;
644 });
Andy Hung953608f2017-06-13 15:21:49 -0700645 mStreamPowerLog.log(buffer, *read);
646 return status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800647}
648
649status_t StreamInHalHidl::callReaderThread(
650 const ReadParameters& params, const char* cmdName,
651 StreamInHalHidl::ReaderCallback callback) {
652 if (!mCommandMQ->write(&params)) {
653 ALOGW("command message queue write failed");
654 return -EAGAIN;
655 }
656 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
657
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800658 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
659 uint32_t efState = 0;
660retry:
Mikhail Naganovb4e77912017-02-15 10:23:09 -0800661 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800662 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800663 ReadStatus readStatus;
664 readStatus.retval = Result::NOT_INITIALIZED;
665 if (!mStatusMQ->read(&readStatus)) {
666 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800667 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800668 if (readStatus.retval == Result::OK) {
669 ret = OK;
670 callback(readStatus);
671 } else {
672 ret = processReturn(cmdName, readStatus.retval);
673 }
674 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800675 }
Mikhail Naganovd2ae9cd2017-03-03 09:15:01 -0800676 if (ret == -EAGAIN || ret == -EINTR) {
677 // Spurious wakeup. This normally retries no more than once.
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800678 goto retry;
679 }
680 return ret;
681}
682
683status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800684 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800685 std::unique_ptr<DataMQ> tempDataMQ;
686 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800687 Result retval;
Mikhail Naganov83f04272017-02-07 10:45:09 -0800688 pid_t halThreadPid, halThreadTid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800689 Return<void> ret = mStream->prepareForReading(
Mikhail Naganov83f04272017-02-07 10:45:09 -0800690 1, bufferSize,
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800691 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800692 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800693 const DataMQ::Descriptor& dataMQ,
Mikhail Naganov83f04272017-02-07 10:45:09 -0800694 const StatusMQ::Descriptor& statusMQ,
695 const ThreadInfo& halThreadInfo) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800696 retval = r;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800697 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800698 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800699 tempDataMQ.reset(new DataMQ(dataMQ));
700 tempStatusMQ.reset(new StatusMQ(statusMQ));
701 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
702 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
703 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800704 halThreadPid = halThreadInfo.pid;
705 halThreadTid = halThreadInfo.tid;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800706 }
707 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800708 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800709 return processReturn("prepareForReading", ret, retval);
710 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800711 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
712 !tempDataMQ || !tempDataMQ->isValid() ||
713 !tempStatusMQ || !tempStatusMQ->isValid() ||
714 !mEfGroup) {
715 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
716 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
717 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800718 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
719 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
720 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
721 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
722 "Status message queue for reading is invalid");
723 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
724 return NO_INIT;
725 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800726 requestHalThreadPriority(halThreadPid, halThreadTid);
727
Mikhail Naganovc8381902017-01-31 13:56:25 -0800728 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800729 mDataMQ = std::move(tempDataMQ);
730 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800731 mReaderClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800732 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800733}
734
735status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
736 if (mStream == 0) return NO_INIT;
737 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
738}
739
740status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
741 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800742 if (mReaderClient == gettid() && mCommandMQ) {
743 ReadParameters params;
744 params.command = ReadCommand::GET_CAPTURE_POSITION;
745 return callReaderThread(params, "getCapturePosition",
746 [&](const ReadStatus& readStatus) {
747 *frames = readStatus.reply.capturePosition.frames;
748 *time = readStatus.reply.capturePosition.time;
749 });
750 } else {
751 Result retval;
752 Return<void> ret = mStream->getCapturePosition(
753 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
754 retval = r;
755 if (retval == Result::OK) {
756 *frames = hidlFrames;
757 *time = hidlTime;
758 }
759 });
760 return processReturn("getCapturePosition", ret, retval);
761 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800762}
763
jiabin9ff780e2018-03-19 18:19:52 -0700764status_t StreamInHalHidl::getActiveMicrophones(
765 std::vector<media::MicrophoneInfo> *microphones __unused) {
766 if (mStream == 0) return NO_INIT;
767 return INVALID_OPERATION;
768}
769
Kevin Rocarda8975a72018-03-27 10:16:52 -0700770status_t StreamInHalHidl::updateSinkMetadata(const SinkMetadata& /* sinkMetadata */) {
771 // Audio HAL V2.0 does not support propagating sink metadata
772 return INVALID_OPERATION;
773}
774
Mikhail Naganovf558e022016-11-14 17:45:17 -0800775} // namespace android