blob: b6e83658fd5199164a9293a5c1c713427d9275b4 [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"
Kevin Rocarddf9b4202018-05-10 19:56:08 -070028#include "VersionUtils.h"
Mikhail Naganovf558e022016-11-14 17:45:17 -080029
30using ::android::hardware::audio::common::V2_0::AudioChannelMask;
31using ::android::hardware::audio::common::V2_0::AudioFormat;
Mikhail Naganov83f04272017-02-07 10:45:09 -080032using ::android::hardware::audio::common::V2_0::ThreadInfo;
Mikhail Naganovf558e022016-11-14 17:45:17 -080033using ::android::hardware::audio::V2_0::AudioDrain;
34using ::android::hardware::audio::V2_0::IStreamOutCallback;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080035using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
Eric Laurentaf35aad2016-12-15 14:25:36 -080036using ::android::hardware::audio::V2_0::MmapBufferInfo;
37using ::android::hardware::audio::V2_0::MmapPosition;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080038using ::android::hardware::audio::V2_0::ParameterValue;
39using ::android::hardware::audio::V2_0::Result;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080040using ::android::hardware::audio::V2_0::TimeSpec;
41using ::android::hardware::MQDescriptorSync;
Mikhail Naganovf558e022016-11-14 17:45:17 -080042using ::android::hardware::Return;
43using ::android::hardware::Void;
Mikhail Naganovc8381902017-01-31 13:56:25 -080044using ReadCommand = ::android::hardware::audio::V2_0::IStreamIn::ReadCommand;
Mikhail Naganovf558e022016-11-14 17:45:17 -080045
46namespace android {
Kevin Rocarddf9b4202018-05-10 19:56:08 -070047namespace V2_0 {
Mikhail Naganovf558e022016-11-14 17:45:17 -080048
49StreamHalHidl::StreamHalHidl(IStream *stream)
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080050 : ConversionHelperHidl("Stream"),
Mikhail Naganov83f04272017-02-07 10:45:09 -080051 mStream(stream),
Mikhail Naganov10fd0562017-08-01 17:20:24 -070052 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
53 mCachedBufferSize(0){
Andy Hung953608f2017-06-13 15:21:49 -070054
55 // Instrument audio signal power logging.
56 // Note: This assumes channel mask, format, and sample rate do not change after creation.
57 if (mStream != nullptr && mStreamPowerLog.isUserDebugOrEngBuild()) {
58 // Obtain audio properties (see StreamHalHidl::getAudioProperties() below).
59 Return<void> ret = mStream->getAudioProperties(
Kevin Rocarddf9b4202018-05-10 19:56:08 -070060 [&](auto sr, auto m, auto f) {
Andy Hung953608f2017-06-13 15:21:49 -070061 mStreamPowerLog.init(sr,
62 static_cast<audio_channel_mask_t>(m),
63 static_cast<audio_format_t>(f));
64 });
65 }
Mikhail Naganovf558e022016-11-14 17:45:17 -080066}
67
68StreamHalHidl::~StreamHalHidl() {
69 mStream = nullptr;
70}
71
72status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
73 if (!mStream) return NO_INIT;
74 return processReturn("getSampleRate", mStream->getSampleRate(), rate);
75}
76
77status_t StreamHalHidl::getBufferSize(size_t *size) {
78 if (!mStream) return NO_INIT;
Mikhail Naganov10fd0562017-08-01 17:20:24 -070079 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
80 if (status == OK) {
81 mCachedBufferSize = *size;
82 }
83 return status;
Mikhail Naganovf558e022016-11-14 17:45:17 -080084}
85
86status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
87 if (!mStream) return NO_INIT;
88 return processReturn("getChannelMask", mStream->getChannelMask(), mask);
89}
90
91status_t StreamHalHidl::getFormat(audio_format_t *format) {
92 if (!mStream) return NO_INIT;
93 return processReturn("getFormat", mStream->getFormat(), format);
94}
95
96status_t StreamHalHidl::getAudioProperties(
97 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
98 if (!mStream) return NO_INIT;
99 Return<void> ret = mStream->getAudioProperties(
Kevin Rocarddf9b4202018-05-10 19:56:08 -0700100 [&](uint32_t sr, auto m, auto f) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800101 *sampleRate = sr;
102 *mask = static_cast<audio_channel_mask_t>(m);
103 *format = static_cast<audio_format_t>(f);
104 });
105 return processReturn("getAudioProperties", ret);
106}
107
108status_t StreamHalHidl::setParameters(const String8& kvPairs) {
109 if (!mStream) return NO_INIT;
110 hidl_vec<ParameterValue> hidlParams;
111 status_t status = parametersFromHal(kvPairs, &hidlParams);
112 if (status != OK) return status;
Kevin Rocarddf9b4202018-05-10 19:56:08 -0700113 return processReturn("setParameters",
114 utils::setParameters(mStream, hidlParams, {} /* options */));
Mikhail Naganovf558e022016-11-14 17:45:17 -0800115}
116
117status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
118 values->clear();
119 if (!mStream) return NO_INIT;
120 hidl_vec<hidl_string> hidlKeys;
121 status_t status = keysFromHal(keys, &hidlKeys);
122 if (status != OK) return status;
123 Result retval;
Kevin Rocarddf9b4202018-05-10 19:56:08 -0700124 Return<void> ret = utils::getParameters(
125 mStream,
126 {} /* context */,
Mikhail Naganovf558e022016-11-14 17:45:17 -0800127 hidlKeys,
128 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
129 retval = r;
130 if (retval == Result::OK) {
131 parametersToHal(parameters, values);
132 }
133 });
134 return processReturn("getParameters", ret, retval);
135}
136
137status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
138 if (!mStream) return NO_INIT;
139 return processReturn("addEffect", mStream->addEffect(
140 static_cast<EffectHalHidl*>(effect.get())->effectId()));
141}
142
143status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
144 if (!mStream) return NO_INIT;
145 return processReturn("removeEffect", mStream->removeEffect(
146 static_cast<EffectHalHidl*>(effect.get())->effectId()));
147}
148
149status_t StreamHalHidl::standby() {
150 if (!mStream) return NO_INIT;
151 return processReturn("standby", mStream->standby());
152}
153
154status_t StreamHalHidl::dump(int fd) {
155 if (!mStream) return NO_INIT;
156 native_handle_t* hidlHandle = native_handle_create(1, 0);
157 hidlHandle->data[0] = fd;
Kevin Rocarddf9b4202018-05-10 19:56:08 -0700158 Return<void> ret = mStream->debug(hidlHandle, {} /* options */);
Mikhail Naganovf558e022016-11-14 17:45:17 -0800159 native_handle_delete(hidlHandle);
Andy Hung953608f2017-06-13 15:21:49 -0700160 mStreamPowerLog.dump(fd);
Mikhail Naganovf558e022016-11-14 17:45:17 -0800161 return processReturn("dump", ret);
162}
163
Eric Laurentaf35aad2016-12-15 14:25:36 -0800164status_t StreamHalHidl::start() {
165 if (!mStream) return NO_INIT;
166 return processReturn("start", mStream->start());
167}
168
169status_t StreamHalHidl::stop() {
170 if (!mStream) return NO_INIT;
171 return processReturn("stop", mStream->stop());
172}
173
174status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
175 struct audio_mmap_buffer_info *info) {
176 Result retval;
177 Return<void> ret = mStream->createMmapBuffer(
178 minSizeFrames,
179 [&](Result r, const MmapBufferInfo& hidlInfo) {
180 retval = r;
181 if (retval == Result::OK) {
Eric Laurentb8753072016-12-21 12:04:10 -0800182 const native_handle *handle = hidlInfo.sharedMemory.handle();
Eric Laurentaf35aad2016-12-15 14:25:36 -0800183 if (handle->numFds > 0) {
Eric Laurent3a85e562017-05-11 18:08:51 -0700184 info->shared_memory_fd = handle->data[0];
Eric Laurentaf35aad2016-12-15 14:25:36 -0800185 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
186 info->burst_size_frames = hidlInfo.burstSizeFrames;
187 // info->shared_memory_address is not needed in HIDL context
188 info->shared_memory_address = NULL;
189 } else {
190 retval = Result::NOT_INITIALIZED;
191 }
192 }
193 });
194 return processReturn("createMmapBuffer", ret, retval);
195}
196
197status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
198 Result retval;
199 Return<void> ret = mStream->getMmapPosition(
200 [&](Result r, const MmapPosition& hidlPosition) {
201 retval = r;
202 if (retval == Result::OK) {
203 position->time_nanoseconds = hidlPosition.timeNanoseconds;
204 position->position_frames = hidlPosition.positionFrames;
205 }
206 });
207 return processReturn("getMmapPosition", ret, retval);
208}
Mikhail Naganovf558e022016-11-14 17:45:17 -0800209
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800210status_t StreamHalHidl::setHalThreadPriority(int priority) {
211 mHalThreadPriority = priority;
212 return OK;
213}
214
Mikhail Naganov10fd0562017-08-01 17:20:24 -0700215status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
216 if (mCachedBufferSize != 0) {
217 *size = mCachedBufferSize;
218 return OK;
219 }
220 return getBufferSize(size);
221}
222
Mikhail Naganov83f04272017-02-07 10:45:09 -0800223bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
224 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
225 return true;
226 }
227 int err = requestPriority(
228 threadPid, threadId,
229 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
230 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
231 mHalThreadPriority, threadPid, threadId, err);
232 // Audio will still work, but latency will be higher and sometimes unacceptable.
233 return err == 0;
234}
235
Mikhail Naganovf558e022016-11-14 17:45:17 -0800236namespace {
237
238/* Notes on callback ownership.
239
240This is how (Hw)Binder ownership model looks like. The server implementation
241is owned by Binder framework (via sp<>). Proxies are owned by clients.
242When the last proxy disappears, Binder framework releases the server impl.
243
244Thus, it is not needed to keep any references to StreamOutCallback (this is
245the server impl) -- it will live as long as HAL server holds a strong ref to
246IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
247from the destructor of StreamOutHalHidl.
248
249The callback only keeps a weak reference to the stream. The stream is owned
250by AudioFlinger.
251
252*/
253
254struct StreamOutCallback : public IStreamOutCallback {
255 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
256
257 // IStreamOutCallback implementation
258 Return<void> onWriteReady() override {
259 sp<StreamOutHalHidl> stream = mStream.promote();
260 if (stream != 0) {
261 stream->onWriteReady();
262 }
263 return Void();
264 }
265
266 Return<void> onDrainReady() override {
267 sp<StreamOutHalHidl> stream = mStream.promote();
268 if (stream != 0) {
269 stream->onDrainReady();
270 }
271 return Void();
272 }
273
274 Return<void> onError() override {
275 sp<StreamOutHalHidl> stream = mStream.promote();
276 if (stream != 0) {
277 stream->onError();
278 }
279 return Void();
280 }
281
282 private:
283 wp<StreamOutHalHidl> mStream;
284};
285
286} // namespace
287
288StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
Mikhail Naganovc8381902017-01-31 13:56:25 -0800289 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800290}
291
292StreamOutHalHidl::~StreamOutHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800293 if (mStream != 0) {
294 if (mCallback.unsafe_get()) {
295 processReturn("clearCallback", mStream->clearCallback());
296 }
297 processReturn("close", mStream->close());
Mikhail Naganov23feba22017-02-23 11:00:55 -0800298 mStream.clear();
Mikhail Naganovf558e022016-11-14 17:45:17 -0800299 }
300 mCallback.clear();
Mikhail Naganov23feba22017-02-23 11:00:55 -0800301 hardware::IPCThreadState::self()->flushCommands();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800302 if (mEfGroup) {
303 EventFlag::deleteEventFlag(&mEfGroup);
304 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800305}
306
307status_t StreamOutHalHidl::getFrameSize(size_t *size) {
308 if (mStream == 0) return NO_INIT;
309 return processReturn("getFrameSize", mStream->getFrameSize(), size);
310}
311
312status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
313 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800314 if (mWriterClient == gettid() && mCommandMQ) {
315 return callWriterThread(
316 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
317 [&](const WriteStatus& writeStatus) {
318 *latency = writeStatus.reply.latencyMs;
319 });
320 } else {
321 return processReturn("getLatency", mStream->getLatency(), latency);
322 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800323}
324
325status_t StreamOutHalHidl::setVolume(float left, float right) {
326 if (mStream == 0) return NO_INIT;
327 return processReturn("setVolume", mStream->setVolume(left, right));
328}
329
330status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
331 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800332 *written = 0;
333
334 if (bytes == 0 && !mDataMQ) {
335 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
336 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
337 return OK;
338 }
339
340 status_t status;
Mikhail Naganov10fd0562017-08-01 17:20:24 -0700341 if (!mDataMQ) {
342 // In case if playback starts close to the end of a compressed track, the bytes
343 // that need to be written is less than the actual buffer size. Need to use
344 // full buffer size for the MQ since otherwise after seeking back to the middle
345 // data will be truncated.
346 size_t bufferSize;
347 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
348 return status;
349 }
350 if (bytes > bufferSize) bufferSize = bytes;
351 if ((status = prepareForWriting(bufferSize)) != OK) {
352 return status;
353 }
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800354 }
355
Andy Hung953608f2017-06-13 15:21:49 -0700356 status = callWriterThread(
Mikhail Naganovc8381902017-01-31 13:56:25 -0800357 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
358 [&] (const WriteStatus& writeStatus) {
359 *written = writeStatus.reply.written;
Mikhail Naganovd15f1272017-02-28 09:10:43 -0800360 // Diagnostics of the cause of b/35813113.
361 ALOGE_IF(*written > bytes,
362 "hal reports more bytes written than asked for: %lld > %lld",
363 (long long)*written, (long long)bytes);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800364 });
Andy Hung953608f2017-06-13 15:21:49 -0700365 mStreamPowerLog.log(buffer, *written);
366 return status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800367}
368
369status_t StreamOutHalHidl::callWriterThread(
370 WriteCommand cmd, const char* cmdName,
371 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
372 if (!mCommandMQ->write(&cmd)) {
373 ALOGE("command message queue write failed for \"%s\"", cmdName);
374 return -EAGAIN;
375 }
376 if (data != nullptr) {
377 size_t availableToWrite = mDataMQ->availableToWrite();
378 if (dataSize > availableToWrite) {
Mikhail Naganovd15f1272017-02-28 09:10:43 -0800379 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
380 (long long)dataSize, (long long)availableToWrite);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800381 dataSize = availableToWrite;
382 }
383 if (!mDataMQ->write(data, dataSize)) {
384 ALOGE("data message queue write failed for \"%s\"", cmdName);
385 }
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800386 }
387 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
388
389 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
390 uint32_t efState = 0;
391retry:
Mikhail Naganovb4e77912017-02-15 10:23:09 -0800392 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800393 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800394 WriteStatus writeStatus;
395 writeStatus.retval = Result::NOT_INITIALIZED;
396 if (!mStatusMQ->read(&writeStatus)) {
397 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800398 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800399 if (writeStatus.retval == Result::OK) {
400 ret = OK;
401 callback(writeStatus);
402 } else {
403 ret = processReturn(cmdName, writeStatus.retval);
404 }
405 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800406 }
Mikhail Naganovd2ae9cd2017-03-03 09:15:01 -0800407 if (ret == -EAGAIN || ret == -EINTR) {
408 // Spurious wakeup. This normally retries no more than once.
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800409 goto retry;
410 }
411 return ret;
412}
413
414status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800415 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800416 std::unique_ptr<DataMQ> tempDataMQ;
417 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800418 Result retval;
Mikhail Naganov83f04272017-02-07 10:45:09 -0800419 pid_t halThreadPid, halThreadTid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800420 Return<void> ret = mStream->prepareForWriting(
Mikhail Naganov83f04272017-02-07 10:45:09 -0800421 1, bufferSize,
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800422 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800423 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800424 const DataMQ::Descriptor& dataMQ,
Mikhail Naganov83f04272017-02-07 10:45:09 -0800425 const StatusMQ::Descriptor& statusMQ,
426 const ThreadInfo& halThreadInfo) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800427 retval = r;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800428 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800429 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800430 tempDataMQ.reset(new DataMQ(dataMQ));
431 tempStatusMQ.reset(new StatusMQ(statusMQ));
432 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
433 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
434 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800435 halThreadPid = halThreadInfo.pid;
436 halThreadTid = halThreadInfo.tid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800437 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800438 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800439 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800440 return processReturn("prepareForWriting", ret, retval);
441 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800442 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
443 !tempDataMQ || !tempDataMQ->isValid() ||
444 !tempStatusMQ || !tempStatusMQ->isValid() ||
445 !mEfGroup) {
446 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
447 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
448 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800449 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
450 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
451 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
452 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
453 "Status message queue for writing is invalid");
454 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
455 return NO_INIT;
456 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800457 requestHalThreadPriority(halThreadPid, halThreadTid);
458
Mikhail Naganovc8381902017-01-31 13:56:25 -0800459 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800460 mDataMQ = std::move(tempDataMQ);
461 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800462 mWriterClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800463 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800464}
465
466status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
467 if (mStream == 0) return NO_INIT;
468 Result retval;
469 Return<void> ret = mStream->getRenderPosition(
470 [&](Result r, uint32_t d) {
471 retval = r;
472 if (retval == Result::OK) {
473 *dspFrames = d;
474 }
475 });
476 return processReturn("getRenderPosition", ret, retval);
477}
478
479status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
480 if (mStream == 0) return NO_INIT;
481 Result retval;
482 Return<void> ret = mStream->getNextWriteTimestamp(
483 [&](Result r, int64_t t) {
484 retval = r;
485 if (retval == Result::OK) {
486 *timestamp = t;
487 }
488 });
489 return processReturn("getRenderPosition", ret, retval);
490}
491
492status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
493 if (mStream == 0) return NO_INIT;
494 status_t status = processReturn(
495 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
496 if (status == OK) {
497 mCallback = callback;
498 }
499 return status;
500}
501
502status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
503 if (mStream == 0) return NO_INIT;
504 Return<void> ret = mStream->supportsPauseAndResume(
505 [&](bool p, bool r) {
506 *supportsPause = p;
507 *supportsResume = r;
508 });
509 return processReturn("supportsPauseAndResume", ret);
510}
511
512status_t StreamOutHalHidl::pause() {
513 if (mStream == 0) return NO_INIT;
514 return processReturn("pause", mStream->pause());
515}
516
517status_t StreamOutHalHidl::resume() {
518 if (mStream == 0) return NO_INIT;
519 return processReturn("pause", mStream->resume());
520}
521
522status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
523 if (mStream == 0) return NO_INIT;
524 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
525}
526
527status_t StreamOutHalHidl::drain(bool earlyNotify) {
528 if (mStream == 0) return NO_INIT;
529 return processReturn(
530 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
531}
532
533status_t StreamOutHalHidl::flush() {
534 if (mStream == 0) return NO_INIT;
535 return processReturn("pause", mStream->flush());
536}
537
538status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
539 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800540 if (mWriterClient == gettid() && mCommandMQ) {
541 return callWriterThread(
542 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
543 [&](const WriteStatus& writeStatus) {
544 *frames = writeStatus.reply.presentationPosition.frames;
545 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
546 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
547 });
548 } else {
549 Result retval;
550 Return<void> ret = mStream->getPresentationPosition(
551 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
552 retval = r;
553 if (retval == Result::OK) {
554 *frames = hidlFrames;
555 timestamp->tv_sec = hidlTimeStamp.tvSec;
556 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
557 }
558 });
559 return processReturn("getPresentationPosition", ret, retval);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800560 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800561}
562
Kevin Rocarda8975a72018-03-27 10:16:52 -0700563status_t StreamOutHalHidl::updateSourceMetadata(const SourceMetadata& /* sourceMetadata */) {
564 // Audio HAL V2.0 does not support propagating source metadata
565 return INVALID_OPERATION;
566}
567
Mikhail Naganovf558e022016-11-14 17:45:17 -0800568void StreamOutHalHidl::onWriteReady() {
569 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
570 if (callback == 0) return;
571 ALOGV("asyncCallback onWriteReady");
572 callback->onWriteReady();
573}
574
575void StreamOutHalHidl::onDrainReady() {
576 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
577 if (callback == 0) return;
578 ALOGV("asyncCallback onDrainReady");
579 callback->onDrainReady();
580}
581
582void StreamOutHalHidl::onError() {
583 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
584 if (callback == 0) return;
585 ALOGV("asyncCallback onError");
586 callback->onError();
587}
588
589
590StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
Mikhail Naganovc8381902017-01-31 13:56:25 -0800591 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800592}
593
594StreamInHalHidl::~StreamInHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800595 if (mStream != 0) {
596 processReturn("close", mStream->close());
Mikhail Naganov23feba22017-02-23 11:00:55 -0800597 mStream.clear();
598 hardware::IPCThreadState::self()->flushCommands();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800599 }
600 if (mEfGroup) {
601 EventFlag::deleteEventFlag(&mEfGroup);
602 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800603}
604
605status_t StreamInHalHidl::getFrameSize(size_t *size) {
606 if (mStream == 0) return NO_INIT;
607 return processReturn("getFrameSize", mStream->getFrameSize(), size);
608}
609
610status_t StreamInHalHidl::setGain(float gain) {
611 if (mStream == 0) return NO_INIT;
612 return processReturn("setGain", mStream->setGain(gain));
613}
614
615status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
616 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800617 *read = 0;
618
619 if (bytes == 0 && !mDataMQ) {
620 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
621 return OK;
622 }
623
624 status_t status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800625 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
626 return status;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800627 }
628
Mikhail Naganovc8381902017-01-31 13:56:25 -0800629 ReadParameters params;
630 params.command = ReadCommand::READ;
631 params.params.read = bytes;
Andy Hung953608f2017-06-13 15:21:49 -0700632 status = callReaderThread(params, "read",
Mikhail Naganovc8381902017-01-31 13:56:25 -0800633 [&](const ReadStatus& readStatus) {
634 const size_t availToRead = mDataMQ->availableToRead();
635 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
636 ALOGE("data message queue read failed for \"read\"");
637 }
638 ALOGW_IF(availToRead != readStatus.reply.read,
639 "HAL read report inconsistent: mq = %d, status = %d",
640 (int32_t)availToRead, (int32_t)readStatus.reply.read);
641 *read = readStatus.reply.read;
642 });
Andy Hung953608f2017-06-13 15:21:49 -0700643 mStreamPowerLog.log(buffer, *read);
644 return status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800645}
646
647status_t StreamInHalHidl::callReaderThread(
648 const ReadParameters& params, const char* cmdName,
649 StreamInHalHidl::ReaderCallback callback) {
650 if (!mCommandMQ->write(&params)) {
651 ALOGW("command message queue write failed");
652 return -EAGAIN;
653 }
654 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
655
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800656 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
657 uint32_t efState = 0;
658retry:
Mikhail Naganovb4e77912017-02-15 10:23:09 -0800659 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800660 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800661 ReadStatus readStatus;
662 readStatus.retval = Result::NOT_INITIALIZED;
663 if (!mStatusMQ->read(&readStatus)) {
664 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800665 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800666 if (readStatus.retval == Result::OK) {
667 ret = OK;
668 callback(readStatus);
669 } else {
670 ret = processReturn(cmdName, readStatus.retval);
671 }
672 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800673 }
Mikhail Naganovd2ae9cd2017-03-03 09:15:01 -0800674 if (ret == -EAGAIN || ret == -EINTR) {
675 // Spurious wakeup. This normally retries no more than once.
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800676 goto retry;
677 }
678 return ret;
679}
680
681status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800682 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800683 std::unique_ptr<DataMQ> tempDataMQ;
684 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800685 Result retval;
Mikhail Naganov83f04272017-02-07 10:45:09 -0800686 pid_t halThreadPid, halThreadTid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800687 Return<void> ret = mStream->prepareForReading(
Mikhail Naganov83f04272017-02-07 10:45:09 -0800688 1, bufferSize,
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800689 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800690 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800691 const DataMQ::Descriptor& dataMQ,
Mikhail Naganov83f04272017-02-07 10:45:09 -0800692 const StatusMQ::Descriptor& statusMQ,
693 const ThreadInfo& halThreadInfo) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800694 retval = r;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800695 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800696 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800697 tempDataMQ.reset(new DataMQ(dataMQ));
698 tempStatusMQ.reset(new StatusMQ(statusMQ));
699 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
700 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
701 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800702 halThreadPid = halThreadInfo.pid;
703 halThreadTid = halThreadInfo.tid;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800704 }
705 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800706 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800707 return processReturn("prepareForReading", ret, retval);
708 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800709 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
710 !tempDataMQ || !tempDataMQ->isValid() ||
711 !tempStatusMQ || !tempStatusMQ->isValid() ||
712 !mEfGroup) {
713 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
714 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
715 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800716 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
717 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
718 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
719 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
720 "Status message queue for reading is invalid");
721 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
722 return NO_INIT;
723 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800724 requestHalThreadPriority(halThreadPid, halThreadTid);
725
Mikhail Naganovc8381902017-01-31 13:56:25 -0800726 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800727 mDataMQ = std::move(tempDataMQ);
728 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800729 mReaderClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800730 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800731}
732
733status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
734 if (mStream == 0) return NO_INIT;
735 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
736}
737
738status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
739 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800740 if (mReaderClient == gettid() && mCommandMQ) {
741 ReadParameters params;
742 params.command = ReadCommand::GET_CAPTURE_POSITION;
743 return callReaderThread(params, "getCapturePosition",
744 [&](const ReadStatus& readStatus) {
745 *frames = readStatus.reply.capturePosition.frames;
746 *time = readStatus.reply.capturePosition.time;
747 });
748 } else {
749 Result retval;
750 Return<void> ret = mStream->getCapturePosition(
751 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
752 retval = r;
753 if (retval == Result::OK) {
754 *frames = hidlFrames;
755 *time = hidlTime;
756 }
757 });
758 return processReturn("getCapturePosition", ret, retval);
759 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800760}
761
jiabin9ff780e2018-03-19 18:19:52 -0700762status_t StreamInHalHidl::getActiveMicrophones(
763 std::vector<media::MicrophoneInfo> *microphones __unused) {
764 if (mStream == 0) return NO_INIT;
765 return INVALID_OPERATION;
766}
767
Kevin Rocarda8975a72018-03-27 10:16:52 -0700768status_t StreamInHalHidl::updateSinkMetadata(const SinkMetadata& /* sinkMetadata */) {
769 // Audio HAL V2.0 does not support propagating sink metadata
770 return INVALID_OPERATION;
771}
772
Kevin Rocarddf9b4202018-05-10 19:56:08 -0700773} // namespace V2_0
Mikhail Naganovf558e022016-11-14 17:45:17 -0800774} // namespace android