blob: 0cafa365e266ab4499774044dd8206757a48e66a [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;
181 info->burst_size_frames = hidlInfo.burstSizeFrames;
182 // info->shared_memory_address is not needed in HIDL context
183 info->shared_memory_address = NULL;
184 } else {
185 retval = Result::NOT_INITIALIZED;
186 }
187 }
188 });
189 return processReturn("createMmapBuffer", ret, retval);
190}
191
192status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
193 Result retval;
194 Return<void> ret = mStream->getMmapPosition(
195 [&](Result r, const MmapPosition& hidlPosition) {
196 retval = r;
197 if (retval == Result::OK) {
198 position->time_nanoseconds = hidlPosition.timeNanoseconds;
199 position->position_frames = hidlPosition.positionFrames;
200 }
201 });
202 return processReturn("getMmapPosition", ret, retval);
203}
Mikhail Naganovf558e022016-11-14 17:45:17 -0800204
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800205status_t StreamHalHidl::setHalThreadPriority(int priority) {
206 mHalThreadPriority = priority;
207 return OK;
208}
209
Mikhail Naganov10fd0562017-08-01 17:20:24 -0700210status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
211 if (mCachedBufferSize != 0) {
212 *size = mCachedBufferSize;
213 return OK;
214 }
215 return getBufferSize(size);
216}
217
Mikhail Naganov83f04272017-02-07 10:45:09 -0800218bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
219 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
220 return true;
221 }
222 int err = requestPriority(
223 threadPid, threadId,
224 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
225 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
226 mHalThreadPriority, threadPid, threadId, err);
227 // Audio will still work, but latency will be higher and sometimes unacceptable.
228 return err == 0;
229}
230
Mikhail Naganovf558e022016-11-14 17:45:17 -0800231namespace {
232
233/* Notes on callback ownership.
234
235This is how (Hw)Binder ownership model looks like. The server implementation
236is owned by Binder framework (via sp<>). Proxies are owned by clients.
237When the last proxy disappears, Binder framework releases the server impl.
238
239Thus, it is not needed to keep any references to StreamOutCallback (this is
240the server impl) -- it will live as long as HAL server holds a strong ref to
241IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
242from the destructor of StreamOutHalHidl.
243
244The callback only keeps a weak reference to the stream. The stream is owned
245by AudioFlinger.
246
247*/
248
249struct StreamOutCallback : public IStreamOutCallback {
250 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
251
252 // IStreamOutCallback implementation
253 Return<void> onWriteReady() override {
254 sp<StreamOutHalHidl> stream = mStream.promote();
255 if (stream != 0) {
256 stream->onWriteReady();
257 }
258 return Void();
259 }
260
261 Return<void> onDrainReady() override {
262 sp<StreamOutHalHidl> stream = mStream.promote();
263 if (stream != 0) {
264 stream->onDrainReady();
265 }
266 return Void();
267 }
268
269 Return<void> onError() override {
270 sp<StreamOutHalHidl> stream = mStream.promote();
271 if (stream != 0) {
272 stream->onError();
273 }
274 return Void();
275 }
276
277 private:
278 wp<StreamOutHalHidl> mStream;
279};
280
281} // namespace
282
283StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
Mikhail Naganovc8381902017-01-31 13:56:25 -0800284 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800285}
286
287StreamOutHalHidl::~StreamOutHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800288 if (mStream != 0) {
289 if (mCallback.unsafe_get()) {
290 processReturn("clearCallback", mStream->clearCallback());
291 }
292 processReturn("close", mStream->close());
Mikhail Naganov23feba22017-02-23 11:00:55 -0800293 mStream.clear();
Mikhail Naganovf558e022016-11-14 17:45:17 -0800294 }
295 mCallback.clear();
Mikhail Naganov23feba22017-02-23 11:00:55 -0800296 hardware::IPCThreadState::self()->flushCommands();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800297 if (mEfGroup) {
298 EventFlag::deleteEventFlag(&mEfGroup);
299 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800300}
301
302status_t StreamOutHalHidl::getFrameSize(size_t *size) {
303 if (mStream == 0) return NO_INIT;
304 return processReturn("getFrameSize", mStream->getFrameSize(), size);
305}
306
307status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
308 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800309 if (mWriterClient == gettid() && mCommandMQ) {
310 return callWriterThread(
311 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
312 [&](const WriteStatus& writeStatus) {
313 *latency = writeStatus.reply.latencyMs;
314 });
315 } else {
316 return processReturn("getLatency", mStream->getLatency(), latency);
317 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800318}
319
320status_t StreamOutHalHidl::setVolume(float left, float right) {
321 if (mStream == 0) return NO_INIT;
322 return processReturn("setVolume", mStream->setVolume(left, right));
323}
324
325status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
326 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800327 *written = 0;
328
329 if (bytes == 0 && !mDataMQ) {
330 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
331 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
332 return OK;
333 }
334
335 status_t status;
Mikhail Naganov10fd0562017-08-01 17:20:24 -0700336 if (!mDataMQ) {
337 // In case if playback starts close to the end of a compressed track, the bytes
338 // that need to be written is less than the actual buffer size. Need to use
339 // full buffer size for the MQ since otherwise after seeking back to the middle
340 // data will be truncated.
341 size_t bufferSize;
342 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
343 return status;
344 }
345 if (bytes > bufferSize) bufferSize = bytes;
346 if ((status = prepareForWriting(bufferSize)) != OK) {
347 return status;
348 }
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800349 }
350
Andy Hung953608f2017-06-13 15:21:49 -0700351 status = callWriterThread(
Mikhail Naganovc8381902017-01-31 13:56:25 -0800352 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
353 [&] (const WriteStatus& writeStatus) {
354 *written = writeStatus.reply.written;
Mikhail Naganovd15f1272017-02-28 09:10:43 -0800355 // Diagnostics of the cause of b/35813113.
356 ALOGE_IF(*written > bytes,
357 "hal reports more bytes written than asked for: %lld > %lld",
358 (long long)*written, (long long)bytes);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800359 });
Andy Hung953608f2017-06-13 15:21:49 -0700360 mStreamPowerLog.log(buffer, *written);
361 return status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800362}
363
364status_t StreamOutHalHidl::callWriterThread(
365 WriteCommand cmd, const char* cmdName,
366 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
367 if (!mCommandMQ->write(&cmd)) {
368 ALOGE("command message queue write failed for \"%s\"", cmdName);
369 return -EAGAIN;
370 }
371 if (data != nullptr) {
372 size_t availableToWrite = mDataMQ->availableToWrite();
373 if (dataSize > availableToWrite) {
Mikhail Naganovd15f1272017-02-28 09:10:43 -0800374 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
375 (long long)dataSize, (long long)availableToWrite);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800376 dataSize = availableToWrite;
377 }
378 if (!mDataMQ->write(data, dataSize)) {
379 ALOGE("data message queue write failed for \"%s\"", cmdName);
380 }
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800381 }
382 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
383
384 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
385 uint32_t efState = 0;
386retry:
Mikhail Naganovb4e77912017-02-15 10:23:09 -0800387 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800388 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800389 WriteStatus writeStatus;
390 writeStatus.retval = Result::NOT_INITIALIZED;
391 if (!mStatusMQ->read(&writeStatus)) {
392 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800393 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800394 if (writeStatus.retval == Result::OK) {
395 ret = OK;
396 callback(writeStatus);
397 } else {
398 ret = processReturn(cmdName, writeStatus.retval);
399 }
400 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800401 }
Mikhail Naganovd2ae9cd2017-03-03 09:15:01 -0800402 if (ret == -EAGAIN || ret == -EINTR) {
403 // Spurious wakeup. This normally retries no more than once.
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800404 goto retry;
405 }
406 return ret;
407}
408
409status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800410 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800411 std::unique_ptr<DataMQ> tempDataMQ;
412 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800413 Result retval;
Mikhail Naganov83f04272017-02-07 10:45:09 -0800414 pid_t halThreadPid, halThreadTid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800415 Return<void> ret = mStream->prepareForWriting(
Mikhail Naganov83f04272017-02-07 10:45:09 -0800416 1, bufferSize,
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800417 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800418 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800419 const DataMQ::Descriptor& dataMQ,
Mikhail Naganov83f04272017-02-07 10:45:09 -0800420 const StatusMQ::Descriptor& statusMQ,
421 const ThreadInfo& halThreadInfo) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800422 retval = r;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800423 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800424 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800425 tempDataMQ.reset(new DataMQ(dataMQ));
426 tempStatusMQ.reset(new StatusMQ(statusMQ));
427 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
428 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
429 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800430 halThreadPid = halThreadInfo.pid;
431 halThreadTid = halThreadInfo.tid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800432 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800433 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800434 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800435 return processReturn("prepareForWriting", ret, retval);
436 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800437 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
438 !tempDataMQ || !tempDataMQ->isValid() ||
439 !tempStatusMQ || !tempStatusMQ->isValid() ||
440 !mEfGroup) {
441 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
442 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
443 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800444 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
445 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
446 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
447 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
448 "Status message queue for writing is invalid");
449 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
450 return NO_INIT;
451 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800452 requestHalThreadPriority(halThreadPid, halThreadTid);
453
Mikhail Naganovc8381902017-01-31 13:56:25 -0800454 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800455 mDataMQ = std::move(tempDataMQ);
456 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800457 mWriterClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800458 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800459}
460
461status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
462 if (mStream == 0) return NO_INIT;
463 Result retval;
464 Return<void> ret = mStream->getRenderPosition(
465 [&](Result r, uint32_t d) {
466 retval = r;
467 if (retval == Result::OK) {
468 *dspFrames = d;
469 }
470 });
471 return processReturn("getRenderPosition", ret, retval);
472}
473
474status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
475 if (mStream == 0) return NO_INIT;
476 Result retval;
477 Return<void> ret = mStream->getNextWriteTimestamp(
478 [&](Result r, int64_t t) {
479 retval = r;
480 if (retval == Result::OK) {
481 *timestamp = t;
482 }
483 });
484 return processReturn("getRenderPosition", ret, retval);
485}
486
487status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
488 if (mStream == 0) return NO_INIT;
489 status_t status = processReturn(
490 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
491 if (status == OK) {
492 mCallback = callback;
493 }
494 return status;
495}
496
497status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
498 if (mStream == 0) return NO_INIT;
499 Return<void> ret = mStream->supportsPauseAndResume(
500 [&](bool p, bool r) {
501 *supportsPause = p;
502 *supportsResume = r;
503 });
504 return processReturn("supportsPauseAndResume", ret);
505}
506
507status_t StreamOutHalHidl::pause() {
508 if (mStream == 0) return NO_INIT;
509 return processReturn("pause", mStream->pause());
510}
511
512status_t StreamOutHalHidl::resume() {
513 if (mStream == 0) return NO_INIT;
514 return processReturn("pause", mStream->resume());
515}
516
517status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
518 if (mStream == 0) return NO_INIT;
519 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
520}
521
522status_t StreamOutHalHidl::drain(bool earlyNotify) {
523 if (mStream == 0) return NO_INIT;
524 return processReturn(
525 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
526}
527
528status_t StreamOutHalHidl::flush() {
529 if (mStream == 0) return NO_INIT;
530 return processReturn("pause", mStream->flush());
531}
532
533status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
534 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800535 if (mWriterClient == gettid() && mCommandMQ) {
536 return callWriterThread(
537 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
538 [&](const WriteStatus& writeStatus) {
539 *frames = writeStatus.reply.presentationPosition.frames;
540 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
541 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
542 });
543 } else {
544 Result retval;
545 Return<void> ret = mStream->getPresentationPosition(
546 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
547 retval = r;
548 if (retval == Result::OK) {
549 *frames = hidlFrames;
550 timestamp->tv_sec = hidlTimeStamp.tvSec;
551 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
552 }
553 });
554 return processReturn("getPresentationPosition", ret, retval);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800555 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800556}
557
558void StreamOutHalHidl::onWriteReady() {
559 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
560 if (callback == 0) return;
561 ALOGV("asyncCallback onWriteReady");
562 callback->onWriteReady();
563}
564
565void StreamOutHalHidl::onDrainReady() {
566 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
567 if (callback == 0) return;
568 ALOGV("asyncCallback onDrainReady");
569 callback->onDrainReady();
570}
571
572void StreamOutHalHidl::onError() {
573 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
574 if (callback == 0) return;
575 ALOGV("asyncCallback onError");
576 callback->onError();
577}
578
579
580StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
Mikhail Naganovc8381902017-01-31 13:56:25 -0800581 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800582}
583
584StreamInHalHidl::~StreamInHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800585 if (mStream != 0) {
586 processReturn("close", mStream->close());
Mikhail Naganov23feba22017-02-23 11:00:55 -0800587 mStream.clear();
588 hardware::IPCThreadState::self()->flushCommands();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800589 }
590 if (mEfGroup) {
591 EventFlag::deleteEventFlag(&mEfGroup);
592 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800593}
594
595status_t StreamInHalHidl::getFrameSize(size_t *size) {
596 if (mStream == 0) return NO_INIT;
597 return processReturn("getFrameSize", mStream->getFrameSize(), size);
598}
599
600status_t StreamInHalHidl::setGain(float gain) {
601 if (mStream == 0) return NO_INIT;
602 return processReturn("setGain", mStream->setGain(gain));
603}
604
605status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
606 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800607 *read = 0;
608
609 if (bytes == 0 && !mDataMQ) {
610 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
611 return OK;
612 }
613
614 status_t status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800615 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
616 return status;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800617 }
618
Mikhail Naganovc8381902017-01-31 13:56:25 -0800619 ReadParameters params;
620 params.command = ReadCommand::READ;
621 params.params.read = bytes;
Andy Hung953608f2017-06-13 15:21:49 -0700622 status = callReaderThread(params, "read",
Mikhail Naganovc8381902017-01-31 13:56:25 -0800623 [&](const ReadStatus& readStatus) {
624 const size_t availToRead = mDataMQ->availableToRead();
625 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
626 ALOGE("data message queue read failed for \"read\"");
627 }
628 ALOGW_IF(availToRead != readStatus.reply.read,
629 "HAL read report inconsistent: mq = %d, status = %d",
630 (int32_t)availToRead, (int32_t)readStatus.reply.read);
631 *read = readStatus.reply.read;
632 });
Andy Hung953608f2017-06-13 15:21:49 -0700633 mStreamPowerLog.log(buffer, *read);
634 return status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800635}
636
637status_t StreamInHalHidl::callReaderThread(
638 const ReadParameters& params, const char* cmdName,
639 StreamInHalHidl::ReaderCallback callback) {
640 if (!mCommandMQ->write(&params)) {
641 ALOGW("command message queue write failed");
642 return -EAGAIN;
643 }
644 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
645
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800646 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
647 uint32_t efState = 0;
648retry:
Mikhail Naganovb4e77912017-02-15 10:23:09 -0800649 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800650 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800651 ReadStatus readStatus;
652 readStatus.retval = Result::NOT_INITIALIZED;
653 if (!mStatusMQ->read(&readStatus)) {
654 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800655 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800656 if (readStatus.retval == Result::OK) {
657 ret = OK;
658 callback(readStatus);
659 } else {
660 ret = processReturn(cmdName, readStatus.retval);
661 }
662 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800663 }
Mikhail Naganovd2ae9cd2017-03-03 09:15:01 -0800664 if (ret == -EAGAIN || ret == -EINTR) {
665 // Spurious wakeup. This normally retries no more than once.
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800666 goto retry;
667 }
668 return ret;
669}
670
671status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800672 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800673 std::unique_ptr<DataMQ> tempDataMQ;
674 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800675 Result retval;
Mikhail Naganov83f04272017-02-07 10:45:09 -0800676 pid_t halThreadPid, halThreadTid;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800677 Return<void> ret = mStream->prepareForReading(
Mikhail Naganov83f04272017-02-07 10:45:09 -0800678 1, bufferSize,
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800679 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800680 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800681 const DataMQ::Descriptor& dataMQ,
Mikhail Naganov83f04272017-02-07 10:45:09 -0800682 const StatusMQ::Descriptor& statusMQ,
683 const ThreadInfo& halThreadInfo) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800684 retval = r;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800685 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800686 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800687 tempDataMQ.reset(new DataMQ(dataMQ));
688 tempStatusMQ.reset(new StatusMQ(statusMQ));
689 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
690 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
691 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800692 halThreadPid = halThreadInfo.pid;
693 halThreadTid = halThreadInfo.tid;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800694 }
695 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800696 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800697 return processReturn("prepareForReading", ret, retval);
698 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800699 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
700 !tempDataMQ || !tempDataMQ->isValid() ||
701 !tempStatusMQ || !tempStatusMQ->isValid() ||
702 !mEfGroup) {
703 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
704 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
705 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800706 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
707 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
708 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
709 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
710 "Status message queue for reading is invalid");
711 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
712 return NO_INIT;
713 }
Mikhail Naganov83f04272017-02-07 10:45:09 -0800714 requestHalThreadPriority(halThreadPid, halThreadTid);
715
Mikhail Naganovc8381902017-01-31 13:56:25 -0800716 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800717 mDataMQ = std::move(tempDataMQ);
718 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800719 mReaderClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800720 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800721}
722
723status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
724 if (mStream == 0) return NO_INIT;
725 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
726}
727
728status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
729 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800730 if (mReaderClient == gettid() && mCommandMQ) {
731 ReadParameters params;
732 params.command = ReadCommand::GET_CAPTURE_POSITION;
733 return callReaderThread(params, "getCapturePosition",
734 [&](const ReadStatus& readStatus) {
735 *frames = readStatus.reply.capturePosition.frames;
736 *time = readStatus.reply.capturePosition.time;
737 });
738 } else {
739 Result retval;
740 Return<void> ret = mStream->getCapturePosition(
741 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
742 retval = r;
743 if (retval == Result::OK) {
744 *frames = hidlFrames;
745 *time = hidlTime;
746 }
747 });
748 return processReturn("getCapturePosition", ret, retval);
749 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800750}
751
752} // namespace android