xref: /aosp_15_r20/frameworks/av/media/libaudiohal/impl/StreamHalAidl.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1 /*
2  * Copyright (C) 2023 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 "StreamHalAidl"
18 //#define LOG_NDEBUG 0
19 
20 #include <algorithm>
21 #include <cstdint>
22 
23 #include <audio_utils/clock.h>
24 #include <media/AidlConversion.h>
25 #include <media/AidlConversionCore.h>
26 #include <media/AidlConversionCppNdk.h>
27 #include <media/AidlConversionNdk.h>
28 #include <media/AidlConversionUtil.h>
29 #include <media/AudioParameter.h>
30 #include <mediautils/TimeCheck.h>
31 #include <system/audio.h>
32 #include <Utils.h>
33 #include <utils/Log.h>
34 
35 #include "AidlUtils.h"
36 #include "DeviceHalAidl.h"
37 #include "EffectHalAidl.h"
38 #include "StreamHalAidl.h"
39 
40 using ::aidl::android::aidl_utils::statusTFromBinderStatus;
41 using ::aidl::android::hardware::audio::common::kDumpFromAudioServerArgument;
42 using ::aidl::android::hardware::audio::common::PlaybackTrackMetadata;
43 using ::aidl::android::hardware::audio::common::RecordTrackMetadata;
44 using ::aidl::android::hardware::audio::core::IStreamCommon;
45 using ::aidl::android::hardware::audio::core::IStreamIn;
46 using ::aidl::android::hardware::audio::core::IStreamOut;
47 using ::aidl::android::hardware::audio::core::MmapBufferDescriptor;
48 using ::aidl::android::hardware::audio::core::StreamDescriptor;
49 using ::aidl::android::media::audio::common::MicrophoneDynamicInfo;
50 using ::aidl::android::media::audio::IHalAdapterVendorExtension;
51 
52 namespace android {
53 
54 using HalCommand = StreamDescriptor::Command;
55 namespace {
makeHalCommand()56 template<HalCommand::Tag cmd> HalCommand makeHalCommand() {
57     return HalCommand::make<cmd>(::aidl::android::media::audio::common::Void{});
58 }
makeHalCommand(T data)59 template<HalCommand::Tag cmd, typename T> HalCommand makeHalCommand(T data) {
60     return HalCommand::make<cmd>(data);
61 }
62 
63 template <typename MQTypeError>
fmqErrorHandler(const char * mqName)64 auto fmqErrorHandler(const char* mqName) {
65     return [m = std::string(mqName)](MQTypeError fmqError, std::string&& errorMessage) {
66         mediautils::TimeCheck::signalAudioHals();
67         LOG_ALWAYS_FATAL_IF(fmqError != MQTypeError::NONE, "%s: %s",
68                 m.c_str(), errorMessage.c_str());
69     };
70 }
71 
72 }  // namespace
73 
74 // static
75 template<class T>
getStreamCommon(const std::shared_ptr<T> & stream)76 std::shared_ptr<IStreamCommon> StreamHalAidl::getStreamCommon(const std::shared_ptr<T>& stream) {
77     std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> streamCommon;
78     if (stream != nullptr) {
79         if (ndk::ScopedAStatus status = stream->getStreamCommon(&streamCommon);
80                 !status.isOk()) {
81             ALOGE("%s: failed to retrieve IStreamCommon instance: %s", __func__,
82                     status.getDescription().c_str());
83         }
84     }
85     return streamCommon;
86 }
87 
StreamHalAidl(std::string_view className,bool isInput,const audio_config & config,int32_t nominalLatency,StreamContextAidl && context,const std::shared_ptr<IStreamCommon> & stream,const std::shared_ptr<IHalAdapterVendorExtension> & vext)88 StreamHalAidl::StreamHalAidl(std::string_view className, bool isInput, const audio_config& config,
89                              int32_t nominalLatency, StreamContextAidl&& context,
90                              const std::shared_ptr<IStreamCommon>& stream,
91                              const std::shared_ptr<IHalAdapterVendorExtension>& vext)
92     : ConversionHelperAidl(className, std::string(isInput ? "in" : "out") + "|ioHandle:" +
93             std::to_string(context.getIoHandle())),
94           mIsInput(isInput),
95           mConfig(configToBase(config)),
96           mContext(std::move(context)),
97           mStream(stream),
98           mVendorExt(vext),
99           mLastReplyLifeTimeNs(
100                   std::min(static_cast<size_t>(20),
101                            mContext.getBufferDurationMs(mConfig.sample_rate))
102                   * NANOS_PER_MILLISECOND)
103 {
104     AUGMENT_LOG(D);
105     {
106         std::lock_guard l(mLock);
107         mLastReply.latencyMs = nominalLatency;
108     }
109     // Instrument audio signal power logging.
110     // Note: This assumes channel mask, format, and sample rate do not change after creation.
111     if (audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
112             /* mStreamPowerLog.isUserDebugOrEngBuild() && */
113             StreamHalAidl::getAudioProperties(&config) == NO_ERROR) {
114         mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
115     }
116 
117     if (mStream != nullptr) {
118         mContext.getCommandMQ()->setErrorHandler(
119                 fmqErrorHandler<StreamContextAidl::CommandMQ::Error>("CommandMQ"));
120         mContext.getReplyMQ()->setErrorHandler(
121                 fmqErrorHandler<StreamContextAidl::ReplyMQ::Error>("ReplyMQ"));
122         if (mContext.getDataMQ() != nullptr) {
123             mContext.getDataMQ()->setErrorHandler(
124                     fmqErrorHandler<StreamContextAidl::DataMQ::Error>("DataMQ"));
125         }
126     }
127 }
128 
~StreamHalAidl()129 StreamHalAidl::~StreamHalAidl() {
130     AUGMENT_LOG(D);
131     if (mStream != nullptr) {
132         ndk::ScopedAStatus status = mStream->close();
133         AUGMENT_LOG_IF(E, !status.isOk(), "status %s", status.getDescription().c_str());
134     }
135 }
136 
getBufferSize(size_t * size)137 status_t StreamHalAidl::getBufferSize(size_t *size) {
138     AUGMENT_LOG(D);
139     if (size == nullptr) {
140         return BAD_VALUE;
141     }
142     if (mContext.getFrameSizeBytes() == 0 || mContext.getBufferSizeFrames() == 0 ||
143             !mStream) {
144         return NO_INIT;
145     }
146     *size = mContext.getBufferSizeBytes();
147     AUGMENT_LOG(I, "size: %zu", *size);
148     return OK;
149 }
150 
getAudioProperties(audio_config_base_t * configBase)151 status_t StreamHalAidl::getAudioProperties(audio_config_base_t *configBase) {
152     AUGMENT_LOG(D);
153     if (configBase == nullptr) {
154         return BAD_VALUE;
155     }
156     if (!mStream) return NO_INIT;
157     *configBase = mConfig;
158     return OK;
159 }
160 
setParameters(const String8 & kvPairs)161 status_t StreamHalAidl::setParameters(const String8& kvPairs) {
162     AUGMENT_LOG(V);
163     TIME_CHECK();
164     if (!mStream) return NO_INIT;
165     AudioParameter parameters(kvPairs);
166     AUGMENT_LOG(D, "parameters: %s", parameters.toString().c_str());
167 
168     (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
169                     parameters, String8(AudioParameter::keyStreamHwAvSync),
170             [&](int hwAvSyncId) {
171                 return statusTFromBinderStatus(mStream->updateHwAvSyncId(hwAvSyncId));
172             }));
173     return parseAndSetVendorParameters(mVendorExt, mStream, parameters);
174 }
175 
getParameters(const String8 & keys __unused,String8 * values)176 status_t StreamHalAidl::getParameters(const String8& keys __unused, String8 *values) {
177     AUGMENT_LOG(V);
178     TIME_CHECK();
179     if (!mStream) return NO_INIT;
180     if (values == nullptr) {
181         return BAD_VALUE;
182     }
183     AudioParameter parameterKeys(keys), result;
184     *values = result.toString();
185     return parseAndGetVendorParameters(mVendorExt, mStream, parameterKeys, values);
186 }
187 
getFrameSize(size_t * size)188 status_t StreamHalAidl::getFrameSize(size_t *size) {
189     AUGMENT_LOG(D);
190     if (size == nullptr) {
191         return BAD_VALUE;
192     }
193     if (mContext.getFrameSizeBytes() == 0 || !mStream) {
194         return NO_INIT;
195     }
196     *size = mContext.getFrameSizeBytes();
197     return OK;
198 }
199 
addEffect(sp<EffectHalInterface> effect)200 status_t StreamHalAidl::addEffect(sp<EffectHalInterface> effect) {
201     AUGMENT_LOG(D);
202     TIME_CHECK();
203     if (!mStream) return NO_INIT;
204     if (effect == nullptr) {
205         return BAD_VALUE;
206     }
207     auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
208     return statusTFromBinderStatus(mStream->addEffect(aidlEffect->getIEffect()));
209 }
210 
removeEffect(sp<EffectHalInterface> effect)211 status_t StreamHalAidl::removeEffect(sp<EffectHalInterface> effect) {
212     AUGMENT_LOG(D);
213     TIME_CHECK();
214     if (!mStream) return NO_INIT;
215     if (effect == nullptr) {
216         return BAD_VALUE;
217     }
218     auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
219     return statusTFromBinderStatus(mStream->removeEffect(aidlEffect->getIEffect()));
220 }
221 
standby()222 status_t StreamHalAidl::standby() {
223     AUGMENT_LOG(D);
224     TIME_CHECK();
225     if (!mStream) return NO_INIT;
226     const auto state = getState();
227     StreamDescriptor::Reply reply;
228     switch (state) {
229         case StreamDescriptor::State::ACTIVE:
230         case StreamDescriptor::State::DRAINING:
231         case StreamDescriptor::State::TRANSFERRING:
232             RETURN_STATUS_IF_ERROR(pause(&reply));
233             if (reply.state != StreamDescriptor::State::PAUSED &&
234                     reply.state != StreamDescriptor::State::DRAIN_PAUSED &&
235                     reply.state != StreamDescriptor::State::TRANSFER_PAUSED &&
236                     (state != StreamDescriptor::State::DRAINING ||
237                         reply.state != StreamDescriptor::State::IDLE)) {
238                 AUGMENT_LOG(E, "unexpected stream state: %s (expected PAUSED)",
239                             toString(reply.state).c_str());
240                 return INVALID_OPERATION;
241             }
242             FALLTHROUGH_INTENDED;
243         case StreamDescriptor::State::PAUSED:
244         case StreamDescriptor::State::DRAIN_PAUSED:
245         case StreamDescriptor::State::TRANSFER_PAUSED:
246             if (mIsInput) return flush();
247             RETURN_STATUS_IF_ERROR(flush(&reply));
248             if (reply.state != StreamDescriptor::State::IDLE) {
249                 AUGMENT_LOG(E, "unexpected stream state: %s (expected IDLE)",
250                             toString(reply.state).c_str());
251                 return INVALID_OPERATION;
252             }
253             FALLTHROUGH_INTENDED;
254         case StreamDescriptor::State::IDLE:
255             RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::standby>(),
256                             &reply, true /*safeFromNonWorkerThread*/));
257             if (reply.state != StreamDescriptor::State::STANDBY) {
258                 AUGMENT_LOG(E, "unexpected stream state: %s (expected STANDBY)",
259                             toString(reply.state).c_str());
260                 return INVALID_OPERATION;
261             }
262             FALLTHROUGH_INTENDED;
263         case StreamDescriptor::State::STANDBY:
264             return OK;
265         default:
266             AUGMENT_LOG(E, "not supported from %s stream state %s", mIsInput ? "input" : "output",
267                         toString(state).c_str());
268             return INVALID_OPERATION;
269     }
270 }
271 
dump(int fd,const Vector<String16> & args)272 status_t StreamHalAidl::dump(int fd, const Vector<String16>& args) {
273     AUGMENT_LOG(D);
274     TIME_CHECK();
275     if (!mStream) return NO_INIT;
276     Vector<String16> newArgs = args;
277     newArgs.push(String16(kDumpFromAudioServerArgument));
278     status_t status = mStream->dump(fd, Args(newArgs).args(), newArgs.size());
279     mStreamPowerLog.dump(fd);
280     return status;
281 }
282 
start()283 status_t StreamHalAidl::start() {
284     AUGMENT_LOG(D);
285     TIME_CHECK();
286     if (!mStream) return NO_INIT;
287     if (!mContext.isMmapped()) {
288         return BAD_VALUE;
289     }
290     StreamDescriptor::Reply reply;
291     RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
292     switch (reply.state) {
293         case StreamDescriptor::State::STANDBY:
294             RETURN_STATUS_IF_ERROR(
295                     sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply, true));
296             if (reply.state != StreamDescriptor::State::IDLE) {
297                 AUGMENT_LOG(E, "unexpected stream state: %s (expected IDLE)",
298                             toString(reply.state).c_str());
299                 return INVALID_OPERATION;
300             }
301             FALLTHROUGH_INTENDED;
302         case StreamDescriptor::State::IDLE:
303             RETURN_STATUS_IF_ERROR(
304                     sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), &reply, true));
305             if (reply.state != StreamDescriptor::State::ACTIVE) {
306                 AUGMENT_LOG(E, "unexpected stream state: %s (expected ACTIVE)",
307                             toString(reply.state).c_str());
308                 return INVALID_OPERATION;
309             }
310             FALLTHROUGH_INTENDED;
311         case StreamDescriptor::State::ACTIVE:
312             return OK;
313         case StreamDescriptor::State::DRAINING:
314             RETURN_STATUS_IF_ERROR(
315                     sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply, true));
316             if (reply.state != StreamDescriptor::State::ACTIVE) {
317                 AUGMENT_LOG(E, "unexpected stream state: %s (expected ACTIVE)",
318                             toString(reply.state).c_str());
319                 return INVALID_OPERATION;
320             }
321             return OK;
322         default:
323             AUGMENT_LOG(E, "not supported from %s stream state %s", mIsInput ? "input" : "output",
324                         toString(reply.state).c_str());
325             return INVALID_OPERATION;
326     }
327 }
328 
stop()329 status_t StreamHalAidl::stop() {
330     AUGMENT_LOG(D);
331     TIME_CHECK();
332     if (!mStream) return NO_INIT;
333     if (!mContext.isMmapped()) {
334         return BAD_VALUE;
335     }
336     StreamDescriptor::Reply reply;
337     RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
338     if (const auto state = reply.state; state == StreamDescriptor::State::ACTIVE) {
339         return drain(false /*earlyNotify*/, nullptr);
340     } else if (state == StreamDescriptor::State::DRAINING) {
341         RETURN_STATUS_IF_ERROR(pause());
342         return flush();
343     } else if (state == StreamDescriptor::State::PAUSED) {
344         return flush();
345     } else if (state != StreamDescriptor::State::IDLE &&
346             state != StreamDescriptor::State::STANDBY) {
347         AUGMENT_LOG(E, "not supported from %s stream state %s", mIsInput ? "input" : "output",
348                     toString(state).c_str());
349         return INVALID_OPERATION;
350     }
351     return OK;
352 }
353 
getLatency(uint32_t * latency)354 status_t StreamHalAidl::getLatency(uint32_t *latency) {
355     AUGMENT_LOG(V);
356     if (!mStream) return NO_INIT;
357     StreamDescriptor::Reply reply;
358     RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
359     *latency = std::clamp(std::max<int32_t>(0, reply.latencyMs), 1, 3000);
360     AUGMENT_LOG_IF(W, reply.latencyMs != static_cast<int32_t>(*latency),
361                    "Suspicious latency value reported by HAL: %d, clamped to %u", reply.latencyMs,
362                    *latency);
363     return OK;
364 }
365 
getObservablePosition(int64_t * frames,int64_t * timestamp,StatePositions * statePositions)366 status_t StreamHalAidl::getObservablePosition(int64_t* frames, int64_t* timestamp,
367         StatePositions* statePositions) {
368     AUGMENT_LOG(V);
369     if (!mStream) return NO_INIT;
370     StreamDescriptor::Reply reply;
371     RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply, statePositions));
372     if (reply.observable.frames == StreamDescriptor::Position::UNKNOWN ||
373         reply.observable.timeNs == StreamDescriptor::Position::UNKNOWN) {
374         return INVALID_OPERATION;
375     }
376     *frames = reply.observable.frames;
377     *timestamp = reply.observable.timeNs;
378     return OK;
379 }
380 
getHardwarePosition(int64_t * frames,int64_t * timestamp)381 status_t StreamHalAidl::getHardwarePosition(int64_t *frames, int64_t *timestamp) {
382     AUGMENT_LOG(V);
383     if (!mStream) return NO_INIT;
384     StreamDescriptor::Reply reply;
385     RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
386     if (reply.hardware.frames == StreamDescriptor::Position::UNKNOWN ||
387         reply.hardware.timeNs == StreamDescriptor::Position::UNKNOWN) {
388         return INVALID_OPERATION;
389     }
390     *frames = reply.hardware.frames;
391     *timestamp = reply.hardware.timeNs;
392     return OK;
393 }
394 
getXruns(int32_t * frames)395 status_t StreamHalAidl::getXruns(int32_t *frames) {
396     AUGMENT_LOG(V);
397     if (!mStream) return NO_INIT;
398     StreamDescriptor::Reply reply;
399     RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
400     if (reply.xrunFrames == StreamDescriptor::Position::UNKNOWN) {
401         return INVALID_OPERATION;
402     }
403     *frames = reply.xrunFrames;
404     return OK;
405 }
406 
transfer(void * buffer,size_t bytes,size_t * transferred)407 status_t StreamHalAidl::transfer(void *buffer, size_t bytes, size_t *transferred) {
408     AUGMENT_LOG(V);
409     // TIME_CHECK();  // TODO(b/243839867) reenable only when optimized.
410     if (!mStream || mContext.getDataMQ() == nullptr) return NO_INIT;
411     mWorkerTid.store(gettid(), std::memory_order_release);
412     // Switch the stream into an active state if needed.
413     // Note: in future we may add support for priming the audio pipeline
414     // with data prior to enabling output (thus we can issue a "burst" command in the "standby"
415     // stream state), however this scenario wasn't supported by the HIDL HAL.
416     if (getState() == StreamDescriptor::State::STANDBY) {
417         StreamDescriptor::Reply reply;
418         RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply));
419         if (reply.state != StreamDescriptor::State::IDLE) {
420             AUGMENT_LOG(E, "failed to get the stream out of standby, actual state: %s",
421                         toString(reply.state).c_str());
422             return INVALID_OPERATION;
423         }
424     }
425     if (!mIsInput) {
426         bytes = std::min(bytes, mContext.getDataMQ()->availableToWrite());
427     }
428     StreamDescriptor::Command burst =
429             StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(bytes);
430     if (!mIsInput) {
431         if (!mContext.getDataMQ()->write(static_cast<const int8_t*>(buffer), bytes)) {
432             AUGMENT_LOG(E, "failed to write %zu bytes to data MQ", bytes);
433             return NOT_ENOUGH_DATA;
434         }
435     }
436     StreamDescriptor::Reply reply;
437     RETURN_STATUS_IF_ERROR(sendCommand(burst, &reply));
438     *transferred = reply.fmqByteCount;
439     if (mIsInput) {
440         LOG_ALWAYS_FATAL_IF(*transferred > bytes,
441                 "%s: HAL module read %zu bytes, which exceeds requested count %zu",
442                 __func__, *transferred, bytes);
443         if (auto toRead = mContext.getDataMQ()->availableToRead();
444                 toRead != 0 && !mContext.getDataMQ()->read(static_cast<int8_t*>(buffer), toRead)) {
445             AUGMENT_LOG(E, "failed to read %zu bytes to data MQ", toRead);
446             return NOT_ENOUGH_DATA;
447         }
448     }
449     mStreamPowerLog.log(buffer, *transferred);
450     return OK;
451 }
452 
pause(StreamDescriptor::Reply * reply)453 status_t StreamHalAidl::pause(StreamDescriptor::Reply* reply) {
454     AUGMENT_LOG(D);
455     TIME_CHECK();
456     if (!mStream) return NO_INIT;
457 
458     if (const auto state = getState(); isInPlayOrRecordState(state)) {
459         StreamDescriptor::Reply localReply{};
460         StreamDescriptor::Reply* innerReply = reply ?: &localReply;
461         auto status = sendCommand(
462                 makeHalCommand<HalCommand::Tag::pause>(), innerReply,
463                 true /*safeFromNonWorkerThread*/);  // The workers stops its I/O activity first.
464         if (status == STATUS_INVALID_OPERATION &&
465                 !isInPlayOrRecordState(innerReply->state)) {
466             /**
467              * In case of transient states like DRAINING, the HAL may change its
468              * StreamDescriptor::State on its own and may not be in synchronization with client.
469              * Thus, client can send the unexpected command and HAL returns failure. such failure is
470              * natural. The client handles it gracefully.
471              * Example where HAL change its state,
472              * 1) DRAINING -> IDLE (on empty buffer)
473              * 2) DRAINING -> IDLE (on IStreamCallback::onDrainReady)
474              **/
475             AUGMENT_LOG(D,
476                         "HAL failed to handle the 'pause' command, but stream state is in one of"
477                         " the PAUSED kind of states, current state: %s",
478                         toString(state).c_str());
479             return OK;
480         }
481         return status;
482     } else {
483         AUGMENT_LOG(D, "already stream in one of the PAUSED kind of states, current state: %s",
484                 toString(state).c_str());
485         return OK;
486     }
487 }
488 
resume(StreamDescriptor::Reply * reply)489 status_t StreamHalAidl::resume(StreamDescriptor::Reply* reply) {
490     AUGMENT_LOG(D);
491     TIME_CHECK();
492     if (!mStream) return NO_INIT;
493     if (mIsInput) {
494         return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), reply);
495     } else {
496         if (const auto state = getState(); state == StreamDescriptor::State::IDLE) {
497             // Handle pause-flush-resume sequence. 'flush' from PAUSED goes to
498             // IDLE. We move here from IDLE to ACTIVE (same as 'start' from PAUSED).
499             StreamDescriptor::Reply localReply{};
500             StreamDescriptor::Reply* innerReply = reply ?: &localReply;
501             RETURN_STATUS_IF_ERROR(
502                     sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), innerReply));
503             if (innerReply->state != StreamDescriptor::State::ACTIVE) {
504                 AUGMENT_LOG(E, "unexpected stream state: %s (expected ACTIVE)",
505                             toString(innerReply->state).c_str());
506                 return INVALID_OPERATION;
507             }
508             return OK;
509         } else if (isInPausedState(state)) {
510             return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
511         } else if (isInPlayOrRecordState(state)) {
512             AUGMENT_LOG(D, "already in stream state: %s", toString(state).c_str());
513             return OK;
514         } else {
515             AUGMENT_LOG(E, "unexpected stream state: %s (expected IDLE or one of *PAUSED states)",
516                         toString(state).c_str());
517             return INVALID_OPERATION;
518         }
519     }
520 }
521 
drain(bool earlyNotify,StreamDescriptor::Reply * reply)522 status_t StreamHalAidl::drain(bool earlyNotify, StreamDescriptor::Reply* reply) {
523     AUGMENT_LOG(D);
524     TIME_CHECK();
525     if (!mStream) return NO_INIT;
526     return sendCommand(makeHalCommand<HalCommand::Tag::drain>(
527                     mIsInput ? StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED :
528                     earlyNotify ? StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY :
529                     StreamDescriptor::DrainMode::DRAIN_ALL), reply,
530                     true /*safeFromNonWorkerThread*/);
531 }
532 
flush(StreamDescriptor::Reply * reply)533 status_t StreamHalAidl::flush(StreamDescriptor::Reply* reply) {
534     AUGMENT_LOG(D);
535     TIME_CHECK();
536     if (!mStream) return NO_INIT;
537 
538     if (const auto state = getState(); isInPausedState(state)) {
539         return sendCommand(
540                 makeHalCommand<HalCommand::Tag::flush>(), reply,
541                 true /*safeFromNonWorkerThread*/);  // The workers stops its I/O activity first.
542     } else if (isInPlayOrRecordState(state)) {
543         AUGMENT_LOG(E, "found stream in non-flushable state: %s", toString(state).c_str());
544         return INVALID_OPERATION;
545     } else {
546         AUGMENT_LOG(D, "already stream in one of the flushable state: current state: %s",
547                     toString(state).c_str());
548         return OK;
549     }
550 }
551 
exit()552 status_t StreamHalAidl::exit() {
553     AUGMENT_LOG(D);
554     TIME_CHECK();
555     if (!mStream) return NO_INIT;
556     return statusTFromBinderStatus(mStream->prepareToClose());
557 }
558 
onAsyncTransferReady()559 void StreamHalAidl::onAsyncTransferReady() {
560     StreamDescriptor::State state;
561     {
562         // Use 'mCommandReplyLock' to ensure that 'sendCommand' has finished updating the state
563         // after the reply from the 'burst' command.
564         std::lock_guard l(mCommandReplyLock);
565         state = getState();
566     }
567     if (state == StreamDescriptor::State::TRANSFERRING) {
568         // Retrieve the current state together with position counters unconditionally
569         // to ensure that the state on our side gets updated.
570         sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(),
571                 nullptr, true /*safeFromNonWorkerThread */);
572     } else {
573         AUGMENT_LOG(W, "unexpected onTransferReady in the state %s", toString(state).c_str());
574     }
575 }
576 
onAsyncDrainReady()577 void StreamHalAidl::onAsyncDrainReady() {
578     StreamDescriptor::State state;
579     {
580         // Use 'mCommandReplyLock' to ensure that 'sendCommand' has finished updating the state
581         // after the reply from the 'drain' command.
582         std::lock_guard l(mCommandReplyLock);
583         state = getState();
584     }
585     if (state == StreamDescriptor::State::DRAINING) {
586         // Retrieve the current state together with position counters unconditionally
587         // to ensure that the state on our side gets updated.
588         sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), nullptr,
589                     true /*safeFromNonWorkerThread */);
590         // For compatibility with HIDL behavior, apply a "soft" position reset
591         // after receiving the "drain ready" callback.
592         std::lock_guard l(mLock);
593         if (mLastReply.observable.frames != StreamDescriptor::Position::UNKNOWN) {
594             mStatePositions.framesAtFlushOrDrain = mLastReply.observable.frames;
595         }
596     } else {
597         AUGMENT_LOG(W, "unexpected onDrainReady in the state %s", toString(state).c_str());
598     }
599 }
600 
onAsyncError()601 void StreamHalAidl::onAsyncError() {
602     std::lock_guard l(mLock);
603     AUGMENT_LOG(W, "received in the state %s", toString(mLastReply.state).c_str());
604     mLastReply.state = StreamDescriptor::State::ERROR;
605 }
606 
createMmapBuffer(int32_t minSizeFrames __unused,struct audio_mmap_buffer_info * info)607 status_t StreamHalAidl::createMmapBuffer(int32_t minSizeFrames __unused,
608                                          struct audio_mmap_buffer_info *info) {
609     AUGMENT_LOG(D);
610     TIME_CHECK();
611     if (!mStream) return NO_INIT;
612     if (!mContext.isMmapped()) {
613         return BAD_VALUE;
614     }
615     const MmapBufferDescriptor& bufferDescriptor = mContext.getMmapBufferDescriptor();
616     info->shared_memory_fd = bufferDescriptor.sharedMemory.fd.get();
617     info->buffer_size_frames = mContext.getBufferSizeFrames();
618     info->burst_size_frames = bufferDescriptor.burstSizeFrames;
619     info->flags = static_cast<audio_mmap_buffer_flag>(bufferDescriptor.flags);
620 
621     return OK;
622 }
623 
getMmapPosition(struct audio_mmap_position * position)624 status_t StreamHalAidl::getMmapPosition(struct audio_mmap_position *position) {
625     TIME_CHECK();
626     if (!mStream) return NO_INIT;
627     if (!mContext.isMmapped()) {
628         return BAD_VALUE;
629     }
630     int64_t aidlPosition = 0, aidlTimestamp = 0;
631     RETURN_STATUS_IF_ERROR(getHardwarePosition(&aidlPosition, &aidlTimestamp));
632     position->time_nanoseconds = aidlTimestamp;
633     position->position_frames = static_cast<int32_t>(aidlPosition);
634     return OK;
635 }
636 
setHalThreadPriority(int priority __unused)637 status_t StreamHalAidl::setHalThreadPriority(int priority __unused) {
638     // Obsolete, must be done by the HAL module.
639     return OK;
640 }
641 
legacyCreateAudioPatch(const struct audio_port_config & port __unused,std::optional<audio_source_t> source __unused,audio_devices_t type __unused)642 status_t StreamHalAidl::legacyCreateAudioPatch(const struct audio_port_config& port __unused,
643                                                std::optional<audio_source_t> source __unused,
644                                                audio_devices_t type __unused) {
645     // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
646     return INVALID_OPERATION;
647 }
648 
legacyReleaseAudioPatch()649 status_t StreamHalAidl::legacyReleaseAudioPatch() {
650     // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
651     return INVALID_OPERATION;
652 }
653 
sendCommand(const::aidl::android::hardware::audio::core::StreamDescriptor::Command & command,::aidl::android::hardware::audio::core::StreamDescriptor::Reply * reply,bool safeFromNonWorkerThread,StatePositions * statePositions)654 status_t StreamHalAidl::sendCommand(
655         const ::aidl::android::hardware::audio::core::StreamDescriptor::Command& command,
656         ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply,
657         bool safeFromNonWorkerThread, StatePositions* statePositions) {
658     // TIME_CHECK();  // TODO(b/243839867) reenable only when optimized.
659     if (!safeFromNonWorkerThread) {
660         const pid_t workerTid = mWorkerTid.load(std::memory_order_acquire);
661         LOG_ALWAYS_FATAL_IF(workerTid != gettid(),
662                 "%s %s: must be invoked from the worker thread (%d)",
663                 __func__, command.toString().c_str(), workerTid);
664     }
665     StreamDescriptor::Reply localReply{};
666     {
667         std::lock_guard l(mCommandReplyLock);
668         if (!mContext.getCommandMQ()->writeBlocking(&command, 1)) {
669             AUGMENT_LOG(E, "failed to write command %s to MQ", command.toString().c_str());
670             return NOT_ENOUGH_DATA;
671         }
672         if (reply == nullptr) {
673             reply = &localReply;
674         }
675         if (!mContext.getReplyMQ()->readBlocking(reply, 1)) {
676             AUGMENT_LOG(E, "failed to read from reply MQ, command %s", command.toString().c_str());
677             return NOT_ENOUGH_DATA;
678         }
679         {
680             std::lock_guard l(mLock);
681             // Not every command replies with 'latencyMs' field filled out, substitute the last
682             // returned value in that case.
683             if (reply->latencyMs <= 0) {
684                 reply->latencyMs = mLastReply.latencyMs;
685             }
686             mLastReply = *reply;
687             mLastReplyExpirationNs = uptimeNanos() + mLastReplyLifeTimeNs;
688             if (!mIsInput && reply->status == STATUS_OK &&
689                     reply->observable.frames != StreamDescriptor::Position::UNKNOWN) {
690                 if (command.getTag() == StreamDescriptor::Command::standby &&
691                         reply->state == StreamDescriptor::State::STANDBY) {
692                     mStatePositions.framesAtStandby = reply->observable.frames;
693                 } else if (command.getTag() == StreamDescriptor::Command::flush &&
694                            reply->state == StreamDescriptor::State::IDLE) {
695                     mStatePositions.framesAtFlushOrDrain = reply->observable.frames;
696                 } else if (!mContext.isAsynchronous() &&
697                         command.getTag() == StreamDescriptor::Command::drain &&
698                         (reply->state == StreamDescriptor::State::IDLE ||
699                                 reply->state == StreamDescriptor::State::DRAINING)) {
700                     mStatePositions.framesAtFlushOrDrain = reply->observable.frames;
701                 } // for asynchronous drain, the frame count is saved in 'onAsyncDrainReady'
702             }
703             if (statePositions != nullptr) {
704                 *statePositions = mStatePositions;
705             }
706         }
707     }
708     switch (reply->status) {
709         case STATUS_OK: return OK;
710         case STATUS_BAD_VALUE: return BAD_VALUE;
711         case STATUS_INVALID_OPERATION: return INVALID_OPERATION;
712         case STATUS_NOT_ENOUGH_DATA: return NOT_ENOUGH_DATA;
713         default:
714             AUGMENT_LOG(E, "unexpected status %d returned for command %s", reply->status,
715                         command.toString().c_str());
716             return INVALID_OPERATION;
717     }
718 }
719 
updateCountersIfNeeded(::aidl::android::hardware::audio::core::StreamDescriptor::Reply * reply,StatePositions * statePositions)720 status_t StreamHalAidl::updateCountersIfNeeded(
721         ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply,
722         StatePositions* statePositions) {
723     bool doUpdate = false;
724     {
725         std::lock_guard l(mLock);
726         doUpdate = uptimeNanos() > mLastReplyExpirationNs;
727     }
728     if (doUpdate) {
729         // Since updates are paced, it is OK to perform them from any thread, they should
730         // not interfere with I/O operations of the worker.
731         return sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(),
732                 reply, true /*safeFromNonWorkerThread */, statePositions);
733     } else if (reply != nullptr) {  // provide cached reply
734         std::lock_guard l(mLock);
735         *reply = mLastReply;
736         if (statePositions != nullptr) {
737             *statePositions = mStatePositions;
738         }
739     }
740     return OK;
741 }
742 
743 // static
744 ConversionResult<::aidl::android::hardware::audio::common::SourceMetadata>
legacy2aidl_SourceMetadata(const StreamOutHalInterface::SourceMetadata & legacy)745 StreamOutHalAidl::legacy2aidl_SourceMetadata(const StreamOutHalInterface::SourceMetadata& legacy) {
746     ::aidl::android::hardware::audio::common::SourceMetadata aidl;
747     aidl.tracks = VALUE_OR_RETURN(
748             ::aidl::android::convertContainer<std::vector<PlaybackTrackMetadata>>(
749                     legacy.tracks,
750                     ::aidl::android::legacy2aidl_playback_track_metadata_v7_PlaybackTrackMetadata));
751     return aidl;
752 }
753 
StreamOutHalAidl(const audio_config & config,StreamContextAidl && context,int32_t nominalLatency,const std::shared_ptr<IStreamOut> & stream,const std::shared_ptr<IHalAdapterVendorExtension> & vext,const sp<CallbackBroker> & callbackBroker)754 StreamOutHalAidl::StreamOutHalAidl(
755         const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
756         const std::shared_ptr<IStreamOut>& stream,
757         const std::shared_ptr<IHalAdapterVendorExtension>& vext,
758         const sp<CallbackBroker>& callbackBroker)
759         : StreamHalAidl("StreamOutHalAidl", false /*isInput*/, config, nominalLatency,
760                 std::move(context), getStreamCommon(stream), vext),
761           mStream(stream), mCallbackBroker(callbackBroker) {
762     // Initialize the offload metadata
763     mOffloadMetadata.sampleRate = static_cast<int32_t>(config.sample_rate);
764     mOffloadMetadata.channelMask = VALUE_OR_FATAL(
765             ::aidl::android::legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
766                     config.channel_mask, false));
767     mOffloadMetadata.averageBitRatePerSecond = static_cast<int32_t>(config.offload_info.bit_rate);
768 }
769 
~StreamOutHalAidl()770 StreamOutHalAidl::~StreamOutHalAidl() {
771     if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
772         broker->clearCallbacks(static_cast<StreamOutHalInterface*>(this));
773     }
774 }
775 
setParameters(const String8 & kvPairs)776 status_t StreamOutHalAidl::setParameters(const String8& kvPairs) {
777     if (!mStream) return NO_INIT;
778 
779     AudioParameter parameters(kvPairs);
780     AUGMENT_LOG(D, "parameters: \"%s\"", parameters.toString().c_str());
781 
782     if (status_t status = filterAndUpdateOffloadMetadata(parameters); status != OK) {
783         AUGMENT_LOG(W, "filtering or updating offload metadata failed: %d", status);
784     }
785 
786     return StreamHalAidl::setParameters(parameters.toString());
787 }
788 
getLatency(uint32_t * latency)789 status_t StreamOutHalAidl::getLatency(uint32_t *latency) {
790     return StreamHalAidl::getLatency(latency);
791 }
792 
setVolume(float left,float right)793 status_t StreamOutHalAidl::setVolume(float left, float right) {
794     AUGMENT_LOG(V, "left %f right %f", left, right);
795     TIME_CHECK();
796     if (!mStream) return NO_INIT;
797     size_t channelCount = audio_channel_count_from_out_mask(mConfig.channel_mask);
798     if (channelCount == 0) channelCount = 2;
799     std::vector<float> volumes(channelCount);
800     if (channelCount == 1) {
801         volumes[0] = (left + right) / 2;
802     } else {
803         volumes[0] = left;
804         volumes[1] = right;
805         for (size_t i = 2; i < channelCount; ++i) {
806             volumes[i] = (left + right) / 2;
807         }
808     }
809     return statusTFromBinderStatus(mStream->setHwVolume(volumes));
810 }
811 
selectPresentation(int presentationId,int programId)812 status_t StreamOutHalAidl::selectPresentation(int presentationId, int programId) {
813     TIME_CHECK();
814     if (!mStream) return NO_INIT;
815     return statusTFromBinderStatus(mStream->selectPresentation(presentationId, programId));
816 }
817 
write(const void * buffer,size_t bytes,size_t * written)818 status_t StreamOutHalAidl::write(const void *buffer, size_t bytes, size_t *written) {
819     if (buffer == nullptr || written == nullptr) {
820         return BAD_VALUE;
821     }
822     // For the output scenario, 'transfer' does not modify the buffer.
823     return transfer(const_cast<void*>(buffer), bytes, written);
824 }
825 
getRenderPosition(uint64_t * dspFrames)826 status_t StreamOutHalAidl::getRenderPosition(uint64_t *dspFrames) {
827     if (dspFrames == nullptr) {
828         return BAD_VALUE;
829     }
830     int64_t aidlFrames = 0, aidlTimestamp = 0;
831     StatePositions statePositions{};
832     RETURN_STATUS_IF_ERROR(
833             getObservablePosition(&aidlFrames, &aidlTimestamp, &statePositions));
834     // Number of audio frames since the stream has exited standby.
835     // See the table at the start of 'StreamHalInterface' on when it needs to reset.
836     int64_t mostRecentResetPoint;
837     if (!mContext.isAsynchronous() && audio_has_proportional_frames(mConfig.format)) {
838         mostRecentResetPoint = statePositions.framesAtStandby;
839     } else {
840         mostRecentResetPoint =
841                 std::max(statePositions.framesAtStandby, statePositions.framesAtFlushOrDrain);
842     }
843     *dspFrames = aidlFrames <= mostRecentResetPoint ? 0 : aidlFrames - mostRecentResetPoint;
844     return OK;
845 }
846 
setCallback(wp<StreamOutHalInterfaceCallback> callback)847 status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
848     AUGMENT_LOG(D);
849     TIME_CHECK();
850     if (!mStream) return NO_INIT;
851     if (!mContext.isAsynchronous()) {
852         AUGMENT_LOG(E, "the callback is intended for asynchronous streams only");
853         return INVALID_OPERATION;
854     }
855     mClientCallback = callback;
856     return OK;
857 }
858 
supportsPauseAndResume(bool * supportsPause,bool * supportsResume)859 status_t StreamOutHalAidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
860     if (supportsPause == nullptr || supportsResume == nullptr) {
861         return BAD_VALUE;
862     }
863     TIME_CHECK();
864     if (!mStream) return NO_INIT;
865     *supportsPause = *supportsResume = true;
866     return OK;
867 }
868 
pause()869 status_t StreamOutHalAidl::pause() {
870     return StreamHalAidl::pause();
871 }
872 
resume()873 status_t StreamOutHalAidl::resume() {
874     return StreamHalAidl::resume();
875 }
876 
supportsDrain(bool * supportsDrain)877 status_t StreamOutHalAidl::supportsDrain(bool *supportsDrain) {
878     if (supportsDrain == nullptr) {
879         return BAD_VALUE;
880     }
881     TIME_CHECK();
882     if (!mStream) return NO_INIT;
883     *supportsDrain = true;
884     return OK;
885 }
886 
drain(bool earlyNotify)887 status_t StreamOutHalAidl::drain(bool earlyNotify) {
888     if (!mStream) return NO_INIT;
889 
890     if (const auto state = getState(); isInDrainedState(state)) {
891         AUGMENT_LOG(D, "stream already in %s state", toString(state).c_str());
892         if (mContext.isAsynchronous()) onDrainReady();
893         return OK;
894     }
895 
896     return StreamHalAidl::drain(earlyNotify);
897 }
898 
flush()899 status_t StreamOutHalAidl::flush() {
900     return StreamHalAidl::flush();
901 }
902 
getPresentationPosition(uint64_t * frames,struct timespec * timestamp)903 status_t StreamOutHalAidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
904     if (frames == nullptr || timestamp == nullptr) {
905         return BAD_VALUE;
906     }
907     int64_t aidlFrames = 0, aidlTimestamp = 0;
908     StatePositions statePositions{};
909     RETURN_STATUS_IF_ERROR(getObservablePosition(&aidlFrames, &aidlTimestamp, &statePositions));
910     // See the table at the start of 'StreamHalInterface'.
911     if (!mContext.isAsynchronous() && audio_has_proportional_frames(mConfig.format)) {
912         *frames = aidlFrames;
913     } else {
914         const int64_t mostRecentResetPoint =
915                 std::max(statePositions.framesAtStandby, statePositions.framesAtFlushOrDrain);
916         *frames = aidlFrames <= mostRecentResetPoint ? 0 : aidlFrames - mostRecentResetPoint;
917     }
918     timestamp->tv_sec = aidlTimestamp / NANOS_PER_SECOND;
919     timestamp->tv_nsec = aidlTimestamp - timestamp->tv_sec * NANOS_PER_SECOND;
920     return OK;
921 }
922 
presentationComplete()923 status_t StreamOutHalAidl::presentationComplete() {
924     AUGMENT_LOG(D);
925     return OK;
926 }
927 
updateSourceMetadata(const StreamOutHalInterface::SourceMetadata & sourceMetadata)928 status_t StreamOutHalAidl::updateSourceMetadata(
929         const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
930     TIME_CHECK();
931     if (!mStream) return NO_INIT;
932     ::aidl::android::hardware::audio::common::SourceMetadata aidlMetadata =
933               VALUE_OR_RETURN_STATUS(legacy2aidl_SourceMetadata(sourceMetadata));
934     return statusTFromBinderStatus(mStream->updateMetadata(aidlMetadata));
935 }
936 
getDualMonoMode(audio_dual_mono_mode_t * mode)937 status_t StreamOutHalAidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
938     TIME_CHECK();
939     if (!mStream) return NO_INIT;
940     if (mode == nullptr) {
941         return BAD_VALUE;
942     }
943     ::aidl::android::media::audio::common::AudioDualMonoMode aidlMode;
944     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mStream->getDualMonoMode(&aidlMode)));
945     *mode = VALUE_OR_RETURN_STATUS(
946             ::aidl::android::aidl2legacy_AudioDualMonoMode_audio_dual_mono_mode_t(aidlMode));
947     return OK;
948 }
949 
setDualMonoMode(audio_dual_mono_mode_t mode)950 status_t StreamOutHalAidl::setDualMonoMode(audio_dual_mono_mode_t mode) {
951     TIME_CHECK();
952     if (!mStream) return NO_INIT;
953     ::aidl::android::media::audio::common::AudioDualMonoMode aidlMode = VALUE_OR_RETURN_STATUS(
954             ::aidl::android::legacy2aidl_audio_dual_mono_mode_t_AudioDualMonoMode(mode));
955     return statusTFromBinderStatus(mStream->setDualMonoMode(aidlMode));
956 }
957 
getAudioDescriptionMixLevel(float * leveldB)958 status_t StreamOutHalAidl::getAudioDescriptionMixLevel(float* leveldB) {
959     TIME_CHECK();
960     if (!mStream) return NO_INIT;
961     if (leveldB == nullptr) {
962         return BAD_VALUE;
963     }
964     return statusTFromBinderStatus(mStream->getAudioDescriptionMixLevel(leveldB));
965 }
966 
setAudioDescriptionMixLevel(float leveldB)967 status_t StreamOutHalAidl::setAudioDescriptionMixLevel(float leveldB) {
968     TIME_CHECK();
969     if (!mStream) return NO_INIT;
970     return statusTFromBinderStatus(mStream->setAudioDescriptionMixLevel(leveldB));
971 }
972 
getPlaybackRateParameters(audio_playback_rate_t * playbackRate)973 status_t StreamOutHalAidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
974     TIME_CHECK();
975     if (!mStream) return NO_INIT;
976     if (playbackRate == nullptr) {
977         return BAD_VALUE;
978     }
979     ::aidl::android::media::audio::common::AudioPlaybackRate aidlRate;
980     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mStream->getPlaybackRateParameters(&aidlRate)));
981     *playbackRate = VALUE_OR_RETURN_STATUS(
982             ::aidl::android::aidl2legacy_AudioPlaybackRate_audio_playback_rate_t(aidlRate));
983     return OK;
984 }
985 
setPlaybackRateParameters(const audio_playback_rate_t & playbackRate)986 status_t StreamOutHalAidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
987     TIME_CHECK();
988     if (!mStream) return NO_INIT;
989     ::aidl::android::media::audio::common::AudioPlaybackRate aidlRate = VALUE_OR_RETURN_STATUS(
990             ::aidl::android::legacy2aidl_audio_playback_rate_t_AudioPlaybackRate(playbackRate));
991     return statusTFromBinderStatus(mStream->setPlaybackRateParameters(aidlRate));
992 }
993 
setEventCallback(const sp<StreamOutHalInterfaceEventCallback> & callback)994 status_t StreamOutHalAidl::setEventCallback(
995         const sp<StreamOutHalInterfaceEventCallback>& callback) {
996     TIME_CHECK();
997     if (!mStream) return NO_INIT;
998     if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
999         broker->setStreamOutEventCallback(static_cast<StreamOutHalInterface*>(this), callback);
1000     }
1001     return OK;
1002 }
1003 
setLatencyMode(audio_latency_mode_t mode)1004 status_t StreamOutHalAidl::setLatencyMode(audio_latency_mode_t mode) {
1005     TIME_CHECK();
1006     if (!mStream) return NO_INIT;
1007     ::aidl::android::media::audio::common::AudioLatencyMode aidlMode = VALUE_OR_RETURN_STATUS(
1008             ::aidl::android::legacy2aidl_audio_latency_mode_t_AudioLatencyMode(mode));
1009     return statusTFromBinderStatus(mStream->setLatencyMode(aidlMode));
1010 };
1011 
getRecommendedLatencyModes(std::vector<audio_latency_mode_t> * modes)1012 status_t StreamOutHalAidl::getRecommendedLatencyModes(std::vector<audio_latency_mode_t> *modes) {
1013     TIME_CHECK();
1014     if (!mStream) return NO_INIT;
1015     if (modes == nullptr) {
1016         return BAD_VALUE;
1017     }
1018     std::vector<::aidl::android::media::audio::common::AudioLatencyMode> aidlModes;
1019     RETURN_STATUS_IF_ERROR(
1020             statusTFromBinderStatus(mStream->getRecommendedLatencyModes(&aidlModes)));
1021     *modes = VALUE_OR_RETURN_STATUS(
1022             ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
1023                     aidlModes,
1024                     ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
1025     return OK;
1026 };
1027 
setLatencyModeCallback(const sp<StreamOutHalInterfaceLatencyModeCallback> & callback)1028 status_t StreamOutHalAidl::setLatencyModeCallback(
1029         const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) {
1030     TIME_CHECK();
1031     if (!mStream) return NO_INIT;
1032     if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
1033         broker->setStreamOutLatencyModeCallback(
1034                 static_cast<StreamOutHalInterface*>(this), callback);
1035     }
1036     return OK;
1037 };
1038 
exit()1039 status_t StreamOutHalAidl::exit() {
1040     return StreamHalAidl::exit();
1041 }
1042 
onWriteReady()1043 void StreamOutHalAidl::onWriteReady() {
1044     onAsyncTransferReady();
1045     if (auto clientCb = mClientCallback.load().promote(); clientCb != nullptr) {
1046         clientCb->onWriteReady();
1047     }
1048 }
1049 
onDrainReady()1050 void StreamOutHalAidl::onDrainReady() {
1051     onAsyncDrainReady();
1052     if (auto clientCb = mClientCallback.load().promote(); clientCb != nullptr) {
1053         clientCb->onDrainReady();
1054     }
1055 }
1056 
onError(bool isHardError)1057 void StreamOutHalAidl::onError(bool isHardError) {
1058     onAsyncError();
1059     if (auto clientCb = mClientCallback.load().promote(); clientCb != nullptr) {
1060         clientCb->onError(isHardError);
1061     }
1062 }
1063 
filterAndUpdateOffloadMetadata(AudioParameter & parameters)1064 status_t StreamOutHalAidl::filterAndUpdateOffloadMetadata(AudioParameter &parameters) {
1065     TIME_CHECK();
1066     bool updateMetadata = false;
1067     if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1068                 parameters, String8(AudioParameter::keyOffloadCodecAverageBitRate),
1069                 [&](int value) {
1070                     return value >= 0 ?
1071                             mOffloadMetadata.averageBitRatePerSecond = value, OK : BAD_VALUE;
1072                 }))) {
1073         updateMetadata = true;
1074     }
1075     if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1076                 parameters, String8(AudioParameter::keyOffloadCodecSampleRate),
1077                 [&](int value) {
1078                     return value > 0 ? mOffloadMetadata.sampleRate = value, OK : BAD_VALUE;
1079                 }))) {
1080         updateMetadata = true;
1081     }
1082     if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1083                 parameters, String8(AudioParameter::keyOffloadCodecChannels),
1084                 [&](int value) -> status_t {
1085                     if (value > 0) {
1086                         audio_channel_mask_t channel_mask = audio_channel_out_mask_from_count(
1087                                 static_cast<uint32_t>(value));
1088                         if (channel_mask == AUDIO_CHANNEL_INVALID) return BAD_VALUE;
1089                         mOffloadMetadata.channelMask = VALUE_OR_RETURN_STATUS(
1090                                 ::aidl::android::legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
1091                                         channel_mask, false /*isInput*/));
1092                         return OK;
1093                     }
1094                     return BAD_VALUE;
1095                 }))) {
1096         updateMetadata = true;
1097     }
1098     if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1099                 parameters, String8(AudioParameter::keyOffloadCodecDelaySamples),
1100                 [&](int value) {
1101                     // The legacy keys are misnamed, the value is in frames.
1102                     return value >= 0 ? mOffloadMetadata.delayFrames = value, OK : BAD_VALUE;
1103                 }))) {
1104         updateMetadata = true;
1105     }
1106     if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1107                 parameters, String8(AudioParameter::keyOffloadCodecPaddingSamples),
1108                 [&](int value) {
1109                     // The legacy keys are misnamed, the value is in frames.
1110                     return value >= 0 ? mOffloadMetadata.paddingFrames = value, OK : BAD_VALUE;
1111                 }))) {
1112         updateMetadata = true;
1113     }
1114     if (updateMetadata) {
1115         AUGMENT_LOG(D, "set offload metadata %s", mOffloadMetadata.toString().c_str());
1116         if (status_t status = statusTFromBinderStatus(
1117                         mStream->updateOffloadMetadata(mOffloadMetadata)); status != OK) {
1118             AUGMENT_LOG(E, "updateOffloadMetadata failed %d", status);
1119             return status;
1120         }
1121     }
1122     return OK;
1123 }
1124 
1125 // static
1126 ConversionResult<::aidl::android::hardware::audio::common::SinkMetadata>
legacy2aidl_SinkMetadata(const StreamInHalInterface::SinkMetadata & legacy)1127 StreamInHalAidl::legacy2aidl_SinkMetadata(const StreamInHalInterface::SinkMetadata& legacy) {
1128     ::aidl::android::hardware::audio::common::SinkMetadata aidl;
1129     aidl.tracks = VALUE_OR_RETURN(
1130             ::aidl::android::convertContainer<std::vector<RecordTrackMetadata>>(
1131                     legacy.tracks,
1132                     ::aidl::android::legacy2aidl_record_track_metadata_v7_RecordTrackMetadata));
1133     return aidl;
1134 }
1135 
StreamInHalAidl(const audio_config & config,StreamContextAidl && context,int32_t nominalLatency,const std::shared_ptr<IStreamIn> & stream,const std::shared_ptr<IHalAdapterVendorExtension> & vext,const sp<MicrophoneInfoProvider> & micInfoProvider)1136 StreamInHalAidl::StreamInHalAidl(
1137         const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
1138         const std::shared_ptr<IStreamIn>& stream,
1139         const std::shared_ptr<IHalAdapterVendorExtension>& vext,
1140         const sp<MicrophoneInfoProvider>& micInfoProvider)
1141         : StreamHalAidl("StreamInHalAidl", true /*isInput*/, config, nominalLatency,
1142                 std::move(context), getStreamCommon(stream), vext),
1143           mStream(stream), mMicInfoProvider(micInfoProvider) {}
1144 
setGain(float gain)1145 status_t StreamInHalAidl::setGain(float gain) {
1146     TIME_CHECK();
1147     if (!mStream) return NO_INIT;
1148     const size_t channelCount = audio_channel_count_from_in_mask(mConfig.channel_mask);
1149     std::vector<float> gains(channelCount != 0 ? channelCount : 1, gain);
1150     return statusTFromBinderStatus(mStream->setHwGain(gains));
1151 }
1152 
read(void * buffer,size_t bytes,size_t * read)1153 status_t StreamInHalAidl::read(void *buffer, size_t bytes, size_t *read) {
1154     if (buffer == nullptr || read == nullptr) {
1155         return BAD_VALUE;
1156     }
1157     return transfer(buffer, bytes, read);
1158 }
1159 
getInputFramesLost(uint32_t * framesLost)1160 status_t StreamInHalAidl::getInputFramesLost(uint32_t *framesLost) {
1161     if (framesLost == nullptr) {
1162         return BAD_VALUE;
1163     }
1164     int32_t aidlXruns = 0;
1165     RETURN_STATUS_IF_ERROR(getXruns(&aidlXruns));
1166     *framesLost = std::max<int32_t>(0, aidlXruns);
1167     return OK;
1168 }
1169 
getCapturePosition(int64_t * frames,int64_t * time)1170 status_t StreamInHalAidl::getCapturePosition(int64_t *frames, int64_t *time) {
1171     if (frames == nullptr || time == nullptr) {
1172         return BAD_VALUE;
1173     }
1174     return getObservablePosition(frames, time);
1175 }
1176 
getActiveMicrophones(std::vector<media::MicrophoneInfoFw> * microphones)1177 status_t StreamInHalAidl::getActiveMicrophones(std::vector<media::MicrophoneInfoFw> *microphones) {
1178     if (!microphones) {
1179         return BAD_VALUE;
1180     }
1181     TIME_CHECK();
1182     if (!mStream) return NO_INIT;
1183     sp<MicrophoneInfoProvider> micInfoProvider = mMicInfoProvider.promote();
1184     if (!micInfoProvider) return NO_INIT;
1185     auto staticInfo = micInfoProvider->getMicrophoneInfo();
1186     if (!staticInfo) return INVALID_OPERATION;
1187     std::vector<MicrophoneDynamicInfo> dynamicInfo;
1188     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mStream->getActiveMicrophones(&dynamicInfo)));
1189     std::vector<media::MicrophoneInfoFw> result;
1190     result.reserve(dynamicInfo.size());
1191     for (const auto& d : dynamicInfo) {
1192         const auto staticInfoIt = std::find_if(staticInfo->begin(), staticInfo->end(),
1193                 [&](const auto& s) { return s.id == d.id; });
1194         if (staticInfoIt != staticInfo->end()) {
1195             // Convert into the c++ backend type from the ndk backend type via the legacy structure.
1196             audio_microphone_characteristic_t legacy = VALUE_OR_RETURN_STATUS(
1197                     ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t(
1198                             *staticInfoIt, d));
1199             media::MicrophoneInfoFw info = VALUE_OR_RETURN_STATUS(
1200                     ::android::legacy2aidl_audio_microphone_characteristic_t_MicrophoneInfoFw(
1201                             legacy));
1202             // Note: info.portId is not filled because it's a bit of framework info.
1203             result.push_back(std::move(info));
1204         } else {
1205             AUGMENT_LOG(E, "no static info for active microphone with id '%s'", d.id.c_str());
1206         }
1207     }
1208     *microphones = std::move(result);
1209     return OK;
1210 }
1211 
updateSinkMetadata(const StreamInHalInterface::SinkMetadata & sinkMetadata)1212 status_t StreamInHalAidl::updateSinkMetadata(
1213         const StreamInHalInterface::SinkMetadata& sinkMetadata) {
1214     TIME_CHECK();
1215     if (!mStream) return NO_INIT;
1216     ::aidl::android::hardware::audio::common::SinkMetadata aidlMetadata =
1217               VALUE_OR_RETURN_STATUS(legacy2aidl_SinkMetadata(sinkMetadata));
1218     return statusTFromBinderStatus(mStream->updateMetadata(aidlMetadata));
1219 }
1220 
setPreferredMicrophoneDirection(audio_microphone_direction_t direction)1221 status_t StreamInHalAidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
1222     TIME_CHECK();
1223     if (!mStream) return NO_INIT;
1224     ::aidl::android::hardware::audio::core::IStreamIn::MicrophoneDirection aidlDirection =
1225               VALUE_OR_RETURN_STATUS(
1226                       ::aidl::android::legacy2aidl_audio_microphone_direction_t_MicrophoneDirection(
1227                               direction));
1228     return statusTFromBinderStatus(mStream->setMicrophoneDirection(aidlDirection));
1229 }
1230 
setPreferredMicrophoneFieldDimension(float zoom)1231 status_t StreamInHalAidl::setPreferredMicrophoneFieldDimension(float zoom) {
1232     TIME_CHECK();
1233     if (!mStream) return NO_INIT;
1234     return statusTFromBinderStatus(mStream->setMicrophoneFieldDimension(zoom));
1235 }
1236 
1237 } // namespace android
1238