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