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