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