xref: /aosp_15_r20/hardware/interfaces/audio/aidl/default/include/core-impl/Stream.h (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
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