blob: 5ac2d9af08225ca16f15a15a974a2c25d2d4a7f9 [file] [log] [blame]
Kevin Rocard4bcd67f2018-02-28 14:33:38 -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
Kevin Rocard070e7512018-05-22 09:29:13 -070020#include <android/hardware/audio/2.0/IStreamOutCallback.h>
Kevin Rocard51e076a2018-02-28 14:36:53 -080021#include <android/hardware/audio/4.0/IStreamOutCallback.h>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080022#include <hwbinder/IPCThreadState.h>
Mikhail Naganovac917ac2018-11-28 14:03:52 -080023#include <media/AudioParameter.h>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080024#include <mediautils/SchedulingPolicyService.h>
25#include <utils/Log.h>
26
27#include "DeviceHalHidl.h"
28#include "EffectHalHidl.h"
29#include "StreamHalHidl.h"
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080030#include "VersionUtils.h"
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080031
Kevin Rocard070e7512018-05-22 09:29:13 -070032using ::android::hardware::audio::common::CPP_VERSION::AudioChannelMask;
33using ::android::hardware::audio::common::CPP_VERSION::AudioFormat;
34using ::android::hardware::audio::common::CPP_VERSION::ThreadInfo;
35using ::android::hardware::audio::CPP_VERSION::AudioDrain;
36using ::android::hardware::audio::CPP_VERSION::IStreamOutCallback;
37using ::android::hardware::audio::CPP_VERSION::MessageQueueFlagBits;
38using ::android::hardware::audio::CPP_VERSION::MmapBufferInfo;
39using ::android::hardware::audio::CPP_VERSION::MmapPosition;
40using ::android::hardware::audio::CPP_VERSION::ParameterValue;
41using ::android::hardware::audio::CPP_VERSION::Result;
42using ::android::hardware::audio::CPP_VERSION::TimeSpec;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080043using ::android::hardware::MQDescriptorSync;
44using ::android::hardware::Return;
45using ::android::hardware::Void;
Kevin Rocard070e7512018-05-22 09:29:13 -070046using ReadCommand = ::android::hardware::audio::CPP_VERSION::IStreamIn::ReadCommand;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080047
Kevin Rocard070e7512018-05-22 09:29:13 -070048#if MAJOR_VERSION == 4
49using ::android::hardware::audio::common::CPP_VERSION::AudioContentType;
50using ::android::hardware::audio::common::CPP_VERSION::AudioSource;
51using ::android::hardware::audio::common::CPP_VERSION::AudioUsage;
52using ::android::hardware::audio::CPP_VERSION::MicrophoneInfo;
53using ::android::hardware::audio::CPP_VERSION::PlaybackTrackMetadata;
54using ::android::hardware::audio::CPP_VERSION::RecordTrackMetadata;
55#endif
Kevin Rocarddf9b4202018-05-10 19:56:08 -070056
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080057namespace android {
Kevin Rocard070e7512018-05-22 09:29:13 -070058namespace CPP_VERSION {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080059
60StreamHalHidl::StreamHalHidl(IStream *stream)
61 : ConversionHelperHidl("Stream"),
62 mStream(stream),
63 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
64 mCachedBufferSize(0){
65
66 // Instrument audio signal power logging.
67 // Note: This assumes channel mask, format, and sample rate do not change after creation.
68 if (mStream != nullptr && mStreamPowerLog.isUserDebugOrEngBuild()) {
69 // Obtain audio properties (see StreamHalHidl::getAudioProperties() below).
70 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080071 [&](auto sr, auto m, auto f) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080072 mStreamPowerLog.init(sr,
73 static_cast<audio_channel_mask_t>(m),
74 static_cast<audio_format_t>(f));
75 });
76 }
77}
78
79StreamHalHidl::~StreamHalHidl() {
80 mStream = nullptr;
81}
82
83status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
84 if (!mStream) return NO_INIT;
85 return processReturn("getSampleRate", mStream->getSampleRate(), rate);
86}
87
88status_t StreamHalHidl::getBufferSize(size_t *size) {
89 if (!mStream) return NO_INIT;
90 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
91 if (status == OK) {
92 mCachedBufferSize = *size;
93 }
94 return status;
95}
96
97status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
98 if (!mStream) return NO_INIT;
99 return processReturn("getChannelMask", mStream->getChannelMask(), mask);
100}
101
102status_t StreamHalHidl::getFormat(audio_format_t *format) {
103 if (!mStream) return NO_INIT;
104 return processReturn("getFormat", mStream->getFormat(), format);
105}
106
107status_t StreamHalHidl::getAudioProperties(
108 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
109 if (!mStream) return NO_INIT;
110 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800111 [&](uint32_t sr, auto m, auto f) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800112 *sampleRate = sr;
113 *mask = static_cast<audio_channel_mask_t>(m);
114 *format = static_cast<audio_format_t>(f);
115 });
116 return processReturn("getAudioProperties", ret);
117}
118
119status_t StreamHalHidl::setParameters(const String8& kvPairs) {
120 if (!mStream) return NO_INIT;
121 hidl_vec<ParameterValue> hidlParams;
122 status_t status = parametersFromHal(kvPairs, &hidlParams);
123 if (status != OK) return status;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800124 return processReturn("setParameters",
125 utils::setParameters(mStream, hidlParams, {} /* options */));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800126}
127
128status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
129 values->clear();
130 if (!mStream) return NO_INIT;
131 hidl_vec<hidl_string> hidlKeys;
132 status_t status = keysFromHal(keys, &hidlKeys);
133 if (status != OK) return status;
134 Result retval;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800135 Return<void> ret = utils::getParameters(
136 mStream,
137 {} /* context */,
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800138 hidlKeys,
139 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
140 retval = r;
141 if (retval == Result::OK) {
142 parametersToHal(parameters, values);
143 }
144 });
145 return processReturn("getParameters", ret, retval);
146}
147
148status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
149 if (!mStream) return NO_INIT;
150 return processReturn("addEffect", mStream->addEffect(
151 static_cast<EffectHalHidl*>(effect.get())->effectId()));
152}
153
154status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
155 if (!mStream) return NO_INIT;
156 return processReturn("removeEffect", mStream->removeEffect(
157 static_cast<EffectHalHidl*>(effect.get())->effectId()));
158}
159
160status_t StreamHalHidl::standby() {
161 if (!mStream) return NO_INIT;
162 return processReturn("standby", mStream->standby());
163}
164
165status_t StreamHalHidl::dump(int fd) {
166 if (!mStream) return NO_INIT;
167 native_handle_t* hidlHandle = native_handle_create(1, 0);
168 hidlHandle->data[0] = fd;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800169 Return<void> ret = mStream->debug(hidlHandle, {} /* options */);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800170 native_handle_delete(hidlHandle);
171 mStreamPowerLog.dump(fd);
172 return processReturn("dump", ret);
173}
174
175status_t StreamHalHidl::start() {
176 if (!mStream) return NO_INIT;
177 return processReturn("start", mStream->start());
178}
179
180status_t StreamHalHidl::stop() {
181 if (!mStream) return NO_INIT;
182 return processReturn("stop", mStream->stop());
183}
184
185status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
186 struct audio_mmap_buffer_info *info) {
187 Result retval;
188 Return<void> ret = mStream->createMmapBuffer(
189 minSizeFrames,
190 [&](Result r, const MmapBufferInfo& hidlInfo) {
191 retval = r;
192 if (retval == Result::OK) {
193 const native_handle *handle = hidlInfo.sharedMemory.handle();
194 if (handle->numFds > 0) {
195 info->shared_memory_fd = handle->data[0];
Kevin Rocard734334f2018-07-12 19:37:41 -0700196#if MAJOR_VERSION == 4
197 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
198#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800199 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700200 // Negative buffer size frame was a hack in O and P to
201 // indicate that the buffer is shareable to applications
202 if (info->buffer_size_frames < 0) {
203 info->buffer_size_frames *= -1;
204 info->flags = audio_mmap_buffer_flag(
205 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
206 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800207 info->burst_size_frames = hidlInfo.burstSizeFrames;
208 // info->shared_memory_address is not needed in HIDL context
209 info->shared_memory_address = NULL;
210 } else {
211 retval = Result::NOT_INITIALIZED;
212 }
213 }
214 });
215 return processReturn("createMmapBuffer", ret, retval);
216}
217
218status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
219 Result retval;
220 Return<void> ret = mStream->getMmapPosition(
221 [&](Result r, const MmapPosition& hidlPosition) {
222 retval = r;
223 if (retval == Result::OK) {
224 position->time_nanoseconds = hidlPosition.timeNanoseconds;
225 position->position_frames = hidlPosition.positionFrames;
226 }
227 });
228 return processReturn("getMmapPosition", ret, retval);
229}
230
231status_t StreamHalHidl::setHalThreadPriority(int priority) {
232 mHalThreadPriority = priority;
233 return OK;
234}
235
236status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
237 if (mCachedBufferSize != 0) {
238 *size = mCachedBufferSize;
239 return OK;
240 }
241 return getBufferSize(size);
242}
243
244bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
245 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
246 return true;
247 }
248 int err = requestPriority(
249 threadPid, threadId,
250 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
251 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
252 mHalThreadPriority, threadPid, threadId, err);
253 // Audio will still work, but latency will be higher and sometimes unacceptable.
254 return err == 0;
255}
256
257namespace {
258
259/* Notes on callback ownership.
260
261This is how (Hw)Binder ownership model looks like. The server implementation
262is owned by Binder framework (via sp<>). Proxies are owned by clients.
263When the last proxy disappears, Binder framework releases the server impl.
264
265Thus, it is not needed to keep any references to StreamOutCallback (this is
266the server impl) -- it will live as long as HAL server holds a strong ref to
267IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
268from the destructor of StreamOutHalHidl.
269
270The callback only keeps a weak reference to the stream. The stream is owned
271by AudioFlinger.
272
273*/
274
275struct StreamOutCallback : public IStreamOutCallback {
276 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
277
278 // IStreamOutCallback implementation
279 Return<void> onWriteReady() override {
280 sp<StreamOutHalHidl> stream = mStream.promote();
281 if (stream != 0) {
282 stream->onWriteReady();
283 }
284 return Void();
285 }
286
287 Return<void> onDrainReady() override {
288 sp<StreamOutHalHidl> stream = mStream.promote();
289 if (stream != 0) {
290 stream->onDrainReady();
291 }
292 return Void();
293 }
294
295 Return<void> onError() override {
296 sp<StreamOutHalHidl> stream = mStream.promote();
297 if (stream != 0) {
298 stream->onError();
299 }
300 return Void();
301 }
302
303 private:
304 wp<StreamOutHalHidl> mStream;
305};
306
307} // namespace
308
309StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
310 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
311}
312
313StreamOutHalHidl::~StreamOutHalHidl() {
314 if (mStream != 0) {
315 if (mCallback.unsafe_get()) {
316 processReturn("clearCallback", mStream->clearCallback());
317 }
318 processReturn("close", mStream->close());
319 mStream.clear();
320 }
321 mCallback.clear();
322 hardware::IPCThreadState::self()->flushCommands();
323 if (mEfGroup) {
324 EventFlag::deleteEventFlag(&mEfGroup);
325 }
326}
327
328status_t StreamOutHalHidl::getFrameSize(size_t *size) {
329 if (mStream == 0) return NO_INIT;
330 return processReturn("getFrameSize", mStream->getFrameSize(), size);
331}
332
333status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
334 if (mStream == 0) return NO_INIT;
335 if (mWriterClient == gettid() && mCommandMQ) {
336 return callWriterThread(
337 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
338 [&](const WriteStatus& writeStatus) {
339 *latency = writeStatus.reply.latencyMs;
340 });
341 } else {
342 return processReturn("getLatency", mStream->getLatency(), latency);
343 }
344}
345
346status_t StreamOutHalHidl::setVolume(float left, float right) {
347 if (mStream == 0) return NO_INIT;
348 return processReturn("setVolume", mStream->setVolume(left, right));
349}
350
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800351#if MAJOR_VERSION == 2
352status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
353 if (mStream == 0) return NO_INIT;
354 std::vector<ParameterValue> parameters;
355 String8 halParameters;
356 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
357 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
358 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
359 return setParameters(halParameters);
360}
361#elif MAJOR_VERSION == 4
362status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
363 if (mStream == 0) return NO_INIT;
364 return processReturn("selectPresentation",
365 mStream->selectPresentation(presentationId, programId));
366}
367#endif
368
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800369status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
370 if (mStream == 0) return NO_INIT;
371 *written = 0;
372
373 if (bytes == 0 && !mDataMQ) {
374 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
375 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
376 return OK;
377 }
378
379 status_t status;
380 if (!mDataMQ) {
381 // In case if playback starts close to the end of a compressed track, the bytes
382 // that need to be written is less than the actual buffer size. Need to use
383 // full buffer size for the MQ since otherwise after seeking back to the middle
384 // data will be truncated.
385 size_t bufferSize;
386 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
387 return status;
388 }
389 if (bytes > bufferSize) bufferSize = bytes;
390 if ((status = prepareForWriting(bufferSize)) != OK) {
391 return status;
392 }
393 }
394
395 status = callWriterThread(
396 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
397 [&] (const WriteStatus& writeStatus) {
398 *written = writeStatus.reply.written;
399 // Diagnostics of the cause of b/35813113.
400 ALOGE_IF(*written > bytes,
401 "hal reports more bytes written than asked for: %lld > %lld",
402 (long long)*written, (long long)bytes);
403 });
404 mStreamPowerLog.log(buffer, *written);
405 return status;
406}
407
408status_t StreamOutHalHidl::callWriterThread(
409 WriteCommand cmd, const char* cmdName,
410 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
411 if (!mCommandMQ->write(&cmd)) {
412 ALOGE("command message queue write failed for \"%s\"", cmdName);
413 return -EAGAIN;
414 }
415 if (data != nullptr) {
416 size_t availableToWrite = mDataMQ->availableToWrite();
417 if (dataSize > availableToWrite) {
418 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
419 (long long)dataSize, (long long)availableToWrite);
420 dataSize = availableToWrite;
421 }
422 if (!mDataMQ->write(data, dataSize)) {
423 ALOGE("data message queue write failed for \"%s\"", cmdName);
424 }
425 }
426 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
427
428 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
429 uint32_t efState = 0;
430retry:
431 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
432 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
433 WriteStatus writeStatus;
434 writeStatus.retval = Result::NOT_INITIALIZED;
435 if (!mStatusMQ->read(&writeStatus)) {
436 ALOGE("status message read failed for \"%s\"", cmdName);
437 }
438 if (writeStatus.retval == Result::OK) {
439 ret = OK;
440 callback(writeStatus);
441 } else {
442 ret = processReturn(cmdName, writeStatus.retval);
443 }
444 return ret;
445 }
446 if (ret == -EAGAIN || ret == -EINTR) {
447 // Spurious wakeup. This normally retries no more than once.
448 goto retry;
449 }
450 return ret;
451}
452
453status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
454 std::unique_ptr<CommandMQ> tempCommandMQ;
455 std::unique_ptr<DataMQ> tempDataMQ;
456 std::unique_ptr<StatusMQ> tempStatusMQ;
457 Result retval;
458 pid_t halThreadPid, halThreadTid;
459 Return<void> ret = mStream->prepareForWriting(
460 1, bufferSize,
461 [&](Result r,
462 const CommandMQ::Descriptor& commandMQ,
463 const DataMQ::Descriptor& dataMQ,
464 const StatusMQ::Descriptor& statusMQ,
465 const ThreadInfo& halThreadInfo) {
466 retval = r;
467 if (retval == Result::OK) {
468 tempCommandMQ.reset(new CommandMQ(commandMQ));
469 tempDataMQ.reset(new DataMQ(dataMQ));
470 tempStatusMQ.reset(new StatusMQ(statusMQ));
471 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
472 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
473 }
474 halThreadPid = halThreadInfo.pid;
475 halThreadTid = halThreadInfo.tid;
476 }
477 });
478 if (!ret.isOk() || retval != Result::OK) {
479 return processReturn("prepareForWriting", ret, retval);
480 }
481 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
482 !tempDataMQ || !tempDataMQ->isValid() ||
483 !tempStatusMQ || !tempStatusMQ->isValid() ||
484 !mEfGroup) {
485 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
486 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
487 "Command message queue for writing is invalid");
488 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
489 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
490 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
491 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
492 "Status message queue for writing is invalid");
493 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
494 return NO_INIT;
495 }
496 requestHalThreadPriority(halThreadPid, halThreadTid);
497
498 mCommandMQ = std::move(tempCommandMQ);
499 mDataMQ = std::move(tempDataMQ);
500 mStatusMQ = std::move(tempStatusMQ);
501 mWriterClient = gettid();
502 return OK;
503}
504
505status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
506 if (mStream == 0) return NO_INIT;
507 Result retval;
508 Return<void> ret = mStream->getRenderPosition(
509 [&](Result r, uint32_t d) {
510 retval = r;
511 if (retval == Result::OK) {
512 *dspFrames = d;
513 }
514 });
515 return processReturn("getRenderPosition", ret, retval);
516}
517
518status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
519 if (mStream == 0) return NO_INIT;
520 Result retval;
521 Return<void> ret = mStream->getNextWriteTimestamp(
522 [&](Result r, int64_t t) {
523 retval = r;
524 if (retval == Result::OK) {
525 *timestamp = t;
526 }
527 });
528 return processReturn("getRenderPosition", ret, retval);
529}
530
531status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
532 if (mStream == 0) return NO_INIT;
533 status_t status = processReturn(
534 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
535 if (status == OK) {
536 mCallback = callback;
537 }
538 return status;
539}
540
541status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
542 if (mStream == 0) return NO_INIT;
543 Return<void> ret = mStream->supportsPauseAndResume(
544 [&](bool p, bool r) {
545 *supportsPause = p;
546 *supportsResume = r;
547 });
548 return processReturn("supportsPauseAndResume", ret);
549}
550
551status_t StreamOutHalHidl::pause() {
552 if (mStream == 0) return NO_INIT;
553 return processReturn("pause", mStream->pause());
554}
555
556status_t StreamOutHalHidl::resume() {
557 if (mStream == 0) return NO_INIT;
558 return processReturn("pause", mStream->resume());
559}
560
561status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
562 if (mStream == 0) return NO_INIT;
563 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
564}
565
566status_t StreamOutHalHidl::drain(bool earlyNotify) {
567 if (mStream == 0) return NO_INIT;
568 return processReturn(
569 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
570}
571
572status_t StreamOutHalHidl::flush() {
573 if (mStream == 0) return NO_INIT;
574 return processReturn("pause", mStream->flush());
575}
576
577status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
578 if (mStream == 0) return NO_INIT;
579 if (mWriterClient == gettid() && mCommandMQ) {
580 return callWriterThread(
581 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
582 [&](const WriteStatus& writeStatus) {
583 *frames = writeStatus.reply.presentationPosition.frames;
584 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
585 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
586 });
587 } else {
588 Result retval;
589 Return<void> ret = mStream->getPresentationPosition(
590 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
591 retval = r;
592 if (retval == Result::OK) {
593 *frames = hidlFrames;
594 timestamp->tv_sec = hidlTimeStamp.tvSec;
595 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
596 }
597 });
598 return processReturn("getPresentationPosition", ret, retval);
599 }
600}
601
Kevin Rocard070e7512018-05-22 09:29:13 -0700602#if MAJOR_VERSION == 2
603status_t StreamOutHalHidl::updateSourceMetadata(const SourceMetadata& /* sourceMetadata */) {
604 // Audio HAL V2.0 does not support propagating source metadata
605 return INVALID_OPERATION;
606}
607#elif MAJOR_VERSION == 4
Kevin Rocarda8975a72018-03-27 10:16:52 -0700608/** Transform a standard collection to an HIDL vector. */
609template <class Values, class ElementConverter>
610static auto transformToHidlVec(const Values& values, ElementConverter converter) {
611 hidl_vec<decltype(converter(*values.begin()))> result{values.size()};
612 using namespace std;
613 transform(begin(values), end(values), begin(result), converter);
614 return result;
615}
616
617status_t StreamOutHalHidl::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700618 hardware::audio::CPP_VERSION::SourceMetadata halMetadata = {
Kevin Rocarda8975a72018-03-27 10:16:52 -0700619 .tracks = transformToHidlVec(sourceMetadata.tracks,
620 [](const playback_track_metadata& metadata) -> PlaybackTrackMetadata {
621 return {
622 .usage=static_cast<AudioUsage>(metadata.usage),
623 .contentType=static_cast<AudioContentType>(metadata.content_type),
624 .gain=metadata.gain,
625 };
626 })};
627 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(halMetadata));
628}
Kevin Rocard070e7512018-05-22 09:29:13 -0700629#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700630
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800631void StreamOutHalHidl::onWriteReady() {
632 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
633 if (callback == 0) return;
634 ALOGV("asyncCallback onWriteReady");
635 callback->onWriteReady();
636}
637
638void StreamOutHalHidl::onDrainReady() {
639 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
640 if (callback == 0) return;
641 ALOGV("asyncCallback onDrainReady");
642 callback->onDrainReady();
643}
644
645void StreamOutHalHidl::onError() {
646 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
647 if (callback == 0) return;
648 ALOGV("asyncCallback onError");
649 callback->onError();
650}
651
652
653StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
654 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
655}
656
657StreamInHalHidl::~StreamInHalHidl() {
658 if (mStream != 0) {
659 processReturn("close", mStream->close());
660 mStream.clear();
661 hardware::IPCThreadState::self()->flushCommands();
662 }
663 if (mEfGroup) {
664 EventFlag::deleteEventFlag(&mEfGroup);
665 }
666}
667
668status_t StreamInHalHidl::getFrameSize(size_t *size) {
669 if (mStream == 0) return NO_INIT;
670 return processReturn("getFrameSize", mStream->getFrameSize(), size);
671}
672
673status_t StreamInHalHidl::setGain(float gain) {
674 if (mStream == 0) return NO_INIT;
675 return processReturn("setGain", mStream->setGain(gain));
676}
677
678status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
679 if (mStream == 0) return NO_INIT;
680 *read = 0;
681
682 if (bytes == 0 && !mDataMQ) {
683 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
684 return OK;
685 }
686
687 status_t status;
688 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
689 return status;
690 }
691
692 ReadParameters params;
693 params.command = ReadCommand::READ;
694 params.params.read = bytes;
695 status = callReaderThread(params, "read",
696 [&](const ReadStatus& readStatus) {
697 const size_t availToRead = mDataMQ->availableToRead();
698 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
699 ALOGE("data message queue read failed for \"read\"");
700 }
701 ALOGW_IF(availToRead != readStatus.reply.read,
702 "HAL read report inconsistent: mq = %d, status = %d",
703 (int32_t)availToRead, (int32_t)readStatus.reply.read);
704 *read = readStatus.reply.read;
705 });
706 mStreamPowerLog.log(buffer, *read);
707 return status;
708}
709
710status_t StreamInHalHidl::callReaderThread(
711 const ReadParameters& params, const char* cmdName,
712 StreamInHalHidl::ReaderCallback callback) {
713 if (!mCommandMQ->write(&params)) {
714 ALOGW("command message queue write failed");
715 return -EAGAIN;
716 }
717 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
718
719 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
720 uint32_t efState = 0;
721retry:
722 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
723 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
724 ReadStatus readStatus;
725 readStatus.retval = Result::NOT_INITIALIZED;
726 if (!mStatusMQ->read(&readStatus)) {
727 ALOGE("status message read failed for \"%s\"", cmdName);
728 }
729 if (readStatus.retval == Result::OK) {
730 ret = OK;
731 callback(readStatus);
732 } else {
733 ret = processReturn(cmdName, readStatus.retval);
734 }
735 return ret;
736 }
737 if (ret == -EAGAIN || ret == -EINTR) {
738 // Spurious wakeup. This normally retries no more than once.
739 goto retry;
740 }
741 return ret;
742}
743
744status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
745 std::unique_ptr<CommandMQ> tempCommandMQ;
746 std::unique_ptr<DataMQ> tempDataMQ;
747 std::unique_ptr<StatusMQ> tempStatusMQ;
748 Result retval;
749 pid_t halThreadPid, halThreadTid;
750 Return<void> ret = mStream->prepareForReading(
751 1, bufferSize,
752 [&](Result r,
753 const CommandMQ::Descriptor& commandMQ,
754 const DataMQ::Descriptor& dataMQ,
755 const StatusMQ::Descriptor& statusMQ,
756 const ThreadInfo& halThreadInfo) {
757 retval = r;
758 if (retval == Result::OK) {
759 tempCommandMQ.reset(new CommandMQ(commandMQ));
760 tempDataMQ.reset(new DataMQ(dataMQ));
761 tempStatusMQ.reset(new StatusMQ(statusMQ));
762 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
763 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
764 }
765 halThreadPid = halThreadInfo.pid;
766 halThreadTid = halThreadInfo.tid;
767 }
768 });
769 if (!ret.isOk() || retval != Result::OK) {
770 return processReturn("prepareForReading", ret, retval);
771 }
772 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
773 !tempDataMQ || !tempDataMQ->isValid() ||
774 !tempStatusMQ || !tempStatusMQ->isValid() ||
775 !mEfGroup) {
776 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
777 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
778 "Command message queue for writing is invalid");
779 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
780 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
781 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
782 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
783 "Status message queue for reading is invalid");
784 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
785 return NO_INIT;
786 }
787 requestHalThreadPriority(halThreadPid, halThreadTid);
788
789 mCommandMQ = std::move(tempCommandMQ);
790 mDataMQ = std::move(tempDataMQ);
791 mStatusMQ = std::move(tempStatusMQ);
792 mReaderClient = gettid();
793 return OK;
794}
795
796status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
797 if (mStream == 0) return NO_INIT;
798 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
799}
800
801status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
802 if (mStream == 0) return NO_INIT;
803 if (mReaderClient == gettid() && mCommandMQ) {
804 ReadParameters params;
805 params.command = ReadCommand::GET_CAPTURE_POSITION;
806 return callReaderThread(params, "getCapturePosition",
807 [&](const ReadStatus& readStatus) {
808 *frames = readStatus.reply.capturePosition.frames;
809 *time = readStatus.reply.capturePosition.time;
810 });
811 } else {
812 Result retval;
813 Return<void> ret = mStream->getCapturePosition(
814 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
815 retval = r;
816 if (retval == Result::OK) {
817 *frames = hidlFrames;
818 *time = hidlTime;
819 }
820 });
821 return processReturn("getCapturePosition", ret, retval);
822 }
823}
824
Kevin Rocard070e7512018-05-22 09:29:13 -0700825#if MAJOR_VERSION == 2
826status_t StreamInHalHidl::getActiveMicrophones(
827 std::vector<media::MicrophoneInfo> *microphones __unused) {
828 if (mStream == 0) return NO_INIT;
829 return INVALID_OPERATION;
830}
831
832status_t StreamInHalHidl::updateSinkMetadata(const SinkMetadata& /* sinkMetadata */) {
833 // Audio HAL V2.0 does not support propagating sink metadata
834 return INVALID_OPERATION;
835}
836
837#elif MAJOR_VERSION == 4
jiabin9ff780e2018-03-19 18:19:52 -0700838status_t StreamInHalHidl::getActiveMicrophones(
839 std::vector<media::MicrophoneInfo> *microphonesInfo) {
840 if (!mStream) return NO_INIT;
841 Result retval;
842 Return<void> ret = mStream->getActiveMicrophones(
843 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
844 retval = r;
845 for (size_t k = 0; k < micArrayHal.size(); k++) {
846 audio_microphone_characteristic_t dst;
847 // convert
848 microphoneInfoToHal(micArrayHal[k], &dst);
849 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
850 microphonesInfo->push_back(microphone);
851 }
852 });
853 return processReturn("getActiveMicrophones", ret, retval);
854}
855
Kevin Rocarda8975a72018-03-27 10:16:52 -0700856status_t StreamInHalHidl::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700857 hardware::audio::CPP_VERSION::SinkMetadata halMetadata = {
Kevin Rocarda8975a72018-03-27 10:16:52 -0700858 .tracks = transformToHidlVec(sinkMetadata.tracks,
859 [](const record_track_metadata& metadata) -> RecordTrackMetadata {
860 return {
861 .source=static_cast<AudioSource>(metadata.source),
862 .gain=metadata.gain,
863 };
864 })};
865 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(halMetadata));
866}
Kevin Rocard070e7512018-05-22 09:29:13 -0700867#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700868
Kevin Rocard070e7512018-05-22 09:29:13 -0700869} // namespace CPP_VERSION
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800870} // namespace android