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