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