blob: 8ba0f728a6354436c0083c2ada971d871d27acd3 [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
Mikhail Naganov247b5f92021-01-15 19:16:12 +000020#include <android/hidl/manager/1.0/IServiceManager.h>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080021#include <hwbinder/IPCThreadState.h>
Mikhail Naganovac917ac2018-11-28 14:03:52 -080022#include <media/AudioParameter.h>
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -080023#include <mediautils/memory.h>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080024#include <mediautils/SchedulingPolicyService.h>
25#include <utils/Log.h>
26
Mikhail Naganov6718c392022-01-27 22:17:21 +000027#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamOutCallback.h)
Mikhail Naganov247b5f92021-01-15 19:16:12 +000028#include <HidlUtils.h>
29#include <util/CoreUtils.h>
30
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080031#include "DeviceHalHidl.h"
Mikhail Naganov247b5f92021-01-15 19:16:12 +000032#include "ParameterUtils.h"
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080033#include "StreamHalHidl.h"
34
Mikhail Naganov6718c392022-01-27 22:17:21 +000035using ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::implementation::HidlUtils;
36using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::implementation::CoreUtils;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080037using ::android::hardware::MQDescriptorSync;
38using ::android::hardware::Return;
39using ::android::hardware::Void;
Kevin Rocarddf9b4202018-05-10 19:56:08 -070040
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080041namespace android {
42
Mikhail Naganovaccbe8a2022-02-03 23:45:36 +000043using ReadCommand = ::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn::ReadCommand;
Mikhail Naganov9ccaa162018-12-12 10:27:29 -080044
Mikhail Naganov6718c392022-01-27 22:17:21 +000045using namespace ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION;
46using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION;
Mikhail Naganov9ccaa162018-12-12 10:27:29 -080047
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080048StreamHalHidl::StreamHalHidl(IStream *stream)
49 : ConversionHelperHidl("Stream"),
50 mStream(stream),
51 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
52 mCachedBufferSize(0){
53
54 // Instrument audio signal power logging.
55 // Note: This assumes channel mask, format, and sample rate do not change after creation.
Mikhail Naganov247b5f92021-01-15 19:16:12 +000056 audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
57 if (/* mStreamPowerLog.isUserDebugOrEngBuild() && */
Mikhail Naganov560637e2021-03-31 22:40:13 +000058 StreamHalHidl::getAudioProperties(&config) == NO_ERROR) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +000059 mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080060 }
61}
62
Andy Hungacb5b982021-01-20 10:12:00 -080063StreamHalHidl::~StreamHalHidl() {
64 // The last step is to flush all binder commands so that the deletion
65 // of IStreamIn / IStreamOut (mStream) is issued with less delay. See b/35394629.
66 hardware::IPCThreadState::self()->flushCommands();
67}
68
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080069status_t StreamHalHidl::getBufferSize(size_t *size) {
70 if (!mStream) return NO_INIT;
71 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
72 if (status == OK) {
73 mCachedBufferSize = *size;
74 }
75 return status;
76}
77
Mikhail Naganov560637e2021-03-31 22:40:13 +000078status_t StreamHalHidl::getAudioProperties(audio_config_base_t *configBase) {
79 *configBase = AUDIO_CONFIG_BASE_INITIALIZER;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080080 if (!mStream) return NO_INIT;
Mikhail Naganov247b5f92021-01-15 19:16:12 +000081#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080082 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080083 [&](uint32_t sr, auto m, auto f) {
Mikhail Naganov560637e2021-03-31 22:40:13 +000084 configBase->sample_rate = sr;
85 configBase->channel_mask = static_cast<audio_channel_mask_t>(m);
86 configBase->format = static_cast<audio_format_t>(f);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080087 });
88 return processReturn("getAudioProperties", ret);
Mikhail Naganov247b5f92021-01-15 19:16:12 +000089#else
90 Result retval;
91 status_t conversionStatus = BAD_VALUE;
Mikhail Naganov247b5f92021-01-15 19:16:12 +000092 Return<void> ret = mStream->getAudioProperties(
93 [&](Result r, const AudioConfigBase& config) {
94 retval = r;
95 if (retval == Result::OK) {
Mikhail Naganov560637e2021-03-31 22:40:13 +000096 conversionStatus = HidlUtils::audioConfigBaseToHal(config, configBase);
Mikhail Naganov247b5f92021-01-15 19:16:12 +000097 }
98 });
99 if (status_t status = processReturn("getAudioProperties", ret, retval); status == NO_ERROR) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000100 return conversionStatus;
101 } else {
102 return status;
103 }
104#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800105}
106
107status_t StreamHalHidl::setParameters(const String8& kvPairs) {
108 if (!mStream) return NO_INIT;
109 hidl_vec<ParameterValue> hidlParams;
110 status_t status = parametersFromHal(kvPairs, &hidlParams);
111 if (status != OK) return status;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800112 return processReturn("setParameters",
Dean Wheatley7b417a22019-01-31 20:39:42 +1100113 utils::setParameters(mStream, {} /* context */, hidlParams));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800114}
115
116status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
117 values->clear();
118 if (!mStream) return NO_INIT;
119 hidl_vec<hidl_string> hidlKeys;
120 status_t status = keysFromHal(keys, &hidlKeys);
121 if (status != OK) return status;
122 Result retval;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800123 Return<void> ret = utils::getParameters(
124 mStream,
125 {} /* context */,
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800126 hidlKeys,
127 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
128 retval = r;
129 if (retval == Result::OK) {
130 parametersToHal(parameters, values);
131 }
132 });
133 return processReturn("getParameters", ret, retval);
134}
135
136status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
137 if (!mStream) return NO_INIT;
Mikhail Naganov6718c392022-01-27 22:17:21 +0000138 return processReturn("addEffect", mStream->addEffect(effect->effectId()));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800139}
140
141status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
142 if (!mStream) return NO_INIT;
Mikhail Naganov6718c392022-01-27 22:17:21 +0000143 return processReturn("removeEffect", mStream->removeEffect(effect->effectId()));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800144}
145
146status_t StreamHalHidl::standby() {
147 if (!mStream) return NO_INIT;
148 return processReturn("standby", mStream->standby());
149}
150
Andy Hung61589a42021-06-16 09:37:53 -0700151status_t StreamHalHidl::dump(int fd, const Vector<String16>& args) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800152 if (!mStream) return NO_INIT;
153 native_handle_t* hidlHandle = native_handle_create(1, 0);
154 hidlHandle->data[0] = fd;
Andy Hung61589a42021-06-16 09:37:53 -0700155 hidl_vec<hidl_string> hidlArgs;
156 argsFromHal(args, &hidlArgs);
157 Return<void> ret = mStream->debug(hidlHandle, hidlArgs);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800158 native_handle_delete(hidlHandle);
Andy Hunge72ff022021-08-16 10:16:15 -0700159
160 // TODO(b/111997867, b/177271958) Workaround - remove when fixed.
161 // A Binder transmitted fd may not close immediately due to a race condition b/111997867
162 // when the remote binder thread removes the last refcount to the fd blocks in the
163 // kernel for binder activity. We send a Binder ping() command to unblock the thread
164 // and complete the fd close / release.
165 //
166 // See DeviceHalHidl::dump(), EffectHalHidl::dump(), StreamHalHidl::dump(),
167 // EffectsFactoryHalHidl::dumpEffects().
168
169 (void)mStream->ping(); // synchronous Binder call
170
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800171 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 Rocard3d48dce2018-11-08 17:16:57 -0800196#if MAJOR_VERSION >= 4
Kevin Rocard734334f2018-07-12 19:37:41 -0700197 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
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000244status_t StreamHalHidl::getHalPid(pid_t *pid) {
245 using ::android::hidl::base::V1_0::DebugInfo;
246 using ::android::hidl::manager::V1_0::IServiceManager;
247
248 DebugInfo debugInfo;
249 auto ret = mStream->getDebugInfo([&] (const auto &info) {
250 debugInfo = info;
251 });
252 if (!ret.isOk()) {
253 return INVALID_OPERATION;
254 }
255 if (debugInfo.pid != (int)IServiceManager::PidConstant::NO_PID) {
256 *pid = debugInfo.pid;
257 return NO_ERROR;
258 }
259 return NAME_NOT_FOUND;
260}
261
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800262bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
263 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
264 return true;
265 }
266 int err = requestPriority(
267 threadPid, threadId,
268 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
269 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
270 mHalThreadPriority, threadPid, threadId, err);
271 // Audio will still work, but latency will be higher and sometimes unacceptable.
272 return err == 0;
273}
274
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800275status_t StreamHalHidl::legacyCreateAudioPatch(const struct audio_port_config& port,
276 std::optional<audio_source_t> source,
277 audio_devices_t type) {
278 LOG_ALWAYS_FATAL_IF(port.type != AUDIO_PORT_TYPE_DEVICE, "port type must be device");
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800279 unique_malloced_ptr<char> address;
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800280 if (strcmp(port.ext.device.address, "") != 0) {
281 // FIXME: we only support address on first sink with HAL version < 3.0
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800282 address.reset(
283 audio_device_address_to_parameter(port.ext.device.type, port.ext.device.address));
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800284 } else {
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800285 address.reset((char*)calloc(1, 1));
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800286 }
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800287 AudioParameter param = AudioParameter(String8(address.get()));
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800288 param.addInt(String8(AudioParameter::keyRouting), (int)type);
289 if (source.has_value()) {
290 param.addInt(String8(AudioParameter::keyInputSource), (int)source.value());
291 }
292 return setParameters(param.toString());
293}
294
295status_t StreamHalHidl::legacyReleaseAudioPatch() {
296 AudioParameter param;
297 param.addInt(String8(AudioParameter::keyRouting), 0);
298 return setParameters(param.toString());
299}
300
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800301namespace {
302
303/* Notes on callback ownership.
304
305This is how (Hw)Binder ownership model looks like. The server implementation
306is owned by Binder framework (via sp<>). Proxies are owned by clients.
307When the last proxy disappears, Binder framework releases the server impl.
308
309Thus, it is not needed to keep any references to StreamOutCallback (this is
310the server impl) -- it will live as long as HAL server holds a strong ref to
311IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
312from the destructor of StreamOutHalHidl.
313
314The callback only keeps a weak reference to the stream. The stream is owned
315by AudioFlinger.
316
317*/
318
319struct StreamOutCallback : public IStreamOutCallback {
320 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
321
322 // IStreamOutCallback implementation
323 Return<void> onWriteReady() override {
324 sp<StreamOutHalHidl> stream = mStream.promote();
325 if (stream != 0) {
326 stream->onWriteReady();
327 }
328 return Void();
329 }
330
331 Return<void> onDrainReady() override {
332 sp<StreamOutHalHidl> stream = mStream.promote();
333 if (stream != 0) {
334 stream->onDrainReady();
335 }
336 return Void();
337 }
338
339 Return<void> onError() override {
340 sp<StreamOutHalHidl> stream = mStream.promote();
341 if (stream != 0) {
342 stream->onError();
343 }
344 return Void();
345 }
346
347 private:
Andy Hung638f45b2021-01-18 20:02:56 -0800348 const wp<StreamOutHalHidl> mStream;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800349};
350
351} // namespace
352
Mikhail Naganov6718c392022-01-27 22:17:21 +0000353StreamOutHalHidl::StreamOutHalHidl(
354 const sp<::android::hardware::audio::CPP_VERSION::IStreamOut>& stream)
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800355 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
356}
357
358StreamOutHalHidl::~StreamOutHalHidl() {
359 if (mStream != 0) {
Andy Hung638f45b2021-01-18 20:02:56 -0800360 if (mCallback.load().unsafe_get()) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800361 processReturn("clearCallback", mStream->clearCallback());
362 }
jiabinf6eb4c32020-02-25 14:06:25 -0800363#if MAJOR_VERSION >= 6
Andy Hung638f45b2021-01-18 20:02:56 -0800364 if (mEventCallback.load().unsafe_get() != nullptr) {
jiabinf6eb4c32020-02-25 14:06:25 -0800365 processReturn("setEventCallback",
366 mStream->setEventCallback(nullptr));
367 }
368#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800369 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800370 }
Andy Hung638f45b2021-01-18 20:02:56 -0800371 mCallback = nullptr;
372 mEventCallback = nullptr;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800373 if (mEfGroup) {
374 EventFlag::deleteEventFlag(&mEfGroup);
375 }
376}
377
378status_t StreamOutHalHidl::getFrameSize(size_t *size) {
379 if (mStream == 0) return NO_INIT;
380 return processReturn("getFrameSize", mStream->getFrameSize(), size);
381}
382
383status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
384 if (mStream == 0) return NO_INIT;
385 if (mWriterClient == gettid() && mCommandMQ) {
386 return callWriterThread(
387 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
388 [&](const WriteStatus& writeStatus) {
389 *latency = writeStatus.reply.latencyMs;
390 });
391 } else {
392 return processReturn("getLatency", mStream->getLatency(), latency);
393 }
394}
395
396status_t StreamOutHalHidl::setVolume(float left, float right) {
397 if (mStream == 0) return NO_INIT;
398 return processReturn("setVolume", mStream->setVolume(left, right));
399}
400
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800401#if MAJOR_VERSION == 2
402status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
403 if (mStream == 0) return NO_INIT;
404 std::vector<ParameterValue> parameters;
405 String8 halParameters;
406 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
407 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
408 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
409 return setParameters(halParameters);
410}
Kevin Rocard1cf6b4d2018-11-20 18:05:44 -0800411#elif MAJOR_VERSION >= 4
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800412status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
413 if (mStream == 0) return NO_INIT;
414 return processReturn("selectPresentation",
415 mStream->selectPresentation(presentationId, programId));
416}
417#endif
418
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800419status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
420 if (mStream == 0) return NO_INIT;
421 *written = 0;
422
423 if (bytes == 0 && !mDataMQ) {
424 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
Andy Hung638f45b2021-01-18 20:02:56 -0800425 ALOGW_IF(mCallback.load().unsafe_get(), "First call to async write with 0 bytes");
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800426 return OK;
427 }
428
429 status_t status;
430 if (!mDataMQ) {
431 // In case if playback starts close to the end of a compressed track, the bytes
432 // that need to be written is less than the actual buffer size. Need to use
433 // full buffer size for the MQ since otherwise after seeking back to the middle
434 // data will be truncated.
435 size_t bufferSize;
436 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
437 return status;
438 }
439 if (bytes > bufferSize) bufferSize = bytes;
440 if ((status = prepareForWriting(bufferSize)) != OK) {
441 return status;
442 }
443 }
444
445 status = callWriterThread(
446 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
447 [&] (const WriteStatus& writeStatus) {
448 *written = writeStatus.reply.written;
449 // Diagnostics of the cause of b/35813113.
450 ALOGE_IF(*written > bytes,
451 "hal reports more bytes written than asked for: %lld > %lld",
452 (long long)*written, (long long)bytes);
453 });
454 mStreamPowerLog.log(buffer, *written);
455 return status;
456}
457
458status_t StreamOutHalHidl::callWriterThread(
459 WriteCommand cmd, const char* cmdName,
460 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
461 if (!mCommandMQ->write(&cmd)) {
462 ALOGE("command message queue write failed for \"%s\"", cmdName);
463 return -EAGAIN;
464 }
465 if (data != nullptr) {
466 size_t availableToWrite = mDataMQ->availableToWrite();
467 if (dataSize > availableToWrite) {
468 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
469 (long long)dataSize, (long long)availableToWrite);
470 dataSize = availableToWrite;
471 }
472 if (!mDataMQ->write(data, dataSize)) {
473 ALOGE("data message queue write failed for \"%s\"", cmdName);
474 }
475 }
476 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
477
478 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
479 uint32_t efState = 0;
480retry:
481 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
482 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
483 WriteStatus writeStatus;
484 writeStatus.retval = Result::NOT_INITIALIZED;
485 if (!mStatusMQ->read(&writeStatus)) {
486 ALOGE("status message read failed for \"%s\"", cmdName);
487 }
488 if (writeStatus.retval == Result::OK) {
489 ret = OK;
490 callback(writeStatus);
491 } else {
492 ret = processReturn(cmdName, writeStatus.retval);
493 }
494 return ret;
495 }
496 if (ret == -EAGAIN || ret == -EINTR) {
497 // Spurious wakeup. This normally retries no more than once.
498 goto retry;
499 }
500 return ret;
501}
502
503status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
504 std::unique_ptr<CommandMQ> tempCommandMQ;
505 std::unique_ptr<DataMQ> tempDataMQ;
506 std::unique_ptr<StatusMQ> tempStatusMQ;
507 Result retval;
508 pid_t halThreadPid, halThreadTid;
509 Return<void> ret = mStream->prepareForWriting(
510 1, bufferSize,
511 [&](Result r,
512 const CommandMQ::Descriptor& commandMQ,
513 const DataMQ::Descriptor& dataMQ,
514 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000515 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800516 retval = r;
517 if (retval == Result::OK) {
518 tempCommandMQ.reset(new CommandMQ(commandMQ));
519 tempDataMQ.reset(new DataMQ(dataMQ));
520 tempStatusMQ.reset(new StatusMQ(statusMQ));
521 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
522 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
523 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000524#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800525 halThreadPid = halThreadInfo.pid;
526 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000527#else
528 halThreadTid = halThreadInfo;
529#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800530 }
531 });
532 if (!ret.isOk() || retval != Result::OK) {
533 return processReturn("prepareForWriting", ret, retval);
534 }
535 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
536 !tempDataMQ || !tempDataMQ->isValid() ||
537 !tempStatusMQ || !tempStatusMQ->isValid() ||
538 !mEfGroup) {
539 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
540 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
541 "Command message queue for writing is invalid");
542 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
543 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
544 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
545 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
546 "Status message queue for writing is invalid");
547 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
548 return NO_INIT;
549 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000550#if MAJOR_VERSION >= 7
551 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
552 return status;
553 }
554#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800555 requestHalThreadPriority(halThreadPid, halThreadTid);
556
557 mCommandMQ = std::move(tempCommandMQ);
558 mDataMQ = std::move(tempDataMQ);
559 mStatusMQ = std::move(tempStatusMQ);
560 mWriterClient = gettid();
561 return OK;
562}
563
564status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
565 if (mStream == 0) return NO_INIT;
566 Result retval;
567 Return<void> ret = mStream->getRenderPosition(
568 [&](Result r, uint32_t d) {
569 retval = r;
570 if (retval == Result::OK) {
571 *dspFrames = d;
572 }
573 });
574 return processReturn("getRenderPosition", ret, retval);
575}
576
577status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
578 if (mStream == 0) return NO_INIT;
579 Result retval;
580 Return<void> ret = mStream->getNextWriteTimestamp(
581 [&](Result r, int64_t t) {
582 retval = r;
583 if (retval == Result::OK) {
584 *timestamp = t;
585 }
586 });
587 return processReturn("getRenderPosition", ret, retval);
588}
589
590status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
591 if (mStream == 0) return NO_INIT;
592 status_t status = processReturn(
593 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
594 if (status == OK) {
595 mCallback = callback;
596 }
597 return status;
598}
599
600status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
601 if (mStream == 0) return NO_INIT;
602 Return<void> ret = mStream->supportsPauseAndResume(
603 [&](bool p, bool r) {
604 *supportsPause = p;
605 *supportsResume = r;
606 });
607 return processReturn("supportsPauseAndResume", ret);
608}
609
610status_t StreamOutHalHidl::pause() {
611 if (mStream == 0) return NO_INIT;
612 return processReturn("pause", mStream->pause());
613}
614
615status_t StreamOutHalHidl::resume() {
616 if (mStream == 0) return NO_INIT;
617 return processReturn("pause", mStream->resume());
618}
619
620status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
621 if (mStream == 0) return NO_INIT;
622 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
623}
624
625status_t StreamOutHalHidl::drain(bool earlyNotify) {
626 if (mStream == 0) return NO_INIT;
627 return processReturn(
628 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
629}
630
631status_t StreamOutHalHidl::flush() {
632 if (mStream == 0) return NO_INIT;
633 return processReturn("pause", mStream->flush());
634}
635
636status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
637 if (mStream == 0) return NO_INIT;
638 if (mWriterClient == gettid() && mCommandMQ) {
639 return callWriterThread(
640 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
641 [&](const WriteStatus& writeStatus) {
642 *frames = writeStatus.reply.presentationPosition.frames;
643 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
644 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
645 });
646 } else {
647 Result retval;
648 Return<void> ret = mStream->getPresentationPosition(
649 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
650 retval = r;
651 if (retval == Result::OK) {
652 *frames = hidlFrames;
653 timestamp->tv_sec = hidlTimeStamp.tvSec;
654 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
655 }
656 });
657 return processReturn("getPresentationPosition", ret, retval);
658 }
659}
660
Kevin Rocard070e7512018-05-22 09:29:13 -0700661#if MAJOR_VERSION == 2
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800662status_t StreamOutHalHidl::updateSourceMetadata(
663 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700664 // Audio HAL V2.0 does not support propagating source metadata
665 return INVALID_OPERATION;
666}
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800667#elif MAJOR_VERSION >= 4
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800668status_t StreamOutHalHidl::updateSourceMetadata(
669 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
Mikhail Naganov6718c392022-01-27 22:17:21 +0000670#if MAJOR_VERSION == 4
671 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
672#else
673 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
674#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000675 if (status_t status = CoreUtils::sourceMetadataFromHalV7(
676 sourceMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
677 status != OK) {
678 return status;
679 }
680 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -0700681}
Kevin Rocard070e7512018-05-22 09:29:13 -0700682#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700683
jiabinf6eb4c32020-02-25 14:06:25 -0800684#if MAJOR_VERSION < 6
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800685status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
686 return INVALID_OPERATION;
687}
688
689status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
690 return INVALID_OPERATION;
691}
692
693status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
694 return INVALID_OPERATION;
695}
696
697status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB __unused) {
698 return INVALID_OPERATION;
699}
700
701status_t StreamOutHalHidl::getPlaybackRateParameters(
702 audio_playback_rate_t* playbackRate __unused) {
703 return INVALID_OPERATION;
704}
705
706status_t StreamOutHalHidl::setPlaybackRateParameters(
707 const audio_playback_rate_t& playbackRate __unused) {
708 return INVALID_OPERATION;
709}
710
jiabinf6eb4c32020-02-25 14:06:25 -0800711status_t StreamOutHalHidl::setEventCallback(
712 const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
713 // Codec format callback is supported starting from audio HAL V6.0
714 return INVALID_OPERATION;
715}
Eric Laurentafa586b2022-01-27 21:10:55 +0100716
jiabinf6eb4c32020-02-25 14:06:25 -0800717#else
718
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800719status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
720 if (mStream == 0) return NO_INIT;
721 Result retval;
722 Return<void> ret = mStream->getDualMonoMode(
723 [&](Result r, DualMonoMode hidlMode) {
724 retval = r;
725 if (retval == Result::OK) {
726 *mode = static_cast<audio_dual_mono_mode_t>(hidlMode);
727 }
728 });
729 return processReturn("getDualMonoMode", ret, retval);
730}
731
732status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode) {
733 if (mStream == 0) return NO_INIT;
734 return processReturn(
735 "setDualMonoMode", mStream->setDualMonoMode(static_cast<DualMonoMode>(mode)));
736}
737
738status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB) {
739 if (mStream == 0) return NO_INIT;
740 Result retval;
741 Return<void> ret = mStream->getAudioDescriptionMixLevel(
742 [&](Result r, float hidlLeveldB) {
743 retval = r;
744 if (retval == Result::OK) {
745 *leveldB = hidlLeveldB;
746 }
747 });
748 return processReturn("getAudioDescriptionMixLevel", ret, retval);
749}
750
751status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB) {
752 if (mStream == 0) return NO_INIT;
753 return processReturn(
754 "setAudioDescriptionMixLevel", mStream->setAudioDescriptionMixLevel(leveldB));
755}
756
757status_t StreamOutHalHidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
758 if (mStream == 0) return NO_INIT;
759 Result retval;
760 Return<void> ret = mStream->getPlaybackRateParameters(
761 [&](Result r, PlaybackRate hidlPlaybackRate) {
762 retval = r;
763 if (retval == Result::OK) {
764 playbackRate->mSpeed = hidlPlaybackRate.speed;
765 playbackRate->mPitch = hidlPlaybackRate.pitch;
766 playbackRate->mStretchMode =
767 static_cast<audio_timestretch_stretch_mode_t>(
768 hidlPlaybackRate.timestretchMode);
769 playbackRate->mFallbackMode =
770 static_cast<audio_timestretch_fallback_mode_t>(
771 hidlPlaybackRate.fallbackMode);
772 }
773 });
774 return processReturn("getPlaybackRateParameters", ret, retval);
775}
776
777status_t StreamOutHalHidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
778 if (mStream == 0) return NO_INIT;
779 return processReturn(
780 "setPlaybackRateParameters", mStream->setPlaybackRateParameters(
781 PlaybackRate{playbackRate.mSpeed, playbackRate.mPitch,
782 static_cast<TimestretchMode>(playbackRate.mStretchMode),
783 static_cast<TimestretchFallbackMode>(playbackRate.mFallbackMode)}));
784}
785
Mikhail Naganov6718c392022-01-27 22:17:21 +0000786#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamOutEventCallback.h)
jiabinf6eb4c32020-02-25 14:06:25 -0800787
788namespace {
789
790struct StreamOutEventCallback : public IStreamOutEventCallback {
791 StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
792
793 // IStreamOutEventCallback implementation
794 Return<void> onCodecFormatChanged(
795 const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
796 sp<StreamOutHalHidl> stream = mStream.promote();
797 if (stream != nullptr) {
798 std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
799 stream->onCodecFormatChanged(metadataBs);
800 }
801 return Void();
802 }
803
804 private:
805 wp<StreamOutHalHidl> mStream;
806};
807
808} // namespace
809
810status_t StreamOutHalHidl::setEventCallback(
811 const sp<StreamOutHalInterfaceEventCallback>& callback) {
812 if (mStream == nullptr) return NO_INIT;
813 mEventCallback = callback;
814 status_t status = processReturn(
815 "setEventCallback",
816 mStream->setEventCallback(
817 callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
818 return status;
819}
820#endif
821
Eric Laurentafa586b2022-01-27 21:10:55 +0100822#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
823using hardware::audio::V7_1::LatencyMode;
824
825status_t StreamOutHalHidl::setLatencyMode(audio_latency_mode_t mode) {
826 if (mStream == 0) return NO_INIT;
827 return processReturn(
828 "setLatencyMode", mStream->setLatencyMode(static_cast<LatencyMode>(mode)));
829};
830
831status_t StreamOutHalHidl::getRecommendedLatencyModes(std::vector<audio_latency_mode_t> *modes) {
832 if (!mStream) return NO_INIT;
833 Result retval;
834 Return<void> ret = mStream->getRecommendedLatencyModes(
835 [&](Result r, hidl_vec<LatencyMode> hidlModes) {
836 retval = r;
837 for (size_t i = 0; i < hidlModes.size(); i++) {
838 modes->push_back(static_cast<audio_latency_mode_t>(hidlModes[i]));
839 }
840 });
841 return processReturn("getRecommendedLatencyModes", ret, retval);
842};
843
844#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutLatencyModeCallback.h)
845
846using hardware::audio::V7_1::IStreamOutLatencyModeCallback;
847
848namespace {
849struct StreamOutLatencyModeCallback : public IStreamOutLatencyModeCallback {
850 StreamOutLatencyModeCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
851
852 // IStreamOutLatencyModeCallback implementation
853 Return<void> onRecommendedLatencyModeChanged(const hidl_vec<LatencyMode>& hidlModes) override {
854 sp<StreamOutHalHidl> stream = mStream.promote();
855 if (stream != nullptr) {
856 std::vector<audio_latency_mode_t> modes;
857 for (size_t i = 0; i < hidlModes.size(); i++) {
858 modes.push_back(static_cast<audio_latency_mode_t>(hidlModes[i]));
859 }
860 stream->onRecommendedLatencyModeChanged(modes);
861 }
862 return Void();
863 }
864
865 private:
866 wp<StreamOutHalHidl> mStream;
867};
868} // namespace
869
870status_t StreamOutHalHidl::setLatencyModeCallback(
871 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) {
872
873 if (mStream == nullptr) return NO_INIT;
874 mLatencyModeCallback = callback;
875 status_t status = processReturn(
876 "setLatencyModeCallback",
877 mStream->setLatencyModeCallback(
878 callback.get() == nullptr ? nullptr : new StreamOutLatencyModeCallback(this)));
879 return status;
880};
881
882#else
883
884status_t StreamOutHalHidl::setLatencyMode(audio_latency_mode_t mode __unused) {
885 return INVALID_OPERATION;
886};
887
888status_t StreamOutHalHidl::getRecommendedLatencyModes(
889 std::vector<audio_latency_mode_t> *modes __unused) {
890 return INVALID_OPERATION;
891};
892
893status_t StreamOutHalHidl::setLatencyModeCallback(
894 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback __unused) {
895 return INVALID_OPERATION;
896};
897
898#endif
899
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800900void StreamOutHalHidl::onWriteReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800901 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800902 if (callback == 0) return;
903 ALOGV("asyncCallback onWriteReady");
904 callback->onWriteReady();
905}
906
907void StreamOutHalHidl::onDrainReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800908 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800909 if (callback == 0) return;
910 ALOGV("asyncCallback onDrainReady");
911 callback->onDrainReady();
912}
913
914void StreamOutHalHidl::onError() {
Andy Hung638f45b2021-01-18 20:02:56 -0800915 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800916 if (callback == 0) return;
917 ALOGV("asyncCallback onError");
918 callback->onError();
919}
920
jiabinf6eb4c32020-02-25 14:06:25 -0800921void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
Andy Hung638f45b2021-01-18 20:02:56 -0800922 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
jiabinf6eb4c32020-02-25 14:06:25 -0800923 if (callback == nullptr) return;
924 ALOGV("asyncCodecFormatCallback %s", __func__);
925 callback->onCodecFormatChanged(metadataBs);
926}
927
Eric Laurentafa586b2022-01-27 21:10:55 +0100928void StreamOutHalHidl::onRecommendedLatencyModeChanged(
929 const std::vector<audio_latency_mode_t>& modes) {
930 sp<StreamOutHalInterfaceLatencyModeCallback> callback = mLatencyModeCallback.load().promote();
931 if (callback == nullptr) return;
932 callback->onRecommendedLatencyModeChanged(modes);
933}
934
Ytai Ben-Tsvi7e0183f2022-02-04 10:49:54 -0800935status_t StreamOutHalHidl::exit() {
936 // FIXME this is using hard-coded strings but in the future, this functionality will be
937 // converted to use audio HAL extensions required to support tunneling
938 return setParameters(String8("exiting=1"));
939}
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800940
Mikhail Naganov6718c392022-01-27 22:17:21 +0000941StreamInHalHidl::StreamInHalHidl(
Mikhail Naganovaccbe8a2022-02-03 23:45:36 +0000942 const sp<::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn>& stream)
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800943 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
944}
945
946StreamInHalHidl::~StreamInHalHidl() {
947 if (mStream != 0) {
948 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800949 }
950 if (mEfGroup) {
951 EventFlag::deleteEventFlag(&mEfGroup);
952 }
953}
954
955status_t StreamInHalHidl::getFrameSize(size_t *size) {
956 if (mStream == 0) return NO_INIT;
957 return processReturn("getFrameSize", mStream->getFrameSize(), size);
958}
959
960status_t StreamInHalHidl::setGain(float gain) {
961 if (mStream == 0) return NO_INIT;
962 return processReturn("setGain", mStream->setGain(gain));
963}
964
965status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
966 if (mStream == 0) return NO_INIT;
967 *read = 0;
968
969 if (bytes == 0 && !mDataMQ) {
970 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
971 return OK;
972 }
973
974 status_t status;
975 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
976 return status;
977 }
978
979 ReadParameters params;
980 params.command = ReadCommand::READ;
981 params.params.read = bytes;
982 status = callReaderThread(params, "read",
983 [&](const ReadStatus& readStatus) {
984 const size_t availToRead = mDataMQ->availableToRead();
985 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
986 ALOGE("data message queue read failed for \"read\"");
987 }
988 ALOGW_IF(availToRead != readStatus.reply.read,
989 "HAL read report inconsistent: mq = %d, status = %d",
990 (int32_t)availToRead, (int32_t)readStatus.reply.read);
991 *read = readStatus.reply.read;
992 });
993 mStreamPowerLog.log(buffer, *read);
994 return status;
995}
996
997status_t StreamInHalHidl::callReaderThread(
998 const ReadParameters& params, const char* cmdName,
999 StreamInHalHidl::ReaderCallback callback) {
1000 if (!mCommandMQ->write(&params)) {
1001 ALOGW("command message queue write failed");
1002 return -EAGAIN;
1003 }
1004 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
1005
1006 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
1007 uint32_t efState = 0;
1008retry:
1009 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
1010 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
1011 ReadStatus readStatus;
1012 readStatus.retval = Result::NOT_INITIALIZED;
1013 if (!mStatusMQ->read(&readStatus)) {
1014 ALOGE("status message read failed for \"%s\"", cmdName);
1015 }
1016 if (readStatus.retval == Result::OK) {
1017 ret = OK;
1018 callback(readStatus);
1019 } else {
1020 ret = processReturn(cmdName, readStatus.retval);
1021 }
1022 return ret;
1023 }
1024 if (ret == -EAGAIN || ret == -EINTR) {
1025 // Spurious wakeup. This normally retries no more than once.
1026 goto retry;
1027 }
1028 return ret;
1029}
1030
1031status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
1032 std::unique_ptr<CommandMQ> tempCommandMQ;
1033 std::unique_ptr<DataMQ> tempDataMQ;
1034 std::unique_ptr<StatusMQ> tempStatusMQ;
1035 Result retval;
1036 pid_t halThreadPid, halThreadTid;
1037 Return<void> ret = mStream->prepareForReading(
1038 1, bufferSize,
1039 [&](Result r,
1040 const CommandMQ::Descriptor& commandMQ,
1041 const DataMQ::Descriptor& dataMQ,
1042 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001043 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001044 retval = r;
1045 if (retval == Result::OK) {
1046 tempCommandMQ.reset(new CommandMQ(commandMQ));
1047 tempDataMQ.reset(new DataMQ(dataMQ));
1048 tempStatusMQ.reset(new StatusMQ(statusMQ));
1049 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
1050 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
1051 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001052#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001053 halThreadPid = halThreadInfo.pid;
1054 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001055#else
1056 halThreadTid = halThreadInfo;
1057#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001058 }
1059 });
1060 if (!ret.isOk() || retval != Result::OK) {
1061 return processReturn("prepareForReading", ret, retval);
1062 }
1063 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
1064 !tempDataMQ || !tempDataMQ->isValid() ||
1065 !tempStatusMQ || !tempStatusMQ->isValid() ||
1066 !mEfGroup) {
1067 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
1068 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
1069 "Command message queue for writing is invalid");
1070 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
1071 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
1072 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
1073 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
1074 "Status message queue for reading is invalid");
1075 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
1076 return NO_INIT;
1077 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001078#if MAJOR_VERSION >= 7
1079 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
1080 return status;
1081 }
1082#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001083 requestHalThreadPriority(halThreadPid, halThreadTid);
1084
1085 mCommandMQ = std::move(tempCommandMQ);
1086 mDataMQ = std::move(tempDataMQ);
1087 mStatusMQ = std::move(tempStatusMQ);
1088 mReaderClient = gettid();
1089 return OK;
1090}
1091
1092status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
1093 if (mStream == 0) return NO_INIT;
1094 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
1095}
1096
1097status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
1098 if (mStream == 0) return NO_INIT;
1099 if (mReaderClient == gettid() && mCommandMQ) {
1100 ReadParameters params;
1101 params.command = ReadCommand::GET_CAPTURE_POSITION;
1102 return callReaderThread(params, "getCapturePosition",
1103 [&](const ReadStatus& readStatus) {
1104 *frames = readStatus.reply.capturePosition.frames;
1105 *time = readStatus.reply.capturePosition.time;
1106 });
1107 } else {
1108 Result retval;
1109 Return<void> ret = mStream->getCapturePosition(
1110 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
1111 retval = r;
1112 if (retval == Result::OK) {
1113 *frames = hidlFrames;
1114 *time = hidlTime;
1115 }
1116 });
1117 return processReturn("getCapturePosition", ret, retval);
1118 }
1119}
1120
Kevin Rocard070e7512018-05-22 09:29:13 -07001121#if MAJOR_VERSION == 2
1122status_t StreamInHalHidl::getActiveMicrophones(
1123 std::vector<media::MicrophoneInfo> *microphones __unused) {
1124 if (mStream == 0) return NO_INIT;
1125 return INVALID_OPERATION;
1126}
1127
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001128status_t StreamInHalHidl::updateSinkMetadata(
1129 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -07001130 // Audio HAL V2.0 does not support propagating sink metadata
1131 return INVALID_OPERATION;
1132}
1133
Kevin Rocard3d48dce2018-11-08 17:16:57 -08001134#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -07001135status_t StreamInHalHidl::getActiveMicrophones(
1136 std::vector<media::MicrophoneInfo> *microphonesInfo) {
1137 if (!mStream) return NO_INIT;
1138 Result retval;
1139 Return<void> ret = mStream->getActiveMicrophones(
1140 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
1141 retval = r;
1142 for (size_t k = 0; k < micArrayHal.size(); k++) {
1143 audio_microphone_characteristic_t dst;
1144 // convert
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001145 (void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst);
jiabin9ff780e2018-03-19 18:19:52 -07001146 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
1147 microphonesInfo->push_back(microphone);
1148 }
1149 });
1150 return processReturn("getActiveMicrophones", ret, retval);
1151}
1152
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001153status_t StreamInHalHidl::updateSinkMetadata(const
1154 StreamInHalInterface::SinkMetadata& sinkMetadata) {
Mikhail Naganov6718c392022-01-27 22:17:21 +00001155#if MAJOR_VERSION == 4
1156 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1157#else
1158 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1159#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001160 if (status_t status = CoreUtils::sinkMetadataFromHalV7(
1161 sinkMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
1162 status != OK) {
1163 return status;
1164 }
1165 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -07001166}
Kevin Rocard070e7512018-05-22 09:29:13 -07001167#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -07001168
Paul McLean03a6e6a2018-12-04 10:54:13 -07001169#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -06001170status_t StreamInHalHidl::setPreferredMicrophoneDirection(
1171 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001172 if (mStream == 0) return NO_INIT;
1173 return INVALID_OPERATION;
1174}
1175
Paul McLean12340082019-03-19 09:35:05 -06001176status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001177 if (mStream == 0) return NO_INIT;
1178 return INVALID_OPERATION;
1179}
1180#else
Paul McLean12340082019-03-19 09:35:05 -06001181status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001182 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001183 return processReturn("setPreferredMicrophoneDirection",
1184 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -07001185}
1186
Paul McLean12340082019-03-19 09:35:05 -06001187status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001188 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001189 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -07001190 mStream->setMicrophoneFieldDimension(zoom));
1191}
1192#endif
1193
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001194} // namespace android