1 /*
2 * Copyright (C) 2022 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 #pragma once
18
19 #include <atomic>
20 #include <chrono>
21 #include <cstdlib>
22 #include <map>
23 #include <memory>
24 #include <optional>
25 #include <variant>
26
27 #include <StreamWorker.h>
28 #include <Utils.h>
29 #include <aidl/android/hardware/audio/common/SinkMetadata.h>
30 #include <aidl/android/hardware/audio/common/SourceMetadata.h>
31 #include <aidl/android/hardware/audio/core/BnStreamCommon.h>
32 #include <aidl/android/hardware/audio/core/BnStreamIn.h>
33 #include <aidl/android/hardware/audio/core/BnStreamOut.h>
34 #include <aidl/android/hardware/audio/core/IStreamCallback.h>
35 #include <aidl/android/hardware/audio/core/IStreamOutEventCallback.h>
36 #include <aidl/android/hardware/audio/core/StreamDescriptor.h>
37 #include <aidl/android/media/audio/common/AudioDevice.h>
38 #include <aidl/android/media/audio/common/AudioIoFlags.h>
39 #include <aidl/android/media/audio/common/AudioOffloadInfo.h>
40 #include <aidl/android/media/audio/common/MicrophoneInfo.h>
41 #include <android-base/thread_annotations.h>
42 #include <error/expected_utils.h>
43 #include <fmq/AidlMessageQueue.h>
44 #include <system/thread_defs.h>
45 #include <utils/Errors.h>
46
47 #include "core-impl/ChildInterface.h"
48 #include "core-impl/SoundDose.h"
49 #include "core-impl/utils.h"
50
51 namespace aidl::android::hardware::audio::core {
52
53 // This class is similar to StreamDescriptor, but unlike
54 // the descriptor, it actually owns the objects implementing
55 // data exchange: FMQs etc, whereas StreamDescriptor only
56 // contains their descriptors.
57 class StreamContext {
58 public:
59 typedef ::android::AidlMessageQueue<
60 StreamDescriptor::Command,
61 ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
62 CommandMQ;
63 typedef ::android::AidlMessageQueue<
64 StreamDescriptor::Reply, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
65 ReplyMQ;
66 typedef ::android::AidlMessageQueue<
67 int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
68 DataMQ;
69
70 // Ensure that this value is not used by any of StreamDescriptor.State enums
71 static constexpr StreamDescriptor::State STATE_CLOSED =
72 static_cast<StreamDescriptor::State>(-1);
73
74 struct DebugParameters {
75 // An extra delay for transient states, in ms.
76 int transientStateDelayMs = 0;
77 // Force the "burst" command to move the SM to the TRANSFERRING state.
78 bool forceTransientBurst = false;
79 // Force the "drain" command to be synchronous, going directly to the IDLE state.
80 bool forceSynchronousDrain = false;
81 // Force the "drain early notify" command to keep the SM in the DRAINING state
82 // after sending 'onDrainReady' callback. The SM moves to IDLE after
83 // 'transientStateDelayMs'.
84 bool forceDrainToDraining = false;
85 };
86
87 StreamContext() = default;
StreamContext(std::unique_ptr<CommandMQ> commandMQ,std::unique_ptr<ReplyMQ> replyMQ,const::aidl::android::media::audio::common::AudioFormatDescription & format,const::aidl::android::media::audio::common::AudioChannelLayout & channelLayout,int sampleRate,const::aidl::android::media::audio::common::AudioIoFlags & flags,int32_t nominalLatencyMs,int32_t mixPortHandle,std::unique_ptr<DataMQ> dataMQ,std::shared_ptr<IStreamCallback> asyncCallback,std::shared_ptr<IStreamOutEventCallback> outEventCallback,std::weak_ptr<sounddose::StreamDataProcessorInterface> streamDataProcessor,DebugParameters debugParameters)88 StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
89 const ::aidl::android::media::audio::common::AudioFormatDescription& format,
90 const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
91 int sampleRate, const ::aidl::android::media::audio::common::AudioIoFlags& flags,
92 int32_t nominalLatencyMs, int32_t mixPortHandle, std::unique_ptr<DataMQ> dataMQ,
93 std::shared_ptr<IStreamCallback> asyncCallback,
94 std::shared_ptr<IStreamOutEventCallback> outEventCallback,
95 std::weak_ptr<sounddose::StreamDataProcessorInterface> streamDataProcessor,
96 DebugParameters debugParameters)
97 : mCommandMQ(std::move(commandMQ)),
98 mInternalCommandCookie(std::rand() | 1 /* make sure it's not 0 */),
99 mReplyMQ(std::move(replyMQ)),
100 mFormat(format),
101 mChannelLayout(channelLayout),
102 mSampleRate(sampleRate),
103 mFlags(flags),
104 mNominalLatencyMs(nominalLatencyMs),
105 mMixPortHandle(mixPortHandle),
106 mDataMQ(std::move(dataMQ)),
107 mAsyncCallback(asyncCallback),
108 mOutEventCallback(outEventCallback),
109 mStreamDataProcessor(streamDataProcessor),
110 mDebugParameters(debugParameters) {}
111
112 void fillDescriptor(StreamDescriptor* desc);
getAsyncCallback()113 std::shared_ptr<IStreamCallback> getAsyncCallback() const { return mAsyncCallback; }
114 size_t getBufferSizeInFrames() const;
getChannelLayout()115 ::aidl::android::media::audio::common::AudioChannelLayout getChannelLayout() const {
116 return mChannelLayout;
117 }
getCommandMQ()118 CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
getDataMQ()119 DataMQ* getDataMQ() const { return mDataMQ.get(); }
getFormat()120 ::aidl::android::media::audio::common::AudioFormatDescription getFormat() const {
121 return mFormat;
122 }
getFlags()123 ::aidl::android::media::audio::common::AudioIoFlags getFlags() const { return mFlags; }
getForceTransientBurst()124 bool getForceTransientBurst() const { return mDebugParameters.forceTransientBurst; }
getForceSynchronousDrain()125 bool getForceSynchronousDrain() const { return mDebugParameters.forceSynchronousDrain; }
getForceDrainToDraining()126 bool getForceDrainToDraining() const { return mDebugParameters.forceDrainToDraining; }
127 size_t getFrameSize() const;
getInternalCommandCookie()128 int getInternalCommandCookie() const { return mInternalCommandCookie; }
getMixPortHandle()129 int32_t getMixPortHandle() const { return mMixPortHandle; }
getNominalLatencyMs()130 int32_t getNominalLatencyMs() const { return mNominalLatencyMs; }
getOutEventCallback()131 std::shared_ptr<IStreamOutEventCallback> getOutEventCallback() const {
132 return mOutEventCallback;
133 }
getStreamDataProcessor()134 std::weak_ptr<sounddose::StreamDataProcessorInterface> getStreamDataProcessor() const {
135 return mStreamDataProcessor;
136 }
137 void startStreamDataProcessor();
getReplyMQ()138 ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
getTransientStateDelayMs()139 int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; }
getSampleRate()140 int getSampleRate() const { return mSampleRate; }
isInput()141 bool isInput() const {
142 return mFlags.getTag() == ::aidl::android::media::audio::common::AudioIoFlags::input;
143 }
144 bool isValid() const;
145 // 'reset' is called on a Binder thread when closing the stream. Does not use
146 // locking because it only cleans MQ pointers which were also set on the Binder thread.
147 void reset();
148 // 'advanceFrameCount' and 'getFrameCount' are only called on the worker thread.
advanceFrameCount(size_t increase)149 long advanceFrameCount(size_t increase) { return mFrameCount += increase; }
getFrameCount()150 long getFrameCount() const { return mFrameCount; }
151
152 private:
153 // Fields are non const to allow move assignment.
154 std::unique_ptr<CommandMQ> mCommandMQ;
155 int mInternalCommandCookie; // The value used to confirm that the command was posted internally
156 std::unique_ptr<ReplyMQ> mReplyMQ;
157 ::aidl::android::media::audio::common::AudioFormatDescription mFormat;
158 ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
159 int mSampleRate;
160 ::aidl::android::media::audio::common::AudioIoFlags mFlags;
161 int32_t mNominalLatencyMs;
162 int32_t mMixPortHandle;
163 std::unique_ptr<DataMQ> mDataMQ;
164 std::shared_ptr<IStreamCallback> mAsyncCallback;
165 std::shared_ptr<IStreamOutEventCallback> mOutEventCallback; // Only used by output streams
166 std::weak_ptr<sounddose::StreamDataProcessorInterface> mStreamDataProcessor;
167 DebugParameters mDebugParameters;
168 long mFrameCount = 0;
169 };
170
171 // This interface provides operations of the stream which are executed on the worker thread.
172 struct DriverInterface {
173 virtual ~DriverInterface() = default;
174 // All the methods below are called on the worker thread.
175 virtual ::android::status_t init() = 0; // This function is only called once.
176 virtual ::android::status_t drain(StreamDescriptor::DrainMode mode) = 0;
177 virtual ::android::status_t flush() = 0;
178 virtual ::android::status_t pause() = 0;
179 virtual ::android::status_t standby() = 0;
180 virtual ::android::status_t start() = 0;
181 virtual ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
182 int32_t* latencyMs) = 0;
183 // No need to implement 'refinePosition' unless the driver can provide more precise
184 // data than just total frame count. For example, the driver may correctly account
185 // for any intermediate buffers.
refinePositionDriverInterface186 virtual ::android::status_t refinePosition(StreamDescriptor::Position* /*position*/) {
187 return ::android::OK;
188 }
189 // Implement 'getMmapPositionAndLatency' is necessary if driver can support mmap stream.
getMmapPositionAndLatencyDriverInterface190 virtual ::android::status_t getMmapPositionAndLatency(StreamDescriptor::Position* /*position*/,
191 int32_t* /*latency*/) {
192 return ::android::OK;
193 }
194 virtual void shutdown() = 0; // This function is only called once.
195 };
196
197 class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic {
198 public:
isClosed()199 bool isClosed() const { return mState == StreamContext::STATE_CLOSED; }
setClosed()200 StreamDescriptor::State setClosed() {
201 auto prevState = mState.exchange(StreamContext::STATE_CLOSED);
202 if (prevState != StreamContext::STATE_CLOSED) {
203 mStatePriorToClosing = prevState;
204 }
205 return mStatePriorToClosing;
206 }
setIsConnected(bool connected)207 void setIsConnected(bool connected) { mIsConnected = connected; }
208
209 protected:
210 using DataBufferElement = int8_t;
211
StreamWorkerCommonLogic(StreamContext * context,DriverInterface * driver)212 StreamWorkerCommonLogic(StreamContext* context, DriverInterface* driver)
213 : mContext(context),
214 mDriver(driver),
215 mTransientStateDelayMs(context->getTransientStateDelayMs()) {}
216 pid_t getTid() const;
217 std::string init() override;
218 void populateReply(StreamDescriptor::Reply* reply, bool isConnected) const;
219 void populateReplyWrongState(StreamDescriptor::Reply* reply,
220 const StreamDescriptor::Command& command) const;
switchToTransientState(StreamDescriptor::State state)221 void switchToTransientState(StreamDescriptor::State state) {
222 mState = state;
223 mTransientStateStart = std::chrono::steady_clock::now();
224 }
225
226 // The context is only used for reading, except for updating the frame count,
227 // which happens on the worker thread only.
228 StreamContext* const mContext;
229 DriverInterface* const mDriver;
230 // This is the state the stream was in before being closed. It is retrieved by the main
231 // thread after joining the worker thread.
232 StreamDescriptor::State mStatePriorToClosing = StreamDescriptor::State::STANDBY;
233 // Atomic fields are used both by the main and worker threads.
234 std::atomic<bool> mIsConnected = false;
235 static_assert(std::atomic<StreamDescriptor::State>::is_always_lock_free);
236 std::atomic<StreamDescriptor::State> mState = StreamDescriptor::State::STANDBY;
237 // All fields below are used on the worker thread only.
238 const std::chrono::duration<int, std::milli> mTransientStateDelayMs;
239 std::chrono::time_point<std::chrono::steady_clock> mTransientStateStart;
240 // We use an array and the "size" field instead of a vector to be able to detect
241 // memory allocation issues.
242 std::unique_ptr<DataBufferElement[]> mDataBuffer;
243 size_t mDataBufferSize;
244 };
245
246 // This interface is used to decouple stream implementations from a concrete StreamWorker
247 // implementation.
248 struct StreamWorkerInterface {
249 using CreateInstance =
250 std::function<StreamWorkerInterface*(StreamContext* context, DriverInterface* driver)>;
251 virtual ~StreamWorkerInterface() = default;
252 virtual bool isClosed() const = 0;
253 virtual void setIsConnected(bool isConnected) = 0;
254 virtual StreamDescriptor::State setClosed() = 0;
255 virtual bool start() = 0;
256 virtual pid_t getTid() = 0;
257 virtual void join() = 0;
258 virtual std::string getError() = 0;
259 };
260
261 template <class WorkerLogic>
262 class StreamWorkerImpl : public StreamWorkerInterface,
263 public ::android::hardware::audio::common::StreamWorker<WorkerLogic> {
264 using WorkerImpl = ::android::hardware::audio::common::StreamWorker<WorkerLogic>;
265
266 public:
StreamWorkerImpl(StreamContext * context,DriverInterface * driver)267 StreamWorkerImpl(StreamContext* context, DriverInterface* driver)
268 : WorkerImpl(context, driver) {}
isClosed()269 bool isClosed() const override { return WorkerImpl::isClosed(); }
setIsConnected(bool isConnected)270 void setIsConnected(bool isConnected) override { WorkerImpl::setIsConnected(isConnected); }
setClosed()271 StreamDescriptor::State setClosed() override { return WorkerImpl::setClosed(); }
start()272 bool start() override {
273 // This is an "audio service thread," must have elevated priority.
274 return WorkerImpl::start(WorkerImpl::kThreadName, ANDROID_PRIORITY_URGENT_AUDIO);
275 }
getTid()276 pid_t getTid() override { return WorkerImpl::getTid(); }
join()277 void join() override { return WorkerImpl::join(); }
getError()278 std::string getError() override { return WorkerImpl::getError(); }
279 };
280
281 class StreamInWorkerLogic : public StreamWorkerCommonLogic {
282 public:
283 static const std::string kThreadName;
StreamInWorkerLogic(StreamContext * context,DriverInterface * driver)284 StreamInWorkerLogic(StreamContext* context, DriverInterface* driver)
285 : StreamWorkerCommonLogic(context, driver) {}
286
287 protected:
288 Status cycle() override;
289
290 private:
291 bool read(size_t clientSize, StreamDescriptor::Reply* reply);
292 };
293 using StreamInWorker = StreamWorkerImpl<StreamInWorkerLogic>;
294
295 class StreamOutWorkerLogic : public StreamWorkerCommonLogic {
296 public:
297 static const std::string kThreadName;
StreamOutWorkerLogic(StreamContext * context,DriverInterface * driver)298 StreamOutWorkerLogic(StreamContext* context, DriverInterface* driver)
299 : StreamWorkerCommonLogic(context, driver),
300 mEventCallback(context->getOutEventCallback()) {}
301
302 protected:
303 Status cycle() override;
304
305 private:
306 bool write(size_t clientSize, StreamDescriptor::Reply* reply);
307
308 std::shared_ptr<IStreamOutEventCallback> mEventCallback;
309
310 enum OnDrainReadyStatus : int32_t { IGNORE /*used for DRAIN_ALL*/, UNSENT, SENT };
311 OnDrainReadyStatus mOnDrainReadyStatus = OnDrainReadyStatus::IGNORE;
312 };
313 using StreamOutWorker = StreamWorkerImpl<StreamOutWorkerLogic>;
314
315 // This interface provides operations of the stream which are executed on a Binder pool thread.
316 // These methods originate both from the AIDL interface and its implementation.
317 struct StreamCommonInterface {
318 using ConnectedDevices = std::vector<::aidl::android::media::audio::common::AudioDevice>;
319 using Metadata =
320 std::variant<::aidl::android::hardware::audio::common::SinkMetadata /*IStreamIn*/,
321 ::aidl::android::hardware::audio::common::SourceMetadata /*IStreamOut*/>;
322
isInputStreamCommonInterface323 static constexpr bool isInput(const Metadata& metadata) { return metadata.index() == 0; }
324
325 virtual ~StreamCommonInterface() = default;
326 // Methods below originate from the 'IStreamCommon' interface.
327 // This is semantically equivalent to inheriting from 'IStreamCommon' with a benefit
328 // that concrete stream implementations can inherit both from this interface and IStreamIn/Out.
329 virtual ndk::ScopedAStatus close() = 0;
330 virtual ndk::ScopedAStatus prepareToClose() = 0;
331 virtual ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) = 0;
332 virtual ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
333 std::vector<VendorParameter>* _aidl_return) = 0;
334 virtual ndk::ScopedAStatus setVendorParameters(
335 const std::vector<VendorParameter>& in_parameters, bool in_async) = 0;
336 virtual ndk::ScopedAStatus addEffect(
337 const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>&
338 in_effect) = 0;
339 virtual ndk::ScopedAStatus removeEffect(
340 const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>&
341 in_effect) = 0;
342 // Methods below are common for both 'IStreamIn' and 'IStreamOut'. Note that
343 // 'updateMetadata' in them uses an individual structure which is wrapped here.
344 // The 'Common' suffix is added to distinguish them from the methods from 'IStreamIn/Out'.
345 virtual ndk::ScopedAStatus getStreamCommonCommon(
346 std::shared_ptr<IStreamCommon>* _aidl_return) = 0;
347 virtual ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) = 0;
348 // Methods below are called by implementation of 'IModule', 'IStreamIn' and 'IStreamOut'.
349 virtual ndk::ScopedAStatus initInstance(
350 const std::shared_ptr<StreamCommonInterface>& delegate) = 0;
351 virtual const StreamContext& getContext() const = 0;
352 virtual bool isClosed() const = 0;
353 virtual const ConnectedDevices& getConnectedDevices() const = 0;
354 virtual ndk::ScopedAStatus setConnectedDevices(
355 const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) = 0;
356 virtual ndk::ScopedAStatus bluetoothParametersUpdated() = 0;
357 virtual ndk::ScopedAStatus setGain(float gain) = 0;
358 };
359
360 // This is equivalent to automatically generated 'IStreamCommonDelegator' but uses
361 // a weak pointer to avoid creating a reference loop. The loop will occur because
362 // 'IStreamIn/Out.getStreamCommon' must return the same instance every time, thus
363 // the stream implementation must hold a strong pointer to an instance of 'IStreamCommon'.
364 // Also, we use 'StreamCommonInterface' here instead of 'IStreamCommon'.
365 class StreamCommonDelegator : public BnStreamCommon {
366 public:
StreamCommonDelegator(const std::shared_ptr<StreamCommonInterface> & delegate)367 explicit StreamCommonDelegator(const std::shared_ptr<StreamCommonInterface>& delegate)
368 : mDelegate(delegate) {}
369
370 private:
close()371 ndk::ScopedAStatus close() override {
372 auto delegate = mDelegate.lock();
373 return delegate != nullptr ? delegate->close()
374 : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
375 }
prepareToClose()376 ndk::ScopedAStatus prepareToClose() override {
377 auto delegate = mDelegate.lock();
378 return delegate != nullptr ? delegate->prepareToClose()
379 : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
380 }
updateHwAvSyncId(int32_t in_hwAvSyncId)381 ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override {
382 auto delegate = mDelegate.lock();
383 return delegate != nullptr ? delegate->updateHwAvSyncId(in_hwAvSyncId)
384 : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
385 }
getVendorParameters(const std::vector<std::string> & in_ids,std::vector<VendorParameter> * _aidl_return)386 ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
387 std::vector<VendorParameter>* _aidl_return) override {
388 auto delegate = mDelegate.lock();
389 return delegate != nullptr ? delegate->getVendorParameters(in_ids, _aidl_return)
390 : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
391 }
setVendorParameters(const std::vector<VendorParameter> & in_parameters,bool in_async)392 ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
393 bool in_async) override {
394 auto delegate = mDelegate.lock();
395 return delegate != nullptr ? delegate->setVendorParameters(in_parameters, in_async)
396 : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
397 }
addEffect(const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> & in_effect)398 ndk::ScopedAStatus addEffect(
399 const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
400 override {
401 auto delegate = mDelegate.lock();
402 return delegate != nullptr ? delegate->addEffect(in_effect)
403 : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
404 }
removeEffect(const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> & in_effect)405 ndk::ScopedAStatus removeEffect(
406 const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
407 override {
408 auto delegate = mDelegate.lock();
409 return delegate != nullptr ? delegate->removeEffect(in_effect)
410 : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
411 }
412 // It is possible that on the client side the proxy for IStreamCommon will outlive
413 // the IStream* instance, and the server side IStream* instance will get destroyed
414 // while this IStreamCommon instance is still alive.
415 std::weak_ptr<StreamCommonInterface> mDelegate;
416 };
417
418 // The implementation of DriverInterface must be provided by each concrete stream implementation.
419 // Note that StreamCommonImpl does not own the context. This is to support swapping on the fly
420 // implementations of the stream while keeping the same IStreamIn/Out instance. It's that instance
421 // who must be owner of the context.
422 class StreamCommonImpl : virtual public StreamCommonInterface, virtual public DriverInterface {
423 public:
StreamCommonImpl(StreamContext * context,const Metadata & metadata,const StreamWorkerInterface::CreateInstance & createWorker)424 StreamCommonImpl(StreamContext* context, const Metadata& metadata,
425 const StreamWorkerInterface::CreateInstance& createWorker)
426 : mContext(*context), mMetadata(metadata), mWorker(createWorker(context, this)) {}
StreamCommonImpl(StreamContext * context,const Metadata & metadata)427 StreamCommonImpl(StreamContext* context, const Metadata& metadata)
428 : StreamCommonImpl(
429 context, metadata,
430 isInput(metadata) ? getDefaultInWorkerCreator() : getDefaultOutWorkerCreator()) {}
431 ~StreamCommonImpl();
432
433 ndk::ScopedAStatus close() override;
434 ndk::ScopedAStatus prepareToClose() override;
435 ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override;
436 ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
437 std::vector<VendorParameter>* _aidl_return) override;
438 ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
439 bool in_async) override;
440 ndk::ScopedAStatus addEffect(
441 const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
442 override;
443 ndk::ScopedAStatus removeEffect(
444 const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
445 override;
446
447 ndk::ScopedAStatus getStreamCommonCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override;
448 ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) override;
449
450 ndk::ScopedAStatus initInstance(
451 const std::shared_ptr<StreamCommonInterface>& delegate) override;
getContext()452 const StreamContext& getContext() const override { return mContext; }
isClosed()453 bool isClosed() const override { return mWorker->isClosed(); }
getConnectedDevices()454 const ConnectedDevices& getConnectedDevices() const override { return mConnectedDevices; }
455 ndk::ScopedAStatus setConnectedDevices(
456 const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
457 override;
458 ndk::ScopedAStatus bluetoothParametersUpdated() override;
459 ndk::ScopedAStatus setGain(float gain) override;
460
461 protected:
getDefaultInWorkerCreator()462 static StreamWorkerInterface::CreateInstance getDefaultInWorkerCreator() {
463 return [](StreamContext* ctx, DriverInterface* driver) -> StreamWorkerInterface* {
464 return new StreamInWorker(ctx, driver);
465 };
466 }
getDefaultOutWorkerCreator()467 static StreamWorkerInterface::CreateInstance getDefaultOutWorkerCreator() {
468 return [](StreamContext* ctx, DriverInterface* driver) -> StreamWorkerInterface* {
469 return new StreamOutWorker(ctx, driver);
470 };
471 }
472
473 virtual void onClose(StreamDescriptor::State statePriorToClosing) = 0;
474 // Any stream class implementing 'DriverInterface::shutdown' must call 'cleanupWorker' in
475 // the destructor in order to stop and join the worker thread in the case when the client
476 // has not called 'IStreamCommon::close' method.
477 void cleanupWorker();
478 void stopAndJoinWorker();
479 void stopWorker();
480
481 const StreamContext& mContext;
482 Metadata mMetadata;
483 std::unique_ptr<StreamWorkerInterface> mWorker;
484 ChildInterface<StreamCommonDelegator> mCommon;
485 ConnectedDevices mConnectedDevices;
486
487 private:
488 std::atomic<bool> mWorkerStopIssued = false;
489 };
490
491 // Note: 'StreamIn/Out' can not be used on their own. Instead, they must be used for defining
492 // concrete input/output stream implementations.
493 class StreamIn : virtual public StreamCommonInterface, public BnStreamIn {
494 protected:
495 void defaultOnClose();
496
getStreamCommon(std::shared_ptr<IStreamCommon> * _aidl_return)497 ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
498 return getStreamCommonCommon(_aidl_return);
499 }
updateMetadata(const::aidl::android::hardware::audio::common::SinkMetadata & in_sinkMetadata)500 ndk::ScopedAStatus updateMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata&
501 in_sinkMetadata) override {
502 return updateMetadataCommon(in_sinkMetadata);
503 }
504 ndk::ScopedAStatus getActiveMicrophones(
505 std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
506 override;
507 ndk::ScopedAStatus getMicrophoneDirection(MicrophoneDirection* _aidl_return) override;
508 ndk::ScopedAStatus setMicrophoneDirection(MicrophoneDirection in_direction) override;
509 ndk::ScopedAStatus getMicrophoneFieldDimension(float* _aidl_return) override;
510 ndk::ScopedAStatus setMicrophoneFieldDimension(float in_zoom) override;
511 ndk::ScopedAStatus getHwGain(std::vector<float>* _aidl_return) override;
512 ndk::ScopedAStatus setHwGain(const std::vector<float>& in_channelGains) override;
513
514 friend class ndk::SharedRefBase;
515
516 StreamIn(StreamContext&& context,
517 const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
518
519 StreamContext mContextInstance;
520 const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones;
521 };
522
523 class StreamInHwGainHelper {
524 protected:
525 explicit StreamInHwGainHelper(const StreamContext* context);
526
527 ndk::ScopedAStatus getHwGainImpl(std::vector<float>* _aidl_return);
528 ndk::ScopedAStatus setHwGainImpl(const std::vector<float>& in_channelGains);
529
530 const size_t mChannelCount;
531 std::vector<float> mHwGains;
532 };
533
534 class StreamOut : virtual public StreamCommonInterface, public BnStreamOut {
535 protected:
536 void defaultOnClose();
537
getStreamCommon(std::shared_ptr<IStreamCommon> * _aidl_return)538 ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
539 return getStreamCommonCommon(_aidl_return);
540 }
updateMetadata(const::aidl::android::hardware::audio::common::SourceMetadata & in_sourceMetadata)541 ndk::ScopedAStatus updateMetadata(
542 const ::aidl::android::hardware::audio::common::SourceMetadata& in_sourceMetadata)
543 override {
544 return updateMetadataCommon(in_sourceMetadata);
545 }
546 ndk::ScopedAStatus updateOffloadMetadata(
547 const ::aidl::android::hardware::audio::common::AudioOffloadMetadata&
548 in_offloadMetadata) override;
549 ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
550 ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
551 ndk::ScopedAStatus getAudioDescriptionMixLevel(float* _aidl_return) override;
552 ndk::ScopedAStatus setAudioDescriptionMixLevel(float in_leveldB) override;
553 ndk::ScopedAStatus getDualMonoMode(
554 ::aidl::android::media::audio::common::AudioDualMonoMode* _aidl_return) override;
555 ndk::ScopedAStatus setDualMonoMode(
556 ::aidl::android::media::audio::common::AudioDualMonoMode in_mode) override;
557 ndk::ScopedAStatus getRecommendedLatencyModes(
558 std::vector<::aidl::android::media::audio::common::AudioLatencyMode>* _aidl_return)
559 override;
560 ndk::ScopedAStatus setLatencyMode(
561 ::aidl::android::media::audio::common::AudioLatencyMode in_mode) override;
562 ndk::ScopedAStatus getPlaybackRateParameters(
563 ::aidl::android::media::audio::common::AudioPlaybackRate* _aidl_return) override;
564 ndk::ScopedAStatus setPlaybackRateParameters(
565 const ::aidl::android::media::audio::common::AudioPlaybackRate& in_playbackRate)
566 override;
567 ndk::ScopedAStatus selectPresentation(int32_t in_presentationId, int32_t in_programId) override;
568
569 friend class ndk::SharedRefBase;
570
571 StreamOut(StreamContext&& context,
572 const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
573 offloadInfo);
574
575 StreamContext mContextInstance;
576 const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo;
577 std::optional<::aidl::android::hardware::audio::common::AudioOffloadMetadata> mOffloadMetadata;
578 };
579
580 class StreamOutHwVolumeHelper {
581 protected:
582 explicit StreamOutHwVolumeHelper(const StreamContext* context);
583
584 ndk::ScopedAStatus getHwVolumeImpl(std::vector<float>* _aidl_return);
585 ndk::ScopedAStatus setHwVolumeImpl(const std::vector<float>& in_channelVolumes);
586
587 const size_t mChannelCount;
588 std::vector<float> mHwVolumes;
589 };
590
591 // The recommended way to create a stream instance.
592 // 'StreamImpl' is the concrete stream implementation, 'StreamInOrOut' is either 'StreamIn' or
593 // 'StreamOut', the rest are the arguments forwarded to the constructor of 'StreamImpl'.
594 template <class StreamImpl, class StreamInOrOut, class... Args>
createStreamInstance(std::shared_ptr<StreamInOrOut> * result,Args &&...args)595 ndk::ScopedAStatus createStreamInstance(std::shared_ptr<StreamInOrOut>* result, Args&&... args) {
596 std::shared_ptr<StreamInOrOut> stream =
597 ::ndk::SharedRefBase::make<StreamImpl>(std::forward<Args>(args)...);
598 RETURN_STATUS_IF_ERROR(stream->initInstance(stream));
599 *result = std::move(stream);
600 return ndk::ScopedAStatus::ok();
601 }
602
603 class StreamWrapper {
604 public:
StreamWrapper(const std::shared_ptr<StreamIn> & streamIn)605 explicit StreamWrapper(const std::shared_ptr<StreamIn>& streamIn)
606 : mStream(streamIn), mStreamBinder(streamIn->asBinder()) {}
StreamWrapper(const std::shared_ptr<StreamOut> & streamOut)607 explicit StreamWrapper(const std::shared_ptr<StreamOut>& streamOut)
608 : mStream(streamOut), mStreamBinder(streamOut->asBinder()) {}
getBinder()609 ndk::SpAIBinder getBinder() const { return mStreamBinder; }
isStreamOpen()610 bool isStreamOpen() const {
611 auto s = mStream.lock();
612 return s && !s->isClosed();
613 }
setConnectedDevices(const std::vector<::aidl::android::media::audio::common::AudioDevice> & devices)614 ndk::ScopedAStatus setConnectedDevices(
615 const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
616 auto s = mStream.lock();
617 if (s) return s->setConnectedDevices(devices);
618 return ndk::ScopedAStatus::ok();
619 }
bluetoothParametersUpdated()620 ndk::ScopedAStatus bluetoothParametersUpdated() {
621 auto s = mStream.lock();
622 if (s) return s->bluetoothParametersUpdated();
623 return ndk::ScopedAStatus::ok();
624 }
625
setGain(float gain)626 ndk::ScopedAStatus setGain(float gain) {
627 auto s = mStream.lock();
628 if (s) return s->setGain(gain);
629 return ndk::ScopedAStatus::ok();
630 }
631
632 private:
633 std::weak_ptr<StreamCommonInterface> mStream;
634 ndk::SpAIBinder mStreamBinder;
635 };
636
637 class Streams {
638 public:
639 Streams() = default;
640 Streams(const Streams&) = delete;
641 Streams& operator=(const Streams&) = delete;
count(int32_t id)642 size_t count(int32_t id) {
643 // Streams do not remove themselves from the collection on close.
644 erase_if(mStreams, [](const auto& pair) { return !pair.second.isStreamOpen(); });
645 return mStreams.count(id);
646 }
insert(int32_t portId,int32_t portConfigId,StreamWrapper sw)647 void insert(int32_t portId, int32_t portConfigId, StreamWrapper sw) {
648 mStreams.insert(std::pair{portConfigId, sw});
649 mStreams.insert(std::pair{portId, std::move(sw)});
650 }
setStreamConnectedDevices(int32_t portConfigId,const std::vector<::aidl::android::media::audio::common::AudioDevice> & devices)651 ndk::ScopedAStatus setStreamConnectedDevices(
652 int32_t portConfigId,
653 const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
654 if (auto it = mStreams.find(portConfigId); it != mStreams.end()) {
655 return it->second.setConnectedDevices(devices);
656 }
657 return ndk::ScopedAStatus::ok();
658 }
bluetoothParametersUpdated()659 ndk::ScopedAStatus bluetoothParametersUpdated() {
660 bool isOk = true;
661 for (auto& it : mStreams) {
662 if (!it.second.bluetoothParametersUpdated().isOk()) isOk = false;
663 }
664 return isOk ? ndk::ScopedAStatus::ok()
665 : ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
666 }
setGain(int32_t portId,float gain)667 ndk::ScopedAStatus setGain(int32_t portId, float gain) {
668 if (auto it = mStreams.find(portId); it != mStreams.end()) {
669 return it->second.setGain(gain);
670 }
671 return ndk::ScopedAStatus::ok();
672 }
673
674 private:
675 // Maps port ids and port config ids to streams. Multimap because a port
676 // (not port config) can have multiple streams opened on it.
677 std::multimap<int32_t, StreamWrapper> mStreams;
678 };
679
680 } // namespace aidl::android::hardware::audio::core
681